First Submit

This commit is contained in:
Arnaud Jamin
2023-10-02 01:32:41 -04:00
parent c34574e841
commit 1aabdb5c4e
445 changed files with 93851 additions and 0 deletions
+38
View File
@@ -0,0 +1,38 @@
{
"FileVersion": 1,
"Version": 1,
"VersionName": "1.0",
"FriendlyName": "CogEngine",
"Description": "",
"Category": "Other",
"CreatedBy": "Arnaud Jamin",
"CreatedByURL": "",
"DocsURL": "",
"MarketplaceURL": "",
"SupportURL": "",
"CanContainContent": true,
"IsBetaVersion": false,
"IsExperimentalVersion": false,
"Installed": false,
"Modules": [
{
"Name": "CogEngine",
"Type": "Runtime",
"LoadingPhase": "Default"
}
],
"Plugins": [
{
"Name": "CogImgui",
"Enabled": true
},
{
"Name": "CogDebug",
"Enabled": true
},
{
"Name": "CogWindow",
"Enabled": true
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1,50 @@
using UnrealBuildTool;
public class CogEngine : ModuleRules
{
public CogEngine(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.AddRange(
new string[] {
}
);
PrivateIncludePaths.AddRange(
new string[] {
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CogImgui",
"CogDebug",
"CogWindow",
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
"NetCore",
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
}
);
}
}
@@ -0,0 +1,48 @@
#include "CogEngineModule.h"
#define LOCTEXT_NAMESPACE "FCogEngineModule"
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineModule::StartupModule()
{
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineModule::ShutdownModule()
{
}
//--------------------------------------------------------------------------------------------------------------------------
ACogEngineReplicator* FCogEngineModule::GetLocalReplicator()
{
return LocalReplicator;
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineModule::SetLocalReplicator(ACogEngineReplicator* Value)
{
LocalReplicator = Value;
}
//--------------------------------------------------------------------------------------------------------------------------
ACogEngineReplicator* FCogEngineModule::GetRemoteReplicator(const APlayerController* PlayerController)
{
for (ACogEngineReplicator* Replicator : RemoteReplicators)
{
if (Replicator->GetPlayerController() == PlayerController)
{
return Replicator;
}
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------------------------------
void FCogEngineModule::AddRemoteReplicator(ACogEngineReplicator* Value)
{
RemoteReplicators.Add(Value);
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FCogEngineModule, CogEngine)
@@ -0,0 +1,120 @@
#include "CogEngineReplicator.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/WorldSettings.h"
#include "Net/Core/PushModel/PushModel.h"
#include "Net/UnrealNetwork.h"
//--------------------------------------------------------------------------------------------------------------------------
void ACogEngineReplicator::Create(APlayerController* Controller)
{
if (Controller->GetWorld()->GetNetMode() != NM_Client)
{
FActorSpawnParameters SpawnInfo;
SpawnInfo.Owner = Controller;
Controller->GetWorld()->SpawnActor<ACogEngineReplicator>(SpawnInfo);
}
}
//--------------------------------------------------------------------------------------------------------------------------
ACogEngineReplicator::ACogEngineReplicator(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
#if !UE_BUILD_SHIPPING
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.bAllowTickOnDedicatedServer = true;
PrimaryActorTick.bTickEvenWhenPaused = true;
PrimaryActorTick.bStartWithTickEnabled = true;
PrimaryActorTick.TickGroup = TG_PrePhysics;
bHasAuthority = false;
bIsLocal = false;
bReplicates = true;
bOnlyRelevantToOwner = true;
#endif // !UE_BUILD_SHIPPING
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogEngineReplicator::BeginPlay()
{
Super::BeginPlay();
UWorld* World = GetWorld();
check(World);
const ENetMode NetMode = World->GetNetMode();
bHasAuthority = NetMode != NM_Client;
bIsLocal = NetMode != NM_DedicatedServer;
OwnerPlayerController = Cast<APlayerController>(GetOwner());
if (OwnerPlayerController->IsLocalController())
{
FCogEngineModule::Get().SetLocalReplicator(this);
}
else
{
FCogEngineModule::Get().AddRemoteReplicator(this);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogEngineReplicator::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
FDoRepLifetimeParams Params;
Params.bIsPushBased = true;
DOREPLIFETIME_WITH_PARAMS_FAST(ACogEngineReplicator, TimeDilation, Params);
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogEngineReplicator::TickSpawnActions()
{
#if !UE_BUILD_SHIPPING
if (OwnerPlayerController == nullptr)
{
return;
}
for (int32 i = SpawnActions.Num() - 1; i >= 0; --i)
{
const FCogEngineReplicatorSpawnAction& SpawnInfo = SpawnActions[i];
SpawnActions.RemoveAt(i);
}
#endif // !UE_BUILD_SHIPPING
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogEngineReplicator::Server_SetTimeDilation_Implementation(float Value)
{
#if !UE_BUILD_SHIPPING
COMPARE_ASSIGN_AND_MARK_PROPERTY_DIRTY(ACogEngineReplicator, TimeDilation, Value, this);
OnRep_TimeDilation();
#endif // !UE_BUILD_SHIPPING
}
//--------------------------------------------------------------------------------------------------------------------------
void ACogEngineReplicator::OnRep_TimeDilation()
{
#if !UE_BUILD_SHIPPING
UWorld* World = GetWorld();
if (World == nullptr)
return;
AWorldSettings* WorldSettings = World->GetWorldSettings();
if (WorldSettings == nullptr)
return;
WorldSettings->SetTimeDilation(TimeDilation);
#endif // !UE_BUILD_SHIPPING
}
@@ -0,0 +1,373 @@
#include "CogEngineWindow_Collisions.h"
#include "CogDebugDrawHelper.h"
#include "CogDebugSettings.h"
#include "CogImGuiHelper.h"
#include "Components/BoxComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/PrimitiveComponent.h"
#include "Components/SceneComponent.h"
#include "Components/SphereComponent.h"
#include "imgui.h"
#include "Kismet/GameplayStatics.h"
//--------------------------------------------------------------------------------------------------------------------------
UCogEngineWindow_Collisions::UCogEngineWindow_Collisions()
{
ObjectTypesToQuery = 0;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Collisions::SetCollisionsAsset(const UCogEngineDataAsset_Collisions* Asset)
{
if (Asset == nullptr)
{
return;
}
for (FChannel& Channel : Channels)
{
Channel.IsValid = false;
}
for (const FCogCollisionChannel& AssetChannel : Asset->Channels)
{
FChannel& Channel = Channels[(uint8)AssetChannel.Channel];
Channel.IsValid = true;
Channel.Color = AssetChannel.Color.ToFColor(true);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Collisions::RenderContent()
{
Super::RenderContent();
const APlayerController* PlayerController = GetLocalPlayerController();
if (PlayerController == nullptr)
{
return;
}
//-------------------------------------------------
// Query Profile
//-------------------------------------------------
const UCollisionProfile* CollisionProfile = UCollisionProfile::Get();
if (CollisionProfile == nullptr)
{
return;
}
const FCollisionResponseTemplate* SelectedProfile = CollisionProfile->GetProfileByIndex(ProfileIndex);
FName SelectedProfileName = SelectedProfile != nullptr ? SelectedProfile->Name : FName("Custom");
if (ImGui::BeginCombo("Profile", TCHAR_TO_ANSI(*SelectedProfileName.ToString()), ImGuiComboFlags_HeightLargest))
{
for (int i = 0; i < CollisionProfile->GetNumOfProfiles(); ++i)
{
const FCollisionResponseTemplate* Profile = CollisionProfile->GetProfileByIndex(i);
if (ImGui::Selectable(TCHAR_TO_ANSI(*Profile->Name.ToString()), false))
{
ProfileIndex = i;
ObjectTypesToQuery = 0;
SelectedProfile = CollisionProfile->GetProfileByIndex(ProfileIndex);
if (Profile->CollisionEnabled != ECollisionEnabled::NoCollision)
{
for (int j = 0; j < ECC_MAX; ++j)
{
ECollisionResponse Response = Profile->ResponseToChannels.GetResponse((ECollisionChannel)j);
if (Response != ECR_Ignore)
{
ObjectTypesToQuery |= ECC_TO_BITFIELD(j);
}
}
}
}
}
ImGui::EndCombo();
}
ImGui::Separator();
//-------------------------------------------------
// Query Filtering
//-------------------------------------------------
for (int ChannelIndex = 0; ChannelIndex < (int32)ECC_MAX; ++ChannelIndex)
{
ImGui::PushID(ChannelIndex);
const FChannel& Channel = Channels[ChannelIndex];
if (Channel.IsValid == false)
{
continue;
}
ImColor Color = FCogImguiHelper::ToImColor(Channel.Color);
ImGui::ColorEdit4("Color", (float*)&Color.Value, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel);
ImGui::SameLine();
bool IsCollisionActive = (ObjectTypesToQuery & ECC_TO_BITFIELD(ChannelIndex)) > 0;
const FName ChannelName = CollisionProfile->ReturnChannelNameFromContainerIndex(ChannelIndex);
if (ImGui::Checkbox(TCHAR_TO_ANSI(*ChannelName.ToString()), &IsCollisionActive))
{
if (IsCollisionActive)
{
ObjectTypesToQuery |= ECC_TO_BITFIELD(ChannelIndex);
ProfileIndex = INDEX_NONE;
}
else
{
ObjectTypesToQuery &= ~ECC_TO_BITFIELD(ChannelIndex);
ProfileIndex = INDEX_NONE;
}
}
ImGui::PopID();
}
ImGui::Separator();
//-------------------------------------------------
// Query Mode
//-------------------------------------------------
static int QueryType = 0;
ImGui::Combo("Query", &QueryType,
"Sphere\0"
"Raycast Crosshair\0"
"Raycast Cursor\0"
"\0"
);
//-------------------------------------------------
// Query Distance
//-------------------------------------------------
static float QueryDistance = 5000.0f;
ImGui::SliderFloat("Distance", &QueryDistance, 0.0f, 20000.0f, "%0.f");
//-------------------------------------------------
// Query Thickness
//-------------------------------------------------
static float QueryThickness = 0.0f;
if (QueryType == 1 || QueryType == 2)
{
ImGui::SliderFloat("Thickness", &QueryThickness, 0.0f, 1000.0f, "%0.f");
}
//-------------------------------------------------
// Query Use Complex Collisions
//-------------------------------------------------
static bool UseComplexCollisions = false;
ImGui::Checkbox("Use Complex Collisions", &UseComplexCollisions);
//-------------------------------------------------
// Show Names
//-------------------------------------------------
static bool ShowActorsNames = false;
ImGui::Checkbox("Show Actors Names", &ShowActorsNames);
//-------------------------------------------------
// Show Query
//-------------------------------------------------
static bool ShowQuery = false;
ImGui::Checkbox("Show Query", &ShowQuery);
//-------------------------------------------------
// Perform Query
//-------------------------------------------------
if (ObjectTypesToQuery == 0)
{
return;
}
UWorld* World = GetWorld();
FVector QueryStart;
FVector QueryEnd;
float QueryRadius = 0.0f;
switch (QueryType)
{
case 0:
{
FVector Location = FVector::ZeroVector;
if (APawn* Pawn = PlayerController->GetPawn())
{
Location = Pawn->GetActorLocation();
}
QueryRadius = QueryDistance;
QueryStart = Location;
QueryEnd = QueryStart;
break;
}
case 1:
{
FVector Location;
FRotator Rotation;
PlayerController->GetPlayerViewPoint(Location, Rotation);
QueryStart = Location;
QueryEnd = QueryStart + Rotation.Vector() * QueryDistance;
QueryRadius = QueryThickness;
break;
}
case 2:
{
FVector Direction;
UGameplayStatics::DeprojectScreenToWorld(PlayerController, FCogImguiHelper::ToVector2D(ImGui::GetMousePos()), QueryStart, Direction);
QueryEnd = QueryStart + Direction * QueryDistance;
QueryRadius = QueryThickness;
break;
}
}
static const FName TraceTag(TEXT("FCogWindow_Collision"));
FCollisionQueryParams QueryParams(TraceTag, SCENE_QUERY_STAT_ONLY(CogHitDetection), UseComplexCollisions);
FCollisionObjectQueryParams QueryObjectParams;
QueryObjectParams.ObjectTypesToQuery = ObjectTypesToQuery;
FCollisionShape QueryShape;
QueryShape.SetSphere(QueryRadius);
TArray<FHitResult> QueryHits;
World->SweepMultiByObjectType(
QueryHits,
QueryStart,
QueryEnd,
FQuat::Identity,
QueryObjectParams,
QueryShape,
QueryParams);
if (ShowQuery)
{
FCogDebugDrawHelper::DrawCapsuleCastMulti(World, QueryStart, QueryEnd, FQuat::Identity, 0.0f, QueryRadius, EDrawDebugTrace::ForOneFrame, false, QueryHits, FLinearColor::White, FLinearColor::Red, FCogDebugSettings::GetDebugDuration(true));
}
TSet<const AActor*> AlreadyDrawnActors;
TSet<const UPrimitiveComponent*> AlreadyDrawnComponents;
for (const FHitResult& HitResult : QueryHits)
{
//-------------------------------------------------------
// Don't draw same primitives multiple times (for bones)
//-------------------------------------------------------
const UPrimitiveComponent* PrimitiveComponent = HitResult.GetComponent();
if (AlreadyDrawnComponents.Contains(PrimitiveComponent))
{
continue;
}
AlreadyDrawnComponents.Add(PrimitiveComponent);
ECollisionChannel CollisionObjectType = PrimitiveComponent->GetCollisionObjectType();
FColor Color = Channels[CollisionObjectType].Color;
//-------------------------------------------------------
// Draw Name
//-------------------------------------------------------
if (ShowActorsNames)
{
const AActor* Actor = HitResult.GetActor();
if (Actor != nullptr)
{
if (AlreadyDrawnActors.Contains(Actor) == false)
{
FColor TextColor = Color.WithAlpha(255);
DrawDebugString(World, Actor->GetActorLocation(), GetNameSafe(Actor->GetClass()), nullptr, FColor::White, 0.0f, FCogDebugSettings::TextShadow, FCogDebugSettings::TextSize);
AlreadyDrawnActors.Add(Actor);
}
}
}
//-------------------------------------------------------
// Draw Shape
//-------------------------------------------------------
FCollisionShape Shape = PrimitiveComponent->GetCollisionShape();
switch (Shape.ShapeType)
{
case ECollisionShape::Box:
{
FVector Location;
FVector Extent;
FQuat Rotation;
if (const UBoxComponent* BoxComponent = Cast<UBoxComponent>(PrimitiveComponent))
{
Location = BoxComponent->GetComponentLocation();
Extent = BoxComponent->GetScaledBoxExtent();
Rotation = BoxComponent->GetComponentQuat();
}
else
{
PrimitiveComponent->Bounds.GetBox().GetCenterAndExtents(Location, Extent);
Extent += FVector::OneVector;
Rotation = FQuat::Identity;
}
DrawDebugSolidBox(
World,
Location,
Extent,
Rotation,
Color,
false,
0.0f,
FCogDebugSettings::GetDebugDepthPriority(0));
DrawDebugBox(
World,
Location,
Extent,
Rotation,
Color,
false,
0.0f,
FCogDebugSettings::GetDebugDepthPriority(0),
FCogDebugSettings::GetDebugThickness(0.0f));
break;
}
case ECollisionShape::Sphere:
{
if (const USphereComponent* SphereComponent = Cast<USphereComponent>(PrimitiveComponent))
{
FCogDebugDrawHelper::DrawSphere(
World,
SphereComponent->GetComponentLocation(),
SphereComponent->GetScaledSphereRadius(),
FCogDebugSettings::GetCircleSegments(),
Color,
false,
0.0f,
FCogDebugSettings::GetDebugDepthPriority(0),
FCogDebugSettings::GetDebugThickness(0.0f));
}
break;
}
case ECollisionShape::Capsule:
{
if (const UCapsuleComponent* CapsuleComponent = Cast<UCapsuleComponent>(PrimitiveComponent))
{
DrawDebugCapsule(World,
CapsuleComponent->GetComponentLocation(),
CapsuleComponent->GetScaledCapsuleHalfHeight(),
CapsuleComponent->GetScaledCapsuleRadius(),
CapsuleComponent->GetComponentQuat(),
Color,
false,
0.0f,
FCogDebugSettings::GetDebugDepthPriority(0),
FCogDebugSettings::GetDebugThickness(0.0f));
}
break;
}
}
}
}
@@ -0,0 +1,105 @@
#include "CogEngineWindow_DebugSettings.h"
#include "CogDebugSettings.h"
#include "CogWindowWidgets.h"
//--------------------------------------------------------------------------------------------------------------------------
UCogEngineWindow_DebugSettings::UCogEngineWindow_DebugSettings()
{
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_DebugSettings::PreRender(ImGuiWindowFlags& WindowFlags)
{
WindowFlags = ImGuiWindowFlags_MenuBar;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_DebugSettings::RenderContent()
{
Super::RenderContent();
if (ImGui::BeginMenuBar())
{
if (ImGui::MenuItem("Reset"))
{
FCogDebugSettings::Reset();
}
ImGui::EndMenuBar();
}
ImGui::Checkbox("Filter by selection", &FCogDebugSettings::FilterBySelection);
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("If checked, only show the debug of the currently selected actor. Otherwise show the debug of all actors.");
ImGui::Checkbox("Persistent", &FCogDebugSettings::Persistent);
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("Make debug draw always persist");
ImGui::Checkbox("Text Shadow", &FCogDebugSettings::TextShadow);
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("Show a shadow below debug text.");
const float ItemsWidth = FCogWindowWidgets::TextBaseWidth * 10;
ImGui::SetNextItemWidth(ItemsWidth);
ImGui::Checkbox("Fade 2D", &FCogDebugSettings::Fade2D);
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("Does the 2D debug is fading out.");
ImGui::SetNextItemWidth(ItemsWidth);
ImGui::DragFloat("Duration", &FCogDebugSettings::Duration, 0.01f, 0.0f, 100.0f, "%.1f");
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("The duration of debug elements.");
ImGui::SetNextItemWidth(ItemsWidth);
ImGui::DragFloat("Thickness", &FCogDebugSettings::Thickness, 0.05f, 0.0f, 5.0f, "%.1f");
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("The thickness of debug lines.");
ImGui::SetNextItemWidth(ItemsWidth);
ImGui::DragFloat("Server Thickness", &FCogDebugSettings::ServerThickness, 0.05f, 0.0f, 5.0f, "%.1f");
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("The thickness the server debug lines.");
ImGui::SetNextItemWidth(ItemsWidth);
ImGui::DragFloat("Server Color Mult", &FCogDebugSettings::ServerColorMultiplier, 0.01f, 0.0f, 1.0f, "%.1f");
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("The color multiplier applied to the server debug lines.");
ImGui::SetNextItemWidth(ItemsWidth);
ImGui::DragInt("Depth Priority", &FCogDebugSettings::DepthPriority, 0.1f, 0, 100);
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("The depth priority of debug elements.");
ImGui::SetNextItemWidth(ItemsWidth);
ImGui::DragInt("Segments", &FCogDebugSettings::Segments, 0.1f, 4, 20.0f);
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("The number of segments used for circular shapes.");
ImGui::SetNextItemWidth(ItemsWidth);
ImGui::DragFloat("Axes Scale", &FCogDebugSettings::AxesScale, 0.1f, 0, 10.0f, "%.1f");
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("The scaling debug axis.");
ImGui::SetNextItemWidth(ItemsWidth);
ImGui::DragFloat("Arrow Size", &FCogDebugSettings::ArrowSize, 1.0f, 0.0f, 200.0f, "%.0f");
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("The size of debug arrows.");
ImGui::SetNextItemWidth(ItemsWidth);
ImGui::DragFloat("Gradient Intensity", &FCogDebugSettings::GradientColorIntensity, 0.01f, 0.0f, 1.0f, "%.2f");
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("How much the debug elements color should be changed by a gradient color over time.");
ImGui::SetNextItemWidth(ItemsWidth);
ImGui::DragFloat("Gradient Speed", &FCogDebugSettings::GradientColorSpeed, 0.1f, 0.0f, 10.0f, "%.1f");
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("The speed of the gradient color change.");
ImGui::SetNextItemWidth(ItemsWidth);
ImGui::DragFloat("Text Size", &FCogDebugSettings::TextSize, 0.1f, 0.1f, 5.0f, "%.1f");
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("The size of the debug texts.");
}
@@ -0,0 +1,54 @@
#include "CogEngineWindow_ImGui.h"
#include "imgui.h"
#include "implot.h"
//--------------------------------------------------------------------------------------------------------------------------
UCogEngineWindow_ImGui::UCogEngineWindow_ImGui()
{
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_ImGui::RenderTick(float DeltaTime)
{
Super::RenderTick(DeltaTime);
if (bShowImguiDemo)
{
ImGui::ShowDemoWindow(&bShowImguiDemo);
}
if (bShowImguiMetric)
{
ImGui::ShowMetricsWindow(&bShowImguiMetric);
}
if (bShowImguiDebugLog)
{
ImGui::ShowDebugLogWindow(&bShowImguiDebugLog);
}
if (bShowImguiStyleEditor)
{
ImGui::Begin("Dear ImGui Style Editor", &bShowImguiStyleEditor);
ImGui::ShowStyleEditor();
ImGui::End();
}
if (bShowImguiPlot)
{
ImPlot::ShowDemoWindow(&bShowImguiPlot);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_ImGui::RenderContent()
{
Super::RenderContent();
ImGui::MenuItem("ImGui Demo", nullptr, &bShowImguiDemo);
ImGui::MenuItem("ImGui Metric", nullptr, &bShowImguiMetric);
ImGui::MenuItem("ImGui Debug Log", nullptr, &bShowImguiDebugLog);
ImGui::MenuItem("ImGui Style Editor", nullptr, &bShowImguiStyleEditor);
ImGui::MenuItem("Plot Demo", "", &bShowImguiPlot);
}
@@ -0,0 +1,207 @@
#include "CogEngineWindow_LogCategories.h"
#include "CogDebugHelper.h"
#include "CogWindowWidgets.h"
#include "CogDebugLogCategoryManager.h"
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_LogCategories::PreRender(ImGuiWindowFlags& WindowFlags)
{
WindowFlags = ImGuiWindowFlags_MenuBar;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_LogCategories::RenderContent()
{
Super::RenderContent();
UWorld* World = GetWorld();
if (World == nullptr)
{
return;
}
static bool bShowAllVerbosity = false;
if (ImGui::BeginMenuBar())
{
if (ImGui::BeginMenu("Options"))
{
ImGui::Checkbox("Show detailed verbosity", &bShowAllVerbosity);
ImGui::SameLine();
FCogWindowWidgets::HelpMarker("Show the verbosity level of each log category.");
ImGui::EndMenu();
}
if (ImGui::MenuItem("Reset"))
{
FCogDebugLogCategoryManager::DeactivateAllLogCateories(*World);
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Deactivate all the log categories");
}
if (ImGui::MenuItem("Flush"))
{
FlushPersistentDebugLines(World);
FlushDebugStrings(GWorld);
GEngine->ClearOnScreenDebugMessages();
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Clear all the debug drawn on screen");
}
ImGui::EndMenuBar();
}
const bool IsClient = World->GetNetMode() == NM_Client;
ImGuiStyle& Style = ImGui::GetStyle();
int Index = 0;
for (const auto& Entry : FCogDebugLogCategoryManager::GetLogCategories())
{
FName CategoryName = Entry.Key;
const FCogDebugLogCategoryInfo& CategoryInfo = Entry.Value;
FLogCategoryBase* Category = CategoryInfo.LogCategory;
ImGui::PushID(Index);
FString CategoryFriendlyName = Category->GetCategoryName().ToString();
if (bShowAllVerbosity == false)
{
const bool IsControlDown = ImGui::GetIO().KeyCtrl;
if (IsClient)
{
ELogVerbosity::Type Verbosity = FCogDebugLogCategoryManager::GetServerVerbosity(CategoryName);
bool IsActive = FCogDebugLogCategoryManager::IsVerbosityActive(Verbosity);
if (Verbosity == ELogVerbosity::VeryVerbose)
{
ImGui::PushStyleColor(ImGuiCol_CheckMark, IM_COL32(255, 0, 0, 200));
}
if (ImGui::Checkbox("##Server", &IsActive))
{
ELogVerbosity::Type NewVerbosity = IsActive ? (IsControlDown ? ELogVerbosity::VeryVerbose : ELogVerbosity::Verbose) : ELogVerbosity::Warning;
FCogDebugLogCategoryManager::SetServerVerbosity(CategoryName, NewVerbosity);
}
if (Verbosity == ELogVerbosity::VeryVerbose)
{
ImGui::PopStyleColor(1);
}
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Server");
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsControlDown ? 1.0f : 0.5f), "Very Verbose [CTRL]");
ImGui::EndTooltip();
}
ImGui::SameLine();
}
{
ELogVerbosity::Type Verbosity = Category->GetVerbosity();
bool IsActive = FCogDebugLogCategoryManager::IsVerbosityActive(Verbosity);
if (Verbosity == ELogVerbosity::VeryVerbose)
{
ImGui::PushStyleColor(ImGuiCol_CheckMark, IM_COL32(255, 0, 0, 200));
}
if (ImGui::Checkbox(TCHAR_TO_ANSI(*CategoryFriendlyName), &IsActive))
{
ELogVerbosity::Type NewVerbosity = IsActive ? (IsControlDown ? ELogVerbosity::VeryVerbose : ELogVerbosity::Verbose) : ELogVerbosity::Warning;
Category->SetVerbosity(NewVerbosity);
}
if (Verbosity == ELogVerbosity::VeryVerbose)
{
ImGui::PopStyleColor(1);
}
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
if (IsClient)
{
ImGui::Text("Local Client");
}
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, IsControlDown ? 1.0f : 0.5f), "Very Verbose [CTRL]");
ImGui::EndTooltip();
}
}
}
else
{
if (IsClient)
{
ELogVerbosity::Type CurrentVerbosity = FCogDebugLogCategoryManager::GetServerVerbosity(CategoryName);
ImGui::SetNextItemWidth(FCogWindowWidgets::TextBaseWidth * 12);
if (ImGui::BeginCombo("##Server", FCogDebugHelper::VerbosityToString(CurrentVerbosity)))
{
for (int32 i = (int32)ELogVerbosity::Error; i <= (int32)ELogVerbosity::VeryVerbose; ++i)
{
bool IsSelected = i == (int32)CurrentVerbosity;
ELogVerbosity::Type Verbosity = (ELogVerbosity::Type)i;
if (ImGui::Selectable(FCogDebugHelper::VerbosityToString(Verbosity), IsSelected))
{
FCogDebugLogCategoryManager::SetServerVerbosity(CategoryName, Verbosity);
}
}
ImGui::EndCombo();
}
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Server");
ImGui::EndTooltip();
}
ImGui::SameLine();
}
{
ELogVerbosity::Type CurrentVerbosity = Category->GetVerbosity();
ImGui::SetNextItemWidth(FCogWindowWidgets::TextBaseWidth * 12);
if (ImGui::BeginCombo("##Local", FCogDebugHelper::VerbosityToString(CurrentVerbosity)))
{
for (int32 i = (int32)ELogVerbosity::Error; i <= (int32)ELogVerbosity::VeryVerbose; ++i)
{
bool IsSelected = i == (int32)CurrentVerbosity;
ELogVerbosity::Type Verbosity = (ELogVerbosity::Type)i;
if (ImGui::Selectable(FCogDebugHelper::VerbosityToString(Verbosity), IsSelected))
{
Category->SetVerbosity(Verbosity);
}
}
ImGui::EndCombo();
}
if (IsClient && ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Local Client");
ImGui::EndTooltip();
}
}
ImGui::SameLine();
ImGui::Text("%s", TCHAR_TO_ANSI(*CategoryFriendlyName));
}
ImGui::PopID();
Index++;
}
}
@@ -0,0 +1,201 @@
#include "CogEngineWindow_NetEmulation.h"
#include "CogEngineWindow_Stats.h"
#include "Engine/Engine.h"
#include "Engine/NetDriver.h"
#include "Engine/NetConnection.h"
#include "Engine/World.h"
#include "GameFramework/PlayerState.h"
//--------------------------------------------------------------------------------------------------------------------------
void DrawControls(UWorld* World)
{
FWorldContext& WorldContext = GEngine->GetWorldContextFromWorldChecked(World);
if (WorldContext.ActiveNetDrivers.Num() == 0)
{
return;
}
static int32 SelectedIndex = 0;
if (SelectedIndex >= WorldContext.ActiveNetDrivers.Num())
{
SelectedIndex = 0;
}
FNamedNetDriver* SelectedNetDriver = &WorldContext.ActiveNetDrivers[SelectedIndex];
if (SelectedNetDriver == nullptr)
{
return;
}
if (ImGui::BeginCombo("Driver", TCHAR_TO_ANSI(*SelectedNetDriver->NetDriver->GetName())))
{
int i = 0;
for (FNamedNetDriver& NamedNetDriver : WorldContext.ActiveNetDrivers)
{
if (NamedNetDriver.NetDriver != nullptr)
{
if (ImGui::Selectable(TCHAR_TO_ANSI(*NamedNetDriver.NetDriver->GetName())))
{
SelectedIndex = i;
SelectedNetDriver = &WorldContext.ActiveNetDrivers[i];
}
}
i++;
}
ImGui::EndCombo();
}
ImGui::Separator();
if (SelectedNetDriver == nullptr)
{
return;
}
#if DO_ENABLE_NET_TEST
FPacketSimulationSettings Settings = SelectedNetDriver->NetDriver->PacketSimulationSettings;
//-------------------------------------------------------------------------------------------
if (ImGui::DragInt("Lag Min", &Settings.PktLagMin, 1.0f, 0, INT_MAX, "%d ms"))
{
SelectedNetDriver->NetDriver->SetPacketSimulationSettings(Settings);
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip(
"If set lag values will randomly fluctuate between Min and Max.");
}
//-------------------------------------------------------------------------------------------
if (ImGui::DragInt("Lag Max", &Settings.PktLagMax, 1.0f, 0, INT_MAX, "%d ms"))
{
SelectedNetDriver->NetDriver->SetPacketSimulationSettings(Settings);
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip(
"If set lag values will randomly fluctuate between Min and Max.");
}
if (ImGui::SliderInt("Packet Loss", &Settings.PktLoss, 0, 100, "%d%%"))
{
SelectedNetDriver->NetDriver->SetPacketSimulationSettings(Settings);
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip(
"When set, will cause calls to FlushNet to drop packets.\n"
"Value is treated as %% of packets dropped (i.e. 0 = None, 100 = All).\n"
"No general pattern / ordering is guaranteed.\n"
"Clamped between 0 and 100.\n"
"Works with all other settings.");
}
//-------------------------------------------------------------------------------------------
if (ImGui::SliderInt("Packet Order", &Settings.PktOrder, 0, 100, "%d%%"))
{
SelectedNetDriver->NetDriver->SetPacketSimulationSettings(Settings);
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip(
"When set, will cause calls to FlushNet to change ordering of packets at random.\n"
"Value is treated as a bool(i.e. 0 = False, anything else = True). \n"
"This works by randomly selecting packets to be delayed until a subsequent call to FlushNet.\n"
"Takes precedence over PktDup and PktLag.");
}
//-------------------------------------------------------------------------------------------
if (ImGui::SliderInt("Packet Dup", &Settings.PktDup, 0, 100, "%d%%"))
{
SelectedNetDriver->NetDriver->SetPacketSimulationSettings(Settings);
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip(
"When set, will cause calls to FlushNet to duplicate packets.\n"
"Value is treated as %% of packets duplicated(i.e. 0 = None, 100 = All).\n"
"No general pattern / ordering is guaranteed.\n"
"Clamped between 0 and 100.\n"
"Cannot be used with PktOrder or PktLag.");
}
ImGui::Separator();
//-------------------------------------------------------------------------------------------
if (ImGui::DragInt("Incoming Lag Min", &Settings.PktIncomingLagMin, 1.0f, 0, INT_MAX, "%d ms"))
{
SelectedNetDriver->NetDriver->SetPacketSimulationSettings(Settings);
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip(
"The minimum delay in milliseconds to incoming packets before they are processed");
}
//-------------------------------------------------------------------------------------------
if (ImGui::DragInt("Incoming Lag Max", &Settings.PktIncomingLagMax, 1.0f, 0, INT_MAX, "%d ms"))
{
SelectedNetDriver->NetDriver->SetPacketSimulationSettings(Settings);
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip(
"The maximum delay in milliseconds to add to incoming packets before they are processed");
}
//-------------------------------------------------------------------------------------------
if (ImGui::SliderInt("Incoming Packet Loss", &Settings.PktIncomingLoss, 0, 100, "%d%%"))
{
SelectedNetDriver->NetDriver->SetPacketSimulationSettings(Settings);
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip(
"The ratio of incoming packets that will be dropped to simulate packet loss");
}
#endif //DO_ENABLE_NET_TEST
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_NetEmulation::RenderContent()
{
Super::RenderContent();
const APlayerController* PlayerController = GetLocalPlayerController();
if (PlayerController == nullptr)
{
return;
}
if (const APlayerState* PlayerState = PlayerController->GetPlayerState<APlayerState>())
{
const float Ping = PlayerState->GetPingInMilliseconds();
ImGui::Text("Ping ");
ImGui::SameLine();
ImGui::TextColored(UCogEngineWindow_Stats::GetPingColor(Ping), "%0.0fms", Ping);
}
if (UNetConnection* Connection = PlayerController->GetNetConnection())
{
const float OutPacketLost = Connection->GetOutLossPercentage().GetAvgLossPercentage() * 100.0f;
ImGui::Text("Packet Loss Out ");
ImGui::SameLine();
ImGui::TextColored(UCogEngineWindow_Stats::GetPacketLossColor(OutPacketLost), "%0.0f%%", OutPacketLost);
const float InPacketLost = Connection->GetInLossPercentage().GetAvgLossPercentage() * 100.0f;
ImGui::Text("Packet Loss In ");
ImGui::SameLine();
ImGui::TextColored(UCogEngineWindow_Stats::GetPacketLossColor(InPacketLost), "%0.0f%%", InPacketLost);
}
ImGui::Separator();
DrawControls(GetWorld());
}
@@ -0,0 +1,307 @@
#include "CogEngineWindow_OutputLog.h"
#include "CogDebugHelper.h"
#include "Engine/Engine.h"
#include "Misc/StringBuilder.h"
char ImGuiTextBuffer::EmptyString[1] = { 0 };
//--------------------------------------------------------------------------------------------------------------------------
// FCogLogOutputDevice
//--------------------------------------------------------------------------------------------------------------------------
UCogLogOutputDevice::UCogLogOutputDevice()
{
GLog->AddOutputDevice(this);
}
//--------------------------------------------------------------------------------------------------------------------------
UCogLogOutputDevice::~UCogLogOutputDevice()
{
if (GLog != nullptr)
{
GLog->RemoveOutputDevice(this);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogLogOutputDevice::Serialize(const TCHAR* Message, ELogVerbosity::Type Verbosity, const class FName& Category)
{
if (OutputLog != nullptr)
{
OutputLog->AddLog(Message, Verbosity, Category);
}
}
//--------------------------------------------------------------------------------------------------------------------------
// FCogWindow_Log
//--------------------------------------------------------------------------------------------------------------------------
UCogEngineWindow_OutputLog::UCogEngineWindow_OutputLog()
{
OutputDevice.OutputLog = this;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_OutputLog::Clear()
{
TextBuffer.clear();
LineInfos.Empty();
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_OutputLog::AddLog(const TCHAR* Message, ELogVerbosity::Type Verbosity, const class FName& Category)
{
static TAnsiStringBuilder<512> Format;
Format.Reset();
if (Message)
{
Format.Append(Message);
}
FLineInfo& LineInfo = LineInfos.AddDefaulted_GetRef();
LineInfo.Frame = GFrameCounter % 1000;
LineInfo.Verbosity = Verbosity;
LineInfo.Category = Category;
LineInfo.Start = TextBuffer.size();
TextBuffer.append(Format.GetData(), Format.GetData() + Format.Len());
LineInfo.End = TextBuffer.size();
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_OutputLog::DrawRow(const char* BufferStart, const FLineInfo& LineInfo, bool IsTableShown)
{
ImU32 Color;
switch (LineInfo.Verbosity)
{
case ELogVerbosity::Error: Color = IM_COL32(255, 0, 0, 255); break;
case ELogVerbosity::Warning: Color = IM_COL32(255, 200, 0, 255); break;
default: Color = IM_COL32(200, 200, 200, 255); break;
}
ImGui::PushStyleColor(ImGuiCol_Text, Color);
if (IsTableShown)
{
ImGui::TableNextRow();
if (ShowFrame)
{
ImGui::TableNextColumn();
ImGui::Text("%3d", LineInfo.Frame);
}
if (ShowCategory)
{
ImGui::TableNextColumn();
ImGui::Text("%s", TCHAR_TO_ANSI(*LineInfo.Category.ToString()));
}
if (ShowVerbosity)
{
ImGui::TableNextColumn();
ImGui::Text("%s", TCHAR_TO_ANSI(ToString(LineInfo.Verbosity)));
}
ImGui::TableNextColumn();
const char* LineStart = BufferStart + LineInfo.Start;
const char* LineEnd = BufferStart + LineInfo.End;
ImGui::TextUnformatted(LineStart, LineEnd);
}
else
{
if (ShowFrame)
{
ImGui::Text("[%3d] ", LineInfo.Frame);
ImGui::SameLine();
}
if (ShowCategory)
{
ImGui::Text("%s: ", TCHAR_TO_ANSI(*LineInfo.Category.ToString()));
ImGui::SameLine();
}
if (ShowVerbosity)
{
ImGui::Text("%s: ", TCHAR_TO_ANSI(ToString(LineInfo.Verbosity)));
ImGui::SameLine();
}
const char* LineStart = BufferStart + LineInfo.Start;
const char* LineEnd = BufferStart + LineInfo.End;
ImGui::TextUnformatted(LineStart, LineEnd);
}
ImGui::PopStyleColor();
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_OutputLog::PreRender(ImGuiWindowFlags& WindowFlags)
{
WindowFlags = ImGuiWindowFlags_MenuBar;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_OutputLog::RenderContent()
{
Super::RenderContent();
bool ClearPressed = false;
bool CopyPressed = false;
if (ImGui::BeginMenuBar())
{
if (ImGui::BeginMenu("Options"))
{
if (ImGui::MenuItem("Copy"))
{
ImGui::LogToClipboard();
}
ImGui::Separator();
ImGui::Checkbox("Auto Scroll", &AutoScroll);
ImGui::Checkbox("Show Frame", &ShowFrame);
ImGui::Checkbox("Show Category", &ShowCategory);
ImGui::Checkbox("Show Verbosity", &ShowVerbosity);
ImGui::Checkbox("Show As Table", &ShowAsTable);
//if (ImGui::SmallButton("Add Log"))
//{
// AddLog(TEXT("ABCD"), ELogVerbosity::Verbose, FName("Test"));
// AddLog(TEXT("EFGH"), ELogVerbosity::Warning, FName("Test"));
// AddLog(TEXT("WXYZ"), ELogVerbosity::Error, FName("Test"));
//}
ImGui::EndMenu();
}
ImGui::SameLine();
if (ImGui::MenuItem("Clear"))
{
Clear();
}
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 9);
if (ImGui::BeginCombo("##Verbosity", FCogDebugHelper::VerbosityToString((ELogVerbosity::Type)VerbosityFilter)))
{
for (int32 i = (int32)ELogVerbosity::Error; i <= (int32)ELogVerbosity::VeryVerbose; ++i)
{
bool IsSelected = i == VerbosityFilter;
ELogVerbosity::Type Verbosity = (ELogVerbosity::Type)i;
if (ImGui::Selectable(FCogDebugHelper::VerbosityToString(Verbosity), IsSelected))
{
VerbosityFilter = i;
}
}
ImGui::EndCombo();
}
FCogWindowWidgets::MenuSearchBar(Filter);
ImGui::EndMenuBar();
}
int32 ColumnCount = 1;
ColumnCount += (int32)ShowFrame;
ColumnCount += (int32)ShowCategory;
ColumnCount += (int32)ShowVerbosity;
bool IsTableShown = false;
if (ShowAsTable)
{
if (ImGui::BeginTable("LogTable", ColumnCount, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ScrollX))
{
IsTableShown = true;
if (ShowFrame)
{
ImGui::TableSetupColumn("Frame", ImGuiTableColumnFlags_WidthFixed, FCogWindowWidgets::TextBaseWidth * 4);
}
if (ShowCategory)
{
ImGui::TableSetupColumn("Category", ImGuiTableColumnFlags_WidthFixed, FCogWindowWidgets::TextBaseWidth * 10);
}
if (ShowVerbosity)
{
ImGui::TableSetupColumn("Verbosity", ImGuiTableColumnFlags_WidthFixed, FCogWindowWidgets::TextBaseWidth * 10);
}
ImGui::TableSetupColumn("Message", ImGuiTableColumnFlags_WidthStretch);
}
}
if (IsTableShown == false)
{
ImGui::BeginChild("Scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_AlwaysVerticalScrollbar);
}
const char* BufferStart = TextBuffer.begin();
if (Filter.IsActive())
{
for (int32 LineIndex = 0; LineIndex < LineInfos.Num(); LineIndex++)
{
const FLineInfo& LineInfo = LineInfos[LineIndex];
const char* LineStart = BufferStart + LineInfo.Start;
const char* LineEnd = BufferStart + LineInfo.End;
if (Filter.PassFilter(LineStart, LineEnd))
{
DrawRow(BufferStart, LineInfo, IsTableShown);
}
}
}
else if (VerbosityFilter != ELogVerbosity::VeryVerbose)
{
for (int32 LineIndex = 0; LineIndex < LineInfos.Num(); LineIndex++)
{
const FLineInfo& LineInfo = LineInfos[LineIndex];
if (LineInfo.Verbosity <= (ELogVerbosity::Type)VerbosityFilter)
{
const char* LineStart = BufferStart + LineInfo.Start;
const char* LineEnd = BufferStart + LineInfo.End;
DrawRow(BufferStart, LineInfo, IsTableShown);
}
}
}
else
{
ImGuiListClipper Clipper;
Clipper.Begin(LineInfos.Num());
while (Clipper.Step())
{
for (int32 LineIndex = Clipper.DisplayStart; LineIndex < Clipper.DisplayEnd; LineIndex++)
{
if (LineInfos.IsValidIndex(LineIndex))
{
const FLineInfo& LineInfo = LineInfos[LineIndex];
DrawRow(BufferStart, LineInfo, IsTableShown);
}
}
}
Clipper.End();
}
if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
{
ImGui::SetScrollHereY(1.0f);
}
if (IsTableShown)
{
ImGui::EndTable();
}
else
{
ImGui::EndChild();
}
}
@@ -0,0 +1,477 @@
#include "CogEngineWindow_Plots.h"
#include "CogImGuiHelper.h"
#include "CogDebugPlot.h"
#include "CogWindowWidgets.h"
#include "imgui.h"
#include "implot_internal.h"
#include "Kismet/GameplayStatics.h"
//--------------------------------------------------------------------------------------------------------------------------
UCogEngineWindow_Plots::UCogEngineWindow_Plots()
{
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Plots::RenderTick(float DeltaTime)
{
Super::RenderTick(DeltaTime);
FCogDebugPlot::IsVisible = GetIsVisible();
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Plots::RenderContent()
{
Super::RenderContent();
static int Rows = 1;
static int Cols = 1;
if (ImGui::BeginTable("PlotTable", 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable))
{
ImGui::TableSetupColumn("Settings", ImGuiTableColumnFlags_WidthFixed, FCogWindowWidgets::TextBaseWidth * 20.0f);
ImGui::TableSetupColumn("Graph", ImGuiTableColumnFlags_WidthStretch, 0.0f);
ImGui::TableNextRow();
//--------------------------------------------------------------------------------------
// Settings and Entries
//--------------------------------------------------------------------------------------
ImGui::TableNextColumn();
if (ImGui::Button("Settings"))
{
ImGui::OpenPopup("SettingsPopup");
}
ImGui::SameLine();
FCogWindowWidgets::ToggleButton(&FCogDebugPlot::Pause, "Pause", "Pause", ImVec4(1.0f, 0.0f, 0.0f, 1.0f), ImVec4(0.5f, 0.5f, 0.5f, 1.0f));
if (ImGui::BeginPopup("SettingsPopup"))
{
ImGui::SliderInt("Rows", &Rows, 1, 5);
if (ImGui::Button("Clear Data", ImVec2(-1, 0)))
{
FCogDebugPlot::Clear();
}
if (ImGui::Button("Reset Layout", ImVec2(-1, 0)))
{
FCogDebugPlot::Pause = false;
Rows = 1;
FCogDebugPlot::Reset();
}
ImGui::EndPopup();
}
if (ImGui::BeginChild("Separator", ImVec2(0, 2)))
{
ImGui::Separator();
}
ImGui::EndChild();
TArray<FCogDebugPlotEntry*> VisiblePlots;
if (ImGui::BeginChild("Plots", ImVec2(0, -1)))
{
int Index = 0;
for (FCogDebugPlotEntry& Plot : FCogDebugPlot::Plots)
{
const auto Label = StringCast<ANSICHAR>(*Plot.Name.ToString());
if (Plot.CurrentYAxis != ImAxis_COUNT && Plot.CurrentRow != INDEX_NONE)
{
VisiblePlots.Add(&Plot);
}
ImGui::PushID(Index);
ImGui::PushStyleColor(ImGuiCol_Text, Plot.IsEventPlot ? IM_COL32(128, 128, 255, 255) : IM_COL32(255, 255, 255, 255));
ImGui::Selectable(Label.Get(), false, 0);
ImGui::PopStyleColor();
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
{
ImGui::SetDragDropPayload("DragAndDrop", Label.Get(), Label.Length() + 1);
ImGui::TextUnformatted(Label.Get());
ImGui::EndDragDropSource();
}
ImGui::PopID();
Index++;
}
}
ImGui::EndChild();
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
{
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
{
Plot->ResetAxis();
}
}
ImGui::EndDragDropTarget();
}
//--------------------------------------------------------------------------------------
// Graph
//--------------------------------------------------------------------------------------
ImGui::TableNextColumn();
if (ImGui::BeginChild("Graph", ImVec2(0, -1)))
{
static float RowRatios[] = { 1, 1, 1, 1, 1, 1 };
static float ColRatios[] = { 1 };
static ImPlotSubplotFlags SubplotsFlags = ImPlotSubplotFlags_LinkCols;
if (ImPlot::BeginSubplots("", Rows, Cols, ImVec2(-1, -1), SubplotsFlags, RowRatios, ColRatios))
{
for (int PlotIndex = 0; PlotIndex < Rows; ++PlotIndex)
{
if (ImPlot::BeginPlot("##Plot", ImVec2(-1, 250)))
{
ImPlotAxisFlags HasPlotOnAxisY1 = false;
ImPlotAxisFlags HasPlotOnAxisY2 = false;
ImPlotAxisFlags HasPlotOnAxisY3 = false;
for (FCogDebugPlotEntry* PlotPtr : VisiblePlots)
{
HasPlotOnAxisY1 |= PlotPtr->CurrentYAxis == ImAxis_Y1 && PlotPtr->CurrentRow == PlotIndex;
HasPlotOnAxisY2 |= PlotPtr->CurrentYAxis == ImAxis_Y2 && PlotPtr->CurrentRow == PlotIndex;
HasPlotOnAxisY3 |= PlotPtr->CurrentYAxis == ImAxis_Y3 && PlotPtr->CurrentRow == PlotIndex;
}
ImPlot::SetupAxis(ImAxis_X1, NULL, ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines);
ImPlot::SetupAxis(ImAxis_Y1, HasPlotOnAxisY1 ? "" : "[drop here]", (HasPlotOnAxisY1 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit);
ImPlot::SetupAxis(ImAxis_Y2, HasPlotOnAxisY2 ? "" : "[drop here]", (HasPlotOnAxisY2 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_Opposite);
ImPlot::SetupAxis(ImAxis_Y3, HasPlotOnAxisY3 ? "" : "[drop here]", (HasPlotOnAxisY3 ? ImPlotAxisFlags_None : (ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines)) | ImPlotAxisFlags_AutoFit | ImPlotAxisFlags_Opposite);
//--------------------------------------------------------------------------------------------------
// Set the initial X axis range. After it is automatically updated to move with the current time.
//--------------------------------------------------------------------------------------------------
ImPlot::SetupAxisLimits(ImAxis_X1, 0, 10.0f, ImGuiCond_Appearing);
const ImPlotRange& Range = ImPlot::GetCurrentPlot()->Axes[ImAxis_X1].Range;
const float AxisXRange = Range.Max - Range.Min;
//----------------------------------------------------------------
// Draw a vertical lines representing the current time and the mouse time
//----------------------------------------------------------------
ImDrawList* PlotDrawList = ImPlot::GetPlotDrawList();
const ImVec2 PlotMin = ImPlot::GetPlotPos();
const ImVec2 PlotSize = ImPlot::GetPlotSize();
const ImVec2 PlotMax = ImVec2(PlotMin.x + PlotSize.x, PlotMin.y + PlotSize.y);
const float PlotTop = PlotMin.y;
const float TimeBarBottom = PlotTop + PlotSize.y;
ImPlot::PushPlotClipRect();
PlotDrawList->AddLine(ImVec2(ImGui::GetMousePos().x, PlotTop), ImVec2(ImGui::GetMousePos().x, TimeBarBottom), IM_COL32(128, 128, 128, 64));
if (FCogDebugPlot::Pause)
{
const float Time = GetWorld() ? GetWorld()->GetTimeSeconds() : 0.0;
const float TimeBarX = ImPlot::PlotToPixels(Time, 0.0f).x;
PlotDrawList->AddLine(ImVec2(TimeBarX, PlotTop), ImVec2(TimeBarX, TimeBarBottom), IM_COL32(255, 255, 255, 64));
}
ImPlot::PopPlotClipRect();
for (FCogDebugPlotEntry* PlotPtr : VisiblePlots)
{
if (PlotPtr == nullptr)
{
continue;
}
FCogDebugPlotEntry& Entry = *PlotPtr;
if (Entry.CurrentRow == PlotIndex)
{
//--------------------------------------------------------------------------------
// Make the time axis move forward automatically, unless the user pauses or zoom.
//--------------------------------------------------------------------------------
if (FCogDebugPlot::Pause == false && ImGui::GetIO().MouseWheel == 0)
{
ImPlot::SetupAxisLimits(ImAxis_X1, Entry.Time - AxisXRange, Entry.Time, ImGuiCond_Always);
}
ImPlot::SetAxis(Entry.CurrentYAxis);
ImPlot::SetNextLineStyle(IMPLOT_AUTO_COL);
const auto Label = StringCast<ANSICHAR>(*Entry.Name.ToString());
//----------------------------------------------------------------
// Pause the scrolling if the user drag inside
//----------------------------------------------------------------
ImVec2 Mouse = ImGui::GetMousePos();
if (Mouse.x > PlotMin.x
&& Mouse.y > PlotMin.y
&& Mouse.x < PlotMax.x
&& Mouse.y < PlotMax.y
&& ImGui::GetDragDropPayload() == nullptr)
{
ImVec2 Drag = ImGui::GetMouseDragDelta(0);
if (FMath::Abs(Drag.x) > 10)
{
FCogDebugPlot::Pause = true;
}
}
//-------------------------------------------------------
// Plot Events
//-------------------------------------------------------
const bool IsEventPlot = Entry.Events.Num() > 0;
if (IsEventPlot)
{
//--------------------------------------------------------------------
// Update plot time for events as events are not pushed every frames
//--------------------------------------------------------------------
Entry.UpdateTime(GetWorld());
ImPlot::SetupAxisLimits(Entry.CurrentYAxis, 0, Entry.MaxRow + 2, ImGuiCond_Always);
ImPlot::PushPlotClipRect();
//----------------------------------------------------------------
// Plot line only to make the plotter move in time and auto scale
//----------------------------------------------------------------
ImVector<ImVec2> DummyData;
DummyData.push_back(ImVec2(0, 0));
DummyData.push_back(ImVec2(0, 8));
ImPlot::PlotLine(Label.Get(), &DummyData[0].x, &DummyData[0].y, DummyData.size(), Entry.ValueOffset, 2 * sizeof(float));
const FCogDebugPlotEvent* HoveredEvent = nullptr;
for (const FCogDebugPlotEvent& Event : Entry.Events)
{
const ImVec2 PosBot = ImPlot::PlotToPixels(ImPlotPoint(Event.StartTime, Event.Row + 0.8f));
const ImVec2 PosTop = ImPlot::PlotToPixels(ImPlotPoint(Event.StartTime, Event.Row + 0.2f));
const ImVec2 PosMid(PosBot.x, PosBot.y + (PosTop.y - PosBot.y) * 0.5f);
const bool IsInstant = Event.StartTime == Event.EndTime;
if (IsInstant)
{
const float Radius = 10.0f;
PlotDrawList->AddNgon(PosMid, 10, Event.BorderColor, 4);
PlotDrawList->AddNgonFilled(PosMid, 10, Event.FillColor, 4);
PlotDrawList->AddText(ImVec2(PosMid.x + 15, PosMid.y - 6), IM_COL32(255, 255, 255, 255), TCHAR_TO_ANSI(*Event.DisplayName));
if ((Mouse.x > PosMid.x - Radius) && (Mouse.x < PosMid.x + Radius) && (Mouse.y > PosMid.y - Radius) && (Mouse.y < PosMid.y + Radius))
{
HoveredEvent = &Event;
}
}
else
{
const float ActualEndTime = Event.GetActualEndTime(Entry);
const ImVec2 PosEnd = ImPlot::PlotToPixels(ImPlotPoint(ActualEndTime, 0));
const ImVec2 Min = ImVec2(PosBot.x, PosBot.y);
const ImVec2 Max = ImVec2(PosEnd.x, PosTop.y);
ImDrawFlags Flags = Event.EndTime == 0.0f ? ImDrawFlags_RoundCornersLeft : ImDrawFlags_RoundCornersAll;
PlotDrawList->AddRect(Min, Max, Event.BorderColor, 6.0f, Flags);
PlotDrawList->AddRectFilled(Min, Max, Event.FillColor, 6.0f, Flags);
PlotDrawList->PushClipRect(ImMax(Min, PlotMin), ImMin(Max, PlotMax));
PlotDrawList->AddText(ImVec2(PosMid.x + 5, PosMid.y - 7), IM_COL32(255, 255, 255, 255), TCHAR_TO_ANSI(*Event.DisplayName));
PlotDrawList->PopClipRect();
if (Mouse.x > Min.x && Mouse.x < Max.x && Mouse.y > Min.y && Mouse.y < Max.y)
{
HoveredEvent = &Event;
}
}
}
//-------------------------------------------------------
// Write info on the graph to help debugging
//-------------------------------------------------------
//char Buffer[64];
//ImFormatString(Buffer, 64, "%0.1f %0.1f", Mouse.x, Mouse.y);
//PlotDrawList->AddText(ImVec2(PlotMin.x + 50, PlotMin.y + 100), IM_COL32(255, 255, 255, 255), Buffer);
//-------------------------------------------------------
// Hovered event tooltip
//-------------------------------------------------------
if (ImPlot::IsPlotHovered() && HoveredEvent != nullptr)
{
FCogWindowWidgets::BeginTableTooltip();
if (ImGui::BeginTable("Params", 2, ImGuiTableFlags_Borders))
{
//------------------------
// Event Name
//------------------------
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Name");
ImGui::TableNextColumn();
ImGui::Text("%s", TCHAR_TO_ANSI(*HoveredEvent->DisplayName));
//------------------------
// Owner Name
//------------------------
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Owner");
ImGui::TableNextColumn();
ImGui::Text("%s", TCHAR_TO_ANSI(*HoveredEvent->OwnerName));
//------------------------
// Times
//------------------------
if (HoveredEvent->EndTime != HoveredEvent->StartTime)
{
const float ActualEndTime = HoveredEvent->GetActualEndTime(Entry);
const uint64 ActualEndFrame = HoveredEvent->GetActualEndFrame(Entry);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Duration");
ImGui::TableNextColumn();
ImGui::Text("%0.2fs", ActualEndTime - HoveredEvent->StartTime);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Frames");
ImGui::TableNextColumn();
ImGui::Text("%d [%d-%d]",
(int32)(ActualEndFrame - HoveredEvent->StartFrame),
(int32)(HoveredEvent->StartFrame % 1000),
(int32)(ActualEndFrame % 1000));
}
else
{
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Frame");
ImGui::TableNextColumn();
ImGui::Text("%d", (int32)(HoveredEvent->StartFrame % 1000));
}
//------------------------
// Params
//------------------------
for (FCogDebugPlotEventParams Param : HoveredEvent->Params)
{
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%s", TCHAR_TO_ANSI(*Param.Name.ToString()));
ImGui::TableNextColumn();
ImGui::Text("%s", TCHAR_TO_ANSI(*Param.Value));
}
ImGui::EndTable();
}
FCogWindowWidgets::EndTableTooltip();
}
ImPlot::PopPlotClipRect();
}
//-------------------------------------------------------
// Plot Values
//-------------------------------------------------------
else
{
//----------------------------------------------------------------
// Custom tooltip
//----------------------------------------------------------------
if (ImPlot::IsPlotHovered())
{
float Value;
if (Entry.FindValue(ImPlot::GetPlotMousePos().x, Value))
{
ImGui::BeginTooltip();
ImGui::Text("%s: %0.1f", Label.Get(), Value);
ImGui::EndTooltip();
}
}
if (Entry.ShowValuesMarkers)
{
ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
}
ImPlot::PlotLine(Label.Get(), &Entry.Values[0].x, &Entry.Values[0].y, Entry.Values.size(), ImPlotLineFlags_None, Entry.ValueOffset, 2 * sizeof(float));
if (ImPlot::BeginLegendPopup(Label.Get()))
{
if (ImGui::Button("Clear"))
{
Entry.Clear();
}
ImGui::Checkbox("Show Markers", &Entry.ShowValuesMarkers);
ImPlot::EndLegendPopup();
}
}
//-------------------------------------------------------
// Allow legend item labels to be drag and drop sources
//-------------------------------------------------------
if (ImPlot::BeginDragDropSourceItem(Label.Get()))
{
ImGui::SetDragDropPayload("DragAndDrop", Label.Get(), Label.Length() + 1);
ImGui::TextUnformatted(Label.Get());
ImPlot::EndDragDropSource();
}
}
}
//-------------------------------------------------------
// Allow the main plot area to be a drag and drop target
//-------------------------------------------------------
if (ImPlot::BeginDragDropTargetPlot())
{
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
{
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
{
Plot->AssignAxis(PlotIndex, ImAxis_Y1);
}
}
ImPlot::EndDragDropTarget();
}
//-------------------------------------------------------
// Allow each y-axis to be a drag and drop target
//-------------------------------------------------------
for (int y = ImAxis_Y1; y <= ImAxis_Y3; ++y)
{
if (ImPlot::BeginDragDropTargetAxis(y))
{
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
{
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
{
Plot->AssignAxis(PlotIndex, y);
}
}
ImPlot::EndDragDropTarget();
}
}
//-------------------------------------------------------
// Allow the legend to be a drag and drop target
//-------------------------------------------------------
if (ImPlot::BeginDragDropTargetLegend())
{
if (const ImGuiPayload* Payload = ImGui::AcceptDragDropPayload("DragAndDrop"))
{
if (FCogDebugPlotEntry* Plot = FCogDebugPlot::FindPlot(FName((const char*)Payload->Data)))
{
Plot->AssignAxis(PlotIndex, ImAxis_Y1);
}
}
ImPlot::EndDragDropTarget();
}
ImPlot::EndPlot();
}
}
ImPlot::EndSubplots();
}
}
ImGui::EndChild();
ImGui::EndTable();
}
}
@@ -0,0 +1,95 @@
#include "CogEngineWindow_Scalability.h"
#include "imgui.h"
#include "CogImguiHelper.h"
#include "Engine/Engine.h"
#define SCALABILITY_NUM_LEVELS 5
//--------------------------------------------------------------------------------------------------------------------------
UCogEngineWindow_Scalability::UCogEngineWindow_Scalability()
{
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Scalability::RenderContent()
{
Super::RenderContent();
Scalability::FQualityLevels Levels = Scalability::GetQualityLevels();
FString CurrentQualityName = Scalability::GetQualityLevelText(Levels.GetMinQualityLevel(), SCALABILITY_NUM_LEVELS).ToString();
if (ImGui::BeginCombo("Scalability", TCHAR_TO_ANSI(*CurrentQualityName)))
{
for (int32 i = 0; i < SCALABILITY_NUM_LEVELS; ++i)
{
FString QualityName = Scalability::GetQualityLevelText(i, SCALABILITY_NUM_LEVELS).ToString();
if (ImGui::Selectable(TCHAR_TO_ANSI(*QualityName)))
{
Levels.SetFromSingleQualityLevel(i);
Scalability::SetQualityLevels(Levels);
ImGui::LogToClipboard();
ImGui::LogText("%s", TCHAR_TO_ANSI(*FString::Printf(TEXT("Setting Quality Level to %s"), *QualityName)));
ImGui::LogFinish();
}
}
ImGui::EndCombo();
}
ImGui::Separator();
if (ImGui::SliderFloat("Resolution", &Levels.ResolutionQuality, 10.0f, 100.0f, "%0.f"))
{
Scalability::SetQualityLevels(Levels);
}
if (ImGui::SliderInt("View Distance", &Levels.ViewDistanceQuality, 0, SCALABILITY_NUM_LEVELS - 1))
{
Scalability::SetQualityLevels(Levels);
}
if (ImGui::SliderInt("Anti Aliasing", &Levels.AntiAliasingQuality, 0, SCALABILITY_NUM_LEVELS - 1))
{
Scalability::SetQualityLevels(Levels);
}
if (ImGui::SliderInt("Shadow", &Levels.ShadowQuality, 0, SCALABILITY_NUM_LEVELS - 1))
{
Scalability::SetQualityLevels(Levels);
}
if (ImGui::SliderInt("Global Illumination", &Levels.GlobalIlluminationQuality, 0, SCALABILITY_NUM_LEVELS - 1))
{
Scalability::SetQualityLevels(Levels);
}
if (ImGui::SliderInt("Reflection", &Levels.ReflectionQuality, 0, SCALABILITY_NUM_LEVELS - 1))
{
Scalability::SetQualityLevels(Levels);
}
if (ImGui::SliderInt("Post Process", &Levels.PostProcessQuality, 0, SCALABILITY_NUM_LEVELS - 1))
{
Scalability::SetQualityLevels(Levels);
}
if (ImGui::SliderInt("Texture", &Levels.TextureQuality, 0, SCALABILITY_NUM_LEVELS - 1))
{
Scalability::SetQualityLevels(Levels);
}
if (ImGui::SliderInt("Effects", &Levels.EffectsQuality, 0, SCALABILITY_NUM_LEVELS - 1))
{
Scalability::SetQualityLevels(Levels);
}
if (ImGui::SliderInt("Foliage", &Levels.FoliageQuality, 0, SCALABILITY_NUM_LEVELS - 1))
{
Scalability::SetQualityLevels(Levels);
}
if (ImGui::SliderInt("Shading", &Levels.ShadingQuality, 0, SCALABILITY_NUM_LEVELS - 1))
{
Scalability::SetQualityLevels(Levels);
}
}
@@ -0,0 +1,485 @@
#include "CogEngineWindow_Selection.h"
#include "CogDebugDraw.h"
#include "CogImguiModule.h"
#include "CogWindowManager.h"
#include "CogWindowWidgets.h"
#include "EngineUtils.h"
#include "imgui.h"
#include "Kismet/GameplayStatics.h"
//--------------------------------------------------------------------------------------------------------------------------
UCogEngineWindow_Selection::UCogEngineWindow_Selection()
{
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Selection::PreRender(ImGuiWindowFlags& WindowFlags)
{
WindowFlags = ImGuiWindowFlags_MenuBar;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Selection::ToggleSelectionMode()
{
if (bSelectionModeActive)
{
DeactivateSelectionMode();
}
else
{
ActivateSelectionMode();
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Selection::ActivateSelectionMode()
{
bSelectionModeActive = true;
bImGuiHadInputBeforeEnteringSelectionMode = FCogImguiModule::Get().GetEnableInput();
FCogImguiModule::Get().SetEnableInput(true);
GetOwner()->SetHideAllWindows(true);
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Selection::HackWaitInputRelease()
{
WaitInputReleased = 1;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Selection::DeactivateSelectionMode()
{
bSelectionModeActive = false;
//--------------------------------------------------------------------------------------------
// We can enter selection mode by a command, and imgui might not have the input focus
// 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
//--------------------------------------------------------------------------------------------
if (bImGuiHadInputBeforeEnteringSelectionMode == false)
{
FCogImguiModule::Get().SetEnableInput(false);
}
GetOwner()->SetHideAllWindows(false);
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Selection::RenderTick(float DeltaTime)
{
Super::RenderTick(DeltaTime);
if (FCogDebugSettings::GetSelection() == nullptr)
{
FCogDebugSettings::SetSelection(GetLocalPlayerPawn());
}
if (bSelectionModeActive)
{
TickSelectionMode();
}
if (AActor* Actor = GetSelection())
{
if (Actor != GetLocalPlayerPawn())
{
DrawActorFrame(Actor);
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Selection::RenderContent()
{
Super::RenderContent();
if (ImGui::BeginMenuBar())
{
if (ImGui::MenuItem("Pick"))
{
ActivateSelectionMode();
HackWaitInputRelease();
}
ImGui::EndMenuBar();
}
DrawSelectionCombo();
}
//--------------------------------------------------------------------------------------------------------------------------
bool UCogEngineWindow_Selection::DrawSelectionCombo()
{
bool SelectionChanged = false;
APawn* LocalPlayerPawn = GetLocalPlayerPawn();
//------------------------
// Actor Class Combo
//------------------------
ImGui::SetNextItemWidth(-1);
if (ImGui::BeginCombo("##SelectionType", TCHAR_TO_ANSI(*GetNameSafe(SelectedSubClass))))
{
for (TSubclassOf<AActor> ItSubClass : SubClasses)
{
if (ImGui::Selectable(TCHAR_TO_ANSI(*GetNameSafe(ItSubClass)), false))
{
SelectedSubClass = ItSubClass;
}
}
ImGui::EndCombo();
}
ImGui::Separator();
//------------------------
// Actor List
//------------------------
//ImGui::BeginChild("ActorList", ImVec2(-1, -1), false);
TArray<AActor*> Actors;
for (TActorIterator<AActor> It(GetWorld(), SelectedSubClass); It; ++It)
{
AActor* Actor = *It;
Actors.Add(Actor);
}
ImGuiListClipper Clipper;
Clipper.Begin(Actors.Num());
while (Clipper.Step())
{
for (int32 i = Clipper.DisplayStart; i < Clipper.DisplayEnd; i++)
{
AActor* Actor = Actors[i];
if (Actor == nullptr)
{
continue;
}
ImGui::PushStyleColor(ImGuiCol_Text, Actor == LocalPlayerPawn ? IM_COL32(255, 255, 0, 255) : IM_COL32(255, 255, 255, 255));
bool bIsSelected = Actor == FCogDebugSettings::GetSelection();
const FString ActorName = GetNameSafe(Actor);
if (ImGui::Selectable(TCHAR_TO_ANSI(*ActorName), bIsSelected))
{
FCogDebugSettings::SetSelection(Actor);
SelectionChanged = true;
}
ImGui::PopStyleColor(1);
DrawActorContextMenu(Actor);
//------------------------
// Draw Frame
//------------------------
if (ImGui::IsItemHovered())
{
DrawActorFrame(Actor);
}
if (bIsSelected)
{
ImGui::SetItemDefaultFocus();
}
}
}
Clipper.End();
//ImGui::EndChild();
return SelectionChanged;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Selection::DrawActorContextMenu(AActor* Actor)
{
//------------------------
// ContextMenu
//------------------------
ImGui::SetNextWindowSize(ImVec2(FCogWindowWidgets::TextBaseWidth * 20, 0));
if (ImGui::BeginPopupContextItem())
{
if (ImGui::Button("Reset Selection", ImVec2(-1, 0)))
{
ImGui::CloseCurrentPopup();
FCogDebugSettings::SetSelection(GetLocalPlayerPawn());
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Reset the selection to the controlled actor.");
}
ImGui::EndPopup();
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Selection::TickSelectionMode()
{
if (ImGui::IsMouseClicked(ImGuiMouseButton_Right))
{
DeactivateSelectionMode();
return;
}
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AnyWindow))
{
return;
}
APlayerController* PlayerController = GetLocalPlayerController();
if (PlayerController == nullptr)
{
DeactivateSelectionMode();
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");
AActor* HoveredActor = nullptr;
FVector WorldOrigin, WorldDirection;
if (UGameplayStatics::DeprojectScreenToWorld(PlayerController, FCogImguiHelper::ToVector2D(ImGui::GetMousePos()), WorldOrigin, WorldDirection))
{
TArray<AActor*> IgnoreList;
FHitResult HitResult;
if (UKismetSystemLibrary::LineTraceSingle(GetWorld(), WorldOrigin, WorldOrigin + WorldDirection * 10000, TraceType, false, IgnoreList, EDrawDebugTrace::None, HitResult, true))
{
if (HitResult.GetActor() != nullptr)
{
if (HitResult.GetActor()->GetClass()->IsChildOf(SelectedSubClass))
{
HoveredActor = HitResult.GetActor();
}
}
}
}
if (HoveredActor != nullptr)
{
DrawActorFrame(HoveredActor);
}
if (bSelectionModeActive)
{
if (ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
if (WaitInputReleased == 0)
{
if (HoveredActor != nullptr)
{
FCogDebugSettings::SetSelection(HoveredActor);
}
DeactivateSelectionMode();
}
else
{
WaitInputReleased--;
}
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Selection::DrawActorFrame(const AActor* Actor)
{
APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
if (PlayerController == nullptr)
{
return;
}
ImDrawList* DrawList = ImGui::GetBackgroundDrawList();
FVector BoxOrigin, BoxExtent;
bool PrimitiveFound = false;
FBox Bounds(ForceInit);
if (const UPrimitiveComponent* PrimitiveComponent = Cast<UPrimitiveComponent>(Actor->GetRootComponent()))
{
PrimitiveFound = true;
Bounds += PrimitiveComponent->Bounds.GetBox();
}
else
{
Actor->ForEachComponent<UPrimitiveComponent>(true, [&](const UPrimitiveComponent* InPrimComp)
{
if (InPrimComp->IsRegistered() && InPrimComp->IsCollisionEnabled())
{
Bounds += InPrimComp->Bounds.GetBox();
PrimitiveFound = true;
}
});
}
if (PrimitiveFound)
{
Bounds.GetCenterAndExtents(BoxOrigin, BoxExtent);
}
else
{
BoxOrigin = Actor->GetActorLocation();
BoxExtent = FVector(50.f, 50.f, 50.f);
}
FVector2D ScreenPosMin, ScreenPosMax;
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(*Actor->GetName()));
}
}
//-----------------------------------------------------------------------------------------
bool UCogEngineWindow_Selection::ComputeBoundingBoxScreenPosition(const APlayerController* PlayerController, const FVector& Origin, const FVector& Extent, FVector2D& Min, FVector2D& Max)
{
FVector Corners[8];
Corners[0].Set(-Extent.X, -Extent.Y, -Extent.Z); // - - -
Corners[1].Set(Extent.X, -Extent.Y, -Extent.Z); // + - -
Corners[2].Set(-Extent.X, Extent.Y, -Extent.Z); // - + -
Corners[3].Set(-Extent.X, -Extent.Y, Extent.Z); // - - +
Corners[4].Set(Extent.X, Extent.Y, -Extent.Z); // + + -
Corners[5].Set(Extent.X, -Extent.Y, Extent.Z); // + - +
Corners[6].Set(-Extent.X, Extent.Y, Extent.Z); // - + +
Corners[7].Set(Extent.X, Extent.Y, Extent.Z); // + + +
Min.X = FLT_MAX;
Min.Y = FLT_MAX;
Max.X = -FLT_MAX;
Max.Y = -FLT_MAX;
for (int i = 0; i < 8; ++i)
{
FVector2D ScreenLocation;
if (PlayerController->ProjectWorldLocationToScreen(Origin + Corners[i], ScreenLocation, false) == false)
{
return false;
}
Min.X = FMath::Min(ScreenLocation.X, Min.X);
Min.Y = FMath::Min(ScreenLocation.Y, Min.Y);
Max.X = FMath::Max(ScreenLocation.X, Max.X);
Max.Y = FMath::Max(ScreenLocation.Y, Max.Y);
}
// Prevent getting large values when the camera get close to the target
ImVec2 DisplaySize = ImGui::GetIO().DisplaySize;
Min.X = FMath::Max(-DisplaySize.x, Min.X);
Min.Y = FMath::Max(-DisplaySize.y, Min.Y);
Max.X = FMath::Min(DisplaySize.x * 2, Max.X);
Max.Y = FMath::Min(DisplaySize.y * 2, Max.Y);
return true;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Selection::DrawMainMenuWidget(bool Draw, float& Width)
{
const float PickButtonWidth = FCogWindowWidgets::TextBaseWidth * 5;
const float SelectionButtonWidth = FCogWindowWidgets::TextBaseWidth * 30;
const float ResetButtonWidth = FCogWindowWidgets::TextBaseWidth * 2;
Width = PickButtonWidth + SelectionButtonWidth + ResetButtonWidth;
if (Draw == false)
{
return;
}
if (ImGui::BeginPopup("SelectionPopup"))
{
ImGui::BeginChild("Popup", ImVec2(Width, FCogWindowWidgets::TextBaseWidth * 40), false);
if (DrawSelectionCombo())
{
ImGui::CloseCurrentPopup();
}
ImGui::EndChild();
ImGui::EndPopup();
}
//-----------------------------------
// Pick Button
//-----------------------------------
{
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0));
if (ImGui::Button("Pick", ImVec2(PickButtonWidth, 0)))
{
ActivateSelectionMode();
HackWaitInputRelease();
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Enter picking mode to select an actor on screen.");
}
ImGui::PopStyleColor(1);
ImGui::PopStyleVar(2);
}
AActor* GlobalSelection = FCogDebugSettings::GetSelection();
//-----------------------------------
// Selection
//-----------------------------------
{
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyleColorVec4((ImGuiCol_FrameBg)));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4((ImGuiCol_FrameBgActive)));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetStyleColorVec4((ImGuiCol_FrameBgHovered)));
ImGui::SameLine();
FString SelectionName = GetNameSafe(GlobalSelection);
if (ImGui::Button(TCHAR_TO_ANSI(*SelectionName), ImVec2(SelectionButtonWidth, 0)))
{
ImGui::OpenPopup("SelectionPopup");
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Current Selection: %s", TCHAR_TO_ANSI(*SelectionName));
}
ImGui::PopStyleColor(3);
ImGui::PopStyleVar(2);
DrawActorContextMenu(GlobalSelection);
}
//-----------------------------------
// Reset Button
//-----------------------------------
{
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyleColorVec4((ImGuiCol_FrameBg)));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4((ImGuiCol_FrameBgActive)));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetStyleColorVec4((ImGuiCol_FrameBgHovered)));
ImGui::SameLine(ImGui::GetCursorPos().x - ResetButtonWidth + (ImGui::GetStyle().WindowPadding.x - 2) * ImGui::GetWindowDpiScale());
if (ImGui::Button("X", ImVec2(ResetButtonWidth, 0)))
{
FCogDebugSettings::SetSelection(nullptr);
ImGui::CloseCurrentPopup();
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Reset the selection to the controlled actor.");
}
ImGui::PopStyleColor(3);
ImGui::PopStyleVar(1);
}
}
@@ -0,0 +1,370 @@
#include "CogEngineWindow_Skeleton.h"
#include "CogDebugSettings.h"
#include "Components/LineBatchComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Engine/SkeletalMesh.h"
//--------------------------------------------------------------------------------------------------------------------------
UCogEngineWindow_Skeleton::UCogEngineWindow_Skeleton()
{
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Skeleton::PreRender(ImGuiWindowFlags& WindowFlags)
{
WindowFlags = ImGuiWindowFlags_MenuBar;
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Skeleton::OnSelectionChanged(AActor* OldSelection, AActor* NewSelection)
{
RefreshSkeleton();
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Skeleton::RenderTick(float DeltaTime)
{
Super::RenderTick(DeltaTime);
if (GetIsVisible() == false)
{
return;
}
DrawSkeleton();
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Skeleton::RefreshSkeleton()
{
CurrentSkeleton = nullptr;
BonesInfos.Empty();
AActor* Selection = GetSelection();
if (Selection == nullptr)
{
return;
}
CurrentSkeleton = Selection->FindComponentByClass<USkeletalMeshComponent>();
if (CurrentSkeleton == nullptr)
{
return;
}
const FTransform WorldTransform = CurrentSkeleton->GetComponentTransform();
const TArray<FTransform>& ComponentSpaceTransforms = CurrentSkeleton->GetComponentSpaceTransforms();
BonesInfos.SetNum(ComponentSpaceTransforms.Num());
for (int32 BoneIndex = 0; BoneIndex < ComponentSpaceTransforms.Num(); ++BoneIndex)
{
const FReferenceSkeleton& ReferenceSkeleton = CurrentSkeleton->GetSkeletalMeshAsset()->GetRefSkeleton();
FBoneInfo& CurrentBoneInfo = BonesInfos[BoneIndex];
CurrentBoneInfo.Index = BoneIndex;
CurrentBoneInfo.Name = ReferenceSkeleton.GetBoneName(BoneIndex);
const FTransform Transform = ComponentSpaceTransforms[BoneIndex] * WorldTransform;
CurrentBoneInfo.LastLocation = Transform.GetLocation();
CurrentBoneInfo.IsSecondaryBone = FCogDebugSettings::IsSecondarySkeletonBone(CurrentBoneInfo.Name);
CurrentBoneInfo.ShowBone = !(HideSecondaryBones && CurrentBoneInfo.IsSecondaryBone);
const int32 ParentIndex = ReferenceSkeleton.GetParentIndex(BoneIndex);
if (ParentIndex != INDEX_NONE)
{
FBoneInfo& ParentBoneInfo = BonesInfos[ParentIndex];
ParentBoneInfo.Children.Add(BoneIndex);
CurrentBoneInfo.ParentIndex = ParentIndex;
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Skeleton::RenderContent()
{
Super::RenderContent();
if (ImGui::BeginMenuBar())
{
if (ImGui::BeginMenu("Options"))
{
ImGui::Checkbox("Hide secondary bones", &HideSecondaryBones);
ImGui::Separator();
ImGui::Checkbox("Show bones", &ShowBones);
ImGui::Checkbox("Show name", &ShowNames);
ImGui::Checkbox("Show axes", &ShowAxes);
ImGui::Checkbox("Show local velocity", &ShowVelocities);
ImGui::Checkbox("Show trajectories", &ShowTrajectories);
ImGui::EndMenu();
}
FCogWindowWidgets::MenuSearchBar(Filter);
ImGui::EndMenuBar();
}
ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, FCogWindowWidgets::TextBaseWidth);
HoveredBoneIndex = INDEX_NONE;
DrawBoneEntry(0, false);
ImGui::PopStyleVar();
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Skeleton::DrawBoneEntry(int32 BoneIndex, bool OpenAllChildren)
{
if (BonesInfos.IsValidIndex(BoneIndex) == false)
{
return;
}
FBoneInfo& BoneInfo = BonesInfos[BoneIndex];
if (HideSecondaryBones && BoneInfo.IsSecondaryBone)
{
return;
}
const char* BoneName = TCHAR_TO_ANSI(*BoneInfo.Name.ToString());
const bool ShowNode = Filter.PassFilter(BoneName);
bool OpenChildren = false;
if (ShowNode)
{
ImGui::PushID(BoneIndex);
if (OpenAllChildren)
{
ImGui::SetNextItemOpen(true, ImGuiCond_Always);
}
else
{
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
}
//------------------------
// TreeNode
//------------------------
if (BoneInfo.Children.Num() > 0 && Filter.IsActive() == false)
{
OpenChildren = ImGui::TreeNodeEx("##Bone", ImGuiTreeNodeFlags_AllowItemOverlap | ImGuiTreeNodeFlags_SpanFullWidth);
}
else
{
ImGui::TreeNodeEx("##Bone", ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_AllowItemOverlap | ImGuiTreeNodeFlags_SpanFullWidth);
}
const bool IsControlDown = ImGui::GetCurrentContext()->IO.KeyCtrl;
if (ImGui::IsItemClicked(ImGuiMouseButton_Left) && IsControlDown)
{
OpenAllChildren = true;
}
//------------------------
// ContextMenu
//------------------------
if (ImGui::BeginPopupContextItem())
{
ImGui::Checkbox("Show Name", &BoneInfo.ShowName);
ImGui::Checkbox("Show Axe", &BoneInfo.ShowAxes);
ImGui::Checkbox("Show Local Velocity", &BoneInfo.ShowLocalVelocity);
ImGui::Checkbox("Show Trajectory", &BoneInfo.ShowTrajectory);
ImGui::EndPopup();
HoveredBoneIndex = BoneIndex;
}
//------------------------
// Tooltip
//------------------------
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::BeginDisabled();
ImGui::Checkbox("Show Name", &BoneInfo.ShowName);
ImGui::Checkbox("Show Axe", &BoneInfo.ShowAxes);
ImGui::Checkbox("Show Local Velocity", &BoneInfo.ShowLocalVelocity);
ImGui::Checkbox("Show Trajectory", &BoneInfo.ShowTrajectory);
ImGui::EndDisabled();
ImGui::EndTooltip();
HoveredBoneIndex = BoneIndex;
}
//------------------------
// Checkbox
//------------------------
ImGui::SameLine();
if (ImGui::Checkbox("##Visible", &BoneInfo.ShowBone))
{
if (IsControlDown)
{
SetChildrenVisibility(BoneIndex, BoneInfo.ShowBone);
}
if (BoneInfo.ShowBone == false)
{
BoneInfo.ShowName = false;
BoneInfo.ShowAxes = false;
BoneInfo.ShowLocalVelocity = false;
BoneInfo.ShowTrajectory = false;
}
}
const bool HasCustomVisiblity = BoneInfo.ShowName || BoneInfo.ShowAxes || BoneInfo.ShowLocalVelocity || BoneInfo.ShowTrajectory;
if (HasCustomVisiblity)
{
BoneInfo.ShowBone = true;
}
//------------------------
// Name
//------------------------
ImGui::SameLine();
ImVec4 NameColor = HasCustomVisiblity ? ImVec4(1.0f, 1.0f, 0.0f, 1.0f) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
ImGui::TextColored(NameColor, "%s", BoneName);
}
//------------------------
// Children
//------------------------
if (OpenChildren || Filter.IsActive())
{
for (int32 ChildIndex : BoneInfo.Children)
{
DrawBoneEntry(ChildIndex, OpenAllChildren);
}
}
if (ShowNode)
{
if (OpenChildren && ShowNode)
{
ImGui::TreePop();
}
ImGui::PopID();
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Skeleton::SetChildrenVisibility(int32 BoneIndex, bool IsVisible)
{
if (BonesInfos.IsValidIndex(BoneIndex) == false)
{
return;
}
FBoneInfo& BoneInfo = BonesInfos[BoneIndex];
for (int32 ChildIndex : BoneInfo.Children)
{
FBoneInfo& ChildBoneInfo = BonesInfos[ChildIndex];
ChildBoneInfo.ShowBone = IsVisible && !(HideSecondaryBones && ChildBoneInfo.IsSecondaryBone);
SetChildrenVisibility(ChildIndex, IsVisible);
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Skeleton::DrawSkeleton()
{
if (CurrentSkeleton == nullptr || CurrentSkeleton->GetWorld() == nullptr)
{
return;
}
const UWorld* World = CurrentSkeleton->GetWorld();
const FTransform WorldTransform = CurrentSkeleton->GetComponentTransform();
const TArray<FTransform>& ComponentSpaceTransforms = CurrentSkeleton->GetComponentSpaceTransforms();
for (int32 BoneIndex = 0; BoneIndex < ComponentSpaceTransforms.Num(); ++BoneIndex)
{
FBoneInfo& BoneInfo = BonesInfos[BoneIndex];
const FTransform Transform = ComponentSpaceTransforms[BoneIndex] * WorldTransform;
FVector BoneLocation = Transform.GetLocation();
FRotator BoneRotation = FRotator(Transform.GetRotation());
FVector ParentLocation;
if (BoneInfo.ParentIndex >= 0)
{
ParentLocation = (ComponentSpaceTransforms[BoneInfo.ParentIndex] * WorldTransform).GetLocation();
}
else
{
ParentLocation = WorldTransform.GetLocation();
}
if (BoneInfo.ShowBone)
{
const bool IsHovered = BoneIndex == HoveredBoneIndex;
if (ShowBones)
{
::DrawDebugLine(World, ParentLocation, BoneLocation, IsHovered ? FColor::Red : FColor::White, false, 0.0f, 1, FCogDebugSettings::GetDebugThickness(IsHovered ? 0.5f : 0.0f));
::DrawDebugPoint(World, BoneLocation, FCogDebugSettings::GetDebugThickness(IsHovered ? 6.0f : 4.0f), IsHovered ? FColor::Red : FColor::White, false, 0.0f, 1);
}
if (ShowNames || BoneInfo.ShowName || IsHovered)
{
::DrawDebugString(World, BoneLocation, BoneInfo.Name.ToString(), nullptr, IsHovered ? FColor::Red : FColor::White, 0.0f, true, FCogDebugSettings::TextSize);
}
if (ShowAxes || BoneInfo.ShowAxes)
{
::DrawDebugCoordinateSystem(
World,
BoneLocation,
BoneRotation,
10.0f * FCogDebugSettings::AxesScale,
false,
0.0f,
1,
FCogDebugSettings::GetDebugThickness(0.0f));
}
if (ShowVelocities || BoneInfo.ShowLocalVelocity)
{
if (const FBodyInstance* ParentBodyInstance = CurrentSkeleton->GetBodyInstance(BoneInfo.Name))
{
DrawDebugDirectionalArrow(
World,
BoneLocation,
BoneLocation + ParentBodyInstance->GetUnrealWorldVelocity() * World->GetDeltaSeconds(),
FCogDebugSettings::ArrowSize,
FCogDebugSettings::ModulateDebugColor(World, FColor::Cyan),
FCogDebugSettings::GetDebugPersistent(true),
FCogDebugSettings::GetDebugDuration(true),
0,
FCogDebugSettings::GetDebugThickness(0.0f));
}
}
if (ShowTrajectories || BoneInfo.ShowTrajectory)
{
const FColor Color = FCogDebugSettings::ModulateDebugColor(World, FColor::Yellow);
DrawDebugLine(
World,
BoneInfo.LastLocation,
BoneLocation,
Color,
FCogDebugSettings::GetDebugPersistent(true),
FCogDebugSettings::GetDebugDuration(true),
0,
FCogDebugSettings::GetDebugThickness(0.0f));
DrawDebugPoint(
World,
BoneLocation,
FCogDebugSettings::GetDebugThickness(2.0f),
Color,
FCogDebugSettings::GetDebugPersistent(true),
FCogDebugSettings::GetDebugDuration(true),
0);
}
BoneInfo.LastLocation = BoneLocation;
}
}
}
@@ -0,0 +1,126 @@
#include "CogEngineWindow_Stats.h"
#include "Engine/Engine.h"
#include "Engine/NetConnection.h"
#include "GameFramework/PlayerState.h"
ImVec4 StatRedColor(1.0f, 0.4f, 0.3f, 1.0f);
ImVec4 StatOrangeColor(1.0f, 0.7f, 0.4f, 1.0f);
ImVec4 StatGreenColor(0.5f, 1.0f, 0.6f, 1.0f);
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Stats::RenderContent()
{
Super::RenderContent();
extern ENGINE_API float GAverageFPS;
ImGui::Text("FPS ");
ImGui::SameLine();
ImGui::TextColored(GetFpsColor(GAverageFPS), "%0.0f", GAverageFPS);
if (const APlayerController* PlayerController = GetLocalPlayerController())
{
if (const APlayerState* PlayerState = PlayerController->GetPlayerState<APlayerState>())
{
const float Ping = PlayerState->GetPingInMilliseconds();
ImGui::Text("Ping ");
ImGui::SameLine();
ImGui::TextColored(GetPingColor(Ping), "%0.0fms", Ping);
}
if (UNetConnection* Connection = PlayerController->GetNetConnection())
{
const float OutPacketLost = Connection->GetOutLossPercentage().GetAvgLossPercentage() * 100.0f;
ImGui::Text("Packet Loss Out ");
ImGui::SameLine();
ImGui::TextColored(GetPacketLossColor(OutPacketLost), "%0.0f%%", OutPacketLost);
const float InPacketLost = Connection->GetInLossPercentage().GetAvgLossPercentage() * 100.0f;
ImGui::Text("Packet Loss In ");
ImGui::SameLine();
ImGui::TextColored(GetPacketLossColor(InPacketLost), "%0.0f%%", InPacketLost);
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Stats::DrawMainMenuWidget(bool Draw, float& Width)
{
const float ResetButtonWidth = FCogWindowWidgets::TextBaseWidth * 5;
Width = FCogWindowWidgets::TextBaseWidth * 15;
if (Draw == false)
{
return;
}
extern ENGINE_API float GAverageFPS;
ImGui::TextColored(GetFpsColor(GAverageFPS), "%3dfps ", (int32)GAverageFPS);
if (const APlayerController* PlayerController = GetLocalPlayerController())
{
if (const APlayerState* PlayerState = PlayerController->GetPlayerState<APlayerState>())
{
const float Ping = PlayerState->GetPingInMilliseconds();
ImGui::SameLine();
ImGui::TextColored(GetPingColor(Ping), "%3dms ", (int32)Ping);
}
if (UNetConnection* Connection = PlayerController->GetNetConnection())
{
const float OutPacketLost = Connection->GetOutLossPercentage().GetAvgLossPercentage() * 100.0f;
const float InPacketLost = Connection->GetInLossPercentage().GetAvgLossPercentage() * 100.0f;
const float TotalPacketLost = OutPacketLost + InPacketLost;
ImGui::SameLine();
ImGui::TextColored(GetPacketLossColor(TotalPacketLost), "%2d%% ", (int32)TotalPacketLost);
}
}
}
//--------------------------------------------------------------------------------------------------------------------------
ImVec4 UCogEngineWindow_Stats::GetFpsColor(float Value, float Good /*= 50.0f*/, float Medium /*= 30.0f*/)
{
if (Value > Good)
{
return StatGreenColor;
}
if (Value > Medium)
{
return StatOrangeColor;
}
return StatRedColor;
}
//--------------------------------------------------------------------------------------------------------------------------
ImVec4 UCogEngineWindow_Stats::GetPingColor(float Value, float Good /*= 100.0f*/, float Medium /*= 200.0f*/)
{
if (Value > Medium)
{
return StatRedColor;
}
if (Value > Good)
{
return StatOrangeColor;
}
return StatGreenColor;
}
//--------------------------------------------------------------------------------------------------------------------------
ImVec4 UCogEngineWindow_Stats::GetPacketLossColor(float Value, float Good /*= 10.0f*/, float Medium /*= 20.0f*/)
{
if (Value > Medium)
{
return StatRedColor;
}
if (Value > Good)
{
return StatOrangeColor;
}
return StatGreenColor;
}
@@ -0,0 +1,76 @@
#include "CogEngineWindow_Time.h"
#include "CogEngineReplicator.h"
#include "Engine/Engine.h"
#include "Engine/World.h"
//--------------------------------------------------------------------------------------------------------------------------
void DrawTimeButton(ACogEngineReplicator* Replicator, float Value)
{
const bool IsSelected = FMath::IsNearlyEqual(Replicator->GetTimeDilation(), Value, 0.0001f);
if (IsSelected)
{
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
}
else
{
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(128, 128, 128, 50));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, IM_COL32(128, 128, 128, 100));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, IM_COL32(128, 128, 128, 150));
}
const char* Text = TCHAR_TO_ANSI(*FString::Printf(TEXT("%g"), Value).Replace(TEXT("0."), TEXT(".")));
if (ImGui::Button(Text, ImVec2(3.5f * FCogWindowWidgets::TextBaseWidth, 0)))
{
Replicator->Server_SetTimeDilation(Value);
}
if (IsSelected)
{
ImGui::PopStyleVar();
}
else
{
ImGui::PopStyleColor(3);
}
}
//--------------------------------------------------------------------------------------------------------------------------
UCogEngineWindow_Time::UCogEngineWindow_Time()
{
TimingScales.Add(0.00f);
TimingScales.Add(0.01f);
TimingScales.Add(0.10f);
TimingScales.Add(0.50f);
TimingScales.Add(1.00f);
TimingScales.Add(2.00f);
TimingScales.Add(5.00f);
TimingScales.Add(10.0f);
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogEngineWindow_Time::RenderContent()
{
Super::RenderContent();
ACogEngineReplicator* Replicator = FCogEngineModule::Get().GetLocalReplicator();
if (Replicator == nullptr)
{
return;
}
ImGuiStyle& Style = ImGui::GetStyle();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(Style.WindowPadding.x * 0.40f, (float)(int)(Style.WindowPadding.y * 0.60f)));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(Style.FramePadding.x * 0.40f, (float)(int)(Style.FramePadding.y * 0.60f)));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(Style.ItemSpacing.x * 0.30f, (float)(int)(Style.ItemSpacing.y * 0.60f)));
ImGui::PushStyleColor(ImGuiCol_Border, IM_COL32(255, 255, 255, 180));
for (float TimeScale : TimingScales)
{
DrawTimeButton(Replicator, TimeScale);
ImGui::SameLine();
}
ImGui::PopStyleColor(1);
ImGui::PopStyleVar(3);
}
@@ -0,0 +1,32 @@
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "CogEngineDataAsset_Collisions.generated.h"
//--------------------------------------------------------------------------------------------------------------------------
USTRUCT()
struct COGENGINE_API FCogCollisionChannel
{
GENERATED_BODY()
UPROPERTY(EditAnywhere)
TEnumAsByte<ECollisionChannel> Channel = ECollisionChannel::ECC_WorldStatic;
UPROPERTY(EditAnywhere)
FLinearColor Color = FLinearColor(0.5f, 0.5f, 0.5f, 1.0f);
};
//--------------------------------------------------------------------------------------------------------------------------
UCLASS(Blueprintable)
class COGENGINE_API UCogEngineDataAsset_Collisions : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
UCogEngineDataAsset_Collisions() {}
UPROPERTY(EditAnywhere, meta = (TitleProperty = "Channel"))
TArray<FCogCollisionChannel> Channels;
};
@@ -0,0 +1,32 @@
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class ACogEngineReplicator;
class APlayerController;
class COGENGINE_API FCogEngineModule : public IModuleInterface
{
public:
static inline FCogEngineModule& Get() { return FModuleManager::LoadModuleChecked<FCogEngineModule>("CogEngine"); }
virtual void StartupModule() override;
virtual void ShutdownModule() override;
ACogEngineReplicator* GetLocalReplicator();
void SetLocalReplicator(ACogEngineReplicator* Value);
ACogEngineReplicator* GetRemoteReplicator(const APlayerController* PlayerController);
TArray<TObjectPtr<ACogEngineReplicator>> GetRemoteReplicators() const { return RemoteReplicators; }
void AddRemoteReplicator(ACogEngineReplicator* Value);
private:
TObjectPtr<ACogEngineReplicator> LocalReplicator;
TArray<TObjectPtr<ACogEngineReplicator>> RemoteReplicators;
};
@@ -0,0 +1,60 @@
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "UObject/Class.h"
#include "UObject/ObjectMacros.h"
#include "CogEngineReplicator.generated.h"
class APlayerController;
//--------------------------------------------------------------------------------------------------------------------------
USTRUCT()
struct FCogEngineReplicatorSpawnAction
{
GENERATED_USTRUCT_BODY()
bool Control = false;
bool Select = false;
};
//--------------------------------------------------------------------------------------------------------------------------
UCLASS(NotBlueprintable, NotBlueprintType, notplaceable, noteditinlinenew, hidedropdown, Transient)
class COGENGINE_API ACogEngineReplicator : public AActor
{
GENERATED_UCLASS_BODY()
public:
static void Create(APlayerController* Controller);
virtual void BeginPlay() override;
APlayerController* GetPlayerController() const { return OwnerPlayerController.Get(); }
bool IsLocal() const { return bIsLocal; }
UFUNCTION(Server, Reliable)
void Server_SetTimeDilation(float Value);
float GetTimeDilation() const { return TimeDilation; }
protected:
void TickSpawnActions();
UFUNCTION()
void OnRep_TimeDilation();
UPROPERTY()
TArray<FCogEngineReplicatorSpawnAction> SpawnActions;
TObjectPtr<APlayerController> OwnerPlayerController;
uint32 bHasAuthority : 1;
uint32 bIsLocal : 1;
private:
UPROPERTY(ReplicatedUsing = OnRep_TimeDilation)
float TimeDilation = 1.0f;
};
@@ -0,0 +1,38 @@
#pragma once
#include "CoreMinimal.h"
#include "CogWindow.h"
#include "CogEngineWindow_Collisions.generated.h"
class UCogEngineDataAsset_Collisions;
UCLASS(Config = Cog)
class COGENGINE_API UCogEngineWindow_Collisions : public UCogWindow
{
GENERATED_BODY()
public:
UCogEngineWindow_Collisions();
virtual void RenderContent() override;
void SetCollisionsAsset(const UCogEngineDataAsset_Collisions* Asset);
private:
struct FChannel
{
bool IsValid = false;
FColor Color;
};
TWeakObjectPtr<UCogEngineDataAsset_Collisions> CollisionsAsset;
FChannel Channels[ECC_MAX];
UPROPERTY(Config)
int32 ObjectTypesToQuery;
UPROPERTY(Config)
int32 ProfileIndex = 0;
};
@@ -0,0 +1,18 @@
#pragma once
#include "CoreMinimal.h"
#include "CogWindow.h"
#include "CogEngineWindow_DebugSettings.generated.h"
UCLASS()
class COGENGINE_API UCogEngineWindow_DebugSettings : public UCogWindow
{
GENERATED_BODY()
public:
UCogEngineWindow_DebugSettings();
virtual void PreRender(ImGuiWindowFlags& WindowFlags) override;
virtual void RenderContent() override;
};
@@ -0,0 +1,24 @@
#pragma once
#include "CoreMinimal.h"
#include "CogWindow.h"
#include "CogEngineWindow_ImGui.generated.h"
UCLASS()
class COGENGINE_API UCogEngineWindow_ImGui : public UCogWindow
{
GENERATED_BODY()
public:
UCogEngineWindow_ImGui();
virtual void RenderTick(float DeltaTime) override;
virtual void RenderContent() override;
private:
bool bShowImguiDemo = false;
bool bShowImguiPlot = false;
bool bShowImguiMetric = false;
bool bShowImguiDebugLog = false;
bool bShowImguiStyleEditor = false;
};
@@ -0,0 +1,16 @@
#pragma once
#include "CoreMinimal.h"
#include "CogWindow.h"
#include "CogEngineWindow_LogCategories.generated.h"
UCLASS()
class COGENGINE_API UCogEngineWindow_LogCategories : public UCogWindow
{
GENERATED_BODY()
public:
virtual void PreRender(ImGuiWindowFlags& WindowFlags) override;
virtual void RenderContent() override;
};
@@ -0,0 +1,18 @@
#pragma once
#include "CoreMinimal.h"
#include "CogWindow.h"
#include "CogEngineWindow_NetEmulation.generated.h"
UCLASS()
class COGENGINE_API UCogEngineWindow_NetEmulation : public UCogWindow
{
GENERATED_BODY()
public:
virtual void RenderContent() override;
private:
};
@@ -0,0 +1,78 @@
#pragma once
#include "CoreMinimal.h"
#include "CogWindow.h"
#include "imgui.h"
#include "Misc/OutputDevice.h"
#include "CogEngineWindow_OutputLog.generated.h"
class UCogEngineWindow_OutputLog;
class UCogLogOutputDevice : public FOutputDevice
{
public:
friend class UCogEngineWindow_OutputLog;
UCogLogOutputDevice();
~UCogLogOutputDevice();
virtual void Serialize(const TCHAR* Message, ELogVerbosity::Type Verbosity, const FName& Category) override;
UCogEngineWindow_OutputLog* OutputLog = nullptr;
};
UCLASS(Config = Cog)
class COGENGINE_API UCogEngineWindow_OutputLog : public UCogWindow
{
GENERATED_BODY()
public:
UCogEngineWindow_OutputLog();
virtual void PreRender(ImGuiWindowFlags& WindowFlags) override;
virtual void RenderContent() override;
void Clear();
void AddLog(const TCHAR* Message, ELogVerbosity::Type Verbosity, const FName& Category);
private:
struct FLineInfo
{
int32 Start = 0;
int32 End = 0;
int32 Frame = 0;
ELogVerbosity::Type Verbosity;
FName Category;
};
void DrawRow(const char* BufferStart, const FLineInfo& Info, bool IsTableShown);
UPROPERTY(Config)
bool AutoScroll = true;
UPROPERTY(Config)
bool ShowFrame = true;
UPROPERTY(Config)
bool ShowCategory = true;
UPROPERTY(Config)
bool ShowVerbosity = false;
UPROPERTY(Config)
bool ShowAsTable = false;
UPROPERTY(Config)
int32 VerbosityFilter = ELogVerbosity::VeryVerbose;
ImGuiTextBuffer TextBuffer;
ImGuiTextFilter Filter;
TArray<FLineInfo> LineInfos;
UCogLogOutputDevice OutputDevice;
};
@@ -0,0 +1,23 @@
#pragma once
#include "CoreMinimal.h"
#include "CogWindow.h"
#include "CogEngineWindow_Plots.generated.h"
class UCogEngineDataAsset_Collisions;
UCLASS()
class COGENGINE_API UCogEngineWindow_Plots : public UCogWindow
{
GENERATED_BODY()
public:
UCogEngineWindow_Plots();
virtual void RenderTick(float DeltaTime) override;
virtual void RenderContent() override;
private:
};
@@ -0,0 +1,16 @@
#pragma once
#include "CoreMinimal.h"
#include "CogWindow.h"
#include "CogEngineWindow_Scalability.generated.h"
UCLASS()
class COGENGINE_API UCogEngineWindow_Scalability : public UCogWindow
{
GENERATED_BODY()
public:
UCogEngineWindow_Scalability();
virtual void RenderContent() override;
};
@@ -0,0 +1,73 @@
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CogWindow.h"
#include "CogEngineWindow_Selection.generated.h"
UCLASS()
class COGENGINE_API UCogEngineWindow_Selection : public UCogWindow
{
GENERATED_BODY()
public:
UCogEngineWindow_Selection();
virtual void RenderTick(float DeltaTime);
virtual void PreRender(ImGuiWindowFlags& WindowFlags) override;
virtual void RenderContent() override;
virtual void DrawMainMenuWidget(bool Draw, float& Width) override;
bool DrawSelectionCombo();
void DrawActorContextMenu(AActor* Actor);
void ActivateSelectionMode();
void HackWaitInputRelease();
bool GetIsSelecting() const { return bSelectionModeActive; }
void SetCurrentActorSubClass(TSubclassOf<AActor> Value) { SelectedSubClass = Value; }
TSubclassOf<AActor> GetCurrentActorSubClass() const { return SelectedSubClass; }
const TArray<TSubclassOf<AActor>>& GetActorSubClasses() const { return SubClasses; }
void SetActorSubClasses(const TArray<TSubclassOf<AActor>>& Value) { SubClasses = Value; }
ETraceTypeQuery GetTraceType() const { return TraceType; }
void SetTraceType(ETraceTypeQuery Value) { TraceType = Value; }
private:
void TickSelectionMode();
void ToggleSelectionMode();
void DeactivateSelectionMode();
void DrawActorFrame(const AActor* Actor);
//void DrawActorDebug(const AActor* Actor);
bool ComputeBoundingBoxScreenPosition(const APlayerController* PlayerController, const FVector& Origin, const FVector& Extent, FVector2D& Min, FVector2D& Max);
FVector LastSelectedActorLocation = FVector::ZeroVector;
bool bSelectionModeActive = false;
bool bImGuiHadInputBeforeEnteringSelectionMode = false;
int32 WaitInputReleased = 0;
TSubclassOf<AActor> SelectedSubClass;
TArray<TSubclassOf<AActor>> SubClasses;
ETraceTypeQuery TraceType = TraceTypeQuery1;
};
@@ -0,0 +1,57 @@
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CogWindow.h"
#include "CogEngineWindow_Skeleton.generated.h"
class USkeletalMeshComponent;
struct FBoneInfo
{
FName Name;
TArray<int32> Children;
int32 Index = 0;
int32 ParentIndex = INDEX_NONE;
FVector LastLocation = FVector::ZeroVector;
bool IsSecondaryBone = false;
bool ShowBone = true;
bool ShowName = false;
bool ShowLocalVelocity = false;
bool ShowAxes = false;
bool ShowTrajectory = false;
};
UCLASS()
class COGENGINE_API UCogEngineWindow_Skeleton : public UCogWindow
{
GENERATED_BODY()
public:
UCogEngineWindow_Skeleton();
virtual void RenderContent() override;
virtual void RenderTick(float DeltaTime) override;
protected:
virtual void PreRender(ImGuiWindowFlags& WindowFlags) override;
virtual void OnSelectionChanged(AActor* OldSelection, AActor* NewSelection) override;
private:
void DrawBoneEntry(int32 BoneIndex, bool OpenAllChildren);
void SetChildrenVisibility(int32 BoneIndex, bool IsVisible);
void DrawSkeleton();
void RefreshSkeleton();
TWeakObjectPtr<USkeletalMeshComponent> CurrentSkeleton = nullptr;
bool ShowBones = true;
bool ShowNames = false;
bool ShowAxes = false;
bool ShowVelocities = false;
bool ShowTrajectories = false;
bool HideSecondaryBones = true;
int32 HoveredBoneIndex = INDEX_NONE;
TArray<FBoneInfo> BonesInfos;
ImGuiTextFilter Filter;
};
@@ -0,0 +1,20 @@
#pragma once
#include "CoreMinimal.h"
#include "CogWindow.h"
#include "CogEngineWindow_Stats.generated.h"
UCLASS()
class COGENGINE_API UCogEngineWindow_Stats : public UCogWindow
{
GENERATED_BODY()
public:
virtual void RenderContent() override;
virtual void DrawMainMenuWidget(bool Draw, float& Width) override;
static ImVec4 GetFpsColor(float Value, float Good = 50.0f, float Medium = 30.0f);
static ImVec4 GetPingColor(float Value, float Good = 100.0f, float Medium = 200.0f);
static ImVec4 GetPacketLossColor(float Value, float Good = 10.0f, float Medium = 20.0f);
};
@@ -0,0 +1,21 @@
#pragma once
#include "CoreMinimal.h"
#include "CogWindow.h"
#include "CogEngineWindow_Time.generated.h"
UCLASS()
class COGENGINE_API UCogEngineWindow_Time : public UCogWindow
{
GENERATED_BODY()
public:
UCogEngineWindow_Time();
virtual void RenderContent() override;
TArray<float> TimingScales;
private:
};