mirror of
https://github.com/kevinporetti/UnrealImGui.git
synced 2025-01-18 08:20:32 +00:00
Added interface to register ImGui debug delegates.
This commit is contained in:
parent
1a6aa98f51
commit
00ad746267
@ -72,7 +72,7 @@ void FImGuiContextManager::Tick(float DeltaSeconds)
|
|||||||
if (ContextData.CanTick())
|
if (ContextData.CanTick())
|
||||||
{
|
{
|
||||||
ContextData.ContextProxy.SetAsCurrent();
|
ContextData.ContextProxy.SetAsCurrent();
|
||||||
ContextData.ContextProxy.Tick(DeltaSeconds);
|
ContextData.ContextProxy.Tick(DeltaSeconds, &DrawMultiContextEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,7 +105,7 @@ FImGuiContextManager::FContextData& FImGuiContextManager::GetStandaloneWorldCont
|
|||||||
}
|
}
|
||||||
#endif // !WITH_EDITOR
|
#endif // !WITH_EDITOR
|
||||||
|
|
||||||
FImGuiContextManager::FContextData& FImGuiContextManager::GetWorldContextData(const UWorld& World)
|
FImGuiContextManager::FContextData& FImGuiContextManager::GetWorldContextData(const UWorld& World, int32* OutIndex)
|
||||||
{
|
{
|
||||||
using namespace Utilities;
|
using namespace Utilities;
|
||||||
|
|
||||||
@ -140,5 +140,9 @@ FImGuiContextManager::FContextData& FImGuiContextManager::GetWorldContextData(co
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (OutIndex)
|
||||||
|
{
|
||||||
|
*OutIndex = Index;
|
||||||
|
}
|
||||||
return *Data;
|
return *Data;
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,9 @@ public:
|
|||||||
// Get or create ImGui context proxy for given world.
|
// Get or create ImGui context proxy for given world.
|
||||||
FORCEINLINE FImGuiContextProxy& GetWorldContextProxy(const UWorld& World) { return GetWorldContextData(World).ContextProxy; }
|
FORCEINLINE FImGuiContextProxy& GetWorldContextProxy(const UWorld& World) { return GetWorldContextData(World).ContextProxy; }
|
||||||
|
|
||||||
|
// Get or create ImGui context proxy for given world. Additionally get context index for that proxy.
|
||||||
|
FORCEINLINE FImGuiContextProxy& GetWorldContextProxy(const UWorld& World, int32& OutContextIndex) { return GetWorldContextData(World, &OutContextIndex).ContextProxy; }
|
||||||
|
|
||||||
// Get context proxy by index, or null if context with that index doesn't exist.
|
// Get context proxy by index, or null if context with that index doesn't exist.
|
||||||
FORCEINLINE FImGuiContextProxy* GetContextProxy(int32 ContextIndex)
|
FORCEINLINE FImGuiContextProxy* GetContextProxy(int32 ContextIndex)
|
||||||
{
|
{
|
||||||
@ -41,6 +44,10 @@ public:
|
|||||||
return Data ? &(Data->ContextProxy) : nullptr;
|
return Data ? &(Data->ContextProxy) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delegate called for all contexts in manager, right after calling context specific draw event. Allows listeners
|
||||||
|
// draw the same content to multiple contexts.
|
||||||
|
FSimpleMulticastDelegate& OnDrawMultiContext() { return DrawMultiContextEvent; }
|
||||||
|
|
||||||
void Tick(float DeltaSeconds);
|
void Tick(float DeltaSeconds);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -87,9 +94,11 @@ private:
|
|||||||
FContextData& GetStandaloneWorldContextData();
|
FContextData& GetStandaloneWorldContextData();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FContextData& GetWorldContextData(const UWorld& World);
|
FContextData& GetWorldContextData(const UWorld& World, int32* OutContextIndex = nullptr);
|
||||||
|
|
||||||
TMap<int32, FContextData> Contexts;
|
TMap<int32, FContextData> Contexts;
|
||||||
|
|
||||||
FImGuiDemo ImGuiDemo;
|
FImGuiDemo ImGuiDemo;
|
||||||
|
|
||||||
|
FSimpleMulticastDelegate DrawMultiContextEvent;
|
||||||
};
|
};
|
||||||
|
@ -117,7 +117,7 @@ FImGuiContextProxy::~FImGuiContextProxy()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FImGuiContextProxy::Tick(float DeltaSeconds)
|
void FImGuiContextProxy::Tick(float DeltaSeconds, FSimpleMulticastDelegate* SharedDrawEvent)
|
||||||
{
|
{
|
||||||
if (bIsFrameStarted)
|
if (bIsFrameStarted)
|
||||||
{
|
{
|
||||||
@ -126,6 +126,10 @@ void FImGuiContextProxy::Tick(float DeltaSeconds)
|
|||||||
{
|
{
|
||||||
DrawEvent.Broadcast();
|
DrawEvent.Broadcast();
|
||||||
}
|
}
|
||||||
|
if (SharedDrawEvent && SharedDrawEvent->IsBound())
|
||||||
|
{
|
||||||
|
SharedDrawEvent->Broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
// Ending frame will produce render output that we capture and store for later use. This also puts context to
|
// Ending frame will produce render output that we capture and store for later use. This also puts context to
|
||||||
// state in which it does not allow to draw controls, so we want to immediately start a new frame.
|
// state in which it does not allow to draw controls, so we want to immediately start a new frame.
|
||||||
|
@ -53,7 +53,8 @@ public:
|
|||||||
FSimpleMulticastDelegate& OnDraw() { return DrawEvent; }
|
FSimpleMulticastDelegate& OnDraw() { return DrawEvent; }
|
||||||
|
|
||||||
// Tick to advance context to the next frame.
|
// Tick to advance context to the next frame.
|
||||||
void Tick(float DeltaSeconds);
|
// @param SharedDrawEvent - Shared draw event provided from outside to be called right after context own event
|
||||||
|
void Tick(float DeltaSeconds, FSimpleMulticastDelegate* SharedDrawEvent = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include "ImGuiPrivatePCH.h"
|
#include "ImGuiPrivatePCH.h"
|
||||||
|
|
||||||
#include "ImGuiModuleManager.h"
|
#include "ImGuiModuleManager.h"
|
||||||
|
#include "Utilities/WorldContext.h"
|
||||||
|
#include "Utilities/WorldContextIndex.h"
|
||||||
|
|
||||||
#include <IPluginManager.h>
|
#include <IPluginManager.h>
|
||||||
|
|
||||||
@ -10,8 +12,77 @@
|
|||||||
#define LOCTEXT_NAMESPACE "FImGuiModule"
|
#define LOCTEXT_NAMESPACE "FImGuiModule"
|
||||||
|
|
||||||
|
|
||||||
|
struct EDelegateCategory
|
||||||
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
// Default per-context draw events.
|
||||||
|
Default,
|
||||||
|
|
||||||
|
// Multi-context draw event defined in context manager.
|
||||||
|
MultiContext
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
static FImGuiModuleManager* ModuleManager = nullptr;
|
static FImGuiModuleManager* ModuleManager = nullptr;
|
||||||
|
|
||||||
|
#if WITH_EDITOR
|
||||||
|
FImGuiDelegateHandle FImGuiModule::AddEditorImGuiDelegate(const FImGuiDelegate& Delegate)
|
||||||
|
{
|
||||||
|
checkf(ModuleManager, TEXT("Null pointer to internal module implementation. Is module available?"));
|
||||||
|
|
||||||
|
return { ModuleManager->GetContextManager().GetEditorContextProxy().OnDraw().Add(Delegate),
|
||||||
|
EDelegateCategory::Default, Utilities::EDITOR_CONTEXT_INDEX };
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FImGuiDelegateHandle FImGuiModule::AddWorldImGuiDelegate(const FImGuiDelegate& Delegate)
|
||||||
|
{
|
||||||
|
checkf(ModuleManager, TEXT("Null pointer to internal module implementation. Is module available?"));
|
||||||
|
|
||||||
|
#if WITH_EDITOR
|
||||||
|
checkf(GEngine, TEXT("Null GEngine. AddWorldImGuiDelegate should be only called with GEngine initialized."));
|
||||||
|
|
||||||
|
const FWorldContext* WorldContext = Utilities::GetWorldContext(GEngine->GameViewport);
|
||||||
|
if (!WorldContext)
|
||||||
|
{
|
||||||
|
WorldContext = Utilities::GetWorldContextFromNetMode(ENetMode::NM_DedicatedServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkf(WorldContext, TEXT("Couldn't find current world. AddWorldImGuiDelegate should be only called from a valid world."));
|
||||||
|
|
||||||
|
int32 Index;
|
||||||
|
FImGuiContextProxy& Proxy = ModuleManager->GetContextManager().GetWorldContextProxy(*WorldContext->World(), Index);
|
||||||
|
#else
|
||||||
|
const int32 Index = Utilities::STANDALONE_GAME_CONTEXT_INDEX;
|
||||||
|
FImGuiContextProxy& Proxy = ModuleManager->GetContextManager().GetWorldContextProxy();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return{ Proxy.OnDraw().Add(Delegate), EDelegateCategory::Default, Index };
|
||||||
|
}
|
||||||
|
|
||||||
|
FImGuiDelegateHandle FImGuiModule::AddMultiContextImGuiDelegate(const FImGuiDelegate& Delegate)
|
||||||
|
{
|
||||||
|
checkf(ModuleManager, TEXT("Null pointer to internal module implementation. Is module available?"));
|
||||||
|
|
||||||
|
return { ModuleManager->GetContextManager().OnDrawMultiContext().Add(Delegate), EDelegateCategory::MultiContext };
|
||||||
|
}
|
||||||
|
|
||||||
|
void FImGuiModule::RemoveImGuiDelegate(const FImGuiDelegateHandle& Handle)
|
||||||
|
{
|
||||||
|
if (ModuleManager)
|
||||||
|
{
|
||||||
|
if (Handle.Category == EDelegateCategory::MultiContext)
|
||||||
|
{
|
||||||
|
ModuleManager->GetContextManager().OnDrawMultiContext().Remove(Handle.Handle);
|
||||||
|
}
|
||||||
|
else if (auto* Proxy = ModuleManager->GetContextManager().GetContextProxy(Handle.Index))
|
||||||
|
{
|
||||||
|
Proxy->OnDraw().Remove(Handle.Handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FImGuiModule::StartupModule()
|
void FImGuiModule::StartupModule()
|
||||||
{
|
{
|
||||||
checkf(!ModuleManager, TEXT("Instance of Module Manager already exists. Instance should be created only during module startup."));
|
checkf(!ModuleManager, TEXT("Instance of Module Manager already exists. Instance should be created only during module startup."));
|
||||||
@ -23,12 +94,12 @@ void FImGuiModule::StartupModule()
|
|||||||
void FImGuiModule::ShutdownModule()
|
void FImGuiModule::ShutdownModule()
|
||||||
{
|
{
|
||||||
checkf(ModuleManager, TEXT("Null Module Manager. Manager instance should be deleted during module shutdown."));
|
checkf(ModuleManager, TEXT("Null Module Manager. Manager instance should be deleted during module shutdown."));
|
||||||
|
|
||||||
// Before we shutdown we need to delete manager that will do all necessary cleanup.
|
// Before we shutdown we need to delete manager that will do all necessary cleanup.
|
||||||
delete ModuleManager;
|
delete ModuleManager;
|
||||||
ModuleManager = nullptr;
|
ModuleManager = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef LOCTEXT_NAMESPACE
|
#undef LOCTEXT_NAMESPACE
|
||||||
|
|
||||||
IMPLEMENT_MODULE(FImGuiModule, ImGui)
|
IMPLEMENT_MODULE(FImGuiModule, ImGui)
|
||||||
|
55
Source/ImGui/Public/ImGuiDelegates.h
Normal file
55
Source/ImGui/Public/ImGuiDelegates.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// Distributed under the MIT License (MIT) (see accompanying LICENSE file)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Core.h>
|
||||||
|
|
||||||
|
|
||||||
|
/** Delegate that allows to subscribe for ImGui events. */
|
||||||
|
typedef FSimpleMulticastDelegate::FDelegate FImGuiDelegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle to ImGui delegate. Contains additional information locating delegates in different contexts.
|
||||||
|
*/
|
||||||
|
class FImGuiDelegateHandle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
FImGuiDelegateHandle() = default;
|
||||||
|
|
||||||
|
bool IsValid() const
|
||||||
|
{
|
||||||
|
return Handle.IsValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
Handle.Reset();
|
||||||
|
Index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
FImGuiDelegateHandle(const FDelegateHandle& InHandle, int32 InCategory, int32 InIndex = 0)
|
||||||
|
: Handle(InHandle)
|
||||||
|
, Category(InCategory)
|
||||||
|
, Index(InIndex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator==(const FImGuiDelegateHandle& Lhs, const FImGuiDelegateHandle& Rhs)
|
||||||
|
{
|
||||||
|
return Lhs.Handle == Rhs.Handle && Lhs.Category == Rhs.Category && Lhs.Index == Rhs.Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(const FImGuiDelegateHandle& Lhs, const FImGuiDelegateHandle& Rhs)
|
||||||
|
{
|
||||||
|
return !(Lhs == Rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
FDelegateHandle Handle;
|
||||||
|
int32 Category = 0;
|
||||||
|
int32 Index = 0;
|
||||||
|
|
||||||
|
friend class FImGuiModule;
|
||||||
|
};
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "ImGuiDelegates.h"
|
||||||
|
|
||||||
#include <ModuleManager.h>
|
#include <ModuleManager.h>
|
||||||
|
|
||||||
|
|
||||||
@ -9,6 +11,64 @@ class FImGuiModule : public IModuleInterface
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Singleton-like access to this module's interface. This is just for convenience!
|
||||||
|
* Beware of calling this during the shutdown phase, though. Your module might have been unloaded already.
|
||||||
|
*
|
||||||
|
* @return Returns singleton instance, loading the module on demand if needed
|
||||||
|
*/
|
||||||
|
static inline FImGuiModule& Get()
|
||||||
|
{
|
||||||
|
return FModuleManager::LoadModuleChecked<FImGuiModule>("ImGui");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true.
|
||||||
|
*
|
||||||
|
* @return True if the module is loaded and ready to use
|
||||||
|
*/
|
||||||
|
static inline bool IsAvailable()
|
||||||
|
{
|
||||||
|
return FModuleManager::Get().IsModuleLoaded("ImGui");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if WITH_EDITOR
|
||||||
|
/**
|
||||||
|
* Add a delegate called at the end of editor debug frame to draw debug controls in its ImGui context, creating
|
||||||
|
* that context on demand.
|
||||||
|
*
|
||||||
|
* @param Delegate - Delegate that we want to add (@see FImGuiDelegate::Create...)
|
||||||
|
* @returns Returns handle that can be used to remove delegate (@see RemoveImGuiDelegate)
|
||||||
|
*/
|
||||||
|
virtual FImGuiDelegateHandle AddEditorImGuiDelegate(const FImGuiDelegate& Delegate);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a delegate called at the end of current world debug frame to draw debug controls in its ImGui context,
|
||||||
|
* creating that context on demand.
|
||||||
|
* This function will throw if called outside of a world context (i.e. current world cannot be found).
|
||||||
|
*
|
||||||
|
* @param Delegate - Delegate that we want to add (@see FImGuiDelegate::Create...)
|
||||||
|
* @returns Returns handle that can be used to remove delegate (@see RemoveImGuiDelegate)
|
||||||
|
*/
|
||||||
|
virtual FImGuiDelegateHandle AddWorldImGuiDelegate(const FImGuiDelegate& Delegate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add shared delegate called for each ImGui context at the end of debug frame, after calling context specific
|
||||||
|
* delegate. This delegate will be used for any ImGui context, created before or after it is registered.
|
||||||
|
*
|
||||||
|
* @param Delegate - Delegate that we want to add (@see FImGuiDelegate::Create...)
|
||||||
|
* @returns Returns handle that can be used to remove delegate (@see RemoveImGuiDelegate)
|
||||||
|
*/
|
||||||
|
virtual FImGuiDelegateHandle AddMultiContextImGuiDelegate(const FImGuiDelegate& Delegate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove delegate added with any version of Add...ImGuiDelegate
|
||||||
|
*
|
||||||
|
* @param Handle - Delegate handle that was returned by adding function
|
||||||
|
*/
|
||||||
|
virtual void RemoveImGuiDelegate(const FImGuiDelegateHandle& Handle);
|
||||||
|
|
||||||
/** IModuleInterface implementation */
|
/** IModuleInterface implementation */
|
||||||
virtual void StartupModule() override;
|
virtual void StartupModule() override;
|
||||||
virtual void ShutdownModule() override;
|
virtual void ShutdownModule() override;
|
||||||
|
Loading…
Reference in New Issue
Block a user