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"
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. " ) ;
}
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
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 ) ;
CommonProps - > RestoreProperties ( this ) ;
CommonProps - > WatchProperty ( CommonProps - > LocalFrameMode ,
[ this ] ( ELocalFrameMode ) { UpdateGizmoFrame ( ) ; } ) ;
CommonProps - > WatchProperty ( CommonProps - > bLockRotation ,
[ this ] ( bool )
{
LockedTransfomerFrame = LastTransformerFrame ;
} ) ;
// 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 ( ) ;
2021-07-29 15:22:26 -04:00
CurrentMesh = MakeShared < FDynamicMesh3 > ( UE : : ToolTarget : : GetDynamicMeshCopy ( Target ) ) ;
2021-07-26 17:57:22 -04:00
// 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
Topology = ( bTriangleMode ) ? MakeShared < FTriangleGroupTopology , ESPMode : : ThreadSafe > ( CurrentMesh . Get ( ) , true )
: MakeShared < FGroupTopology , ESPMode : : ThreadSafe > ( CurrentMesh . Get ( ) , true ) ;
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 ) ;
SelectionMechanic - > Properties - > RestoreProperties ( this ) ;
SelectionMechanic - > OnSelectionChanged . AddUObject ( this , & UEditMeshPolygonsTool : : OnSelectionModifiedEvent ) ;
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 ( ) ,
Preview - > PreviewMesh - > GetTransform ( ) ,
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 ,
const UE : : Geometry : : FGroupTopologySelection & OutputSelection ,
bool bTopologyModified )
{
EmitCurrentMeshChangeAndUpdate ( TransactionLabel , MoveTemp ( MeshChangeIn ) , OutputSelection , bTopologyModified ) ;
} ;
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 ) ;
// 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 ) ;
DragAlignmentMechanic = NewObject < UDragAlignmentMechanic > ( this ) ;
DragAlignmentMechanic - > Setup ( this ) ;
DragAlignmentMechanic - > InitializeDeformedMeshRayCast (
[ this ] ( ) { return & GetSpatial ( ) ; } ,
WorldTransform , & LinearDeformer ) ; // Should happen after LinearDeformer is initialized
DragAlignmentMechanic - > AddToGizmo ( TransformGizmo ) ;
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 " ,
" This object has only a single Polygroup. Use the GenGrps, GrpPnt or TriSel (Create Polygroup) tools to modify Polygroups. " ) ,
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
}
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
}
2019-10-01 20:41:42 -04:00
void UEditMeshPolygonsTool : : Shutdown ( EToolShutdownType ShutdownType )
{
2021-07-26 17:57:22 -04:00
if ( CurrentActivity )
{
CurrentActivity - > End ( ShutdownType ) ;
CurrentActivity = nullptr ;
}
2020-09-24 00:43:27 -04:00
CommonProps - > SaveProperties ( this ) ;
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 ) ;
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
{
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
// 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 ( )
{
if ( SelectionMechanic & & SelectionMechanic - > HasSelection ( ) )
{
FAxisAlignedBox3d Bounds = SelectionMechanic - > GetSelectionBounds ( true ) ;
return ( FBox ) Bounds ;
}
2021-07-26 17:57:22 -04:00
return FBox ( ) ;
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 ) ,
2021-05-10 01:17:30 -04:00
WorldTransform . InverseTransformNormal ( ( FVector3d ) WorldRay . Direction ) ) ;
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 ;
bLastUpdateUsedWorldFrame = ( TransformGizmo - > CurrentCoordinateSystem = = EToolContextCoordinateSystem : : World ) ;
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 ( ) ) ;
2021-04-27 11:08:23 -04:00
if ( CommonProps - > bLockRotation )
{
2021-07-26 17:57:22 -04:00
FFrame3d SetFrame = TransformFrame ;
2021-04-27 11:08:23 -04:00
SetFrame . Rotation = LockedTransfomerFrame . Rotation ;
2021-07-26 17:57:22 -04:00
TransformGizmo - > ReinitializeGizmoTransform ( SetFrame . ToFTransform ( ) ) ;
2021-04-27 11:08:23 -04:00
}
else
{
2021-07-26 17:57:22 -04:00
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
{
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 ;
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 )
{
TransformGizmo - > SetVisibility ( false ) ;
SelectionMechanic - > SetIsEnabled ( false ) ;
CurrentActivity = Activity ;
2021-11-16 13:24:21 -05:00
if ( CurrentActivity = = BevelEdgeActivity )
{
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 ) ;
2019-10-01 20:41:42 -04:00
2021-07-26 17:57:22 -04:00
// Reset info message.
GetToolManager ( ) - > DisplayMessage ( DefaultMessage ,
EToolMessageLevel : : UserNotification ) ;
}
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 ) ;
UpdateGizmoVisibility ( ) ;
}
}
void UEditMeshPolygonsTool : : NotifyActivitySelfEnded ( UInteractiveToolActivity * Activity )
{
EndCurrentActivity ( ) ;
}
void UEditMeshPolygonsTool : : UpdateGizmoVisibility ( )
{
if ( SelectionMechanic - > HasSelection ( ) )
{
TransformGizmo - > SetVisibility ( true ) ;
// update frame because we might be here due to an undo event/etc, rather than an explicit
// selection change
LastGeometryFrame = SelectionMechanic - > GetSelectionFrame ( true , & LastGeometryFrame ) ;
UpdateGizmoFrame ( ) ;
}
else
{
TransformGizmo - > SetVisibility ( false ) ;
}
}
2019-10-01 20:41:42 -04:00
void UEditMeshPolygonsTool : : Render ( IToolsContextRenderAPI * RenderAPI )
{
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 )
{
SelectionMechanic - > DrawHUD ( Canvas , RenderAPI ) ;
}
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 ) ;
}
2021-07-26 17:57:22 -04:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshMergeChange " , " Merge " ) , ChangeTracker . EndChange ( ) , NewSelection , true ) ;
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 ;
2021-07-26 17:57:22 -04:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshDeleteChange " , " Delete " ) , ChangeTracker . EndChange ( ) , NewSelection , true ) ;
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
// same route as everything else.
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshRecalcNormalsChange " , " Recalc Normals " ) ,
ChangeTracker . EndChange ( ) , ActiveSelection , false ) ;
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 " ) ,
2021-10-21 22:27:36 -04:00
ChangeTracker . EndChange ( ) , ActiveSelection , true ) ;
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 ) ;
}
2021-07-26 17:57:22 -04:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshRetriangulateChange " , " Retriangulate " ) ,
ChangeTracker . EndChange ( ) , ActiveSelection , true ) ;
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
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshSimplifyByGroup " , " Simplify by Group " ) , ChangeTracker . EndChange ( ) , NewSelection , true ) ;
}
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 ) ;
}
}
2021-07-26 17:57:22 -04:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshDecomposeChange " , " Decompose " ) , ChangeTracker . EndChange ( ) , NewSelection , true ) ;
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 ) ;
2021-07-26 17:57:22 -04:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshDisconnectChange " , " Disconnect " ) , ChangeTracker . EndChange ( ) , ActiveSelection , true ) ;
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
2021-07-26 17:57:22 -04:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshDisconnectChange " , " Disconnect " ) , ChangeTracker . EndChange ( ) , NewSelection , true ) ;
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 ;
2021-07-26 17:57:22 -04:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshEdgeCollapseChange " , " Collapse " ) , ChangeTracker . EndChange ( ) , NewSelection , true ) ;
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 ;
2021-07-26 17:57:22 -04:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshWeldEdgeChange " , " Weld Edges " ) , ChangeTracker . EndChange ( ) , NewSelection , true ) ;
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
}
}
}
FGroupTopologySelection NewSelection ;
2021-07-26 17:57:22 -04:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshStraightenEdgeChange " , " Straighten Edges " ) ,
ChangeTracker . EndChange ( ) , NewSelection , false ) ;
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
}
}
}
2021-07-26 17:57:22 -04:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshFillHoleChange " , " Fill Hole " ) , ChangeTracker . EndChange ( ) , NewSelection , true ) ;
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 ) ;
}
}
2021-07-26 17:57:22 -04:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshPokeChange " , " Poke Faces " ) , ChangeTracker . EndChange ( ) , NewSelection , true ) ;
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.
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshFlipChange " , " Flip Edges " ) , ChangeTracker . EndChange ( ) , ActiveSelection , true ) ;
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 " ) ,
ChangeTracker . EndChange ( ) , FGroupTopologySelection ( ) , true ) ;
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 ) ;
}
}
}
}
2021-07-26 17:57:22 -04:00
EmitCurrentMeshChangeAndUpdate ( LOCTEXT ( " PolyMeshSplitChange " , " Split Edges " ) , ChangeTracker . EndChange ( ) , NewSelection , true ) ;
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 ,
const FGroupTopologySelection & OutputSelection ,
bool bGroupTopologyModified )
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
2021-07-26 17:57:22 -04:00
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
2021-07-26 17:57:22 -04:00
// If the selection is going to be cleared, we need to do it explicitly ourselves so that we can emit a change.
if ( ! SelectionMechanic - > GetActiveSelection ( ) . IsEmpty ( ) & & ( bSelectionModified | | bGroupTopologyModified ) )
{
if ( bReferencingSameSelection )
{
// Need to make a copy because OutputSelection will get cleared due to bGroupTopologyModified
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 ,
MakeUnique < FEditMeshPolygonsToolMeshChange > ( MoveTemp ( MeshChangeIn ) , bGroupTopologyModified ) ,
TransactionLabel ) ;
// Update related structures
UpdateFromCurrentMesh ( bGroupTopologyModified ) ;
ModifiedTopologyCounter + = bGroupTopologyModified ;
// Set output selection either if we changed selections (to something non-empty), or if
// our selection got cleared due to bGroupTopologyModified.
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 ) ;
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 ) ;
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