diff --git a/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorCommands.cpp b/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorCommands.cpp index 9aa557da2ee8..1922bce3b225 100644 --- a/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorCommands.cpp +++ b/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorCommands.cpp @@ -10,6 +10,24 @@ #define LOCTEXT_NAMESPACE "MeshEditorCommands" +namespace MeshEditorCommands +{ + const TArray& Get() + { + static UMeshEditorCommandList* MeshEditorCommandList = nullptr; + if( MeshEditorCommandList == nullptr ) + { + MeshEditorCommandList = NewObject(); + MeshEditorCommandList->AddToRoot(); + + MeshEditorCommandList->HarvestMeshEditorCommands(); + } + + return MeshEditorCommandList->MeshEditorCommands; + } +} + + FUIAction UMeshEditorInstantCommand::MakeUIAction( IMeshEditorModeUIContract& MeshEditorMode ) { const EEditableMeshElementType ElementType = GetElementType(); @@ -86,15 +104,11 @@ void FMeshEditorCommonCommands::RegisterCommands() UI_COMMAND(SetPolygonSelectionMode, "Set Polygon Selection Mode", "Sets the selection mode so that only polygons will be selected.", EUserInterfaceActionType::None, FInputChord(EKeys::Three)); UI_COMMAND(SetAnySelectionMode, "Set Any Selection Mode", "Sets the selection mode so that any element type may be selected.", EUserInterfaceActionType::None, FInputChord(EKeys::Four)); - for( TObjectIterator CommandCDOIter( RF_NoFlags ); CommandCDOIter; ++CommandCDOIter ) + for( UMeshEditorCommand* Command : MeshEditorCommands::Get() ) { - UMeshEditorCommand* CommandCDO = *CommandCDOIter; - if( !( CommandCDO->GetClass()->GetClassFlags() & CLASS_Abstract ) ) + if( Command->GetElementType() == EEditableMeshElementType::Invalid ) { - if( CommandCDO->GetElementType() == EEditableMeshElementType::Invalid ) - { - CommandCDO->RegisterUICommand( this ); - } + Command->RegisterUICommand( this ); } } } @@ -130,15 +144,11 @@ void FMeshEditorVertexCommands::RegisterCommands() UI_COMMAND(WeldVertices, "Weld Vertices", "Weld the selected vertices, keeping the first selected vertex.", EUserInterfaceActionType::Button, FInputChord()); - for( TObjectIterator CommandCDOIter( RF_NoFlags ); CommandCDOIter; ++CommandCDOIter ) + for( UMeshEditorCommand* Command : MeshEditorCommands::Get() ) { - UMeshEditorCommand* CommandCDO = *CommandCDOIter; - if( !( CommandCDO->GetClass()->GetClassFlags() & CLASS_Abstract ) ) + if( Command->GetElementType() == EEditableMeshElementType::Vertex ) { - if( CommandCDO->GetElementType() == EEditableMeshElementType::Vertex ) - { - CommandCDO->RegisterUICommand( this ); - } + Command->RegisterUICommand( this ); } } } @@ -159,15 +169,11 @@ void FMeshEditorEdgeCommands::RegisterCommands() UI_COMMAND(SelectEdgeLoop, "Select Edge Loop", "Select the edge loops which contain the selected edges.", EUserInterfaceActionType::Button, FInputChord(EKeys::Two, EModifierKey::Shift)); - for( TObjectIterator CommandCDOIter( RF_NoFlags ); CommandCDOIter; ++CommandCDOIter ) + for( UMeshEditorCommand* Command : MeshEditorCommands::Get() ) { - UMeshEditorCommand* CommandCDO = *CommandCDOIter; - if( !( CommandCDO->GetClass()->GetClassFlags() & CLASS_Abstract ) ) + if( Command->GetElementType() == EEditableMeshElementType::Edge ) { - if( CommandCDO->GetElementType() == EEditableMeshElementType::Edge ) - { - CommandCDO->RegisterUICommand( this ); - } + Command->RegisterUICommand( this ); } } } @@ -189,17 +195,28 @@ void FMeshEditorPolygonCommands::RegisterCommands() UI_COMMAND(TriangulatePolygon, "Triangulate Polygon", "Triangulate the currently selected polygons.", EUserInterfaceActionType::Button, FInputChord(EKeys::T)); UI_COMMAND(AssignMaterial, "Assign Material", "Assigns the highlighted material in the Content Browser to the currently selected polygons.", EUserInterfaceActionType::Button, FInputChord(EKeys::M)); + for( UMeshEditorCommand* Command : MeshEditorCommands::Get() ) + { + if( Command->GetElementType() == EEditableMeshElementType::Polygon ) + { + Command->RegisterUICommand( this ); + } + } +} + + +void UMeshEditorCommandList::HarvestMeshEditorCommands() +{ + MeshEditorCommands.Reset(); for( TObjectIterator CommandCDOIter( RF_NoFlags ); CommandCDOIter; ++CommandCDOIter ) { UMeshEditorCommand* CommandCDO = *CommandCDOIter; if( !( CommandCDO->GetClass()->GetClassFlags() & CLASS_Abstract ) ) { - if( CommandCDO->GetElementType() == EEditableMeshElementType::Polygon ) - { - CommandCDO->RegisterUICommand( this ); - } + MeshEditorCommands.Add( NewObject( this, CommandCDO->GetClass() ) ); } } } + #undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorMode.cpp b/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorMode.cpp index 28e8c0aa9026..46828ac645f9 100644 --- a/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorMode.cpp +++ b/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorMode.cpp @@ -575,39 +575,35 @@ void FMeshEditorMode::BindCommands() RegisterPolygonCommand( MeshEditorPolygonCommands.TriangulatePolygon, FExecuteAction::CreateLambda( [this] { TriangulateSelectedPolygons(); } ) ); RegisterPolygonCommand( MeshEditorPolygonCommands.AssignMaterial, FExecuteAction::CreateLambda( [this] { AssignSelectedMaterialToSelectedPolygons(); } ) ); - for( TObjectIterator CommandCDOIter( RF_NoFlags ); CommandCDOIter; ++CommandCDOIter ) + for( UMeshEditorCommand* Command : MeshEditorCommands::Get() ) { - UMeshEditorCommand* CommandCDO = *CommandCDOIter; - if( !( CommandCDO->GetClass()->GetClassFlags() & CLASS_Abstract ) ) + switch( Command->GetElementType() ) { - switch( CommandCDO->GetElementType() ) - { - case EEditableMeshElementType::Invalid: - { - // Common action - FUIAction UIAction = CommandCDO->MakeUIAction( *this ); - CommonActions.Emplace( CommandCDO->GetUICommandInfo(), UIAction ); - VertexActions.Emplace( CommandCDO->GetUICommandInfo(), UIAction ); - EdgeActions.Emplace( CommandCDO->GetUICommandInfo(), UIAction ); - PolygonActions.Emplace( CommandCDO->GetUICommandInfo(), UIAction ); - } - break; + case EEditableMeshElementType::Invalid: + { + // Common action + FUIAction UIAction = Command->MakeUIAction( *this ); + CommonActions.Emplace( Command->GetUICommandInfo(), UIAction ); + VertexActions.Emplace( Command->GetUICommandInfo(), UIAction ); + EdgeActions.Emplace( Command->GetUICommandInfo(), UIAction ); + PolygonActions.Emplace( Command->GetUICommandInfo(), UIAction ); + } + break; - case EEditableMeshElementType::Vertex: - VertexActions.Emplace( CommandCDO->GetUICommandInfo(), CommandCDO->MakeUIAction( *this ) ); - break; + case EEditableMeshElementType::Vertex: + VertexActions.Emplace( Command->GetUICommandInfo(), Command->MakeUIAction( *this ) ); + break; - case EEditableMeshElementType::Edge: - EdgeActions.Emplace( CommandCDO->GetUICommandInfo(), CommandCDO->MakeUIAction( *this ) ); - break; + case EEditableMeshElementType::Edge: + EdgeActions.Emplace( Command->GetUICommandInfo(), Command->MakeUIAction( *this ) ); + break; - case EEditableMeshElementType::Polygon: - PolygonActions.Emplace( CommandCDO->GetUICommandInfo(), CommandCDO->MakeUIAction( *this ) ); - break; + case EEditableMeshElementType::Polygon: + PolygonActions.Emplace( Command->GetUICommandInfo(), Command->MakeUIAction( *this ) ); + break; - default: - check( 0 ); - } + default: + check( 0 ); } } @@ -3249,16 +3245,16 @@ void FMeshEditorMode::UpdateActiveAction( const bool bIsActionFinishing ) { // Check for registered commands that are active right now bool bFoundValidCommand = false; - for( TObjectIterator CommandCDOIter( RF_NoFlags ); CommandCDOIter; ++CommandCDOIter ) + for( UMeshEditorCommand* Command : MeshEditorCommands::Get() ) { - UMeshEditorEditCommand* CommandCDO = *CommandCDOIter; - if( !( CommandCDO->GetClass()->GetClassFlags() & CLASS_Abstract ) ) + UMeshEditorEditCommand* EditCommand = Cast( Command ); + if( EditCommand != nullptr ) { - if( ActiveAction == CommandCDO->GetCommandName() ) + if( ActiveAction == EditCommand->GetCommandName() ) { - CommandCDO->ApplyDuringDrag( *this, ActiveActionInteractor ); + EditCommand->ApplyDuringDrag( *this, ActiveActionInteractor ); - bIsMovingSelectedMeshElements = CommandCDO->NeedsDraggingInitiated(); + bIsMovingSelectedMeshElements = EditCommand->NeedsDraggingInitiated(); // Should always only be one candidate bFoundValidCommand = true; @@ -3457,11 +3453,12 @@ void FMeshEditorMode::GetSelectedMeshesAndElements( EEditableMeshElementType Ele } -void FMeshEditorMode::FindEdgeSplitUnderInteractor( UViewportInteractor* ViewportInteractor, const UEditableMesh* EditableMesh, const TArray& EdgeElements, TArray& OutSplits ) +bool FMeshEditorMode::FindEdgeSplitUnderInteractor( UViewportInteractor* ViewportInteractor, const UEditableMesh* EditableMesh, const TArray& EdgeElements, FEdgeID& OutClosestEdgeID, float& OutSplit ) { check( ViewportInteractor != nullptr ); - OutSplits.Reset(); + OutClosestEdgeID = FEdgeID::Invalid; + bool bFoundSplit = false; // Figure out where to split based on where the interactor is aiming. We'll look at all of the // selected edges, and choose a split offset based on the closest point along one of those edges @@ -3513,11 +3510,14 @@ void FMeshEditorMode::FindEdgeSplitUnderInteractor( UViewportInteractor* Viewpor 1.0f ); } - OutSplits.Reset(); - OutSplits.Add( ProgressAlongEdge ); + bFoundSplit = true; + OutClosestEdgeID = EdgeID; + OutSplit = ProgressAlongEdge; } } } + + return bFoundSplit; } @@ -4016,10 +4016,10 @@ void FMeshEditorMode::OnViewportInteractionInputAction( FEditorViewportClient& V } else { - for( TObjectIterator CommandCDOIter( RF_NoFlags ); CommandCDOIter; ++CommandCDOIter ) + for( UMeshEditorCommand* Command : MeshEditorCommands::Get() ) { - UMeshEditorEditCommand* CommandCDO = *CommandCDOIter; - if( !( CommandCDO->GetClass()->GetClassFlags() & CLASS_Abstract ) ) + UMeshEditorEditCommand* EditCommand = Cast( Command ); + if( EditCommand != nullptr ) { FName EquippedAction = NAME_None; switch( SelectedMeshElementType ) @@ -4037,15 +4037,15 @@ void FMeshEditorMode::OnViewportInteractionInputAction( FEditorViewportClient& V break; } - const EEditableMeshElementType CommandElementType = CommandCDO->GetElementType(); - if( ( CommandElementType == SelectedMeshElementType || CommandElementType == EEditableMeshElementType::Invalid || CommandElementType == EEditableMeshElementType::Any ) && - EquippedAction == CommandCDO->GetCommandName() ) + const EEditableMeshElementType CommandElementType = EditCommand->GetElementType(); + if( ( CommandElementType == SelectedMeshElementType || CommandElementType == EEditableMeshElementType::Invalid || CommandElementType == EEditableMeshElementType::Any ) && + EquippedAction == EditCommand->GetCommandName() ) { - if( CommandCDO->TryStartingToDrag( *this, ViewportInteractor ) ) + if( EditCommand->TryStartingToDrag( *this, ViewportInteractor ) ) { - StartAction( EquippedAction, ViewportInteractor, CommandCDO->NeedsHoverLocation(), CommandCDO->GetUndoText() ); + StartAction( EquippedAction, ViewportInteractor, EditCommand->NeedsHoverLocation(), EditCommand->GetUndoText() ); - if( CommandCDO->NeedsDraggingInitiated() ) + if( EditCommand->NeedsDraggingInitiated() ) { bWantToStartMoving = true; } @@ -4909,13 +4909,9 @@ void FMeshEditorMode::MakeVRRadialMenuActionsMenu(FMenuBuilder& MenuBuilder, TSh ); } - for( TObjectIterator CommandCDOIter( RF_NoFlags ); CommandCDOIter; ++CommandCDOIter ) + for( UMeshEditorCommand* Command : MeshEditorCommands::Get() ) { - UMeshEditorCommand* CommandCDO = *CommandCDOIter; - if( !( CommandCDO->GetClass()->GetClassFlags() & CLASS_Abstract ) ) - { - CommandCDO->AddToVRRadialMenuActionsMenu( *this, MenuBuilder, CommandList, FMeshEditorStyle::GetStyleSetName(), VRMode ); - } + Command->AddToVRRadialMenuActionsMenu( *this, MenuBuilder, CommandList, FMeshEditorStyle::GetStyleSetName(), VRMode ); } } diff --git a/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorMode.h b/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorMode.h index 886cf499757c..ff25f1d4df88 100644 --- a/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorMode.h +++ b/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/MeshEditorMode.h @@ -197,7 +197,7 @@ protected: virtual void DeselectAllMeshElements() override; virtual void DeselectMeshElements( const TArray& MeshElementsToDeselect ) override; virtual void DeselectMeshElements( const TMap>& MeshElementsToDeselect ) override; - virtual void FindEdgeSplitUnderInteractor( UViewportInteractor* ViewportInteractor, const UEditableMesh* EditableMesh, const TArray& EdgeElements, TArray& OutSplits ) override; + virtual bool FindEdgeSplitUnderInteractor( UViewportInteractor* ViewportInteractor, const UEditableMesh* EditableMesh, const TArray& EdgeElements, FEdgeID& OutClosestEdgeID, float& OutSplit ) override; virtual class UViewportInteractor* GetActiveActionInteractor() override { return ActiveActionInteractor; diff --git a/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/Public/IMeshEditorModeEditingContract.h b/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/Public/IMeshEditorModeEditingContract.h index 43e448d2866a..e29a5c3e1569 100644 --- a/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/Public/IMeshEditorModeEditingContract.h +++ b/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/Public/IMeshEditorModeEditingContract.h @@ -52,8 +52,8 @@ public: /** Commits all selected meshes */ virtual void CommitSelectedMeshes() = 0; - /** Given an interactor and a mesh, finds edges under the interactor along with their exact split position (progress along the edge) */ - virtual void FindEdgeSplitUnderInteractor( class UViewportInteractor* ViewportInteractor, const UEditableMesh* EditableMesh, const TArray& EdgeElements, TArray& OutSplits ) = 0; + /** Given an interactor and a mesh, finds edges under the interactor along with their exact split position (progress along the edge). Returns true if we found a split position. */ + virtual bool FindEdgeSplitUnderInteractor( class UViewportInteractor* ViewportInteractor, const UEditableMesh* EditableMesh, const TArray& EdgeElements, FEdgeID& OutClosestEdgeID, float& OutSplit ) = 0; /** When performing an interactive action that was initiated using an interactor, this is the interactor that was used. */ virtual class UViewportInteractor* GetActiveActionInteractor() = 0; diff --git a/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/Public/MeshEditorCommands.h b/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/Public/MeshEditorCommands.h index f2eef72ff0a8..e19c3c4f01ac 100644 --- a/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/Public/MeshEditorCommands.h +++ b/Engine/Plugins/Editor/MeshEditor/Source/MeshEditor/Public/MeshEditorCommands.h @@ -251,3 +251,26 @@ public: TSharedPtr AssignMaterial; }; + +UCLASS() +class UMeshEditorCommandList : public UObject +{ + GENERATED_BODY() + +public: + + void HarvestMeshEditorCommands(); + + /** All of the mesh editor commands that were registered at startup */ + UPROPERTY() + TArray MeshEditorCommands; +}; + + +namespace MeshEditorCommands +{ + extern const TArray& Get(); +} + + + diff --git a/Engine/Plugins/Editor/MeshEditor/Source/PolygonModeling/InsertEdgeLoop.cpp b/Engine/Plugins/Editor/MeshEditor/Source/PolygonModeling/InsertEdgeLoop.cpp index 0136086a5d3d..87c6b324e204 100644 --- a/Engine/Plugins/Editor/MeshEditor/Source/PolygonModeling/InsertEdgeLoop.cpp +++ b/Engine/Plugins/Editor/MeshEditor/Source/PolygonModeling/InsertEdgeLoop.cpp @@ -42,25 +42,13 @@ void UInsertEdgeLoopCommand::ApplyDuringDrag( IMeshEditorModeEditingContract& Me const TArray& EdgeElements = MeshAndEdges.Value; // Figure out where to add the loop along the edge - static TArray Splits; - MeshEditorMode.FindEdgeSplitUnderInteractor( MeshEditorMode.GetActiveActionInteractor(), EditableMesh, EdgeElements, /* Out */ Splits ); + FEdgeID ClosestEdgeID = FEdgeID::Invalid; + float Split = 0.0f; + const bool bFoundSplit = MeshEditorMode.FindEdgeSplitUnderInteractor( MeshEditorMode.GetActiveActionInteractor(), EditableMesh, EdgeElements, /* Out */ ClosestEdgeID, /* Out */ Split ); // Insert the edge loop - if( Splits.Num() > 0 ) + if( bFoundSplit ) { - // @todo mesheditor edgeloop: Test code - if( false ) - { - if( Splits[ 0 ] > 0.25f ) - { - Splits.Insert( FMath::Max( Splits[ 0 ] - 0.2f, 0.0f ), 0 ); - } - if( Splits.Last() < 0.75f ) - { - Splits.Add( FMath::Min( Splits.Last() + 0.2f, 1.0f ) ); - } - } - for( const FMeshElement& EdgeMeshElement : EdgeElements ) { const FEdgeID EdgeID( EdgeMeshElement.ElementAddress.ElementID ); @@ -68,6 +56,9 @@ void UInsertEdgeLoopCommand::ApplyDuringDrag( IMeshEditorModeEditingContract& Me static TArray NewEdgeIDs; NewEdgeIDs.Reset(); + static TArray Splits; // @todo mesheditor edgeloop: Add support for inserting multiple splits at once! + Splits.Reset(); + Splits.Add( Split ); EditableMesh->InsertEdgeLoop( EdgeID, Splits, /* Out */ NewEdgeIDs ); // Select all of the new edges that were created by inserting the loop diff --git a/Engine/Plugins/Editor/MeshEditor/Source/PolygonModeling/SplitEdge.cpp b/Engine/Plugins/Editor/MeshEditor/Source/PolygonModeling/SplitEdge.cpp index 3bc156e2f659..db11ff876fa2 100644 --- a/Engine/Plugins/Editor/MeshEditor/Source/PolygonModeling/SplitEdge.cpp +++ b/Engine/Plugins/Editor/MeshEditor/Source/PolygonModeling/SplitEdge.cpp @@ -26,6 +26,8 @@ bool USplitEdgeCommand::TryStartingToDrag( IMeshEditorModeEditingContract& MeshE // Figure out what to split MeshEditorMode.GetSelectedMeshesAndEdges( /* Out */ SplitEdgeMeshesAndEdgesToSplit ); + SplitEdgeSplitList.Reset(); + if( SplitEdgeMeshesAndEdgesToSplit.Num() > 0 ) { for( auto& MeshAndEdges : SplitEdgeMeshesAndEdgesToSplit ) @@ -34,12 +36,15 @@ bool USplitEdgeCommand::TryStartingToDrag( IMeshEditorModeEditingContract& MeshE const TArray& EdgeElements = MeshAndEdges.Value; // Figure out where to split - MeshEditorMode.FindEdgeSplitUnderInteractor( ViewportInteractor, EditableMesh, EdgeElements, /* Out */ SplitEdgeSplitList ); + FEdgeID ClosestEdgeID = FEdgeID::Invalid; + float Split = 0.0f; + const bool bFoundSplit = MeshEditorMode.FindEdgeSplitUnderInteractor( ViewportInteractor, EditableMesh, EdgeElements, /* Out */ ClosestEdgeID, /* Out */ Split ); - // Split the edges - if( SplitEdgeSplitList.Num() > 0 ) + if( bFoundSplit ) { + SplitEdgeSplitList.Add( Split ); bHaveEdge = true; + break; } } }