improve NetImgui integration

This commit is contained in:
Arnaud Jamin
2025-01-06 00:55:39 -05:00
parent 4e126dacba
commit 01e6619e86
11 changed files with 452 additions and 160 deletions
@@ -11,14 +11,14 @@
#include "NetImgui_Api.h" #include "NetImgui_Api.h"
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_NetImGui::Initialize() void FCogEngineWindow_NetImgui::Initialize()
{ {
Super::Initialize(); Super::Initialize();
bHasMenu = true;
Config = GetConfig<UCogEngineConfig_NetImGui>(); Config = GetConfig<UCogEngineWindowConfig_NetImgui>();
FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand(
TEXT("Cog.NetImgui.ConnectTo"), TEXT("Cog.NetImgui.Connect"),
TEXT("Connect to NetImgui server"), TEXT("Connect to NetImgui server"),
GetWorld(), GetWorld(),
FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray<FString>& InArgs, UWorld* InWorld) FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray<FString>& InArgs, UWorld* InWorld)
@@ -27,7 +27,7 @@ void FCogEngineWindow_NetImGui::Initialize()
})); }));
FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand(
TEXT("Cog.NetImgui.ConnectFrom"), TEXT("Cog.NetImgui.Listen"),
TEXT("Listen for NetImgui server connection"), TEXT("Listen for NetImgui server connection"),
GetWorld(), GetWorld(),
FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray<FString>& InArgs, UWorld* InWorld) FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray<FString>& InArgs, UWorld* InWorld)
@@ -43,121 +43,129 @@ void FCogEngineWindow_NetImGui::Initialize()
{ {
Disconnect(); Disconnect();
})); }));
FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand(
TEXT("Cog.NetImgui.RunServer"),
TEXT("Run NetImgui server"),
GetWorld(),
FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray<FString>& InArgs, UWorld* InWorld)
{
RunServer();
}));
FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand(
TEXT("Cog.NetImgui.CloseServer"),
TEXT("Close NetImgui server"),
GetWorld(),
FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray<FString>& InArgs, UWorld* InWorld)
{
CloseServer();
}));
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_NetImGui::Shutdown() void FCogEngineWindow_NetImgui::Shutdown()
{ {
if (NetImgui::IsConnected()) if (NetImgui::IsConnected() || NetImgui::IsConnectionPending())
{ {
ImGui::TextUnformatted("Status: Connected"); NetImgui::Disconnect();
if (ImGui::Button("Disconnect"))
{
NetImgui::Disconnect();
}
}
else if (NetImgui::IsConnectionPending())
{
ImGui::TextUnformatted("Status: Waiting Server");
if (ImGui::Button("Cancel"))
{
NetImgui::Disconnect();
}
} }
CloseServer();
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_NetImGui::ResetConfig() void FCogEngineWindow_NetImgui::ResetConfig()
{ {
Super::ResetConfig(); Super::ResetConfig();
Config->Reset(); Config->Reset();
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_NetImGui::RenderHelp() void FCogEngineWindow_NetImgui::RenderHelp()
{ {
ImGui::Text(""); ImGui::Text("This window manage the connection to the NetImgui server."
"See https://github.com/sammyfreg/netImgui for more info.");
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_NetImGui::RenderTick(float DeltaTime) void FCogEngineWindow_NetImgui::RenderTick(float DeltaTime)
{ {
//------------------------------------------------------ //------------------------------------------------------
// Before auto connecting, wait for NetImgui startup, // Before auto connecting, wait for NetImgui startup,
// which require imgui context to be initialized // which require imgui context to be initialized
//------------------------------------------------------ //------------------------------------------------------
if (HasAlreadyTriedToConnectOnDedicatedServer == false if (HasAlreadyTriedToConnect == false && FCogImguiContext::GetIsNetImguiInitialized())
&& Config->AutoConnectOnDedicatedServer {
&& UCogWindowManager::GetIsNetImguiInitialized() const ENetMode NetMode = GetWorld()->GetNetMode();
&& IsRunningDedicatedServer()) const bool ShouldConnect = (Config->AutoConnectOnDedicatedServer && NetMode == NM_DedicatedServer)
|| (Config->AutoConnectOnListenServer && NetMode == NM_ListenServer)
|| (Config->AutoConnectOnClient && NetMode == NM_Client)
|| (Config->AutoConnectOnStandalone && NetMode == NM_Standalone);
if (ShouldConnect)
{ {
ConnectFrom(); if (Config->AutoRunServer)
HasAlreadyTriedToConnectOnDedicatedServer = true; {
ConnectTo();
}
else
{
ConnectFrom();
}
} }
if (Config->AutoRunServer)
{
RunServer();
}
HasAlreadyTriedToConnect = true;
}
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_NetImGui::RenderContent() void FCogEngineWindow_NetImgui::RenderContent()
{ {
Super::RenderContent(); Super::RenderContent();
#if NETIMGUI_ENABLED #if NETIMGUI_ENABLED
if (ImGui::BeginMenuBar()) //----------------------------------------
{ // Status
if (ImGui::BeginMenu("Settings")) //----------------------------------------
{
{
static char Buffer[256] = "";
ImStrncpy(Buffer, TCHAR_TO_ANSI(*Config->ServerName), IM_ARRAYSIZE(Buffer));
if (ImGui::InputText("Server Name", Buffer, IM_ARRAYSIZE(Buffer)))
{
Config->ServerName = FString(Buffer);
}
}
ImGui::InputInt("Server Port", &Config->ServerPort);
ImGui::Separator();
{
static char Buffer[256] = "";
ImStrncpy(Buffer, TCHAR_TO_ANSI(*Config->ClientName), IM_ARRAYSIZE(Buffer));
if (ImGui::InputText("Client Name", Buffer, IM_ARRAYSIZE(Buffer)))
{
Config->ClientName = FString(Buffer);
}
}
ImGui::InputInt("Client Port", &Config->ClientPort);
ImGui::Separator();
ImGui::Checkbox("Auto Listen On Dedicated Server", &Config->AutoConnectOnDedicatedServer);
ImGui::EndMenu();
}
ImGui::EndMenuBar();
}
if (NetImgui::IsConnected()) if (NetImgui::IsConnected())
{ {
ImGui::TextUnformatted("Status: Connected"); ImGui::TextUnformatted("Status: Connected");
if (ImGui::Button("Disconnect")) }
else if (NetImgui::IsConnectionPending())
{
ImGui::TextUnformatted("Status: Waiting Server");
}
else
{
ImGui::TextUnformatted("Status: Not Connected");
}
//----------------------------------------
// Connection buttons
//----------------------------------------
if (NetImgui::IsConnected())
{
if (ImGui::Button("Disconnect", ImVec2(ImGui::GetContentRegionAvail().x, 0)))
{ {
NetImgui::Disconnect(); NetImgui::Disconnect();
} }
} }
else if (NetImgui::IsConnectionPending()) else if (NetImgui::IsConnectionPending())
{ {
ImGui::TextUnformatted("Status: Waiting Server"); if (ImGui::Button("Cancel Connection", ImVec2(ImGui::GetContentRegionAvail().x, 0)))
if (ImGui::Button("Cancel"))
{ {
NetImgui::Disconnect(); NetImgui::Disconnect();
} }
} }
else // No connection else
{ {
ImGui::TextUnformatted("Status: Not Connected");
if (ImGui::Button("Connect", ImVec2(ImGui::GetContentRegionAvail().x, 0))) if (ImGui::Button("Connect", ImVec2(ImGui::GetContentRegionAvail().x, 0)))
{ {
ConnectTo(); ConnectTo();
@@ -177,55 +185,238 @@ void FCogEngineWindow_NetImGui::RenderContent()
} }
} }
//----------------------------------------
// Run/Close server button
//----------------------------------------
if (FPlatformProcess::IsProcRunning(ServerProcess))
{
if (ImGui::Button("Close Server", ImVec2(ImGui::GetContentRegionAvail().x, 0)))
{
CloseServer();
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Close the NetImgui server executable.");
}
}
else
{
if (ImGui::Button("Run Server", ImVec2(ImGui::GetContentRegionAvail().x, 0)))
{
RunServer();
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Run the NetImgui server executable.");
}
}
//----------------------------------------
// Settings
//----------------------------------------
if (ImGui::CollapsingHeader("Settings", ImGuiTreeNodeFlags_DefaultOpen))
{
FCogWindowWidgets::SetNextItemToShortWidth();
FCogWindowWidgets::InputText("Server Address", Config->ServerAddress);
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("NetImgui server application address.");
}
FCogWindowWidgets::SetNextItemToShortWidth();
ImGui::InputInt("Server Port", &Config->ServerPort);
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Port of the NetImgui Server application to connect to.");
}
FCogWindowWidgets::SetNextItemToShortWidth();
FCogWindowWidgets::InputText("Client Name", Config->ClientName);
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Client name displayed in the server's clients list.");
}
FCogWindowWidgets::SetNextItemToShortWidth();
ImGui::InputInt("Client Port", &Config->ClientPort);
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Port this client should wait for connection from server application.");
}
ImGui::Checkbox("Auto Connect on Dedicated Server", &Config->AutoConnectOnDedicatedServer);
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Automatically connect to the NetImgui server when launching on dedicated server mode.");
}
ImGui::Checkbox("Auto Connect on Listen Server", &Config->AutoConnectOnListenServer);
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Automatically connect to the NetImgui server when launching on listen server mode.");
}
ImGui::Checkbox("Auto Connect on Client", &Config->AutoConnectOnClient);
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Automatically connect to the NetImgui server when launching on client mode.");
}
ImGui::Checkbox("Auto Connect on Standalone", &Config->AutoConnectOnStandalone);
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Automatically connect to the NetImgui server when launching on standlone mode.");
}
ImGui::Checkbox("Auto Run Server", &Config->AutoRunServer);
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Automatically run the NetImgui server executable at startup.");
}
FCogWindowWidgets::SetNextItemToShortWidth();
FCogWindowWidgets::InputText("Server Exe Path", Config->ServerExePath);
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Path to NetImgui server executable path. Used to automatically run the NetImgui server executable.");
}
FCogWindowWidgets::SetNextItemToShortWidth();
FCogWindowWidgets::InputText("Server Exe Args", Config->ServerExeArgs);
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Argument used when launching the NetImgui server executable.");
}
}
#endif // #if NETIMGUI_ENABLED #endif // #if NETIMGUI_ENABLED
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_NetImGui::ConnectTo() FString FCogEngineWindow_NetImgui::GetClientName()
{
switch (GetWorld()->GetNetMode())
{
case NM_Standalone:
return FString::Printf(TEXT("%s_%s"), *Config->ClientName, TEXT("Standalone"));
case NM_DedicatedServer:
return FString::Printf(TEXT("%s_%s"), *Config->ClientName, TEXT("DedicatedServer"));
case NM_ListenServer:
return FString::Printf(TEXT("%s_%s"), *Config->ClientName, TEXT("ListenServer"));
case NM_Client:
return FString::Printf(TEXT("%s_%s"), *Config->ClientName, TEXT("Client"));
}
return Config->ClientName;
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_NetImgui::ConnectTo()
{ {
FCogImGuiContextScope ImGuiContextScope(GetOwner()->GetContext()); FCogImGuiContextScope ImGuiContextScope(GetOwner()->GetContext());
UE_LOG(LogCogImGui, Verbose, TEXT("FCogEngineWindow_NetImGui::ConnectTo | Client:%s | Server:%s | ServerPort:%d"), const FString ClientName = GetClientName();
*Config->ClientName,
*Config->ServerName, UE_LOG(LogCogImGui, Verbose, TEXT("FCogEngineWindow_NetImgui::ConnectTo | ClientName:%s | ServerAddress:%s | ServerPort:%d"),
*ClientName,
*Config->ServerAddress,
Config->ServerPort); Config->ServerPort);
const auto clientName = StringCast<ANSICHAR>(*Config->ClientName); const auto clientName = StringCast<ANSICHAR>(*ClientName);
const auto serverName = StringCast<ANSICHAR>(*Config->ServerName); const auto serverAddress = StringCast<ANSICHAR>(*Config->ServerAddress);
NetImgui::ConnectToApp(clientName.Get(), serverName.Get(), Config->ServerPort, nullptr, nullptr); NetImgui::ConnectToApp(clientName.Get(), serverAddress.Get(), Config->ServerPort, nullptr, nullptr);
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_NetImGui::ConnectFrom() void FCogEngineWindow_NetImgui::ConnectFrom()
{ {
FCogImGuiContextScope ImGuiContextScope(GetOwner()->GetContext()); FCogImGuiContextScope ImGuiContextScope(GetOwner()->GetContext());
UE_LOG(LogCogImGui, Verbose, TEXT("FCogEngineWindow_NetImGui::ConnectFrom | Client:%s | ClientPort:%d"), const FString ClientName = GetClientName();
*Config->ClientName,
UE_LOG(LogCogImGui, Verbose, TEXT("FCogEngineWindow_NetImgui::ConnectFrom | ClientName:%s | ClientPort:%d"),
*ClientName,
Config->ClientPort); Config->ClientPort);
const auto clientName = StringCast<ANSICHAR>(*Config->ClientName); const auto clientName = StringCast<ANSICHAR>(*ClientName);
NetImgui::ConnectFromApp(clientName.Get(), Config->ClientPort, nullptr, nullptr); NetImgui::ConnectFromApp(clientName.Get(), Config->ClientPort, nullptr, nullptr);
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_NetImGui::Disconnect() void FCogEngineWindow_NetImgui::Disconnect()
{ {
FCogImGuiContextScope ImGuiContextScope(GetOwner()->GetContext()); FCogImGuiContextScope ImGuiContextScope(GetOwner()->GetContext());
UE_LOG(LogCogImGui, Verbose, TEXT("FCogEngineWindow_NetImGui::Disconnect")); UE_LOG(LogCogImGui, Verbose, TEXT("FCogEngineWindow_NetImgui::Disconnect"));
NetImgui::Disconnect(); NetImgui::Disconnect();
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void UCogEngineConfig_NetImGui::Reset() void FCogEngineWindow_NetImgui::RunServer()
{
if (FPlatformProcess::IsProcRunning(ServerProcess))
{
return;
}
if (Config->ServerExePath.IsEmpty())
{
return;
}
ServerProcess = FPlatformProcess::CreateProc(
*Config->ServerExePath,
*Config->ServerExeArgs,
true,
false,
false,
nullptr,
0,
nullptr,
nullptr
);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_NetImgui::CloseServer()
{
if (FPlatformProcess::IsProcRunning(ServerProcess) == false)
{
return;
}
if (Config->ServerExePath.IsEmpty() == false)
{
FPlatformProcess::TerminateProc(ServerProcess);
}
}
//--------------------------------------------------------------------------------------------------------------------------
// Config
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindowConfig_NetImgui::Reset()
{ {
Super::Reset(); Super::Reset();
#if NETIMGUI_ENABLED #if NETIMGUI_ENABLED
ClientName = FString("cog");
ServerName = FString("localhost"); ClientName = FString("Cog");
ClientPort = NetImgui::kDefaultClientPort; ClientPort = NetImgui::kDefaultClientPort;
AutoConnectOnDedicatedServer = true;
AutoConnectOnListenServer = false;
AutoConnectOnClient = false;
AutoConnectOnStandalone = false;
ServerAddress = FString("127.0.0.1");
ServerPort = NetImgui::kDefaultServerPort; ServerPort = NetImgui::kDefaultServerPort;
ServerExePath = FString("C:\\NetImgui\\Server_Exe\\NetImguiServer.exe");
ServerExeArgs = FString("");
AutoRunServer = false;
#endif #endif
} }
@@ -139,7 +139,7 @@ void FCogEngineWindow_Selection::ActivateSelectionMode()
bSelectionModeActive = true; bSelectionModeActive = true;
bIsInputEnabledBeforeEnteringSelectionMode = GetOwner()->GetContext().GetEnableInput(); bIsInputEnabledBeforeEnteringSelectionMode = GetOwner()->GetContext().GetEnableInput();
GetOwner()->GetContext().SetEnableInput(true); GetOwner()->GetContext().SetEnableInput(true);
GetOwner()->SetHideAllWindows(true); GetOwner()->SetActivateSelectionMode(true);
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
@@ -161,7 +161,7 @@ void FCogEngineWindow_Selection::DeactivateSelectionMode()
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
GetOwner()->GetContext().SetEnableInput(bIsInputEnabledBeforeEnteringSelectionMode); GetOwner()->GetContext().SetEnableInput(bIsInputEnabledBeforeEnteringSelectionMode);
GetOwner()->SetHideAllWindows(false); GetOwner()->SetActivateSelectionMode(false);
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
@@ -254,7 +254,15 @@ void FCogEngineWindow_Selection::TickSelectionMode()
AActor* HoveredActor = nullptr; AActor* HoveredActor = nullptr;
FVector WorldOrigin, WorldDirection; FVector WorldOrigin, WorldDirection;
if (UGameplayStatics::DeprojectScreenToWorld(PlayerController, FCogImguiHelper::ToFVector2D(ImGui::GetMousePos() - ViewportPos), WorldOrigin, WorldDirection))
//-----------------------------------------------------------------------------------------------
// Do not use imgui mouse pos because when connected to NetImgui, the mouse position is invalid.
// See https://github.com/sammyfreg/netImgui/issues/61
//-----------------------------------------------------------------------------------------------
//ImVec2 mousePos = ImGui::GetMousePos();
ImVec2 mousePos = GetOwner()->GetContext().GetImguiMousePos();
if (UGameplayStatics::DeprojectScreenToWorld(PlayerController, FCogImguiHelper::ToFVector2D(mousePos - ViewportPos), WorldOrigin, WorldDirection))
{ {
//-------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------
// Prioritize another actor than the selected actor unless we only touch the selected actor. // Prioritize another actor than the selected actor unless we only touch the selected actor.
@@ -3,11 +3,11 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "CogCommonConfig.h" #include "CogCommonConfig.h"
#include "CogWindow.h" #include "CogWindow.h"
#include "CogEngineWindow_NetImGui.generated.h" #include "CogEngineWindow_NetImgui.generated.h"
class UCogEngineConfig_NetImGui; class UCogEngineWindowConfig_NetImgui;
class COGENGINE_API FCogEngineWindow_NetImGui : public FCogWindow class COGENGINE_API FCogEngineWindow_NetImgui : public FCogWindow
{ {
typedef FCogWindow Super; typedef FCogWindow Super;
@@ -35,16 +35,24 @@ protected:
void TryStartup(); void TryStartup();
void RunServer();
void CloseServer();
private: private:
TWeakObjectPtr<UCogEngineConfig_NetImGui> Config = nullptr; FString GetClientName();
bool HasAlreadyTriedToConnectOnDedicatedServer = false; TObjectPtr<UCogEngineWindowConfig_NetImgui> Config = nullptr;
bool HasAlreadyTriedToConnect = false;
FProcHandle ServerProcess;
}; };
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
UCLASS(Config = Cog) UCLASS(Config = Cog)
class UCogEngineConfig_NetImGui : public UCogCommonConfig class UCogEngineWindowConfig_NetImgui : public UCogCommonConfig
{ {
GENERATED_BODY() GENERATED_BODY()
@@ -53,17 +61,35 @@ public:
virtual void Reset() override; virtual void Reset() override;
UPROPERTY(Config) UPROPERTY(Config)
FString ClientName = FString("cog"); FString ClientName = FString("Cog");
UPROPERTY(Config)
FString ServerName = FString("localhost");
UPROPERTY(Config)
int32 ServerPort = 8888;
UPROPERTY(Config) UPROPERTY(Config)
int32 ClientPort = 8889; int32 ClientPort = 8889;
UPROPERTY(Config) UPROPERTY(Config)
bool AutoConnectOnDedicatedServer = true; bool AutoConnectOnDedicatedServer = true;
UPROPERTY(Config)
bool AutoConnectOnListenServer = false;
UPROPERTY(Config)
bool AutoConnectOnClient = false;
UPROPERTY(Config)
bool AutoConnectOnStandalone = false;
UPROPERTY(Config)
FString ServerAddress = FString("127.0.0.1");
UPROPERTY(Config)
int32 ServerPort = 8888;
UPROPERTY(Config)
FString ServerExePath = FString("C:\\NetImgui\\Server_Exe\\NetImguiServer.exe");
UPROPERTY(Config)
FString ServerExeArgs = FString("");
UPROPERTY(Config)
bool AutoRunServer = false;
}; };
@@ -18,6 +18,7 @@
#include "imgui_internal.h" #include "imgui_internal.h"
#include "implot.h" #include "implot.h"
#include "Misc/EngineVersionComparison.h" #include "Misc/EngineVersionComparison.h"
#include "NetImgui_Api.h"
#include "TextureResource.h" #include "TextureResource.h"
#include "Widgets/SViewport.h" #include "Widgets/SViewport.h"
#include "Widgets/SWindow.h" #include "Widgets/SWindow.h"
@@ -51,6 +52,8 @@ FCogImGuiContextScope::
ImPlot::SetCurrentContext(PrevPlotContext); ImPlot::SetCurrentContext(PrevPlotContext);
} }
//--------------------------------------------------------------------------------------------------------------------------
bool FCogImguiContext::bIsNetImguiInitialized = false;
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::Initialize() void FCogImguiContext::Initialize()
@@ -139,6 +142,14 @@ void FCogImguiContext::Initialize()
DisplayMetrics.MonitorInfo.Add(monitorInfo); DisplayMetrics.MonitorInfo.Add(monitorInfo);
OnDisplayMetricsChanged(DisplayMetrics); OnDisplayMetricsChanged(DisplayMetrics);
} }
#if NETIMGUI_ENABLED
if (bIsNetImguiInitialized == false)
{
NetImgui::Startup();
bIsNetImguiInitialized = true;
}
#endif
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
@@ -146,6 +157,17 @@ void FCogImguiContext::Shutdown()
{ {
FCogImGuiContextScope ImGuiContextScope(ImGuiContext, PlotContext); FCogImGuiContextScope ImGuiContextScope(ImGuiContext, PlotContext);
//------------------------------------------------------------------
// NetImgui must be shutdown before imgui as it uses context hooks
//------------------------------------------------------------------
#if NETIMGUI_ENABLED
if (bIsNetImguiInitialized)
{
NetImgui::Shutdown();
bIsNetImguiInitialized = false;
}
#endif
if (ImGuiViewport* MainViewport = ImGui::GetMainViewport()) if (ImGuiViewport* MainViewport = ImGui::GetMainViewport())
{ {
if (const FCogImGuiViewportData* ViewportData = static_cast<FCogImGuiViewportData*>(MainViewport->PlatformUserData)) if (const FCogImGuiViewportData* ViewportData = static_cast<FCogImGuiViewportData*>(MainViewport->PlatformUserData))
@@ -287,7 +309,7 @@ bool FCogImguiContext::BeginFrame(float InDeltaTime)
//------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------
// //
//------------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------------
if (bEnableInput) if (bEnableInput || NetImgui::IsConnected())
{ {
IO.ConfigFlags &= ~ImGuiConfigFlags_NoMouse; IO.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
} }
@@ -296,7 +318,7 @@ bool FCogImguiContext::BeginFrame(float InDeltaTime)
IO.ConfigFlags |= ImGuiConfigFlags_NoMouse; IO.ConfigFlags |= ImGuiConfigFlags_NoMouse;
} }
if (MainWidget != nullptr) if (MainWidget != nullptr && FSlateApplication::IsInitialized())
{ {
const bool bHasMouse = (IO.ConfigFlags & ImGuiConfigFlags_NoMouse) == 0; const bool bHasMouse = (IO.ConfigFlags & ImGuiConfigFlags_NoMouse) == 0;
const bool bUpdateMouseMouseCursor = (IO.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) == 0; const bool bUpdateMouseMouseCursor = (IO.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) == 0;
@@ -305,18 +327,10 @@ bool FCogImguiContext::BeginFrame(float InDeltaTime)
MainWidget->SetCursor(FCogImguiInputHelper::ToSlateMouseCursor(ImGui::GetMouseCursor())); MainWidget->SetCursor(FCogImguiInputHelper::ToSlateMouseCursor(ImGui::GetMouseCursor()));
} }
if (FSlateApplication::IsInitialized()) if (bEnableInput)
{ {
const FVector2D& MousePosition = FSlateApplication::Get().GetCursorPos(); const ImVec2 mousePos = GetImguiMousePos();
if (IO.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) IO.AddMousePosEvent(mousePos.x, mousePos.y);
{
IO.AddMousePosEvent(MousePosition.X, MousePosition.Y);
}
else
{
const FVector2D TransformedMousePosition = MousePosition - MainWidget->GetTickSpaceGeometry().GetAbsolutePosition();
IO.AddMousePosEvent(TransformedMousePosition.X, TransformedMousePosition.Y);
}
} }
} }
@@ -334,18 +348,37 @@ bool FCogImguiContext::BeginFrame(float InDeltaTime)
} }
ImGui::NewFrame(); ImGui::NewFrame();
//if (NetImgui::NewFrame(true) == false)
//{
// return false;
//}
//DrawDebug(); //DrawDebug();
return true; return true;
} }
//--------------------------------------------------------------------------------------------------------------------------
ImVec2 FCogImguiContext::GetImguiMousePos()
{
const FVector2D& MousePosition = FSlateApplication::Get().GetCursorPos();
if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
return ImVec2(MousePosition.X, MousePosition.Y);
}
const FVector2D TransformedMousePosition = MousePosition - MainWidget->GetTickSpaceGeometry().GetAbsolutePosition();
return ImVec2(TransformedMousePosition.X, TransformedMousePosition.Y);
}
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::EndFrame() void FCogImguiContext::EndFrame()
{ {
FCogImGuiContextScope ImGuiContextScope(ImGuiContext, PlotContext); FCogImGuiContextScope ImGuiContextScope(ImGuiContext, PlotContext);
ImGui::Render(); ImGui::Render();
//NetImgui::EndFrame();
ImGui_RenderWindow(ImGui::GetMainViewport(), nullptr); ImGui_RenderWindow(ImGui::GetMainViewport(), nullptr);
ImGui::UpdatePlatformWindows(); ImGui::UpdatePlatformWindows();
@@ -862,3 +895,16 @@ ULocalPlayer* FCogImguiContext::GetLocalPlayer() const
ULocalPlayer* LocalPlayer = World->GetFirstLocalPlayerFromController(); ULocalPlayer* LocalPlayer = World->GetFirstLocalPlayerFromController();
return LocalPlayer; return LocalPlayer;
} }
//--------------------------------------------------------------------------------------------------------------------------
bool FCogImguiContext::GetSkipRendering() const
{
return bSkipRendering;
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::SetSkipRendering(bool Value)
{
bSkipRendering = Value;
}
@@ -45,6 +45,10 @@ int32 SCogImguiWidget::OnPaint(
const FWidgetStyle& WidgetStyle, const FWidgetStyle& WidgetStyle,
bool bParentEnabled) const bool bParentEnabled) const
{ {
if (Context == nullptr || Context->GetSkipRendering())
{
return LayerId;
}
const FSlateRenderTransform Transform(FCogImguiHelper::RoundTranslation(AllottedGeometry.GetAccumulatedRenderTransform().GetTranslation() - FVector2d(DrawData.DisplayPos))); const FSlateRenderTransform Transform(FCogImguiHelper::RoundTranslation(AllottedGeometry.GetAccumulatedRenderTransform().GetTranslation() - FVector2d(DrawData.DisplayPos)));
@@ -65,16 +65,26 @@ public:
bool BeginFrame(float InDeltaTime); bool BeginFrame(float InDeltaTime);
void GetCursorPos(ImGuiIO& IO);
void EndFrame(); void EndFrame();
float GetDpiScale() const { return DpiScale; } float GetDpiScale() const { return DpiScale; }
void SetDPIScale(float Value); void SetDPIScale(float Value);
bool GetSkipRendering() const;
void SetSkipRendering(bool Value);
ImVec2 GetImguiMousePos();
TObjectPtr<const UGameViewportClient> GetGameViewport() const { return GameViewport; } TObjectPtr<const UGameViewportClient> GetGameViewport() const { return GameViewport; }
TSharedPtr<const SCogImguiWidget> GetMainWidget() const { return MainWidget; } TSharedPtr<const SCogImguiWidget> GetMainWidget() const { return MainWidget; }
static bool GetIsNetImguiInitialized() { return bIsNetImguiInitialized; }
private: private:
friend struct FCogImGuiContextScope; friend struct FCogImGuiContextScope;
@@ -161,4 +171,6 @@ private:
bool bWantCaptureMouse = false; bool bWantCaptureMouse = false;
float DpiScale = 1.f; float DpiScale = 1.f;
static bool bIsNetImguiInitialized;
}; };
@@ -23,8 +23,6 @@ FString UCogWindowManager::LoadLayoutCommand = TEXT("Cog.LoadLayout");
FString UCogWindowManager::SaveLayoutCommand = TEXT("Cog.SaveLayout"); FString UCogWindowManager::SaveLayoutCommand = TEXT("Cog.SaveLayout");
FString UCogWindowManager::ResetLayoutCommand = TEXT("Cog.ResetLayout"); FString UCogWindowManager::ResetLayoutCommand = TEXT("Cog.ResetLayout");
bool UCogWindowManager::IsNetImguiInitialized = false;
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
UCogWindowManager::UCogWindowManager() UCogWindowManager::UCogWindowManager()
{ {
@@ -132,15 +130,6 @@ void UCogWindowManager::InitializeInternal()
} }
})); }));
#if NETIMGUI_ENABLED
if (IsNetImguiInitialized == false)
{
NetImgui::Startup();
IsNetImguiInitialized = true;
}
#endif
IsInitialized = true; IsInitialized = true;
} }
@@ -159,17 +148,6 @@ void UCogWindowManager::Shutdown()
Window->PreSaveConfig(); Window->PreSaveConfig();
} }
//------------------------------------------------------------------
// NetImgui must be shutdown before imgui as it uses context hooks
//------------------------------------------------------------------
#if NETIMGUI_ENABLED
if (IsNetImguiInitialized)
{
NetImgui::Shutdown();
IsNetImguiInitialized = false;
}
#endif
//------------------------------------------------------------------ //------------------------------------------------------------------
// Destroy ImGui before destroying the windows to make sure // Destroy ImGui before destroying the windows to make sure
// imgui serialize their visibility state in imgui.ini // imgui serialize their visibility state in imgui.ini
@@ -223,6 +201,9 @@ void UCogWindowManager::Tick(float DeltaTime)
Window->GameTick(DeltaTime); Window->GameTick(DeltaTime);
} }
const bool shouldSkipRendering = NetImgui::IsConnected() && bIsSelectionModeActive == false;
Context.SetSkipRendering(shouldSkipRendering);
if (Context.BeginFrame(DeltaTime)) if (Context.BeginFrame(DeltaTime))
{ {
Render(DeltaTime); Render(DeltaTime);
@@ -246,19 +227,25 @@ void UCogWindowManager::Render(float DeltaTime)
FCogWindowWidgets::PushStyleCompact(); FCogWindowWidgets::PushStyleCompact();
} }
if (bHideAllWindows == false) //----------------------------------------------------------------------
// There is no need to have Imgui input enabled if the imgui rendering
// is only done on the NetImgui server. So we disable imgui input.
//----------------------------------------------------------------------
if (Context.GetEnableInput() && NetImgui::IsConnected() && bIsSelectionModeActive == false)
{ {
if (Context.GetEnableInput()) Context.SetEnableInput(false);
{ }
RenderMainMenu();
} if ((Context.GetEnableInput() || NetImgui::IsConnected()) && bIsSelectionModeActive == false)
{
RenderMainMenu();
} }
for (FCogWindow* Window : Windows) for (FCogWindow* Window : Windows)
{ {
Window->RenderTick(DeltaTime); Window->RenderTick(DeltaTime);
if (Window->GetIsVisible() && bHideAllWindows == false) if (Window->GetIsVisible() && bIsSelectionModeActive == false)
{ {
if (SettingsWindow->GetSettingsConfig()->bTransparentMode) if (SettingsWindow->GetSettingsConfig()->bTransparentMode)
{ {
@@ -314,10 +301,15 @@ FCogWindow* UCogWindowManager::FindWindowByID(const ImGuiID ID)
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
void UCogWindowManager::SetHideAllWindows(const bool Value) void UCogWindowManager::SetActivateSelectionMode(const bool Value)
{ {
HideAllWindowsCounter = FMath::Max(HideAllWindowsCounter + (Value ? +1 : -1), 0); SelectionModeActiveCounter = FMath::Max(SelectionModeActiveCounter + (Value ? 1 : -1), 0);
bHideAllWindows = HideAllWindowsCounter > 0; bIsSelectionModeActive = SelectionModeActiveCounter > 0;
if (bIsSelectionModeActive)
{
Context.SetEnableInput(true);
}
} }
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
@@ -429,7 +421,6 @@ void UCogWindowManager::RenderMainMenu()
ImGui::Separator(); ImGui::Separator();
RenderMenuItem(*LayoutsWindow, "Layouts"); RenderMenuItem(*LayoutsWindow, "Layouts");
RenderMenuItem(*SettingsWindow, "Settings"); RenderMenuItem(*SettingsWindow, "Settings");
if (ImGui::BeginMenu("Spacing")) if (ImGui::BeginMenu("Spacing"))
@@ -880,4 +871,3 @@ void UCogWindowManager::DisableInputMode()
UE_LOG(LogCogImGui, Verbose, TEXT("UCogWindowManager::DisableInputMode")); UE_LOG(LogCogImGui, Verbose, TEXT("UCogWindowManager::DisableInputMode"));
Context.SetEnableInput(false); Context.SetEnableInput(false);
} }
@@ -1029,4 +1029,19 @@ void FCogWindowWidgets::SmallButton(const char* Text, const ImVec4& Color)
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(Color.x, Color.y, Color.z, Color.w * 1.0f)); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(Color.x, Color.y, Color.z, Color.w * 1.0f));
ImGui::SmallButton(Text); ImGui::SmallButton(Text);
ImGui::PopStyleColor(3); ImGui::PopStyleColor(3);
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogWindowWidgets::InputText(const char* Text, FString& Value)
{
static char Buffer[256] = "";
ImStrncpy(Buffer, TCHAR_TO_ANSI(*Value), IM_ARRAYSIZE(Buffer));
bool result = ImGui::InputText(Text, Buffer, IM_ARRAYSIZE(Buffer));
if (result)
{
Value = FString(Buffer);
}
return result;
} }
@@ -36,6 +36,7 @@ public:
virtual void Tick(float DeltaTime); virtual void Tick(float DeltaTime);
virtual void AddWindow(FCogWindow* Window, const FString& Name, bool AddToMainMenu = true); virtual void AddWindow(FCogWindow* Window, const FString& Name, bool AddToMainMenu = true);
template<class T> template<class T>
@@ -51,9 +52,9 @@ public:
virtual void SaveLayout(int32 LayoutIndex); virtual void SaveLayout(int32 LayoutIndex);
virtual bool GetHideAllWindows() const { return bHideAllWindows; } virtual bool GetHideAllWindows() const { return bIsSelectionModeActive; }
virtual void SetHideAllWindows(bool Value); virtual void SetActivateSelectionMode(bool Value);
virtual void ResetAllWindowsConfig(); virtual void ResetAllWindowsConfig();
@@ -79,8 +80,6 @@ public:
static void SortCommands(UPlayerInput* PlayerInput); static void SortCommands(UPlayerInput* PlayerInput);
static bool GetIsNetImguiInitialized() { return IsNetImguiInitialized; }
protected: protected:
friend class FCogWindow_Layouts; friend class FCogWindow_Layouts;
@@ -156,13 +155,11 @@ protected:
int32 LayoutToLoad = -1; int32 LayoutToLoad = -1;
int32 HideAllWindowsCounter = 0; int32 SelectionModeActiveCounter = 0;
bool bHideAllWindows = false; bool bIsSelectionModeActive = false;
bool IsInitialized = false; bool IsInitialized = false;
static bool IsNetImguiInitialized;
}; };
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
@@ -104,6 +104,9 @@ public:
static void ActorFrame(const AActor& Actor); static void ActorFrame(const AActor& Actor);
static void SmallButton(const char* Text, const ImVec4& Color); static void SmallButton(const char* Text, const ImVec4& Color);
static bool InputText(const char* Text, FString& Value);
}; };
template<typename EnumType> template<typename EnumType>
@@ -18,8 +18,8 @@
#include "CogEngineWindow_Inspector.h" #include "CogEngineWindow_Inspector.h"
#include "CogEngineWindow_LogCategories.h" #include "CogEngineWindow_LogCategories.h"
#include "CogEngineWindow_Metrics.h" #include "CogEngineWindow_Metrics.h"
#include "CogEngineWindow_NetImgui.h"
#include "CogEngineWindow_NetEmulation.h" #include "CogEngineWindow_NetEmulation.h"
#include "CogEngineWindow_NetImGui.h"
#include "CogEngineWindow_OutputLog.h" #include "CogEngineWindow_OutputLog.h"
#include "CogEngineWindow_Plots.h" #include "CogEngineWindow_Plots.h"
#include "CogEngineWindow_Scalability.h" #include "CogEngineWindow_Scalability.h"
@@ -70,7 +70,7 @@ void Cog::AddAllWindows(UCogWindowManager& CogWindowManager)
CogWindowManager.AddWindow<FCogEngineWindow_NetEmulation>("Engine.Net Emulation"); CogWindowManager.AddWindow<FCogEngineWindow_NetEmulation>("Engine.Net Emulation");
CogWindowManager.AddWindow<FCogEngineWindow_NetImGui>("Engine.NetImGui"); CogWindowManager.AddWindow<FCogEngineWindow_NetImgui>("Engine.Net ImGui");
CogWindowManager.AddWindow<FCogEngineWindow_OutputLog>("Engine.Output Log"); CogWindowManager.AddWindow<FCogEngineWindow_OutputLog>("Engine.Output Log");