2022-07-15 13:49:13 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
#include "Commands/DeleteGeometrySelectionCommand.h"
|
|
|
|
|
#include "ToolContextInterfaces.h"
|
|
|
|
|
#include "UDynamicMesh.h"
|
|
|
|
|
#include "DynamicMesh/DynamicMesh3.h"
|
|
|
|
|
#include "DynamicMesh/DynamicMeshChangeTracker.h"
|
|
|
|
|
#include "DynamicMeshEditor.h"
|
2024-09-10 10:26:02 -04:00
|
|
|
#include "FaceGroupUtil.h"
|
2022-07-15 13:49:13 -04:00
|
|
|
#include "Changes/MeshChange.h"
|
2022-07-15 17:53:52 -04:00
|
|
|
#include "Selections/GeometrySelectionUtil.h"
|
ModelingMode: selection system bugfixes & improvements.
Add DynamicMeshSelector::UpdateAfterGeometryEdit API. StaticMeshSelector implementation updates static mesh after an Edit instead of emitting MeshChange on temporary DynamicMesh.
Delete and Retriangulate Commands now use this API instead of directly emitting transaction, so now these commands work properly on Static Meshes.
FStaticMeshComponentSelectorFactory::CanBuildForTarget now only allows UStaticMeshComponent specifically, filtering out subclasses. This is not ideal but I don't know what else we can do for now, there are many subclasses like ISMC, SplineMeshComponent, etc, that will not work w/ the Selection system. Also now filtering out Engine assets and cooked assets.
ModelingToolsEditorMode now listens for blueprint pre-compiles, and when this occurs, clears the active selection and selection targets. This is necessary because if the selection Component was part of a BP, on recompile it is re-instanced and the old pointer goes stale. Possibly can handle this better or at a more granular level, but clearing the selection is safest. This currently results in things not being undoable because the FChange transactions are on the "old" UDynamicMesh that no longer exists.
UModelingToolsEditorMode::UpdateSelectionManagerOnEditorSelectionChange now does a more thorough job of inspecting the current Actor/Component selection to find Components that could work w/ the selection system.
#rb lonnie.li
[CL 26133067 by ryan schmidt in ue5-main branch]
2023-06-20 16:23:43 -04:00
|
|
|
#include "Selection/DynamicMeshSelector.h"
|
2024-09-10 10:26:02 -04:00
|
|
|
#include "Selections/MeshConnectedComponents.h"
|
2022-07-15 13:49:13 -04:00
|
|
|
|
2022-11-22 20:17:33 -05:00
|
|
|
#include UE_INLINE_GENERATED_CPP_BY_NAME(DeleteGeometrySelectionCommand)
|
|
|
|
|
|
2022-07-15 13:49:13 -04:00
|
|
|
using namespace UE::Geometry;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define LOCTEXT_NAMESPACE "UDeleteGeometrySelectionCommand"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FText UDeleteGeometrySelectionCommand::GetCommandShortString() const
|
|
|
|
|
{
|
|
|
|
|
return LOCTEXT("ShortString", "Delete Selection");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool UDeleteGeometrySelectionCommand::CanExecuteCommandForSelection(UGeometrySelectionEditCommandArguments* SelectionArgs)
|
|
|
|
|
{
|
|
|
|
|
return SelectionArgs->IsMatchingType(FGeometryIdentifier::ETargetType::MeshContainer, FGeometryIdentifier::EObjectType::DynamicMesh);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
ModelingMode: Selection system improvements. Add Disconnect command and various new Selection-Edit Commands
Add UInteractiveCommandResult, UInteractiveCommand::ExecuteCommand() now optionally can return a result subclass
Add UGeometrySelectionEditCommandResult, UGeometrySelectionEditCommand now can optionally return an "output" selection via this type
UGeometrySelectionManager::ExecuteSelectionCommand optionally can restore a selection after a command, via UGeometrySelectionEditCommandResult
Add UDisconnectGeometrySelectionCommand, implements disconnection of selected triangles (ie separates but not into a new mesh)
Add UModifyGeometrySelectionCommand, implements various selection edits (select all, expand to connected, invert, invert connected, expand, contract)
Add IGeometrySelector::InitializeSelectionFromPredicate() and ::UpdateSelectionFromSelection(), implement in UDynamicMeshSelector, used to implement selection edit commands
Add UI to enable new commands in Modeling Mode
#rb none
#preflight 63c047f4305002c64170f6a2
[CL 23667880 by ryan schmidt in ue5-main branch]
2023-01-12 14:52:52 -05:00
|
|
|
void UDeleteGeometrySelectionCommand::ExecuteCommandForSelection(UGeometrySelectionEditCommandArguments* SelectionArgs, UInteractiveCommandResult** Result)
|
2022-07-15 13:49:13 -04:00
|
|
|
{
|
ModelingMode: selection system bugfixes & improvements.
Add DynamicMeshSelector::UpdateAfterGeometryEdit API. StaticMeshSelector implementation updates static mesh after an Edit instead of emitting MeshChange on temporary DynamicMesh.
Delete and Retriangulate Commands now use this API instead of directly emitting transaction, so now these commands work properly on Static Meshes.
FStaticMeshComponentSelectorFactory::CanBuildForTarget now only allows UStaticMeshComponent specifically, filtering out subclasses. This is not ideal but I don't know what else we can do for now, there are many subclasses like ISMC, SplineMeshComponent, etc, that will not work w/ the Selection system. Also now filtering out Engine assets and cooked assets.
ModelingToolsEditorMode now listens for blueprint pre-compiles, and when this occurs, clears the active selection and selection targets. This is necessary because if the selection Component was part of a BP, on recompile it is re-instanced and the old pointer goes stale. Possibly can handle this better or at a more granular level, but clearing the selection is safest. This currently results in things not being undoable because the FChange transactions are on the "old" UDynamicMesh that no longer exists.
UModelingToolsEditorMode::UpdateSelectionManagerOnEditorSelectionChange now does a more thorough job of inspecting the current Actor/Component selection to find Components that could work w/ the selection system.
#rb lonnie.li
[CL 26133067 by ryan schmidt in ue5-main branch]
2023-06-20 16:23:43 -04:00
|
|
|
IGeometrySelector* BaseSelector = SelectionArgs->SelectionHandle.Selector;
|
|
|
|
|
if (!ensure(BaseSelector != nullptr))
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogGeometry, Warning, TEXT("UDeleteGeometrySelectionCommand: Delete Selection requires Selector be provided in Selection Arguments"));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
ModelingMode: Selection system improvements. Add Disconnect command and various new Selection-Edit Commands
Add UInteractiveCommandResult, UInteractiveCommand::ExecuteCommand() now optionally can return a result subclass
Add UGeometrySelectionEditCommandResult, UGeometrySelectionEditCommand now can optionally return an "output" selection via this type
UGeometrySelectionManager::ExecuteSelectionCommand optionally can restore a selection after a command, via UGeometrySelectionEditCommandResult
Add UDisconnectGeometrySelectionCommand, implements disconnection of selected triangles (ie separates but not into a new mesh)
Add UModifyGeometrySelectionCommand, implements various selection edits (select all, expand to connected, invert, invert connected, expand, contract)
Add IGeometrySelector::InitializeSelectionFromPredicate() and ::UpdateSelectionFromSelection(), implement in UDynamicMeshSelector, used to implement selection edit commands
Add UI to enable new commands in Modeling Mode
#rb none
#preflight 63c047f4305002c64170f6a2
[CL 23667880 by ryan schmidt in ue5-main branch]
2023-01-12 14:52:52 -05:00
|
|
|
// delete never returns a new selection
|
|
|
|
|
if (Result != nullptr)
|
|
|
|
|
{
|
|
|
|
|
*Result = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-15 13:49:13 -04:00
|
|
|
// should have been verified by CanExecute
|
|
|
|
|
check(SelectionArgs->IsMatchingType(FGeometryIdentifier::ETargetType::MeshContainer, FGeometryIdentifier::EObjectType::DynamicMesh));
|
ModelingMode: selection system bugfixes & improvements.
Add DynamicMeshSelector::UpdateAfterGeometryEdit API. StaticMeshSelector implementation updates static mesh after an Edit instead of emitting MeshChange on temporary DynamicMesh.
Delete and Retriangulate Commands now use this API instead of directly emitting transaction, so now these commands work properly on Static Meshes.
FStaticMeshComponentSelectorFactory::CanBuildForTarget now only allows UStaticMeshComponent specifically, filtering out subclasses. This is not ideal but I don't know what else we can do for now, there are many subclasses like ISMC, SplineMeshComponent, etc, that will not work w/ the Selection system. Also now filtering out Engine assets and cooked assets.
ModelingToolsEditorMode now listens for blueprint pre-compiles, and when this occurs, clears the active selection and selection targets. This is necessary because if the selection Component was part of a BP, on recompile it is re-instanced and the old pointer goes stale. Possibly can handle this better or at a more granular level, but clearing the selection is safest. This currently results in things not being undoable because the FChange transactions are on the "old" UDynamicMesh that no longer exists.
UModelingToolsEditorMode::UpdateSelectionManagerOnEditorSelectionChange now does a more thorough job of inspecting the current Actor/Component selection to find Components that could work w/ the selection system.
#rb lonnie.li
[CL 26133067 by ryan schmidt in ue5-main branch]
2023-06-20 16:23:43 -04:00
|
|
|
|
|
|
|
|
// TODO: extremely hardcoded behavior right here. Need a way to make this more generic, however
|
|
|
|
|
// having the UpdateAfterGeometryEdit function in the base GeometrySelector does not make sense as
|
|
|
|
|
// it is specific to meshes. Probably this Command needs to be specialized for Mesh Edits.
|
|
|
|
|
FBaseDynamicMeshSelector* BaseDynamicMeshSelector = static_cast<FBaseDynamicMeshSelector*>(BaseSelector);
|
|
|
|
|
|
2022-07-15 13:49:13 -04:00
|
|
|
// collect up all our inputs
|
|
|
|
|
UDynamicMesh* MeshObject = SelectionArgs->SelectionHandle.Identifier.GetAsObjectType<UDynamicMesh>();
|
|
|
|
|
check(MeshObject != nullptr);
|
|
|
|
|
const FGeometrySelection* Selection = SelectionArgs->SelectionHandle.Selection;
|
|
|
|
|
if (Selection->Selection.Num() == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-10 10:26:02 -04:00
|
|
|
const bool bTrackChanges = SelectionArgs->HasTransactionsAPI();
|
2022-07-15 13:49:13 -04:00
|
|
|
TUniquePtr<FDynamicMeshChange> DynamicMeshChange; // only initialized if bTrackChanges == true
|
|
|
|
|
|
|
|
|
|
// apply the delete operation
|
|
|
|
|
MeshObject->EditMesh([&](FDynamicMesh3& EditMesh)
|
|
|
|
|
{
|
|
|
|
|
FDynamicMeshChangeTracker ChangeTracker(&EditMesh);
|
2024-09-10 10:26:02 -04:00
|
|
|
|
|
|
|
|
// handles the case of deleting polygroup edge by merging adjoining groups to match behavior in PolyEdit
|
|
|
|
|
if (SelectionArgs->TopologyMode == UE::Geometry::EGeometryTopologyType::Polygroup
|
|
|
|
|
&& SelectionArgs->ElementType == UE::Geometry::EGeometryElementType::Edge)
|
2022-07-15 13:49:13 -04:00
|
|
|
{
|
2024-09-10 10:26:02 -04:00
|
|
|
FMeshConnectedComponents Components(&EditMesh);
|
|
|
|
|
|
|
|
|
|
// retrieve all selected edges
|
|
|
|
|
TSet<int32> EdgeIDs;
|
|
|
|
|
UE::Geometry::EnumeratePolygroupSelectionEdges(*Selection, EditMesh, FPolygroupSet(&EditMesh),
|
|
|
|
|
[&](const int32 EdgeID) { EdgeIDs.Add(EdgeID); });
|
|
|
|
|
|
|
|
|
|
// similar but simplified version of work done in EnumeratePolygroupSelectionTriangles
|
|
|
|
|
// retrieves the TriIDs of the triangles adjacent to all edges in the PolyEdge as they will all be merged into one Polygroup
|
|
|
|
|
TSet<int32> SeedTriangleIDs;
|
|
|
|
|
for (int32 Edge : EdgeIDs.Array())
|
|
|
|
|
{
|
|
|
|
|
FIndex2i AdjacentTriangles = EditMesh.GetEdgeT(Edge);
|
|
|
|
|
EdgeIDs.Add(Edge);
|
|
|
|
|
SeedTriangleIDs.Add(AdjacentTriangles.A);
|
|
|
|
|
if (AdjacentTriangles.B != FDynamicMesh3::InvalidID)
|
|
|
|
|
{
|
|
|
|
|
SeedTriangleIDs.Add(AdjacentTriangles.B);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// retrieve the rest of the connected components which will be in the merged PolyGroup
|
|
|
|
|
Components.FindTrianglesConnectedToSeeds(SeedTriangleIDs.Array(), [&EditMesh, &EdgeIDs](const int32 Tri0, const int32 Tri1)
|
|
|
|
|
{
|
|
|
|
|
return EditMesh.GetTriangleGroup(Tri0) == EditMesh.GetTriangleGroup(Tri1) || EdgeIDs.Contains(EditMesh.FindEdgeFromTriPair(Tri0,Tri1));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// mark triangles for change
|
|
|
|
|
if (bTrackChanges)
|
|
|
|
|
{
|
|
|
|
|
ChangeTracker.BeginChange();
|
|
|
|
|
|
|
|
|
|
for (FMeshConnectedComponents::FComponent& Component : Components.Components)
|
|
|
|
|
{
|
|
|
|
|
ChangeTracker.SaveTriangles(Component.Indices, true);
|
|
|
|
|
int32 NewGroupID = EditMesh.GetTriangleGroup(Component.Indices[0]);
|
|
|
|
|
FaceGroupUtil::SetGroupID(EditMesh, Component.Indices, NewGroupID);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-15 13:49:13 -04:00
|
|
|
}
|
2024-09-10 10:26:02 -04:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// build list of triangles from whatever the selection contains
|
|
|
|
|
TSet<int32> TriangleList;
|
|
|
|
|
//UE::Geometry::FPolygroupSet UsePolygroupSet = ...; // need to support this eventually
|
|
|
|
|
UE::Geometry::EnumerateSelectionTriangles(*Selection, EditMesh,
|
|
|
|
|
[&](const int32 TriangleID) { TriangleList.Add(TriangleID); });
|
2022-07-15 13:49:13 -04:00
|
|
|
|
2024-09-10 10:26:02 -04:00
|
|
|
// mark triangles for change
|
|
|
|
|
if (bTrackChanges)
|
|
|
|
|
{
|
|
|
|
|
ChangeTracker.BeginChange();
|
|
|
|
|
ChangeTracker.SaveTriangles(TriangleList, true);
|
|
|
|
|
}
|
2022-07-15 13:49:13 -04:00
|
|
|
|
2024-09-10 10:26:02 -04:00
|
|
|
// actually delete them
|
|
|
|
|
FDynamicMeshEditor Editor(&EditMesh);
|
|
|
|
|
Editor.RemoveTriangles(TriangleList.Array(), true);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-15 13:49:13 -04:00
|
|
|
// extract the change record
|
|
|
|
|
if (bTrackChanges)
|
|
|
|
|
{
|
|
|
|
|
DynamicMeshChange = ChangeTracker.EndChange();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}, EDynamicMeshChangeType::GeneralEdit, EDynamicMeshAttributeChangeFlags::Unknown, false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// emit change
|
|
|
|
|
if ( bTrackChanges && DynamicMeshChange.IsValid() )
|
|
|
|
|
{
|
|
|
|
|
SelectionArgs->GetTransactionsAPI()->BeginUndoTransaction(GetCommandShortString());
|
ModelingMode: selection system bugfixes & improvements.
Add DynamicMeshSelector::UpdateAfterGeometryEdit API. StaticMeshSelector implementation updates static mesh after an Edit instead of emitting MeshChange on temporary DynamicMesh.
Delete and Retriangulate Commands now use this API instead of directly emitting transaction, so now these commands work properly on Static Meshes.
FStaticMeshComponentSelectorFactory::CanBuildForTarget now only allows UStaticMeshComponent specifically, filtering out subclasses. This is not ideal but I don't know what else we can do for now, there are many subclasses like ISMC, SplineMeshComponent, etc, that will not work w/ the Selection system. Also now filtering out Engine assets and cooked assets.
ModelingToolsEditorMode now listens for blueprint pre-compiles, and when this occurs, clears the active selection and selection targets. This is necessary because if the selection Component was part of a BP, on recompile it is re-instanced and the old pointer goes stale. Possibly can handle this better or at a more granular level, but clearing the selection is safest. This currently results in things not being undoable because the FChange transactions are on the "old" UDynamicMesh that no longer exists.
UModelingToolsEditorMode::UpdateSelectionManagerOnEditorSelectionChange now does a more thorough job of inspecting the current Actor/Component selection to find Components that could work w/ the selection system.
#rb lonnie.li
[CL 26133067 by ryan schmidt in ue5-main branch]
2023-06-20 16:23:43 -04:00
|
|
|
|
|
|
|
|
BaseDynamicMeshSelector->UpdateAfterGeometryEdit(
|
|
|
|
|
SelectionArgs->GetTransactionsAPI(), true, MoveTemp(DynamicMeshChange), GetCommandShortString());
|
|
|
|
|
|
2022-07-15 13:49:13 -04:00
|
|
|
SelectionArgs->GetTransactionsAPI()->EndUndoTransaction();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|