mirror of
https://github.com/kevinporetti/UnrealImGui.git
synced 2025-01-29 20:40:31 +00:00
Added ImGui early debug events:
- Added to FImGuiDelegates interface early debug delegates called during world tick start. - Delegates are called in fixed order: multi-context early debug, world early debug (called during world tick start), world debug, multi-context debug (called during world post actor tick or if not available, during world tick start). - Removed from build script configuration of debug delegates.
This commit is contained in:
parent
867a34e640
commit
4a9d66889b
@ -11,6 +11,9 @@ Version: 1.15 (2019/04)
|
||||
- DEPRECIATED old FImGuiModule delegates interface and FImGuiDelegateHandle.
|
||||
- Delegates registered with depreciated interface are redirected and get benefit of being preserved during hot-reloading. This can be controlled with IMGUI_REDIRECT_OBSOLETE_DELEGATES.
|
||||
- Added IMGUI_WITH_OBSOLETE_DELEGATES allowing to strip depreciated interface from builds (that interface will be officially removed in one of later releases).
|
||||
- Added new ImGui early debug delegates called during world tick start.
|
||||
- Delegates are called in fixed order: multi-context early debug, world early debug (called during world tick start), world debug, multi-context debug (called during world post actor tick or if not available, during world tick start).
|
||||
- Removed from build script configuration of debug delegates.
|
||||
|
||||
Version: 1.14 (2019/03)
|
||||
- Added SImGuiLayout to resets layout for SImGuiWidget.
|
||||
|
@ -1,45 +1,11 @@
|
||||
// Distributed under the MIT License (MIT) (see accompanying LICENSE file)
|
||||
|
||||
#if UE_4_18_OR_LATER
|
||||
#define WITH_POST_ACTOR_TICK
|
||||
#endif
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class ImGui : ModuleRules
|
||||
{
|
||||
// Defines when events should be broadcast. Note that at the end of the ImGui frame some global variables might be
|
||||
// not set and so it seems preferable to use post actor tick (not available in older engine versions) or world tick
|
||||
// start events. If more control is required Late mode with manually calling events may be used (as in practice
|
||||
// events are guaranteed to be raised only once per frame).
|
||||
enum EEventsBroadcastMode
|
||||
{
|
||||
OnWorldTickStart, // Broadcast during world tick start event.
|
||||
#if WITH_POST_ACTOR_TICK
|
||||
OnPostActorTick, // Broadcast during post actor tick event.
|
||||
#endif
|
||||
Late, // Broadcast at the end of the ImGui frame.
|
||||
}
|
||||
|
||||
// Defines order in which multi-context and world-context events are called.
|
||||
enum EEventsOrder
|
||||
{
|
||||
MultiBeforeWorldContext,
|
||||
WorldBeforeMultiContext,
|
||||
}
|
||||
|
||||
#if WITH_POST_ACTOR_TICK
|
||||
EEventsBroadcastMode DrawEventsBroadcastMode = EEventsBroadcastMode.OnPostActorTick;
|
||||
EEventsOrder DrawEventsOrder = EEventsOrder.WorldBeforeMultiContext;
|
||||
#else
|
||||
EEventsBroadcastMode DrawEventsBroadcastMode = EEventsBroadcastMode.OnWorldTickStart;
|
||||
EEventsOrder DrawEventsOrder = EEventsOrder.MultiBeforeWorldContext;
|
||||
#endif // WITH_POST_ACTOR_TICK
|
||||
|
||||
|
||||
|
||||
#if WITH_FORWARDED_MODULE_RULES_CTOR
|
||||
public ImGui(ReadOnlyTargetRules Target) : base(Target)
|
||||
#else
|
||||
@ -128,17 +94,5 @@ public class ImGui : ModuleRules
|
||||
#endif
|
||||
|
||||
PrivateDefinitions.Add(string.Format("RUNTIME_LOADER_ENABLED={0}", bEnableRuntimeLoader ? 1 : 0));
|
||||
|
||||
bool bDrawOnWorldTickStart = (DrawEventsBroadcastMode == EEventsBroadcastMode.OnWorldTickStart);
|
||||
#if WITH_POST_ACTOR_TICK
|
||||
bool bDrawOnPostActorTick = (DrawEventsBroadcastMode == EEventsBroadcastMode.OnPostActorTick);
|
||||
#else
|
||||
bool bDrawOnPostActorTick = false;
|
||||
#endif
|
||||
|
||||
PrivateDefinitions.Add(string.Format("DRAW_EVENTS_ON_WORLD_TICK_START={0}", bDrawOnWorldTickStart ? 1 : 0));
|
||||
PrivateDefinitions.Add(string.Format("DRAW_EVENTS_ON_POST_ACTOR_TICK={0}", bDrawOnPostActorTick ? 1 : 0));
|
||||
PrivateDefinitions.Add(string.Format("DRAW_EVENTS_ORDER_WORLD_BEFORE_MULTI_CONTEXT={0}",
|
||||
(DrawEventsOrder == EEventsOrder.WorldBeforeMultiContext) ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ FImGuiContextManager::FImGuiContextManager()
|
||||
FontAtlas.GetTexDataAsRGBA32(&Pixels, &Width, &Height, &Bpp);
|
||||
|
||||
FWorldDelegates::OnWorldTickStart.AddRaw(this, &FImGuiContextManager::OnWorldTickStart);
|
||||
#if DRAW_EVENTS_ON_POST_ACTOR_TICK
|
||||
#if ENGINE_COMPATIBILITY_WITH_WORLD_POST_ACTOR_TICK
|
||||
FWorldDelegates::OnWorldPostActorTick.AddRaw(this, &FImGuiContextManager::OnWorldPostActorTick);
|
||||
#endif
|
||||
}
|
||||
@ -73,7 +73,7 @@ FImGuiContextManager::~FImGuiContextManager()
|
||||
{
|
||||
// Order matters because contexts can be created during World Tick Start events.
|
||||
FWorldDelegates::OnWorldTickStart.RemoveAll(this);
|
||||
#if DRAW_EVENTS_ON_POST_ACTOR_TICK
|
||||
#if ENGINE_COMPATIBILITY_WITH_WORLD_POST_ACTOR_TICK
|
||||
FWorldDelegates::OnWorldPostActorTick.RemoveAll(this);
|
||||
#endif
|
||||
}
|
||||
@ -103,22 +103,23 @@ void FImGuiContextManager::OnWorldTickStart(ELevelTick TickType, float DeltaSeco
|
||||
if (GWorld)
|
||||
{
|
||||
FImGuiContextProxy& ContextProxy = GetWorldContextProxy(*GWorld);
|
||||
|
||||
// Set as current, so we have right context ready when updating world objects.
|
||||
ContextProxy.SetAsCurrent();
|
||||
|
||||
#if DRAW_EVENTS_ON_WORLD_TICK_START
|
||||
ContextProxy.Draw();
|
||||
ContextProxy.DrawEarlyDebug();
|
||||
#if !ENGINE_COMPATIBILITY_WITH_WORLD_POST_ACTOR_TICK
|
||||
ContextProxy.DrawDebug();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if DRAW_EVENTS_ON_POST_ACTOR_TICK
|
||||
#if ENGINE_COMPATIBILITY_WITH_WORLD_POST_ACTOR_TICK
|
||||
void FImGuiContextManager::OnWorldPostActorTick(UWorld* World, ELevelTick TickType, float DeltaSeconds)
|
||||
{
|
||||
FImGuiContextProxy& ContextProxy = GetWorldContextProxy(*GWorld);
|
||||
ContextProxy.SetAsCurrent();
|
||||
ContextProxy.Draw();
|
||||
GetWorldContextProxy(*GWorld).DrawDebug();
|
||||
}
|
||||
#endif // DRAW_EVENTS_ON_POST_ACTOR_TICK
|
||||
#endif // ENGINE_COMPATIBILITY_WITH_WORLD_POST_ACTOR_TICK
|
||||
|
||||
#if WITH_EDITOR
|
||||
FImGuiContextManager::FContextData& FImGuiContextManager::GetEditorContextData()
|
||||
|
@ -100,7 +100,7 @@ private:
|
||||
|
||||
void OnWorldTickStart(ELevelTick TickType, float DeltaSeconds);
|
||||
|
||||
#if DRAW_EVENTS_ON_POST_ACTOR_TICK
|
||||
#if ENGINE_COMPATIBILITY_WITH_WORLD_POST_ACTOR_TICK
|
||||
void OnWorldPostActorTick(UWorld* World, ELevelTick TickType, float DeltaSeconds);
|
||||
#endif
|
||||
|
||||
|
@ -83,24 +83,34 @@ FImGuiContextProxy::FImGuiContextProxy(const FString& InName, int32 InContextInd
|
||||
BeginFrame();
|
||||
}
|
||||
|
||||
void FImGuiContextProxy::Draw()
|
||||
void FImGuiContextProxy::DrawEarlyDebug()
|
||||
{
|
||||
if (bIsFrameStarted && !bIsDrawCalled)
|
||||
if (bIsFrameStarted && !bIsDrawEarlyDebugCalled)
|
||||
{
|
||||
bIsDrawCalled = true;
|
||||
bIsDrawEarlyDebugCalled = true;
|
||||
|
||||
SetAsCurrent();
|
||||
|
||||
// Broadcast draw event to allow listeners to draw their controls to this context.
|
||||
#if DRAW_EVENTS_ORDER_WORLD_BEFORE_MULTI_CONTEXT
|
||||
BroadcastWorldTick();
|
||||
#endif // DRAW_EVENTS_ORDER_WORLD_BEFORE_MULTI_CONTEXT
|
||||
// Delegates called in order specified in FImGuiDelegates.
|
||||
BroadcastMultiContextEarlyDebug();
|
||||
BroadcastWorldEarlyDebug();
|
||||
}
|
||||
}
|
||||
|
||||
BroadcastMultiContextTick();
|
||||
void FImGuiContextProxy::DrawDebug()
|
||||
{
|
||||
if (bIsFrameStarted && !bIsDrawDebugCalled)
|
||||
{
|
||||
bIsDrawDebugCalled = true;
|
||||
|
||||
#if !DRAW_EVENTS_ORDER_WORLD_BEFORE_MULTI_CONTEXT
|
||||
BroadcastWorldTick();
|
||||
#endif // !DRAW_EVENTS_ORDER_WORLD_BEFORE_MULTI_CONTEXT
|
||||
// Make sure that early debug is always called first to guarantee order specified in FImGuiDelegates.
|
||||
DrawEarlyDebug();
|
||||
|
||||
SetAsCurrent();
|
||||
|
||||
// Delegates called in order specified in FImGuiDelegates.
|
||||
BroadcastWorldDebug();
|
||||
BroadcastMultiContextDebug();
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,7 +126,7 @@ void FImGuiContextProxy::Tick(float DeltaSeconds)
|
||||
if (bIsFrameStarted)
|
||||
{
|
||||
// Make sure that draw events are called before the end of the frame.
|
||||
Draw();
|
||||
DrawDebug();
|
||||
|
||||
// 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.
|
||||
@ -149,7 +159,8 @@ void FImGuiContextProxy::BeginFrame(float DeltaTime)
|
||||
ImGui::NewFrame();
|
||||
|
||||
bIsFrameStarted = true;
|
||||
bIsDrawCalled = false;
|
||||
bIsDrawEarlyDebugCalled = false;
|
||||
bIsDrawDebugCalled = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,7 +197,28 @@ void FImGuiContextProxy::UpdateDrawData(ImDrawData* DrawData)
|
||||
}
|
||||
}
|
||||
|
||||
void FImGuiContextProxy::BroadcastWorldTick()
|
||||
void FImGuiContextProxy::BroadcastWorldEarlyDebug()
|
||||
{
|
||||
if (ContextIndex != Utilities::INVALID_CONTEXT_INDEX)
|
||||
{
|
||||
FSimpleMulticastDelegate& WorldEarlyDebugEvent = FImGuiDelegatesContainer::Get().OnWorldEarlyDebug(ContextIndex);
|
||||
if (WorldEarlyDebugEvent.IsBound())
|
||||
{
|
||||
WorldEarlyDebugEvent.Broadcast();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FImGuiContextProxy::BroadcastMultiContextEarlyDebug()
|
||||
{
|
||||
FSimpleMulticastDelegate& MultiContextEarlyDebugEvent = FImGuiDelegatesContainer::Get().OnMultiContextEarlyDebug();
|
||||
if (MultiContextEarlyDebugEvent.IsBound())
|
||||
{
|
||||
MultiContextEarlyDebugEvent.Broadcast();
|
||||
}
|
||||
}
|
||||
|
||||
void FImGuiContextProxy::BroadcastWorldDebug()
|
||||
{
|
||||
if (DrawEvent.IsBound())
|
||||
{
|
||||
@ -203,7 +235,7 @@ void FImGuiContextProxy::BroadcastWorldTick()
|
||||
}
|
||||
}
|
||||
|
||||
void FImGuiContextProxy::BroadcastMultiContextTick()
|
||||
void FImGuiContextProxy::BroadcastMultiContextDebug()
|
||||
{
|
||||
if (SharedDrawEvent && SharedDrawEvent->IsBound())
|
||||
{
|
||||
|
@ -84,9 +84,11 @@ public:
|
||||
// Delegate called right before ending the frame to allows listeners draw their controls.
|
||||
FSimpleMulticastDelegate& OnDraw() { return DrawEvent; }
|
||||
|
||||
// Call draw events to allow listeners draw their widgets. Only one call per frame is processed. If it is not
|
||||
// called manually before, then it will be called from the Tick function.
|
||||
void Draw();
|
||||
// Call early debug events to allow listeners draw their debug widgets.
|
||||
void DrawEarlyDebug();
|
||||
|
||||
// Call debug events to allow listeners draw their debug widgets.
|
||||
void DrawDebug();
|
||||
|
||||
// Tick to advance context to the next frame. Only one call per frame will be processed.
|
||||
void Tick(float DeltaSeconds);
|
||||
@ -98,8 +100,11 @@ private:
|
||||
|
||||
void UpdateDrawData(ImDrawData* DrawData);
|
||||
|
||||
void BroadcastWorldTick();
|
||||
void BroadcastMultiContextTick();
|
||||
void BroadcastWorldEarlyDebug();
|
||||
void BroadcastMultiContextEarlyDebug();
|
||||
|
||||
void BroadcastWorldDebug();
|
||||
void BroadcastMultiContextDebug();
|
||||
|
||||
FImGuiContextPtr Context;
|
||||
|
||||
@ -109,7 +114,8 @@ private:
|
||||
bool bHasActiveItem = false;
|
||||
|
||||
bool bIsFrameStarted = false;
|
||||
bool bIsDrawCalled = false;
|
||||
bool bIsDrawEarlyDebugCalled = false;
|
||||
bool bIsDrawDebugCalled = false;
|
||||
|
||||
uint32 LastFrameNumber = 0;
|
||||
|
||||
|
@ -6,6 +6,21 @@
|
||||
#include "ImGuiDelegatesContainer.h"
|
||||
|
||||
|
||||
FSimpleMulticastDelegate& FImGuiDelegates::OnWorldEarlyDebug()
|
||||
{
|
||||
return OnWorldEarlyDebug(GWorld);
|
||||
}
|
||||
|
||||
FSimpleMulticastDelegate& FImGuiDelegates::OnWorldEarlyDebug(UWorld* World)
|
||||
{
|
||||
return FImGuiDelegatesContainer::Get().OnWorldEarlyDebug(World);
|
||||
}
|
||||
|
||||
FSimpleMulticastDelegate& FImGuiDelegates::OnMultiContextEarlyDebug()
|
||||
{
|
||||
return FImGuiDelegatesContainer::Get().OnMultiContextEarlyDebug();
|
||||
}
|
||||
|
||||
FSimpleMulticastDelegate& FImGuiDelegates::OnWorldDebug()
|
||||
{
|
||||
return OnWorldDebug(GWorld);
|
||||
|
@ -25,13 +25,15 @@ void FImGuiDelegatesContainer::MoveContainer(FImGuiDelegatesContainer& Dst)
|
||||
InstancePtr = &Dst;
|
||||
}
|
||||
|
||||
FSimpleMulticastDelegate& FImGuiDelegatesContainer::OnWorldDebug(UWorld* World)
|
||||
int32 FImGuiDelegatesContainer::GetContextIndex(UWorld* World)
|
||||
{
|
||||
return OnWorldDebug(Utilities::GetWorldContextIndex(*World));
|
||||
return Utilities::GetWorldContextIndex(*World);
|
||||
}
|
||||
|
||||
void FImGuiDelegatesContainer::Clear()
|
||||
{
|
||||
WorldDelegates.Empty();
|
||||
MultiContextDelegate.Clear();
|
||||
WorldEarlyDebugDelegates.Empty();
|
||||
WorldDebugDelegates.Empty();
|
||||
MultiContextEarlyDebugDelegate.Clear();
|
||||
MultiContextDebugDelegate.Clear();
|
||||
}
|
||||
|
@ -16,21 +16,34 @@ public:
|
||||
// If this is an active container move its data to a destination and redirect all future calls to that instance.
|
||||
static void MoveContainer(FImGuiDelegatesContainer& Dst);
|
||||
|
||||
// Get delegate to ImGui world early debug event from known world instance.
|
||||
FSimpleMulticastDelegate& OnWorldEarlyDebug(UWorld* World) { return OnWorldEarlyDebug(GetContextIndex(World)); }
|
||||
|
||||
// Get delegate to ImGui world early debug event from known context index.
|
||||
FSimpleMulticastDelegate& OnWorldEarlyDebug(int32 ContextIndex) { return WorldEarlyDebugDelegates.FindOrAdd(ContextIndex); }
|
||||
|
||||
// Get delegate to ImGui multi-context early debug event.
|
||||
FSimpleMulticastDelegate& OnMultiContextEarlyDebug() { return MultiContextEarlyDebugDelegate; }
|
||||
|
||||
// Get delegate to ImGui world debug event from known world instance.
|
||||
FSimpleMulticastDelegate& OnWorldDebug(UWorld* World);
|
||||
FSimpleMulticastDelegate& OnWorldDebug(UWorld* World) { return OnWorldDebug(GetContextIndex(World)); }
|
||||
|
||||
// Get delegate to ImGui world debug event from known context index.
|
||||
FSimpleMulticastDelegate& OnWorldDebug(int32 ContextIndex) { return WorldDelegates.FindOrAdd(ContextIndex); }
|
||||
FSimpleMulticastDelegate& OnWorldDebug(int32 ContextIndex) { return WorldDebugDelegates.FindOrAdd(ContextIndex); }
|
||||
|
||||
// Get delegate to ImGui multi-context debug event.
|
||||
FSimpleMulticastDelegate& OnMultiContextDebug() { return MultiContextDelegate; }
|
||||
FSimpleMulticastDelegate& OnMultiContextDebug() { return MultiContextDebugDelegate; }
|
||||
|
||||
private:
|
||||
|
||||
int32 GetContextIndex(UWorld* World);
|
||||
|
||||
void Clear();
|
||||
|
||||
TMap<int32, FSimpleMulticastDelegate> WorldDelegates;
|
||||
FSimpleMulticastDelegate MultiContextDelegate;
|
||||
TMap<int32, FSimpleMulticastDelegate> WorldEarlyDebugDelegates;
|
||||
TMap<int32, FSimpleMulticastDelegate> WorldDebugDelegates;
|
||||
FSimpleMulticastDelegate MultiContextEarlyDebugDelegate;
|
||||
FSimpleMulticastDelegate MultiContextDebugDelegate;
|
||||
|
||||
// Default container instance.
|
||||
static FImGuiDelegatesContainer DefaultInstance;
|
||||
|
@ -23,3 +23,8 @@
|
||||
// that renames FStringClassReference to FSoftClassPath, so it is still possible tu use the old type name in code.
|
||||
// The old header forwards to the new one but if used it outputs a warning, so we want to avoid it.
|
||||
#define ENGINE_COMPATIBILITY_LEGACY_STRING_CLASS_REF BELOW_ENGINE_VERSION(4, 18)
|
||||
|
||||
// Starting from version 4.18 engine has a world post actor tick event which if available, provides a good opportunity
|
||||
// to call debug delegates after world actors are already updated.
|
||||
#define ENGINE_COMPATIBILITY_WITH_WORLD_POST_ACTOR_TICK FROM_ENGINE_VERSION(4, 18)
|
||||
|
||||
|
@ -6,16 +6,37 @@
|
||||
|
||||
|
||||
/**
|
||||
* Delegates to ImGui debug events called. World delegates are called once per frame to draw debug for owning world
|
||||
* and are automatically cleared when that world becomes invalid. Multi-context delegates are called once for every
|
||||
* world that needs to be debugged.
|
||||
* In engine version 4.18 or later delegates are called during OnWorldPostActorTick event while in older versions
|
||||
* 4.18 during OnWorldTickStart event. Calling behaviours can be changed in build configuration.
|
||||
* Delegates to ImGui debug events. World delegates are called once per frame during world updates and have invocation
|
||||
* lists cleared after their worlds become invalid. Multi-context delegates are called once for every updated world.
|
||||
* Early debug delegates are called during world tick start and debug delegates are called during world post actor tick
|
||||
* or in engine versions below 4.18 during world tick start.
|
||||
*
|
||||
* Order of events is defined in a way that multi-context delegates can be used to draw headers and/or footers:
|
||||
* multi-context early debug, world early debug, world debug, multi-context debug.
|
||||
*/
|
||||
class IMGUI_API FImGuiDelegates
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Get a delegate to ImGui world early debug event for current world (GWorld).
|
||||
* @returns Simple multicast delegate to debug events called once per frame to debug current world
|
||||
*/
|
||||
static FSimpleMulticastDelegate& OnWorldEarlyDebug();
|
||||
|
||||
/**
|
||||
* Get a delegate to ImGui world early debug event for given world.
|
||||
* @param World - World for which we need a delegate
|
||||
* @returns Simple multicast delegate to debug events called once per frame to debug given world
|
||||
*/
|
||||
static FSimpleMulticastDelegate& OnWorldEarlyDebug(UWorld* World);
|
||||
|
||||
/**
|
||||
* Get a delegate to ImGui multi-context early debug event.
|
||||
* @returns Simple multicast delegate to debug events called once per frame for every world to debug
|
||||
*/
|
||||
static FSimpleMulticastDelegate& OnMultiContextEarlyDebug();
|
||||
|
||||
/**
|
||||
* Get a delegate to ImGui world debug event for current world (GWorld).
|
||||
* @returns Simple multicast delegate to debug events called once per frame to debug current world
|
||||
|
Loading…
Reference in New Issue
Block a user