diff --git a/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs b/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs index 27ae133..36de3c5 100644 --- a/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs +++ b/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs @@ -1,12 +1,13 @@ #if GODOT_PC using Godot; +using ImGuiGodot.Internal; using System; namespace ImGuiGodot; public static class ImGuiGD { - private static readonly Internal.IBackend _backend; + private static readonly IBackend _backend; /// /// Deadzone for all axes @@ -40,7 +41,7 @@ public static float Scale static ImGuiGD() { - _backend = ClassDB.ClassExists("ImGuiGD") ? new Internal.BackendNative() : new Internal.BackendNet(); + _backend = ClassDB.ClassExists("ImGuiGD") ? new BackendNative() : new BackendNet(); } public static IntPtr BindTexture(Texture2D tex) @@ -84,6 +85,19 @@ public static void Connect(Action action) Connect(Callable.From(action)); } + public static bool ToolInit() + { + if (_backend is BackendNative nbe) + { + nbe.ToolInit(); + return true; + } + else + { + return false; + } + } + internal static bool SubViewportWidget(SubViewport svp) { return _backend.SubViewportWidget(svp); diff --git a/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs b/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs index 2a63e13..c35b953 100644 --- a/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs +++ b/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs @@ -91,7 +91,7 @@ public override void _Ready() public override void _ExitTree() { - Internal.State.Instance.Shutdown(); + Internal.State.Instance.Dispose(); RenderingServer.FreeRid(_ci); RenderingServer.FreeRid(_subViewportRid); } diff --git a/addons/imgui-godot/ImGuiGodot/ImGuiSync.cs b/addons/imgui-godot/ImGuiGodot/ImGuiSync.cs index a9214ca..c94ea1a 100644 --- a/addons/imgui-godot/ImGuiGodot/ImGuiSync.cs +++ b/addons/imgui-godot/ImGuiGodot/ImGuiSync.cs @@ -8,10 +8,12 @@ namespace ImGuiGodot; public partial class ImGuiSync : GodotObject { + public static readonly StringName GetImGuiPtrs = "GetImGuiPtrs"; + public static void SyncPtrs() { GodotObject gd = Engine.GetSingleton("ImGuiGD"); - long[] ptrs = (long[])gd.Call("GetImGuiPtrs", + long[] ptrs = (long[])gd.Call(GetImGuiPtrs, ImGui.GetVersion(), Marshal.SizeOf(), Marshal.SizeOf(), diff --git a/addons/imgui-godot/ImGuiGodot/Internal/BackendNative.cs b/addons/imgui-godot/ImGuiGodot/Internal/BackendNative.cs index 191598a..d87424f 100644 --- a/addons/imgui-godot/ImGuiGodot/Internal/BackendNative.cs +++ b/addons/imgui-godot/ImGuiGodot/Internal/BackendNative.cs @@ -5,38 +5,64 @@ namespace ImGuiGodot.Internal; internal sealed class BackendNative : IBackend { + private readonly GodotObject _gd = Engine.GetSingleton("ImGuiGD"); + + private sealed class MethodName + { + public static readonly StringName AddFont = "AddFont"; + public static readonly StringName AddFontDefault = "AddFontDefault"; + public static readonly StringName Connect = "Connect"; + public static readonly StringName RebuildFontAtlas = "RebuildFontAtlas"; + public static readonly StringName ResetFonts = "ResetFonts"; + public static readonly StringName SubViewport = "SubViewport"; + public static readonly StringName ToolInit = "ToolInit"; + } + + private sealed class PropertyName + { + public static readonly StringName JoyAxisDeadZone = "JoyAxisDeadZone"; + public static readonly StringName Scale = "Scale"; + public static readonly StringName Visible = "Visible"; + } + public float JoyAxisDeadZone { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } - public float Scale { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public float Scale { get; set; } = 1.0f; // TODO: make property public bool Visible { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } public void AddFont(FontFile fontData, int fontSize, bool merge) { - throw new System.NotImplementedException(); + _gd.Call(MethodName.AddFont, fontData, fontSize, merge); } public void AddFontDefault() { - throw new System.NotImplementedException(); + _gd.Call(MethodName.AddFontDefault); } public void Connect(Callable callable) { - throw new System.NotImplementedException(); + _gd.Call(MethodName.Connect, callable); } public void RebuildFontAtlas(float scale) { - throw new System.NotImplementedException(); + _gd.Call(MethodName.RebuildFontAtlas, scale); } public void ResetFonts() { - throw new System.NotImplementedException(); + _gd.Call(MethodName.ResetFonts); } public bool SubViewportWidget(SubViewport svp) { - throw new System.NotImplementedException(); + return (bool)_gd.Call(MethodName.SubViewport, svp); + } + + public void ToolInit() + { + _gd.Call(MethodName.ToolInit); + ImGuiSync.SyncPtrs(); } } #endif diff --git a/addons/imgui-godot/ImGuiGodot/Internal/CanvasRenderer.cs b/addons/imgui-godot/ImGuiGodot/Internal/CanvasRenderer.cs index 9e1205b..5c8eaae 100644 --- a/addons/imgui-godot/ImGuiGodot/Internal/CanvasRenderer.cs +++ b/addons/imgui-godot/ImGuiGodot/Internal/CanvasRenderer.cs @@ -34,7 +34,7 @@ public void InitViewport(Rid vprid) }; } - public void RenderDrawData() + public void Render() { var pio = ImGui.GetPlatformIO(); for (int vpidx = 0; vpidx < pio.Viewports.Size; vpidx++) @@ -186,7 +186,7 @@ public void OnHide() ClearCanvasItems(); } - public void Shutdown() + public void Dispose() { ClearCanvasItems(); foreach (ViewportData vd in _vpData.Values) diff --git a/addons/imgui-godot/ImGuiGodot/Internal/DummyRenderer.cs b/addons/imgui-godot/ImGuiGodot/Internal/DummyRenderer.cs index 410e692..88b95b6 100644 --- a/addons/imgui-godot/ImGuiGodot/Internal/DummyRenderer.cs +++ b/addons/imgui-godot/ImGuiGodot/Internal/DummyRenderer.cs @@ -19,11 +19,11 @@ public void OnHide() { } - public void RenderDrawData() + public void Render() { } - public void Shutdown() + public void Dispose() { } } diff --git a/addons/imgui-godot/ImGuiGodot/Internal/IRenderer.cs b/addons/imgui-godot/ImGuiGodot/Internal/IRenderer.cs index 1413de4..8c81461 100644 --- a/addons/imgui-godot/ImGuiGodot/Internal/IRenderer.cs +++ b/addons/imgui-godot/ImGuiGodot/Internal/IRenderer.cs @@ -1,15 +1,15 @@ #if GODOT_PC using Godot; +using System; namespace ImGuiGodot.Internal; -internal interface IRenderer +internal interface IRenderer : IDisposable { public string Name { get; } public void InitViewport(Rid vprid); public void CloseViewport(Rid vprid); - public void RenderDrawData(); + public void Render(); public void OnHide(); - public void Shutdown(); } #endif diff --git a/addons/imgui-godot/ImGuiGodot/Internal/RdRenderer.cs b/addons/imgui-godot/ImGuiGodot/Internal/RdRenderer.cs index 33834a7..db4408b 100644 --- a/addons/imgui-godot/ImGuiGodot/Internal/RdRenderer.cs +++ b/addons/imgui-godot/ImGuiGodot/Internal/RdRenderer.cs @@ -236,7 +236,7 @@ protected void FreeUnusedTextures() _usedTextures.Clear(); } - public void RenderDrawData() + public void Render() { var pio = ImGui.GetPlatformIO(); for (int i = 0; i < pio.Viewports.Size; ++i) @@ -371,7 +371,7 @@ public void OnHide() { } - public void Shutdown() + public void Dispose() { RD.FreeRid(_sampler); RD.FreeRid(_shader); diff --git a/addons/imgui-godot/ImGuiGodot/Internal/RdRendererThreadSafe.cs b/addons/imgui-godot/ImGuiGodot/Internal/RdRendererThreadSafe.cs index d716945..f9290fc 100644 --- a/addons/imgui-godot/ImGuiGodot/Internal/RdRendererThreadSafe.cs +++ b/addons/imgui-godot/ImGuiGodot/Internal/RdRendererThreadSafe.cs @@ -81,7 +81,7 @@ public RdRendererThreadSafe() : base() RenderingServer.FramePreDraw -= OnFramePreDraw; } - public new void RenderDrawData() + public new void Render() { var pio = ImGui.GetPlatformIO(); var newData = new SharedList(pio.Viewports.Size); diff --git a/addons/imgui-godot/ImGuiGodot/Internal/State.cs b/addons/imgui-godot/ImGuiGodot/Internal/State.cs index 8491ccb..61c33a9 100644 --- a/addons/imgui-godot/ImGuiGodot/Internal/State.cs +++ b/addons/imgui-godot/ImGuiGodot/Internal/State.cs @@ -65,9 +65,8 @@ public State(Window mainWindow, Rid mainSubViewport, IRenderer renderer) public void Dispose() { if (ImGui.GetCurrentContext() != IntPtr.Zero) - { ImGui.DestroyContext(); - } + Renderer.Dispose(); } public static void Init(Window mainWindow, Rid mainSubViewport, Resource cfg) @@ -181,17 +180,10 @@ public void Render() ImGui.Render(); ImGui.UpdatePlatformWindows(); - Renderer.RenderDrawData(); + Renderer.Render(); //_inProcessFrame = false; } - public void Shutdown() - { - Renderer.Shutdown(); - if (ImGui.GetCurrentContext() != IntPtr.Zero) - ImGui.DestroyContext(); - } - /// /// True if the InputEvent was consumed /// diff --git a/addons/imgui-godot/ImGuiGodot/Internal/Viewports.cs b/addons/imgui-godot/ImGuiGodot/Internal/Viewports.cs index d7c2a9a..a2a36c1 100644 --- a/addons/imgui-godot/ImGuiGodot/Internal/Viewports.cs +++ b/addons/imgui-godot/ImGuiGodot/Internal/Viewports.cs @@ -70,6 +70,7 @@ public void Dispose() { if (GodotWindow.GetParent() != null) { + State.Instance.Renderer.CloseViewport(Util.ConstructRid((ulong)_vp.RendererUserData)); GodotWindow.QueueFree(); } _gcHandle.Free(); diff --git a/addons/imgui-godot/scripts/ImGuiPlugin.gd b/addons/imgui-godot/scripts/ImGuiPlugin.gd index 2ea6996..1e08201 100644 --- a/addons/imgui-godot/scripts/ImGuiPlugin.gd +++ b/addons/imgui-godot/scripts/ImGuiPlugin.gd @@ -5,6 +5,7 @@ func _enter_tree(): if ProjectSettings.has_setting("autoload/ImGuiLayer"): remove_autoload_singleton("ImGuiLayer") add_autoload_singleton("ImGuiRoot", "res://addons/imgui-godot/data/ImGuiRoot.tscn") + Engine.register_singleton("ImGuiPlugin", self) func _exit_tree(): remove_autoload_singleton("ImGuiRoot") diff --git a/gdext/src/CMakeLists.txt b/gdext/src/CMakeLists.txt index eae2de7..caa6a37 100644 --- a/gdext/src/CMakeLists.txt +++ b/gdext/src/CMakeLists.txt @@ -1,5 +1,7 @@ target_sources(imgui-godot-native PRIVATE common.h + CanvasRenderer.cpp + CanvasRenderer.h Context.cpp Context.h DummyRenderer.h diff --git a/gdext/src/CanvasRenderer.cpp b/gdext/src/CanvasRenderer.cpp new file mode 100644 index 0000000..4163807 --- /dev/null +++ b/gdext/src/CanvasRenderer.cpp @@ -0,0 +1,54 @@ +#include "CanvasRenderer.h" +#include "common.h" +#include +#include +#include + +using namespace godot; + +namespace ImGui::Godot { + +struct CanvasRenderer::Impl +{ + struct ViewportData + { + RID canvas; + RID rootCanvasItem; + }; + + std::unordered_map> canvasItemPools; + std::unordered_map vpData; +}; + +CanvasRenderer::CanvasRenderer() +{ +} + +CanvasRenderer::~CanvasRenderer() +{ +} + +void CanvasRenderer::InitViewport(RID vprid) +{ + RenderingServer* RS = RenderingServer::get_singleton(); + RID canvas = RS->canvas_create(); + RID canvasItem = RS->canvas_item_create(); + RS->viewport_attach_canvas(vprid, canvas); + RS->canvas_item_set_parent(canvasItem, canvas); + + impl->vpData[vprid] = {canvas, canvasItem}; +} + +void CanvasRenderer::CloseViewport(RID vprid) +{ +} + +void CanvasRenderer::Render() +{ +} + +void CanvasRenderer::OnHide() +{ +} + +} // namespace ImGui::Godot diff --git a/gdext/src/CanvasRenderer.h b/gdext/src/CanvasRenderer.h new file mode 100644 index 0000000..c3ed6de --- /dev/null +++ b/gdext/src/CanvasRenderer.h @@ -0,0 +1,35 @@ +#pragma once +#include "Renderer.h" +#include +#include + +#pragma warning(push, 0) +#include +#pragma warning(pop) + +using godot::RID; + +namespace ImGui::Godot { + +class CanvasRenderer : public Renderer +{ +public: + CanvasRenderer(); + virtual ~CanvasRenderer(); + + virtual const char* Name() override + { + return "godot4_canvas"; + } + + void InitViewport(RID vprid) override; + void CloseViewport(RID vprid) override; + void Render() override; + void OnHide() override; + +private: + struct Impl; + std::unique_ptr impl; +}; + +} // namespace ImGui::Godot diff --git a/gdext/src/DummyRenderer.h b/gdext/src/DummyRenderer.h index 6a4eafb..98ff155 100644 --- a/gdext/src/DummyRenderer.h +++ b/gdext/src/DummyRenderer.h @@ -9,6 +9,7 @@ class DummyRenderer : public Renderer DummyRenderer() { } + ~DummyRenderer() { } @@ -18,9 +19,21 @@ class DummyRenderer : public Renderer return "godot4_dummy"; } + void InitViewport(RID vprid) override + { + } + + void CloseViewport(RID vprid) override + { + } + void Render() override { } + + void OnHide() override + { + } }; } // namespace ImGui::Godot diff --git a/gdext/src/ImGuiGD.cpp b/gdext/src/ImGuiGD.cpp index 47e01bf..b0051c2 100644 --- a/gdext/src/ImGuiGD.cpp +++ b/gdext/src/ImGuiGD.cpp @@ -59,9 +59,14 @@ void ImGuiGD::ToolInit() #ifdef DEBUG_ENABLED if (!Engine::get_singleton()->is_editor_hint()) return; - ImGuiLayer* igl = Object::cast_to(Engine::get_singleton()->get_singleton("ImGuiLayer")); - if (igl) + + Node* plugin = Object::cast_to(Engine::get_singleton()->get_singleton("ImGuiPlugin")); + if (!plugin->get_node_or_null("ImGuiLayer")) + { + ImGuiLayer* igl = memnew(ImGuiLayer); + plugin->add_child(igl); igl->ToolInit(); + } #endif } diff --git a/gdext/src/RdRenderer.cpp b/gdext/src/RdRenderer.cpp index 87c6d5a..d43d1ea 100644 --- a/gdext/src/RdRenderer.cpp +++ b/gdext/src/RdRenderer.cpp @@ -25,15 +25,6 @@ using namespace godot; -template <> -struct std::hash -{ - std::size_t operator()(const RID& rid) const noexcept - { - return std::hash{}(rid.get_id()); - } -}; - namespace ImGui::Godot { struct RdRenderer::Impl diff --git a/gdext/src/RdRenderer.h b/gdext/src/RdRenderer.h index a4e78fa..d03e2a9 100644 --- a/gdext/src/RdRenderer.h +++ b/gdext/src/RdRenderer.h @@ -22,7 +22,17 @@ class RdRenderer : public Renderer return "godot4_rd"; } + void InitViewport(RID vprid) override + { + } + void CloseViewport(RID vprid) override + { + } virtual void Render() override; + void OnHide() override + { + } + protected: void Render(RID fb, ImDrawData* drawData); diff --git a/gdext/src/RdRendererThreadSafe.cpp b/gdext/src/RdRendererThreadSafe.cpp index 1d7321e..3f81adc 100644 --- a/gdext/src/RdRendererThreadSafe.cpp +++ b/gdext/src/RdRendererThreadSafe.cpp @@ -13,6 +13,7 @@ struct RdRendererThreadSafe::Impl { ClonedDrawData(ImDrawData* drawData) { + static_assert(sizeof(ImDrawData) == 64); data = IM_NEW(ImDrawData); data->Valid = drawData->Valid; data->CmdListsCount = drawData->CmdListsCount; diff --git a/gdext/src/Renderer.h b/gdext/src/Renderer.h index 910dc17..17cdccb 100644 --- a/gdext/src/Renderer.h +++ b/gdext/src/Renderer.h @@ -22,7 +22,11 @@ class Renderer } virtual const char* Name() = 0; + + virtual void InitViewport(RID vprid) = 0; + virtual void CloseViewport(RID vprid) = 0; virtual void Render() = 0; + virtual void OnHide() = 0; virtual void OnFramePreDraw() { } diff --git a/gdext/src/Viewports.cpp b/gdext/src/Viewports.cpp index 276f97e..1065e6f 100644 --- a/gdext/src/Viewports.cpp +++ b/gdext/src/Viewports.cpp @@ -51,7 +51,7 @@ static void Godot_CreateWindow(ImGuiViewport* vp) // vd->window->connect("close_requested", Callable(vd->signalProxy, "close_requested")); // vd->window->connect("size_changed", Callable(vd->signalProxy, "size_changed")); - Node* root = Object::cast_to(Engine::get_singleton()->get_singleton("ImGuiRoot")); + Node* root = Object::cast_to(Engine::get_singleton()->get_singleton("ImGuiLayer")); root->add_child(vd->window); // need to do this after add_child diff --git a/gdext/src/common.h b/gdext/src/common.h index e466178..5c92f28 100644 --- a/gdext/src/common.h +++ b/gdext/src/common.h @@ -25,3 +25,12 @@ inline RID make_rid(ImTextureID id) } } // namespace ImGui::Godot + +template <> +struct std::hash +{ + std::size_t operator()(const RID& rid) const noexcept + { + return std::hash{}(rid.get_id()); + } +};