ModelingTools: replace StorableSelection mechanism with new UPersistentMeshSelection and UPersistentMeshSelectionManager context object.
- UPersistentMeshSelection is largely a port of UGroupTopologyStorableSelection, with the actual selection data moved to FGenericMeshSelection
- UPersistentMeshSelectionManager is meant to be used as a ContextObject in a ToolsContext, also contains utility functions to register/unregister/find context object
- Selection is no longer passed as part of FToolBuilderState. Instead Tools access the selection via ContextObject
- UPersistentMeshSelectionManager currently supports a single active selection. Selection changes are transacted via an FChange.
- When not inside a Tool, Selection is visualized with a pink border outline. Currently vertex selection is not visualized.
- Usage model is that on Tool Accept/Complete, prior to Tool Shutdown, any existing selection is cleared, and Tool may set a new Output selection which becomes the active selection
- StoredMeshSelectionUtil.h has utility functions to get current selection, set output selection, and clear it
- SingleSelectionMeshEditingTool already made input selection available to subclasses, port that capability to new architecture
- convert EditMeshPolygonsTool to be a SingleSelectionMeshEditingTool, use provided Input selection and set Output selection as appropriate
- ModelingToolsEditorMode clears active selection where appropriate, eg if selected object changes. However the behavior here will need further improvement, currently relies on questionable event handling from the TypedElement system
#rb semion.piskarev
#rnx
#jira none
#preflight 6136cbbfd9c85a0001fc3b56
#ROBOMERGE-AUTHOR: ryan.schmidt
#ROBOMERGE-SOURCE: CL 17441056 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v870-17433530)
[CL 17441061 by ryan schmidt in ue5-release-engine-test branch]
2021-09-06 23:05:07 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
#include "Selection/PersistentMeshSelectionManager.h"
|
|
|
|
|
#include "Selection/PersistentMeshSelection.h"
|
|
|
|
|
|
|
|
|
|
#include "InteractiveToolsContext.h"
|
|
|
|
|
#include "InteractiveToolManager.h"
|
|
|
|
|
#include "ContextObjectStore.h"
|
|
|
|
|
#include "Drawing/PreviewGeometryActor.h"
|
|
|
|
|
|
|
|
|
|
using namespace UE::Geometry;
|
|
|
|
|
|
|
|
|
|
#define LOCTEXT_NAMESPACE "UPersistentMeshSelectionManager"
|
|
|
|
|
|
|
|
|
|
void UPersistentMeshSelectionManager::Initialize(TObjectPtr<UInteractiveToolsContext> ToolsContext)
|
|
|
|
|
{
|
|
|
|
|
ParentContext = ToolsContext;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UPersistentMeshSelectionManager::Shutdown()
|
|
|
|
|
{
|
|
|
|
|
if (SelectionDisplay != nullptr)
|
|
|
|
|
{
|
|
|
|
|
SelectionDisplay->Disconnect();
|
|
|
|
|
SelectionDisplay = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UPersistentMeshSelectionManager::HasActiveSelection()
|
|
|
|
|
{
|
|
|
|
|
return (ActiveSelection != nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UPersistentMeshSelection* UPersistentMeshSelectionManager::GetActiveSelection()
|
|
|
|
|
{
|
|
|
|
|
return ActiveSelection;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UPersistentMeshSelectionManager::SetNewActiveSelection(UPersistentMeshSelection* Selection)
|
|
|
|
|
{
|
|
|
|
|
TUniquePtr<FPersistentMeshSelectionChange> SelectionChange = MakeUnique<FPersistentMeshSelectionChange>();
|
|
|
|
|
if (ActiveSelection != nullptr)
|
|
|
|
|
{
|
|
|
|
|
SelectionChange->From = ActiveSelection->GetSelection();
|
|
|
|
|
}
|
|
|
|
|
if (Selection != nullptr)
|
|
|
|
|
{
|
|
|
|
|
SelectionChange->To = Selection->GetSelection();
|
|
|
|
|
}
|
|
|
|
|
ParentContext->ToolManager->GetContextTransactionsAPI()->AppendChange(this, MoveTemp(SelectionChange),
|
|
|
|
|
LOCTEXT("SelectionChange", "Selection Change"));
|
|
|
|
|
|
|
|
|
|
ActiveSelection = Selection;
|
|
|
|
|
OnSelectionModified();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void UPersistentMeshSelectionManager::SetNewActiveSelectionInternal(UPersistentMeshSelection* Selection)
|
|
|
|
|
{
|
|
|
|
|
ActiveSelection = Selection;
|
|
|
|
|
OnSelectionModified();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void UPersistentMeshSelectionManager::ClearActiveSelection()
|
|
|
|
|
{
|
|
|
|
|
if (ActiveSelection == nullptr)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetNewActiveSelection(nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void UPersistentMeshSelectionManager::OnSelectionModified()
|
|
|
|
|
{
|
|
|
|
|
if (ActiveSelection != nullptr && SelectionDisplay == nullptr)
|
|
|
|
|
{
|
|
|
|
|
SelectionDisplay = NewObject<UPreviewGeometry>(ParentContext);
|
|
|
|
|
SelectionDisplay->CreateInWorld(ActiveSelection->GetTargetComponent()->GetWorld(), FTransform::Identity);
|
|
|
|
|
}
|
|
|
|
|
if (SelectionDisplay == nullptr)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FGenericMeshSelection* SelectionData = (ActiveSelection != nullptr) ? &ActiveSelection->GetSelection() : nullptr;
|
|
|
|
|
|
|
|
|
|
bool bShowLines = (SelectionData != nullptr) && (SelectionData->HasRenderableLines());
|
|
|
|
|
|
|
|
|
|
if (bShowLines)
|
|
|
|
|
{
|
|
|
|
|
const FColor ROIBorderColor(240, 15, 240);
|
|
|
|
|
const float ROIBorderThickness = 8.0f;
|
|
|
|
|
//const float ROIBorderDepthBias = 0.1f * (float)(WorldBounds.DiagonalLength() * 0.01);
|
|
|
|
|
const float ROIBorderDepthBias = 0.01f;
|
|
|
|
|
|
2022-01-29 14:37:53 -05:00
|
|
|
FTransform3d Transform(ActiveSelection->GetTargetComponent()->GetComponentToWorld());
|
ModelingTools: replace StorableSelection mechanism with new UPersistentMeshSelection and UPersistentMeshSelectionManager context object.
- UPersistentMeshSelection is largely a port of UGroupTopologyStorableSelection, with the actual selection data moved to FGenericMeshSelection
- UPersistentMeshSelectionManager is meant to be used as a ContextObject in a ToolsContext, also contains utility functions to register/unregister/find context object
- Selection is no longer passed as part of FToolBuilderState. Instead Tools access the selection via ContextObject
- UPersistentMeshSelectionManager currently supports a single active selection. Selection changes are transacted via an FChange.
- When not inside a Tool, Selection is visualized with a pink border outline. Currently vertex selection is not visualized.
- Usage model is that on Tool Accept/Complete, prior to Tool Shutdown, any existing selection is cleared, and Tool may set a new Output selection which becomes the active selection
- StoredMeshSelectionUtil.h has utility functions to get current selection, set output selection, and clear it
- SingleSelectionMeshEditingTool already made input selection available to subclasses, port that capability to new architecture
- convert EditMeshPolygonsTool to be a SingleSelectionMeshEditingTool, use provided Input selection and set Output selection as appropriate
- ModelingToolsEditorMode clears active selection where appropriate, eg if selected object changes. However the behavior here will need further improvement, currently relies on questionable event handling from the TypedElement system
#rb semion.piskarev
#rnx
#jira none
#preflight 6136cbbfd9c85a0001fc3b56
#ROBOMERGE-AUTHOR: ryan.schmidt
#ROBOMERGE-SOURCE: CL 17441056 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v870-17433530)
[CL 17441061 by ryan schmidt in ue5-release-engine-test branch]
2021-09-06 23:05:07 -04:00
|
|
|
|
|
|
|
|
const TArray<UE::Geometry::FSegment3d>& Lines = SelectionData->RenderEdges;
|
|
|
|
|
SelectionDisplay->CreateOrUpdateLineSet(TEXT("SelectionEdges"), Lines.Num(),
|
|
|
|
|
[&](int32 Index, TArray<FRenderableLine>& LinesOut)
|
|
|
|
|
{
|
|
|
|
|
const UE::Geometry::FSegment3d& Segment = Lines[Index];
|
|
|
|
|
FVector3d A = Transform.TransformPosition(Segment.StartPoint());
|
|
|
|
|
FVector3d B = Transform.TransformPosition(Segment.EndPoint());
|
|
|
|
|
LinesOut.Add(FRenderableLine((FVector)A, (FVector)B, ROIBorderColor, ROIBorderThickness, ROIBorderDepthBias));
|
|
|
|
|
}, 1);
|
|
|
|
|
|
|
|
|
|
SelectionDisplay->SetLineSetVisibility(TEXT("SelectionEdges"), true);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SelectionDisplay->SetLineSetVisibility(TEXT("SelectionEdges"), false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool UE::Geometry::RegisterPersistentMeshSelectionManager(UInteractiveToolsContext* ToolsContext)
|
|
|
|
|
{
|
|
|
|
|
if (ensure(ToolsContext))
|
|
|
|
|
{
|
|
|
|
|
UPersistentMeshSelectionManager* Found = ToolsContext->ContextObjectStore->FindContext<UPersistentMeshSelectionManager>();
|
|
|
|
|
if (Found == nullptr)
|
|
|
|
|
{
|
|
|
|
|
UPersistentMeshSelectionManager* SelectionManager = NewObject<UPersistentMeshSelectionManager>(ToolsContext->ToolManager);
|
|
|
|
|
if (ensure(SelectionManager))
|
|
|
|
|
{
|
|
|
|
|
SelectionManager->Initialize(ToolsContext);
|
|
|
|
|
ToolsContext->ContextObjectStore->AddContextObject(SelectionManager);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool UE::Geometry::DeregisterPersistentMeshSelectionManager(UInteractiveToolsContext* ToolsContext)
|
|
|
|
|
{
|
|
|
|
|
if (ensure(ToolsContext))
|
|
|
|
|
{
|
|
|
|
|
UPersistentMeshSelectionManager* Found = ToolsContext->ContextObjectStore->FindContext<UPersistentMeshSelectionManager>();
|
|
|
|
|
if (Found != nullptr)
|
|
|
|
|
{
|
|
|
|
|
Found->Shutdown();
|
|
|
|
|
ToolsContext->ContextObjectStore->RemoveContextObject(Found);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UPersistentMeshSelectionManager* UE::Geometry::FindPersistentMeshSelectionManager(UInteractiveToolManager* ToolManager)
|
|
|
|
|
{
|
|
|
|
|
if (ensure(ToolManager))
|
|
|
|
|
{
|
|
|
|
|
UPersistentMeshSelectionManager* Found = ToolManager->GetContextObjectStore()->FindContext<UPersistentMeshSelectionManager>();
|
|
|
|
|
if (Found != nullptr)
|
|
|
|
|
{
|
|
|
|
|
return Found;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FPersistentMeshSelectionChange::Apply(UObject* Object)
|
|
|
|
|
{
|
|
|
|
|
UPersistentMeshSelectionManager* SelectionManager = Cast<UPersistentMeshSelectionManager>(Object);
|
|
|
|
|
if (SelectionManager)
|
|
|
|
|
{
|
|
|
|
|
UPersistentMeshSelection* NewSelection = NewObject<UPersistentMeshSelection>(SelectionManager);
|
|
|
|
|
NewSelection->SetSelection(To);
|
|
|
|
|
SelectionManager->SetNewActiveSelectionInternal(NewSelection);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FPersistentMeshSelectionChange::Revert(UObject* Object)
|
|
|
|
|
{
|
|
|
|
|
UPersistentMeshSelectionManager* SelectionManager = Cast<UPersistentMeshSelectionManager>(Object);
|
|
|
|
|
if (SelectionManager)
|
|
|
|
|
{
|
|
|
|
|
UPersistentMeshSelection* NewSelection = NewObject<UPersistentMeshSelection>(SelectionManager);
|
|
|
|
|
NewSelection->SetSelection(From);
|
|
|
|
|
SelectionManager->SetNewActiveSelectionInternal(NewSelection);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FPersistentMeshSelectionChange::HasExpired(UObject* Object) const
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FString FPersistentMeshSelectionChange::ToString() const
|
|
|
|
|
{
|
|
|
|
|
return TEXT("PersistentMeshSelectionChange");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|