566 lines
21 KiB
C#
566 lines
21 KiB
C#
using Echo.Core.Common.Packed;
|
|
using ImGuiNET;
|
|
using SDL2;
|
|
using SDL2Demo.SdlWrapper;
|
|
using skyscraper8.Skyscraper.Plugins;
|
|
using System;
|
|
using System.Numerics;
|
|
using System.Runtime.InteropServices;
|
|
using System.Runtime.Intrinsics;
|
|
using System.Runtime.Intrinsics.X86;
|
|
using testdrid.SdlWrapper;
|
|
|
|
namespace Echo.UserInterface.Backend;
|
|
|
|
using static SDL;
|
|
|
|
/// <summary>
|
|
/// Implementation reference:
|
|
/// https://github.com/ocornut/imgui/blob/e23c5edd5fdef85ea0f5418b1368adb94bf86230/backends/imgui_impl_sdl.cpp
|
|
/// https://github.com/ocornut/imgui/blob/e23c5edd5fdef85ea0f5418b1368adb94bf86230/backends/imgui_impl_sdlrenderer.cpp
|
|
/// </summary>
|
|
public sealed unsafe class ImGuiDevice : IDisposable, IEventConsumer
|
|
{
|
|
private static PluginLogger logger = PluginLogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
|
public ImGuiDevice(IntPtr window, IntPtr renderer)
|
|
{
|
|
this.window = window;
|
|
this.renderer = renderer;
|
|
io = ImGui.GetIO();
|
|
|
|
//Assign global names and flags
|
|
AssignBackendNames();
|
|
io.BackendFlags |= ImGuiBackendFlags.HasMouseCursors;
|
|
io.BackendFlags |= ImGuiBackendFlags.HasSetMousePos;
|
|
io.BackendFlags |= ImGuiBackendFlags.RendererHasVtxOffset;
|
|
|
|
//Link viewport data
|
|
SDL_SysWMinfo info = default;
|
|
SDL_VERSION(out info.version);
|
|
|
|
if (SDL_GetWindowWMInfo(window, ref info) == SDL_bool.SDL_TRUE)
|
|
{
|
|
ImGuiViewportPtr viewport = ImGui.GetMainViewport();
|
|
viewport.PlatformHandleRaw = info.info.win.window;
|
|
}
|
|
|
|
//Setup SDL hint
|
|
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
|
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest"); //Can be nearest, linear, or best
|
|
}
|
|
|
|
public void Initialize()
|
|
{
|
|
//Create resources
|
|
CreateMouseCursors();
|
|
CreateFontTexture();
|
|
CreateClipboardSetup();
|
|
}
|
|
|
|
readonly IntPtr window;
|
|
readonly IntPtr renderer;
|
|
ImGuiIOPtr io;
|
|
|
|
IntPtr[] mouseCursors;
|
|
IntPtr fontTexture;
|
|
|
|
int mouseButtonDownCount;
|
|
int pendingMouseLeaveFrame;
|
|
|
|
bool disposed;
|
|
|
|
static readonly SetClipboardTextFn SetClipboardText = (_, text) => SDL_SetClipboardText(text);
|
|
static readonly GetClipboardTextFn GetClipboardText = _ => SDL_GetClipboardText();
|
|
|
|
public void ProcessEvent(in SDL_Event sdlEvent)
|
|
{
|
|
switch (sdlEvent.type)
|
|
{
|
|
case SDL_EventType.SDL_MOUSEMOTION:
|
|
{
|
|
io.AddMousePosEvent(sdlEvent.motion.x, sdlEvent.motion.y);
|
|
break;
|
|
}
|
|
case SDL_EventType.SDL_MOUSEWHEEL:
|
|
{
|
|
io.AddMouseWheelEvent(sdlEvent.wheel.x, sdlEvent.wheel.y);
|
|
break;
|
|
}
|
|
case SDL_EventType.SDL_MOUSEBUTTONDOWN:
|
|
case SDL_EventType.SDL_MOUSEBUTTONUP:
|
|
{
|
|
ProcessMouseButtonEvent(sdlEvent.button);
|
|
break;
|
|
}
|
|
case SDL_EventType.SDL_TEXTINPUT:
|
|
{
|
|
fixed (byte* ptr = sdlEvent.text.text) ImGuiNative.ImGuiIO_AddInputCharactersUTF8(io.NativePtr, ptr);
|
|
break;
|
|
}
|
|
case SDL_EventType.SDL_KEYDOWN:
|
|
case SDL_EventType.SDL_KEYUP:
|
|
{
|
|
ProcessKeyboardEvent(sdlEvent.key);
|
|
break;
|
|
}
|
|
case SDL_EventType.SDL_WINDOWEVENT:
|
|
{
|
|
ProcessWindowEvent(sdlEvent.window);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void NewFrame(in TimeSpan deltaTime)
|
|
{
|
|
io.DeltaTime = (float)deltaTime.TotalSeconds;
|
|
|
|
RefreshDisplaySize();
|
|
UpdateMouseData();
|
|
UpdateMouseCursor();
|
|
}
|
|
|
|
public void Render(ImDrawDataPtr data)
|
|
{
|
|
|
|
//Setup clip information
|
|
Vector2 scale = data.FramebufferScale;
|
|
Float4 clipSize = Widen(scale * data.DisplaySize);
|
|
if (clipSize.X <= 0f || clipSize.Y <= 0f) return;
|
|
|
|
SDL_Rect zerocopy = new SDL_Rect();
|
|
//Render
|
|
if (SDL_RenderSetScale(renderer, scale.X, scale.Y) != 0)
|
|
throw SdlException.GenerateException();
|
|
|
|
if (SDL_RenderSetClipRect(renderer, ref zerocopy) != 0)
|
|
throw SdlException.GenerateException();
|
|
|
|
Float4 clipOffset = Widen(data.DisplayPos);
|
|
var lists = data.CmdListsRange;
|
|
|
|
for (int i = 0; i < lists.Count; i++)
|
|
{
|
|
ExecuteCommandList(lists[i], clipOffset, clipSize);
|
|
}
|
|
|
|
// SDL_RenderPresent(renderer);
|
|
|
|
static Float4 Widen(Vector2 vector) => new Float4(vector.AsVector128()).XYXY;
|
|
}
|
|
|
|
public IntPtr CreateTexture(Int2 size, bool streaming, bool bigEndian = false)
|
|
{
|
|
int access = streaming ?
|
|
(int)SDL_TextureAccess.SDL_TEXTUREACCESS_STREAMING :
|
|
(int)SDL_TextureAccess.SDL_TEXTUREACCESS_STATIC;
|
|
uint format = bigEndian ? SDL_PIXELFORMAT_RGBA8888 : SDL_PIXELFORMAT_ABGR8888;
|
|
|
|
IntPtr texture = SDL_CreateTexture(renderer, format, access, size.X, size.Y);
|
|
if (texture == IntPtr.Zero)
|
|
throw SdlException.GenerateException();
|
|
|
|
if (SDL_SetTextureBlendMode(texture, SDL_BlendMode.SDL_BLENDMODE_BLEND) != 0)
|
|
throw SdlException.GenerateException();
|
|
|
|
return texture;
|
|
}
|
|
|
|
public void DestroyTexture(ref IntPtr texture)
|
|
{
|
|
if (texture == IntPtr.Zero) return;
|
|
|
|
SDL_DestroyTexture(texture);
|
|
texture = IntPtr.Zero;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (disposed) return;
|
|
disposed = true;
|
|
|
|
DestroyMouseCursors();
|
|
DestroyFontTexture();
|
|
DestroyClipboardSetup();
|
|
io = null;
|
|
}
|
|
|
|
void AssignBackendNames()
|
|
{
|
|
if (SDL_GetRendererInfo(renderer, out SDL_RendererInfo info) != 0)
|
|
throw SdlException.GenerateException();
|
|
|
|
var name = (Marshal.PtrToStringAnsi(info.name) ?? "unknown").ToUpper();
|
|
var size = new Int2(info.max_texture_width, info.max_texture_height);
|
|
|
|
io.NativePtr->BackendPlatformName = (byte*)Marshal.StringToHGlobalAnsi("SDL2 & Dear ImGui for C#");
|
|
io.NativePtr->BackendRendererName = (byte*)Marshal.StringToHGlobalAnsi($"{name} {size.X}x{size.Y}");
|
|
}
|
|
|
|
void CreateMouseCursors()
|
|
{
|
|
mouseCursors = new IntPtr[(int)ImGuiMouseCursor.COUNT];
|
|
|
|
mouseCursors[(int)ImGuiMouseCursor.Arrow] = SDL_CreateSystemCursor(SDL_SystemCursor.SDL_SYSTEM_CURSOR_ARROW);
|
|
mouseCursors[(int)ImGuiMouseCursor.TextInput] = SDL_CreateSystemCursor(SDL_SystemCursor.SDL_SYSTEM_CURSOR_IBEAM);
|
|
mouseCursors[(int)ImGuiMouseCursor.ResizeAll] = SDL_CreateSystemCursor(SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZEALL);
|
|
mouseCursors[(int)ImGuiMouseCursor.ResizeNS] = SDL_CreateSystemCursor(SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENS);
|
|
mouseCursors[(int)ImGuiMouseCursor.ResizeEW] = SDL_CreateSystemCursor(SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZEWE);
|
|
mouseCursors[(int)ImGuiMouseCursor.ResizeNESW] = SDL_CreateSystemCursor(SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENESW);
|
|
mouseCursors[(int)ImGuiMouseCursor.ResizeNWSE] = SDL_CreateSystemCursor(SDL_SystemCursor.SDL_SYSTEM_CURSOR_SIZENWSE);
|
|
mouseCursors[(int)ImGuiMouseCursor.Hand] = SDL_CreateSystemCursor(SDL_SystemCursor.SDL_SYSTEM_CURSOR_HAND);
|
|
mouseCursors[(int)ImGuiMouseCursor.NotAllowed] = SDL_CreateSystemCursor(SDL_SystemCursor.SDL_SYSTEM_CURSOR_NO);
|
|
}
|
|
|
|
void DestroyMouseCursors()
|
|
{
|
|
if (mouseCursors == null) return;
|
|
|
|
foreach (IntPtr cursor in mouseCursors)
|
|
{
|
|
if (cursor == IntPtr.Zero) continue;
|
|
SDL_FreeCursor(cursor);
|
|
}
|
|
|
|
mouseCursors = null;
|
|
}
|
|
|
|
void CreateFontTexture()
|
|
{
|
|
io.Fonts.GetTexDataAsRGBA32(out IntPtr pixels, out int width, out int height);
|
|
fontTexture = CreateTexture(new Int2(width, height), false);
|
|
|
|
if (SDL_UpdateTexture(fontTexture, IntPtr.Zero, pixels, width * sizeof(uint)) != 0)
|
|
throw SdlException.GenerateException();
|
|
if (SDL_SetTextureBlendMode(fontTexture, SDL_BlendMode.SDL_BLENDMODE_BLEND) != 0)
|
|
throw SdlException.GenerateException();
|
|
if (SDL_SetTextureScaleMode(fontTexture, SDL_ScaleMode.SDL_ScaleModeLinear) != 0)
|
|
throw SdlException.GenerateException();
|
|
|
|
io.Fonts.SetTexID(fontTexture);
|
|
}
|
|
|
|
void DestroyFontTexture()
|
|
{
|
|
DestroyTexture(ref fontTexture);
|
|
io.Fonts.SetTexID(IntPtr.Zero);
|
|
}
|
|
|
|
void CreateClipboardSetup()
|
|
{
|
|
io.SetClipboardTextFn = Marshal.GetFunctionPointerForDelegate(SetClipboardText);
|
|
io.GetClipboardTextFn = Marshal.GetFunctionPointerForDelegate(GetClipboardText);
|
|
}
|
|
|
|
void DestroyClipboardSetup()
|
|
{
|
|
io.SetClipboardTextFn = IntPtr.Zero;
|
|
io.GetClipboardTextFn = IntPtr.Zero;
|
|
}
|
|
|
|
void ProcessMouseButtonEvent(SDL_MouseButtonEvent mouseButtonEvent)
|
|
{
|
|
int mouseButton = (uint)mouseButtonEvent.button switch
|
|
{
|
|
SDL_BUTTON_LEFT => 0,
|
|
SDL_BUTTON_RIGHT => 1,
|
|
SDL_BUTTON_MIDDLE => 2,
|
|
SDL_BUTTON_X1 => 3,
|
|
SDL_BUTTON_X2 => 4,
|
|
_ => -1
|
|
};
|
|
|
|
if (mouseButton < 0) return;
|
|
|
|
bool down = mouseButtonEvent.type == SDL_EventType.SDL_MOUSEBUTTONDOWN;
|
|
io.AddMouseButtonEvent(mouseButton, down);
|
|
mouseButtonDownCount += down ? 1 : -1;
|
|
}
|
|
|
|
void ProcessKeyboardEvent(in SDL_KeyboardEvent keyboardEvent)
|
|
{
|
|
ref readonly SDL_Keysym key = ref keyboardEvent.keysym;
|
|
bool down = keyboardEvent.type == SDL_EventType.SDL_KEYDOWN;
|
|
|
|
io.AddKeyEvent(ImGuiKey.ModCtrl, (key.mod & SDL_Keymod.KMOD_CTRL) != 0);
|
|
io.AddKeyEvent(ImGuiKey.ModShift, (key.mod & SDL_Keymod.KMOD_SHIFT) != 0);
|
|
io.AddKeyEvent(ImGuiKey.ModAlt, (key.mod & SDL_Keymod.KMOD_ALT) != 0);
|
|
io.AddKeyEvent(ImGuiKey.ModSuper, (key.mod & SDL_Keymod.KMOD_GUI) != 0);
|
|
|
|
io.AddKeyEvent(SDL_KeycodeToImGuiKey(key.sym), down);
|
|
}
|
|
|
|
public static ImGuiKey SDL_KeycodeToImGuiKey(SDL_Keycode key) => key switch
|
|
{
|
|
SDL_Keycode.SDLK_TAB => ImGuiKey.Tab,
|
|
SDL_Keycode.SDLK_LEFT => ImGuiKey.LeftArrow,
|
|
SDL_Keycode.SDLK_RIGHT => ImGuiKey.RightArrow,
|
|
SDL_Keycode.SDLK_UP => ImGuiKey.UpArrow,
|
|
SDL_Keycode.SDLK_DOWN => ImGuiKey.DownArrow,
|
|
SDL_Keycode.SDLK_PAGEUP => ImGuiKey.PageUp,
|
|
SDL_Keycode.SDLK_PAGEDOWN => ImGuiKey.PageDown,
|
|
SDL_Keycode.SDLK_HOME => ImGuiKey.Home,
|
|
SDL_Keycode.SDLK_END => ImGuiKey.End,
|
|
SDL_Keycode.SDLK_INSERT => ImGuiKey.Insert,
|
|
SDL_Keycode.SDLK_DELETE => ImGuiKey.Delete,
|
|
SDL_Keycode.SDLK_BACKSPACE => ImGuiKey.Backspace,
|
|
SDL_Keycode.SDLK_SPACE => ImGuiKey.Space,
|
|
SDL_Keycode.SDLK_RETURN => ImGuiKey.Enter,
|
|
SDL_Keycode.SDLK_ESCAPE => ImGuiKey.Escape,
|
|
SDL_Keycode.SDLK_QUOTE => ImGuiKey.Apostrophe,
|
|
SDL_Keycode.SDLK_COMMA => ImGuiKey.Comma,
|
|
SDL_Keycode.SDLK_MINUS => ImGuiKey.Minus,
|
|
SDL_Keycode.SDLK_PERIOD => ImGuiKey.Period,
|
|
SDL_Keycode.SDLK_SLASH => ImGuiKey.Slash,
|
|
SDL_Keycode.SDLK_SEMICOLON => ImGuiKey.Semicolon,
|
|
SDL_Keycode.SDLK_EQUALS => ImGuiKey.Equal,
|
|
SDL_Keycode.SDLK_LEFTBRACKET => ImGuiKey.LeftBracket,
|
|
SDL_Keycode.SDLK_BACKSLASH => ImGuiKey.Backslash,
|
|
SDL_Keycode.SDLK_RIGHTBRACKET => ImGuiKey.RightBracket,
|
|
SDL_Keycode.SDLK_BACKQUOTE => ImGuiKey.GraveAccent,
|
|
SDL_Keycode.SDLK_CAPSLOCK => ImGuiKey.CapsLock,
|
|
SDL_Keycode.SDLK_SCROLLLOCK => ImGuiKey.ScrollLock,
|
|
SDL_Keycode.SDLK_NUMLOCKCLEAR => ImGuiKey.NumLock,
|
|
SDL_Keycode.SDLK_PRINTSCREEN => ImGuiKey.PrintScreen,
|
|
SDL_Keycode.SDLK_PAUSE => ImGuiKey.Pause,
|
|
SDL_Keycode.SDLK_KP_0 => ImGuiKey.Keypad0,
|
|
SDL_Keycode.SDLK_KP_1 => ImGuiKey.Keypad1,
|
|
SDL_Keycode.SDLK_KP_2 => ImGuiKey.Keypad2,
|
|
SDL_Keycode.SDLK_KP_3 => ImGuiKey.Keypad3,
|
|
SDL_Keycode.SDLK_KP_4 => ImGuiKey.Keypad4,
|
|
SDL_Keycode.SDLK_KP_5 => ImGuiKey.Keypad5,
|
|
SDL_Keycode.SDLK_KP_6 => ImGuiKey.Keypad6,
|
|
SDL_Keycode.SDLK_KP_7 => ImGuiKey.Keypad7,
|
|
SDL_Keycode.SDLK_KP_8 => ImGuiKey.Keypad8,
|
|
SDL_Keycode.SDLK_KP_9 => ImGuiKey.Keypad9,
|
|
SDL_Keycode.SDLK_KP_PERIOD => ImGuiKey.KeypadDecimal,
|
|
SDL_Keycode.SDLK_KP_DIVIDE => ImGuiKey.KeypadDivide,
|
|
SDL_Keycode.SDLK_KP_MULTIPLY => ImGuiKey.KeypadMultiply,
|
|
SDL_Keycode.SDLK_KP_MINUS => ImGuiKey.KeypadSubtract,
|
|
SDL_Keycode.SDLK_KP_PLUS => ImGuiKey.KeypadAdd,
|
|
SDL_Keycode.SDLK_KP_ENTER => ImGuiKey.KeypadEnter,
|
|
SDL_Keycode.SDLK_KP_EQUALS => ImGuiKey.KeypadEqual,
|
|
SDL_Keycode.SDLK_LCTRL => ImGuiKey.LeftCtrl,
|
|
SDL_Keycode.SDLK_LSHIFT => ImGuiKey.LeftShift,
|
|
SDL_Keycode.SDLK_LALT => ImGuiKey.LeftAlt,
|
|
SDL_Keycode.SDLK_LGUI => ImGuiKey.LeftSuper,
|
|
SDL_Keycode.SDLK_RCTRL => ImGuiKey.RightCtrl,
|
|
SDL_Keycode.SDLK_RSHIFT => ImGuiKey.RightShift,
|
|
SDL_Keycode.SDLK_RALT => ImGuiKey.RightAlt,
|
|
SDL_Keycode.SDLK_RGUI => ImGuiKey.RightSuper,
|
|
SDL_Keycode.SDLK_APPLICATION => ImGuiKey.Menu,
|
|
SDL_Keycode.SDLK_0 => ImGuiKey._0,
|
|
SDL_Keycode.SDLK_1 => ImGuiKey._1,
|
|
SDL_Keycode.SDLK_2 => ImGuiKey._2,
|
|
SDL_Keycode.SDLK_3 => ImGuiKey._3,
|
|
SDL_Keycode.SDLK_4 => ImGuiKey._4,
|
|
SDL_Keycode.SDLK_5 => ImGuiKey._5,
|
|
SDL_Keycode.SDLK_6 => ImGuiKey._6,
|
|
SDL_Keycode.SDLK_7 => ImGuiKey._7,
|
|
SDL_Keycode.SDLK_8 => ImGuiKey._8,
|
|
SDL_Keycode.SDLK_9 => ImGuiKey._9,
|
|
SDL_Keycode.SDLK_a => ImGuiKey.A,
|
|
SDL_Keycode.SDLK_b => ImGuiKey.B,
|
|
SDL_Keycode.SDLK_c => ImGuiKey.C,
|
|
SDL_Keycode.SDLK_d => ImGuiKey.D,
|
|
SDL_Keycode.SDLK_e => ImGuiKey.E,
|
|
SDL_Keycode.SDLK_f => ImGuiKey.F,
|
|
SDL_Keycode.SDLK_g => ImGuiKey.G,
|
|
SDL_Keycode.SDLK_h => ImGuiKey.H,
|
|
SDL_Keycode.SDLK_i => ImGuiKey.I,
|
|
SDL_Keycode.SDLK_j => ImGuiKey.J,
|
|
SDL_Keycode.SDLK_k => ImGuiKey.K,
|
|
SDL_Keycode.SDLK_l => ImGuiKey.L,
|
|
SDL_Keycode.SDLK_m => ImGuiKey.M,
|
|
SDL_Keycode.SDLK_n => ImGuiKey.N,
|
|
SDL_Keycode.SDLK_o => ImGuiKey.O,
|
|
SDL_Keycode.SDLK_p => ImGuiKey.P,
|
|
SDL_Keycode.SDLK_q => ImGuiKey.Q,
|
|
SDL_Keycode.SDLK_r => ImGuiKey.R,
|
|
SDL_Keycode.SDLK_s => ImGuiKey.S,
|
|
SDL_Keycode.SDLK_t => ImGuiKey.T,
|
|
SDL_Keycode.SDLK_u => ImGuiKey.U,
|
|
SDL_Keycode.SDLK_v => ImGuiKey.V,
|
|
SDL_Keycode.SDLK_w => ImGuiKey.W,
|
|
SDL_Keycode.SDLK_x => ImGuiKey.X,
|
|
SDL_Keycode.SDLK_y => ImGuiKey.Y,
|
|
SDL_Keycode.SDLK_z => ImGuiKey.Z,
|
|
SDL_Keycode.SDLK_F1 => ImGuiKey.F1,
|
|
SDL_Keycode.SDLK_F2 => ImGuiKey.F2,
|
|
SDL_Keycode.SDLK_F3 => ImGuiKey.F3,
|
|
SDL_Keycode.SDLK_F4 => ImGuiKey.F4,
|
|
SDL_Keycode.SDLK_F5 => ImGuiKey.F5,
|
|
SDL_Keycode.SDLK_F6 => ImGuiKey.F6,
|
|
SDL_Keycode.SDLK_F7 => ImGuiKey.F7,
|
|
SDL_Keycode.SDLK_F8 => ImGuiKey.F8,
|
|
SDL_Keycode.SDLK_F9 => ImGuiKey.F9,
|
|
SDL_Keycode.SDLK_F10 => ImGuiKey.F10,
|
|
SDL_Keycode.SDLK_F11 => ImGuiKey.F11,
|
|
SDL_Keycode.SDLK_F12 => ImGuiKey.F12,
|
|
_ => ImGuiKey.None
|
|
};
|
|
|
|
void ProcessWindowEvent(in SDL_WindowEvent windowEvent)
|
|
{
|
|
switch (windowEvent.windowEvent)
|
|
{
|
|
case SDL_WindowEventID.SDL_WINDOWEVENT_ENTER:
|
|
{
|
|
pendingMouseLeaveFrame = 0;
|
|
break;
|
|
}
|
|
case SDL_WindowEventID.SDL_WINDOWEVENT_LEAVE:
|
|
{
|
|
pendingMouseLeaveFrame = ImGui.GetFrameCount() + 1;
|
|
break;
|
|
}
|
|
case SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED:
|
|
{
|
|
io.AddFocusEvent(true);
|
|
break;
|
|
}
|
|
case SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_LOST:
|
|
{
|
|
io.AddFocusEvent(false);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void RefreshDisplaySize()
|
|
{
|
|
SDL_GetWindowSize(window, out int width, out int height);
|
|
var size = io.DisplaySize = new Vector2(width, height);
|
|
|
|
if (SDL_GetRendererOutputSize(renderer, out int displayWidth, out int displayHeight) != 0)
|
|
throw SdlException.GenerateException();
|
|
|
|
if ((SDL_GetWindowFlags(window) & (uint)SDL_WindowFlags.SDL_WINDOW_MINIMIZED) != 0) size = Vector2.Zero;
|
|
if (size.X > 0f && size.Y > 0f) io.DisplayFramebufferScale = new Vector2(displayWidth, displayHeight) / size;
|
|
}
|
|
|
|
private long nandate = 0;
|
|
void UpdateMouseData()
|
|
{
|
|
if (pendingMouseLeaveFrame >= ImGui.GetFrameCount() && mouseButtonDownCount == 0)
|
|
{
|
|
io.AddMousePosEvent(float.MinValue, float.MinValue);
|
|
pendingMouseLeaveFrame = 0;
|
|
}
|
|
|
|
if (SDL_CaptureMouse(mouseButtonDownCount != 0 ? SDL_bool.SDL_TRUE : SDL_bool.SDL_FALSE) != 0)
|
|
{
|
|
nandate++;
|
|
//throw SdlException.GenerateException();
|
|
}
|
|
|
|
if (window != SDL_GetKeyboardFocus()) return;
|
|
if (io.WantSetMousePos) SDL_WarpMouseInWindow(window, (int)io.MousePos.X, (int)io.MousePos.Y);
|
|
|
|
if (mouseButtonDownCount == 0)
|
|
{
|
|
_ = SDL_GetGlobalMouseState(out int globalX, out int globalY);
|
|
SDL_GetWindowPosition(window, out int windowX, out int windowY);
|
|
|
|
io.AddMousePosEvent(globalX - windowX, globalY - windowY);
|
|
}
|
|
}
|
|
|
|
void UpdateMouseCursor()
|
|
{
|
|
if ((io.ConfigFlags & ImGuiConfigFlags.NoMouseCursorChange) != 0) return;
|
|
|
|
ImGuiMouseCursor cursor = ImGui.GetMouseCursor();
|
|
|
|
if (!io.MouseDrawCursor && cursor != ImGuiMouseCursor.None)
|
|
{
|
|
IntPtr mouseCursor = mouseCursors[(int)cursor];
|
|
const int Fallback = (int)ImGuiMouseCursor.Arrow;
|
|
|
|
if (mouseCursor == IntPtr.Zero) mouseCursor = mouseCursors[Fallback];
|
|
|
|
SDL_SetCursor(mouseCursor);
|
|
_ = SDL_ShowCursor((int)SDL_bool.SDL_TRUE);
|
|
}
|
|
else _ = SDL_ShowCursor((int)SDL_bool.SDL_FALSE);
|
|
}
|
|
|
|
private uint numErrors;
|
|
void ExecuteCommandList(ImDrawListPtr list, in Float4 clipOffset, in Float4 clipSize)
|
|
{
|
|
ImPtrVector<ImDrawCmdPtr> buffer = list.CmdBuffer;
|
|
var vertices = (ImDrawVert*)list.VtxBuffer.Data;
|
|
var indices = (ushort*)list.IdxBuffer.Data;
|
|
|
|
for (int i = 0; i < buffer.Size; i++)
|
|
{
|
|
ImDrawCmdPtr command = buffer[i];
|
|
|
|
if (command.UserCallback == IntPtr.Zero)
|
|
{
|
|
var clipRect = new Float4(command.ClipRect.AsVector128()) - clipOffset;
|
|
|
|
Float4 clipMin = clipRect.Max(Float4.Zero); //(minX, minY, ____, ____).Max(zero)
|
|
Float4 clipMax = clipRect.Min(clipSize); //(____, ____, maxX, maxY).Min(size)
|
|
|
|
if (clipMax.Z <= clipMin.X || clipMax.W <= clipMin.Y) continue;
|
|
|
|
clipMin = clipMin.XYXY; //(minX, minY, minX, minY)
|
|
clipMax = clipMax.__ZW; //(0000, 0000, maxX, maxY)
|
|
|
|
Float4 clip = (clipMax - clipMin).Absoluted; //(-minX, -minY, maxX - minX, maxY - minY).Absoluted
|
|
var rect = Sse2.ConvertToVector128Int32(clip.v); //( X, Y, width, height)
|
|
ImDrawVert* vertex = vertices + command.VtxOffset;
|
|
int stride = sizeof(ImDrawVert);
|
|
|
|
lock (Renderer.Lockable)
|
|
{
|
|
if (SDL_RenderGeometryRaw
|
|
(
|
|
renderer, command.TextureId,
|
|
(float*)&vertex->pos, stride,
|
|
(int*)&vertex->col, stride,
|
|
(float*)&vertex->uv, stride,
|
|
list.VtxBuffer.Size - (int)command.VtxOffset,
|
|
(IntPtr)(indices + command.IdxOffset),
|
|
(int)command.ElemCount, sizeof(ushort)
|
|
) != 0)
|
|
{
|
|
numErrors++;
|
|
SdlException sdlException = SdlException.GenerateException();
|
|
//We can tolerate the Geometry Renderer going sideways a few times
|
|
logger.Log(PluginLogLevel.Error, String.Format("{0}, ({1}x)",sdlException.ToString(),numErrors));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var callback = Marshal.GetDelegateForFunctionPointer<ImDrawCallback>(command.UserCallback);
|
|
callback(new IntPtr(list), new IntPtr(command)); //Perform user callback, not really used
|
|
}
|
|
}
|
|
}
|
|
|
|
[DllImport("SDL2", CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern unsafe int SDL_RenderGeometryRaw(IntPtr renderer,
|
|
IntPtr texture,
|
|
float* xy,
|
|
int xy_stride,
|
|
int* color,
|
|
int color_stride,
|
|
float* uv,
|
|
int uv_stride,
|
|
int num_vertices,
|
|
IntPtr indices,
|
|
int num_indices,
|
|
int size_indices);
|
|
|
|
delegate void SetClipboardTextFn(IntPtr _, string text);
|
|
delegate string GetClipboardTextFn(IntPtr _);
|
|
delegate void ImDrawCallback(IntPtr list, IntPtr cmd);
|
|
|
|
public void ProcessEvent(SDL_Event evt)
|
|
{
|
|
ProcessEvent(in evt);
|
|
}
|
|
} |