2022-01-24 11:36:13 -05:00
|
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
|
|
#include "SmartObjectComponentVisualizer.h"
|
2023-01-19 00:48:07 -05:00
|
|
|
|
#include "Engine/Engine.h"
|
2022-01-24 11:36:13 -05:00
|
|
|
|
#include "SmartObjectComponent.h"
|
2023-01-19 00:48:07 -05:00
|
|
|
|
#include "SceneManagement.h"
|
2022-11-01 15:11:25 -04:00
|
|
|
|
#include "SmartObjectAnnotation.h"
|
|
|
|
|
|
#include "SmartObjectVisualizationContext.h"
|
2023-01-23 12:48:16 -05:00
|
|
|
|
#include "Misc/EnumerateRange.h"
|
2023-01-18 06:27:31 -05:00
|
|
|
|
#include "Settings/EditorStyleSettings.h"
|
2022-11-01 15:11:25 -04:00
|
|
|
|
|
|
|
|
|
|
IMPLEMENT_HIT_PROXY(HSmartObjectSlotProxy, HComponentVisProxy);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace UE::SmartObjects::Editor
|
|
|
|
|
|
{
|
|
|
|
|
|
|
2023-03-14 06:26:29 -04:00
|
|
|
|
void Draw(const USmartObjectDefinition& Definition, TConstArrayView<FSelectedItem> Selection, const FTransform& OwnerLocalToWorld, const FSceneView& View, FPrimitiveDrawInterface& PDI, const UWorld& World, const AActor* PreviewActor)
|
2022-11-01 15:11:25 -04:00
|
|
|
|
{
|
2023-03-14 06:26:29 -04:00
|
|
|
|
constexpr float DepthBias = 2.0f;
|
|
|
|
|
|
constexpr bool Screenspace = true;
|
|
|
|
|
|
|
2023-03-02 05:58:30 -05:00
|
|
|
|
FSmartObjectVisualizationContext VisContext(Definition, World);
|
2022-11-01 15:11:25 -04:00
|
|
|
|
VisContext.OwnerLocalToWorld = OwnerLocalToWorld;
|
|
|
|
|
|
VisContext.View = &View;
|
|
|
|
|
|
VisContext.PDI = &PDI;
|
|
|
|
|
|
VisContext.Font = GEngine->GetSmallFont();
|
2023-01-18 06:27:31 -05:00
|
|
|
|
VisContext.SelectedColor = GetDefault<UEditorStyleSettings>()->SelectionColor;
|
2023-03-14 06:26:29 -04:00
|
|
|
|
VisContext.PreviewActor = PreviewActor;
|
2022-11-01 15:11:25 -04:00
|
|
|
|
|
|
|
|
|
|
if (!VisContext.IsValidForDraw())
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-18 06:27:31 -05:00
|
|
|
|
FLinearColor Color = FColor::White;
|
2022-11-01 15:11:25 -04:00
|
|
|
|
FGuid SlotID;
|
|
|
|
|
|
bool bIsSelected = false;
|
|
|
|
|
|
|
2022-11-02 11:58:09 -04:00
|
|
|
|
const TConstArrayView<FSmartObjectSlotDefinition> Slots = Definition.GetSlots();
|
2023-01-23 12:48:16 -05:00
|
|
|
|
for (TConstEnumerateRef<FSmartObjectSlotDefinition> Slot : EnumerateRange(Slots))
|
2022-11-01 15:11:25 -04:00
|
|
|
|
{
|
2023-01-18 06:27:31 -05:00
|
|
|
|
constexpr FVector::FReal DebugCylinderRadius = 40.0;
|
|
|
|
|
|
constexpr FVector::FReal TickSize = 10.0;
|
|
|
|
|
|
|
2023-01-23 12:48:16 -05:00
|
|
|
|
TOptional<FTransform> Transform = Definition.GetSlotTransform(OwnerLocalToWorld, FSmartObjectSlotIndex(Slot.GetIndex()));
|
2022-11-01 15:11:25 -04:00
|
|
|
|
if (!Transform.IsSet())
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
bIsSelected = false;
|
2023-03-02 05:58:30 -05:00
|
|
|
|
float SlotSize = DebugCylinderRadius;
|
|
|
|
|
|
ESmartObjectSlotShape SlotShape = ESmartObjectSlotShape::Circle;
|
|
|
|
|
|
|
2022-11-01 15:11:25 -04:00
|
|
|
|
#if WITH_EDITORONLY_DATA
|
2023-01-23 12:48:16 -05:00
|
|
|
|
Color = Slot->bEnabled ? Slot->DEBUG_DrawColor : FColor::Silver;
|
|
|
|
|
|
SlotID = Slot->ID;
|
2023-03-02 05:58:30 -05:00
|
|
|
|
SlotShape = Slot->DEBUG_DrawShape;
|
|
|
|
|
|
SlotSize = Slot->DEBUG_DrawSize;
|
2022-11-01 15:11:25 -04:00
|
|
|
|
|
2023-01-23 12:48:16 -05:00
|
|
|
|
if (Selection.Contains(FSelectedItem(Slot->ID)))
|
2022-11-01 15:11:25 -04:00
|
|
|
|
{
|
2023-01-18 06:27:31 -05:00
|
|
|
|
Color = VisContext.SelectedColor;
|
2022-11-01 15:11:25 -04:00
|
|
|
|
bIsSelected = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
PDI.SetHitProxy(new HSmartObjectSlotProxy(/*Component*/nullptr, SlotID));
|
|
|
|
|
|
|
|
|
|
|
|
{
|
2023-01-18 06:27:31 -05:00
|
|
|
|
const FVector Location = Transform->GetLocation();
|
|
|
|
|
|
const FVector AxisX = Transform->GetUnitAxis(EAxis::X);
|
|
|
|
|
|
const FVector AxisY = Transform->GetUnitAxis(EAxis::Y);
|
|
|
|
|
|
|
2023-01-21 19:01:11 -05:00
|
|
|
|
// Arrow with tick at base.
|
2023-03-14 06:26:29 -04:00
|
|
|
|
VisContext.DrawArrow(Location - AxisX * TickSize, Location + AxisX * SlotSize * 2.0, Color, /*ArrowHeadLength*/ 10.0f, /*EndLocationInset*/ 0.0f, SDPG_World, 2.0f, DepthBias, Screenspace);
|
|
|
|
|
|
PDI.DrawTranslucentLine(Location - AxisY * TickSize, Location + AxisY * TickSize, Color, SDPG_World, 1.0f, DepthBias, Screenspace);
|
2023-01-18 06:27:31 -05:00
|
|
|
|
|
|
|
|
|
|
// Circle and direction arrow.
|
2023-03-02 05:58:30 -05:00
|
|
|
|
if (SlotShape == ESmartObjectSlotShape::Circle)
|
|
|
|
|
|
{
|
2023-03-14 06:26:29 -04:00
|
|
|
|
DrawCircle(&PDI, Location, AxisX, AxisY, Color, SlotSize, /*NumSides*/64, SDPG_World, /*Thickness*/4.f, DepthBias, Screenspace);
|
2023-03-02 05:58:30 -05:00
|
|
|
|
}
|
|
|
|
|
|
else if (SlotShape == ESmartObjectSlotShape::Rectangle)
|
|
|
|
|
|
{
|
2023-03-14 06:26:29 -04:00
|
|
|
|
DrawRectangle(&PDI, Location, AxisX, AxisY, Color.ToFColor(/*bSRGB*/true), SlotSize * 2.0f, SlotSize * 2.0f, SDPG_World, /*Thickness*/4.f, DepthBias, Screenspace);
|
2023-03-02 05:58:30 -05:00
|
|
|
|
}
|
2023-01-18 06:27:31 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PDI.SetHitProxy(nullptr);
|
|
|
|
|
|
|
2023-01-23 12:48:16 -05:00
|
|
|
|
for (TConstEnumerateRef<FInstancedStruct> Data : EnumerateRange(Slot->Data))
|
2023-01-18 06:27:31 -05:00
|
|
|
|
{
|
2023-01-23 12:48:16 -05:00
|
|
|
|
if (const FSmartObjectSlotAnnotation* Annotation = Data->GetPtr<FSmartObjectSlotAnnotation>())
|
2022-11-01 15:11:25 -04:00
|
|
|
|
{
|
2023-01-23 12:48:16 -05:00
|
|
|
|
PDI.SetHitProxy(new HSmartObjectSlotProxy(/*Component*/nullptr, SlotID, Data.GetIndex()));
|
2023-01-18 06:27:31 -05:00
|
|
|
|
|
2023-01-23 12:48:16 -05:00
|
|
|
|
VisContext.SlotIndex = FSmartObjectSlotIndex(Slot.GetIndex());
|
2023-03-14 06:26:29 -04:00
|
|
|
|
VisContext.AnnotationIndex = Data.GetIndex();
|
2022-11-01 15:11:25 -04:00
|
|
|
|
VisContext.bIsSlotSelected = bIsSelected;
|
2023-01-23 12:48:16 -05:00
|
|
|
|
VisContext.bIsAnnotationSelected = Selection.Contains(FSelectedItem(Slot->ID, Data.GetIndex()));
|
2022-11-01 15:11:25 -04:00
|
|
|
|
|
|
|
|
|
|
Annotation->DrawVisualization(VisContext);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-03-14 06:26:29 -04:00
|
|
|
|
void DrawCanvas(const USmartObjectDefinition& Definition, TConstArrayView<FSelectedItem> Selection, const FTransform& OwnerLocalToWorld, const FSceneView& View, FCanvas& Canvas, const UWorld& World, const AActor* PreviewActor)
|
2022-11-01 15:11:25 -04:00
|
|
|
|
{
|
2023-03-02 05:58:30 -05:00
|
|
|
|
FSmartObjectVisualizationContext VisContext(Definition, World);
|
2022-11-01 15:11:25 -04:00
|
|
|
|
VisContext.OwnerLocalToWorld = OwnerLocalToWorld;
|
|
|
|
|
|
VisContext.View = &View;
|
|
|
|
|
|
VisContext.Canvas = &Canvas;
|
|
|
|
|
|
VisContext.Font = GEngine->GetSmallFont();
|
2023-01-18 06:27:31 -05:00
|
|
|
|
VisContext.SelectedColor = GetDefault<UEditorStyleSettings>()->SelectionColor;
|
2023-03-14 06:26:29 -04:00
|
|
|
|
VisContext.PreviewActor = PreviewActor;
|
2022-11-01 15:11:25 -04:00
|
|
|
|
|
|
|
|
|
|
if (!VisContext.IsValidForDrawHUD())
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FColor Color = FColor::White;
|
|
|
|
|
|
bool bIsSelected = false;
|
|
|
|
|
|
|
2022-11-02 11:58:09 -04:00
|
|
|
|
const TConstArrayView<FSmartObjectSlotDefinition> Slots = Definition.GetSlots();
|
2023-01-23 12:48:16 -05:00
|
|
|
|
for (TConstEnumerateRef<FSmartObjectSlotDefinition> Slot : EnumerateRange(Slots))
|
2022-11-01 15:11:25 -04:00
|
|
|
|
{
|
2023-01-23 12:48:16 -05:00
|
|
|
|
TOptional<FTransform> Transform = Definition.GetSlotTransform(OwnerLocalToWorld, FSmartObjectSlotIndex(Slot.GetIndex()));
|
2022-11-01 15:11:25 -04:00
|
|
|
|
if (!Transform.IsSet())
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bIsSelected = false;
|
|
|
|
|
|
#if WITH_EDITORONLY_DATA
|
2023-01-23 12:48:16 -05:00
|
|
|
|
Color = Slot->bEnabled ? Slot->DEBUG_DrawColor : FColor::Silver;
|
2022-11-01 15:11:25 -04:00
|
|
|
|
|
2023-01-23 12:48:16 -05:00
|
|
|
|
if (Selection.Contains(Slot->ID))
|
2022-11-01 15:11:25 -04:00
|
|
|
|
{
|
|
|
|
|
|
Color = FColor::Red;
|
|
|
|
|
|
bIsSelected = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// Slot name
|
|
|
|
|
|
const FVector SlotLocation = Transform->GetLocation();
|
2023-01-23 12:48:16 -05:00
|
|
|
|
VisContext.DrawString(SlotLocation, *Slot->Name.ToString(), Color);
|
2022-11-01 15:11:25 -04:00
|
|
|
|
|
|
|
|
|
|
// Slot data annotations
|
2023-01-23 12:48:16 -05:00
|
|
|
|
for (TConstEnumerateRef<FInstancedStruct> Data : EnumerateRange(Slot->Data))
|
2022-11-01 15:11:25 -04:00
|
|
|
|
{
|
2023-01-23 12:48:16 -05:00
|
|
|
|
if (const FSmartObjectSlotAnnotation* Annotation = Data->GetPtr<FSmartObjectSlotAnnotation>())
|
2022-11-01 15:11:25 -04:00
|
|
|
|
{
|
2023-01-23 12:48:16 -05:00
|
|
|
|
VisContext.SlotIndex = FSmartObjectSlotIndex(Slot.GetIndex());
|
2023-03-14 06:26:29 -04:00
|
|
|
|
VisContext.AnnotationIndex = Data.GetIndex();
|
2022-11-01 15:11:25 -04:00
|
|
|
|
VisContext.bIsSlotSelected = bIsSelected;
|
2023-01-23 12:48:16 -05:00
|
|
|
|
VisContext.bIsAnnotationSelected = Selection.Contains(FSelectedItem(Slot->ID, Data.GetIndex()));
|
2022-11-01 15:11:25 -04:00
|
|
|
|
|
|
|
|
|
|
Annotation->DrawVisualizationHUD(VisContext);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}; // UE::SmartObjects::Editor
|
2022-01-24 11:36:13 -05:00
|
|
|
|
|
|
|
|
|
|
void FSmartObjectComponentVisualizer::DrawVisualization( const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI )
|
|
|
|
|
|
{
|
2022-11-01 15:11:25 -04:00
|
|
|
|
if (View == nullptr || PDI == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-01-24 11:36:13 -05:00
|
|
|
|
const USmartObjectComponent* SOComp = Cast<const USmartObjectComponent>(Component);
|
|
|
|
|
|
if (SOComp == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const USmartObjectDefinition* Definition = SOComp->GetDefinition();
|
|
|
|
|
|
if (Definition == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-01 15:11:25 -04:00
|
|
|
|
const FTransform OwnerLocalToWorld = SOComp->GetComponentTransform();
|
|
|
|
|
|
|
2023-03-14 06:26:29 -04:00
|
|
|
|
UE::SmartObjects::Editor::Draw(*Definition, {}, OwnerLocalToWorld, *View, *PDI, *Component->GetWorld(), Component->GetOwner());
|
2022-11-01 15:11:25 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FSmartObjectComponentVisualizer::DrawVisualizationHUD(const UActorComponent* Component, const FViewport* Viewport, const FSceneView* View, FCanvas* Canvas)
|
|
|
|
|
|
{
|
2022-11-02 11:58:09 -04:00
|
|
|
|
if (View == nullptr || Canvas == nullptr)
|
2022-11-01 15:11:25 -04:00
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const USmartObjectComponent* SOComp = Cast<const USmartObjectComponent>(Component);
|
|
|
|
|
|
if (SOComp == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const USmartObjectDefinition* Definition = SOComp->GetDefinition();
|
|
|
|
|
|
if (Definition == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2022-01-24 11:36:13 -05:00
|
|
|
|
|
|
|
|
|
|
const FTransform OwnerLocalToWorld = SOComp->GetComponentTransform();
|
|
|
|
|
|
|
2023-03-14 06:26:29 -04:00
|
|
|
|
UE::SmartObjects::Editor::DrawCanvas(*Definition, {}, OwnerLocalToWorld, *View, *Canvas, *Component->GetWorld(), Component->GetOwner());
|
2022-01-24 11:36:13 -05:00
|
|
|
|
}
|