Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NetImgui branch update #1

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Binary file added NetImguiServer/Background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions NetImguiServer/netImgui.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"CompressionEnable": true,
"Configs": [
{
"Auto": true,
"HostPort": 8889,
"Hostname": "localhost",
"Name": "UE Game"
},
{
"Auto": true,
"HostPort": 8890,
"Hostname": "localhost",
"Name": "UE Editor"
},
{
"Auto": true,
"HostPort": 8891,
"Hostname": "localhost",
"Name": "UE Server"
}
],
"Note": "netImgui Server's list of Clients (Using JSON format).",
"RefreshFPSActive": 30.0,
"RefreshFPSInactive": 30.0,
"ServerPort": 8888,
"Version": 2
}
Binary file added NetImguiServer/netImguiServer.exe
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't like this, including binaries in the repository. This should be a separate download, ideally from NetImgui itself?

Copy link
Author

@sammyfreg sammyfreg Jul 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The server app needs to match the client code included. Since the .exe is small, I always included it pre-compiled together to keep simple for users. I could store it on a github wiki, like I do for the github webpage's images. I guess it will also need to have an updated webpage documentation to include the link.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the server application and updated the documentation.

Binary file not shown.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Dear ImGui is an immediate-mode graphical user interface library that is very li
Status
------
- [ImGui `v1.89.6`](https://github.com/ocornut/imgui/releases/tag/v1.89.6)
- [NetImgui `v1.9`](https://github.com/sammyfreg/netImgui/releases/tag/v1.9.0)
- [ImPlot `v0.14+18758e23`](https://github.com/epezent/implot/tree/18758e237e8906a97ddf42de1e75793526f30ce9)

Supported Unreal Engine version: `4.26`, `5.0`, `5.1`, `5.2`
Expand Down Expand Up @@ -104,6 +105,19 @@ void Init()
SceneCaptureComponent2D->CaptureSource = ESceneCaptureSource::SCS_FinalToneCurveHDR;
}
```
How to Set up NetImgui
----------------------

To use NetImgui, use content of the *net_imgui* branch in place of *master*. This will be gradually merged into the *master* but until then you need to use that experimental branch.

Similarly like ImGui, NetImgui is built as part of the UnrealImGui plugin and no other integration steps are required.

To be able to connect to the Unreal editor or application that use NetImgui, you need to run a server (netImguiServer). Please, see the [NetImgui](https://github.com/sammyfreg/netImgui) page for instructions how to get it.

After launching the server for the first time, you need to add two client configurations, for ports 8889 and 8890. After that, you can either initialise connection from the server or set it to autoconnection mode. More info will be added later.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still true if netImgui.cfg is provided?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right this is no longuer needed with provided config (the 2 basics config). Still need to add console config. It'll update this info.


Once you establish connection, you can use a top bar to switch between contexts and modes. In standalone game it should be one context and in the editor one editor context, plus one for each PIE instance.
Please, note that all those features are experimental and might evolve. Any input is welcomed.

### Troubleshooting
If you're using a scene capture and your quad is not drawing at all, make sure your scene capture "Capture Source" is set to "Final Color (with tone curve) in Linear sRGB gamut" to avoid alpha being set to 0 (since there's no way to instruct ImGui to ignore alpha without modding the core UnrealImGui plugin).
Expand Down
5 changes: 3 additions & 2 deletions Source/ImGui/ImGui.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ public ImGui(TargetInfo Target)
"Engine",
"InputCore",
"Slate",
"SlateCore"
// ... add private dependencies that you statically link with here ...
"SlateCore",
"NetImguiLibrary"
// ... add private dependencies that you statically link with here ...
}
);

Expand Down
30 changes: 26 additions & 4 deletions Source/ImGui/Private/ImGuiContextManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@
#include "ImGuiContextManager.h"

#include "ImGuiDelegatesContainer.h"
#include "ImGuiImplementation.h"
#include "ThirdPartyBuildNetImgui.h"
#include "ImGuiModuleSettings.h"
#include "ImGuiModule.h"
#include "Utilities/WorldContext.h"
#include "Utilities/WorldContextIndex.h"

#include <imgui.h>

#include "Fonts/Roboto_Medium.cpp"
#include "Fonts/Cousine_Regular.cpp"
#include "Fonts/Droid_Sans.cpp"
#include "Fonts/Karla_Regular.cpp"
#include "Fonts/Proggy_Tiny.cpp"

// MSVC warnings
#ifdef _MSC_VER
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
Expand Down Expand Up @@ -89,6 +95,8 @@ FImGuiContextManager::~FImGuiContextManager()

void FImGuiContextManager::Tick(float DeltaSeconds)
{
NetImguiUpdate(Contexts);

// In editor, worlds can get invalid. We could remove corresponding entries, but that would mean resetting ImGui
// context every time when PIE session is restarted. Instead we freeze contexts until their worlds are re-created.

Expand Down Expand Up @@ -150,7 +158,7 @@ void FImGuiContextManager::OnWorldPostActorTick(UWorld* World, ELevelTick TickTy
#endif // ENGINE_COMPATIBILITY_WITH_WORLD_POST_ACTOR_TICK

#if WITH_EDITOR
FImGuiContextManager::FContextData& FImGuiContextManager::GetEditorContextData()
FContextData& FImGuiContextManager::GetEditorContextData()
{
FContextData* Data = Contexts.Find(Utilities::EDITOR_CONTEXT_INDEX);

Expand All @@ -165,7 +173,7 @@ FImGuiContextManager::FContextData& FImGuiContextManager::GetEditorContextData()
#endif // WITH_EDITOR

#if !WITH_EDITOR
FImGuiContextManager::FContextData& FImGuiContextManager::GetStandaloneWorldContextData()
FContextData& FImGuiContextManager::GetStandaloneWorldContextData()
{
FContextData* Data = Contexts.Find(Utilities::STANDALONE_GAME_CONTEXT_INDEX);

Expand All @@ -179,7 +187,7 @@ FImGuiContextManager::FContextData& FImGuiContextManager::GetStandaloneWorldCont
}
#endif // !WITH_EDITOR

FImGuiContextManager::FContextData& FImGuiContextManager::GetWorldContextData(const UWorld& World, int32* OutIndex)
FContextData& FImGuiContextManager::GetWorldContextData(const UWorld& World, int32* OutIndex)
{
using namespace Utilities;

Expand Down Expand Up @@ -263,9 +271,23 @@ void FImGuiContextManager::BuildFontAtlas(const TMap<FName, TSharedPtr<ImFontCon
{
if (!FontAtlas.IsBuilt())
{
//---------------------------------------------------------------------------------------------
// Load our Font (Must be loaded in same order as FImguiModule::eFont enum)
ImFontConfig FontConfig = {};
FontConfig.SizePixels = FMath::RoundFromZero(13.f * DPIScale);
FontAtlas.AddFontDefault(&FontConfig);
FPlatformString::Strcpy(FontConfig.Name, sizeof(FontConfig.Name), "Roboto Medium, 16px");
FontAtlas.AddFontFromMemoryCompressedTTF(Roboto_Medium_compressed_data, Roboto_Medium_compressed_size, 16.0f*DPIScale, &FontConfig);
FPlatformString::Strcpy(FontConfig.Name, sizeof(FontConfig.Name), "Cousine Regular, 15px");
FontAtlas.AddFontFromMemoryCompressedTTF(Cousine_Regular_compressed_data, Cousine_Regular_compressed_size, 15.0f*DPIScale, &FontConfig);
FPlatformString::Strcpy(FontConfig.Name, sizeof(FontConfig.Name), "Karla Regular, 16px");
FontAtlas.AddFontFromMemoryCompressedTTF(Karla_Regular_compressed_data, Karla_Regular_compressed_size, 16.0f*DPIScale, &FontConfig);
FPlatformString::Strcpy(FontConfig.Name, sizeof(FontConfig.Name), "Droid Sans, 16px");
FontAtlas.AddFontFromMemoryCompressedTTF(Droid_Sans_compressed_data, Droid_Sans_compressed_size, 16.0f*DPIScale, &FontConfig);
FPlatformString::Strcpy(FontConfig.Name, sizeof(FontConfig.Name), "Proggy Tiny, 10px");
FontAtlas.AddFontFromMemoryCompressedTTF(Proggy_Tiny_compressed_data, Proggy_Tiny_compressed_size, 10.0f*DPIScale, &FontConfig);

// ... add extra fonts here (and add extra entry in 'FImguiModule::eFont' enum)

// Build custom fonts
for (const TPair<FName, TSharedPtr<ImFontConfig>>& CustomFontPair : CustomFontConfigs)
Expand Down
34 changes: 20 additions & 14 deletions Source/ImGui/Private/ImGuiContextManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,26 @@ struct FImGuiDPIScaleInfo;
// @param ContextProxy - Created context proxy
DECLARE_MULTICAST_DELEGATE_TwoParams(FContextProxyCreatedDelegate, int32, FImGuiContextProxy&);

// NETIMGUI_ENABLED
// NOTE: Made this public, to share with NetImgui. Need access to the proxy and CanTick property
// Could be done other ways like building the data and sending it to NetImguiUpdate
// instead of accessing it directly)
struct FContextData
{
FContextData(const FString& ContextName, int32 ContextIndex, ImFontAtlas& FontAtlas, float DPIScale, int32 InPIEInstance = -1)
: PIEInstance(InPIEInstance)
, ContextProxy(new FImGuiContextProxy(ContextName, ContextIndex, &FontAtlas, DPIScale))
{
}

FORCEINLINE bool CanTick() const { return PIEInstance < 0 || GEngine->GetWorldContextFromPIEInstance(PIEInstance); }

int32 PIEInstance = -1;
TUniquePtr<FImGuiContextProxy> ContextProxy;
};
// NETIMGUI_ENABLED


// Manages ImGui context proxies.
class FImGuiContextManager
{
Expand Down Expand Up @@ -70,20 +90,6 @@ class FImGuiContextManager

private:

struct FContextData
{
FContextData(const FString& ContextName, int32 ContextIndex, ImFontAtlas& FontAtlas, float DPIScale, int32 InPIEInstance = -1)
: PIEInstance(InPIEInstance)
, ContextProxy(new FImGuiContextProxy(ContextName, ContextIndex, &FontAtlas, DPIScale))
{
}

FORCEINLINE bool CanTick() const { return PIEInstance < 0 || GEngine->GetWorldContextFromPIEInstance(PIEInstance); }

int32 PIEInstance = -1;
TUniquePtr<FImGuiContextProxy> ContextProxy;
};

#if ENGINE_COMPATIBILITY_LEGACY_WORLD_ACTOR_TICK
void OnWorldTickStart(ELevelTick TickType, float DeltaSeconds);
#endif
Expand Down
87 changes: 59 additions & 28 deletions Source/ImGui/Private/ImGuiContextProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include "ImGuiContextProxy.h"

#include "ImGuiDelegatesContainer.h"
#include "ImGuiImplementation.h"
#include "ThirdPartyBuildNetImgui.h"
#include "ImGuiInteroperability.h"
#include "Utilities/Arrays.h"
#include "VersionCompatibility.h"
Expand Down Expand Up @@ -152,12 +152,20 @@ void FImGuiContextProxy::DrawEarlyDebug()
if (bIsFrameStarted && !bIsDrawEarlyDebugCalled)
{
bIsDrawEarlyDebugCalled = true;
if( NetImGuiCanDrawProxy(this) )
{
SetAsCurrent();

// Delegates called in order specified in FImGuiDelegates.
BroadcastMultiContextEarlyDebug();
BroadcastWorldEarlyDebug();
}

SetAsCurrent();

// Delegates called in order specified in FImGuiDelegates.
BroadcastMultiContextEarlyDebug();
BroadcastWorldEarlyDebug();
if( NetImGuiSetupDrawRemote(this) )
{
BroadcastMultiContextEarlyDebug();
BroadcastWorldEarlyDebug();
}
}
}

Expand All @@ -170,22 +178,29 @@ void FImGuiContextProxy::DrawDebug()
// Make sure that early debug is always called first to guarantee order specified in FImGuiDelegates.
DrawEarlyDebug();

SetAsCurrent();
if (NetImGuiCanDrawProxy(this))
{
SetAsCurrent();

// Delegates called in order specified in FImGuiDelegates.
BroadcastWorldDebug();
BroadcastMultiContextDebug();
// Delegates called in order specified in FImGuiDelegates.
BroadcastWorldDebug();
BroadcastMultiContextDebug();
}

if (NetImGuiSetupDrawRemote(this))
{
BroadcastWorldDebug();
BroadcastMultiContextDebug();
}
}
}

void FImGuiContextProxy::Tick(float DeltaSeconds)
{
// Making sure that we tick only once per frame.
if (LastFrameNumber < GFrameNumber)
if (LastFrameNumber < GFrameCounter)
{
LastFrameNumber = GFrameNumber;

SetAsCurrent();
LastFrameNumber = GFrameCounter;

if (bIsFrameStarted)
{
Expand Down Expand Up @@ -214,16 +229,17 @@ void FImGuiContextProxy::BeginFrame(float DeltaTime)
{
if (!bIsFrameStarted)
{
ImGuiIO& IO = ImGui::GetIO();
IO.DeltaTime = DeltaTime;
if( NetImGuiCanDrawProxy(this) )
{
SetAsCurrent();
ImGuiIO& IO = ImGui::GetIO();
IO.DeltaTime = DeltaTime;
IO.DisplaySize = { (float)DisplaySize.X, (float)DisplaySize.Y };
ImGuiInterops::CopyInput(IO, InputState);
ImGui::NewFrame();
}

ImGuiInterops::CopyInput(IO, InputState);
InputState.ClearUpdateState();

IO.DisplaySize = { (float)DisplaySize.X, (float)DisplaySize.Y };

ImGui::NewFrame();

bIsFrameStarted = true;
bIsDrawEarlyDebugCalled = false;
bIsDrawDebugCalled = false;
Expand All @@ -234,17 +250,32 @@ void FImGuiContextProxy::EndFrame()
{
if (bIsFrameStarted)
{
// Prepare draw data (after this call we cannot draw to this context until we start a new frame).
ImGui::Render();

// Update our draw data, so we can use them later during Slate rendering while ImGui is in the middle of the
// next frame.
UpdateDrawData(ImGui::GetDrawData());
if ( NetImGuiCanDrawProxy(this) )
{
// Prepare draw data (after this call we cannot draw to this context until we start a new frame).
SetAsCurrent();
ImGui::Render();

// Update our draw data, so we can use them later during Slate rendering while ImGui is in the middle of the
// next frame.
UpdateDrawData(ImGui::GetDrawData());
}
bIsFrameStarted = false;
}
}

// Is this context the current ImGui context.
bool FImGuiContextProxy::IsCurrentContext() const
{
return ImGui::GetCurrentContext() == Context;
}

// Set this context as current ImGui context.
void FImGuiContextProxy::SetAsCurrent()
{
ImGui::SetCurrentContext(Context);
}

void FImGuiContextProxy::UpdateDrawData(ImDrawData* DrawData)
{
if (DrawData && DrawData->CmdListsCount > 0)
Expand Down
11 changes: 5 additions & 6 deletions Source/ImGui/Private/ImGuiContextProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include <GenericPlatform/ICursor.h>

#include <imgui.h>

#include <string>


Expand Down Expand Up @@ -39,10 +38,10 @@ class FImGuiContextProxy
const FImGuiInputState& GetInputState() const { return InputState; }

// Is this context the current ImGui context.
bool IsCurrentContext() const { return ImGui::GetCurrentContext() == Context; }
bool IsCurrentContext() const;

// Set this context as current ImGui context.
void SetAsCurrent() { ImGui::SetCurrentContext(Context); }
void SetAsCurrent();

// Get the desired context display size.
const FVector2D& GetDisplaySize() const { return DisplaySize; }
Expand Down Expand Up @@ -81,12 +80,12 @@ class FImGuiContextProxy
// Tick to advance context to the next frame. Only one call per frame will be processed.
void Tick(float DeltaSeconds);

void UpdateDrawData(ImDrawData* DrawData);

private:

void BeginFrame(float DeltaTime = 1.f / 60.f);
void EndFrame();

void UpdateDrawData(ImDrawData* DrawData);
void EndFrame();

void BroadcastWorldEarlyDebug();
void BroadcastMultiContextEarlyDebug();
Expand Down
4 changes: 4 additions & 0 deletions Source/ImGui/Private/ImGuiDrawData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,8 @@ void FImGuiDrawList::TransferDrawData(ImDrawList& Src)
Src.CmdBuffer.swap(ImGuiCommandBuffer);
Src.IdxBuffer.swap(ImGuiIndexBuffer);
Src.VtxBuffer.swap(ImGuiVertexBuffer);

// ImGui seems to clear draw lists in every frame, but since source list can contain pointers to buffers that
// we just swapped, it is better to clear explicitly here.
Src._ResetForNewFrame();
}
Loading