diff --git a/.github/workflows/gdext.yml b/.github/workflows/gdext.yml
index 2571a10..a5fa78b 100644
--- a/.github/workflows/gdext.yml
+++ b/.github/workflows/gdext.yml
@@ -230,6 +230,7 @@ jobs:
pkgdir=~/out/imgui-godot-${plugin_ver}
mkdir -p $pkgdir
mv * $pkgdir
+ echo "pkgdir=$pkgdir" >> $GITHUB_OUTPUT
- name: Upload package
uses: actions/upload-artifact@v4
@@ -238,6 +239,12 @@ jobs:
path: |
~/out
+ - name: Upload asset package
+ uses: actions/upload-artifact@v4
+ with:
+ name: AssetLib-${{ steps.prep.outputs.pkgfn }}
+ path: ${{ steps.prep.outputs.pkgdir }}/addons
+
package_cs:
name: 📦Package (C# only)
runs-on: ubuntu-latest
diff --git a/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs b/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs
index dfdfa1d..47927ad 100644
--- a/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs
+++ b/addons/imgui-godot/ImGuiGodot/ImGuiLayer.cs
@@ -13,7 +13,6 @@ public partial class ImGuiLayer : CanvasLayer
private Transform2D _finalTransform = Transform2D.Identity;
private bool _visible = true;
private Viewport _parentViewport = null!;
- public Vector2I ViewportSize { get; private set; }
public override void _EnterTree()
{
@@ -26,7 +25,7 @@ public override void _EnterTree()
RenderingServer.CanvasItemSetParent(_canvasItem, GetCanvas());
State.Instance.Renderer.InitViewport(_subViewportRid);
- State.Instance.Viewports.SetMainViewport(_parentViewport, _subViewportRid);
+ State.Instance.Viewports.SetMainWindow(GetWindow(), _subViewportRid);
}
public override void _Ready()
@@ -59,7 +58,7 @@ private void OnChangeVisibility()
public override void _Input(InputEvent @event)
{
- if (State.Instance.ProcessInput(@event))
+ if (State.Instance.Input.ProcessInput(@event))
{
_parentViewport.SetInputAsHandled();
}
diff --git a/addons/imgui-godot/ImGuiGodot/Internal/BackendNative.cs b/addons/imgui-godot/ImGuiGodot/Internal/BackendNative.cs
index e5d5bdb..f62a88e 100644
--- a/addons/imgui-godot/ImGuiGodot/Internal/BackendNative.cs
+++ b/addons/imgui-godot/ImGuiGodot/Internal/BackendNative.cs
@@ -16,6 +16,7 @@ private sealed class MethodName
public static readonly StringName Connect = "Connect";
public static readonly StringName RebuildFontAtlas = "RebuildFontAtlas";
public static readonly StringName ResetFonts = "ResetFonts";
+ public static readonly StringName SetMainViewport = "SetMainViewport";
public static readonly StringName SubViewport = "SubViewport";
public static readonly StringName ToolInit = "ToolInit";
}
@@ -81,7 +82,7 @@ public void ResetFonts()
}
public void SetMainViewport(Viewport vp)
{
- throw new NotImplementedException();
+ _gd.Call(MethodName.SetMainViewport, vp);
}
public bool SubViewportWidget(SubViewport svp)
diff --git a/addons/imgui-godot/ImGuiGodot/Internal/Input.cs b/addons/imgui-godot/ImGuiGodot/Internal/Input.cs
index fc74af1..576cd3e 100644
--- a/addons/imgui-godot/ImGuiGodot/Internal/Input.cs
+++ b/addons/imgui-godot/ImGuiGodot/Internal/Input.cs
@@ -119,7 +119,7 @@ protected void ProcessSubViewportWidget(InputEvent evt)
}
}
- protected virtual bool HandleEvent(InputEvent evt)
+ protected bool HandleEvent(InputEvent evt)
{
var io = ImGui.GetIO();
bool consumed = false;
@@ -236,7 +236,7 @@ protected virtual bool HandleEvent(InputEvent evt)
return consumed;
}
- public bool ProcessInput(InputEvent evt)
+ public virtual bool ProcessInput(InputEvent evt)
{
ProcessSubViewportWidget(evt);
return HandleEvent(evt);
diff --git a/addons/imgui-godot/ImGuiGodot/Internal/InputLocal.cs b/addons/imgui-godot/ImGuiGodot/Internal/InputLocal.cs
index fb9c534..f5a2af3 100644
--- a/addons/imgui-godot/ImGuiGodot/Internal/InputLocal.cs
+++ b/addons/imgui-godot/ImGuiGodot/Internal/InputLocal.cs
@@ -11,7 +11,7 @@ protected override void UpdateMousePos(ImGuiIOPtr io)
// do not use global mouse position
}
- protected override bool HandleEvent(InputEvent evt)
+ public override bool ProcessInput(InputEvent evt)
{
// no support for SubViewport widgets
@@ -23,7 +23,7 @@ protected override bool HandleEvent(InputEvent evt)
mm.Dispose();
return io.WantCaptureMouse;
}
- return base.HandleEvent(evt);
+ return HandleEvent(evt);
}
}
#endif
diff --git a/addons/imgui-godot/ImGuiGodot/Internal/State.cs b/addons/imgui-godot/ImGuiGodot/Internal/State.cs
index 0f7b8fd..4a8a37e 100644
--- a/addons/imgui-godot/ImGuiGodot/Internal/State.cs
+++ b/addons/imgui-godot/ImGuiGodot/Internal/State.cs
@@ -184,16 +184,5 @@ public void Render()
ImGui.UpdatePlatformWindows();
Renderer.Render();
}
-
- ///
- /// Send input event to ImGui
- ///
- ///
- /// True if the InputEvent was consumed
- ///
- public bool ProcessInput(InputEvent evt)
- {
- return Input.ProcessInput(evt);
- }
}
#endif
diff --git a/addons/imgui-godot/ImGuiGodot/Internal/Viewports.cs b/addons/imgui-godot/ImGuiGodot/Internal/Viewports.cs
index b33af29..b3e2afa 100644
--- a/addons/imgui-godot/ImGuiGodot/Internal/Viewports.cs
+++ b/addons/imgui-godot/ImGuiGodot/Internal/Viewports.cs
@@ -7,20 +7,7 @@
namespace ImGuiGodot.Internal;
-internal interface IViewportWindow : IDisposable
-{
- public void ShowWindow();
- public void SetWindowPos(Vector2I pos);
- public Vector2I GetWindowPos();
- public void SetWindowSize(Vector2I size);
- public Vector2I GetWindowSize();
- public void SetWindowFocus();
- public bool GetWindowFocus();
- public bool GetWindowMinimized();
- public void SetWindowTitle(string title);
-}
-
-internal sealed class GodotImGuiWindow : IViewportWindow
+internal sealed class GodotImGuiWindow
{
private readonly GCHandle _gcHandle;
private readonly ImGuiViewportPtr _vp;
@@ -150,68 +137,6 @@ public void SetWindowTitle(string title)
}
}
-internal sealed class GodotImGuiSubViewport : IViewportWindow
-{
- private readonly GCHandle _gcHandle;
- private readonly SubViewport _svp;
-
- public GodotImGuiSubViewport(ImGuiViewportPtr vp, SubViewport svp, Rid mainSubViewport)
- {
- _gcHandle = GCHandle.Alloc(this);
- vp.PlatformUserData = (IntPtr)_gcHandle;
- vp.RendererUserData = (IntPtr)mainSubViewport.Id;
- _svp = svp;
- }
-
- public void Dispose()
- {
- if (_gcHandle.IsAllocated)
- {
- _gcHandle.Free();
- }
- }
-
- public bool GetWindowFocus()
- {
- return true;
- }
-
- public bool GetWindowMinimized()
- {
- return false;
- }
-
- public Vector2I GetWindowPos()
- {
- return new(0, 0);
- }
-
- public Vector2I GetWindowSize()
- {
- return _svp.Size;
- }
-
- public void SetWindowFocus()
- {
- }
-
- public void SetWindowPos(Vector2I pos)
- {
- }
-
- public void SetWindowSize(Vector2I size)
- {
- }
-
- public void SetWindowTitle(string title)
- {
- }
-
- public void ShowWindow()
- {
- }
-}
-
internal static class ViewportsExts
{
internal static Vector2 ToImVec2(this Vector2I v)
@@ -283,7 +208,7 @@ private static readonly Platform_GetWindowMinimized _getWindowMinimized
private delegate void Platform_SetWindowTitle(ImGuiViewportPtr vp, string title);
private static readonly Platform_SetWindowTitle _setWindowTitle = Godot_SetWindowTitle;
- private IViewportWindow _mainWindow = null!;
+ private GodotImGuiWindow _mainWindow = null!;
private static void UpdateMonitors()
{
@@ -346,17 +271,10 @@ public Viewports()
UpdateMonitors();
}
- public void SetMainViewport(Viewport vp, Rid mainSubViewport)
+ public void SetMainWindow(Window window, Rid mainSubViewport)
{
_mainWindow?.Dispose();
- if (vp is Window window)
- {
- _mainWindow = new GodotImGuiWindow(ImGui.GetMainViewport(), window, mainSubViewport);
- }
- else if (vp is SubViewport svp)
- {
- _mainWindow = new GodotImGuiSubViewport(ImGui.GetMainViewport(), svp, mainSubViewport);
- }
+ _mainWindow = new GodotImGuiWindow(ImGui.GetMainViewport(), window, mainSubViewport);
}
private static void Godot_CreateWindow(ImGuiViewportPtr vp)
@@ -368,7 +286,7 @@ private static void Godot_DestroyWindow(ImGuiViewportPtr vp)
{
if (vp.PlatformUserData != IntPtr.Zero)
{
- var window = (IViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
+ var window = (GodotImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
window.Dispose();
vp.PlatformUserData = IntPtr.Zero;
}
@@ -376,55 +294,55 @@ private static void Godot_DestroyWindow(ImGuiViewportPtr vp)
private static void Godot_ShowWindow(ImGuiViewportPtr vp)
{
- var window = (IViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
+ var window = (GodotImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
window.ShowWindow();
}
private static void Godot_SetWindowPos(ImGuiViewportPtr vp, Vector2 pos)
{
- var window = (IViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
+ var window = (GodotImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
window.SetWindowPos(pos.ToVector2I());
}
private static void Godot_GetWindowPos(ImGuiViewportPtr vp, out Vector2 pos)
{
- var window = (IViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
+ var window = (GodotImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
pos = window.GetWindowPos().ToImVec2();
}
private static void Godot_SetWindowSize(ImGuiViewportPtr vp, Vector2 size)
{
- var window = (IViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
+ var window = (GodotImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
window.SetWindowSize(size.ToVector2I());
}
private static void Godot_GetWindowSize(ImGuiViewportPtr vp, out Vector2 size)
{
- var window = (IViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
+ var window = (GodotImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
size = window.GetWindowSize().ToImVec2();
}
private static void Godot_SetWindowFocus(ImGuiViewportPtr vp)
{
- var window = (IViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
+ var window = (GodotImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
window.SetWindowFocus();
}
private static bool Godot_GetWindowFocus(ImGuiViewportPtr vp)
{
- var window = (IViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
+ var window = (GodotImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
return window.GetWindowFocus();
}
private static bool Godot_GetWindowMinimized(ImGuiViewportPtr vp)
{
- var window = (IViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
+ var window = (GodotImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
return window.GetWindowMinimized();
}
private static void Godot_SetWindowTitle(ImGuiViewportPtr vp, string title)
{
- var window = (IViewportWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
+ var window = (GodotImGuiWindow)GCHandle.FromIntPtr(vp.PlatformUserData).Target!;
window.SetWindowTitle(title);
}
}
diff --git a/addons/imgui-godot/scripts/ImGuiPlugin.gd b/addons/imgui-godot/scripts/ImGuiPlugin.gd
index cb2eb22..36b657b 100644
--- a/addons/imgui-godot/scripts/ImGuiPlugin.gd
+++ b/addons/imgui-godot/scripts/ImGuiPlugin.gd
@@ -2,17 +2,18 @@
extends EditorPlugin
func _enter_tree():
+ Engine.register_singleton("ImGuiPlugin", self)
+ add_autoload_singleton("ImGuiRoot", "res://addons/imgui-godot/data/ImGuiRoot.tscn")
+
+ # remove obsolete ImGuiLayer autoload
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)
+ # warn user if csproj will fail to build
if "C#" in ProjectSettings.get_setting("application/config/features"):
var projPath: String = ProjectSettings.get_setting("dotnet/project/solution_directory")
var fn: String = "%s.csproj" % ProjectSettings.get_setting("dotnet/project/assembly_name")
- if projPath != "":
- fn = "%s/%s" % [projPath, fn]
- check_csproj(fn)
+ check_csproj(projPath.path_join(fn))
func check_csproj(fn):
var fi := FileAccess.open(fn, FileAccess.READ)
@@ -29,12 +30,10 @@ func check_csproj(fn):
if netVer < 8:
changesNeeded += "- Set target framework to .NET 8 or later\n"
- idx = data.find("True")
- if idx == -1:
+ if !data.contains("True"):
changesNeeded += "- Allow unsafe blocks\n"
- idx = data.find(",debug,release>.x86_64")
+
+set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/project")
+
+install(TARGETS gdexample
+ RUNTIME DESTINATION bin
+ )
diff --git a/doc/examples/GDExt/src/example.cpp b/doc/examples/GDExt/src/example.cpp
index 9ab33ab..553c603 100644
--- a/doc/examples/GDExt/src/example.cpp
+++ b/doc/examples/GDExt/src/example.cpp
@@ -18,7 +18,6 @@ Example::~Example()
void Example::_ready()
{
- ImGui::Godot::SyncImGuiPtrs();
_img = ResourceLoader::get_singleton()->load("res://robot_eye.tres");
}
diff --git a/doc/examples/GDExt/src/register_types.cpp b/doc/examples/GDExt/src/register_types.cpp
index 24f9ad8..a786728 100644
--- a/doc/examples/GDExt/src/register_types.cpp
+++ b/doc/examples/GDExt/src/register_types.cpp
@@ -5,15 +5,16 @@
#include
#include
#include
+#include
using namespace godot;
void initialize_example_module(ModuleInitializationLevel p_level)
{
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE)
- {
return;
- }
+
+ ImGui::Godot::SyncImGuiPtrs();
GDREGISTER_CLASS(Example);
}
@@ -21,9 +22,7 @@ void initialize_example_module(ModuleInitializationLevel p_level)
void uninitialize_example_module(ModuleInitializationLevel p_level)
{
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE)
- {
return;
- }
}
extern "C" {
diff --git a/doc/icon.png b/doc/icon.png
new file mode 100644
index 0000000..b0f7be9
Binary files /dev/null and b/doc/icon.png differ
diff --git a/gdext/godot-cpp b/gdext/godot-cpp
index 98c143a..b28098e 160000
--- a/gdext/godot-cpp
+++ b/gdext/godot-cpp
@@ -1 +1 @@
-Subproject commit 98c143a48365f3f3bf5f99d6289a2cb25e6472d1
+Subproject commit b28098e76b84e8831b8ac68d490f4bca44678b2a
diff --git a/gdext/include/imgui-godot.h b/gdext/include/imgui-godot.h
index 8941067..a7f39a2 100644
--- a/gdext/include/imgui-godot.h
+++ b/gdext/include/imgui-godot.h
@@ -38,6 +38,7 @@ using godot::SubViewport;
using godot::Texture2D;
using godot::TypedArray;
using godot::Vector2;
+using godot::Viewport;
using godot::Window;
#else
// module
@@ -133,6 +134,13 @@ inline void SetVisible(bool vis)
detail::ImGuiGD->set(sn, vis);
}
+inline void SetMainViewport(Viewport* vp)
+{
+ ERR_FAIL_COND(!detail::GET_IMGUIGD());
+ static const StringName sn("SetMainViewport");
+ detail::ImGuiGD->set(sn, vp);
+}
+
inline bool ToolInit()
{
ERR_FAIL_COND_V(!detail::GET_IMGUIGD(), false);
@@ -142,14 +150,16 @@ inline bool ToolInit()
inline void SyncImGuiPtrs()
{
- ERR_FAIL_COND(!detail::GET_IMGUIGD());
+ Object* obj = ClassDB::instantiate("ImGuiSync");
+ ERR_FAIL_COND(!obj);
+
static const StringName sn("GetImGuiPtrs");
- TypedArray ptrs = detail::ImGuiGD->call(sn,
- String(ImGui::GetVersion()),
- (int32_t)sizeof(ImGuiIO),
- (int32_t)sizeof(ImDrawVert),
- (int32_t)sizeof(ImDrawIdx),
- (int32_t)sizeof(ImWchar));
+ TypedArray ptrs = obj->call(sn,
+ String(ImGui::GetVersion()),
+ (int32_t)sizeof(ImGuiIO),
+ (int32_t)sizeof(ImDrawVert),
+ (int32_t)sizeof(ImDrawIdx),
+ (int32_t)sizeof(ImWchar));
ERR_FAIL_COND(ptrs.size() != 3);
@@ -157,6 +167,7 @@ inline void SyncImGuiPtrs()
ImGuiMemAllocFunc alloc_func = reinterpret_cast((int64_t)ptrs[1]);
ImGuiMemFreeFunc free_func = reinterpret_cast((int64_t)ptrs[2]);
ImGui::SetAllocatorFunctions(alloc_func, free_func, nullptr);
+ memdelete(obj);
}
inline ImTextureID BindTexture(Texture2D* tex)
diff --git a/gdext/src/CMakeLists.txt b/gdext/src/CMakeLists.txt
index c1003e4..b96616c 100644
--- a/gdext/src/CMakeLists.txt
+++ b/gdext/src/CMakeLists.txt
@@ -11,14 +11,20 @@ target_sources(imgui-godot-native PRIVATE
GdsCache.h
ImGuiAPI.cpp
ImGuiAPI.h
+ ImGuiController.cpp
+ ImGuiController.h
+ ImGuiControllerHelper.cpp
+ ImGuiControllerHelper.h
ImGuiGD.cpp
ImGuiGD.h
ImGuiLayer.cpp
ImGuiLayer.h
- ImGuiLayerHelper.cpp
- ImGuiLayerHelper.h
+ ImGuiSync.cpp
+ ImGuiSync.h
Input.cpp
Input.h
+ InputLocal.cpp
+ InputLocal.h
main.cpp
RdRenderer.cpp
RdRenderer.h
diff --git a/gdext/src/Context.cpp b/gdext/src/Context.cpp
index 703bdf4..9b1537e 100644
--- a/gdext/src/Context.cpp
+++ b/gdext/src/Context.cpp
@@ -18,10 +18,10 @@ Context* GetContext()
return ctx.get();
}
-Context::Context(Window* mainWindow, RID mainSubViewport, std::unique_ptr r)
+Context::Context(std::unique_ptr r)
{
renderer = std::move(r);
- input = std::make_unique(mainWindow);
+ input = std::make_unique();
fonts = std::make_unique();
ImGuiIO& io = ImGui::GetIO();
@@ -32,7 +32,7 @@ Context::Context(Window* mainWindow, RID mainSubViewport, std::unique_ptrName();
- viewports = std::make_unique(mainWindow, mainSubViewport);
+ viewports = std::make_unique();
}
Context::~Context()
@@ -41,7 +41,7 @@ Context::~Context()
ImGui::DestroyContext();
}
-void Init(godot::Window* mainWindow, RID mainSubViewport, const Ref& cfg)
+void Init(const Ref& cfg)
{
// re-init not allowed
ERR_FAIL_COND(ctx);
@@ -99,9 +99,8 @@ void Init(godot::Window* mainWindow, RID mainSubViewport, const Ref& c
renderer->Init();
}
- ctx = std::make_unique(mainWindow, mainSubViewport, std::move(renderer));
+ ctx = std::make_unique(std::move(renderer));
ctx->scale = cfg->get("Scale");
- ctx->renderer->InitViewport(mainSubViewport);
String iniFilename = cfg->get("IniFilename");
if (iniFilename.length() > 0)
@@ -124,34 +123,23 @@ void Init(godot::Window* mainWindow, RID mainSubViewport, const Ref& c
RebuildFontAtlas();
}
-void Update(double delta, Vector2 displaySize)
+void Context::Update(double delta, Vector2 displaySize)
{
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize = displaySize;
io.DeltaTime = static_cast(delta);
- ctx->input->Update();
+ input->Update();
gdscache->OnNewFrame();
ImGui::NewFrame();
}
-bool ProcessInput(const Ref& evt, Window* window)
-{
- return ctx->input->ProcessInput(evt, window);
-}
-
-void ProcessNotification(int what)
-{
- if (ctx)
- ctx->input->ProcessNotification(what);
-}
-
-void Render()
+void Context::Render()
{
ImGui::Render();
ImGui::UpdatePlatformWindows();
- ctx->renderer->Render();
+ renderer->Render();
}
void Shutdown()
@@ -163,9 +151,9 @@ void Shutdown()
void Connect(const godot::Callable& callable)
{
- Object* igl = Engine::get_singleton()->get_singleton("ImGuiLayer");
- ERR_FAIL_COND(!igl);
- igl->connect("imgui_layout", callable);
+ Object* igc = Engine::get_singleton()->get_singleton("ImGuiController");
+ ERR_FAIL_COND(!igc);
+ igc->connect("imgui_layout", callable);
}
void ResetFonts()
@@ -189,6 +177,8 @@ void AddFontDefault()
void RebuildFontAtlas()
{
ERR_FAIL_COND(!ctx);
+ ERR_FAIL_COND(ctx->inProcessFrame);
+
bool scaleToDpi = ProjectSettings::get_singleton()->get_setting("display/window/dpi/allow_hidpi");
int dpiFactor = std::max(1, DisplayServer::get_singleton()->screen_get_dpi() / 96);
ctx->fonts->RebuildFontAtlas(scaleToDpi ? dpiFactor * ctx->scale : ctx->scale);
@@ -210,11 +200,6 @@ void SetIniFilename(const String& fn)
io.IniFilename = nullptr;
}
-void OnFramePreDraw()
-{
- ctx->renderer->OnFramePreDraw();
-}
-
bool SubViewportWidget(SubViewport* svp)
{
ImVec2 vpSize = svp->get_size();
diff --git a/gdext/src/Context.h b/gdext/src/Context.h
index ab2a9ff..ead82d4 100644
--- a/gdext/src/Context.h
+++ b/gdext/src/Context.h
@@ -22,6 +22,7 @@
#include "Fonts.h"
#include "GdsCache.h"
#include "ImGuiGD.h"
+#include "ImGuiLayer.h"
#include "Input.h"
#include "RdRenderer.h"
#include "RdRendererThreadSafe.h"
@@ -45,19 +46,24 @@ struct Context
std::unique_ptr fonts;
std::unique_ptr input;
std::unique_ptr renderer;
+
float scale = 1.0f;
+ float joyAxisDeadZone = 0.15f;
+ int layerNum = 128;
+ Vector2i viewportSize;
+ ImGuiLayer* layer = nullptr;
+ bool inProcessFrame = false;
- Context(Window* mainWindow, RID mainSubViewport, std::unique_ptr r);
+ Context(std::unique_ptr r);
~Context();
+
+ void Render();
+ void Update(double delta, Vector2 displaySize);
};
Context* GetContext();
-void Init(Window* mainWindow, RID mainSubViewport, const Ref& config);
-void Update(double delta, Vector2 displaySize);
-bool ProcessInput(const Ref& evt, Window* window);
-void ProcessNotification(int what);
-void Render();
+void Init(const Ref& config);
void Shutdown();
void Connect(const Callable& callable);
void ResetFonts();
@@ -69,6 +75,4 @@ void SetIniFilename(const String& fn);
void SetVisible(bool visible);
bool SubViewportWidget(SubViewport* svp);
-
-void OnFramePreDraw();
} // namespace ImGui::Godot
diff --git a/gdext/src/ImGuiController.cpp b/gdext/src/ImGuiController.cpp
new file mode 100644
index 0000000..20e1f22
--- /dev/null
+++ b/gdext/src/ImGuiController.cpp
@@ -0,0 +1,171 @@
+#include "ImGuiController.h"
+#include "Context.h"
+#include "ImGuiControllerHelper.h"
+#include "ImGuiLayer.h"
+#include "Input.h"
+#include "InputLocal.h"
+#include
+#include
+#include
+#include
+
+namespace ImGui::Godot {
+
+namespace {
+ImGuiController* instance = nullptr;
+}
+
+struct ImGuiController::Impl
+{
+ Window* window;
+ ImGuiControllerHelper* helper = nullptr;
+
+ void CheckContentScale() const;
+};
+
+void ImGuiController::Impl::CheckContentScale() const
+{
+ if (window->get_content_scale_mode() == Window::CONTENT_SCALE_MODE_VIEWPORT)
+ {
+ UtilityFunctions::printerr("imgui-godot: scale mode `viewport` is unsupported");
+ }
+}
+
+
+ImGuiController* ImGuiController::Instance()
+{
+ return instance;
+}
+
+void ImGuiController::_bind_methods()
+{
+ ADD_SIGNAL(MethodInfo("imgui_layout"));
+ ClassDB::bind_method(D_METHOD("on_frame_pre_draw"), &ImGuiController::on_frame_pre_draw);
+ ClassDB::bind_method(D_METHOD("OnLayerExiting"), &ImGuiController::OnLayerExiting);
+}
+
+ImGuiController::ImGuiController() : impl(std::make_unique())
+{
+}
+
+ImGuiController::~ImGuiController()
+{
+}
+
+void ImGuiController::_enter_tree()
+{
+ instance = this;
+
+ set_name("ImGuiController");
+ Engine::get_singleton()->register_singleton("ImGuiController", this);
+ impl->window = get_window();
+
+ impl->CheckContentScale();
+
+ Ref cfgPackedScene = ResourceLoader::get_singleton()->load("res://addons/imgui-godot/Config.tscn");
+ Node* cfgScene = cfgPackedScene->instantiate();
+ Ref cfg = cfgScene->get("Config");
+ memdelete(cfgScene);
+
+ if (cfg.is_null())
+ {
+ Ref script = ResourceLoader::get_singleton()->load("res://addons/imgui-godot/scripts/ImGuiConfig.gd");
+ cfg = script->new_();
+ }
+
+ ImGui::Godot::Init(cfg);
+
+ impl->helper = memnew(ImGuiControllerHelper);
+ add_child(impl->helper);
+
+ SetMainViewport(impl->window);
+}
+
+void ImGuiController::_ready()
+{
+ set_process_priority(std::numeric_limits::max());
+}
+
+void ImGuiController::_exit_tree()
+{
+ ImGui::Godot::Shutdown();
+}
+
+void ImGuiController::_process(double delta)
+{
+#ifdef DEBUG_ENABLED
+ if (Engine::get_singleton()->is_editor_hint())
+ {
+ // verify signal connections
+ auto conns = get_signal_connection_list("imgui_layout");
+ for (int i = 0; i < conns.size(); ++i)
+ {
+ const Dictionary& conn = conns[i];
+ const Callable& cb = conn["callable"];
+ if (!cb.is_valid())
+ disconnect("imgui_layout", cb);
+ }
+ }
+#endif
+
+ Context* ctx = GetContext();
+ ctx->layer->UpdateViewport();
+ emit_signal("imgui_layout");
+ ctx->Render();
+ ctx->inProcessFrame = false;
+}
+
+void ImGuiController::_notification(int p_what)
+{
+ Context* ctx = GetContext();
+ if (ctx)
+ ctx->input->ProcessNotification(p_what);
+}
+
+void ImGuiController::OnLayerExiting()
+{
+ // an ImGuiLayer is being destroyed without calling SetMainViewport
+ if (GetContext()->layer->get_viewport() != impl->window)
+ {
+ // revert to main window
+ SetMainViewport(impl->window);
+ }
+}
+
+void ImGuiController::SetMainViewport(Viewport* vp)
+{
+ Context* ctx = GetContext();
+ ImGuiLayer* oldLayer = ctx->layer;
+ if (oldLayer)
+ {
+ oldLayer->disconnect("tree_exiting", Callable(this, "OnLayerExiting"));
+ oldLayer->queue_free();
+ }
+
+ ImGuiLayer* newLayer = memnew(ImGuiLayer);
+ newLayer->connect("tree_exiting", Callable(this, "OnLayerExiting"));
+
+ if (vp->get_class() == "Window")
+ {
+ ctx->input = std::make_unique();
+ if (vp == impl->window)
+ add_child(newLayer);
+ else
+ vp->add_child(newLayer);
+ ImGui::GetIO().BackendFlags |= ImGuiBackendFlags_PlatformHasViewports;
+ }
+ else
+ {
+ ctx->input = std::make_unique();
+ vp->add_child(newLayer);
+ ImGui::GetIO().BackendFlags &= ~ImGuiBackendFlags_PlatformHasViewports;
+ }
+ ctx->layer = newLayer;
+}
+
+void ImGuiController::on_frame_pre_draw()
+{
+ GetContext()->renderer->OnFramePreDraw();
+}
+
+} // namespace ImGui::Godot
diff --git a/gdext/src/ImGuiController.h b/gdext/src/ImGuiController.h
new file mode 100644
index 0000000..f508360
--- /dev/null
+++ b/gdext/src/ImGuiController.h
@@ -0,0 +1,37 @@
+#pragma once
+#include
+#include
+
+using namespace godot;
+
+namespace ImGui::Godot {
+
+class ImGuiController : public Node
+{
+ GDCLASS(ImGuiController, Node);
+
+protected:
+ static void _bind_methods();
+
+public:
+ static ImGuiController* Instance();
+
+ ImGuiController();
+ ~ImGuiController();
+
+ void _ready() override;
+ void _enter_tree() override;
+ void _exit_tree() override;
+ void _process(double delta) override;
+ void _notification(int p_what);
+ void SetMainViewport(Viewport* vp);
+
+ void OnLayerExiting();
+ void on_frame_pre_draw();
+
+private:
+ struct Impl;
+ std::unique_ptr impl;
+};
+
+} // namespace ImGui::Godot
diff --git a/gdext/src/ImGuiControllerHelper.cpp b/gdext/src/ImGuiControllerHelper.cpp
new file mode 100644
index 0000000..a670165
--- /dev/null
+++ b/gdext/src/ImGuiControllerHelper.cpp
@@ -0,0 +1,41 @@
+#include "ImGuiControllerHelper.h"
+#include "Context.h"
+using namespace godot;
+
+namespace ImGui::Godot {
+
+ImGuiControllerHelper::ImGuiControllerHelper()
+{
+}
+
+ImGuiControllerHelper::~ImGuiControllerHelper()
+{
+}
+
+void ImGuiControllerHelper::_bind_methods()
+{
+}
+
+void ImGuiControllerHelper::_enter_tree()
+{
+}
+
+void ImGuiControllerHelper::_ready()
+{
+ set_name("ImGuiControllerHelper");
+ set_process_priority(std::numeric_limits::min());
+ set_process_mode(Node::PROCESS_MODE_ALWAYS);
+}
+
+void ImGuiControllerHelper::_exit_tree()
+{
+}
+
+void ImGuiControllerHelper::_process(double delta)
+{
+ Context* ctx = GetContext();
+ ctx->inProcessFrame = true;
+ ctx->Update(delta, ctx->viewportSize);
+}
+
+} // namespace ImGui::Godot
diff --git a/gdext/src/ImGuiLayerHelper.h b/gdext/src/ImGuiControllerHelper.h
similarity index 56%
rename from gdext/src/ImGuiLayerHelper.h
rename to gdext/src/ImGuiControllerHelper.h
index 8d0a562..2f77048 100644
--- a/gdext/src/ImGuiLayerHelper.h
+++ b/gdext/src/ImGuiControllerHelper.h
@@ -1,16 +1,13 @@
#pragma once
#include
-#include
-using godot::InputEvent;
using godot::Node;
-using godot::Ref;
namespace ImGui::Godot {
-class ImGuiLayerHelper : public Node
+class ImGuiControllerHelper : public Node
{
- GDCLASS(ImGuiLayerHelper, Node);
+ GDCLASS(ImGuiControllerHelper, Node);
protected:
static void _bind_methods();
@@ -21,12 +18,8 @@ class ImGuiLayerHelper : public Node
void _exit_tree() override;
void _process(double delta) override;
- ImGuiLayerHelper();
- ~ImGuiLayerHelper();
-
-private:
- struct Impl;
- std::unique_ptr impl;
+ ImGuiControllerHelper();
+ ~ImGuiControllerHelper();
};
} // namespace ImGui::Godot
diff --git a/gdext/src/ImGuiGD.cpp b/gdext/src/ImGuiGD.cpp
index 48be0d4..bf5e715 100644
--- a/gdext/src/ImGuiGD.cpp
+++ b/gdext/src/ImGuiGD.cpp
@@ -1,5 +1,6 @@
#include "ImGuiGD.h"
#include "Context.h"
+#include "ImGuiController.h"
#include "ImGuiLayer.h"
#include "common.h"
#include
@@ -32,6 +33,8 @@ void ImGuiGD::_bind_methods()
ClassDB::bind_method(D_METHOD("Connect", "callable"), &ImGuiGD::Connect);
ClassDB::bind_method(D_METHOD("RebuildFontAtlas"), &ImGuiGD::RebuildFontAtlas);
ClassDB::bind_method(D_METHOD("ResetFonts"), &ImGuiGD::ResetFonts);
+ ClassDB::bind_method(D_METHOD("SetMainViewport", "vp"), &ImGuiGD::SetMainViewport);
+
ClassDB::bind_method(D_METHOD("SubViewport", "svp"), &ImGuiGD::SubViewport);
ClassDB::bind_method(D_METHOD("GetImGuiPtrs", "version", "ioSize", "vertSize", "idxSize", "charSize"),
&ImGuiGD::GetImGuiPtrs);
@@ -96,20 +99,26 @@ void ImGuiGD::RebuildFontAtlas()
ImGui::Godot::RebuildFontAtlas();
}
+void ImGuiGD::SetMainViewport(Viewport* vp)
+{
+ ImGuiController* igc = Object::cast_to(Engine::get_singleton()->get_singleton("ImGuiController"));
+ ERR_FAIL_COND(!igc);
+ igc->SetMainViewport(vp);
+}
+
void ImGuiGD::_SetVisible(bool visible)
{
- CanvasLayer* igl = Object::cast_to(Engine::get_singleton()->get_singleton("ImGuiLayer"));
- ERR_FAIL_COND(!igl);
- igl->set_visible(visible);
+ Context* ctx = GetContext();
+ ERR_FAIL_COND(!ctx);
+ ERR_FAIL_COND(!ctx->layer);
+ ctx->layer->set_visible(visible);
}
bool ImGuiGD::_GetVisible()
{
- CanvasLayer* igl = nullptr;
- if (Engine::get_singleton()->has_singleton("ImGuiLayer"))
- igl = Object::cast_to(Engine::get_singleton()->get_singleton("ImGuiLayer"));
- if (igl)
- return igl->is_visible();
+ Context* ctx = GetContext();
+ if (ctx && ctx->layer)
+ return ctx->layer->is_visible();
return false;
}
@@ -117,14 +126,14 @@ void ImGuiGD::_SetJoyAxisDeadZone(float zone)
{
Context* ctx = ImGui::Godot::GetContext();
ERR_FAIL_COND(!ctx);
- ctx->input->SetJoyAxisDeadZone(zone);
+ ctx->joyAxisDeadZone = zone;
}
float ImGuiGD::_GetJoyAxisDeadZone()
{
Context* ctx = ImGui::Godot::GetContext();
if (ctx)
- return ctx->input->GetJoyAxisDeadZone();
+ return ctx->joyAxisDeadZone;
return 0.15f;
}
diff --git a/gdext/src/ImGuiGD.h b/gdext/src/ImGuiGD.h
index 02ab303..bbaedfb 100644
--- a/gdext/src/ImGuiGD.h
+++ b/gdext/src/ImGuiGD.h
@@ -37,6 +37,8 @@ class ImGuiGD : public Object
void _SetScale(float scale);
float _GetScale();
+ void SetMainViewport(Viewport* vp);
+
PackedInt64Array GetFontPtrs();
PackedInt64Array GetImGuiPtrs(String version, int ioSize, int vertSize, int idxSize, int charSize);
diff --git a/gdext/src/ImGuiLayer.cpp b/gdext/src/ImGuiLayer.cpp
index baf89f7..3d61ba0 100644
--- a/gdext/src/ImGuiLayer.cpp
+++ b/gdext/src/ImGuiLayer.cpp
@@ -1,6 +1,6 @@
#include "ImGuiLayer.h"
#include "Context.h"
-#include "ImGuiLayerHelper.h"
+#include "ImGuiControllerHelper.h"
#include
#include
@@ -19,17 +19,14 @@ namespace ImGui::Godot {
struct ImGuiLayer::Impl
{
- ImGuiLayerHelper* helper = nullptr;
- Window* window = nullptr;
RID subViewportRid;
Vector2i subViewportSize{0, 0};
RID canvasItem;
Transform2D finalTransform{1.f, 0.f, 0.f, 1.f, 0.f, 0.f}; // identity
bool visible = true;
- Ref cfg;
+ Viewport* parentViewport = nullptr;
static RID AddLayerSubViewport(Node* parent);
- void CheckContentScale() const;
};
RID ImGuiLayer::Impl::AddLayerSubViewport(Node* parent)
@@ -44,14 +41,6 @@ RID ImGuiLayer::Impl::AddLayerSubViewport(Node* parent)
return svp;
}
-void ImGuiLayer::Impl::CheckContentScale() const
-{
- if (window->get_content_scale_mode() == Window::CONTENT_SCALE_MODE_VIEWPORT)
- {
- UtilityFunctions::printerr("imgui-godot: scale mode `viewport` is unsupported");
- }
-}
-
ImGuiLayer::ImGuiLayer() : impl(std::make_unique())
{
}
@@ -62,90 +51,75 @@ ImGuiLayer::~ImGuiLayer()
void ImGuiLayer::_bind_methods()
{
- ADD_SIGNAL(MethodInfo("imgui_layout"));
ClassDB::bind_method(D_METHOD("on_visibility_changed"), &ImGuiLayer::on_visibility_changed);
- ClassDB::bind_method(D_METHOD("on_frame_pre_draw"), &ImGuiLayer::on_frame_pre_draw);
}
void ImGuiLayer::_enter_tree()
{
- Node* parent = get_parent();
- if (!parent)
- return;
- if (Engine::get_singleton()->has_singleton("ImGuiLayer"))
- return;
-
+ Context* ctx = GetContext();
set_name("ImGuiLayer");
- Engine::get_singleton()->register_singleton("ImGuiLayer", this);
- impl->window = get_window();
+ set_layer(ctx->layerNum);
- impl->CheckContentScale();
+ impl->parentViewport = get_viewport();
+ impl->subViewportRid = Impl::AddLayerSubViewport(this);
RenderingServer* RS = RenderingServer::get_singleton();
-
- impl->subViewportRid = Impl::AddLayerSubViewport(this);
impl->canvasItem = RS->canvas_item_create();
RS->canvas_item_set_parent(impl->canvasItem, get_canvas());
- Ref cfgPackedScene = ResourceLoader::get_singleton()->load("res://addons/imgui-godot/Config.tscn");
- Node* cfgScene = cfgPackedScene->instantiate();
- Ref cfg = cfgScene->get("Config");
- memdelete(cfgScene);
-
- if (cfg.is_null())
- {
- Ref script = ResourceLoader::get_singleton()->load("res://addons/imgui-godot/scripts/ImGuiConfig.gd");
- cfg = script->new_();
- }
- impl->cfg = cfg;
-
- set_layer(cfg->get("Layer"));
-
- impl->helper = memnew(ImGuiLayerHelper);
- add_child(impl->helper);
-
- ImGui::Godot::Init(get_window(), impl->subViewportRid, cfg);
+ ctx->renderer->InitViewport(impl->subViewportRid);
+ ctx->viewports->SetMainWindow(get_window(), impl->subViewportRid);
}
void ImGuiLayer::_ready()
{
- set_process_priority(std::numeric_limits::max());
- set_process_mode(Node::PROCESS_MODE_ALWAYS);
-
connect("visibility_changed", Callable(this, "on_visibility_changed"));
}
void ImGuiLayer::_exit_tree()
{
- Engine::get_singleton()->unregister_singleton("ImGuiLayer");
- ImGui::Godot::Shutdown();
RenderingServer::get_singleton()->free_rid(impl->canvasItem);
RenderingServer::get_singleton()->free_rid(impl->subViewportRid);
}
-void ImGuiLayer::_process(double delta)
+void ImGuiLayer::on_visibility_changed()
{
-#ifdef DEBUG_ENABLED
- if (Engine::get_singleton()->is_editor_hint())
+ impl->visible = is_visible();
+ if (impl->visible)
{
- // verify signal connections
- auto conns = get_signal_connection_list("imgui_layout");
- for (int i = 0; i < conns.size(); ++i)
- {
- const Dictionary& conn = conns[i];
- const Callable& cb = conn["callable"];
- if (!cb.is_valid())
- disconnect("imgui_layout", cb);
- }
+ set_process_input(true);
}
-#endif
+ else
+ {
+ set_process_input(false);
+ ImGui::Godot::GetContext()->renderer->OnHide();
+ impl->subViewportSize = {0, 0};
+ RenderingServer::get_singleton()->canvas_item_clear(impl->canvasItem);
+ }
+}
+
+void ImGuiLayer::_input(const Ref& event)
+{
+ if (GetContext()->input->ProcessInput(event))
+ {
+ impl->parentViewport->set_input_as_handled();
+ }
+}
+void ImGuiLayer::UpdateViewport()
+{
if (impl->visible)
{
- Vector2i winSize = impl->window->get_size();
- Transform2D ft = impl->window->get_final_transform();
+ Vector2i vpSize;
+ if (Window* w = Object::cast_to(impl->parentViewport))
+ vpSize = w->get_size();
+ else
+ vpSize = Object::cast_to(impl->parentViewport)->get_size();
+ GetContext()->viewportSize = vpSize;
- if (impl->subViewportSize != winSize ||
+ Transform2D ft = impl->parentViewport->get_final_transform();
+
+ if (impl->subViewportSize != vpSize ||
impl->finalTransform != ft
#ifdef DEBUG_ENABLED
// force redraw on every frame in editor
@@ -154,7 +128,7 @@ void ImGuiLayer::_process(double delta)
)
{
// this is more or less how SubViewportContainer works
- impl->subViewportSize = winSize;
+ impl->subViewportSize = vpSize;
impl->finalTransform = ft;
RenderingServer* RS = RenderingServer::get_singleton();
@@ -166,49 +140,7 @@ void ImGuiLayer::_process(double delta)
Rect2(0, 0, impl->subViewportSize.x, impl->subViewportSize.y),
vptex);
}
-
- emit_signal("imgui_layout");
- }
-
- ImGui::Godot::Render();
-}
-
-void ImGuiLayer::_input(const Ref& event)
-{
- if (ImGui::Godot::ProcessInput(event, impl->window))
- {
- impl->window->set_input_as_handled();
- }
-}
-
-void ImGuiLayer::_notification(int p_what)
-{
- // quick filter
- if (p_what > 2000)
- {
- ImGui::Godot::ProcessNotification(p_what);
- }
-}
-
-void ImGuiLayer::on_visibility_changed()
-{
- impl->visible = is_visible();
- if (impl->visible)
- {
- set_process_input(true);
- }
- else
- {
- set_process_input(false);
- ImGui::Godot::GetContext()->renderer->OnHide();
- impl->subViewportSize = {0, 0};
- RenderingServer::get_singleton()->canvas_item_clear(impl->canvasItem);
}
}
-void ImGuiLayer::on_frame_pre_draw()
-{
- ImGui::Godot::OnFramePreDraw();
-}
-
} // namespace ImGui::Godot
diff --git a/gdext/src/ImGuiLayer.h b/gdext/src/ImGuiLayer.h
index 91b24b3..3b93b77 100644
--- a/gdext/src/ImGuiLayer.h
+++ b/gdext/src/ImGuiLayer.h
@@ -21,11 +21,10 @@ class ImGuiLayer : public CanvasLayer
void _ready() override;
void _enter_tree() override;
void _exit_tree() override;
- void _process(double delta) override;
void _input(const Ref& event) override;
- void _notification(int p_what);
+
void on_visibility_changed();
- void on_frame_pre_draw();
+ void UpdateViewport();
private:
struct Impl;
diff --git a/gdext/src/ImGuiLayerHelper.cpp b/gdext/src/ImGuiLayerHelper.cpp
deleted file mode 100644
index 8188583..0000000
--- a/gdext/src/ImGuiLayerHelper.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#include "ImGuiLayerHelper.h"
-#include "Context.h"
-#include "imgui-godot.h"
-#include
-#include
-#include
-#include
-using namespace godot;
-
-namespace ImGui::Godot {
-
-struct ImGuiLayerHelper::Impl
-{
- Window* window;
-};
-
-ImGuiLayerHelper::ImGuiLayerHelper() : impl(std::make_unique())
-{
-}
-
-ImGuiLayerHelper::~ImGuiLayerHelper()
-{
-}
-
-void ImGuiLayerHelper::_bind_methods()
-{
-}
-
-void ImGuiLayerHelper::_enter_tree()
-{
-}
-
-void ImGuiLayerHelper::_ready()
-{
- set_name("ImGuiLayerHelper");
- set_process_priority(std::numeric_limits::min());
- set_process_mode(Node::PROCESS_MODE_ALWAYS);
- impl->window = get_window();
-}
-
-void ImGuiLayerHelper::_exit_tree()
-{
-}
-
-void ImGuiLayerHelper::_process(double delta)
-{
- ImGui::Godot::Update(delta, impl->window->get_size());
-}
-
-} // namespace ImGui::Godot
diff --git a/gdext/src/ImGuiSync.cpp b/gdext/src/ImGuiSync.cpp
new file mode 100644
index 0000000..95f99af
--- /dev/null
+++ b/gdext/src/ImGuiSync.cpp
@@ -0,0 +1,35 @@
+#include "ImGuiSync.h"
+#include
+#include
+
+namespace ImGui::Godot {
+
+void ImGuiSync::_bind_methods()
+{
+ ClassDB::bind_static_method("ImGuiSync", D_METHOD("GetImGuiPtrs"), &ImGuiSync::GetImGuiPtrs);
+}
+
+PackedInt64Array ImGuiSync::GetImGuiPtrs(String version, int ioSize, int vertSize, int idxSize, int charSize)
+{
+ if (version != String(ImGui::GetVersion()) || ioSize != sizeof(ImGuiIO) || vertSize != sizeof(ImDrawVert) ||
+ idxSize != sizeof(ImDrawIdx) || charSize != sizeof(ImWchar))
+ {
+ UtilityFunctions::push_error("ImGui version mismatch, use v", ImGui::GetVersion(), "-docking");
+ return {};
+ }
+
+ ImGuiMemAllocFunc alloc_func = nullptr;
+ ImGuiMemFreeFunc free_func = nullptr;
+ void* user_data = nullptr;
+
+ ImGui::GetAllocatorFunctions(&alloc_func, &free_func, &user_data);
+
+ PackedInt64Array rv;
+ rv.resize(3);
+ rv[0] = reinterpret_cast(ImGui::GetCurrentContext());
+ rv[1] = reinterpret_cast(alloc_func);
+ rv[2] = reinterpret_cast(free_func);
+ return rv;
+}
+
+} // namespace ImGui::Godot
diff --git a/gdext/src/ImGuiSync.h b/gdext/src/ImGuiSync.h
new file mode 100644
index 0000000..a1f4fb7
--- /dev/null
+++ b/gdext/src/ImGuiSync.h
@@ -0,0 +1,19 @@
+#pragma once
+#include
+
+using namespace godot;
+
+namespace ImGui::Godot {
+
+class ImGuiSync : public Object
+{
+ GDCLASS(ImGuiSync, Object);
+
+protected:
+ static void _bind_methods();
+
+public:
+ static PackedInt64Array GetImGuiPtrs(String version, int ioSize, int vertSize, int idxSize, int charSize);
+};
+
+} // namespace ImGui::Godot
diff --git a/gdext/src/Input.cpp b/gdext/src/Input.cpp
index 6244d60..adc1bb4 100644
--- a/gdext/src/Input.cpp
+++ b/gdext/src/Input.cpp
@@ -1,4 +1,5 @@
#include "Input.h"
+#include "Context.h"
#include "imgui-godot.h"
#include
@@ -21,16 +22,12 @@ namespace ImGui::Godot {
struct Input::Impl
{
- Window* mainWindow = nullptr;
godot::SubViewport* previousSubViewport = nullptr;
godot::SubViewport* currentSubViewport = nullptr;
Vector2 currentSubViewportPos;
Vector2 mouseWheel;
ImGuiMouseCursor currentCursor = ImGuiMouseCursor_None;
bool hasMouse;
- float deadZone = 0.15f;
-
- void UpdateMouse();
};
namespace {
@@ -73,9 +70,8 @@ void UpdateKeyMods(ImGuiIO& io)
} // namespace
-Input::Input(Window* mainWindow) : impl(std::make_unique())
+Input::Input() : impl(std::make_unique())
{
- impl->mainWindow = mainWindow;
impl->hasMouse = DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_MOUSE);
}
@@ -83,7 +79,7 @@ Input::~Input()
{
}
-void Input::Impl::UpdateMouse()
+void Input::UpdateMousePos()
{
ImGuiIO& io = ImGui::GetIO();
@@ -119,44 +115,51 @@ void Input::Impl::UpdateMouse()
}
else
{
- Vector2i winPos = mainWindow->get_position();
+ Vector2i winPos = GetContext()->layer->get_window()->get_position();
io.AddMousePosEvent(mousePos.x - winPos.x, mousePos.y - winPos.y);
}
}
+}
+
+void Input::UpdateMouse()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ DisplayServer* DS = DisplayServer::get_singleton();
- if (mouseWheel != Vector2())
+ UpdateMousePos();
+
+ // scrolling works better if we allow no more than one event per frame
+ if (impl->mouseWheel != Vector2())
{
- io.AddMouseWheelEvent(mouseWheel.x, mouseWheel.y);
- mouseWheel = Vector2();
+ io.AddMouseWheelEvent(impl->mouseWheel.x, impl->mouseWheel.y);
+ impl->mouseWheel = Vector2();
}
if (io.WantCaptureMouse && !(io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange))
{
ImGuiMouseCursor newCursor = ImGui::GetMouseCursor();
- if (newCursor != currentCursor)
+ if (newCursor != impl->currentCursor)
{
DS->cursor_set_shape(ToCursorShape(newCursor));
}
}
else
{
- currentCursor = ImGuiMouseCursor_None;
+ impl->currentCursor = ImGuiMouseCursor_None;
}
}
void Input::Update()
{
if (impl->hasMouse)
- impl->UpdateMouse();
+ UpdateMouse();
impl->previousSubViewport = impl->currentSubViewport;
impl->currentSubViewport = nullptr;
}
-bool Input::ProcessInput(const Ref& evt, Window* window)
+void Input::ProcessSubViewportWidget(const Ref& evt)
{
- ImGuiIO& io = ImGui::GetIO();
-
if (impl->currentSubViewport)
{
if (impl->currentSubViewport != impl->previousSubViewport)
@@ -165,10 +168,11 @@ bool Input::ProcessInput(const Ref& evt, Window* window)
Ref vpevt = evt->duplicate();
if (Ref me = vpevt; me.is_valid())
{
+ ImGuiIO& io = ImGui::GetIO();
Vector2i mousePos = DisplayServer::get_singleton()->mouse_get_position();
Vector2i windowPos{0, 0};
if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable))
- windowPos = window->get_position();
+ windowPos = GetContext()->layer->get_window()->get_position();
me->set_position(Vector2(mousePos.x - windowPos.x - impl->currentSubViewportPos.x,
mousePos.y - windowPos.y - impl->currentSubViewportPos.y)
@@ -180,6 +184,11 @@ bool Input::ProcessInput(const Ref& evt, Window* window)
{
impl->previousSubViewport->notification(Node::NOTIFICATION_VP_MOUSE_EXIT);
}
+}
+
+bool Input::HandleEvent(const Ref& evt)
+{
+ ImGuiIO& io = ImGui::GetIO();
bool consumed = false;
@@ -259,7 +268,7 @@ bool Input::ProcessInput(const Ref& evt, Window* window)
{
bool pressed = true;
float v = jm->get_axis_value();
- if (std::abs(v) < impl->deadZone)
+ if (std::abs(v) < GetContext()->joyAxisDeadZone)
{
v = 0;
pressed = false;
@@ -298,6 +307,12 @@ bool Input::ProcessInput(const Ref& evt, Window* window)
return consumed;
}
+bool Input::ProcessInput(const Ref& evt)
+{
+ ProcessSubViewportWidget(evt);
+ return HandleEvent(evt);
+}
+
void Input::ProcessNotification(int what)
{
switch (what)
@@ -317,14 +332,4 @@ void Input::SetActiveSubViewport(godot::SubViewport* svp, Vector2 pos)
impl->currentSubViewportPos = pos;
}
-void Input::SetJoyAxisDeadZone(float val)
-{
- impl->deadZone = val;
-}
-
-float Input::GetJoyAxisDeadZone()
-{
- return impl->deadZone;
-}
-
} // namespace ImGui::Godot
diff --git a/gdext/src/Input.h b/gdext/src/Input.h
index b513f31..16d89ef 100644
--- a/gdext/src/Input.h
+++ b/gdext/src/Input.h
@@ -12,18 +12,22 @@ namespace ImGui::Godot {
class Input
{
public:
- Input(Window* mainWindow);
- ~Input();
+ Input();
+ virtual ~Input();
void Update();
- bool ProcessInput(const Ref& evt, Window* window);
+ virtual bool ProcessInput(const Ref& evt);
void ProcessNotification(int what);
void SetActiveSubViewport(godot::SubViewport* svp, Vector2 pos);
- void SetJoyAxisDeadZone(float val);
- float GetJoyAxisDeadZone();
+protected:
+ virtual void UpdateMousePos();
+ void ProcessSubViewportWidget(const Ref& evt);
+ bool HandleEvent(const Ref& evt);
private:
+ void UpdateMouse();
+
struct Impl;
std::unique_ptr impl;
};
diff --git a/gdext/src/InputLocal.cpp b/gdext/src/InputLocal.cpp
new file mode 100644
index 0000000..0825649
--- /dev/null
+++ b/gdext/src/InputLocal.cpp
@@ -0,0 +1,26 @@
+#include "InputLocal.h"
+#include
+#include
+
+namespace ImGui::Godot {
+
+void InputLocal::UpdateMousePos()
+{
+ // do not use global mouse position
+}
+
+bool InputLocal::ProcessInput(const Ref& evt)
+{
+ // no support for SubViewport widgets
+
+ if (Ref mm = evt; mm.is_valid())
+ {
+ ImGuiIO& io = ImGui::GetIO();
+ Vector2 mousePos = mm->get_position();
+ io.AddMousePosEvent(mousePos.x, mousePos.y);
+ return io.WantCaptureMouse;
+ }
+ return HandleEvent(evt);
+}
+
+} // namespace ImGui::Godot
diff --git a/gdext/src/InputLocal.h b/gdext/src/InputLocal.h
new file mode 100644
index 0000000..02f17ea
--- /dev/null
+++ b/gdext/src/InputLocal.h
@@ -0,0 +1,15 @@
+#pragma once
+#include "Input.h"
+
+using namespace godot;
+
+namespace ImGui::Godot {
+
+class InputLocal : public Input
+{
+protected:
+ void UpdateMousePos() override;
+ bool ProcessInput(const Ref& evt) override;
+};
+
+} // namespace ImGui::Godot
diff --git a/gdext/src/Viewports.cpp b/gdext/src/Viewports.cpp
index b4b82ad..c674edd 100644
--- a/gdext/src/Viewports.cpp
+++ b/gdext/src/Viewports.cpp
@@ -47,7 +47,7 @@ static void Godot_CreateWindow(ImGuiViewport* vp)
vd->window->set_transparent_background(true);
vd->window->set_flag(Window::FLAG_TRANSPARENT, true);
- Node* root = Object::cast_to(Engine::get_singleton()->get_singleton("ImGuiLayer"));
+ Node* root = Object::cast_to(Engine::get_singleton()->get_singleton("ImGuiController"));
root->add_child(vd->window);
// need to do this after add_child
@@ -169,13 +169,16 @@ void Viewports::Impl::UpdateMonitors()
}
}
-Viewports::Viewports(Window* mainWindow, RID mainSubViewport) : impl(std::make_unique())
+Viewports::Viewports() : impl(std::make_unique())
{
auto& io = ImGui::GetIO();
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports;
impl->InitPlatformInterface();
impl->UpdateMonitors();
+}
+void Viewports::SetMainWindow(Window* mainWindow, RID mainSubViewport)
+{
Godot_ViewportData* mainvd = IM_NEW(Godot_ViewportData);
mainvd->window = mainWindow;
ImGuiViewport* vp = ImGui::GetMainViewport();
@@ -189,7 +192,7 @@ Viewports::~Viewports()
void ImGuiWindow::_input(const Ref& evt)
{
- ImGui::Godot::ProcessInput(evt, this);
+ GetContext()->input->ProcessInput(evt);
}
} // namespace ImGui::Godot
diff --git a/gdext/src/Viewports.h b/gdext/src/Viewports.h
index 9f20906..110cb18 100644
--- a/gdext/src/Viewports.h
+++ b/gdext/src/Viewports.h
@@ -40,9 +40,11 @@ class ImGuiWindow : public Window
class Viewports
{
public:
- Viewports(Window* mainWindow, RID mainSubViewport);
+ Viewports();
~Viewports();
+ void SetMainWindow(Window* mainWindow, RID mainSubViewport);
+
private:
struct Impl;
std::unique_ptr impl;
diff --git a/gdext/src/main.cpp b/gdext/src/main.cpp
index 80bf788..b84f60d 100644
--- a/gdext/src/main.cpp
+++ b/gdext/src/main.cpp
@@ -12,9 +12,11 @@ static_assert(GODOT_VERSION_MAJOR == 4 && GODOT_VERSION_MINOR >= 2);
#include
+#include "ImGuiController.h"
+#include "ImGuiControllerHelper.h"
#include "ImGuiGD.h"
#include "ImGuiLayer.h"
-#include "ImGuiLayerHelper.h"
+#include "ImGuiSync.h"
#include "Viewports.h"
// avoid including cimgui.h elsewhere
@@ -55,13 +57,18 @@ void sync_modules()
void initialize_ign_module(ModuleInitializationLevel p_level)
{
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS)
+ {
+ ImGui::CreateContext();
+ ClassDB::register_internal_class();
+ }
+
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE)
return;
- ImGui::CreateContext();
-
ClassDB::register_internal_class();
- ClassDB::register_internal_class();
+ ClassDB::register_internal_class();
+ ClassDB::register_internal_class();
ClassDB::register_class();
ClassDB::register_internal_class();
register_imgui_api();