CogImGui: Add imgui viewport support

This commit is contained in:
Arnaud Jamin
2023-11-28 01:28:09 -05:00
parent 4857b23be3
commit a385e15f64
27 changed files with 1386 additions and 1260 deletions
Binary file not shown.
@@ -228,7 +228,7 @@ void FCogEngineWindow_Collisions::RenderContent()
case 2:
{
FVector Direction;
UGameplayStatics::DeprojectScreenToWorld(PlayerController, FCogImguiHelper::ToVector2D(ImGui::GetMousePos()), QueryStart, Direction);
UGameplayStatics::DeprojectScreenToWorld(PlayerController, FCogImguiHelper::ToFVector2D(ImGui::GetMousePos()), QueryStart, Direction);
QueryEnd = QueryStart + Direction * Config->QueryDistance;
QueryRadius = Config->QueryThickness;
break;
@@ -4,6 +4,7 @@
#include "CogDebugSettings.h"
#include "CogEngineReplicator.h"
#include "CogImguiModule.h"
#include "CogImguiHelper.h"
#include "CogImguiInputHelper.h"
#include "CogWindowManager.h"
#include "CogWindowWidgets.h"
@@ -136,8 +137,8 @@ void FCogEngineWindow_Selection::ToggleSelectionMode()
void FCogEngineWindow_Selection::ActivateSelectionMode()
{
bSelectionModeActive = true;
bIsInputEnabledBeforeEnteringSelectionMode = GetOwner()->GetImGuiWidget()->GetEnableInput();
GetOwner()->GetImGuiWidget()->SetEnableInput(true);
bIsInputEnabledBeforeEnteringSelectionMode = GetOwner()->GetContext().GetEnableInput();
GetOwner()->GetContext().SetEnableInput(true);
GetOwner()->SetHideAllWindows(true);
}
@@ -158,7 +159,7 @@ void FCogEngineWindow_Selection::DeactivateSelectionMode()
// When in selection mode we need imgui to have the input focus
// When leaving selection mode we want to leave it as is was before
//--------------------------------------------------------------------------------------------
GetOwner()->GetImGuiWidget()->SetEnableInput(bIsInputEnabledBeforeEnteringSelectionMode);
GetOwner()->GetContext().SetEnableInput(bIsInputEnabledBeforeEnteringSelectionMode);
GetOwner()->SetHideAllWindows(false);
}
@@ -393,15 +394,23 @@ void FCogEngineWindow_Selection::TickSelectionMode()
return;
}
ImDrawList* DrawList = ImGui::GetBackgroundDrawList();
DrawList->AddRect(ImVec2(0, 0), ImGui::GetIO().DisplaySize, IM_COL32(255, 0, 0, 128), 0.0f, 0, 20.0f);
FCogWindowWidgets::AddTextWithShadow(DrawList, ImVec2(20, 20), IM_COL32(255, 255, 255, 255), "Picking Mode. \n[LMB] Pick \n[RMB] Cancel");
ImGuiViewport* Viewport = ImGui::GetMainViewport();
if (Viewport == nullptr)
{
return;
}
const ImVec2 ViewportPos = Viewport->Pos;
const ImVec2 ViewportSize = Viewport->Size;
ImDrawList* DrawList = ImGui::GetBackgroundDrawList(Viewport);
DrawList->AddRect(ViewportPos, ViewportPos + ViewportSize, IM_COL32(255, 0, 0, 128), 0.0f, 0, 20.0f);
FCogWindowWidgets::AddTextWithShadow(DrawList, ViewportPos + ImVec2(20, 20), IM_COL32(255, 255, 255, 255), "Picking Mode. \n[LMB] Pick \n[RMB] Cancel");
TSubclassOf<AActor> SelectedActorClass = GetSelectedActorClass();
AActor* HoveredActor = nullptr;
FVector WorldOrigin, WorldDirection;
if (UGameplayStatics::DeprojectScreenToWorld(PlayerController, FCogImguiHelper::ToVector2D(ImGui::GetMousePos()), WorldOrigin, WorldDirection))
if (UGameplayStatics::DeprojectScreenToWorld(PlayerController, FCogImguiHelper::ToFVector2D(ImGui::GetMousePos() - ViewportPos), WorldOrigin, WorldDirection))
{
//--------------------------------------------------------------------------------------------------------
// Prioritize another actor than the selected actor unless we only touch the selected actor.
@@ -463,7 +472,13 @@ void FCogEngineWindow_Selection::DrawActorFrame(const AActor& Actor)
return;
}
ImDrawList* DrawList = ImGui::GetBackgroundDrawList();
ImGuiViewport* Viewport = ImGui::GetMainViewport();
if (Viewport == nullptr)
{
return;
}
ImDrawList* DrawList = ImGui::GetBackgroundDrawList(Viewport);
FVector BoxOrigin, BoxExtent;
@@ -502,8 +517,8 @@ void FCogEngineWindow_Selection::DrawActorFrame(const AActor& Actor)
if (ComputeBoundingBoxScreenPosition(PlayerController, BoxOrigin, BoxExtent, ScreenPosMin, ScreenPosMax))
{
const ImU32 Color = (&Actor == GetSelection()) ? IM_COL32(255, 255, 255, 255) : IM_COL32(255, 255, 255, 128);
DrawList->AddRect(FCogImguiHelper::ToImVec2(ScreenPosMin), FCogImguiHelper::ToImVec2(ScreenPosMax), Color, 0.0f, 0, 1.0f);
FCogWindowWidgets::AddTextWithShadow(DrawList, FCogImguiHelper::ToImVec2(ScreenPosMin + FVector2D(0, -14.0f)), Color, TCHAR_TO_ANSI(*GetActorName(Actor)));
DrawList->AddRect(FCogImguiHelper::ToImVec2(ScreenPosMin) + Viewport->Pos, FCogImguiHelper::ToImVec2(ScreenPosMax) + Viewport->Pos, Color, 0.0f, 0, 1.0f);
FCogWindowWidgets::AddTextWithShadow(DrawList, FCogImguiHelper::ToImVec2(ScreenPosMin + FVector2D(0, -14.0f)) + Viewport->Pos, Color, TCHAR_TO_ANSI(*GetActorName(Actor)));
}
}
@@ -0,0 +1,105 @@
#include "CogEngineWindow_Slate.h"
#include "CogImguiHelper.h"
#include "Framework/Application/SlateApplication.h"
#include "Framework/Application/SlateUser.h"
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_Slate::RenderHelp()
{
ImGui::Text(
"This window displays slate debug info. "
);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_Slate::RenderContent()
{
Super::RenderContent();
if (FSlateApplication::IsInitialized() == false)
{
ImGui::Text("Not initialized");
return;
}
FSlateApplication& SlateApp = FSlateApplication::Get();
static int32 SelectedUserIndex = 0;
ImGui::SetNextItemWidth(-1);
if (ImGui::BeginCombo("##User", TCHAR_TO_ANSI(*FString::Printf(TEXT("%d"), SelectedUserIndex))))
{
SlateApp.ForEachUser([this](FSlateUser& User)
{
if (ImGui::Selectable(TCHAR_TO_ANSI(*FString::Printf(TEXT("%d"), SelectedUserIndex)), false))
{
SelectedUserIndex = User.GetUserIndex();
}
});
ImGui::EndCombo();
}
if (TSharedPtr<FSlateUser> User = SlateApp.GetUser(SelectedUserIndex))
{
RenderUser(*User.Get());
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineWindow_Slate::RenderUser(FSlateUser& User)
{
if (ImGui::BeginTable("SlateUser", 2, ImGuiTableFlags_Borders))
{
const ImVec4 LabelColor(1.0f, 1.0f, 1.0f, 0.5f);
ImGui::TableSetupColumn("Property");
ImGui::TableSetupColumn("Value");
//------------------------
// Focused Widget
//------------------------
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextColored(LabelColor, "Focused Widget");
ImGui::TableNextColumn();
FString FocusedWidgetText = "None";
if (TSharedPtr<SWidget> FocusedWidget = User.GetFocusedWidget())
{
FocusedWidgetText = FocusedWidget->ToString();
}
ImGui::Text("%s", TCHAR_TO_ANSI(*FocusedWidgetText));
//------------------------
// Cursor Captor
//------------------------
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextColored(LabelColor, "Cursor Captor");
ImGui::TableNextColumn();
FString CursorCaptoreWidgetText = "None";
if (TSharedPtr<SWidget> CursorCaptoreWidget = User.GetCursorCaptor())
{
CursorCaptoreWidgetText = CursorCaptoreWidget->ToString();
}
ImGui::Text("%s", TCHAR_TO_ANSI(*CursorCaptoreWidgetText));
//------------------------
// Cursor Position
//------------------------
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextColored(LabelColor, "Cursor Position");
ImGui::TableNextColumn();
ImVec2 CursorPosition = FCogImguiHelper::ToImVec2(User.GetCursorPosition());
ImGui::InputFloat2("##Cursor Position", &CursorPosition.x, "%0.0f");
ImGui::EndTable();
}
}
@@ -0,0 +1,22 @@
#pragma once
#include "CoreMinimal.h"
#include "CogWindow.h"
class FSlateUser;
class COGENGINE_API FCogEngineWindow_Slate : public FCogWindow
{
typedef FCogWindow Super;
public:
protected:
virtual void RenderHelp() override;
virtual void RenderContent() override;
virtual void RenderUser(FSlateUser& User);
};
@@ -3,9 +3,11 @@
#include "CogImguiHelper.h"
#include "CogImguiInputHelper.h"
#include "CogImguiWidget.h"
#include "CogImguiContext.h"
#include "GameFramework/InputSettings.h"
#include "GameFramework/PlayerInput.h"
#include "imgui.h"
#include "imgui_internal.h"
#include "Slate/SGameLayerManager.h"
#if WITH_EDITOR
@@ -16,9 +18,10 @@ constexpr bool ForwardEvent = false;
constexpr bool TerminateEvent = true;
//--------------------------------------------------------------------------------------------------------------------------
FImGuiInputProcessor::FImGuiInputProcessor(UPlayerInput* InPlayerInput, SCogImguiWidget* InMainWidget)
FImGuiInputProcessor::FImGuiInputProcessor(UPlayerInput* InPlayerInput, FCogImguiContext* InContext, SCogImguiWidget* InMainWidget)
{
PlayerInput = InPlayerInput;
Context = InContext;
MainWidget = InMainWidget;
}
@@ -43,14 +46,16 @@ void FImGuiInputProcessor::Tick(const float DeltaTime, FSlateApplication& SlateA
AddMousePosEvent(SlateApp.GetCursorPos());
if ((IO.ConfigFlags & ImGuiConfigFlags_NoMouse) == 0)
const bool bHasMouse = (IO.ConfigFlags & ImGuiConfigFlags_NoMouse) == 0;
const bool bUpdateMouseMouseCursor = (IO.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) == 0;
if (bHasMouse && bUpdateMouseMouseCursor)
{
SlateCursor->SetType(FCogImguiInputHelper::ToSlateMouseCursor(ImGui::GetMouseCursor()));
}
if (IO.WantSetMousePos)
{
SlateApp.SetCursorPos(FCogImguiHelper::ToVector2D(IO.MousePos));
SlateApp.SetCursorPos(FCogImguiHelper::ToFVector2D(IO.MousePos));
//UE_LOG(LogCogImGui, VeryVerbose, TEXT("FImGuiInputProcessor::Tick | SetCursorPos"));
}
}
@@ -175,7 +180,7 @@ bool FImGuiInputProcessor::HandleMouseMoveEvent(FSlateApplication& SlateApp, con
{
AddMousePosEvent(Event.GetScreenSpacePosition());
if (MainWidget->GetEnableInput() && MainWidget->GetShareMouse() == false)
if (Context->GetEnableInput() && Context->GetShareMouse() == false && IsMouseInsideMainViewport())
{
return TerminateEvent;
}
@@ -211,7 +216,7 @@ bool FImGuiInputProcessor::HandleMouseButtonEvent(FSlateApplication& SlateApp, c
const uint32 Button = ToImGuiMouseButton(Event.GetEffectingButton());
IO.AddMouseButtonEvent(Button, IsButtonDown);
if (MainWidget->GetEnableInput() && MainWidget->GetShareMouse() == false)
if (Context->GetEnableInput() && Context->GetShareMouse() == false && IsMouseInsideMainViewport())
{
const bool Result = TerminateEvent;
UE_LOG(LogCogImGui, VeryVerbose, TEXT("FImGuiInputProcessor::HandleMouseButtonEvent | Button:%d | IsButtonDown:%d | WantCaptureMouse:%d | TerminateEvent:%d | ShareMouse == false"), Button, IsButtonDown, IO.WantCaptureMouse, Result);
@@ -237,6 +242,19 @@ void FImGuiInputProcessor::AddMousePosEvent(const FVector2D& MousePosition) cons
}
}
//--------------------------------------------------------------------------------------------------------------------------
bool FImGuiInputProcessor::IsMouseInsideMainViewport()
{
if (ImGuiViewportP* Viewport = (ImGuiViewportP*)ImGui::GetMainViewport())
{
ImGuiIO& IO = ImGui::GetIO();
const bool Result = Viewport->GetMainRect().Contains(IO.MousePos);
return Result;
}
return false;
}
//--------------------------------------------------------------------------------------------------------------------------
bool FImGuiInputProcessor::HandleMouseWheelOrGestureEvent(FSlateApplication& SlateApp, const FPointerEvent& Event, const FPointerEvent* GestureEvent)
{
@@ -0,0 +1,726 @@
#include "CogImGuiContext.h"
#include "CogImguiHelper.h"
#include "CogImguiInputHelper.h"
#include "CogImguiInputProcessor.h"
#include "CogImguiWidget.h"
#include "Engine/Console.h"
#include "Engine/LocalPlayer.h"
#include "Framework/Application/SlateApplication.h"
#include "Framework/Application/SlateUser.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/PlayerInput.h"
#include "imgui.h"
#include "imgui_internal.h"
#include "implot.h"
#include "TextureResource.h"
#include "Widgets/SViewport.h"
#include "Widgets/SWindow.h"
static UPlayerInput* GetPlayerInput(const UWorld* World);
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::Initialize()
{
IMGUI_CHECKVERSION();
if (FSlateApplication::IsInitialized() == false)
{
return;
}
FSlateApplication& SlateApp = FSlateApplication::Get();
GameViewport = GEngine->GameViewport;
SAssignNew(MainWidget, SCogImguiWidget)
.Context(this);
GameViewport->AddViewportWidgetContent(MainWidget.ToSharedRef(), TNumericLimits<int32>::Max());
//--------------------------------------------------------------------
// Register input processor to forward input events to imgui
//--------------------------------------------------------------------
if (FSlateApplication::IsInitialized())
{
UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*GameViewport->GetWorld());
InputProcessor = MakeShared<FImGuiInputProcessor>(PlayerInput, this, MainWidget.Get());
FSlateApplication::Get().RegisterInputPreProcessor(InputProcessor.ToSharedRef(), 0);
}
ImGuiContext = ImGui::CreateContext();
PlotContext = ImPlot::CreateContext();
ImPlot::SetImGuiContext(ImGuiContext);
ImGuiIO& IO = ImGui::GetIO();
IO.UserData = this;
IO.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
IO.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
IO.ConfigFlags |= ImGuiConfigFlags_NavNoCaptureKeyboard;
IO.ConfigFlags |= ImGuiConfigFlags_NavEnableSetMousePos;
IO.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
IO.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;
IO.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;
IO.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports;
IO.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport;
IO.BackendFlags |= ImGuiBackendFlags_RendererHasViewports;
IO.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
//--------------------------------------------------------------------
//
//--------------------------------------------------------------------
ImGuiViewport* MainViewport = ImGui::GetMainViewport();
FImGuiViewportData* ViewportData = new FImGuiViewportData();
MainViewport->PlatformUserData = ViewportData;
ViewportData->Window = SlateApp.GetActiveTopLevelWindow();
ViewportData->Context = this;
ViewportData->Widget = MainWidget;
const char* InitFilenameTemp = TCHAR_TO_ANSI(*FCogImguiHelper::GetIniFilePath("imgui"));
ImStrncpy(IniFilename, InitFilenameTemp, IM_ARRAYSIZE(IniFilename));
IO.IniFilename = IniFilename;
ImGuiPlatformIO& PlatformIO = ImGui::GetPlatformIO();
PlatformIO.Platform_CreateWindow = ImGui_CreateWindow;
PlatformIO.Platform_DestroyWindow = ImGui_DestroyWindow;
PlatformIO.Platform_ShowWindow = ImGui_ShowWindow;
PlatformIO.Platform_SetWindowPos = ImGui_SetWindowPos;
PlatformIO.Platform_GetWindowPos = ImGui_GetWindowPos;
PlatformIO.Platform_SetWindowSize = ImGui_SetWindowSize;
PlatformIO.Platform_GetWindowSize = ImGui_GetWindowSize;
PlatformIO.Platform_SetWindowFocus = ImGui_SetWindowFocus;
PlatformIO.Platform_GetWindowFocus = ImGui_GetWindowFocus;
PlatformIO.Platform_GetWindowMinimized = ImGui_GetWindowMinimized;
PlatformIO.Platform_SetWindowTitle = ImGui_SetWindowTitle;
PlatformIO.Platform_SetWindowAlpha = ImGui_SetWindowAlpha;
PlatformIO.Platform_RenderWindow = ImGui_RenderWindow;
if (const TSharedPtr<GenericApplication> PlatformApplication = SlateApp.GetPlatformApplication())
{
FDisplayMetrics DisplayMetrics;
PlatformApplication->GetInitialDisplayMetrics(DisplayMetrics);
PlatformApplication->OnDisplayMetricsChanged().AddRaw(this, &FCogImguiContext::OnDisplayMetricsChanged);
OnDisplayMetricsChanged(DisplayMetrics);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::Shutdown()
{
ImGuiViewport* MainViewport = ImGui::GetMainViewport();
if (const FImGuiViewportData* ViewportData = static_cast<FImGuiViewportData*>(MainViewport->PlatformUserData))
{
delete ViewportData;
MainViewport->PlatformUserData = nullptr;
}
if (FSlateApplication::IsInitialized())
{
FSlateApplication& SlateApp = FSlateApplication::Get();
if (InputProcessor.IsValid())
{
SlateApp.UnregisterInputPreProcessor(InputProcessor);
}
if (const TSharedPtr<GenericApplication> PlatformApplication = SlateApp.GetPlatformApplication())
{
PlatformApplication->OnDisplayMetricsChanged().RemoveAll(this);
}
}
if (PlotContext)
{
ImPlot::DestroyContext(PlotContext);
PlotContext = nullptr;
}
if (ImGuiContext)
{
ImGui::DestroyContext(ImGuiContext);
ImGuiContext = nullptr;
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::OnDisplayMetricsChanged(const FDisplayMetrics& DisplayMetrics) const
{
ImGuiPlatformIO& PlatformIO = ImGui::GetPlatformIO();
PlatformIO.Monitors.resize(0);
for (const FMonitorInfo& Monitor : DisplayMetrics.MonitorInfo)
{
ImGuiPlatformMonitor ImGuiMonitor;
ImGuiMonitor.MainPos = ImVec2(Monitor.DisplayRect.Left, Monitor.DisplayRect.Top);
ImGuiMonitor.MainSize = ImVec2(Monitor.DisplayRect.Right - Monitor.DisplayRect.Left, Monitor.DisplayRect.Bottom - Monitor.DisplayRect.Top);
ImGuiMonitor.WorkPos = ImVec2(Monitor.WorkArea.Left, Monitor.WorkArea.Top);
ImGuiMonitor.WorkSize = ImVec2(Monitor.WorkArea.Right - Monitor.WorkArea.Left, Monitor.WorkArea.Bottom - Monitor.WorkArea.Top);
ImGuiMonitor.DpiScale = Monitor.DPI;
if (Monitor.bIsPrimary)
{
PlatformIO.Monitors.push_front(ImGuiMonitor);
}
else
{
PlatformIO.Monitors.push_back(ImGuiMonitor);
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::BeginFrame(float InDeltaTime)
{
ImGui::SetCurrentContext(ImGuiContext);
ImPlot::SetImGuiContext(ImGuiContext);
ImPlot::SetCurrentContext(PlotContext);
ImGuiIO& IO = ImGui::GetIO();
IO.DeltaTime = InDeltaTime;
IO.DisplaySize = FCogImguiHelper::ToImVec2(MainWidget->GetTickSpaceGeometry().GetAbsoluteSize());
//-------------------------------------------------------------------------------------------------------
// Build font
//-------------------------------------------------------------------------------------------------------
if (IO.Fonts->IsBuilt() == false || FontAtlasTexturePtr.IsValid() == false)
{
BuildFont();
}
//-------------------------------------------------------------------------------------------------------
// Update which viewport is under the mouse
//-------------------------------------------------------------------------------------------------------
ImGuiID MouseViewportId = 0;
FSlateApplication& SlateApp = FSlateApplication::Get();
FWidgetPath WidgetsUnderCursor = SlateApp.LocateWindowUnderMouse(SlateApp.GetCursorPos(), SlateApp.GetInteractiveTopLevelWindows());
if (WidgetsUnderCursor.IsValid())
{
TSharedRef<SWindow> Window = WidgetsUnderCursor.GetWindow();
ImGuiID* ViewportId = WindowToViewportMap.Find(Window);
if (ViewportId != nullptr)
{
MouseViewportId = *ViewportId;
}
else
{
MouseViewportId = ImGui::GetMainViewport()->ID;
}
}
IO.AddMouseViewportEvent(MouseViewportId);
//-------------------------------------------------------------------------------------------------------
// Refresh modifiers otherwise, when pressing ALT-TAB, the Alt modifier is always true
//-------------------------------------------------------------------------------------------------------
FModifierKeysState ModifierKeys = FSlateApplication::Get().GetModifierKeys();
if (ModifierKeys.IsControlDown() != IO.KeyCtrl) { IO.AddKeyEvent(ImGuiMod_Ctrl, ModifierKeys.IsControlDown()); }
if (ModifierKeys.IsShiftDown() != IO.KeyShift) { IO.AddKeyEvent(ImGuiMod_Shift, ModifierKeys.IsShiftDown()); }
if (ModifierKeys.IsAltDown() != IO.KeyAlt) { IO.AddKeyEvent(ImGuiMod_Alt, ModifierKeys.IsAltDown()); }
if (ModifierKeys.IsCommandDown() != IO.KeySuper) { IO.AddKeyEvent(ImGuiMod_Super, ModifierKeys.IsCommandDown()); }
//-------------------------------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------------------------------
if (bEnableInput)
{
IO.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
TryReleaseGameMouseCapture();
}
else
{
IO.ConfigFlags |= ImGuiConfigFlags_NoMouse;
}
//-------------------------------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------------------------------
const bool bHasMouse = (IO.ConfigFlags & ImGuiConfigFlags_NoMouse) == 0;
const bool bUpdateMouseMouseCursor = (IO.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) == 0;
if (bHasMouse && bUpdateMouseMouseCursor)
{
MainWidget->SetCursor(FCogImguiInputHelper::ToSlateMouseCursor(ImGui::GetMouseCursor()));
}
//-------------------------------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------------------------------
if (bRefreshDPIScale)
{
RefreshDPIScale();
}
ImGui::NewFrame();
DrawDebug();
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::EndFrame()
{
ImGui::Render();
ImGui_RenderWindow(ImGui::GetMainViewport(), nullptr);
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::ImGui_CreateWindow(ImGuiViewport* Viewport)
{
if (Viewport->ParentViewportId == 0)
{
return;
}
ImGuiViewport* ParentViewport = ImGui::FindViewportByID(Viewport->ParentViewportId);
if (ParentViewport == nullptr)
{
return;
}
const FImGuiViewportData* ParentViewportData = static_cast<FImGuiViewportData*>(ParentViewport->PlatformUserData);
if (ParentViewportData == nullptr)
{
return;
}
FCogImguiContext* Context = ParentViewportData->Context.Get();
const bool bTooltipWindow = (Viewport->Flags & ImGuiViewportFlags_TopMost);
const bool bPopupWindow = (Viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon);
static FWindowStyle WindowStyle = FWindowStyle()
.SetActiveTitleBrush(FSlateNoResource())
.SetInactiveTitleBrush(FSlateNoResource())
.SetFlashTitleBrush(FSlateNoResource())
.SetOutlineBrush(FSlateNoResource())
.SetBorderBrush(FSlateNoResource())
.SetBackgroundBrush(FSlateNoResource())
.SetChildBackgroundBrush(FSlateNoResource());
TSharedPtr<SCogImguiWidget> Widget;
const TSharedRef<SWindow> Window =
SNew(SWindow)
.Type(bTooltipWindow ? EWindowType::ToolTip : EWindowType::Normal)
.Style(&WindowStyle)
.ScreenPosition(FCogImguiHelper::ToFVector2D(Viewport->Pos))
.ClientSize(FCogImguiHelper::ToFVector2D(Viewport->Size))
.SupportsTransparency(EWindowTransparency::PerWindow)
.SizingRule(ESizingRule::UserSized)
.IsPopupWindow(bTooltipWindow || bPopupWindow)
.IsTopmostWindow(bTooltipWindow)
.FocusWhenFirstShown(!(Viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing))
.HasCloseButton(false)
.SupportsMaximize(false)
.SupportsMinimize(false)
.CreateTitleBar(false)
.LayoutBorder(0)
.UserResizeBorder(0)
.UseOSWindowBorder(false)
[
SAssignNew(Widget, SCogImguiWidget)
.Context(Context)
];
if (ParentViewportData->Window.IsValid())
{
FSlateApplication::Get().AddWindowAsNativeChild(Window, ParentViewportData->Window.Pin().ToSharedRef());
}
else
{
FSlateApplication::Get().AddWindow(Window);
}
FImGuiViewportData* ViewportData = new FImGuiViewportData();
Viewport->PlatformUserData = ViewportData;
ViewportData->Context = ParentViewportData->Context;
ViewportData->Widget = Widget;
ViewportData->Window = Window;
ParentViewportData->Context->WindowToViewportMap.Add(Window, Viewport->ID);
Viewport->PlatformRequestResize = false;
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::ImGui_DestroyWindow(ImGuiViewport* Viewport)
{
FImGuiViewportData* ViewportData = static_cast<FImGuiViewportData*>(Viewport->PlatformUserData);
if (ViewportData == nullptr)
{
return;
}
if ((Viewport->Flags & ImGuiViewportFlags_OwnedByApp))
{
return;
}
ViewportData->Context->WindowToViewportMap.Remove(ViewportData->Window);
if (const TSharedPtr<SWindow> Window = ViewportData->Window.Pin())
{
Window->RequestDestroyWindow();
}
delete ViewportData;
Viewport->PlatformUserData = nullptr;
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::ImGui_ShowWindow(ImGuiViewport* Viewport)
{
if (const FImGuiViewportData* ViewportData = static_cast<FImGuiViewportData*>(Viewport->PlatformUserData))
{
if (const TSharedPtr<SWindow> Window = ViewportData->Window.Pin())
{
Window->ShowWindow();
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::ImGui_SetWindowPos(ImGuiViewport* Viewport, ImVec2 Pos)
{
if (const FImGuiViewportData* ViewportData = static_cast<FImGuiViewportData*>(Viewport->PlatformUserData))
{
if (const TSharedPtr<SWindow> Window = ViewportData->Window.Pin())
{
Window->MoveWindowTo(FCogImguiHelper::ToFVector2D(Pos));
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
ImVec2 FCogImguiContext::ImGui_GetWindowPos(ImGuiViewport* Viewport)
{
if (const FImGuiViewportData* ViewportData = static_cast<FImGuiViewportData*>(Viewport->PlatformUserData))
{
if (const TSharedPtr<SCogImguiWidget> Widget = ViewportData->Widget.Pin())
{
return FCogImguiHelper::ToImVec2(Widget->GetTickSpaceGeometry().GetAbsolutePosition());
}
}
return ImVec2(0, 0);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::ImGui_SetWindowSize(ImGuiViewport* Viewport, ImVec2 Size)
{
if (const FImGuiViewportData* ViewportData = static_cast<FImGuiViewportData*>(Viewport->PlatformUserData))
{
if (const TSharedPtr<SWindow> Window = ViewportData->Window.Pin())
{
Window->Resize(FCogImguiHelper::ToFVector2D(Size));
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
ImVec2 FCogImguiContext::ImGui_GetWindowSize(ImGuiViewport* Viewport)
{
if (const FImGuiViewportData* ViewportData = static_cast<FImGuiViewportData*>(Viewport->PlatformUserData))
{
if (const TSharedPtr<SCogImguiWidget> Widget = ViewportData->Widget.Pin())
{
return FCogImguiHelper::ToImVec2(Widget->GetTickSpaceGeometry().GetAbsoluteSize());
}
}
return ImVec2(0, 0);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::ImGui_SetWindowFocus(ImGuiViewport* Viewport)
{
if (const FImGuiViewportData* ViewportData = static_cast<FImGuiViewportData*>(Viewport->PlatformUserData))
{
if (const TSharedPtr<SWindow> Window = ViewportData->Window.Pin())
{
if (const TSharedPtr<FGenericWindow> NativeWindow = Window->GetNativeWindow())
{
NativeWindow->BringToFront();
NativeWindow->SetWindowFocus();
}
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogImguiContext::ImGui_GetWindowFocus(ImGuiViewport* Viewport)
{
if (const FImGuiViewportData* ViewportData = static_cast<FImGuiViewportData*>(Viewport->PlatformUserData))
{
if (const TSharedPtr<SWindow> Window = ViewportData->Window.Pin())
{
if (const TSharedPtr<FGenericWindow> NativeWindow = Window->GetNativeWindow())
{
return NativeWindow->IsForegroundWindow();
}
}
}
return false;
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogImguiContext::ImGui_GetWindowMinimized(ImGuiViewport* Viewport)
{
if (const FImGuiViewportData* ViewportData = static_cast<FImGuiViewportData*>(Viewport->PlatformUserData))
{
if (const TSharedPtr<SWindow> Window = ViewportData->Window.Pin())
{
return Window->IsWindowMinimized();
}
}
return false;
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::ImGui_SetWindowTitle(ImGuiViewport* Viewport, const char* TitleAnsi)
{
if (const FImGuiViewportData* ViewportData = static_cast<FImGuiViewportData*>(Viewport->PlatformUserData))
{
if (const TSharedPtr<SWindow> Window = ViewportData->Window.Pin())
{
Window->SetTitle(FText::FromString(ANSI_TO_TCHAR(TitleAnsi)));
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::ImGui_SetWindowAlpha(ImGuiViewport* Viewport, float Alpha)
{
if (const FImGuiViewportData* ViewportData = static_cast<FImGuiViewportData*>(Viewport->PlatformUserData))
{
if (const TSharedPtr<SWindow> Window = ViewportData->Window.Pin())
{
Window->SetOpacity(Alpha);
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::ImGui_RenderWindow(ImGuiViewport* Viewport, void* Data)
{
if (const FImGuiViewportData* ViewportData = static_cast<FImGuiViewportData*>(Viewport->PlatformUserData))
{
if (const TSharedPtr<SCogImguiWidget> Widget = ViewportData->Widget.Pin())
{
Widget->SetDrawData(Viewport->DrawData);
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
static UPlayerInput* GetPlayerInput(const UWorld* World)
{
if (World == nullptr)
{
return nullptr;
}
APlayerController* PlayerController = nullptr;
for (FConstPlayerControllerIterator Iterator = World->GetPlayerControllerIterator(); Iterator; ++Iterator)
{
APlayerController* ItPlayerController = Iterator->Get();
if (ItPlayerController->IsLocalController())
{
PlayerController = ItPlayerController;
break;
}
}
if (PlayerController == nullptr)
{
return nullptr;
}
UPlayerInput* PlayerInput = PlayerController->PlayerInput;
return PlayerInput;
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::SetEnableInput(bool Value)
{
bEnableInput = Value;
if (bEnableInput == false)
{
TryGiveMouseCaptureBackToGame();
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::SetShareMouse(bool Value)
{
bShareMouse = Value;
if (bEnableInput == false)
{
TryGiveMouseCaptureBackToGame();
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::TryReleaseGameMouseCapture()
{
if (bShareMouse)
{
return;
}
if (TSharedPtr<FSlateUser> User = FSlateApplication::Get().GetCursorUser())
{
if (User->HasCursorCapture())
{
PreviousMouseCaptor = User->GetCursorCaptor();
}
}
if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
{
LocalPlayer->GetSlateOperations()
.ReleaseMouseLock()
.ReleaseMouseCapture();
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::TryGiveMouseCaptureBackToGame()
{
if (PreviousMouseCaptor.IsValid() == false)
{
return;
}
TSharedRef<SWidget> PreviousMouseCaptorRef = PreviousMouseCaptor.Pin().ToSharedRef();
if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
{
LocalPlayer->GetSlateOperations().CaptureMouse(PreviousMouseCaptorRef);
}
PreviousMouseCaptor.Reset();
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::SetDPIScale(float Value)
{
if (DpiScale == Value)
{
return;
}
DpiScale = Value;
bRefreshDPIScale = true;
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::RefreshDPIScale()
{
bRefreshDPIScale = false;
BuildFont();
ImGuiStyle NewStyle = ImGuiStyle();
ImGui::GetStyle() = MoveTemp(NewStyle);
NewStyle.ScaleAllSizes(DpiScale);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::BuildFont()
{
ImGuiIO& IO = ImGui::GetIO();
IO.Fonts->Clear();
ImFontConfig FontConfig;
FontConfig.SizePixels = FMath::RoundFromZero(13.f * DpiScale);
IO.Fonts->AddFontDefault(&FontConfig);
uint8* TextureDataRaw;
int32 TextureWidth, TextureHeight, BytesPerPixel;
IO.Fonts->GetTexDataAsRGBA32(&TextureDataRaw, &TextureWidth, &TextureHeight, &BytesPerPixel);
UTexture2D* FontAtlasTexture = UTexture2D::CreateTransient(TextureWidth, TextureHeight, PF_R8G8B8A8, TEXT("ImGuiFontAtlas"));
FontAtlasTexture->Filter = TF_Bilinear;
FontAtlasTexture->AddressX = TA_Wrap;
FontAtlasTexture->AddressY = TA_Wrap;
uint8* FontAtlasTextureData = static_cast<uint8*>(FontAtlasTexture->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE));
FMemory::Memcpy(FontAtlasTextureData, TextureDataRaw, TextureWidth * TextureHeight * BytesPerPixel);
FontAtlasTexture->GetPlatformData()->Mips[0].BulkData.Unlock();
FontAtlasTexture->UpdateResource();
IO.Fonts->SetTexID(FontAtlasTexture);
FontAtlasTexturePtr.Reset(FontAtlasTexture);
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogImguiContext::IsConsoleOpened() const
{
return GameViewport->ViewportConsole && GameViewport->ViewportConsole->ConsoleState != NAME_None;
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiContext::DrawDebug()
{
if (ImGui::Begin("ImGui Integration Debug"))
{
ImGui::BeginDisabled();
ImVec2 AbsPos = FCogImguiHelper::ToImVec2(MainWidget->GetTickSpaceGeometry().GetAbsolutePosition());
ImGui::InputFloat2("Widget Abs Pos", &AbsPos.x, "%0.1f");
ImVec2 AbsSize = FCogImguiHelper::ToImVec2(MainWidget->GetTickSpaceGeometry().GetAbsoluteSize());
ImGui::InputFloat2("Widget Abs Size", &AbsSize.x, "%0.1f");
ImVec2 LocalSize = FCogImguiHelper::ToImVec2(MainWidget->GetTickSpaceGeometry().GetLocalSize());
ImGui::InputFloat2("Widget Local Size", &LocalSize.x, "%0.1f");
FSlateApplication& SlateApp = FSlateApplication::Get();
ImVec2 MousePosition = FCogImguiHelper::ToImVec2(SlateApp.GetCursorPos());
ImGui::InputFloat2("Mouse", &MousePosition.x, "%0.1f");
ImGuiIO& IO = ImGui::GetIO();
ImGui::InputFloat2("ImGui Mouse", &IO.MousePos.x, "%0.1f");
FString Focus = "None";
if (TSharedPtr<SWidget> KeyboardFocusedWidget = SlateApp.GetKeyboardFocusedWidget())
{
Focus = KeyboardFocusedWidget->ToString();
}
static char Buffer[256] = "";
ImStrncpy(Buffer, TCHAR_TO_ANSI(*Focus), IM_ARRAYSIZE(Buffer));
ImGui::InputText("Keyboard Focus", Buffer, IM_ARRAYSIZE(Buffer));
ImGui::EndDisabled();
}
ImGui::End();
}
//--------------------------------------------------------------------------------------------------------------------------
ULocalPlayer* FCogImguiContext::GetLocalPlayer() const
{
if (GameViewport == nullptr)
{
return nullptr;
}
UWorld* World = GameViewport->GetWorld();
if (World == nullptr)
{
return nullptr;
}
ULocalPlayer* LocalPlayer = World->GetFirstLocalPlayerFromController();
return LocalPlayer;
}
@@ -1,66 +1,28 @@
#include "CogImguiDrawList.h"
#include "CogImguiHelper.h"
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiDrawList::CopyVertexData(TArray<FSlateVertex>& OutVertexBuffer, const FTransform2D& Transform) const
FCogImguiDrawList::FCogImguiDrawList(ImDrawList* Source)
{
// Reset and reserve space in destination buffer.
OutVertexBuffer.SetNumUninitialized(ImGuiVertexBuffer.Size, false);
// Transform and copy vertex data.
for (int Idx = 0; Idx < ImGuiVertexBuffer.Size; Idx++)
{
const ImDrawVert& ImGuiVertex = ImGuiVertexBuffer[Idx];
FSlateVertex& SlateVertex = OutVertexBuffer[Idx];
// Final UV is calculated in shader as XY * ZW, so we need set all components.
SlateVertex.TexCoords[0] = ImGuiVertex.uv.x;
SlateVertex.TexCoords[1] = ImGuiVertex.uv.y;
SlateVertex.TexCoords[2] = SlateVertex.TexCoords[3] = 1.f;
const FVector2D VertexPosition = Transform.TransformPoint(FCogImguiHelper::ToVector2D(ImGuiVertex.pos));
SlateVertex.Position[0] = VertexPosition.X;
SlateVertex.Position[1] = VertexPosition.Y;
// Unpack ImU32 color.
SlateVertex.Color = FCogImguiHelper::UnpackImU32Color(ImGuiVertex.col);
}
VtxBuffer.swap(Source->VtxBuffer);
IdxBuffer.swap(Source->IdxBuffer);
CmdBuffer.swap(Source->CmdBuffer);
Flags = Source->Flags;
}
//--------------------------------------------------------------------------------------------------------------------------
FCogImguiDrawList::DrawCommand FCogImguiDrawList::GetCommand(int CommandCount, const FTransform2D& Transform) const
FCogImguiDrawData::FCogImguiDrawData(const ImDrawData* Source)
{
const ImDrawCmd& ImGuiCommand = ImGuiCommandBuffer[CommandCount];
return
{
ImGuiCommand.ElemCount,
TransformRect(Transform, FCogImguiHelper::ToSlateRect(ImGuiCommand.ClipRect)),
FCogImguiHelper::ToTextureIndex(ImGuiCommand.TextureId)
};
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiDrawList::CopyIndexData(TArray<SlateIndex>& OutIndexBuffer, const int32 StartIndex, const int32 NumElements) const
{
// Reset buffer.
OutIndexBuffer.SetNumUninitialized(NumElements, false);
// Copy elements (slow copy because of different sizes of ImDrawIdx and SlateIndex and because SlateIndex can
// have different size on different platforms).
for (int i = 0; i < NumElements; i++)
{
OutIndexBuffer[i] = ImGuiIndexBuffer[StartIndex + i];
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiDrawList::TransferDrawData(ImDrawList& Src)
{
// Move data from source to this list.
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();
bValid = Source->Valid;
TotalIdxCount = Source->TotalIdxCount;
TotalVtxCount = Source->TotalVtxCount;
DrawLists.SetNumUninitialized(Source->CmdListsCount);
ConstructItems<FCogImguiDrawList>(DrawLists.GetData(), Source->CmdLists.Data, Source->CmdListsCount);
DisplayPos = FCogImguiHelper::ToFVector2f(Source->DisplayPos);
DisplaySize = FCogImguiHelper::ToFVector2f(Source->DisplaySize);
FrameBufferScale = FCogImguiHelper::ToFVector2f(Source->FramebufferScale);
}
@@ -31,7 +31,7 @@ ImGuiWindow* FCogImguiHelper::GetCurrentWindow()
}
//--------------------------------------------------------------------------------------------------------------------------
FColor FCogImguiHelper::UnpackImU32Color(ImU32 Color)
FColor FCogImguiHelper::ToFColor(ImU32 Color)
{
return FColor
{
@@ -49,7 +49,13 @@ FSlateRect FCogImguiHelper::ToSlateRect(const ImVec4& Value)
}
//--------------------------------------------------------------------------------------------------------------------------
FVector2D FCogImguiHelper::ToVector2D(const ImVec2& Value)
FVector2f FCogImguiHelper::ToFVector2f(const ImVec2& Value)
{
return FVector2f(Value.x, Value.y);
}
//--------------------------------------------------------------------------------------------------------------------------
FVector2D FCogImguiHelper::ToFVector2D(const ImVec2& Value)
{
return FVector2D(Value.x, Value.y);
}
@@ -90,7 +96,6 @@ ImVec4 FCogImguiHelper::ToImVec4(const FVector4f& Value)
return ImVec4(Value.X, Value.Y, Value.Z, Value.W);
}
//--------------------------------------------------------------------------------------------------------------------------
ImU32 FCogImguiHelper::ToImU32(const FColor& Value)
{
@@ -1,18 +1,11 @@
#include "CogImguiModule.h"
#include "CogImguiWidget.h"
#include "Engine/Engine.h"
#include "Engine/GameViewportClient.h"
#include "imgui.h"
#include "HAL/LowLevelMemTracker.h"
#include "HAL/UnrealMemory.h"
#include "Widgets/Layout/SScaleBox.h"
#define LOCTEXT_NAMESPACE "FCogImguiModule"
//--------------------------------------------------------------------------------------------------------------------------
constexpr int32 Cog_ZOrder = 10000;
//--------------------------------------------------------------------------------------------------------------------------
static void* ImGui_MemAlloc(size_t Size, void* UserData)
{
@@ -37,64 +30,6 @@ void FCogImguiModule::ShutdownModule()
{
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiModule::Initialize()
{
TextureManager.InitializeErrorTexture();
TextureManager.CreatePlainTexture("ImGuiModule_Plain", 2, 2, FColor::White);
unsigned char* Pixels;
int Width, Height, Bpp;
DefaultFontAtlas.Clear();
DefaultFontAtlas.GetTexDataAsRGBA32(&Pixels, &Width, &Height, &Bpp);
const CogTextureIndex FontsTexureIndex = TextureManager.CreateTexture("ImGuiModule_FontAtlas", Width, Height, Bpp, Pixels);
DefaultFontAtlas.TexID = FCogImguiHelper::ToImTextureID(FontsTexureIndex);
}
//--------------------------------------------------------------------------------------------------------------------------
TSharedPtr<SCogImguiWidget> FCogImguiModule::CreateImGuiWidget(UGameViewportClient* GameViewport, FCogImguiRenderFunction Render, ImFontAtlas* FontAtlas /*= nullptr*/)
{
if (bIsInitialized == false)
{
Initialize();
bIsInitialized = true;
}
if (FontAtlas == nullptr)
{
FontAtlas = &DefaultFontAtlas;
}
TSharedPtr<SCogImguiWidget> ImguiWidget;
SAssignNew(ImguiWidget, SCogImguiWidget)
.GameViewport(GameViewport)
.FontAtlas(FontAtlas)
.Render(Render);
GameViewport->AddViewportWidgetContent(ImguiWidget.ToSharedRef(), TNumericLimits<int32>::Max());
return ImguiWidget;
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiModule::DestroyImGuiWidget(TSharedPtr<SCogImguiWidget> ImGuiWidget)
{
UGameViewportClient* Viewport = ImGuiWidget->GetGameViewport().Get();
if (Viewport == nullptr)
{
return;
}
TSharedPtr<SWidget> ParentWidget = ImGuiWidget->GetParentWidget();
if (ParentWidget.IsValid() == false)
{
return;
}
Viewport->RemoveViewportWidgetContent(ParentWidget.ToSharedRef());
}
//--------------------------------------------------------------------------------------------------------------------------
#undef LOCTEXT_NAMESPACE
@@ -1,195 +0,0 @@
#include "CogImguiTextureManager.h"
#include "Framework/Application/SlateApplication.h"
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiTextureManager::InitializeErrorTexture()
{
CreatePlainTextureInternal(NAME_ErrorTexture, 2, 2, FColor::Magenta);
}
//--------------------------------------------------------------------------------------------------------------------------
CogTextureIndex FCogImguiTextureManager::CreateTexture(const FName& Name, int32 Width, int32 Height, uint32 SrcBpp, uint8* SrcData, TFunction<void(uint8*)> SrcDataCleanup)
{
checkf(Name != NAME_None, TEXT("Trying to create a texture with a name 'NAME_None' is not allowed."));
return CreateTextureInternal(Name, Width, Height, SrcBpp, SrcData, SrcDataCleanup);
}
//--------------------------------------------------------------------------------------------------------------------------
CogTextureIndex FCogImguiTextureManager::CreatePlainTexture(const FName& Name, int32 Width, int32 Height, FColor Color)
{
checkf(Name != NAME_None, TEXT("Trying to create a texture with a name 'NAME_None' is not allowed."));
return CreatePlainTextureInternal(Name, Width, Height, Color);
}
//--------------------------------------------------------------------------------------------------------------------------
CogTextureIndex FCogImguiTextureManager::CreateTextureResources(const FName& Name, UTexture2D* Texture)
{
checkf(Name != NAME_None, TEXT("Trying to create texture resources with a name 'NAME_None' is not allowed."));
checkf(Texture, TEXT("Null Texture."));
// Create an entry for the texture.
return AddTextureEntry(Name, Texture, false);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiTextureManager::ReleaseTextureResources(CogTextureIndex Index)
{
checkf(IsInRange(Index), TEXT("Invalid texture index %d. Texture resources array has %d entries total."), Index, TextureResources.Num());
TextureResources[Index] = {};
}
//--------------------------------------------------------------------------------------------------------------------------
CogTextureIndex FCogImguiTextureManager::CreateTextureInternal(const FName& Name, int32 Width, int32 Height, uint32 SrcBpp, uint8* SrcData, TFunction<void(uint8*)> SrcDataCleanup)
{
// Create a texture.
UTexture2D* Texture = UTexture2D::CreateTransient(Width, Height);
// Create a new resource for that texture.
Texture->UpdateResource();
// Update texture data.
FUpdateTextureRegion2D* TextureRegion = new FUpdateTextureRegion2D(0, 0, 0, 0, Width, Height);
auto DataCleanup = [SrcDataCleanup](uint8* Data, const FUpdateTextureRegion2D* UpdateRegion)
{
SrcDataCleanup(Data);
delete UpdateRegion;
};
Texture->UpdateTextureRegions(0, 1u, TextureRegion, SrcBpp * Width, SrcBpp, SrcData, DataCleanup);
// Create an entry for the texture.
if (Name == NAME_ErrorTexture)
{
ErrorTexture = { Name, Texture, true };
return INDEX_ErrorTexture;
}
else
{
return AddTextureEntry(Name, Texture, true);
}
}
//--------------------------------------------------------------------------------------------------------------------------
CogTextureIndex FCogImguiTextureManager::CreatePlainTextureInternal(const FName& Name, int32 Width, int32 Height, const FColor& Color)
{
// Create buffer with raw data.
const uint32 ColorPacked = Color.ToPackedARGB();
const uint32 Bpp = sizeof(ColorPacked);
const uint32 SizeInPixels = Width * Height;
const uint32 SizeInBytes = SizeInPixels * Bpp;
uint8* SrcData = new uint8[SizeInBytes];
std::fill(reinterpret_cast<uint32*>(SrcData), reinterpret_cast<uint32*>(SrcData) + SizeInPixels, ColorPacked);
auto SrcDataCleanup = [](uint8* Data) { delete[] Data; };
// Create new texture from raw data.
return CreateTextureInternal(Name, Width, Height, Bpp, SrcData, SrcDataCleanup);
}
//--------------------------------------------------------------------------------------------------------------------------
CogTextureIndex FCogImguiTextureManager::AddTextureEntry(const FName& Name, UTexture2D* Texture, bool bAddToRoot)
{
// Try to find an entry with that name.
CogTextureIndex Index = FindTextureIndex(Name);
// If this is a new name, try to find an entry to reuse.
if (Index == INDEX_NONE)
{
Index = FindTextureIndex(NAME_None);
}
// Either update/reuse an entry or add a new one.
if (Index != INDEX_NONE)
{
TextureResources[Index] = { Name, Texture, bAddToRoot };
return Index;
}
else
{
return TextureResources.Emplace(Name, Texture, bAddToRoot);
}
}
//--------------------------------------------------------------------------------------------------------------------------
FCogImguiTextureManager::FTextureEntry::FTextureEntry(const FName& InName, UTexture2D* InTexture, bool bAddToRoot)
: Name(InName)
{
checkf(InTexture, TEXT("Null texture."));
if (bAddToRoot)
{
// Get pointer only for textures that we added to root, so we can later release them.
Texture = InTexture;
// Add texture to the root to prevent garbage collection.
InTexture->AddToRoot();
}
// Create brush and resource handle for input texture.
Brush.SetResourceObject(InTexture);
CachedResourceHandle = FSlateApplication::Get().GetRenderer()->GetResourceHandle(Brush);
}
//--------------------------------------------------------------------------------------------------------------------------
FCogImguiTextureManager::FTextureEntry::~FTextureEntry()
{
Reset(true);
}
//--------------------------------------------------------------------------------------------------------------------------
FCogImguiTextureManager::FTextureEntry& FCogImguiTextureManager::FTextureEntry::operator=(FTextureEntry&& Other)
{
// Release old resources if allocated.
Reset(true);
// Move data and ownership to this instance.
Name = MoveTemp(Other.Name);
Texture = MoveTemp(Other.Texture);
Brush = MoveTemp(Other.Brush);
CachedResourceHandle = MoveTemp(Other.CachedResourceHandle);
// Reset the other entry (without releasing resources which are already moved to this instance) to remove tracks
// of ownership and mark it as empty/reusable.
Other.Reset(false);
return *this;
}
//--------------------------------------------------------------------------------------------------------------------------
const FSlateResourceHandle& FCogImguiTextureManager::FTextureEntry::GetResourceHandle() const
{
if (!CachedResourceHandle.IsValid() && Brush.HasUObject())
{
CachedResourceHandle = FSlateApplication::Get().GetRenderer()->GetResourceHandle(Brush);
}
return CachedResourceHandle;
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogImguiTextureManager::FTextureEntry::Reset(bool bReleaseResources)
{
if (bReleaseResources)
{
// Release brush.
if (Brush.HasUObject() && FSlateApplication::IsInitialized())
{
FSlateApplication::Get().GetRenderer()->ReleaseDynamicResource(Brush);
}
// Remove texture from root to allow for garbage collection (it might be invalid, if we never set it
// or this is an application shutdown).
if (Texture.IsValid())
{
Texture->RemoveFromRoot();
}
}
// We use empty name to mark unused entries.
Name = NAME_None;
// Clean fields to make sure that we don't reference released or moved resources.
Texture.Reset();
Brush = FSlateNoResource();
CachedResourceHandle = FSlateResourceHandle();
}
@@ -1,227 +1,32 @@
#include "CogImguiWidget.h"
#include "CogImguiInputHelper.h"
#include "CogImguiInputHelper.h"
#include "CogImGuiInputProcessor.h"
#include "CogImguiModule.h"
#include "CogImguiModule.h"
#include "CogImguiTextureManager.h"
#include "CogImguiWidget.h"
#include "Engine/Console.h"
#include "Engine/GameViewportClient.h"
#include "Engine/LocalPlayer.h"
#include "Framework/Application/SlateApplication.h"
#include "GameFramework/PlayerController.h"
#include "imgui.h"
#include "imgui_internal.h"
#include "implot.h"
#include "SlateOptMacros.h"
#include "UnrealClient.h"
#include "Widgets/Layout/SBorder.h"
#include "Widgets/Layout/SBox.h"
#include "Widgets/SViewport.h"
//--------------------------------------------------------------------------------------------------------------------------
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SCogImguiWidget::Construct(const FArguments& InArgs)
{
checkf(InArgs._GameViewport, TEXT("Null Game Viewport argument"));
GameViewport = InArgs._GameViewport;
FontAtlas = InArgs._FontAtlas;
Render = InArgs._Render;
Context = InArgs._Context;
SetVisibility(EVisibility::SelfHitTestInvisible);
ImGuiContext = ImGui::CreateContext(FontAtlas);
ImPlotContext = ImPlot::CreateContext();
ImPlot::SetImGuiContext(ImGuiContext);
const char* InitFilenameTemp = TCHAR_TO_ANSI(*FCogImguiHelper::GetIniFilePath("imgui"));
ImStrncpy(IniFilename, InitFilenameTemp, IM_ARRAYSIZE(IniFilename));
ImGuiIO& IO = ImGui::GetIO();
IO.IniFilename = IniFilename;
IO.DisplaySize = ImVec2(100, 100);
IO.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
IO.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
IO.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
IO.ConfigFlags |= ImGuiConfigFlags_NavNoCaptureKeyboard;
//--------------------------------------------------------------------
// Register input processor to forward input events to imgui
//--------------------------------------------------------------------
if (FSlateApplication::IsInitialized())
{
UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*GameViewport->GetWorld());
InputProcessor = MakeShared<FImGuiInputProcessor>(PlayerInput, this);
FSlateApplication::Get().RegisterInputPreProcessor(InputProcessor.ToSharedRef(), 0);
}
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
//--------------------------------------------------------------------------------------------------------------------------
SCogImguiWidget::~SCogImguiWidget()
{
if (FSlateApplication::IsInitialized())
{
if (InputProcessor.IsValid())
{
FSlateApplication::Get().UnregisterInputPreProcessor(InputProcessor);
}
}
DestroyImGuiContext();
}
//--------------------------------------------------------------------------------------------------------------------------
void SCogImguiWidget::DestroyImGuiContext()
void SCogImguiWidget::SetDrawData(const ImDrawData* InDrawData)
{
if (ImPlotContext != nullptr)
{
ImPlot::DestroyContext(ImPlotContext);
ImPlotContext = nullptr;
}
if (ImGuiContext != nullptr)
{
ImGui::DestroyContext(ImGuiContext);
ImGuiContext = nullptr;
}
DrawData = FCogImguiDrawData(InDrawData);
}
//--------------------------------------------------------------------------------------------------------------------------
void SCogImguiWidget::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
{
Super::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);
TickKeyModifiers();
TickFocus();
TickImGui(InDeltaTime);
}
//--------------------------------------------------------------------------------------------------------------------------
void SCogImguiWidget::TickKeyModifiers()
{
//-------------------------------------------------------------------------------------------------------
// Refresh modifiers otherwise, when pressing ALT-TAB, the Alt modifier is always true
//-------------------------------------------------------------------------------------------------------
FModifierKeysState ModifierKeys = FSlateApplication::Get().GetModifierKeys();
ImGuiIO& IO = ImGui::GetIO();
if (ModifierKeys.IsControlDown() != IO.KeyCtrl) { IO.AddKeyEvent(ImGuiMod_Ctrl, ModifierKeys.IsControlDown()); }
if (ModifierKeys.IsShiftDown() != IO.KeyShift) { IO.AddKeyEvent(ImGuiMod_Shift, ModifierKeys.IsShiftDown()); }
if (ModifierKeys.IsAltDown() != IO.KeyAlt) { IO.AddKeyEvent(ImGuiMod_Alt, ModifierKeys.IsAltDown()); }
if (ModifierKeys.IsCommandDown() != IO.KeySuper) { IO.AddKeyEvent(ImGuiMod_Super, ModifierKeys.IsCommandDown()); }
}
//--------------------------------------------------------------------------------------------------------------------------
void SCogImguiWidget::TickImGui(float InDeltaTime)
{
if (ImGuiContext == nullptr)
{
return;
}
ImGui::SetCurrentContext(ImGuiContext);
ImPlot::SetImGuiContext(ImGuiContext);
ImPlot::SetCurrentContext(ImPlotContext);
ImGuiIO& IO = ImGui::GetIO();
IO.DeltaTime = FApp::GetDeltaTime();
IO.DisplaySize = FCogImguiHelper::ToImVec2(GetTickSpaceGeometry().GetAbsoluteSize());
ImGui::NewFrame();
Render(InDeltaTime);
//DrawDebug();
ImGui::Render();
if ((IO.ConfigFlags & ImGuiConfigFlags_NoMouse) == 0)
{
SetCursor(FCogImguiInputHelper::ToSlateMouseCursor(ImGui::GetMouseCursor()));
}
ImDrawData* DrawData = ImGui::GetDrawData();
if (DrawData && DrawData->CmdListsCount > 0)
{
DrawLists.SetNum(DrawData->CmdListsCount, false);
for (int i = 0; i < DrawData->CmdListsCount; i++)
{
DrawLists[i].TransferDrawData(*DrawData->CmdLists[i]);
}
}
else
{
DrawLists.Empty();
}
}
//--------------------------------------------------------------------------------------------------------------------------
void SCogImguiWidget::TickFocus()
{
if (bEnableInput)
{
const auto& ViewportWidget = GameViewport->GetGameViewportWidget();
if (!HasKeyboardFocus() && !IsConsoleOpened() && (ViewportWidget->HasKeyboardFocus() || ViewportWidget->HasFocusedDescendants()))
{
TakeFocus();
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void SCogImguiWidget::TakeFocus()
{
FSlateApplication& SlateApplication = FSlateApplication::Get();
PreviousUserFocusedWidget = SlateApplication.GetUserFocusedWidget(SlateApplication.GetUserIndexForKeyboard());
if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
{
TSharedRef<SWidget> FocusWidget = SharedThis(this);
LocalPlayer->GetSlateOperations().CaptureMouse(FocusWidget);
LocalPlayer->GetSlateOperations().SetUserFocus(FocusWidget);
}
else
{
SlateApplication.SetKeyboardFocus(SharedThis(this));
}
}
//--------------------------------------------------------------------------------------------------------------------------
void SCogImguiWidget::ReturnFocus()
{
if (HasKeyboardFocus())
{
auto FocusWidgetPtr = PreviousUserFocusedWidget.IsValid()
? PreviousUserFocusedWidget.Pin()
: GameViewport->GetGameViewportWidget();
if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
{
auto FocusWidgetRef = FocusWidgetPtr.ToSharedRef();
if (FocusWidgetPtr == GameViewport->GetGameViewportWidget())
{
LocalPlayer->GetSlateOperations().CaptureMouse(FocusWidgetRef);
}
LocalPlayer->GetSlateOperations().SetUserFocus(FocusWidgetRef);
}
else
{
FSlateApplication& SlateApplication = FSlateApplication::Get();
SlateApplication.ResetToDefaultPointerInputSettings();
SlateApplication.SetUserFocus(SlateApplication.GetUserIndexForKeyboard(), FocusWidgetPtr);
}
}
PreviousUserFocusedWidget.Reset();
}
//--------------------------------------------------------------------------------------------------------------------------
int32 SCogImguiWidget::OnPaint(
const FPaintArgs& Args,
@@ -233,36 +38,56 @@ int32 SCogImguiWidget::OnPaint(
bool bParentEnabled) const
{
const FSlateRenderTransform& WidgetToScreen = AllottedGeometry.GetAccumulatedRenderTransform().GetTranslation();
const FSlateRenderTransform ImGuiToScreen = FCogImguiHelper::RoundTranslation(ImGuiRenderTransform.Concatenate(WidgetToScreen));
const FSlateRenderTransform Transform(FCogImguiHelper::RoundTranslation(AllottedGeometry.GetAccumulatedRenderTransform().GetTranslation() - FVector2d(DrawData.DisplayPos)));
FCogImguiTextureManager& TextureManager = FCogImguiModule::Get().GetTextureManager();
for (const auto& DrawList : DrawLists)
FSlateBrush TextureBrush;
for (const FCogImguiDrawList& DrawList : DrawData.DrawLists)
{
DrawList.CopyVertexData(VertexBuffer, ImGuiToScreen);
int IndexBufferOffset = 0;
for (int i = 0; i < DrawList.NumCommands(); i++)
TArray<FSlateVertex> Vertices;
Vertices.SetNumUninitialized(DrawList.VtxBuffer.Size);
for (int32 BufferIdx = 0; BufferIdx < Vertices.Num(); ++BufferIdx)
{
const auto& DrawCommand = DrawList.GetCommand(i, ImGuiToScreen);
const ImDrawVert& Vtx = DrawList.VtxBuffer.Data[BufferIdx];
Vertices[BufferIdx] = FSlateVertex::Make<ESlateVertexRounding::Disabled>(Transform, FCogImguiHelper::ToFVector2f(Vtx.pos), FCogImguiHelper::ToFVector2f(Vtx.uv), FVector2f::UnitVector, FCogImguiHelper::ToFColor(Vtx.col));
}
DrawList.CopyIndexData(IndexBuffer, IndexBufferOffset, DrawCommand.NumElements);
TArray<SlateIndex> Indices;
Indices.SetNumUninitialized(DrawList.IdxBuffer.Size);
for (int32 BufferIdx = 0; BufferIdx < Indices.Num(); ++BufferIdx)
{
Indices[BufferIdx] = DrawList.IdxBuffer.Data[BufferIdx];
}
// Advance offset by number of copied elements to position it for the next command.
IndexBufferOffset += DrawCommand.NumElements;
for (const ImDrawCmd& DrawCmd : DrawList.CmdBuffer)
{
TArray VerticesSlice(Vertices.GetData() + DrawCmd.VtxOffset, Vertices.Num() - DrawCmd.VtxOffset);
TArray IndicesSlice(Indices.GetData() + DrawCmd.IdxOffset, DrawCmd.ElemCount);
// Get texture resource handle for this draw command (null index will be also mapped to a valid texture).
const FSlateResourceHandle& Handle = TextureManager.GetTextureHandle(DrawCommand.TextureId);
UTexture2D* Texture = DrawCmd.GetTexID();
if (TextureBrush.GetResourceObject() != Texture)
{
TextureBrush.SetResourceObject(Texture);
if (IsValid(Texture))
{
TextureBrush.ImageSize.X = Texture->GetSizeX();
TextureBrush.ImageSize.Y = Texture->GetSizeY();
TextureBrush.ImageType = ESlateBrushImageType::FullColor;
TextureBrush.DrawAs = ESlateBrushDrawType::Image;
}
else
{
TextureBrush.ImageSize.X = 0;
TextureBrush.ImageSize.Y = 0;
TextureBrush.ImageType = ESlateBrushImageType::NoImage;
TextureBrush.DrawAs = ESlateBrushDrawType::NoDrawType;
}
}
// Transform clipping rectangle to screen space and apply to elements that we draw.
const FSlateRect ClippingRect = DrawCommand.ClippingRect.IntersectionWith(MyClippingRect);
OutDrawElements.PushClip(FSlateClippingZone{ ClippingRect });
// Add elements to the list.
FSlateDrawElement::MakeCustomVerts(OutDrawElements, LayerId, Handle, VertexBuffer, IndexBuffer, nullptr, 0, 0);
FSlateRect ClipRect(DrawCmd.ClipRect.x, DrawCmd.ClipRect.y, DrawCmd.ClipRect.z, DrawCmd.ClipRect.w);
ClipRect = TransformRect(Transform, ClipRect);
OutDrawElements.PushClip(FSlateClippingZone(ClipRect));
FSlateDrawElement::MakeCustomVerts(OutDrawElements, LayerId, TextureBrush.GetRenderingResource(), VerticesSlice, IndicesSlice, nullptr, 0, 0);
OutDrawElements.PopClip();
}
}
@@ -274,128 +99,22 @@ int32 SCogImguiWidget::OnPaint(
FVector2D SCogImguiWidget::ComputeDesiredSize(float Scale) const
{
return FVector2D::ZeroVector;
//return Super::ComputeDesiredSize(Scale);
}
//--------------------------------------------------------------------------------------------------------------------------
ULocalPlayer* SCogImguiWidget::GetLocalPlayer() const
{
if (GameViewport.IsValid() == false)
{
return nullptr;
}
UWorld* World = GameViewport->GetWorld();
if (World == nullptr)
{
return nullptr;
}
ULocalPlayer* LocalPlayer = World->GetFirstLocalPlayerFromController();
return LocalPlayer;
}
//--------------------------------------------------------------------------------------------------------------------------
FVector2D SCogImguiWidget::TransformScreenPointToImGui(const FGeometry& MyGeometry, const FVector2D& Point) const
{
const FSlateRenderTransform ImGuiToScreen = MyGeometry.GetAccumulatedRenderTransform();
return ImGuiToScreen.Inverse().TransformPoint(Point);
}
//--------------------------------------------------------------------------------------------------------------------------
bool SCogImguiWidget::IsConsoleOpened() const
{
return GameViewport->ViewportConsole && GameViewport->ViewportConsole->ConsoleState != NAME_None;
}
//--------------------------------------------------------------------------------------------------------------------------
bool SCogImguiWidget::IsCurrentContext() const
{
return ImGui::GetCurrentContext() == ImGuiContext;
}
//--------------------------------------------------------------------------------------------------------------------------
void SCogImguiWidget::SetAsCurrentContext()
{
ImGui::SetCurrentContext(ImGuiContext);
}
//--------------------------------------------------------------------------------------------------------------------------
void SCogImguiWidget::SetEnableInput(bool Value)
{
bEnableInput = Value;
if (bEnableInput)
{
TakeFocus();
}
else
{
ReturnFocus();
}
ImGuiIO& IO = ImGui::GetIO();
if (bEnableInput)
{
IO.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
}
else
{
IO.ConfigFlags |= ImGuiConfigFlags_NoMouse;
}
}
//--------------------------------------------------------------------------------------------------------------------------
void SCogImguiWidget::SetDPIScale(float Value)
{
if (DpiScale == Value)
{
return;
}
DpiScale = Value;
OnDpiChanged();
}
//--------------------------------------------------------------------------------------------------------------------------
void SCogImguiWidget::OnDpiChanged()
{
if (FontAtlas == nullptr)
{
return;
}
FontAtlas->Clear();
ImFontConfig FontConfig = {};
FontConfig.SizePixels = FMath::RoundFromZero(13.f * DpiScale);
FontAtlas->AddFontDefault(&FontConfig);
unsigned char* Pixels;
int Width, Height, Bpp;
FontAtlas->GetTexDataAsRGBA32(&Pixels, &Width, &Height, &Bpp);
const CogTextureIndex FontsTexureIndex = FCogImguiModule::Get().GetTextureManager().CreateTexture("xx", Width, Height, Bpp, Pixels);
FontAtlas->TexID = FCogImguiHelper::ToImTextureID(FontsTexureIndex);
ImGuiStyle NewStyle = ImGuiStyle();
ImGui::GetStyle() = MoveTemp(NewStyle);
NewStyle.ScaleAllSizes(DpiScale);
}
//--------------------------------------------------------------------------------------------------------------------------
FReply SCogImguiWidget::OnFocusReceived(const FGeometry& MyGeometry, const FFocusEvent& FocusEvent)
{
if (bEnableInput == false)
{
return FReply::Unhandled();
}
Super::OnFocusReceived(MyGeometry, FocusEvent);
FSlateApplication::Get().ResetToDefaultPointerInputSettings();
return FReply::Handled();
}
////--------------------------------------------------------------------------------------------------------------------------
//FReply SCogImguiWidget::OnFocusReceived(const FGeometry& MyGeometry, const FFocusEvent& FocusEvent)
//{
// if (bEnableInput == false)
// {
// return FReply::Unhandled();
// }
//
// Super::OnFocusReceived(MyGeometry, FocusEvent);
//
// FSlateApplication::Get().ResetToDefaultPointerInputSettings();
//
// return FReply::Handled();
//}
//--------------------------------------------------------------------------------------------------------------------------
FReply SCogImguiWidget::OnKeyChar(const FGeometry& MyGeometry, const FCharacterEvent& CharacterEvent)
@@ -408,33 +127,4 @@ FReply SCogImguiWidget::OnKeyChar(const FGeometry& MyGeometry, const FCharacterE
}
//--------------------------------------------------------------------------------------------------------------------------
void SCogImguiWidget::DrawDebug()
{
if (ImGui::Begin("ImGui Integration Debug"))
{
ImGui::BeginDisabled();
ImVec2 AbsPos = FCogImguiHelper::ToImVec2(GetTickSpaceGeometry().GetAbsolutePosition());
ImGui::InputFloat2("Widget Abs Pos", &AbsPos.x, "%0.1f");
ImVec2 AbsSize = FCogImguiHelper::ToImVec2(GetTickSpaceGeometry().GetAbsoluteSize());
ImGui::InputFloat2("Widget Abs Size", &AbsSize.x, "%0.1f");
ImVec2 LocalSize = FCogImguiHelper::ToImVec2(GetTickSpaceGeometry().GetLocalSize());
ImGui::InputFloat2("Widget Local Size", &LocalSize.x, "%0.1f");
FSlateApplication& SlateApp = FSlateApplication::Get();
ImVec2 MousePosition = FCogImguiHelper::ToImVec2(SlateApp.GetCursorPos());
ImGui::InputFloat2("Mouse", &MousePosition.x, "%0.1f");
ImGuiIO& IO = ImGui::GetIO();
ImGui::InputFloat2("ImGui Mouse", &IO.MousePos.x, "%0.1f");
ImGui::EndDisabled();
}
ImGui::End();
}
@@ -2,6 +2,7 @@
#include "Framework/Application/IInputProcessor.h"
class FCogImguiContext;
class SCogImguiWidget;
class UPlayerInput;
enum ImGuiKey : int;
@@ -11,7 +12,7 @@ class FImGuiInputProcessor : public IInputProcessor
{
public:
FImGuiInputProcessor(UPlayerInput* InPlayerInput, SCogImguiWidget* InWidget);
FImGuiInputProcessor(UPlayerInput* InPlayerInput, FCogImguiContext* InContext, SCogImguiWidget* InWidget);
virtual void Tick(const float DeltaTime, FSlateApplication& SlateApp, TSharedRef<ICursor> SlateCursor) override;
@@ -37,6 +38,8 @@ protected:
bool HandleMouseButtonEvent(FSlateApplication& SlateApp, const FPointerEvent& Event, bool IsButtonDown);
bool IsMouseInsideMainViewport();
void AddMousePosEvent(const FVector2D& MousePosition) const;
bool IsKeyBoundToCommand(const FKeyEvent& KeyEvent);
@@ -51,6 +54,8 @@ protected:
static uint32 ToImGuiMouseButton(const FKey& MouseButton);
TObjectPtr<FCogImguiContext> Context = nullptr;
TObjectPtr<UPlayerInput> PlayerInput = nullptr;
TObjectPtr<SCogImguiWidget> MainWidget = nullptr;
@@ -0,0 +1,117 @@
#pragma once
#include "CoreMinimal.h"
#include "Engine/Texture2D.h"
#include "Templates/SharedPointer.h"
#include "UObject/StrongObjectPtr.h"
#include "imgui.h"
class FCogImguiContext;
class IInputProcessor;
class SCogImguiWidget;
class SCogImguiWidget;
class SWindow;
class UGameViewportClient;
struct FDisplayMetrics;
struct ImPlotContext;
struct COGIMGUI_API FImGuiViewportData
{
TWeakPtr<SWindow> Window = nullptr;
TObjectPtr<FCogImguiContext> Context = nullptr;
TWeakPtr<SCogImguiWidget> Widget = nullptr;
};
class COGIMGUI_API FCogImguiContext : public TSharedFromThis<FCogImguiContext>
{
public:
void Initialize();
void Shutdown();
bool GetEnableInput() const { return bEnableInput; }
void SetEnableInput(bool Value);
bool GetShareMouse() const { return bShareMouse; }
void SetShareMouse(bool Value);
void BeginFrame(float InDeltaTime);
void EndFrame();
float GetDpiScale() const { return DpiScale; }
void SetDPIScale(float Value);
private:
void OnDisplayMetricsChanged(const FDisplayMetrics& DisplayMetrics) const;
bool IsConsoleOpened() const;
void DrawDebug();
void TryGiveMouseCaptureBackToGame();
void TryReleaseGameMouseCapture();
void RefreshDPIScale();
void BuildFont();
ULocalPlayer* GetLocalPlayer() const;
static void ImGui_CreateWindow(ImGuiViewport* Viewport);
static void ImGui_DestroyWindow(ImGuiViewport* Viewport);
static void ImGui_ShowWindow(ImGuiViewport* Viewport);
static void ImGui_SetWindowPos(ImGuiViewport* Viewport, ImVec2 Pos);
static ImVec2 ImGui_GetWindowPos(ImGuiViewport* Viewport);
static void ImGui_SetWindowSize(ImGuiViewport* Viewport, ImVec2 Size);
static ImVec2 ImGui_GetWindowSize(ImGuiViewport* Viewport);
static void ImGui_SetWindowFocus(ImGuiViewport* Viewport);
static bool ImGui_GetWindowFocus(ImGuiViewport* Viewport);
static bool ImGui_GetWindowMinimized(ImGuiViewport* Viewport);
static void ImGui_SetWindowTitle(ImGuiViewport* Viewport, const char* TitleAnsi);
static void ImGui_SetWindowAlpha(ImGuiViewport* Viewport, float Alpha);
static void ImGui_RenderWindow(ImGuiViewport* Viewport, void* Data);
TMap<TWeakPtr<SWindow>, ImGuiID> WindowToViewportMap;
TSharedPtr<IInputProcessor> InputProcessor = nullptr;
TStrongObjectPtr<UTexture2D> FontAtlasTexturePtr = nullptr;
TSharedPtr<SCogImguiWidget> MainWidget = nullptr;
TWeakPtr<SWidget> PreviousMouseCaptor = nullptr;
TObjectPtr<UGameViewportClient> GameViewport = nullptr;
ImGuiContext* ImGuiContext = nullptr;
ImPlotContext* PlotContext = nullptr;
char IniFilename[512] = {};
bool bEnableInput = false;
bool bShareMouse = true;
float DpiScale = 1.f;
bool bRefreshDPIScale = false;
};
@@ -6,44 +6,39 @@
#include "Rendering/RenderingCommon.h"
//--------------------------------------------------------------------------------------------------------------------------
class FCogImguiDrawList
struct FCogImguiDrawList
{
public:
FCogImguiDrawList() {};
FCogImguiDrawList(ImDrawList* Source);
struct DrawCommand
{
uint32 NumElements;
FSlateRect ClippingRect;
CogTextureIndex TextureId;
};
ImVector<ImDrawVert> VtxBuffer;
ImVector<ImDrawIdx> IdxBuffer;
ImVector<ImDrawCmd> CmdBuffer;
// Get the number of draw commands in this list.
FORCEINLINE int NumCommands() const { return ImGuiCommandBuffer.Size; }
// Get the draw command by number.
// @param CommandNb - Number of draw command
// @param Transform - Transform to apply to clipping rectangle
// @returns Draw command data
DrawCommand GetCommand(int CommandCount, const FTransform2D& Transform) const;
// Transform and copy vertex data to target buffer (old data in the target buffer are replaced).
// @param OutVertexBuffer - Destination buffer
// @param Transform - Transform to apply to all vertices
void CopyVertexData(TArray<FSlateVertex>& OutVertexBuffer, const FTransform2D& Transform) const;
// Transform and copy index data to target buffer (old data in the target buffer are replaced).
// Internal index buffer contains enough data to match the sum of NumElements from all draw commands.
// @param OutIndexBuffer - Destination buffer
// @param StartIndex - Start copying source data starting from this index
// @param NumElements - How many elements we want to copy
void CopyIndexData(TArray<SlateIndex>& OutIndexBuffer, const int32 StartIndex, const int32 NumElements) const;
// Transfers data from ImGui source list to this object. Leaves source cleared.
void TransferDrawData(ImDrawList& Src);
private:
ImVector<ImDrawCmd> ImGuiCommandBuffer;
ImVector<ImDrawIdx> ImGuiIndexBuffer;
ImVector<ImDrawVert> ImGuiVertexBuffer;
ImDrawListFlags Flags = ImDrawListFlags_None;
};
//--------------------------------------------------------------------------------------------------------------------------
struct FCogImguiDrawData
{
FCogImguiDrawData() {};
FCogImguiDrawData(const ImDrawData* Source);
bool bValid = false;
int32 TotalIdxCount = 0;
int32 TotalVtxCount = 0;
TArray<FCogImguiDrawList> DrawLists;
FVector2f DisplayPos = FVector2f::ZeroVector;
FVector2f DisplaySize = FVector2f::ZeroVector;
FVector2f FrameBufferScale = FVector2f::ZeroVector;
};
@@ -20,11 +20,13 @@ public:
static ImGuiWindow* GetCurrentWindow();
static FColor UnpackImU32Color(ImU32 Color);
static FColor ToFColor(ImU32 Color);
static FSlateRect ToSlateRect(const ImVec4& Value);
static FVector2D ToVector2D(const ImVec2& Value);
static FVector2f ToFVector2f(const ImVec2& Value);
static FVector2D ToFVector2D(const ImVec2& Value);
static ImVec2 ToImVec2(const FVector2D& Value);
@@ -1,10 +1,6 @@
#pragma once
#include "CoreMinimal.h"
#include "CogImguiWidget.h"
#include "CogImguiKeyInfo.h"
#include "CogImguiTextureManager.h"
#include "imgui.h"
#include "Modules/ModuleManager.h"
class COGIMGUI_API FCogImguiModule : public IModuleInterface
@@ -22,22 +18,6 @@ public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;
//----------------------------------------------------------------------------------------------------------------------
TSharedPtr<SCogImguiWidget> CreateImGuiWidget(UGameViewportClient* GameViewport, FCogImguiRenderFunction Render, ImFontAtlas* FontAtlas = nullptr);
void DestroyImGuiWidget(TSharedPtr<SCogImguiWidget> ImGuiWidget);
FCogImguiTextureManager& GetTextureManager() { return TextureManager; }
ImFontAtlas& GetDefaultFontAtlas() { return DefaultFontAtlas; }
private:
void Initialize();
FCogImguiTextureManager TextureManager;
ImFontAtlas DefaultFontAtlas;
bool bIsInitialized = false;
};
@@ -1,147 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "CogImguiHelper.h"
#include "Engine/Texture2D.h"
#include "Styling/SlateBrush.h"
#include "Textures/SlateShaderResource.h"
#include "UObject/WeakObjectPtr.h"
//--------------------------------------------------------------------------------------------------------------------------
class FCogImguiTextureManager
{
public:
// Creates an empty manager.
FCogImguiTextureManager() = default;
// Copying is disabled to protected resource ownership.
FCogImguiTextureManager(const FCogImguiTextureManager&) = delete;
FCogImguiTextureManager& operator=(const FCogImguiTextureManager&) = delete;
// Moving transfers ownership and leaves source empty.
FCogImguiTextureManager(FCogImguiTextureManager&&) = delete;
FCogImguiTextureManager& operator=(FCogImguiTextureManager&&) = delete;
void InitializeErrorTexture();
// Find texture index by name.
// @param Name - The name of a texture to find
// @returns The index of a texture with given name or INDEX_NONE if there is no such texture
CogTextureIndex FindTextureIndex(const FName& Name) const
{
return TextureResources.IndexOfByPredicate([&](const auto& Entry) { return Entry.GetName() == Name; });
}
// Get the name of a texture at given index. Returns NAME_None, if index is out of range.
// @param Index - Index of a texture
// @returns The name of a texture at given index or NAME_None if index is out of range.
FName GetTextureName(CogTextureIndex Index) const
{
return IsInRange(Index) ? TextureResources[Index].GetName() : NAME_None;
}
// Get the Slate Resource Handle to a texture at given index. If index is out of range or resources are not valid
// it returns a handle to the error texture.
// @param Index - Index of a texture
// @returns The Slate Resource Handle for a texture at given index or to error texture, if no valid resources were
// found at given index
const FSlateResourceHandle& GetTextureHandle(CogTextureIndex Index) const
{
return IsValidTexture(Index) ? TextureResources[Index].GetResourceHandle() : ErrorTexture.GetResourceHandle();
}
// Create a texture from raw data.
// @param Name - The texture name
// @param Width - The texture width
// @param Height - The texture height
// @param SrcBpp - The size in bytes of one pixel
// @param SrcData - The source data
// @param SrcDataCleanup - Optional function called to release source data after texture is created (only needed, if data need to be released)
// @returns The index of a texture that was created
CogTextureIndex CreateTexture(const FName& Name, int32 Width, int32 Height, uint32 SrcBpp, uint8* SrcData, TFunction<void(uint8*)> SrcDataCleanup = [](uint8*) {});
// Create a plain texture.
// @param Name - The texture name
// @param Width - The texture width
// @param Height - The texture height
// @param Color - The texture color
// @returns The index of a texture that was created
CogTextureIndex CreatePlainTexture(const FName& Name, int32 Width, int32 Height, FColor Color);
// Create Slate resources to an existing texture, managed externally.
// @param Name - The texture name
// @param Texture - The texture
// @returns The index to created/updated texture resources
CogTextureIndex CreateTextureResources(const FName& Name, UTexture2D* Texture);
// Release resources for given texture. Ignores invalid indices.
// @param Index - The index of a texture resources
void ReleaseTextureResources(CogTextureIndex Index);
private:
// See CreateTexture for general description.
// Internal implementations doesn't validate name or resource uniqueness. Instead it uses NAME_ErrorTexture
// (aka NAME_None) and INDEX_ErrorTexture (aka INDEX_NONE) to identify ErrorTexture.
CogTextureIndex CreateTextureInternal(const FName& Name, int32 Width, int32 Height, uint32 SrcBpp, uint8* SrcData, TFunction<void(uint8*)> SrcDataCleanup = [](uint8*) {});
// See CreatePlainTexture for general description.
// Internal implementations doesn't validate name or resource uniqueness. Instead it uses NAME_ErrorTexture
// (aka NAME_None) and INDEX_ErrorTexture (aka INDEX_NONE) to identify ErrorTexture.
CogTextureIndex CreatePlainTextureInternal(const FName& Name, int32 Width, int32 Height, const FColor& Color);
// Add or reuse texture entry.
// @param Name - The texture name
// @param Texture - The texture
// @param bAddToRoot - If true, we should add texture to root to prevent garbage collection (use for own textures)
// @returns The index of the entry that we created or reused
CogTextureIndex AddTextureEntry(const FName& Name, UTexture2D* Texture, bool bAddToRoot);
// Check whether index is in range allocated for TextureResources (it doesn't mean that resources are valid).
FORCEINLINE bool IsInRange(CogTextureIndex Index) const
{
return static_cast<uint32>(Index) < static_cast<uint32>(TextureResources.Num());
}
// Check whether index is in range and whether texture resources are valid (using NAME_None sentinel).
FORCEINLINE bool IsValidTexture(CogTextureIndex Index) const
{
return IsInRange(Index) && TextureResources[Index].GetName() != NAME_None;
}
// Entry for texture resources. Only supports explicit construction.
struct FTextureEntry
{
FTextureEntry() = default;
FTextureEntry(const FName& InName, UTexture2D* InTexture, bool bAddToRoot);
~FTextureEntry();
// Copying is not supported.
FTextureEntry(const FTextureEntry&) = delete;
FTextureEntry& operator=(const FTextureEntry&) = delete;
// We rely on TArray and don't implement custom move constructor...
FTextureEntry(FTextureEntry&&) = delete;
// ... but we need move assignment to support reusing entries.
FTextureEntry& operator=(FTextureEntry&& Other);
const FName& GetName() const { return Name; }
const FSlateResourceHandle& GetResourceHandle() const;
private:
void Reset(bool bReleaseResources);
FName Name = NAME_None;
mutable FSlateResourceHandle CachedResourceHandle;
TWeakObjectPtr<UTexture2D> Texture;
FSlateBrush Brush;
};
TArray<FTextureEntry> TextureResources;
FTextureEntry ErrorTexture;
static constexpr EName NAME_ErrorTexture = NAME_None;
static constexpr CogTextureIndex INDEX_ErrorTexture = INDEX_NONE;
};
@@ -7,14 +7,8 @@
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/SLeafWidget.h"
class IInputProcessor;
class FCogImguiContext;
class UGameViewportClient;
class ULocalPlayer;
struct ImFontAtlas;
struct ImGuiContext;
struct ImPlotContext;
using FCogImguiRenderFunction = TFunction<void(float DeltaTime)>;
//--------------------------------------------------------------------------------------------------------------------------
class COGIMGUI_API SCogImguiWidget : public SLeafWidget
@@ -24,81 +18,26 @@ class COGIMGUI_API SCogImguiWidget : public SLeafWidget
public:
SLATE_BEGIN_ARGS(SCogImguiWidget) {}
SLATE_ARGUMENT(UGameViewportClient*, GameViewport)
SLATE_ARGUMENT(ImFontAtlas*, FontAtlas)
SLATE_ARGUMENT(FCogImguiRenderFunction, Render)
SLATE_ARGUMENT(FCogImguiContext*, Context)
SLATE_END_ARGS()
void Construct(const FArguments& InArgs);
~SCogImguiWidget();
//----------------------------------------------------------------------------------------------------
// SWidget overrides
//----------------------------------------------------------------------------------------------------
virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override;
virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyClippingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& WidgetStyle, bool bParentEnabled) const override;
virtual bool SupportsKeyboardFocus() const override { return true; }
virtual FReply OnKeyChar(const FGeometry& MyGeometry, const FCharacterEvent& CharacterEvent) override;
virtual FReply OnFocusReceived(const FGeometry& MyGeometry, const FFocusEvent& FocusEvent) override;
virtual FVector2D ComputeDesiredSize(float Scale) const override;
ULocalPlayer* GetLocalPlayer() const;
bool GetEnableInput() const { return bEnableInput; }
void SetEnableInput(bool Value);
bool GetShareMouse() const { return bShareMouse; }
void SetShareMouse(bool Value) { bShareMouse = Value; }
float GetDpiScale() const { return DpiScale; }
void SetDPIScale(float Value);
bool IsCurrentContext() const;
void SetAsCurrentContext();
TWeakObjectPtr<UGameViewportClient> GetGameViewport() const { return GameViewport; }
void DestroyImGuiContext();
void SetDrawData(const ImDrawData* InDrawData);
protected:
FVector2D TransformScreenPointToImGui(const FGeometry& MyGeometry, const FVector2D& Point) const;
virtual void TickKeyModifiers();
virtual void TickImGui(float InDeltaTime);
virtual void TickFocus();
virtual void TakeFocus();
virtual void ReturnFocus();
virtual void OnDpiChanged();
virtual bool IsConsoleOpened() const;
virtual void DrawDebug();
TWeakObjectPtr<UGameViewportClient> GameViewport;
ImFontAtlas* FontAtlas = nullptr;
TWeakPtr<SWidget> PreviousUserFocusedWidget;
bool bEnableInput = false;
bool bShareMouse = true;
TObjectPtr<FCogImguiContext> Context = nullptr;
FSlateRenderTransform ImGuiRenderTransform;
@@ -106,17 +45,5 @@ protected:
mutable TArray<SlateIndex> IndexBuffer;
TArray<FCogImguiDrawList> DrawLists;
ImGuiContext* ImGuiContext = nullptr;
ImPlotContext* ImPlotContext = nullptr;
FCogImguiRenderFunction Render;
float DpiScale = 1.f;
char IniFilename[512];
TSharedPtr<IInputProcessor> InputProcessor = nullptr;
FCogImguiDrawData DrawData;
};
@@ -2,6 +2,7 @@
#include "CogDebugDraw.h"
#include "CogDebugSettings.h"
#include "CogWindow_Settings.h"
#include "CogWindowManager.h"
#include "CogWindowWidgets.h"
#include "Engine/World.h"
@@ -75,7 +76,7 @@ void FCogWindow::Render(float DeltaTime)
ImGui::PopStyleVar(1);
}
if (GetOwner()->GetShowHelp())
if (GetOwner()->GetSettingsWindow()->GetSettingsConfig()->bShowHelp)
{
if (ImGui::IsItemHovered())
{
@@ -1,9 +1,9 @@
#include "CogWindowManager.h"
#include "CogDebugDrawImGui.h"
#include "CogImguiHelper.h"
#include "CogImguiInputHelper.h"
#include "CogImguiModule.h"
#include "CogWindow_Inputs.h"
#include "CogWindow_Layouts.h"
#include "CogWindow_Settings.h"
#include "CogWindow_Spacing.h"
@@ -41,7 +41,7 @@ void UCogWindowManager::PostInitProperties()
//--------------------------------------------------------------------------------------------------------------------------
void UCogWindowManager::InitializeInternal()
{
ImGuiWidget = FCogImguiModule::Get().CreateImGuiWidget(GEngine->GameViewport, [this](float DeltaTime) { Render(DeltaTime); });
Context.Initialize();
ImGuiSettingsHandler IniHandler;
IniHandler.TypeName = "Cog";
@@ -59,7 +59,6 @@ void UCogWindowManager::InitializeInternal()
SpaceWindows.Add(AddWindow<FCogWindow_Spacing>("Spacing 3", false));
SpaceWindows.Add(AddWindow<FCogWindow_Spacing>("Spacing 4", false));
InputsWindow = AddWindow<FCogWindow_Inputs>("Window.Inputs", false);
LayoutsWindow = AddWindow<FCogWindow_Layouts>("Window.Layouts", false);
SettingsWindow = AddWindow<FCogWindow_Settings>("Window.Settings", false);
@@ -86,7 +85,8 @@ void UCogWindowManager::InitializeInternal()
TEXT("Save the layout. Cog.SaveLayout <Index>"),
FConsoleCommandWithArgsDelegate::CreateLambda([this](const TArray<FString>& Args) { if (Args.Num() > 0) { SaveLayout(FCString::Atoi(*Args[0])); }}),
ECVF_Cheat));
IsInitialized = true;
}
//--------------------------------------------------------------------------------------------------------------------------
@@ -105,7 +105,7 @@ void UCogWindowManager::Shutdown()
// Destroy ImGui before destroying the windows to make sure
// imgui serialize their visibility state in imgui.ini
//------------------------------------------------------------
ImGuiWidget->DestroyImGuiContext();
Context.Shutdown();
SaveConfig();
@@ -125,8 +125,6 @@ void UCogWindowManager::Shutdown()
{
IConsoleManager::Get().UnregisterConsoleObject(ConsoleCommand);
}
FCogImguiModule::Get().DestroyImGuiWidget(ImGuiWidget);
}
//--------------------------------------------------------------------------------------------------------------------------
@@ -137,7 +135,7 @@ void UCogWindowManager::Tick(float DeltaTime)
return;
}
if (ImGuiWidget.IsValid() == false)
if (IsInitialized == false)
{
InitializeInternal();
}
@@ -149,16 +147,14 @@ void UCogWindowManager::Tick(float DeltaTime)
LayoutToLoad = -1;
}
if (bRefreshDPIScale)
{
RefreshDPIScale();
bRefreshDPIScale = false;
}
for (FCogWindow* Window : Windows)
{
Window->GameTick(DeltaTime);
}
Context.BeginFrame(DeltaTime);
Render(DeltaTime);
Context.EndFrame();
}
//--------------------------------------------------------------------------------------------------------------------------
@@ -168,7 +164,7 @@ void UCogWindowManager::Render(float DeltaTime)
ImGui::DockSpaceOverViewport(0, ImGuiDockNodeFlags_PassthruCentralNode | ImGuiDockNodeFlags_NoDockingInCentralNode | ImGuiDockNodeFlags_AutoHideTabBar);
ImGui::PopStyleColor(1);
bool bCompactSaved = bCompactMode;
bool bCompactSaved = SettingsWindow->GetSettingsConfig()->bCompactMode;
if (bCompactSaved)
{
FCogWindowWidgets::PushStyleCompact();
@@ -176,7 +172,7 @@ void UCogWindowManager::Render(float DeltaTime)
if (bHideAllWindows == false)
{
if (ImGuiWidget->GetEnableInput() || bHideMainMenuOnGameInput == false)
if (Context.GetEnableInput())
{
RenderMainMenu();
}
@@ -188,7 +184,7 @@ void UCogWindowManager::Render(float DeltaTime)
if (Window->GetIsVisible() && bHideAllWindows == false)
{
if (bTransparentMode)
if (SettingsWindow->GetSettingsConfig()->bTransparentMode)
{
ImGui::SetNextWindowBgAlpha(0.35f);
}
@@ -202,8 +198,6 @@ void UCogWindowManager::Render(float DeltaTime)
FCogWindowWidgets::PopStyleCompact();
}
TickDPI();
FCogDebugDrawImGui::Draw();
}
@@ -354,8 +348,6 @@ void UCogWindowManager::RenderMainMenu()
ImGui::Separator();
RenderMenuItem(*InputsWindow, "Inputs");
RenderMenuItem(*LayoutsWindow, "Layouts");
RenderMenuItem(*SettingsWindow, "Settings");
@@ -508,7 +500,7 @@ void UCogWindowManager::RenderOptionMenu(UCogWindowManager::FMenu& Menu)
//--------------------------------------------------------------------------------------------------------------------------
void UCogWindowManager::RenderMenuItem(FCogWindow& Window, const char* MenuItemName)
{
if (bShowWindowsInMainMenu)
if (SettingsWindow->GetSettingsConfig()->bShowWindowsInMainMenu)
{
ImGui::SetNextWindowSizeConstraints(
ImVec2(FCogWindowWidgets::GetFontWidth() * 40, ImGui::GetTextLineHeightWithSpacing() * 5),
@@ -535,31 +527,7 @@ void UCogWindowManager::RenderMenuItem(FCogWindow& Window, const char* MenuItemN
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogWindowManager::TickDPI()
{
const float MouseWheel = ImGui::GetIO().MouseWheel;
const bool IsControlDown = ImGui::GetIO().KeyCtrl;
if (IsControlDown && MouseWheel != 0)
{
SetDPIScale(FMath::Clamp(DPIScale + (MouseWheel > 0 ? 0.1f : -0.1f), 0.5f, 2.0f));
}
const bool IsMiddleMouseClicked = ImGui::GetIO().MouseClicked[2];
if (IsControlDown && IsMiddleMouseClicked)
{
SetDPIScale(1.0f);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogWindowManager::RefreshDPIScale()
{
if (SCogImguiWidget* Widget = ImGuiWidget.Get())
{
Widget->SetDPIScale(DPIScale);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogWindowManager::SettingsHandler_ClearAll(ImGuiContext* Context, ImGuiSettingsHandler* Handler)
@@ -652,18 +620,6 @@ void UCogWindowManager::SettingsHandler_WriteAll(ImGuiContext* Context, ImGuiSet
Buffer->append("\n");
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogWindowManager::SetDPIScale(float Value)
{
if (DPIScale == Value)
{
return;
}
DPIScale = Value;
bRefreshDPIScale = true;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogWindowManager::ResetAllWindowsConfig()
{
@@ -786,5 +742,5 @@ const UObject* UCogWindowManager::GetAsset(const TSubclassOf<UObject> AssetClass
void UCogWindowManager::ToggleInputMode()
{
UE_LOG(LogCogImGui, Verbose, TEXT("UCogWindowManager::ToggleInputMode"));
ImGuiWidget->SetEnableInput(!ImGuiWidget->GetEnableInput());
Context.SetEnableInput(!Context.GetEnableInput());
}
@@ -1,89 +1,2 @@
#include "CogWindow_Inputs.h"
#include "CogImguiInputHelper.h"
#include "CogImguiWidget.h"
#include "CogWindowManager.h"
#include "CogWindowWidgets.h"
#include "InputCoreTypes.h"
#include "imgui.h"
//--------------------------------------------------------------------------------------------------------------------------
void FCogWindow_Inputs::Initialize()
{
Super::Initialize();
bHasMenu = false;
Config = GetConfig<UCogEngineConfig_Inputs>();
SCogImguiWidget* ImGuiWidget = GetOwner()->GetImGuiWidget().Get();
ImGuiWidget->SetEnableInput(Config->bEnableInput);
ImGuiIO& IO = ImGui::GetIO();
FCogImguiHelper::SetFlags(IO.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard, Config->bNavEnableKeyboard);
FCogImguiHelper::SetFlags(IO.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad, Config->bNavEnableGamepad);
FCogImguiHelper::SetFlags(IO.ConfigFlags, ImGuiConfigFlags_NavNoCaptureKeyboard, Config->bNavNoCaptureInput);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogWindow_Inputs::PreSaveConfig()
{
Super::PreSaveConfig();
ImGuiIO& IO = ImGui::GetIO();
Config->bNavEnableKeyboard = IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard;
Config->bNavEnableGamepad = IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad;
Config->bNavNoCaptureInput = IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard;
if (SCogImguiWidget* ImGuiWidget = GetOwner()->GetImGuiWidget().Get())
{
Config->bEnableInput = ImGuiWidget->GetEnableInput();
Config->bShareMouse = ImGuiWidget->GetShareMouse();
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogWindow_Inputs::RenderContent()
{
const UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*GetWorld());
if (PlayerInput == nullptr)
{
return;
}
SCogImguiWidget* ImGuiWidget = GetOwner()->GetImGuiWidget().Get();
if (ImGuiWidget == nullptr)
{
return;
}
bool bEnableInput = ImGuiWidget->GetEnableInput();
if (ImGui::Checkbox("Enable Input", &bEnableInput))
{
ImGuiWidget->SetEnableInput(bEnableInput);
}
const char* ShortcutText = TCHAR_TO_ANSI(*FCogImguiInputHelper::CommandToString(PlayerInput, UCogWindowManager::ToggleInputCommand));
const float ShortcutWidth = (ShortcutText && ShortcutText[0]) ? ImGui::CalcTextSize(ShortcutText, NULL).x : 0.0f;
if (ShortcutWidth > 0.0f)
{
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetWindowContentRegionMax().x - ShortcutWidth);
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
ImGui::Text(ShortcutText);
ImGui::PopStyleColor();
}
ImGui::Separator();
bool bShareMouse = ImGuiWidget->GetShareMouse();
if (ImGui::Checkbox("Share Mouse", &bShareMouse))
{
ImGuiWidget->SetShareMouse(bShareMouse);
}
ImGuiIO& IO = ImGui::GetIO();
ImGui::CheckboxFlags("Keyboard Navigation", &IO.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
ImGui::CheckboxFlags("Gamepad Navigation", &IO.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
ImGui::CheckboxFlags("Navigation No Capture", &IO.ConfigFlags, ImGuiConfigFlags_NavNoCaptureKeyboard);
}
@@ -1,8 +1,12 @@
#include "CogWindow_Settings.h"
#include "CogImguiHelper.h"
#include "CogImguiInputHelper.h"
#include "CogImguiModule.h"
#include "CogImguiWidget.h"
#include "CogWindowManager.h"
#include "CogWindowWidgets.h"
#include "imgui.h"
#include "InputCoreTypes.h"
//--------------------------------------------------------------------------------------------------------------------------
@@ -11,17 +15,86 @@ void FCogWindow_Settings::Initialize()
Super::Initialize();
bHasMenu = false;
Config = GetConfig<UCogWindowConfig_Settings>();
ImGuiIO& IO = ImGui::GetIO();
FCogImguiHelper::SetFlags(IO.ConfigFlags, ImGuiConfigFlags_ViewportsEnable, Config->bEnableViewports);
GetOwner()->GetContext().SetDPIScale(Config->DPIScale);
FCogImguiContext& Context = GetOwner()->GetContext();
Context.SetEnableInput(Config->bEnableInput);
Context.SetShareMouse(Config->bShareMouse);
FCogImguiHelper::SetFlags(IO.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard, Config->bNavEnableKeyboard);
FCogImguiHelper::SetFlags(IO.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad, Config->bNavEnableGamepad);
FCogImguiHelper::SetFlags(IO.ConfigFlags, ImGuiConfigFlags_NavNoCaptureKeyboard, Config->bNavNoCaptureInput);
FCogImguiHelper::SetFlags(IO.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange, Config->bNoMouseCursorChange);
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogWindow_Settings::PreSaveConfig()
{
Super::PreSaveConfig();
ImGuiIO& IO = ImGui::GetIO();
Config->bNavEnableKeyboard = IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard;
Config->bNavEnableGamepad = IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad;
Config->bNavNoCaptureInput = IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard;
Config->bNoMouseCursorChange = IO.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange;
const FCogImguiContext& Context = GetOwner()->GetContext();
Config->bEnableInput = Context.GetEnableInput();
Config->bShareMouse = Context.GetShareMouse();
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogWindow_Settings::ResetConfig()
{
Super::ResetConfig();
Config->Reset();
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogWindow_Settings::RenderContent()
{
const UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*GetWorld());
if (PlayerInput == nullptr)
{
return;
}
ImGuiIO& IO = ImGui::GetIO();
FCogImguiContext& Context = GetOwner()->GetContext();
bool bEnableInput = Context.GetEnableInput();
if (ImGui::Checkbox("Enable Input", &bEnableInput))
{
Context.SetEnableInput(bEnableInput);
}
const char* ShortcutText = TCHAR_TO_ANSI(*FCogImguiInputHelper::CommandToString(PlayerInput, UCogWindowManager::ToggleInputCommand));
const float ShortcutWidth = (ShortcutText && ShortcutText[0]) ? ImGui::CalcTextSize(ShortcutText, NULL).x : 0.0f;
if (ShortcutWidth > 0.0f)
{
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetWindowContentRegionMax().x - ShortcutWidth);
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
ImGui::Text(ShortcutText);
ImGui::PopStyleColor();
}
ImGui::Separator();
FCogWindowWidgets::SetNextItemToShortWidth();
ImGui::SliderFloat("DPI Scale", &GetOwner()->DPIScale, 0.5f, 2.0f, "%.1f");
ImGui::SliderFloat("DPI Scale", &Config->DPIScale, 0.5f, 2.0f, "%.1f");
if (ImGui::IsItemDeactivatedAfterEdit())
{
GetOwner()->bRefreshDPIScale = true;
SetDPIScale(Config->DPIScale);
}
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
@@ -30,20 +103,63 @@ void FCogWindow_Settings::RenderContent()
ImGui::EndTooltip();
}
ImGui::Checkbox("Compact Mode", &GetOwner()->bCompactMode);
ImGui::Separator();
ImGui::Checkbox("Show Windows In Main Menu", &GetOwner()->bShowWindowsInMainMenu);
if (ImGui::Checkbox("Enable Viewports", &Config->bEnableViewports))
{
FCogImguiHelper::SetFlags(IO.ConfigFlags, ImGuiConfigFlags_ViewportsEnable, Config->bEnableViewports);
}
ImGui::Checkbox("Hide Main Menu On Game Input", &GetOwner()->bHideMainMenuOnGameInput);
ImGui::Checkbox("Compact Mode", &Config->bCompactMode);
ImGui::Checkbox("Show Window Help", &GetOwner()->bShowHelp);
ImGui::Checkbox("Show Windows In Main Menu", &Config->bShowWindowsInMainMenu);
ImGui::Checkbox("Show Window Help", &Config->bShowHelp);
ImGui::Separator();
bool bShareMouse = Context.GetShareMouse();
if (ImGui::Checkbox("Share Mouse", &bShareMouse))
{
Context.SetShareMouse(bShareMouse);
}
ImGui::CheckboxFlags("Keyboard Navigation", &IO.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
ImGui::CheckboxFlags("Gamepad Navigation", &IO.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
ImGui::CheckboxFlags("Navigation No Capture", &IO.ConfigFlags, ImGuiConfigFlags_NavNoCaptureKeyboard);
ImGui::CheckboxFlags("No Mouse Cursor Change", &IO.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
ImGui::Separator();
ImGui::Spacing();
ImGui::Spacing();
if (ImGui::Button("Reset All Windows Config"))
{
GetOwner()->ResetAllWindowsConfig();
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogWindow_Settings::RenderTick(float DeltaTime)
{
Super::RenderTick(DeltaTime);
const float MouseWheel = ImGui::GetIO().MouseWheel;
const bool IsControlDown = ImGui::GetIO().KeyCtrl;
if (IsControlDown && MouseWheel != 0)
{
SetDPIScale(FMath::Clamp(Config->DPIScale + (MouseWheel > 0 ? 0.1f : -0.1f), 0.5f, 2.0f));
}
const bool IsMiddleMouseClicked = ImGui::GetIO().MouseClicked[2];
if (IsControlDown && IsMiddleMouseClicked)
{
SetDPIScale(1.0f);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogWindow_Settings::SetDPIScale(float Value)
{
Config->DPIScale = Value;
GetOwner()->GetContext().SetDPIScale(Config->DPIScale);
}
@@ -1,12 +1,11 @@
#pragma once
#include "CoreMinimal.h"
#include "CogImguiWidget.h"
#include "CogImguiContext.h"
#include "imgui.h"
#include "CogWindowManager.generated.h"
class FCogWindow;
class FCogWindow_Inputs;
class FCogWindow_Layouts;
class FCogWindow_Settings;
class IConsoleObject;
@@ -55,26 +54,12 @@ public:
virtual void SetHideAllWindows(bool Value);
virtual float GetDPIScale() const { return DPIScale; }
virtual void SetDPIScale(float Value);
virtual bool GetCompactMode() const { return bCompactMode; }
virtual void SetCompactMode(bool Value) { bCompactMode = Value; }
virtual bool GetShowHelp() const { return bShowHelp; }
virtual void SetShowHelp(bool Value) { bShowHelp = Value; }
virtual bool GetPreviewWindowsInMenu() const { return bShowWindowsInMainMenu; }
virtual void SetPreviewWindowsInMenu(bool Value) { bShowWindowsInMainMenu = Value; }
virtual void ResetAllWindowsConfig();
virtual bool RegisterDefaultCommandBindings();
const FCogWindow_Settings* GetSettingsWindow() const { return SettingsWindow; }
UCogWindowConfig* GetConfig(const TSubclassOf<UCogWindowConfig> ConfigClass);
template<class T>
@@ -85,7 +70,9 @@ public:
template<typename T>
T* GetAsset();
TSharedPtr<SCogImguiWidget> GetImGuiWidget() const { return ImGuiWidget; }
const FCogImguiContext& GetContext() const { return Context; }
FCogImguiContext& GetContext() { return Context; }
static void AddCommand(UPlayerInput* PlayerInput, const FString& Command, const FKey& Key);
@@ -93,7 +80,6 @@ public:
protected:
friend class FCogWindow_Inputs;
friend class FCogWindow_Layouts;
friend class FCogWindow_Settings;
@@ -106,8 +92,6 @@ protected:
virtual void InitializeInternal();
virtual void RefreshDPIScale();
virtual void RenderMainMenu();
virtual FMenu* AddMenu(const FString& Name);
@@ -116,8 +100,6 @@ protected:
virtual void RenderMenuItem(FCogWindow& Window, const char* MenuItemName);
virtual void TickDPI();
virtual void ToggleInputMode();
static void SettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*);
@@ -144,37 +126,10 @@ protected:
UPROPERTY()
mutable TArray<const UObject*> Assets;
UPROPERTY(Config)
bool bCompactMode = false;
UPROPERTY(Config)
bool bTransparentMode = false;
UPROPERTY(Config)
float DPIScale = 1.0f;
UPROPERTY(Config)
bool bShowHelp = true;
UPROPERTY(Config)
bool bShowWindowsInMainMenu = true;
UPROPERTY(Config)
bool bRegisterDefaultCommands = true;
UPROPERTY(Config)
bool bAuthorizeInactiveInput = true;
UPROPERTY(Config)
bool bAuthorizeExclusiveInput = true;
UPROPERTY(Config)
bool bAuthorizeSharedInput = true;
UPROPERTY(Config)
bool bHideMainMenuOnGameInput = true;
TSharedPtr<SCogImguiWidget> ImGuiWidget = nullptr;
FCogImguiContext Context;
TArray<FCogWindow*> Windows;
@@ -184,8 +139,6 @@ protected:
TArray<FCogWindow*> SpaceWindows;
FCogWindow_Inputs* InputsWindow = nullptr;
FCogWindow_Settings* SettingsWindow = nullptr;
FCogWindow_Layouts* LayoutsWindow = nullptr;
@@ -198,7 +151,7 @@ protected:
bool bHideAllWindows = false;
bool bRefreshDPIScale = false;
bool IsInitialized = false;
TArray<IConsoleObject*> ConsoleCommands;
};
@@ -1,60 +1 @@
#pragma once
#include "CoreMinimal.h"
#include "CogWindow.h"
#include "CogWindowConfig.h"
#include "CogWindow_Inputs.generated.h"
class UCogEngineConfig_Inputs;
class COGWINDOW_API FCogWindow_Inputs : public FCogWindow
{
typedef FCogWindow Super;
public:
virtual void Initialize() override;
virtual void PreSaveConfig() override;
protected:
virtual void RenderContent() override;
TObjectPtr<UCogEngineConfig_Inputs> Config = nullptr;
};
//--------------------------------------------------------------------------------------------------------------------------
UCLASS(Config = Cog)
class UCogEngineConfig_Inputs : public UCogWindowConfig
{
GENERATED_BODY()
public:
UPROPERTY(Config)
bool bEnableInput = false;
UPROPERTY(Config)
bool bShareMouse = true;
UPROPERTY(Config)
bool bNavEnableKeyboard = true;
UPROPERTY(Config)
bool bNavEnableGamepad = true;
UPROPERTY(Config)
bool bNavNoCaptureInput = true;
virtual void Reset() override
{
Super::Reset();
bEnableInput = false;
bShareMouse = true;
bNavEnableKeyboard = true;
bNavEnableGamepad = true;
bNavNoCaptureInput = true;
}
};
@@ -2,7 +2,12 @@
#include "CoreMinimal.h"
#include "CogWindow.h"
#include "CogWindowConfig.h"
#include "CogWindow_Settings.generated.h"
class UCogEngineConfig_Settings;
//--------------------------------------------------------------------------------------------------------------------------
class COGWINDOW_API FCogWindow_Settings : public FCogWindow
{
typedef FCogWindow Super;
@@ -11,7 +16,83 @@ public:
virtual void Initialize() override;
virtual void RenderTick(float DeltaTime) override;
const UCogWindowConfig_Settings* GetSettingsConfig() const { return Config; }
void SetDPIScale(float Value);
protected:
virtual void RenderContent() override;
virtual void PreSaveConfig() override;
virtual void ResetConfig() override;
TObjectPtr<UCogWindowConfig_Settings> Config = nullptr;
};
//--------------------------------------------------------------------------------------------------------------------------
UCLASS(Config = Cog)
class UCogWindowConfig_Settings : public UCogWindowConfig
{
GENERATED_BODY()
public:
UPROPERTY(Config)
float DPIScale = 1.0f;
UPROPERTY(Config)
bool bEnableViewports = false;
UPROPERTY(Config)
bool bCompactMode = false;
UPROPERTY(Config)
bool bTransparentMode = false;
UPROPERTY(Config)
bool bShowHelp = true;
UPROPERTY(Config)
bool bShowWindowsInMainMenu = true;
UPROPERTY(Config)
bool bEnableInput = false;
UPROPERTY(Config)
bool bShareMouse = true;
UPROPERTY(Config)
bool bNavEnableKeyboard = true;
UPROPERTY(Config)
bool bNavEnableGamepad = true;
UPROPERTY(Config)
bool bNavNoCaptureInput = true;
UPROPERTY(Config)
bool bNoMouseCursorChange = false;
virtual void Reset() override
{
Super::Reset();
DPIScale = 1.0f;
bEnableViewports = false;
bCompactMode = false;
bTransparentMode = false;
bShowHelp = true;
bShowWindowsInMainMenu = true;
bEnableInput = false;
bShareMouse = true;
bNavEnableKeyboard = true;
bNavEnableGamepad = true;
bNavNoCaptureInput = true;
bNoMouseCursorChange = false;
}
};
+3
View File
@@ -36,6 +36,7 @@
#include "CogEngineWindow_Scalability.h"
#include "CogEngineWindow_Selection.h"
#include "CogEngineWindow_Skeleton.h"
#include "CogEngineWindow_Slate.h"
#include "CogEngineWindow_Spawns.h"
#include "CogEngineWindow_Stats.h"
#include "CogEngineWindow_TimeScale.h"
@@ -162,6 +163,8 @@ void ACogSampleGameState::InitializeCog()
CogWindowManager->AddWindow<FCogEngineWindow_Skeleton>("Engine.Skeleton");
CogWindowManager->AddWindow<FCogEngineWindow_Slate>("Engine.Slate");
CogWindowManager->AddWindow<FCogEngineWindow_Spawns>("Engine.Spawns");
FCogEngineWindow_Stats* StatsWindow = CogWindowManager->AddWindow<FCogEngineWindow_Stats>("Engine.Stats");