2019-12-27 09:26:59 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-10-01 20:41:42 -04:00
# include "EditMeshPolygonsTool.h"
2020-09-24 00:43:27 -04:00
# include "Algo/ForEach.h"
2021-07-26 17:57:22 -04:00
# include "BaseBehaviors/SingleClickBehavior.h"
2021-09-30 08:27:39 -04:00
# include "BaseGizmos/CombinedTransformGizmo.h"
2021-07-26 17:57:22 -04:00
# include "BaseGizmos/TransformGizmoUtil.h"
# include "BaseGizmos/TransformProxy.h"
# include "CompGeom/PolygonTriangulation.h"
2021-09-16 23:16:23 -04:00
# include "ConstrainedDelaunay2.h"
2020-11-13 14:07:30 -04:00
# include "Components/BrushComponent.h"
2021-07-26 17:57:22 -04:00
# include "ContextObjectStore.h"
# include "DynamicMesh/DynamicMeshAttributeSet.h"
# include "DynamicMesh/MeshIndexUtil.h" // TriangleToVertexIDs
# include "DynamicMesh/MeshNormals.h"
# include "DynamicMesh/MeshTransforms.h"
# include "DynamicMeshEditor.h"
# include "FaceGroupUtil.h"
# include "GroupTopology.h"
# include "InteractiveGizmoManager.h"
# include "InteractiveToolManager.h"
# include "Mechanics/DragAlignmentMechanic.h"
# include "MeshBoundaryLoops.h"
# include "MeshOpPreviewHelpers.h" // UMeshOpPreviewWithBackgroundCompute
# include "MeshRegionBoundaryLoops.h"
# include "ModelingToolTargetUtil.h" // UE::ToolTarget:: functions
# include "Operations/SimpleHoleFiller.h"
2022-06-09 15:08:03 -04:00
# include "Operations/MinimalHoleFiller.h"
2021-09-16 23:16:23 -04:00
# include "Operations/PolygroupRemesh.h"
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
# include "Selection/PersistentMeshSelection.h"
# include "Selection/StoredMeshSelectionUtil.h"
2021-07-26 17:57:22 -04:00
# include "Selection/PolygonSelectionMechanic.h"
# include "Selections/MeshConnectedComponents.h"
# include "TargetInterfaces/MaterialProvider.h"
2021-07-29 15:22:26 -04:00
# include "TargetInterfaces/MeshDescriptionCommitter.h"
# include "TargetInterfaces/MeshDescriptionProvider.h"
2021-07-26 17:57:22 -04:00
# include "TargetInterfaces/PrimitiveComponentBackedTarget.h"
# include "ToolActivities/PolyEditActivityContext.h"
# include "ToolActivities/PolyEditExtrudeActivity.h"
# include "ToolActivities/PolyEditInsertEdgeActivity.h"
# include "ToolActivities/PolyEditInsertEdgeLoopActivity.h"
# include "ToolActivities/PolyEditInsetOutsetActivity.h"
# include "ToolActivities/PolyEditCutFacesActivity.h"
# include "ToolActivities/PolyEditPlanarProjectionUVActivity.h"
2021-11-16 13:24:21 -05:00
# include "ToolActivities/PolyEditBevelEdgeActivity.h"
2021-07-26 17:57:22 -04:00
# include "ToolContextInterfaces.h" // FToolBuilderState
# include "ToolSetupUtil.h"
# include "ToolTargetManager.h"
# include "TransformTypes.h"
# include "Util/CompactMaps.h"
2019-10-01 20:41:42 -04:00
2021-03-09 19:33:56 -04:00
using namespace UE : : Geometry ;
2019-10-01 20:41:42 -04:00
# define LOCTEXT_NAMESPACE "UEditMeshPolygonsTool"
2021-07-26 17:57:22 -04:00
namespace EditMeshPolygonsToolLocals
{
FText PolyEditDefaultMessage = LOCTEXT ( " OnStartEditMeshPolygonsTool_TriangleMode " , " Select triangles to edit mesh. Use middle mouse on gizmo to "
" reposition it. Hold Ctrl while translating or (in local mode) rotating to align to scene. Shift and Ctrl "
" change marquee select behavior. Q toggles Gizmo Orientation Lock. " ) ;
FText TriEditDefaultMessage = LOCTEXT ( " OnStartEditMeshPolygonsTool " , " Select PolyGroups to edit mesh. Use middle mouse on gizmo to reposition it. "
" Hold Ctrl while translating or (in local mode) rotating to align to scene. Shift and Ctrl change marquee select "
" behavior. Q toggles Gizmo Orientation Lock. " ) ;
2022-01-04 11:23:06 -05:00
FString GetPropertyCacheIdentifier ( bool bTriangleMode )
{
return bTriangleMode ? TEXT ( " TriEditTool " ) : TEXT ( " PolyEditTool " ) ;
}
2022-02-02 05:52:52 -05:00
TAutoConsoleVariable < int32 > CVarEdgeLimit (
TEXT ( " modeling.PolyEdit.EdgeLimit " ) ,
60000 ,
TEXT ( " Maximal number of edges that PolyEd and TriEd support. Meshes that would require "
" more than this number of edges to be rendered in PolyEd or TriEd force the tools to "
" be disabled to avoid hanging the editor. " ) ) ;
2021-07-26 17:57:22 -04:00
}
2019-10-01 20:41:42 -04:00
/*
* ToolBuilder
*/
2021-07-26 17:57:22 -04:00
2021-07-29 15:22:26 -04:00
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
USingleSelectionMeshEditingTool * UEditMeshPolygonsToolBuilder : : CreateNewTool ( const FToolBuilderState & SceneState ) const
{
return NewObject < UEditMeshPolygonsTool > ( SceneState . ToolManager ) ;
2021-07-26 17:57:22 -04:00
}
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
void UEditMeshPolygonsToolBuilder : : InitializeNewTool ( USingleSelectionMeshEditingTool * Tool , const FToolBuilderState & SceneState ) const
2021-07-26 17:57:22 -04:00
{
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
USingleSelectionMeshEditingToolBuilder : : InitializeNewTool ( Tool , SceneState ) ;
UEditMeshPolygonsTool * EditPolygonsTool = CastChecked < UEditMeshPolygonsTool > ( Tool ) ;
2020-01-27 20:11:15 -05:00
if ( bTriangleMode )
2019-10-01 20:41:42 -04:00
{
2020-01-27 20:11:15 -05:00
EditPolygonsTool - > EnableTriangleMode ( ) ;
2019-10-01 20:41:42 -04:00
}
}
2020-01-27 20:11:15 -05:00
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
void UEditMeshPolygonsActionModeToolBuilder : : InitializeNewTool ( USingleSelectionMeshEditingTool * Tool , const FToolBuilderState & SceneState ) const
2020-11-18 00:42:35 -04:00
{
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
UEditMeshPolygonsToolBuilder : : InitializeNewTool ( Tool , SceneState ) ;
UEditMeshPolygonsTool * EditPolygonsTool = CastChecked < UEditMeshPolygonsTool > ( Tool ) ;
2020-11-18 00:42:35 -04:00
EEditMeshPolygonsToolActions UseAction = StartupAction ;
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
EditPolygonsTool - > PostSetupFunction = [ UseAction ] ( UEditMeshPolygonsTool * PolyTool )
2020-11-18 00:42:35 -04:00
{
PolyTool - > SetToSelectionModeInterface ( ) ;
PolyTool - > RequestAction ( UseAction ) ;
} ;
}
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
void UEditMeshPolygonsSelectionModeToolBuilder : : InitializeNewTool ( USingleSelectionMeshEditingTool * Tool , const FToolBuilderState & SceneState ) const
2020-11-18 00:42:35 -04:00
{
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
UEditMeshPolygonsToolBuilder : : InitializeNewTool ( Tool , SceneState ) ;
UEditMeshPolygonsTool * EditPolygonsTool = CastChecked < UEditMeshPolygonsTool > ( Tool ) ;
2020-11-18 00:42:35 -04:00
EEditMeshPolygonsToolSelectionMode UseMode = SelectionMode ;
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
EditPolygonsTool - > PostSetupFunction = [ UseMode ] ( UEditMeshPolygonsTool * PolyTool )
2020-11-18 00:42:35 -04:00
{
PolyTool - > SetToSelectionModeInterface ( ) ;
UPolygonSelectionMechanic * SelectionMechanic = PolyTool - > SelectionMechanic ;
UPolygonSelectionMechanicProperties * SelectionProps = SelectionMechanic - > Properties ;
SelectionProps - > bSelectFaces = SelectionProps - > bSelectEdges = SelectionProps - > bSelectVertices = false ;
SelectionProps - > bSelectEdgeLoops = SelectionProps - > bSelectEdgeRings = false ;
switch ( UseMode )
{
default :
case EEditMeshPolygonsToolSelectionMode : : Faces :
SelectionProps - > bSelectFaces = true ;
break ;
case EEditMeshPolygonsToolSelectionMode : : Edges :
SelectionProps - > bSelectEdges = true ;
break ;
case EEditMeshPolygonsToolSelectionMode : : Vertices :
SelectionProps - > bSelectVertices = true ;
break ;
case EEditMeshPolygonsToolSelectionMode : : Loops :
SelectionProps - > bSelectEdges = true ;
SelectionProps - > bSelectEdgeLoops = true ;
break ;
case EEditMeshPolygonsToolSelectionMode : : Rings :
SelectionProps - > bSelectEdges = true ;
SelectionProps - > bSelectEdgeRings = true ;
break ;
case EEditMeshPolygonsToolSelectionMode : : FacesEdgesVertices :
SelectionProps - > bSelectFaces = SelectionProps - > bSelectEdges = SelectionProps - > bSelectVertices = true ;
break ;
}
} ;
}
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
2020-11-18 00:42:35 -04:00
void UEditMeshPolygonsTool : : SetToSelectionModeInterface ( )
{
if ( EditActions ) SetToolPropertySourceEnabled ( EditActions , false ) ;
if ( EditEdgeActions ) SetToolPropertySourceEnabled ( EditEdgeActions , false ) ;
if ( EditUVActions ) SetToolPropertySourceEnabled ( EditUVActions , false ) ;
}
2020-01-27 20:11:15 -05:00
void UEditMeshPolygonsToolActionPropertySet : : PostAction ( EEditMeshPolygonsToolActions Action )
2019-10-01 20:41:42 -04:00
{
2020-01-27 20:11:15 -05:00
if ( ParentTool . IsValid ( ) )
{
ParentTool - > RequestAction ( Action ) ;
}
2019-10-01 20:41:42 -04:00
}
/*
* Tool methods
*/
UEditMeshPolygonsTool : : UEditMeshPolygonsTool ( )
{
2021-02-08 17:02:09 -04:00
SetToolDisplayName ( LOCTEXT ( " EditMeshPolygonsToolName " , " PolyGroup Edit " ) ) ;
2020-01-27 20:11:15 -05:00
}
void UEditMeshPolygonsTool : : EnableTriangleMode ( )
{
2021-07-26 17:57:22 -04:00
check ( Preview = = nullptr ) ; // must not have been initialized!
2020-01-27 20:11:15 -05:00
bTriangleMode = true ;
2019-10-01 20:41:42 -04:00
}
void UEditMeshPolygonsTool : : Setup ( )
{
2021-07-26 17:57:22 -04:00
using namespace EditMeshPolygonsToolLocals ;
2019-10-01 20:41:42 -04:00
2022-02-02 05:52:52 -05:00
// TODO: Currently we draw all the edges in the tool with PDI and can lock up the editor on high-res meshes.
// As a hack, disable everything if the number of edges is too high, so that user doesn't lose work accidentally
// if they start the tool on the wrong thing.
int32 MaxEdges = CVarEdgeLimit . GetValueOnGameThread ( ) ;
CurrentMesh = MakeShared < FDynamicMesh3 > ( UE : : ToolTarget : : GetDynamicMeshCopy ( Target ) ) ;
if ( bTriangleMode )
{
bToolDisabled = CurrentMesh - > EdgeCount ( ) > MaxEdges ;
if ( bToolDisabled )
{
GetToolManager ( ) - > DisplayMessage ( FText : : Format (
LOCTEXT ( " TriEditTooManyEdges " ,
" This tool is currently disallowed from operating on a mesh of this resolution. "
" Current limit set by \" modeling.PolyEdit.EdgeLimit \" is {0} edges, and mesh has "
" {1}. Limit can be changed but exists to avoid hanging the editor when trying to "
" render too many edges using the current system, so make sure to save your work "
" if you change the upper limit and try to edit a very dense mesh. " ) ,
MaxEdges , CurrentMesh - > EdgeCount ( ) ) , EToolMessageLevel : : UserError ) ;
return ;
}
}
Topology = ( bTriangleMode ) ? MakeShared < FTriangleGroupTopology , ESPMode : : ThreadSafe > ( CurrentMesh . Get ( ) , true )
: MakeShared < FGroupTopology , ESPMode : : ThreadSafe > ( CurrentMesh . Get ( ) , true ) ;
if ( ! bTriangleMode )
{
int32 NumEdgesToRender = 0 ;
for ( const FGroupTopology : : FGroupEdge & Edge : Topology - > Edges )
{
NumEdgesToRender + = Edge . Span . Edges . Num ( ) ;
}
bToolDisabled = NumEdgesToRender > MaxEdges ;
if ( bToolDisabled )
{
GetToolManager ( ) - > DisplayMessage ( FText : : Format (
LOCTEXT ( " PolyEditTooManyEdges " ,
" This tool is currently disallowed from operating on a group topology of this resolution. "
" Current limit set by \" modeling.PolyEdit.EdgeLimit \" is {0} displayed edges, and topology has "
" {1} edge segments to display. Limit can be changed, but it exists to avoid hanging the editor "
" when trying to render too many edges using the current system, so make sure to save your work "
" if you change the upper limit and try to edit a very complicated topology. " ) ,
MaxEdges , NumEdgesToRender ) , EToolMessageLevel : : UserError ) ;
return ;
}
}
2021-07-26 17:57:22 -04:00
// Start by adding the actions, because we want them at the top.
2020-03-03 16:56:16 -05:00
if ( bTriangleMode )
{
2021-07-26 17:57:22 -04:00
EditActions_Triangles = NewObject < UEditMeshPolygonsToolActions_Triangles > ( ) ;
EditActions_Triangles - > Initialize ( this ) ;
AddToolPropertySource ( EditActions_Triangles ) ;
EditEdgeActions_Triangles = NewObject < UEditMeshPolygonsToolEdgeActions_Triangles > ( ) ;
EditEdgeActions_Triangles - > Initialize ( this ) ;
AddToolPropertySource ( EditEdgeActions_Triangles ) ;
SetToolDisplayName ( LOCTEXT ( " EditMeshTrianglesToolName " , " Triangle Edit " ) ) ;
DefaultMessage = PolyEditDefaultMessage ;
2020-03-03 16:56:16 -05:00
}
2021-07-26 17:57:22 -04:00
else
2019-10-01 20:41:42 -04:00
{
2020-01-27 20:11:15 -05:00
EditActions = NewObject < UEditMeshPolygonsToolActions > ( ) ;
EditActions - > Initialize ( this ) ;
AddToolPropertySource ( EditActions ) ;
2019-10-01 20:41:42 -04:00
2020-01-27 20:11:15 -05:00
EditEdgeActions = NewObject < UEditMeshPolygonsToolEdgeActions > ( ) ;
EditEdgeActions - > Initialize ( this ) ;
AddToolPropertySource ( EditEdgeActions ) ;
EditUVActions = NewObject < UEditMeshPolygonsToolUVActions > ( ) ;
EditUVActions - > Initialize ( this ) ;
AddToolPropertySource ( EditUVActions ) ;
2021-07-26 17:57:22 -04:00
DefaultMessage = TriEditDefaultMessage ;
2020-01-27 20:11:15 -05:00
}
2021-07-26 17:57:22 -04:00
GetToolManager ( ) - > DisplayMessage ( DefaultMessage ,
EToolMessageLevel : : UserNotification ) ;
// We add an empty line for the error message so that things don't jump when we use it.
GetToolManager ( ) - > DisplayMessage ( FText ( ) , EToolMessageLevel : : UserWarning ) ;
CancelAction = NewObject < UEditMeshPolygonsToolCancelAction > ( ) ;
CancelAction - > Initialize ( this ) ;
AddToolPropertySource ( CancelAction ) ;
SetToolPropertySourceEnabled ( CancelAction , false ) ;
2021-11-16 13:24:21 -05:00
AcceptCancelAction = NewObject < UEditMeshPolygonsToolAcceptCancelAction > ( ) ;
AcceptCancelAction - > Initialize ( this ) ;
AddToolPropertySource ( AcceptCancelAction ) ;
SetToolPropertySourceEnabled ( AcceptCancelAction , false ) ;
2021-07-26 17:57:22 -04:00
// Initialize the common properties but don't add them yet, because we want them to be under the activity-specific ones.
CommonProps = NewObject < UPolyEditCommonProperties > ( this ) ;
2022-01-04 11:23:06 -05:00
CommonProps - > RestoreProperties ( this , GetPropertyCacheIdentifier ( bTriangleMode ) ) ;
2022-06-08 16:27:18 -04:00
2021-07-26 17:57:22 -04:00
CommonProps - > WatchProperty ( CommonProps - > LocalFrameMode ,
[ this ] ( ELocalFrameMode ) { UpdateGizmoFrame ( ) ; } ) ;
CommonProps - > WatchProperty ( CommonProps - > bLockRotation ,
2022-06-08 16:27:18 -04:00
[ this ] ( bool ) { LockedTransfomerFrame = LastTransformerFrame ; } ) ;
CommonProps - > WatchProperty ( CommonProps - > bGizmoVisible ,
2021-07-26 17:57:22 -04:00
[ this ] ( bool )
{
2022-06-08 16:27:18 -04:00
if ( ! CurrentActivity )
{
UpdateGizmoVisibility ( ) ;
ResetUserMessage ( ) ;
}
2021-07-26 17:57:22 -04:00
} ) ;
2022-06-08 16:27:18 -04:00
2021-07-26 17:57:22 -04:00
// We are going to SilentUpdate here because otherwise the Watches above will immediately fire
// and cause UpdateGizmoFrame() to be called emitting a spurious Transform change.
CommonProps - > SilentUpdateWatched ( ) ;
// TODO: Do we need this?
FMeshNormals : : QuickComputeVertexNormals ( * CurrentMesh ) ;
// Create the preview object
Preview = NewObject < UMeshOpPreviewWithBackgroundCompute > ( ) ;
Preview - > Setup ( TargetWorld ) ;
2021-10-07 22:25:54 -04:00
ToolSetupUtil : : ApplyRenderingConfigurationToPreview ( Preview - > PreviewMesh , Target ) ;
2021-07-26 17:57:22 -04:00
WorldTransform = UE : : ToolTarget : : GetLocalToWorldTransform ( Target ) ;
Preview - > PreviewMesh - > SetTransform ( ( FTransform ) WorldTransform ) ;
// We'll use the spatial inside preview mesh mainly for the convenience of having it update automatically.
Preview - > PreviewMesh - > bBuildSpatialDataStructure = true ;
// set materials
FComponentMaterialSet MaterialSet = UE : : ToolTarget : : GetMaterialSet ( Target ) ;
Preview - > ConfigureMaterials ( MaterialSet . Materials , ToolSetupUtil : : GetDefaultWorkingMaterial ( GetToolManager ( ) ) ) ;
// configure secondary render material
UMaterialInterface * SelectionMaterial = ToolSetupUtil : : GetSelectionMaterial ( FLinearColor : : Yellow , GetToolManager ( ) ) ;
if ( SelectionMaterial ! = nullptr )
2020-01-27 20:11:15 -05:00
{
2021-07-26 17:57:22 -04:00
// Note that you have to do it this way rather than reaching into the PreviewMesh because the background compute
// mesh has to be able to swap in/out a working material and restore the primary/secondary ones.
Preview - > SecondaryMaterial = SelectionMaterial ;
2020-01-27 20:11:15 -05:00
}
2021-07-26 17:57:22 -04:00
Preview - > PreviewMesh - > EnableSecondaryTriangleBuffers (
[ this ] ( const FDynamicMesh3 * Mesh , int32 TriangleID )
{
return SelectionMechanic - > GetActiveSelection ( ) . IsSelectedTriangle ( Mesh , Topology . Get ( ) , TriangleID ) ;
} ) ;
2020-01-27 20:11:15 -05:00
2021-07-26 17:57:22 -04:00
Preview - > PreviewMesh - > SetTangentsMode ( EDynamicMeshComponentTangentsMode : : AutoCalculated ) ;
Preview - > PreviewMesh - > UpdatePreview ( CurrentMesh . Get ( ) ) ;
Preview - > PreviewMesh - > EnableWireframe ( CommonProps - > bShowWireframe ) ;
Preview - > SetVisibility ( true ) ;
2020-10-29 13:38:15 -04:00
2021-07-26 17:57:22 -04:00
// initialize AABBTree
MeshSpatial = MakeShared < FDynamicMeshAABBTree3 > ( ) ;
MeshSpatial - > SetMesh ( CurrentMesh . Get ( ) ) ;
2020-01-27 20:11:15 -05:00
2021-07-26 17:57:22 -04:00
// set up SelectionMechanic
SelectionMechanic = NewObject < UPolygonSelectionMechanic > ( this ) ;
SelectionMechanic - > bAddSelectionFilterPropertiesToParentTool = false ; // We'll do this ourselves later
SelectionMechanic - > Setup ( this ) ;
2022-06-07 18:25:43 -04:00
SelectionMechanic - > SetShowSelectableCorners ( CommonProps - > bShowSelectableCorners ) ;
2022-01-04 11:23:06 -05:00
SelectionMechanic - > Properties - > RestoreProperties ( this , GetPropertyCacheIdentifier ( bTriangleMode ) ) ;
2021-07-26 17:57:22 -04:00
SelectionMechanic - > OnSelectionChanged . AddUObject ( this , & UEditMeshPolygonsTool : : OnSelectionModifiedEvent ) ;
2022-01-27 17:09:13 -05:00
SelectionMechanic - > OnFaceSelectionPreviewChanged . AddWeakLambda ( this , [ this ] ( ) {
Preview - > PreviewMesh - > FastNotifySecondaryTrianglesChanged ( ) ;
} ) ;
2020-09-24 00:43:27 -04:00
if ( bTriangleMode )
{
2021-07-26 17:57:22 -04:00
SelectionMechanic - > PolyEdgesRenderer . LineThickness = 1.0 ;
2020-09-24 00:43:27 -04:00
}
2021-07-26 17:57:22 -04:00
SelectionMechanic - > Initialize ( CurrentMesh . Get ( ) ,
2022-02-24 15:01:41 -05:00
( FTransform3d ) Preview - > PreviewMesh - > GetTransform ( ) ,
2021-07-26 17:57:22 -04:00
TargetWorld ,
Topology . Get ( ) ,
[ this ] ( ) { return & GetSpatial ( ) ; }
) ;
LinearDeformer . Initialize ( CurrentMesh . Get ( ) , Topology . Get ( ) ) ;
// Have to load selection after initializing the selection mechanic since we need to have
// the topology built.
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
if ( HasInputSelection ( ) & & IsToolInputSelectionUsable ( GetInputSelection ( ) ) )
2020-09-24 00:43:27 -04:00
{
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
SelectionMechanic - > LoadSelection ( * GetInputSelection ( ) ) ;
2020-09-24 00:43:27 -04:00
}
2021-07-26 17:57:22 -04:00
bSelectionStateDirty = SelectionMechanic - > HasSelection ( ) ;
// Set UV Scale factor based on initial mesh bounds
float BoundsMaxDim = CurrentMesh - > GetBounds ( ) . MaxDim ( ) ;
if ( BoundsMaxDim > 0 )
{
UVScaleFactor = 1.0 / BoundsMaxDim ;
}
// Wrap the data structures into a context that we can give to the activities
2021-10-21 10:11:02 -04:00
ActivityContext = NewObject < UPolyEditActivityContext > ( ) ;
2021-07-26 17:57:22 -04:00
ActivityContext - > bTriangleMode = bTriangleMode ;
ActivityContext - > CommonProperties = CommonProps ;
ActivityContext - > CurrentMesh = CurrentMesh ;
ActivityContext - > Preview = Preview ;
ActivityContext - > CurrentTopology = Topology ;
ActivityContext - > MeshSpatial = MeshSpatial ;
ActivityContext - > SelectionMechanic = SelectionMechanic ;
ActivityContext - > EmitActivityStart = [ this ] ( const FText & TransactionLabel )
{
EmitActivityStart ( TransactionLabel ) ;
} ;
ActivityContext - > EmitCurrentMeshChangeAndUpdate = [ this ] ( const FText & TransactionLabel ,
TUniquePtr < UE : : Geometry : : FDynamicMeshChange > MeshChangeIn ,
2022-01-11 06:48:50 -05:00
const UE : : Geometry : : FGroupTopologySelection & OutputSelection )
2021-07-26 17:57:22 -04:00
{
2022-01-11 06:48:50 -05:00
EmitCurrentMeshChangeAndUpdate ( TransactionLabel , MoveTemp ( MeshChangeIn ) , OutputSelection ) ;
2021-07-26 17:57:22 -04:00
} ;
GetToolManager ( ) - > GetContextObjectStore ( ) - > RemoveContextObjectsOfType ( UPolyEditActivityContext : : StaticClass ( ) ) ;
GetToolManager ( ) - > GetContextObjectStore ( ) - > AddContextObject ( ActivityContext ) ;
ExtrudeActivity = NewObject < UPolyEditExtrudeActivity > ( ) ;
ExtrudeActivity - > Setup ( this ) ;
InsetOutsetActivity = NewObject < UPolyEditInsetOutsetActivity > ( ) ;
InsetOutsetActivity - > Setup ( this ) ;
CutFacesActivity = NewObject < UPolyEditCutFacesActivity > ( ) ;
CutFacesActivity - > Setup ( this ) ;
PlanarProjectionUVActivity = NewObject < UPolyEditPlanarProjectionUVActivity > ( ) ;
PlanarProjectionUVActivity - > Setup ( this ) ;
InsertEdgeLoopActivity = NewObject < UPolyEditInsertEdgeLoopActivity > ( ) ;
InsertEdgeLoopActivity - > Setup ( this ) ;
InsertEdgeActivity = NewObject < UPolyEditInsertEdgeActivity > ( ) ;
InsertEdgeActivity - > Setup ( this ) ;
2021-11-16 13:24:21 -05:00
BevelEdgeActivity = NewObject < UPolyEditBevelEdgeActivity > ( ) ;
BevelEdgeActivity - > Setup ( this ) ;
2021-07-26 17:57:22 -04:00
// Now that we've initialized the activities, add in the selection settings and
// CommonProps so that they are at the bottom.
AddToolPropertySource ( SelectionMechanic - > Properties ) ;
AddToolPropertySource ( CommonProps ) ;
// hide input StaticMeshComponent
UE : : ToolTarget : : HideSourceObject ( Target ) ;
UInteractiveGizmoManager * GizmoManager = GetToolManager ( ) - > GetPairedGizmoManager ( ) ;
TransformGizmo = UE : : TransformGizmoUtil : : CreateCustomRepositionableTransformGizmo ( GizmoManager ,
ETransformGizmoSubElements : : FullTranslateRotateScale , this ) ;
2022-06-02 16:45:08 -04:00
if ( ensure ( TransformGizmo ) ) // If we don't get a valid gizmo a lot of interactions won't work, but at least we won't crash
{
// Stop scaling at 0 rather than going negative
TransformGizmo - > SetDisallowNegativeScaling ( true ) ;
// We allow non uniform scale even when the gizmo mode is set to "world" because we're not scaling components- we're
// moving vertices, so we don't care which axes we "scale" along.
TransformGizmo - > SetIsNonUniformScaleAllowedFunction ( [ ] ( ) {
return true ;
} ) ;
// Hook up callbacks
TransformProxy = NewObject < UTransformProxy > ( this ) ;
TransformProxy - > OnTransformChanged . AddUObject ( this , & UEditMeshPolygonsTool : : OnGizmoTransformChanged ) ;
TransformProxy - > OnBeginTransformEdit . AddUObject ( this , & UEditMeshPolygonsTool : : OnBeginGizmoTransform ) ;
TransformProxy - > OnEndTransformEdit . AddUObject ( this , & UEditMeshPolygonsTool : : OnEndGizmoTransform ) ;
TransformProxy - > OnEndPivotEdit . AddWeakLambda ( this , [ this ] ( UTransformProxy * Proxy ) {
LastTransformerFrame = FFrame3d ( Proxy - > GetTransform ( ) ) ;
if ( CommonProps - > bLockRotation )
{
LockedTransfomerFrame = LastTransformerFrame ;
}
} ) ;
TransformGizmo - > SetActiveTarget ( TransformProxy , GetToolManager ( ) ) ;
TransformGizmo - > SetVisibility ( false ) ;
}
2021-07-26 17:57:22 -04:00
DragAlignmentMechanic = NewObject < UDragAlignmentMechanic > ( this ) ;
DragAlignmentMechanic - > Setup ( this ) ;
DragAlignmentMechanic - > InitializeDeformedMeshRayCast (
[ this ] ( ) { return & GetSpatial ( ) ; } ,
WorldTransform , & LinearDeformer ) ; // Should happen after LinearDeformer is initialized
2022-06-02 16:45:08 -04:00
if ( TransformGizmo )
{
DragAlignmentMechanic - > AddToGizmo ( TransformGizmo ) ;
}
2021-07-26 17:57:22 -04:00
2020-01-27 20:11:15 -05:00
if ( Topology - > Groups . Num ( ) < 2 )
{
2021-10-15 11:20:27 -04:00
GetToolManager ( ) - > DisplayMessage (
LOCTEXT ( " NoGroupsWarning " ,
2022-01-28 12:26:52 -05:00
" This object has only a single Polygroup. Use the GrpGen, GrpPnt or TriSel (Create Polygroup) tools to modify PolyGroups. " ) ,
2021-10-15 11:20:27 -04:00
EToolMessageLevel : : UserWarning ) ;
2019-10-01 20:41:42 -04:00
}
2020-11-18 00:42:35 -04:00
if ( PostSetupFunction )
{
PostSetupFunction ( this ) ;
}
2019-10-01 20:41:42 -04:00
}
2022-06-08 16:27:18 -04:00
void UEditMeshPolygonsTool : : ResetUserMessage ( )
{
// When the gizmo is hidden, notify the user and
// specify the toggle hotkey to prevent panic
if ( ! TransformGizmo - > IsVisible ( ) )
{
GetToolManager ( ) - > DisplayMessage (
LOCTEXT ( " ToggleTransformGizmoNotify " , " Transform Gizmo Hidden, Press 'R' to Unhide " ) ,
EToolMessageLevel : : UserNotification ) ;
}
else
{
GetToolManager ( ) - > DisplayMessage (
DefaultMessage ,
EToolMessageLevel : : UserNotification ) ;
}
}
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
bool UEditMeshPolygonsTool : : IsToolInputSelectionUsable ( const UPersistentMeshSelection * InputSelectionIn )
2020-11-13 14:07:30 -04:00
{
// TODO: We currently don't support persistent selection on volume brushes because
// a conversion back to a brush involves a simplification step that may make the
// same vids unrecoverable. Once we have persistence of dynamic meshes, this will
// hopefully not become a problem, and this function (along with stored selection
// identifying info) will change.
2021-06-11 22:42:32 -04:00
return ! Cast < UBrushComponent > ( UE : : ToolTarget : : GetTargetComponent ( Target ) )
2020-11-13 14:07:30 -04:00
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
& & InputSelectionIn
& & InputSelectionIn - > GetSelectionType ( ) = = ( bTriangleMode ?
FGenericMeshSelection : : ETopologyType : : FTriangleGroupTopology
: FGenericMeshSelection : : ETopologyType : : FGroupTopology )
& & InputSelectionIn - > GetTargetComponent ( ) = = UE : : ToolTarget : : GetTargetComponent ( Target )
& & ! InputSelectionIn - > IsEmpty ( ) ;
2020-11-13 14:07:30 -04:00
}
2022-01-28 18:40:54 -05:00
void UEditMeshPolygonsTool : : OnShutdown ( EToolShutdownType ShutdownType )
2019-10-01 20:41:42 -04:00
{
2022-01-04 11:23:06 -05:00
using namespace EditMeshPolygonsToolLocals ;
2022-02-02 05:52:52 -05:00
if ( bToolDisabled )
{
CurrentMesh . Reset ( ) ;
Topology . Reset ( ) ;
return ;
}
2021-07-26 17:57:22 -04:00
if ( CurrentActivity )
{
CurrentActivity - > End ( ShutdownType ) ;
CurrentActivity = nullptr ;
}
2022-01-04 11:23:06 -05:00
CommonProps - > SaveProperties ( this , GetPropertyCacheIdentifier ( bTriangleMode ) ) ;
SelectionMechanic - > Properties - > SaveProperties ( this , GetPropertyCacheIdentifier ( bTriangleMode ) ) ;
2020-01-27 20:11:15 -05:00
2021-07-26 17:57:22 -04:00
GetToolManager ( ) - > GetContextObjectStore ( ) - > RemoveContextObjectsOfType ( UPolyEditActivityContext : : StaticClass ( ) ) ;
2021-10-21 10:11:02 -04:00
ActivityContext = nullptr ;
2021-07-26 17:57:22 -04:00
ExtrudeActivity - > Shutdown ( ShutdownType ) ;
InsetOutsetActivity - > Shutdown ( ShutdownType ) ;
CutFacesActivity - > Shutdown ( ShutdownType ) ;
PlanarProjectionUVActivity - > Shutdown ( ShutdownType ) ;
InsertEdgeActivity - > Shutdown ( ShutdownType ) ;
InsertEdgeLoopActivity - > Shutdown ( ShutdownType ) ;
2021-11-16 13:24:21 -05:00
BevelEdgeActivity - > Shutdown ( ShutdownType ) ;
2021-07-26 17:57:22 -04:00
GetToolManager ( ) - > GetPairedGizmoManager ( ) - > DestroyAllGizmosByOwner ( this ) ;
2021-01-14 19:07:52 -04:00
DragAlignmentMechanic - > Shutdown ( ) ;
2020-11-13 14:07:30 -04:00
// We wait to shut down the selection mechanic in case we need to do work to store the selection.
2021-07-26 17:57:22 -04:00
if ( Preview ! = nullptr )
2020-01-27 20:11:15 -05:00
{
2021-06-11 22:42:32 -04:00
UE : : ToolTarget : : ShowSourceObject ( Target ) ;
2019-10-01 20:41:42 -04:00
if ( ShutdownType = = EToolShutdownType : : Accept )
{
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
UPersistentMeshSelection * OutputSelection = nullptr ;
2020-11-13 14:07:30 -04:00
FCompactMaps CompactMaps ;
// Prep if we have a selection to store. We don't support storing selections for volumes
// because the conversion will change vids.
if ( ! SelectionMechanic - > GetActiveSelection ( ) . IsEmpty ( )
2021-06-11 22:42:32 -04:00
& & ! Cast < UBrushComponent > ( UE : : ToolTarget : : GetTargetComponent ( Target ) ) )
2020-11-13 14:07:30 -04:00
{
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
OutputSelection = NewObject < UPersistentMeshSelection > ( ) ;
FGenericMeshSelection NewSelection ;
NewSelection . SourceComponent = UE : : ToolTarget : : GetTargetComponent ( Target ) ;
NewSelection . TopologyType = ( bTriangleMode ?
FGenericMeshSelection : : ETopologyType : : FTriangleGroupTopology
: FGenericMeshSelection : : ETopologyType : : FGroupTopology ) ;
OutputSelection - > SetSelection ( NewSelection ) ;
2020-11-13 14:07:30 -04:00
}
2021-10-21 22:27:36 -04:00
// Note: When not in triangle mode, ModifiedTopologyCounter refers to polygroup topology, so does not tell us
// about the triangle topology. In this case, we just assume the triangle topology may have been modified.
bool bModifiedTriangleTopology = bTriangleMode ? ModifiedTopologyCounter > 0 : true ;
2021-07-26 17:57:22 -04:00
2020-01-27 20:11:15 -05:00
// may need to compact the mesh if we did undo on a mesh edit, then vertices will be dense but compact checks will fail...
2021-10-21 22:27:36 -04:00
if ( bModifiedTriangleTopology )
2020-01-27 20:11:15 -05:00
{
2020-11-13 14:07:30 -04:00
// Store the compact maps if we have a selection that we need to update
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
CurrentMesh - > CompactInPlace ( OutputSelection ? & CompactMaps : nullptr ) ;
2020-11-13 14:07:30 -04:00
}
// Finish prepping the stored selection
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
if ( OutputSelection )
2020-11-13 14:07:30 -04:00
{
2021-10-21 22:27:36 -04:00
SelectionMechanic - > GetSelection ( * OutputSelection , bModifiedTriangleTopology ? & CompactMaps : nullptr ) ;
2020-01-27 20:11:15 -05:00
}
2021-07-29 15:22:26 -04:00
// Bake CurrentMesh back to target inside an undo transaction
2019-10-01 20:41:42 -04:00
GetToolManager ( ) - > BeginUndoTransaction ( LOCTEXT ( " EditMeshPolygonsToolTransactionName " , " Deform Mesh " ) ) ;
2021-10-21 22:27:36 -04:00
UE : : ToolTarget : : CommitDynamicMeshUpdate ( Target , * CurrentMesh , bModifiedTriangleTopology ) ;
2020-11-13 14:07:30 -04:00
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
UE : : Geometry : : SetToolOutputSelection ( this , OutputSelection ) ;
2019-10-01 20:41:42 -04:00
GetToolManager ( ) - > EndUndoTransaction ( ) ;
}
2021-07-26 17:57:22 -04:00
Preview - > Shutdown ( ) ;
Preview = nullptr ;
2019-10-01 20:41:42 -04:00
}
2020-11-13 14:07:30 -04:00
// The seleciton mechanic shutdown has to happen after (potentially) saving selection above
SelectionMechanic - > Shutdown ( ) ;
2021-07-26 17:57:22 -04:00
// We null out as many pointers as we can because the tool pointer usually ends up sticking
// around in the undo stack.
TargetWorld = nullptr ;
CommonProps = nullptr ;
EditActions = nullptr ;
EditActions_Triangles = nullptr ;
EditEdgeActions = nullptr ;
EditEdgeActions_Triangles = nullptr ;
EditUVActions = nullptr ;
CancelAction = nullptr ;
2021-11-16 13:24:21 -05:00
AcceptCancelAction = nullptr ;
2021-07-26 17:57:22 -04:00
ExtrudeActivity = nullptr ;
InsetOutsetActivity = nullptr ;
CutFacesActivity = nullptr ;
PlanarProjectionUVActivity = nullptr ;
InsertEdgeActivity = nullptr ;
InsertEdgeLoopActivity = nullptr ;
2021-11-16 13:24:21 -05:00
BevelEdgeActivity = nullptr ;
2021-07-26 17:57:22 -04:00
SelectionMechanic = nullptr ;
DragAlignmentMechanic = nullptr ;
TransformGizmo = nullptr ;
TransformProxy = nullptr ;
CurrentMesh . Reset ( ) ;
Topology . Reset ( ) ;
MeshSpatial . Reset ( ) ;
2019-10-01 20:41:42 -04:00
}
void UEditMeshPolygonsTool : : RegisterActions ( FInteractiveToolActionSet & ActionSet )
{
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 2 ,
2020-01-27 20:11:15 -05:00
TEXT ( " ToggleLockRotation " ) ,
LOCTEXT ( " ToggleLockRotationUIName " , " Lock Rotation " ) ,
LOCTEXT ( " ToggleLockRotationTooltip " , " Toggle Frame Rotation Lock on and off " ) ,
2019-10-01 20:41:42 -04:00
EModifierKey : : None , EKeys : : Q ,
2020-09-01 14:07:48 -04:00
[ this ] ( ) { CommonProps - > bLockRotation = ! CommonProps - > bLockRotation ; } ) ;
2021-03-24 16:38:48 -04:00
// Backspace and delete both trigger deletion (as long as the delete button is also enabled)
auto OnDeletionKeyPress = [ this ] ( )
{
if ( ( EditActions & & EditActions - > IsPropertySetEnabled ( ) )
| | ( EditActions_Triangles & & EditActions_Triangles - > IsPropertySetEnabled ( ) ) )
{
RequestAction ( EEditMeshPolygonsToolActions : : Delete ) ;
}
} ;
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 3 ,
TEXT ( " DeleteSelectionBackSpaceKey " ) ,
LOCTEXT ( " DeleteSelectionUIName " , " Delete Selection " ) ,
LOCTEXT ( " DeleteSelectionTooltip " , " Delete Selection " ) ,
EModifierKey : : None , EKeys : : BackSpace , OnDeletionKeyPress ) ;
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 4 ,
TEXT ( " DeleteSelectionDeleteKey " ) ,
LOCTEXT ( " DeleteSelectionUIName " , " Delete Selection " ) ,
LOCTEXT ( " DeleteSelectionTooltip " , " Delete Selection " ) ,
EModifierKey : : None , EKeys : : Delete , OnDeletionKeyPress ) ;
2022-06-08 16:27:18 -04:00
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 5 ,
TEXT ( " ToggleTransformGizmoAKey " ) ,
LOCTEXT ( " ToggleTransformGizmoUIName " , " Toggle Transform Gizmo Visibility " ) ,
LOCTEXT ( " ToggleTransformGizmoTooltip " , " Toggle Transform Gizmo Visibility " ) ,
EModifierKey : : None , EKeys : : R ,
[ this ] ( )
{
if ( ! CurrentActivity )
{
CommonProps - > bGizmoVisible = ! CommonProps - > bGizmoVisible ;
}
} ) ;
2021-07-26 17:57:22 -04:00
// TODO: Esc should be made to exit out of current activity if one is active. However this
// requires a bit of work because we don't seem to be able to register conditional actions,
// and we don't want to always capture Esc.
2019-10-01 20:41:42 -04:00
}
2020-01-27 20:11:15 -05:00
void UEditMeshPolygonsTool : : RequestAction ( EEditMeshPolygonsToolActions ActionType )
2019-10-01 20:41:42 -04:00
{
2022-02-25 09:43:15 -05:00
if ( SelectionMechanic & & SelectionMechanic - > IsCurrentlyMarqueeDragging ( ) )
{
PendingAction = EEditMeshPolygonsToolActions : : NoAction ;
GetToolManager ( ) - > DisplayMessage (
LOCTEXT ( " CannotActDuringMarquee " , " Cannot perform action while marquee selecting " ) ,
EToolMessageLevel : : UserWarning ) ;
return ;
}
2020-01-27 20:11:15 -05:00
if ( PendingAction ! = EEditMeshPolygonsToolActions : : NoAction )
2019-10-01 20:41:42 -04:00
{
2020-01-27 20:11:15 -05:00
return ;
2019-10-01 20:41:42 -04:00
}
2020-01-27 20:11:15 -05:00
PendingAction = ActionType ;
2019-10-01 20:41:42 -04:00
}
FDynamicMeshAABBTree3 & UEditMeshPolygonsTool : : GetSpatial ( )
{
if ( bSpatialDirty )
{
2021-07-26 17:57:22 -04:00
MeshSpatial - > Build ( ) ;
2019-10-01 20:41:42 -04:00
bSpatialDirty = false ;
}
2021-07-26 17:57:22 -04:00
return * MeshSpatial ;
2019-10-01 20:41:42 -04:00
}
2021-07-26 17:57:22 -04:00
void UEditMeshPolygonsTool : : UpdateGizmoFrame ( const FFrame3d * UseFrame )
2020-01-27 20:11:15 -05:00
{
FFrame3d SetFrame = LastTransformerFrame ;
if ( UseFrame = = nullptr )
{
2020-09-01 14:07:48 -04:00
if ( CommonProps - > LocalFrameMode = = ELocalFrameMode : : FromGeometry )
2020-01-27 20:11:15 -05:00
{
SetFrame = LastGeometryFrame ;
}
else
{
SetFrame = FFrame3d ( LastGeometryFrame . Origin , WorldTransform . GetRotation ( ) ) ;
}
2019-10-01 20:41:42 -04:00
}
else
{
2020-01-27 20:11:15 -05:00
SetFrame = * UseFrame ;
}
2020-09-01 14:07:48 -04:00
if ( CommonProps - > bLockRotation )
2020-01-27 20:11:15 -05:00
{
SetFrame . Rotation = LockedTransfomerFrame . Rotation ;
}
LastTransformerFrame = SetFrame ;
2021-07-26 17:57:22 -04:00
2022-06-02 16:45:08 -04:00
if ( TransformGizmo )
{
// This resets the scale as well
TransformGizmo - > ReinitializeGizmoTransform ( SetFrame . ToFTransform ( ) ) ;
}
2020-01-27 20:11:15 -05:00
}
2021-05-10 01:17:30 -04:00
FBox UEditMeshPolygonsTool : : GetWorldSpaceFocusBox ( )
{
2021-12-15 05:02:56 -05:00
if ( ensure ( SelectionMechanic ) )
2021-05-10 01:17:30 -04:00
{
FAxisAlignedBox3d Bounds = SelectionMechanic - > GetSelectionBounds ( true ) ;
return ( FBox ) Bounds ;
}
2021-12-15 05:02:56 -05:00
return FBox ( EForceInit : : ForceInit ) ;
2021-05-10 01:17:30 -04:00
}
bool UEditMeshPolygonsTool : : GetWorldSpaceFocusPoint ( const FRay & WorldRay , FVector & PointOut )
{
2021-11-17 21:06:46 -05:00
FRay3d LocalRay ( WorldTransform . InverseTransformPosition ( ( FVector3d ) WorldRay . Origin ) ,
2022-03-18 08:32:15 -04:00
WorldTransform . InverseTransformVector ( ( FVector3d ) WorldRay . Direction ) ) ;
2021-05-10 01:17:30 -04:00
UE : : Geometry : : Normalize ( LocalRay . Direction ) ;
int32 HitTID = GetSpatial ( ) . FindNearestHitTriangle ( LocalRay ) ;
if ( HitTID ! = IndexConstants : : InvalidID )
{
FIntrRay3Triangle3d TriHit = TMeshQueries < FDynamicMesh3 > : : TriangleIntersection ( * GetSpatial ( ) . GetMesh ( ) , HitTID , LocalRay ) ;
FVector3d LocalPos = LocalRay . PointAt ( TriHit . RayParameter ) ;
PointOut = ( FVector ) WorldTransform . TransformPosition ( LocalPos ) ;
return true ;
}
return false ;
}
2020-01-27 20:11:15 -05:00
void UEditMeshPolygonsTool : : OnSelectionModifiedEvent ( )
{
bSelectionStateDirty = true ;
}
2021-07-26 17:57:22 -04:00
void UEditMeshPolygonsTool : : OnBeginGizmoTransform ( UTransformProxy * Proxy )
2019-12-19 18:07:47 -05:00
{
2020-01-27 20:11:15 -05:00
SelectionMechanic - > ClearHighlight ( ) ;
UpdateDeformerFromSelection ( SelectionMechanic - > GetActiveSelection ( ) ) ;
2021-07-26 17:57:22 -04:00
FTransform Transform = Proxy - > GetTransform ( ) ;
InitialGizmoFrame = FFrame3d ( Transform ) ;
InitialGizmoScale = FVector3d ( Transform . GetScale3D ( ) ) ;
BeginDeformerChange ( ) ;
bInGizmoDrag = true ;
2019-12-19 18:07:47 -05:00
}
2021-07-26 17:57:22 -04:00
void UEditMeshPolygonsTool : : OnGizmoTransformChanged ( UTransformProxy * Proxy , FTransform Transform )
2019-12-19 18:07:47 -05:00
{
2021-07-26 17:57:22 -04:00
if ( bInGizmoDrag )
2019-10-01 20:41:42 -04:00
{
2021-07-26 17:57:22 -04:00
LastUpdateGizmoFrame = FFrame3d ( Transform ) ;
LastUpdateGizmoScale = FVector3d ( Transform . GetScale3D ( ) ) ;
GetToolManager ( ) - > PostInvalidation ( ) ;
bGizmoUpdatePending = true ;
2022-06-02 16:45:08 -04:00
bLastUpdateUsedWorldFrame = ( TransformGizmo ? TransformGizmo - > CurrentCoordinateSystem = = EToolContextCoordinateSystem : : World : false ) ;
2019-10-01 20:41:42 -04:00
}
}
2021-07-26 17:57:22 -04:00
void UEditMeshPolygonsTool : : OnEndGizmoTransform ( UTransformProxy * Proxy )
2019-12-19 18:07:47 -05:00
{
2021-07-26 17:57:22 -04:00
bInGizmoDrag = false ;
2020-03-05 18:07:34 -05:00
bGizmoUpdatePending = false ;
2019-12-19 18:07:47 -05:00
bSpatialDirty = true ;
2020-01-27 20:11:15 -05:00
SelectionMechanic - > NotifyMeshChanged ( false ) ;
2019-12-19 18:07:47 -05:00
2021-07-26 17:57:22 -04:00
FFrame3d TransformFrame ( Proxy - > GetTransform ( ) ) ;
2022-06-02 16:45:08 -04:00
if ( TransformGizmo )
2021-04-27 11:08:23 -04:00
{
2022-06-02 16:45:08 -04:00
if ( CommonProps - > bLockRotation )
{
FFrame3d SetFrame = TransformFrame ;
SetFrame . Rotation = LockedTransfomerFrame . Rotation ;
TransformGizmo - > ReinitializeGizmoTransform ( SetFrame . ToFTransform ( ) ) ;
}
else
{
TransformGizmo - > SetNewChildScale ( FVector : : OneVector ) ;
}
2021-04-27 11:08:23 -04:00
}
2021-07-26 17:57:22 -04:00
LastTransformerFrame = TransformFrame ;
2019-12-19 18:07:47 -05:00
// close change record
2021-07-26 17:57:22 -04:00
EndDeformerChange ( ) ;
2019-12-19 18:07:47 -05:00
}
2019-10-01 20:41:42 -04:00
2019-12-19 18:07:47 -05:00
void UEditMeshPolygonsTool : : UpdateDeformerFromSelection ( const FGroupTopologySelection & Selection )
{
//Determine which of the following (corners, edges or faces) has been selected by counting the associated feature's IDs
if ( Selection . SelectedCornerIDs . Num ( ) > 0 )
{
//Add all the the Corner's adjacent poly-groups (NbrGroups) to the ongoing array of groups.
2020-09-24 00:43:27 -04:00
LinearDeformer . SetActiveHandleCorners ( Selection . SelectedCornerIDs . Array ( ) ) ;
2019-12-19 18:07:47 -05:00
}
else if ( Selection . SelectedEdgeIDs . Num ( ) > 0 )
{
//Add all the the edge's adjacent poly-groups (NbrGroups) to the ongoing array of groups.
2020-09-24 00:43:27 -04:00
LinearDeformer . SetActiveHandleEdges ( Selection . SelectedEdgeIDs . Array ( ) ) ;
2019-12-19 18:07:47 -05:00
}
else if ( Selection . SelectedGroupIDs . Num ( ) > 0 )
{
2020-09-24 00:43:27 -04:00
LinearDeformer . SetActiveHandleFaces ( Selection . SelectedGroupIDs . Array ( ) ) ;
2019-12-19 18:07:47 -05:00
}
}
void UEditMeshPolygonsTool : : ComputeUpdate_Gizmo ( )
{
2020-03-05 18:07:34 -05:00
if ( SelectionMechanic - > HasSelection ( ) = = false | | bGizmoUpdatePending = = false )
2019-12-19 18:07:47 -05:00
{
return ;
}
2020-03-05 18:07:34 -05:00
bGizmoUpdatePending = false ;
2019-12-19 18:07:47 -05:00
2020-03-05 18:07:34 -05:00
FFrame3d CurFrame = LastUpdateGizmoFrame ;
FVector3d CurScale = LastUpdateGizmoScale ;
2020-01-27 20:11:15 -05:00
FVector3d TranslationDelta = CurFrame . Origin - InitialGizmoFrame . Origin ;
FQuaterniond RotateDelta = CurFrame . Rotation - InitialGizmoFrame . Rotation ;
FVector3d CurScaleDelta = CurScale - InitialGizmoScale ;
2021-03-30 21:25:22 -04:00
FVector3d LocalTranslation = WorldTransform . InverseTransformVector ( TranslationDelta ) ;
2019-12-19 18:07:47 -05:00
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
if ( TranslationDelta . SquaredLength ( ) > 0.0001 | | RotateDelta . SquaredLength ( ) > 0.0001 | | CurScaleDelta . SquaredLength ( ) > 0.0001 )
2019-12-19 18:07:47 -05:00
{
2021-01-14 19:07:52 -04:00
if ( bLastUpdateUsedWorldFrame )
2019-12-19 18:07:47 -05:00
{
2021-01-14 19:07:52 -04:00
// For a world frame gizmo, the scaling needs to happen in world aligned gizmo space, but the
// rotation is still encoded in the local gizmo frame change.
FQuaterniond RotationToApply = CurFrame . Rotation * InitialGizmoFrame . Rotation . Inverse ( ) ;
LinearDeformer . UpdateSolution ( Mesh , [ & ] ( FDynamicMesh3 * TargetMesh , int VertIdx )
{
FVector3d PosLocal = TargetMesh - > GetVertex ( VertIdx ) ;
FVector3d PosWorld = WorldTransform . TransformPosition ( PosLocal ) ;
FVector3d PosWorldGizmo = PosWorld - InitialGizmoFrame . Origin ;
FVector3d NewPosWorld = RotationToApply * ( PosWorldGizmo * CurScale ) + CurFrame . Origin ;
FVector3d NewPosLocal = WorldTransform . InverseTransformPosition ( NewPosWorld ) ;
return NewPosLocal ;
} ) ;
}
else
{
LinearDeformer . UpdateSolution ( Mesh , [ & ] ( FDynamicMesh3 * TargetMesh , int VertIdx )
{
// For a local gizmo, we just get the coordinates in the original frame, scale in that frame,
// then interpret them as coordinates in the new frame.
FVector3d PosLocal = TargetMesh - > GetVertex ( VertIdx ) ;
FVector3d PosWorld = WorldTransform . TransformPosition ( PosLocal ) ;
FVector3d PosGizmo = InitialGizmoFrame . ToFramePoint ( PosWorld ) ;
PosGizmo = CurScale * PosGizmo ;
FVector3d NewPosWorld = CurFrame . FromFramePoint ( PosGizmo ) ;
FVector3d NewPosLocal = WorldTransform . InverseTransformPosition ( NewPosWorld ) ;
return NewPosLocal ;
} ) ;
}
2019-12-19 18:07:47 -05:00
}
else
{
// Reset mesh to initial positions.
LinearDeformer . ClearSolution ( Mesh ) ;
}
2021-07-26 17:57:22 -04:00
Preview - > PreviewMesh - > UpdatePreview ( CurrentMesh . Get ( ) ) ;
2019-12-19 18:07:47 -05:00
GetToolManager ( ) - > PostInvalidation ( ) ;
}
2020-04-18 18:42:59 -04:00
void UEditMeshPolygonsTool : : OnTick ( float DeltaTime )
2019-10-01 20:41:42 -04:00
{
2022-02-02 05:52:52 -05:00
if ( bToolDisabled )
{
return ;
}
2021-07-26 17:57:22 -04:00
Preview - > Tick ( DeltaTime ) ;
if ( CurrentActivity )
{
CurrentActivity - > Tick ( DeltaTime ) ;
}
2019-10-01 20:41:42 -04:00
2021-04-27 11:08:23 -04:00
bool bLocalCoordSystem = GetToolManager ( ) - > GetPairedGizmoManager ( )
- > GetContextQueriesAPI ( ) - > GetCurrentCoordinateSystem ( ) = = EToolContextCoordinateSystem : : Local ;
if ( CommonProps - > bLocalCoordSystem ! = bLocalCoordSystem )
{
CommonProps - > bLocalCoordSystem = bLocalCoordSystem ;
NotifyOfPropertyChangeByTool ( CommonProps ) ;
}
2020-03-05 18:07:34 -05:00
if ( bGizmoUpdatePending )
{
ComputeUpdate_Gizmo ( ) ;
}
2020-01-27 20:11:15 -05:00
if ( bSelectionStateDirty )
{
// update color highlights
2021-07-26 17:57:22 -04:00
Preview - > PreviewMesh - > FastNotifySecondaryTrianglesChanged ( ) ;
2019-10-01 20:41:42 -04:00
2021-07-26 17:57:22 -04:00
UpdateGizmoVisibility ( ) ;
2019-10-01 20:41:42 -04:00
2020-01-27 20:11:15 -05:00
bSelectionStateDirty = false ;
2019-10-01 20:41:42 -04:00
}
2020-01-27 20:11:15 -05:00
if ( PendingAction ! = EEditMeshPolygonsToolActions : : NoAction )
2019-10-01 20:41:42 -04:00
{
2021-07-26 17:57:22 -04:00
// Clear any existing error messages.
GetToolManager ( ) - > DisplayMessage ( FText ( ) , EToolMessageLevel : : UserWarning ) ;
2020-02-21 14:21:06 -05:00
2021-07-26 17:57:22 -04:00
switch ( PendingAction )
2019-10-01 20:41:42 -04:00
{
2021-07-26 17:57:22 -04:00
//Interactive operations:
case EEditMeshPolygonsToolActions : : Extrude :
{
2021-10-19 08:11:46 -04:00
ExtrudeActivity - > ExtrudeMode = FExtrudeOp : : EExtrudeMode : : MoveAndStitch ;
ExtrudeActivity - > PropertySetToUse = UPolyEditExtrudeActivity : : EPropertySetToUse : : Extrude ;
2021-08-30 15:02:57 -04:00
StartActivity ( ExtrudeActivity ) ;
break ;
}
case EEditMeshPolygonsToolActions : : PushPull :
{
2021-10-19 08:11:46 -04:00
ExtrudeActivity - > ExtrudeMode = FExtrudeOp : : EExtrudeMode : : Boolean ;
ExtrudeActivity - > PropertySetToUse = UPolyEditExtrudeActivity : : EPropertySetToUse : : PushPull ;
StartActivity ( ExtrudeActivity ) ;
break ;
}
case EEditMeshPolygonsToolActions : : Offset :
{
ExtrudeActivity - > ExtrudeMode = FExtrudeOp : : EExtrudeMode : : MoveAndStitch ;
ExtrudeActivity - > PropertySetToUse = UPolyEditExtrudeActivity : : EPropertySetToUse : : Offset ;
2021-07-26 17:57:22 -04:00
StartActivity ( ExtrudeActivity ) ;
break ;
2019-10-01 20:41:42 -04:00
}
2021-07-29 15:22:26 -04:00
case EEditMeshPolygonsToolActions : : Inset :
2019-10-01 20:41:42 -04:00
{
2021-07-29 15:22:26 -04:00
InsetOutsetActivity - > Settings - > bOutset = false ;
StartActivity ( InsetOutsetActivity ) ;
break ;
}
case EEditMeshPolygonsToolActions : : Outset :
{
InsetOutsetActivity - > Settings - > bOutset = true ;
2021-07-26 17:57:22 -04:00
StartActivity ( InsetOutsetActivity ) ;
break ;
2019-10-01 20:41:42 -04:00
}
2021-07-26 17:57:22 -04:00
case EEditMeshPolygonsToolActions : : CutFaces :
2019-10-01 20:41:42 -04:00
{
2021-07-26 17:57:22 -04:00
StartActivity ( CutFacesActivity ) ;
break ;
2020-01-27 20:11:15 -05:00
}
2021-07-26 17:57:22 -04:00
case EEditMeshPolygonsToolActions : : PlanarProjectionUV :
2020-01-27 20:11:15 -05:00
{
2021-07-26 17:57:22 -04:00
StartActivity ( PlanarProjectionUVActivity ) ;
break ;
2020-01-27 20:11:15 -05:00
}
2021-07-26 17:57:22 -04:00
case EEditMeshPolygonsToolActions : : InsertEdge :
2020-01-27 20:11:15 -05:00
{
2021-07-26 17:57:22 -04:00
StartActivity ( InsertEdgeActivity ) ;
break ;
2020-01-27 20:11:15 -05:00
}
2021-07-26 17:57:22 -04:00
case EEditMeshPolygonsToolActions : : InsertEdgeLoop :
2020-01-27 20:11:15 -05:00
{
2021-07-26 17:57:22 -04:00
StartActivity ( InsertEdgeLoopActivity ) ;
break ;
}
2021-11-16 13:24:21 -05:00
case EEditMeshPolygonsToolActions : : BevelFaces :
case EEditMeshPolygonsToolActions : : BevelEdges :
{
StartActivity ( BevelEdgeActivity ) ;
break ;
}
2021-07-26 17:57:22 -04:00
case EEditMeshPolygonsToolActions : : CancelCurrent :
{
2021-11-16 13:24:21 -05:00
EndCurrentActivity ( EToolShutdownType : : Cancel ) ;
break ;
}
case EEditMeshPolygonsToolActions : : AcceptCurrent :
{
EndCurrentActivity ( EToolShutdownType : : Accept ) ;
2021-07-26 17:57:22 -04:00
break ;
}
// Single action operations:
case EEditMeshPolygonsToolActions : : Merge :
2020-01-27 20:11:15 -05:00
ApplyMerge ( ) ;
2021-07-26 17:57:22 -04:00
break ;
case EEditMeshPolygonsToolActions : : Delete :
2020-01-27 20:11:15 -05:00
ApplyDelete ( ) ;
2021-07-26 17:57:22 -04:00
break ;
case EEditMeshPolygonsToolActions : : RecalculateNormals :
2020-01-27 20:11:15 -05:00
ApplyRecalcNormals ( ) ;
2021-07-26 17:57:22 -04:00
break ;
case EEditMeshPolygonsToolActions : : FlipNormals :
2020-01-27 20:11:15 -05:00
ApplyFlipNormals ( ) ;
2021-07-26 17:57:22 -04:00
break ;
case EEditMeshPolygonsToolActions : : CollapseEdge :
2020-01-27 20:11:15 -05:00
ApplyCollapseEdge ( ) ;
2021-07-26 17:57:22 -04:00
break ;
case EEditMeshPolygonsToolActions : : WeldEdges :
2020-01-27 20:11:15 -05:00
ApplyWeldEdges ( ) ;
2021-07-26 17:57:22 -04:00
break ;
case EEditMeshPolygonsToolActions : : StraightenEdge :
2020-01-27 20:11:15 -05:00
ApplyStraightenEdges ( ) ;
2021-07-26 17:57:22 -04:00
break ;
case EEditMeshPolygonsToolActions : : FillHole :
2020-01-27 20:11:15 -05:00
ApplyFillHole ( ) ;
2021-07-26 17:57:22 -04:00
break ;
2022-06-09 15:08:03 -04:00
case EEditMeshPolygonsToolActions : : BridgeEdges :
ApplyBridgeEdges ( ) ;
break ;
2021-07-26 17:57:22 -04:00
case EEditMeshPolygonsToolActions : : Retriangulate :
2020-01-27 20:11:15 -05:00
ApplyRetriangulate ( ) ;
2021-07-26 17:57:22 -04:00
break ;
case EEditMeshPolygonsToolActions : : Decompose :
2020-01-27 20:11:15 -05:00
ApplyDecompose ( ) ;
2021-07-26 17:57:22 -04:00
break ;
case EEditMeshPolygonsToolActions : : Disconnect :
2020-01-27 20:11:15 -05:00
ApplyDisconnect ( ) ;
2021-07-26 17:57:22 -04:00
break ;
case EEditMeshPolygonsToolActions : : Duplicate :
2021-05-20 19:44:37 -04:00
ApplyDuplicate ( ) ;
2021-07-26 17:57:22 -04:00
break ;
case EEditMeshPolygonsToolActions : : PokeSingleFace :
2020-01-27 20:11:15 -05:00
ApplyPokeSingleFace ( ) ;
2021-07-26 17:57:22 -04:00
break ;
case EEditMeshPolygonsToolActions : : SplitSingleEdge :
2020-01-27 20:11:15 -05:00
ApplySplitSingleEdge ( ) ;
2021-07-26 17:57:22 -04:00
break ;
case EEditMeshPolygonsToolActions : : CollapseSingleEdge :
2020-01-27 20:11:15 -05:00
ApplyCollapseSingleEdge ( ) ;
2021-07-26 17:57:22 -04:00
break ;
case EEditMeshPolygonsToolActions : : FlipSingleEdge :
2020-01-27 20:11:15 -05:00
ApplyFlipSingleEdge ( ) ;
2021-07-26 17:57:22 -04:00
break ;
2021-09-16 23:16:23 -04:00
case EEditMeshPolygonsToolActions : : SimplifyByGroups :
SimplifyByGroups ( ) ;
break ;
2020-01-27 20:11:15 -05:00
}
PendingAction = EEditMeshPolygonsToolActions : : NoAction ;
}
2019-10-01 20:41:42 -04:00
}
2021-07-26 17:57:22 -04:00
void UEditMeshPolygonsTool : : StartActivity ( TObjectPtr < UInteractiveToolActivity > Activity )
2019-10-01 20:41:42 -04:00
{
2021-07-26 17:57:22 -04:00
EndCurrentActivity ( ) ;
2019-10-01 20:41:42 -04:00
2021-07-26 17:57:22 -04:00
// Right now we rely on the activity to fail to start or to issue an error message if the
// conditions are not right. Someday, we are going to disable the buttons based on a CanStart
// call.
if ( Activity - > Start ( ) = = EToolActivityStartResult : : Running )
{
2022-06-02 16:45:08 -04:00
if ( TransformGizmo )
{
TransformGizmo - > SetVisibility ( false ) ;
}
2021-07-26 17:57:22 -04:00
SelectionMechanic - > SetIsEnabled ( false ) ;
2022-01-28 10:27:25 -05:00
SetToolPropertySourceEnabled ( SelectionMechanic - > Properties , false ) ;
2021-07-26 17:57:22 -04:00
CurrentActivity = Activity ;
2022-03-11 11:01:04 -05:00
if ( CurrentActivity - > HasAccept ( ) )
2021-11-16 13:24:21 -05:00
{
SetToolPropertySourceEnabled ( AcceptCancelAction , true ) ;
}
else
{
SetToolPropertySourceEnabled ( CancelAction , true ) ;
}
2021-07-26 17:57:22 -04:00
SetActionButtonPanelsVisible ( false ) ;
}
2019-10-01 20:41:42 -04:00
}
2021-07-29 15:22:26 -04:00
void UEditMeshPolygonsTool : : EndCurrentActivity ( EToolShutdownType ShutdownType )
2021-07-26 17:57:22 -04:00
{
if ( CurrentActivity )
{
if ( CurrentActivity - > IsRunning ( ) )
{
2021-07-29 15:22:26 -04:00
CurrentActivity - > End ( ShutdownType ) ;
2021-07-26 17:57:22 -04:00
}
2019-10-01 20:41:42 -04:00
2021-07-26 17:57:22 -04:00
CurrentActivity = nullptr ;
+ + ActivityTimestamp ;
SetToolPropertySourceEnabled ( CancelAction , false ) ;
2021-11-16 13:24:21 -05:00
SetToolPropertySourceEnabled ( AcceptCancelAction , false ) ;
2021-07-26 17:57:22 -04:00
SetActionButtonPanelsVisible ( true ) ;
SelectionMechanic - > SetIsEnabled ( true ) ;
2022-01-28 10:27:25 -05:00
SetToolPropertySourceEnabled ( SelectionMechanic - > Properties , true ) ;
2021-07-26 17:57:22 -04:00
UpdateGizmoVisibility ( ) ;
}
2022-06-08 16:27:18 -04:00
// If an activity displays a notification, it should be
// overwritten with an appropriate notification once finished
ResetUserMessage ( ) ;
2021-07-26 17:57:22 -04:00
}
void UEditMeshPolygonsTool : : NotifyActivitySelfEnded ( UInteractiveToolActivity * Activity )
{
EndCurrentActivity ( ) ;
}
void UEditMeshPolygonsTool : : UpdateGizmoVisibility ( )
{
2022-06-08 16:27:18 -04:00
// Only allow gizmo to become visible if something is selected,
// the gizmo isn't hidden, and there is no current activity.
if ( SelectionMechanic - > HasSelection ( ) & & CommonProps - > bGizmoVisible & & ! CurrentActivity )
2021-07-26 17:57:22 -04:00
{
2022-06-02 16:45:08 -04:00
if ( TransformGizmo )
{
TransformGizmo - > SetVisibility ( true ) ;
}
2021-07-26 17:57:22 -04:00
2022-06-08 16:27:18 -04:00
// Update frame because we might be here due to an undo event/etc,
// rather than an explicit selection change
2021-07-26 17:57:22 -04:00
LastGeometryFrame = SelectionMechanic - > GetSelectionFrame ( true , & LastGeometryFrame ) ;
UpdateGizmoFrame ( ) ;
}
2022-06-08 16:27:18 -04:00
else if ( TransformGizmo )
2021-07-26 17:57:22 -04:00
{
2022-06-08 16:27:18 -04:00
TransformGizmo - > SetVisibility ( false ) ;
2021-07-26 17:57:22 -04:00
}
}
2019-10-01 20:41:42 -04:00
void UEditMeshPolygonsTool : : Render ( IToolsContextRenderAPI * RenderAPI )
{
2022-02-02 05:52:52 -05:00
if ( bToolDisabled )
{
return ;
}
2021-07-26 17:57:22 -04:00
Preview - > PreviewMesh - > EnableWireframe ( CommonProps - > bShowWireframe ) ;
2020-01-27 20:11:15 -05:00
SelectionMechanic - > Render ( RenderAPI ) ;
2021-01-14 19:07:52 -04:00
DragAlignmentMechanic - > Render ( RenderAPI ) ;
2021-07-26 17:57:22 -04:00
if ( CurrentActivity )
2019-10-01 20:41:42 -04:00
{
2021-07-26 17:57:22 -04:00
CurrentActivity - > Render ( RenderAPI ) ;
2019-10-01 20:41:42 -04:00
}
}
2020-11-13 12:09:55 -04:00
void UEditMeshPolygonsTool : : DrawHUD ( FCanvas * Canvas , IToolsContextRenderAPI * RenderAPI )
{
2022-02-02 05:52:52 -05:00
if ( bToolDisabled )
{
return ;
}
2020-11-13 12:09:55 -04:00
SelectionMechanic - > DrawHUD ( Canvas , RenderAPI ) ;
}
2022-06-07 18:25:43 -04:00
void UEditMeshPolygonsTool : : OnPropertyModified ( UObject * PropertySet , FProperty * Property )
{
if ( Property & & ( Property - > GetFName ( ) = = GET_MEMBER_NAME_CHECKED ( UPolyEditCommonProperties , bShowSelectableCorners ) ) )
{
SelectionMechanic - > SetShowSelectableCorners ( CommonProps - > bShowSelectableCorners ) ;
}
}
2019-10-01 20:41:42 -04:00
//
2021-07-26 17:57:22 -04:00
// Gizmo change tracking
2019-10-01 20:41:42 -04:00
//
2021-07-26 17:57:22 -04:00
void UEditMeshPolygonsTool : : UpdateDeformerChangeFromROI ( bool bFinal )
2019-10-01 20:41:42 -04:00
{
if ( ActiveVertexChange = = nullptr )
{
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-04-18 18:42:59 -04:00
ActiveVertexChange - > SaveVertices ( Mesh , LinearDeformer . GetModifiedVertices ( ) , ! bFinal ) ;
2020-03-05 18:07:34 -05:00
ActiveVertexChange - > SaveOverlayNormals ( Mesh , LinearDeformer . GetModifiedOverlayNormals ( ) , ! bFinal ) ;
2019-10-01 20:41:42 -04:00
}
2021-07-26 17:57:22 -04:00
void UEditMeshPolygonsTool : : BeginDeformerChange ( )
2019-10-01 20:41:42 -04:00
{
2019-12-19 18:07:47 -05:00
if ( ActiveVertexChange = = nullptr )
2019-10-01 20:41:42 -04:00
{
2020-04-18 18:42:59 -04:00
ActiveVertexChange = new FMeshVertexChangeBuilder ( EMeshVertexChangeComponents : : VertexPositions | EMeshVertexChangeComponents : : OverlayNormals ) ;
2021-07-26 17:57:22 -04:00
UpdateDeformerChangeFromROI ( false ) ;
2019-10-01 20:41:42 -04:00
}
}
2021-07-26 17:57:22 -04:00
void UEditMeshPolygonsTool : : EndDeformerChange ( )
2019-10-01 20:41:42 -04:00
{
if ( ActiveVertexChange ! = nullptr )
{
2021-07-26 17:57:22 -04:00
UpdateDeformerChangeFromROI ( true ) ;
GetToolManager ( ) - > EmitObjectChange ( this , MoveTemp ( ActiveVertexChange - > Change ) ,
LOCTEXT ( " PolyMeshDeformationChange " , " PolyMesh Edit " ) ) ;
2019-10-01 20:41:42 -04:00
}
delete ActiveVertexChange ;
ActiveVertexChange = nullptr ;
2020-01-27 20:11:15 -05:00
}
2021-07-26 17:57:22 -04:00
// This gets called by vertex change events emitted via gizmo (deformer) interaction
void UEditMeshPolygonsTool : : ApplyChange ( const FMeshVertexChange * Change , bool bRevert )
2020-01-27 20:11:15 -05:00
{
2021-07-26 17:57:22 -04:00
Preview - > PreviewMesh - > ApplyChange ( Change , bRevert ) ;
CurrentMesh - > Copy ( * Preview - > PreviewMesh - > GetMesh ( ) ) ;
2020-01-27 20:11:15 -05:00
bSpatialDirty = true ;
SelectionMechanic - > NotifyMeshChanged ( false ) ;
2021-07-26 17:57:22 -04:00
// Topology does not need updating
2020-01-27 20:11:15 -05:00
}
2021-07-26 17:57:22 -04:00
void UEditMeshPolygonsTool : : UpdateFromCurrentMesh ( bool bGroupTopologyModified )
2020-01-27 20:11:15 -05:00
{
2021-07-26 17:57:22 -04:00
Preview - > PreviewMesh - > UpdatePreview ( CurrentMesh . Get ( ) ,
bGroupTopologyModified ? UPreviewMesh : : ERenderUpdateMode : : FullUpdate : UPreviewMesh : : ERenderUpdateMode : : FastUpdate ) ;
2020-01-27 20:11:15 -05:00
bSpatialDirty = true ;
2021-07-26 17:57:22 -04:00
SelectionMechanic - > NotifyMeshChanged ( bGroupTopologyModified ) ;
2020-01-27 20:11:15 -05:00
2021-07-26 17:57:22 -04:00
if ( bGroupTopologyModified )
2020-01-27 20:11:15 -05:00
{
2021-07-26 17:57:22 -04:00
Topology - > RebuildTopology ( ) ;
2020-01-27 20:11:15 -05:00
}
}
void UEditMeshPolygonsTool : : ApplyMerge ( )
{
2021-04-05 15:05:51 -04:00
if ( BeginMeshFaceEditChange ( ) = = false )
2020-01-27 20:11:15 -05:00
{
GetToolManager ( ) - > DisplayMessage (
LOCTEXT ( " OnMergeFailedMessage " , " Cannot Merge Current Selection " ) ,
EToolMessageLevel : : UserWarning ) ;
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
2021-04-05 15:05:51 -04:00
ChangeTracker . SaveTriangles ( ActiveTriangleSelection , true ) ;
2020-01-27 20:11:15 -05:00
FMeshConnectedComponents Components ( Mesh ) ;
Components . FindConnectedTriangles ( ActiveTriangleSelection ) ;
FGroupTopologySelection NewSelection ;
for ( const FMeshConnectedComponents : : FComponent & Component : Components )
{
int32 NewGroupID = Mesh - > AllocateTriangleGroup ( ) ;
FaceGroupUtil : : SetGroupID ( * Mesh , Component . Indices , NewGroupID ) ;
NewSelection . SelectedGroupIDs . Add ( NewGroupID ) ;
}
2022-01-11 06:48:50 -05:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshMergeChange " , " Merge " ) ,
ChangeTracker . EndChange ( ) , NewSelection ) ;
2020-01-27 20:11:15 -05:00
}
void UEditMeshPolygonsTool : : ApplyDelete ( )
{
if ( BeginMeshFaceEditChange ( ) = = false )
{
GetToolManager ( ) - > DisplayMessage (
LOCTEXT ( " OnDeleteFailedMessage " , " Cannot Delete Current Selection " ) ,
EToolMessageLevel : : UserWarning ) ;
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
2021-04-05 15:05:51 -04:00
// prevent deleting all triangles
if ( ActiveTriangleSelection . Num ( ) > = Mesh - > TriangleCount ( ) )
{
GetToolManager ( ) - > DisplayMessage (
LOCTEXT ( " OnDeleteAllFailedMessage " , " Cannot Delete Entire Mesh " ) ,
EToolMessageLevel : : UserWarning ) ;
return ;
}
2020-01-27 20:11:15 -05:00
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
ChangeTracker . SaveTriangles ( ActiveTriangleSelection , true ) ;
FDynamicMeshEditor Editor ( Mesh ) ;
Editor . RemoveTriangles ( ActiveTriangleSelection , true ) ;
FGroupTopologySelection NewSelection ;
2022-01-11 06:48:50 -05:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshDeleteChange " , " Delete " ) ,
ChangeTracker . EndChange ( ) , NewSelection ) ;
2020-01-27 20:11:15 -05:00
}
void UEditMeshPolygonsTool : : ApplyRecalcNormals ( )
{
if ( BeginMeshFaceEditChange ( ) = = false )
{
GetToolManager ( ) - > DisplayMessage (
LOCTEXT ( " OnRecalcNormalsFailedMessage " , " Cannot Recalculate Normals for Current Selection " ) ,
EToolMessageLevel : : UserWarning ) ;
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
FDynamicMeshEditor Editor ( Mesh ) ;
FGroupTopologySelection ActiveSelection = SelectionMechanic - > GetActiveSelection ( ) ;
for ( int32 GroupID : ActiveSelection . SelectedGroupIDs )
{
ChangeTracker . SaveTriangles ( Topology - > GetGroupTriangles ( GroupID ) , true ) ;
Editor . SetTriangleNormals ( Topology - > GetGroupTriangles ( GroupID ) ) ;
}
2021-07-26 17:57:22 -04:00
// We actually don't even need any of the wrapper around this change since we're not altering
// positions or topology (so no other structures need updating), but we go ahead and go the
2022-01-11 06:48:50 -05:00
// same route as everything else. See :HandlePositionOnlyMeshChanges
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshRecalcNormalsChange " , " Recalculate Normals " ) ,
ChangeTracker . EndChange ( ) , ActiveSelection ) ;
2020-01-27 20:11:15 -05:00
}
void UEditMeshPolygonsTool : : ApplyFlipNormals ( )
{
if ( BeginMeshFaceEditChange ( ) = = false )
{
GetToolManager ( ) - > DisplayMessage (
LOCTEXT ( " OnFlipNormalsFailedMessage " , " Cannot Flip Normals for Current Selection " ) ,
EToolMessageLevel : : UserWarning ) ;
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
FDynamicMeshEditor Editor ( Mesh ) ;
FGroupTopologySelection ActiveSelection = SelectionMechanic - > GetActiveSelection ( ) ;
for ( int32 GroupID : ActiveSelection . SelectedGroupIDs )
{
for ( int32 tid : Topology - > GetGroupTriangles ( GroupID ) )
{
ChangeTracker . SaveTriangle ( tid , true ) ;
Mesh - > ReverseTriOrientation ( tid ) ;
}
}
2021-10-21 22:27:36 -04:00
// Note the topology can change in that the ordering of edge elements can reverse
2021-07-26 17:57:22 -04:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshFlipNormalsChange " , " Flip Normals " ) ,
2022-01-11 06:48:50 -05:00
ChangeTracker . EndChange ( ) , ActiveSelection ) ;
2020-01-27 20:11:15 -05:00
}
void UEditMeshPolygonsTool : : ApplyRetriangulate ( )
{
if ( BeginMeshFaceEditChange ( ) = = false )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " OnRetriangulateFailed " , " Cannot Retriangulate Current Selection " ) , EToolMessageLevel : : UserWarning ) ;
return ;
}
int32 nCompleted = 0 ;
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
FDynamicMeshEditor Editor ( Mesh ) ;
FGroupTopologySelection ActiveSelection = SelectionMechanic - > GetActiveSelection ( ) ;
for ( int32 GroupID : ActiveSelection . SelectedGroupIDs )
{
const TArray < int32 > & Triangles = Topology - > GetGroupTriangles ( GroupID ) ;
ChangeTracker . SaveTriangles ( Triangles , true ) ;
FMeshRegionBoundaryLoops RegionLoops ( Mesh , Triangles , true ) ;
2020-02-14 18:50:11 -05:00
if ( ! RegionLoops . bFailed & & RegionLoops . Loops . Num ( ) = = 1 & & Triangles . Num ( ) > 1 )
2020-01-27 20:11:15 -05:00
{
2020-09-24 00:43:27 -04:00
TArray < FMeshRegionBoundaryLoops : : VidOverlayMap < FVector2f > > VidUVMaps ;
if ( Mesh - > HasAttributes ( ) )
{
const FDynamicMeshAttributeSet * Attributes = Mesh - > Attributes ( ) ;
for ( int i = 0 ; i < Attributes - > NumUVLayers ( ) ; + + i )
{
VidUVMaps . Emplace ( ) ;
RegionLoops . GetLoopOverlayMap ( RegionLoops . Loops [ 0 ] , * Attributes - > GetUVLayer ( i ) , VidUVMaps . Last ( ) ) ;
}
}
// We don't want to remove isolated vertices while removing triangles because we don't
// want to throw away boundary verts. However, this means that we'll have to go back
// through these vertices later to throw away isolated internal verts.
TArray < int32 > OldVertices ;
2021-05-22 01:32:46 -04:00
UE : : Geometry : : TriangleToVertexIDs ( Mesh , Triangles , OldVertices ) ;
2020-09-24 00:43:27 -04:00
Editor . RemoveTriangles ( Topology - > GetGroupTriangles ( GroupID ) , false ) ;
2020-01-27 20:11:15 -05:00
RegionLoops . Loops [ 0 ] . Reverse ( ) ;
FSimpleHoleFiller Filler ( Mesh , RegionLoops . Loops [ 0 ] ) ;
Filler . FillType = FSimpleHoleFiller : : EFillType : : PolygonEarClipping ;
Filler . Fill ( GroupID ) ;
2020-09-24 00:43:27 -04:00
// Throw away any of the old verts that are still isolated (they were in the interior of the group)
2021-10-12 21:21:22 -04:00
Algo : : ForEachIf ( OldVertices ,
[ Mesh ] ( int32 Vid )
{
return ! Mesh - > IsReferencedVertex ( Vid ) ;
} ,
[ Mesh ] ( int32 Vid )
{
checkSlow ( ! Mesh - > IsReferencedVertex ( Vid ) ) ;
constexpr bool bPreserveManifold = false ;
Mesh - > RemoveVertex ( Vid , bPreserveManifold ) ;
}
2020-09-24 00:43:27 -04:00
) ;
if ( Mesh - > HasAttributes ( ) )
{
const FDynamicMeshAttributeSet * Attributes = Mesh - > Attributes ( ) ;
for ( int i = 0 ; i < Attributes - > NumUVLayers ( ) ; + + i )
{
RegionLoops . UpdateLoopOverlayMapValidity ( VidUVMaps [ i ] , * Attributes - > GetUVLayer ( i ) ) ;
}
Filler . UpdateAttributes ( VidUVMaps ) ;
}
2020-01-27 20:11:15 -05:00
nCompleted + + ;
}
}
if ( nCompleted ! = ActiveSelection . SelectedGroupIDs . Num ( ) )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " OnRetriangulateFailures " , " Some faces could not be retriangulated " ) , EToolMessageLevel : : UserWarning ) ;
}
2022-01-11 06:48:50 -05:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshRetriangulateChange " , " Retriangulate " ) ,
ChangeTracker . EndChange ( ) , ActiveSelection ) ;
2020-01-27 20:11:15 -05:00
}
2021-09-16 23:16:23 -04:00
void UEditMeshPolygonsTool : : SimplifyByGroups ( )
{
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
ChangeTracker . SaveTriangles ( Mesh - > TriangleIndicesItr ( ) , true ) ; // We will change the entire mesh
FPolygroupRemesh Remesh ( Mesh , Topology . Get ( ) , ConstrainedDelaunayTriangulate < double > ) ;
bool bSuccess = Remesh . Compute ( ) ;
if ( ! bSuccess )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " OnSimplifyByGroupFailures " , " Some polygroups could not be correctly simplified " ) , EToolMessageLevel : : UserWarning ) ;
}
FGroupTopologySelection NewSelection ; // Empty the selection
2022-01-11 06:48:50 -05:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshSimplifyByGroup " , " Simplify by Group " ) ,
ChangeTracker . EndChange ( ) , NewSelection ) ;
2021-09-16 23:16:23 -04:00
}
2020-01-27 20:11:15 -05:00
void UEditMeshPolygonsTool : : ApplyDecompose ( )
{
if ( BeginMeshFaceEditChange ( ) = = false )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " OnDecomposeFailed " , " Cannot Decompose Current Selection " ) , EToolMessageLevel : : UserWarning ) ;
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
FGroupTopologySelection NewSelection ;
for ( int32 GroupID : SelectionMechanic - > GetActiveSelection ( ) . SelectedGroupIDs )
{
const TArray < int32 > & Triangles = Topology - > GetGroupTriangles ( GroupID ) ;
2021-04-05 15:05:51 -04:00
ChangeTracker . SaveTriangles ( Triangles , true ) ;
2020-01-27 20:11:15 -05:00
for ( int32 tid : Triangles )
{
int32 NewGroupID = Mesh - > AllocateTriangleGroup ( ) ;
Mesh - > SetTriangleGroup ( tid , NewGroupID ) ;
NewSelection . SelectedGroupIDs . Add ( NewGroupID ) ;
}
}
2022-01-11 06:48:50 -05:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshDecomposeChange " , " Decompose " ) ,
ChangeTracker . EndChange ( ) , NewSelection ) ;
2020-01-27 20:11:15 -05:00
}
void UEditMeshPolygonsTool : : ApplyDisconnect ( )
{
if ( BeginMeshFaceEditChange ( ) = = false )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " OnDisconnectFailed " , " Cannot Disconnect Current Selection " ) , EToolMessageLevel : : UserWarning ) ;
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
FGroupTopologySelection ActiveSelection = SelectionMechanic - > GetActiveSelection ( ) ;
TArray < int32 > AllTriangles ;
for ( int32 GroupID : ActiveSelection . SelectedGroupIDs )
{
AllTriangles . Append ( Topology - > GetGroupTriangles ( GroupID ) ) ;
}
ChangeTracker . SaveTriangles ( AllTriangles , true ) ;
FDynamicMeshEditor Editor ( Mesh ) ;
Editor . DisconnectTriangles ( AllTriangles , false ) ;
2022-01-11 06:48:50 -05:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshDisconnectChange " , " Disconnect " ) ,
ChangeTracker . EndChange ( ) , ActiveSelection ) ;
2020-01-27 20:11:15 -05:00
}
2021-05-20 19:44:37 -04:00
void UEditMeshPolygonsTool : : ApplyDuplicate ( )
{
if ( BeginMeshFaceEditChange ( ) = = false )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " OnDuplicateFailed " , " Cannot Duplicate Current Selection " ) , EToolMessageLevel : : UserWarning ) ;
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2021-05-20 19:44:37 -04:00
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
FGroupTopologySelection ActiveSelection = SelectionMechanic - > GetActiveSelection ( ) ;
TArray < int32 > AllTriangles ;
for ( int32 GroupID : ActiveSelection . SelectedGroupIDs )
{
AllTriangles . Append ( Topology - > GetGroupTriangles ( GroupID ) ) ;
}
FDynamicMeshEditor Editor ( Mesh ) ;
FMeshIndexMappings Mappings ;
FDynamicMeshEditResult EditResult ;
Editor . DuplicateTriangles ( AllTriangles , Mappings , EditResult ) ;
FGroupTopologySelection NewSelection ;
2021-06-04 19:26:45 -04:00
NewSelection . SelectedGroupIDs . Append ( bTriangleMode ? EditResult . NewTriangles : EditResult . NewGroups ) ;
2021-05-20 19:44:37 -04:00
2022-01-11 06:48:50 -05:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshDisconnectChange " , " Disconnect " ) ,
ChangeTracker . EndChange ( ) , NewSelection ) ;
2021-05-20 19:44:37 -04:00
}
2020-01-27 20:11:15 -05:00
void UEditMeshPolygonsTool : : ApplyCollapseEdge ( )
{
// AAAHHH cannot do because of overlays!
return ;
if ( SelectionMechanic - > GetActiveSelection ( ) . SelectedEdgeIDs . Num ( ) ! = 1 | | BeginMeshEdgeEditChange ( ) = = false )
{
GetToolManager ( ) - > DisplayMessage (
LOCTEXT ( " OnEdgeColllapseFailed " , " Cannot Collapse current selection " ) ,
EToolMessageLevel : : UserWarning ) ;
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
//const TArray<int32>& EdgeIDs = ActiveEdgeSelection[0].EdgeIDs;
//for (int32 eid : EdgeIDs)
//{
// if (Mesh->IsEdge(eid))
// {
// FIndex2i EdgeVerts = Mesh->GetEdgeV(eid);
// ChangeTracker.SaveVertexOneRingTriangles(EdgeVerts.A, true);
// ChangeTracker.SaveVertexOneRingTriangles(EdgeVerts.B, true);
// FDynamicMesh3::FEdgeCollapseInfo CollapseInfo;
// Mesh->CollapseEdge()
// }
//}
// emit undo
FGroupTopologySelection NewSelection ;
2022-01-11 06:48:50 -05:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshEdgeCollapseChange " , " Collapse " ) ,
ChangeTracker . EndChange ( ) , NewSelection ) ;
2020-01-27 20:11:15 -05:00
}
void UEditMeshPolygonsTool : : ApplyWeldEdges ( )
{
bool bValidInput = SelectionMechanic - > GetActiveSelection ( ) . SelectedEdgeIDs . Num ( ) = = 2 & & BeginMeshBoundaryEdgeEditChange ( true ) ;
2021-01-06 14:23:56 -04:00
bValidInput = bValidInput & & ActiveEdgeSelection . Num ( ) = = 2 ; // one of the initial edges may not have been valid
2020-01-27 20:11:15 -05:00
if ( bValidInput = = false )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " OnWeldEdgesFailed " , " Cannot Weld current selection " ) , EToolMessageLevel : : UserWarning ) ;
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
int32 EdgeIDA = Topology - > GetGroupEdgeEdges ( ActiveEdgeSelection [ 0 ] . EdgeTopoID ) [ 0 ] ;
int32 EdgeIDB = Topology - > GetGroupEdgeEdges ( ActiveEdgeSelection [ 1 ] . EdgeTopoID ) [ 0 ] ;
FIndex2i EdgeVerts [ 2 ] = { Mesh - > GetEdgeV ( EdgeIDA ) , Mesh - > GetEdgeV ( EdgeIDB ) } ;
for ( int j = 0 ; j < 2 ; + + j )
{
ChangeTracker . SaveVertexOneRingTriangles ( EdgeVerts [ j ] . A , true ) ;
ChangeTracker . SaveVertexOneRingTriangles ( EdgeVerts [ j ] . B , true ) ;
}
FDynamicMesh3 : : FMergeEdgesInfo MergeInfo ;
EMeshResult Result = Mesh - > MergeEdges ( EdgeIDB , EdgeIDA , MergeInfo ) ;
if ( Result ! = EMeshResult : : Ok )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " OnWeldEdgesFailed " , " Cannot Weld current selection " ) , EToolMessageLevel : : UserWarning ) ;
return ;
}
FGroupTopologySelection NewSelection ;
2022-01-11 06:48:50 -05:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshWeldEdgeChange " , " Weld Edges " ) ,
ChangeTracker . EndChange ( ) , NewSelection ) ;
2020-01-27 20:11:15 -05:00
}
void UEditMeshPolygonsTool : : ApplyStraightenEdges ( )
{
if ( BeginMeshEdgeEditChange ( ) = = false )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " OnStraightenEdgesFailed " , " Cannot Straighten current selection " ) , EToolMessageLevel : : UserWarning ) ;
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
for ( const FSelectedEdge & Edge : ActiveEdgeSelection )
{
const TArray < int32 > & EdgeVerts = Topology - > GetGroupEdgeVertices ( Edge . EdgeTopoID ) ;
int32 NumV = EdgeVerts . Num ( ) ;
if ( NumV > 2 )
{
2020-03-26 17:20:25 -04:00
ChangeTracker . SaveVertexOneRingTriangles ( EdgeVerts , true ) ;
2020-01-27 20:11:15 -05:00
FVector3d A ( Mesh - > GetVertex ( EdgeVerts [ 0 ] ) ) , B ( Mesh - > GetVertex ( EdgeVerts [ NumV - 1 ] ) ) ;
TArray < double > VtxArcLengths ;
double EdgeArcLen = Topology - > GetEdgeArcLength ( Edge . EdgeTopoID , & VtxArcLengths ) ;
for ( int k = 1 ; k < NumV - 1 ; + + k )
{
double t = VtxArcLengths [ k ] / EdgeArcLen ;
2021-03-17 19:32:44 -04:00
Mesh - > SetVertex ( EdgeVerts [ k ] , UE : : Geometry : : Lerp ( A , B , t ) ) ;
2020-01-27 20:11:15 -05:00
}
}
}
2022-01-11 06:48:50 -05:00
// TODO :HandlePositionOnlyMeshChanges Due to the group topology storing edge IDs that do not stay the same across
// undo/redo events even when the mesh topology stays the same after a FDynamicMeshChange, we actually have to treat
// all FDynamicMeshChange-based transactions as affecting group topology. Here we only changed vertex positions so
// we could add a separate overload that takes a FMeshVertexChange, and possibly one that takes an attribute change
// (or unify the three via an interface)
2020-01-27 20:11:15 -05:00
FGroupTopologySelection NewSelection ;
2021-07-26 17:57:22 -04:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshStraightenEdgeChange " , " Straighten Edges " ) ,
2022-01-11 06:48:50 -05:00
ChangeTracker . EndChange ( ) , NewSelection ) ;
2020-01-27 20:11:15 -05:00
}
void UEditMeshPolygonsTool : : ApplyFillHole ( )
{
if ( BeginMeshBoundaryEdgeEditChange ( false ) = = false )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " OnEdgeFillFailed " , " Cannot Fill current selection " ) , EToolMessageLevel : : UserWarning ) ;
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
FGroupTopologySelection NewSelection ;
for ( FSelectedEdge & FillEdge : ActiveEdgeSelection )
{
if ( Mesh - > IsBoundaryEdge ( FillEdge . EdgeIDs [ 0 ] ) ) // may no longer be boundary due to previous fill
{
FMeshBoundaryLoops BoundaryLoops ( Mesh ) ;
int32 LoopID = BoundaryLoops . FindLoopContainingEdge ( FillEdge . EdgeIDs [ 0 ] ) ;
if ( LoopID > = 0 )
{
FEdgeLoop & Loop = BoundaryLoops . Loops [ LoopID ] ;
FSimpleHoleFiller Filler ( Mesh , Loop ) ;
Filler . FillType = FSimpleHoleFiller : : EFillType : : PolygonEarClipping ;
int32 NewGroupID = Mesh - > AllocateTriangleGroup ( ) ;
Filler . Fill ( NewGroupID ) ;
2021-05-25 19:29:53 -04:00
if ( ! bTriangleMode )
{
NewSelection . SelectedGroupIDs . Add ( NewGroupID ) ;
}
else
{
NewSelection . SelectedGroupIDs . Append ( Filler . NewTriangles ) ;
}
2020-08-11 01:36:57 -04:00
// Compute normals and UVs
if ( Mesh - > HasAttributes ( ) )
{
2021-09-23 19:38:55 -04:00
TArray < FVector3d > VertexPositions ;
2020-08-11 01:36:57 -04:00
Loop . GetVertices ( VertexPositions ) ;
2021-09-23 19:38:55 -04:00
FVector3d PlaneOrigin ;
FVector3d PlaneNormal ;
2020-08-11 01:36:57 -04:00
PolygonTriangulation : : ComputePolygonPlane < double > ( VertexPositions , PlaneNormal , PlaneOrigin ) ;
FDynamicMeshEditor Editor ( Mesh ) ;
FFrame3d ProjectionFrame ( PlaneOrigin , PlaneNormal ) ;
Editor . SetTriangleNormals ( Filler . NewTriangles ) ;
Editor . SetTriangleUVsFromProjection ( Filler . NewTriangles , ProjectionFrame , UVScaleFactor ) ;
}
2020-01-27 20:11:15 -05:00
}
}
}
2022-01-11 06:48:50 -05:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshFillHoleChange " , " Fill Hole " ) ,
ChangeTracker . EndChange ( ) , NewSelection ) ;
2020-01-27 20:11:15 -05:00
}
2022-06-09 15:08:03 -04:00
void UEditMeshPolygonsTool : : ApplyBridgeEdges ( )
{
2022-06-10 12:20:09 -04:00
const FText BridgeFailMessage = LOCTEXT ( " OnEdgeBridgeFailed " , " Cannot Bridge current selection " ) ;
2022-06-09 15:08:03 -04:00
if ( SelectionMechanic - > GetActiveSelection ( ) . SelectedEdgeIDs . Num ( ) ! = 2 | | BeginMeshBoundaryEdgeEditChange ( false ) = = false )
{
2022-06-10 12:20:09 -04:00
GetToolManager ( ) - > DisplayMessage ( BridgeFailMessage , EToolMessageLevel : : UserWarning ) ;
2022-06-09 15:08:03 -04:00
return ;
}
2020-01-27 20:11:15 -05:00
2022-06-09 15:08:03 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
FGroupTopologySelection CurrentSelection = SelectionMechanic - > GetActiveSelection ( ) ;
TArray < int32 > LoopVertices ;
TArray < int32 > LoopEdges ;
TArray < int32 > SelectedEdgeIDs = CurrentSelection . SelectedEdgeIDs . Array ( ) ;
// I think doing this will guarantee that every edge in the span stores the vertices corresponding to the connected triangles orientation
FEdgeSpan & SpanA = Topology - > Edges [ SelectedEdgeIDs [ 0 ] ] . Span ;
FEdgeSpan & SpanB = Topology - > Edges [ SelectedEdgeIDs [ 1 ] ] . Span ;
SpanA . SetCorrectOrientation ( ) ;
SpanB . SetCorrectOrientation ( ) ;
// Disallow bridging of edge loops for now
if ( SpanA . Vertices [ 0 ] = = SpanA . Vertices . Last ( ) | | SpanB . Vertices [ 0 ] = = SpanB . Vertices . Last ( ) )
{
2022-06-10 12:20:09 -04:00
GetToolManager ( ) - > DisplayMessage ( BridgeFailMessage , EToolMessageLevel : : UserWarning ) ;
2022-06-09 15:08:03 -04:00
return ;
}
// Add all vertices from first edge
LoopVertices = SpanA . Vertices ;
// If first vertex of second edge is not a duplicate of a terminating vertex of the first edge, add vertex
if ( SpanB . Vertices [ 0 ] ! = SpanA . Vertices [ 0 ] & & SpanB . Vertices [ 0 ] ! = SpanA . Vertices . Last ( ) )
{
LoopVertices . Add ( SpanB . Vertices [ 0 ] ) ;
}
// Definitely add the non-terminating vertices of second edge.
for ( int Vertex = 1 ; Vertex < SpanB . Vertices . Num ( ) - 1 ; + + Vertex )
{
LoopVertices . Add ( SpanB . Vertices [ Vertex ] ) ;
}
// If last vertex of second edge is not a duplicate of a terminating vertex of the first edge, add vertex
if ( SpanB . Vertices . Last ( ) ! = SpanA . Vertices [ 0 ] & & SpanB . Vertices . Last ( ) ! = SpanA . Vertices . Last ( ) )
{
LoopVertices . Add ( SpanB . Vertices . Last ( ) ) ;
}
FEdgeLoop : : VertexLoopToEdgeLoop ( Mesh , LoopVertices , LoopEdges ) ;
FEdgeLoop Loop ( Mesh , LoopVertices , LoopEdges ) ;
// We could always use the minimal hole filler, but it doesn't quite do what "bridge" would suggest when
// the area to be bridged is concave (across two curved-inward edges). Meanwhile simple ear clipping
// seems to fail in some common cases for reasons that we should investigate. For now, start with ear
// clipping, and revert to minimal if needed.
FSimpleHoleFiller SimpleHoleFiller ( Mesh , Loop , FSimpleHoleFiller : : EFillType : : PolygonEarClipping ) ;
TArray < int32 > NewTriangles ;
// Fill the hole
if ( ! SimpleHoleFiller . Fill ( ) )
{
//Ear clipping doesn't add vertices, so don't need to delete isolated verts
FDynamicMeshEditor Editor ( Mesh ) ;
Editor . RemoveTriangles ( SimpleHoleFiller . NewTriangles , false ) ;
FMinimalHoleFiller MinimalHoleFiller ( Mesh , Loop ) ;
if ( ! MinimalHoleFiller . Fill ( ) )
{
Editor . RemoveTriangles ( MinimalHoleFiller . NewTriangles , false ) ;
2022-06-10 12:20:09 -04:00
GetToolManager ( ) - > DisplayMessage ( BridgeFailMessage , EToolMessageLevel : : UserWarning ) ;
2022-06-09 15:08:03 -04:00
return ;
}
else
{
NewTriangles = MinimalHoleFiller . NewTriangles ;
}
}
else {
NewTriangles = SimpleHoleFiller . NewTriangles ;
}
// Compute normals and UVs
if ( Mesh - > HasAttributes ( ) )
{
TArray < FVector3d > VertexPositions ;
Loop . GetVertices ( VertexPositions ) ;
FVector3d PlaneOrigin ;
FVector3d PlaneNormal ;
PolygonTriangulation : : ComputePolygonPlane < double > ( VertexPositions , PlaneNormal , PlaneOrigin ) ;
FDynamicMeshEditor Editor ( Mesh ) ;
FFrame3d ProjectionFrame ( PlaneOrigin , PlaneNormal ) ;
Editor . SetTriangleNormals ( NewTriangles ) ;
Editor . SetTriangleUVsFromProjection ( NewTriangles , ProjectionFrame , UVScaleFactor ) ;
}
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshBridgeEdgeChange " , " Bridge Edge " ) ,
ChangeTracker . EndChange ( ) , CurrentSelection ) ;
}
2020-01-27 20:11:15 -05:00
void UEditMeshPolygonsTool : : ApplyPokeSingleFace ( )
{
if ( BeginMeshFaceEditChange ( ) = = false )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " OnPokeFailedMessage " , " Cannot Poke Current Selection " ) , EToolMessageLevel : : UserWarning ) ;
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
2021-04-05 15:05:51 -04:00
ChangeTracker . SaveTriangles ( ActiveTriangleSelection , true ) ;
2020-01-27 20:11:15 -05:00
FGroupTopologySelection NewSelection ;
for ( int32 tid : ActiveTriangleSelection )
{
FDynamicMesh3 : : FPokeTriangleInfo PokeInfo ;
NewSelection . SelectedGroupIDs . Add ( tid ) ;
if ( Mesh - > PokeTriangle ( tid , PokeInfo ) = = EMeshResult : : Ok )
{
NewSelection . SelectedGroupIDs . Add ( PokeInfo . NewTriangles . A ) ;
NewSelection . SelectedGroupIDs . Add ( PokeInfo . NewTriangles . B ) ;
}
}
2022-01-11 06:48:50 -05:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshPokeChange " , " Poke Faces " ) ,
ChangeTracker . EndChange ( ) , NewSelection ) ;
2020-01-27 20:11:15 -05:00
}
void UEditMeshPolygonsTool : : ApplyFlipSingleEdge ( )
{
if ( BeginMeshEdgeEditChange ( ) = = false )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " OnFlipFailedMessage " , " Cannot Flip Current Selection " ) , EToolMessageLevel : : UserWarning ) ;
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
FGroupTopologySelection ActiveSelection = SelectionMechanic - > GetActiveSelection ( ) ;
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
for ( FSelectedEdge & Edge : ActiveEdgeSelection )
{
int32 eid = Edge . EdgeIDs [ 0 ] ;
if ( Mesh - > IsEdge ( eid ) & & Mesh - > IsBoundaryEdge ( eid ) = = false & & Mesh - > Attributes ( ) - > IsSeamEdge ( eid ) = = false )
{
FIndex2i et = Mesh - > GetEdgeT ( eid ) ;
ChangeTracker . SaveTriangle ( et . A , true ) ;
ChangeTracker . SaveTriangle ( et . B , true ) ;
FDynamicMesh3 : : FEdgeFlipInfo FlipInfo ;
Mesh - > FlipEdge ( eid , FlipInfo ) ;
}
}
2021-07-26 17:57:22 -04:00
// Group topology may or may not change, but just assume that it does.
2022-01-11 06:48:50 -05:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshFlipChange " , " Flip Edges " ) ,
ChangeTracker . EndChange ( ) , ActiveSelection ) ;
2020-01-27 20:11:15 -05:00
}
void UEditMeshPolygonsTool : : ApplyCollapseSingleEdge ( )
{
if ( BeginMeshEdgeEditChange ( ) = = false )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " OnCollapseFailedMessage " , " Cannot Collapse Current Selection " ) , EToolMessageLevel : : UserWarning ) ;
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
FGroupTopologySelection ActiveSelection = SelectionMechanic - > GetActiveSelection ( ) ;
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
TSet < int32 > ValidEdgeIDs ;
for ( FSelectedEdge & Edge : ActiveEdgeSelection )
{
int32 eid = Edge . EdgeIDs [ 0 ] ;
if ( Mesh - > IsEdge ( eid ) & & Mesh - > Attributes ( ) - > IsSeamEdge ( eid ) = = false )
{
ValidEdgeIDs . Add ( eid ) ;
}
}
TSet < int32 > DoneEdgeIDs ;
for ( int32 eid : ValidEdgeIDs )
{
if ( DoneEdgeIDs . Contains ( eid ) = = false & & Mesh - > IsEdge ( eid ) )
{
FIndex2i ev = Mesh - > GetEdgeV ( eid ) ;
ChangeTracker . SaveVertexOneRingTriangles ( ev . A , true ) ;
ChangeTracker . SaveVertexOneRingTriangles ( ev . B , true ) ;
FDynamicMesh3 : : FEdgeCollapseInfo CollapseInfo ;
if ( Mesh - > CollapseEdge ( ev . A , ev . B , CollapseInfo ) = = EMeshResult : : Ok )
{
DoneEdgeIDs . Add ( eid ) ;
DoneEdgeIDs . Add ( CollapseInfo . RemovedEdges . A ) ;
DoneEdgeIDs . Add ( CollapseInfo . RemovedEdges . B ) ;
}
}
}
2021-07-26 17:57:22 -04:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshCollapseChange " , " Collapse Edges " ) ,
2022-01-11 06:48:50 -05:00
ChangeTracker . EndChange ( ) , FGroupTopologySelection ( ) ) ;
2020-01-27 20:11:15 -05:00
}
void UEditMeshPolygonsTool : : ApplySplitSingleEdge ( )
{
if ( BeginMeshEdgeEditChange ( ) = = false )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " OnSplitFailedMessage " , " Cannot Split Current Selection " ) , EToolMessageLevel : : UserWarning ) ;
return ;
}
2021-07-26 17:57:22 -04:00
FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
FGroupTopologySelection NewSelection ;
FDynamicMeshChangeTracker ChangeTracker ( Mesh ) ;
ChangeTracker . BeginChange ( ) ;
for ( FSelectedEdge & Edge : ActiveEdgeSelection )
{
int32 eid = Edge . EdgeIDs [ 0 ] ;
if ( Mesh - > IsEdge ( eid ) )
{
FIndex2i et = Mesh - > GetEdgeT ( eid ) ;
ChangeTracker . SaveTriangle ( et . A , true ) ;
NewSelection . SelectedGroupIDs . Add ( et . A ) ;
if ( et . B ! = FDynamicMesh3 : : InvalidID )
{
ChangeTracker . SaveTriangle ( et . B , true ) ;
NewSelection . SelectedGroupIDs . Add ( et . B ) ;
}
FDynamicMesh3 : : FEdgeSplitInfo SplitInfo ;
if ( Mesh - > SplitEdge ( eid , SplitInfo ) = = EMeshResult : : Ok )
{
NewSelection . SelectedGroupIDs . Add ( SplitInfo . NewTriangles . A ) ;
if ( SplitInfo . NewTriangles . B ! = FDynamicMesh3 : : InvalidID )
{
NewSelection . SelectedGroupIDs . Add ( SplitInfo . NewTriangles . A ) ;
}
}
}
}
2022-01-11 06:48:50 -05:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshSplitChange " , " Split Edges " ) ,
ChangeTracker . EndChange ( ) , NewSelection ) ;
2020-01-27 20:11:15 -05:00
}
bool UEditMeshPolygonsTool : : BeginMeshFaceEditChange ( )
{
ActiveTriangleSelection . Reset ( ) ;
// need some selected faces
const FGroupTopologySelection & ActiveSelection = SelectionMechanic - > GetActiveSelection ( ) ;
Topology - > GetSelectedTriangles ( ActiveSelection , ActiveTriangleSelection ) ;
if ( ActiveSelection . SelectedGroupIDs . Num ( ) = = 0 | | ActiveTriangleSelection . Num ( ) = = 0 )
{
return false ;
}
2021-07-26 17:57:22 -04:00
const FDynamicMesh3 * Mesh = CurrentMesh . Get ( ) ;
2020-01-27 20:11:15 -05:00
ActiveSelectionBounds = FAxisAlignedBox3d : : Empty ( ) ;
for ( int tid : ActiveTriangleSelection )
{
ActiveSelectionBounds . Contain ( Mesh - > GetTriBounds ( tid ) ) ;
}
// world and local frames
ActiveSelectionFrameLocal = Topology - > GetSelectionFrame ( ActiveSelection ) ;
ActiveSelectionFrameWorld = ActiveSelectionFrameLocal ;
ActiveSelectionFrameWorld . Transform ( WorldTransform ) ;
return true ;
}
2021-07-26 17:57:22 -04:00
void UEditMeshPolygonsTool : : EmitCurrentMeshChangeAndUpdate ( const FText & TransactionLabel ,
TUniquePtr < FDynamicMeshChange > MeshChangeIn ,
2022-01-11 06:48:50 -05:00
const FGroupTopologySelection & OutputSelection )
2020-01-27 20:11:15 -05:00
{
2022-05-16 11:23:56 -04:00
// We used to take this as a paremeter, but even if we happen to know that the FDynamicMeshChange doesn't
// involve topology changes, it acts via deleting/reinserting triangles in undo/redo, which changes the
// eids in a mesh and causes problems. So we always treat the group topology as modified in this function.
// TODO: Have an overload that uses a vertex change for non-topology-modifying cases.
constexpr bool bGroupTopologyModified = true ;
2020-01-27 20:11:15 -05:00
// open top-level transaction
GetToolManager ( ) - > BeginUndoTransaction ( TransactionLabel ) ;
2021-07-26 17:57:22 -04:00
// Since we clear the selection in the selection mechanic when topology changes, we need to know
// when OutputSelection is pointing to the selection in the selection mechanic and is not empty,
// so that we can copy it ahead of time and reinstate it.
bool bReferencingSameSelection = ( & SelectionMechanic - > GetActiveSelection ( ) = = & OutputSelection ) ;
2020-01-27 20:11:15 -05:00
2022-05-16 11:23:56 -04:00
// Not actually relevant since our assumption of topology being modified means we always clear existing selection.
// bool bSelectionModified = !bReferencingSameSelection && SelectionMechanic->GetActiveSelection() != OutputSelection;
2020-01-27 20:11:15 -05:00
2021-07-26 17:57:22 -04:00
// In case we need to make a selection copy
FGroupTopologySelection TempSelection ;
const FGroupTopologySelection * OutputSelectionToUse = & OutputSelection ;
2020-01-27 20:11:15 -05:00
2022-05-16 11:23:56 -04:00
// Because we always consider group topology to be modified, the UpdateFromCurrentMesh() call down below
// will clear out our existing selection. However, we want to do this ourselves so that we issue a transaction.
if ( ! SelectionMechanic - > GetActiveSelection ( ) . IsEmpty ( ) /* && (bSelectionModified || bGroupTopologyModified) */ )
2021-07-26 17:57:22 -04:00
{
if ( bReferencingSameSelection )
{
2022-01-11 06:48:50 -05:00
// Need to make a copy because OutputSelection will get cleared
2021-07-26 17:57:22 -04:00
TempSelection = OutputSelection ;
OutputSelectionToUse = & TempSelection ;
}
2020-01-27 20:11:15 -05:00
2021-07-26 17:57:22 -04:00
SelectionMechanic - > BeginChange ( ) ;
SelectionMechanic - > ClearSelection ( ) ;
2021-07-29 15:22:26 -04:00
GetToolManager ( ) - > EmitObjectChange ( SelectionMechanic , SelectionMechanic - > EndChange ( ) , LOCTEXT ( " ClearSelection " , " Clear Selection " ) ) ;
2021-07-26 17:57:22 -04:00
}
GetToolManager ( ) - > EmitObjectChange ( this ,
2022-01-11 06:48:50 -05:00
MakeUnique < FEditMeshPolygonsToolMeshChange > ( MoveTemp ( MeshChangeIn ) ) ,
2021-07-26 17:57:22 -04:00
TransactionLabel ) ;
// Update related structures
2022-05-16 11:23:56 -04:00
UpdateFromCurrentMesh ( bGroupTopologyModified ) ;
ModifiedTopologyCounter + = bGroupTopologyModified ;
2021-07-26 17:57:22 -04:00
2022-05-16 11:23:56 -04:00
// Set output selection if there's a non-empty one. We know we've cleared the selection by
// this point due to treating topology as always modified.
if ( ! OutputSelectionToUse - > IsEmpty ( ) /* && (bSelectionModified || bGroupTopologyModified) */ )
2020-01-27 20:11:15 -05:00
{
SelectionMechanic - > BeginChange ( ) ;
2021-07-26 17:57:22 -04:00
SelectionMechanic - > SetSelection ( * OutputSelectionToUse ) ;
2021-07-29 15:22:26 -04:00
GetToolManager ( ) - > EmitObjectChange ( SelectionMechanic , SelectionMechanic - > EndChange ( ) , LOCTEXT ( " SetSelection " , " Set Selection " ) ) ;
2020-01-27 20:11:15 -05:00
}
GetToolManager ( ) - > EndUndoTransaction ( ) ;
2021-07-26 17:57:22 -04:00
}
2020-01-27 20:11:15 -05:00
2021-07-26 17:57:22 -04:00
void UEditMeshPolygonsTool : : EmitActivityStart ( const FText & TransactionLabel )
{
+ + ActivityTimestamp ;
2020-01-27 20:11:15 -05:00
2021-07-26 17:57:22 -04:00
GetToolManager ( ) - > BeginUndoTransaction ( TransactionLabel ) ;
GetToolManager ( ) - > EmitObjectChange ( this ,
MakeUnique < FPolyEditActivityStartChange > ( ActivityTimestamp ) ,
TransactionLabel ) ;
GetToolManager ( ) - > EndUndoTransaction ( ) ;
2020-01-27 20:11:15 -05:00
}
bool UEditMeshPolygonsTool : : BeginMeshEdgeEditChange ( )
{
return BeginMeshEdgeEditChange ( [ ] ( int32 ) { return true ; } ) ;
}
bool UEditMeshPolygonsTool : : BeginMeshBoundaryEdgeEditChange ( bool bOnlySimple )
{
if ( bOnlySimple )
{
return BeginMeshEdgeEditChange (
[ & ] ( int32 GroupEdgeID ) { return Topology - > IsBoundaryEdge ( GroupEdgeID ) & & Topology - > IsSimpleGroupEdge ( GroupEdgeID ) ; } ) ;
}
else
{
return BeginMeshEdgeEditChange (
[ & ] ( int32 GroupEdgeID ) { return Topology - > IsBoundaryEdge ( GroupEdgeID ) ; } ) ;
}
}
bool UEditMeshPolygonsTool : : BeginMeshEdgeEditChange ( TFunctionRef < bool ( int32 ) > GroupEdgeIDFilterFunc )
{
ActiveEdgeSelection . Reset ( ) ;
const FGroupTopologySelection & ActiveSelection = SelectionMechanic - > GetActiveSelection ( ) ;
int NumEdges = ActiveSelection . SelectedEdgeIDs . Num ( ) ;
if ( NumEdges = = 0 )
{
return false ;
}
ActiveEdgeSelection . Reserve ( NumEdges ) ;
2020-09-24 00:43:27 -04:00
for ( int32 EdgeID : ActiveSelection . SelectedEdgeIDs )
2020-01-27 20:11:15 -05:00
{
if ( GroupEdgeIDFilterFunc ( EdgeID ) )
{
FSelectedEdge & Edge = ActiveEdgeSelection . Emplace_GetRef ( ) ;
Edge . EdgeTopoID = EdgeID ;
Edge . EdgeIDs = Topology - > GetGroupEdgeEdges ( EdgeID ) ;
}
}
return ActiveEdgeSelection . Num ( ) > 0 ;
}
2020-10-22 19:19:16 -04:00
void UEditMeshPolygonsTool : : SetActionButtonPanelsVisible ( bool bVisible )
{
if ( bTriangleMode = = false )
{
if ( EditActions )
{
SetToolPropertySourceEnabled ( EditActions , bVisible ) ;
}
if ( EditEdgeActions )
{
SetToolPropertySourceEnabled ( EditEdgeActions , bVisible ) ;
}
if ( EditUVActions )
{
SetToolPropertySourceEnabled ( EditUVActions , bVisible ) ;
}
}
else
{
if ( EditActions_Triangles )
{
SetToolPropertySourceEnabled ( EditActions_Triangles , bVisible ) ;
}
if ( EditEdgeActions_Triangles )
{
SetToolPropertySourceEnabled ( EditEdgeActions_Triangles , bVisible ) ;
}
}
}
2021-07-29 15:22:26 -04:00
bool UEditMeshPolygonsTool : : CanCurrentlyNestedCancel ( )
{
return CurrentActivity ! = nullptr
| | ( SelectionMechanic & & ! SelectionMechanic - > GetActiveSelection ( ) . IsEmpty ( ) ) ;
}
bool UEditMeshPolygonsTool : : ExecuteNestedCancelCommand ( )
{
if ( CurrentActivity )
{
EndCurrentActivity ( EToolShutdownType : : Cancel ) ;
return true ;
}
else if ( SelectionMechanic & & ! SelectionMechanic - > GetActiveSelection ( ) . IsEmpty ( ) )
{
SelectionMechanic - > BeginChange ( ) ;
SelectionMechanic - > ClearSelection ( ) ;
GetToolManager ( ) - > EmitObjectChange ( SelectionMechanic , SelectionMechanic - > EndChange ( ) , LOCTEXT ( " ClearSelection " , " Clear Selection " ) ) ;
return true ;
}
return false ;
}
bool UEditMeshPolygonsTool : : CanCurrentlyNestedAccept ( )
{
return CurrentActivity ! = nullptr ;
}
bool UEditMeshPolygonsTool : : ExecuteNestedAcceptCommand ( )
{
if ( CurrentActivity )
{
EndCurrentActivity ( EToolShutdownType : : Accept ) ;
return true ;
}
return false ;
}
2021-07-26 17:57:22 -04:00
void FEditMeshPolygonsToolMeshChange : : Apply ( UObject * Object )
2020-01-27 20:11:15 -05:00
{
2021-07-26 17:57:22 -04:00
UEditMeshPolygonsTool * Tool = Cast < UEditMeshPolygonsTool > ( Object ) ;
2022-01-11 06:48:50 -05:00
// This function currently only supports FDynamicMeshChange but that should be issued only when the mesh changes
// topology. For now we use it even when eg vertex postions change. See :HandlePositionOnlyMeshChanges
bool bGroupTopologyModified = true ;
2021-07-26 17:57:22 -04:00
MeshChange - > Apply ( Tool - > CurrentMesh . Get ( ) , false ) ;
Tool - > UpdateFromCurrentMesh ( bGroupTopologyModified ) ;
Tool - > ModifiedTopologyCounter + = bGroupTopologyModified ;
2021-10-21 10:11:02 -04:00
Tool - > ActivityContext - > OnUndoRedo . Broadcast ( bGroupTopologyModified ) ;
2020-01-27 20:11:15 -05:00
}
2021-07-26 17:57:22 -04:00
void FEditMeshPolygonsToolMeshChange : : Revert ( UObject * Object )
2020-01-27 20:11:15 -05:00
{
2021-07-26 17:57:22 -04:00
UEditMeshPolygonsTool * Tool = Cast < UEditMeshPolygonsTool > ( Object ) ;
2022-01-11 06:48:50 -05:00
// This function currently only supports FDynamicMeshChange but that should be issued only when the mesh changes
// topology. For now we use it even when eg vertex postions change. See :HandlePositionOnlyMeshChanges
bool bGroupTopologyModified = true ;
2021-07-26 17:57:22 -04:00
MeshChange - > Apply ( Tool - > CurrentMesh . Get ( ) , true ) ;
Tool - > UpdateFromCurrentMesh ( bGroupTopologyModified ) ;
Tool - > ModifiedTopologyCounter - = bGroupTopologyModified ;
2021-10-21 10:11:02 -04:00
Tool - > ActivityContext - > OnUndoRedo . Broadcast ( bGroupTopologyModified ) ;
2020-01-27 20:11:15 -05:00
}
2021-07-26 17:57:22 -04:00
FString FEditMeshPolygonsToolMeshChange : : ToString ( ) const
2020-01-27 20:11:15 -05:00
{
2021-07-26 17:57:22 -04:00
return TEXT ( " FEditMeshPolygonsToolMeshChange " ) ;
2020-01-27 20:11:15 -05:00
}
2021-07-26 17:57:22 -04:00
void FPolyEditActivityStartChange : : Revert ( UObject * Object )
2020-01-27 20:11:15 -05:00
{
2021-07-26 17:57:22 -04:00
Cast < UEditMeshPolygonsTool > ( Object ) - > EndCurrentActivity ( ) ;
2020-01-27 20:11:15 -05:00
bHaveDoneUndo = true ;
}
2021-07-26 17:57:22 -04:00
bool FPolyEditActivityStartChange : : HasExpired ( UObject * Object ) const
2020-01-27 20:11:15 -05:00
{
2021-07-26 17:57:22 -04:00
return bHaveDoneUndo
| | Cast < UEditMeshPolygonsTool > ( Object ) - > ActivityTimestamp ! = ActivityTimestamp ;
2020-01-27 20:11:15 -05:00
}
2021-07-26 17:57:22 -04:00
FString FPolyEditActivityStartChange : : ToString ( ) const
2020-01-27 20:11:15 -05:00
{
2021-07-26 17:57:22 -04:00
return TEXT ( " FPolyEditActivityStartChange " ) ;
2020-01-27 20:11:15 -05:00
}
2019-10-01 20:41:42 -04:00
# undef LOCTEXT_NAMESPACE