2019-12-27 09:26:59 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-10-01 20:41:42 -04:00
# include "DrawPolygonTool.h"
# include "InteractiveToolManager.h"
# include "InteractiveGizmoManager.h"
# include "ToolBuilderUtil.h"
2021-10-07 22:25:54 -04:00
# include "ToolSetupUtil.h"
2019-10-01 20:41:42 -04:00
# include "BaseBehaviors/MultiClickSequenceInputBehavior.h"
# include "BaseBehaviors/KeyAsModifierInputBehavior.h"
# include "Polygon2.h"
2019-11-01 20:48:07 -04:00
# include "Curve/GeneralPolygon2.h"
2019-10-01 20:41:42 -04:00
# include "FrameTypes.h"
# include "MatrixTypes.h"
2019-11-01 20:48:07 -04:00
# include "Generators/FlatTriangulationMeshGenerator.h"
2019-11-06 20:53:34 -05:00
# include "Generators/DiscMeshGenerator.h"
# include "Generators/RectangleMeshGenerator.h"
2019-10-01 20:41:42 -04:00
# include "Operations/ExtrudeMesh.h"
# include "Distance/DistLine3Ray3.h"
# include "Intersection/IntrSegment2Segment2.h"
# include "ToolSceneQueriesUtil.h"
2022-03-17 14:03:58 -04:00
# include "SceneManagement.h" // FPrimitiveDrawInterface
2021-12-09 14:46:09 -05:00
# include "SceneQueries/SceneSnappingManager.h"
2019-11-01 20:48:07 -04:00
# include "ConstrainedDelaunay2.h"
2019-11-06 14:33:56 -05:00
# include "Arrangement2d.h"
2022-08-25 11:51:02 -04:00
# include "DynamicMesh/MeshTangents.h"
2019-10-01 20:41:42 -04:00
# include "DynamicMeshEditor.h"
# include "BaseGizmos/GizmoComponents.h"
2021-05-20 16:39:39 -04:00
# include "BaseGizmos/TransformGizmoUtil.h"
2019-10-01 20:41:42 -04:00
# include "Drawing/MeshDebugDrawing.h"
# include "Selection/SelectClickedAction.h"
# include "Selection/ToolSelectionUtil.h"
2021-06-02 15:58:00 -04:00
# include "ModelingObjectsCreationAPI.h"
2022-11-16 11:40:11 -05:00
# include "Mechanics/ConstructionPlaneMechanic.h"
2019-10-01 20:41:42 -04:00
2022-06-03 12:42:30 -04:00
# include "Mechanics/DragAlignmentMechanic.h"
2022-09-28 01:06:15 -04:00
# include UE_INLINE_GENERATED_CPP_BY_NAME(DrawPolygonTool)
2021-03-09 19:33:56 -04:00
using namespace UE : : Geometry ;
2019-10-01 20:41:42 -04:00
# define LOCTEXT_NAMESPACE "UDrawPolygonTool"
/*
* ToolBuilder
*/
constexpr int StartPointSnapID = FPointPlanarSnapSolver : : BaseExternalPointID + 1 ;
constexpr int CurrentSceneSnapID = FPointPlanarSnapSolver : : BaseExternalPointID + 2 ;
2019-11-11 16:57:51 -05:00
constexpr int CurrentGridSnapID = FPointPlanarSnapSolver : : BaseExternalPointID + 3 ;
2019-10-01 20:41:42 -04:00
bool UDrawPolygonToolBuilder : : CanBuildTool ( const FToolBuilderState & SceneState ) const
{
2021-06-02 15:58:00 -04:00
return true ;
2019-10-01 20:41:42 -04:00
}
UInteractiveTool * UDrawPolygonToolBuilder : : BuildTool ( const FToolBuilderState & SceneState ) const
{
UDrawPolygonTool * NewTool = NewObject < UDrawPolygonTool > ( SceneState . ToolManager ) ;
NewTool - > SetWorld ( SceneState . World ) ;
return NewTool ;
}
/*
* Properties
*/
UDrawPolygonToolStandardProperties : : UDrawPolygonToolStandardProperties ( )
{
}
/*
* Tool
*/
UDrawPolygonTool : : UDrawPolygonTool ( )
{
bInInteractiveExtrude = false ;
2021-10-21 17:57:49 -04:00
UInteractiveTool : : SetToolDisplayName ( LOCTEXT ( " ToolName " , " Polygon Extrude " ) ) ;
2019-10-01 20:41:42 -04:00
}
void UDrawPolygonTool : : SetWorld ( UWorld * World )
{
this - > TargetWorld = World ;
}
void UDrawPolygonTool : : Setup ( )
{
UInteractiveTool : : Setup ( ) ;
// add default button input behaviors for devices
UMultiClickSequenceInputBehavior * MouseBehavior = NewObject < UMultiClickSequenceInputBehavior > ( ) ;
MouseBehavior - > Initialize ( this ) ;
MouseBehavior - > Modifiers . RegisterModifier ( IgnoreSnappingModifier , FInputDeviceState : : IsShiftKeyDown ) ;
AddInputBehavior ( MouseBehavior ) ;
ModelingTools: add support for creating Volumes directly from DrawPolygon, DrawRevolve, DrawPolyPath, and AddPrimitive, CombineMeshes, CutMeshWithMesh, PlaneCut, BaseCreateFromSelected Tools. Improve support for Editing volumes, eg handling mesh/volume interactions, and add configurable auto-simplification for volumes to avoid painful Editor hangs.
- Move ToolTarget implementations, DynamicMeshToVolume to ModelingComponentsEditorOnly module
- move VolumeToDynamicMesh, DynamicMeshProvider/Commiter interfaces to ModelingComponents module
- Add UCreateMeshObjectTypeProperties property set to expose mesh/volume options
- Add FCreateMeshObjectParams::TypeHintClass to allow AVolume type (or other UClass hints) to be passed to creation APIs
- Add UE::ToolTarget::ConfigureCreateMeshObjectParams() util function in ModelingToolTargetUtil, tries to determine output type in a FCreateMeshObjectParams based on input ToolTarget
- Add UEditorModelingObjectsCreationAPI::CreateVolume() implementation
- Add UEditorModelingObjectsCreationAPI::FilterMaterials() that strips out any internal materials and replaces with WorldGridMaterial. This occurs when (eg) subtracting a Volume from a StaticMesh, because the temporary volume mesh gets assigned internal materials, but the Tools don't know this. Use in EditorModelingObjectsCreationAPI when creating new objects. UStaticMeshComponentToolTarget also does this filtering in ::CommitMaterialSetUpdate().
- Add ::ComponentTypeSupportsCollision() function to ComponentCollisionUtil, use to avoid checks/ensures for Volume targets
- Add support for automatic mesh simplification in DynamicMeshToVolume. Add CVar to VolumeDynamicMeshToolTarget.h to control max triangle count (default 500). Apply auto-simplify when creating or updating an AVolume. This prevents the Editor from blocking for long periods on meshes that are too high-res for volumes (even 500 is quite high).
- DynamicMeshToVolume now emits polygroup-faces that contain holes (ie multiple boundary loops) as a set of triangles, rather than emitting separate overlapping faces for each boundary loop
#rb none
#rnx
#jira none
#preflight 60ba50632c42ea0001cb54c5
[CL 16561742 by Ryan Schmidt in ue5-main branch]
2021-06-04 16:04:03 -04:00
OutputTypeProperties = NewObject < UCreateMeshObjectTypeProperties > ( this ) ;
OutputTypeProperties - > RestoreProperties ( this ) ;
OutputTypeProperties - > InitializeDefault ( ) ;
OutputTypeProperties - > WatchProperty ( OutputTypeProperties - > OutputType , [ this ] ( FString ) { OutputTypeProperties - > UpdatePropertyVisibility ( ) ; } ) ;
2019-10-01 20:41:42 -04:00
ModelingTools: add support for creating Volumes directly from DrawPolygon, DrawRevolve, DrawPolyPath, and AddPrimitive, CombineMeshes, CutMeshWithMesh, PlaneCut, BaseCreateFromSelected Tools. Improve support for Editing volumes, eg handling mesh/volume interactions, and add configurable auto-simplification for volumes to avoid painful Editor hangs.
- Move ToolTarget implementations, DynamicMeshToVolume to ModelingComponentsEditorOnly module
- move VolumeToDynamicMesh, DynamicMeshProvider/Commiter interfaces to ModelingComponents module
- Add UCreateMeshObjectTypeProperties property set to expose mesh/volume options
- Add FCreateMeshObjectParams::TypeHintClass to allow AVolume type (or other UClass hints) to be passed to creation APIs
- Add UE::ToolTarget::ConfigureCreateMeshObjectParams() util function in ModelingToolTargetUtil, tries to determine output type in a FCreateMeshObjectParams based on input ToolTarget
- Add UEditorModelingObjectsCreationAPI::CreateVolume() implementation
- Add UEditorModelingObjectsCreationAPI::FilterMaterials() that strips out any internal materials and replaces with WorldGridMaterial. This occurs when (eg) subtracting a Volume from a StaticMesh, because the temporary volume mesh gets assigned internal materials, but the Tools don't know this. Use in EditorModelingObjectsCreationAPI when creating new objects. UStaticMeshComponentToolTarget also does this filtering in ::CommitMaterialSetUpdate().
- Add ::ComponentTypeSupportsCollision() function to ComponentCollisionUtil, use to avoid checks/ensures for Volume targets
- Add support for automatic mesh simplification in DynamicMeshToVolume. Add CVar to VolumeDynamicMeshToolTarget.h to control max triangle count (default 500). Apply auto-simplify when creating or updating an AVolume. This prevents the Editor from blocking for long periods on meshes that are too high-res for volumes (even 500 is quite high).
- DynamicMeshToVolume now emits polygroup-faces that contain holes (ie multiple boundary loops) as a set of triangles, rather than emitting separate overlapping faces for each boundary loop
#rb none
#rnx
#jira none
#preflight 60ba50632c42ea0001cb54c5
[CL 16561742 by Ryan Schmidt in ue5-main branch]
2021-06-04 16:04:03 -04:00
PolygonProperties = NewObject < UDrawPolygonToolStandardProperties > ( this ) ;
2019-10-01 20:41:42 -04:00
PolygonProperties - > RestoreProperties ( this ) ;
2021-10-20 20:41:00 -04:00
PolygonProperties - > WatchProperty ( PolygonProperties - > bShowGridGizmo ,
2022-11-16 11:40:11 -05:00
[ this ] ( bool bNewValue ) { PlaneMechanic - > PlaneTransformGizmo - > SetVisibility ( bNewValue ) ; } ) ;
2019-10-01 20:41:42 -04:00
2022-11-16 11:40:11 -05:00
PlaneMechanic = NewObject < UConstructionPlaneMechanic > ( this ) ;
PlaneMechanic - > Setup ( this ) ;
PlaneMechanic - > CanUpdatePlaneFunc = [ this ] ( ) { return AllowDrawPlaneUpdates ( ) ; } ;
PlaneMechanic - > OnPlaneChanged . AddLambda ( [ this ] ( ) { SnapEngine . Plane = PlaneMechanic - > Plane ; } ) ; // Keep SnapEngine plane up to date with PlaneMechanic's plane
PlaneMechanic - > Initialize ( TargetWorld , FFrame3d ( ) ) ;
2022-06-03 12:42:30 -04:00
DragAlignmentMechanic = NewObject < UDragAlignmentMechanic > ( this ) ;
DragAlignmentMechanic - > Setup ( this ) ;
2022-11-16 11:40:11 -05:00
DragAlignmentMechanic - > AddToGizmo ( PlaneMechanic - > PlaneTransformGizmo ) ;
2019-10-01 20:41:42 -04:00
// initialize material properties for new objects
MaterialProperties = NewObject < UNewMeshMaterialProperties > ( this ) ;
MaterialProperties - > RestoreProperties ( this ) ;
2020-09-24 00:43:27 -04:00
MaterialProperties - > bShowExtendedOptions = true ;
2019-10-01 20:41:42 -04:00
// create preview mesh object
ModelingTools: add support for creating Volumes directly from DrawPolygon, DrawRevolve, DrawPolyPath, and AddPrimitive, CombineMeshes, CutMeshWithMesh, PlaneCut, BaseCreateFromSelected Tools. Improve support for Editing volumes, eg handling mesh/volume interactions, and add configurable auto-simplification for volumes to avoid painful Editor hangs.
- Move ToolTarget implementations, DynamicMeshToVolume to ModelingComponentsEditorOnly module
- move VolumeToDynamicMesh, DynamicMeshProvider/Commiter interfaces to ModelingComponents module
- Add UCreateMeshObjectTypeProperties property set to expose mesh/volume options
- Add FCreateMeshObjectParams::TypeHintClass to allow AVolume type (or other UClass hints) to be passed to creation APIs
- Add UE::ToolTarget::ConfigureCreateMeshObjectParams() util function in ModelingToolTargetUtil, tries to determine output type in a FCreateMeshObjectParams based on input ToolTarget
- Add UEditorModelingObjectsCreationAPI::CreateVolume() implementation
- Add UEditorModelingObjectsCreationAPI::FilterMaterials() that strips out any internal materials and replaces with WorldGridMaterial. This occurs when (eg) subtracting a Volume from a StaticMesh, because the temporary volume mesh gets assigned internal materials, but the Tools don't know this. Use in EditorModelingObjectsCreationAPI when creating new objects. UStaticMeshComponentToolTarget also does this filtering in ::CommitMaterialSetUpdate().
- Add ::ComponentTypeSupportsCollision() function to ComponentCollisionUtil, use to avoid checks/ensures for Volume targets
- Add support for automatic mesh simplification in DynamicMeshToVolume. Add CVar to VolumeDynamicMeshToolTarget.h to control max triangle count (default 500). Apply auto-simplify when creating or updating an AVolume. This prevents the Editor from blocking for long periods on meshes that are too high-res for volumes (even 500 is quite high).
- DynamicMeshToVolume now emits polygroup-faces that contain holes (ie multiple boundary loops) as a set of triangles, rather than emitting separate overlapping faces for each boundary loop
#rb none
#rnx
#jira none
#preflight 60ba50632c42ea0001cb54c5
[CL 16561742 by Ryan Schmidt in ue5-main branch]
2021-06-04 16:04:03 -04:00
PreviewMesh = NewObject < UPreviewMesh > ( this ) ;
2019-10-01 20:41:42 -04:00
PreviewMesh - > CreateInWorld ( this - > TargetWorld , FTransform : : Identity ) ;
2021-10-07 22:25:54 -04:00
ToolSetupUtil : : ApplyRenderingConfigurationToPreview ( PreviewMesh , nullptr ) ;
2019-10-01 20:41:42 -04:00
PreviewMesh - > SetVisible ( false ) ;
2020-10-09 22:42:26 -04:00
{
UMaterialInterface * Material = nullptr ;
if ( MaterialProperties - > Material . IsValid ( ) )
{
Material = MaterialProperties - > Material . Get ( ) ;
}
PreviewMesh - > SetMaterial ( Material ) ;
}
2019-10-01 20:41:42 -04:00
bPreviewUpdatePending = false ;
// initialize snapping engine and properties
SnapEngine . SnapMetricTolerance = ToolSceneQueriesUtil : : GetDefaultVisualAngleSnapThreshD ( ) ;
SnapEngine . SnapMetricFunc = [ this ] ( const FVector3d & Position1 , const FVector3d & Position2 ) {
2020-06-23 18:40:00 -04:00
return ToolSceneQueriesUtil : : CalculateNormalizedViewVisualAngleD ( this - > CameraState , Position1 , Position2 ) ;
2019-10-01 20:41:42 -04:00
} ;
2022-11-16 11:40:11 -05:00
SnapEngine . Plane = PlaneMechanic - > Plane ;
2019-10-01 20:41:42 -04:00
ModelingTools: add support for creating Volumes directly from DrawPolygon, DrawRevolve, DrawPolyPath, and AddPrimitive, CombineMeshes, CutMeshWithMesh, PlaneCut, BaseCreateFromSelected Tools. Improve support for Editing volumes, eg handling mesh/volume interactions, and add configurable auto-simplification for volumes to avoid painful Editor hangs.
- Move ToolTarget implementations, DynamicMeshToVolume to ModelingComponentsEditorOnly module
- move VolumeToDynamicMesh, DynamicMeshProvider/Commiter interfaces to ModelingComponents module
- Add UCreateMeshObjectTypeProperties property set to expose mesh/volume options
- Add FCreateMeshObjectParams::TypeHintClass to allow AVolume type (or other UClass hints) to be passed to creation APIs
- Add UE::ToolTarget::ConfigureCreateMeshObjectParams() util function in ModelingToolTargetUtil, tries to determine output type in a FCreateMeshObjectParams based on input ToolTarget
- Add UEditorModelingObjectsCreationAPI::CreateVolume() implementation
- Add UEditorModelingObjectsCreationAPI::FilterMaterials() that strips out any internal materials and replaces with WorldGridMaterial. This occurs when (eg) subtracting a Volume from a StaticMesh, because the temporary volume mesh gets assigned internal materials, but the Tools don't know this. Use in EditorModelingObjectsCreationAPI when creating new objects. UStaticMeshComponentToolTarget also does this filtering in ::CommitMaterialSetUpdate().
- Add ::ComponentTypeSupportsCollision() function to ComponentCollisionUtil, use to avoid checks/ensures for Volume targets
- Add support for automatic mesh simplification in DynamicMeshToVolume. Add CVar to VolumeDynamicMeshToolTarget.h to control max triangle count (default 500). Apply auto-simplify when creating or updating an AVolume. This prevents the Editor from blocking for long periods on meshes that are too high-res for volumes (even 500 is quite high).
- DynamicMeshToVolume now emits polygroup-faces that contain holes (ie multiple boundary loops) as a set of triangles, rather than emitting separate overlapping faces for each boundary loop
#rb none
#rnx
#jira none
#preflight 60ba50632c42ea0001cb54c5
[CL 16561742 by Ryan Schmidt in ue5-main branch]
2021-06-04 16:04:03 -04:00
SnapProperties = NewObject < UDrawPolygonToolSnapProperties > ( this ) ;
2019-10-01 20:41:42 -04:00
SnapProperties - > RestoreProperties ( this ) ;
2022-01-11 12:12:12 -05:00
SnapProperties - > bSnapToWorldGrid = GetToolManager ( ) - > GetContextQueriesAPI ( )
- > GetCurrentSnappingSettings ( ) . bEnablePositionGridSnapping ;
2019-10-01 20:41:42 -04:00
// register tool properties
ModelingTools: add support for creating Volumes directly from DrawPolygon, DrawRevolve, DrawPolyPath, and AddPrimitive, CombineMeshes, CutMeshWithMesh, PlaneCut, BaseCreateFromSelected Tools. Improve support for Editing volumes, eg handling mesh/volume interactions, and add configurable auto-simplification for volumes to avoid painful Editor hangs.
- Move ToolTarget implementations, DynamicMeshToVolume to ModelingComponentsEditorOnly module
- move VolumeToDynamicMesh, DynamicMeshProvider/Commiter interfaces to ModelingComponents module
- Add UCreateMeshObjectTypeProperties property set to expose mesh/volume options
- Add FCreateMeshObjectParams::TypeHintClass to allow AVolume type (or other UClass hints) to be passed to creation APIs
- Add UE::ToolTarget::ConfigureCreateMeshObjectParams() util function in ModelingToolTargetUtil, tries to determine output type in a FCreateMeshObjectParams based on input ToolTarget
- Add UEditorModelingObjectsCreationAPI::CreateVolume() implementation
- Add UEditorModelingObjectsCreationAPI::FilterMaterials() that strips out any internal materials and replaces with WorldGridMaterial. This occurs when (eg) subtracting a Volume from a StaticMesh, because the temporary volume mesh gets assigned internal materials, but the Tools don't know this. Use in EditorModelingObjectsCreationAPI when creating new objects. UStaticMeshComponentToolTarget also does this filtering in ::CommitMaterialSetUpdate().
- Add ::ComponentTypeSupportsCollision() function to ComponentCollisionUtil, use to avoid checks/ensures for Volume targets
- Add support for automatic mesh simplification in DynamicMeshToVolume. Add CVar to VolumeDynamicMeshToolTarget.h to control max triangle count (default 500). Apply auto-simplify when creating or updating an AVolume. This prevents the Editor from blocking for long periods on meshes that are too high-res for volumes (even 500 is quite high).
- DynamicMeshToVolume now emits polygroup-faces that contain holes (ie multiple boundary loops) as a set of triangles, rather than emitting separate overlapping faces for each boundary loop
#rb none
#rnx
#jira none
#preflight 60ba50632c42ea0001cb54c5
[CL 16561742 by Ryan Schmidt in ue5-main branch]
2021-06-04 16:04:03 -04:00
if ( OutputTypeProperties - > ShouldShowPropertySet ( ) )
{
AddToolPropertySource ( OutputTypeProperties ) ;
}
2019-10-01 20:41:42 -04:00
AddToolPropertySource ( PolygonProperties ) ;
AddToolPropertySource ( SnapProperties ) ;
AddToolPropertySource ( MaterialProperties ) ;
ShowStartupMessage ( ) ;
}
void UDrawPolygonTool : : Shutdown ( EToolShutdownType ShutdownType )
{
2021-11-23 10:39:20 -05:00
if ( bHasSavedExtrudeHeight )
{
PolygonProperties - > ExtrudeHeight = SavedExtrudeHeight ;
bHasSavedExtrudeHeight = false ;
}
2019-10-01 20:41:42 -04:00
PreviewMesh - > Disconnect ( ) ;
PreviewMesh = nullptr ;
2022-06-03 12:42:30 -04:00
DragAlignmentMechanic - > Shutdown ( ) ;
2022-11-16 11:40:11 -05:00
PlaneMechanic - > Shutdown ( ) ;
PlaneMechanic = nullptr ;
2019-10-01 20:41:42 -04:00
GetToolManager ( ) - > GetPairedGizmoManager ( ) - > DestroyAllGizmosByOwner ( this ) ;
ModelingTools: add support for creating Volumes directly from DrawPolygon, DrawRevolve, DrawPolyPath, and AddPrimitive, CombineMeshes, CutMeshWithMesh, PlaneCut, BaseCreateFromSelected Tools. Improve support for Editing volumes, eg handling mesh/volume interactions, and add configurable auto-simplification for volumes to avoid painful Editor hangs.
- Move ToolTarget implementations, DynamicMeshToVolume to ModelingComponentsEditorOnly module
- move VolumeToDynamicMesh, DynamicMeshProvider/Commiter interfaces to ModelingComponents module
- Add UCreateMeshObjectTypeProperties property set to expose mesh/volume options
- Add FCreateMeshObjectParams::TypeHintClass to allow AVolume type (or other UClass hints) to be passed to creation APIs
- Add UE::ToolTarget::ConfigureCreateMeshObjectParams() util function in ModelingToolTargetUtil, tries to determine output type in a FCreateMeshObjectParams based on input ToolTarget
- Add UEditorModelingObjectsCreationAPI::CreateVolume() implementation
- Add UEditorModelingObjectsCreationAPI::FilterMaterials() that strips out any internal materials and replaces with WorldGridMaterial. This occurs when (eg) subtracting a Volume from a StaticMesh, because the temporary volume mesh gets assigned internal materials, but the Tools don't know this. Use in EditorModelingObjectsCreationAPI when creating new objects. UStaticMeshComponentToolTarget also does this filtering in ::CommitMaterialSetUpdate().
- Add ::ComponentTypeSupportsCollision() function to ComponentCollisionUtil, use to avoid checks/ensures for Volume targets
- Add support for automatic mesh simplification in DynamicMeshToVolume. Add CVar to VolumeDynamicMeshToolTarget.h to control max triangle count (default 500). Apply auto-simplify when creating or updating an AVolume. This prevents the Editor from blocking for long periods on meshes that are too high-res for volumes (even 500 is quite high).
- DynamicMeshToVolume now emits polygroup-faces that contain holes (ie multiple boundary loops) as a set of triangles, rather than emitting separate overlapping faces for each boundary loop
#rb none
#rnx
#jira none
#preflight 60ba50632c42ea0001cb54c5
[CL 16561742 by Ryan Schmidt in ue5-main branch]
2021-06-04 16:04:03 -04:00
OutputTypeProperties - > SaveProperties ( this ) ;
2019-10-01 20:41:42 -04:00
PolygonProperties - > SaveProperties ( this ) ;
SnapProperties - > SaveProperties ( this ) ;
MaterialProperties - > SaveProperties ( this ) ;
}
void UDrawPolygonTool : : RegisterActions ( FInteractiveToolActionSet & ActionSet )
{
2023-02-07 18:29:11 -05:00
// This is an uncommon hotkey to want, and can make tool seem broken if accidentally pressed. The only
// reason a user might want it is if the gizmo is in the way of their drawing, in which case they could
// presumably translate it in the plane... Still, allow it to be settable if the user wants.
2019-10-01 20:41:42 -04:00
ActionSet . RegisterAction ( this , ( int32 ) EStandardToolActions : : BaseClientDefinedActionID + 2 ,
2023-02-07 18:29:11 -05:00
TEXT ( " ToggleGizmoVisibility " ) ,
LOCTEXT ( " ToggleGizmoVisibilityUIName " , " Toggle Gizmo " ) ,
LOCTEXT ( " ToggleGizmoVisibilityTooltip " , " Toggle visibility of the transformation gizmo " ) ,
EModifierKey : : None , EKeys : : Invalid ,
2021-10-20 20:41:00 -04:00
[ this ] ( ) { PolygonProperties - > bShowGridGizmo = ! PolygonProperties - > bShowGridGizmo ; } ) ;
2019-10-01 20:41:42 -04:00
}
2020-10-09 22:42:26 -04:00
void UDrawPolygonTool : : ApplyUndoPoints ( const TArray < FVector3d > & ClickPointsIn , const TArray < FVector3d > & PolygonVerticesIn )
2019-10-01 20:41:42 -04:00
{
if ( bInInteractiveExtrude | | PolygonVertices . Num ( ) = = 0 )
{
return ;
}
2020-03-10 14:00:36 -04:00
bHaveSelfIntersection = false ;
2019-10-01 20:41:42 -04:00
if ( bInFixedPolygonMode = = false )
{
2020-10-09 22:42:26 -04:00
PolygonVertices = PolygonVerticesIn ;
if ( PolygonVertices . Num ( ) = = 0 )
2019-10-01 20:41:42 -04:00
{
bAbortActivePolygonDraw = true ;
2020-03-06 14:44:21 -05:00
CurrentCurveTimestamp + + ;
2019-10-01 20:41:42 -04:00
}
}
else
{
2020-10-09 22:42:26 -04:00
FixedPolygonClickPoints = ClickPointsIn ;
if ( FixedPolygonClickPoints . Num ( ) = = 0 )
2019-10-01 20:41:42 -04:00
{
bAbortActivePolygonDraw = true ;
2020-03-06 14:44:21 -05:00
CurrentCurveTimestamp + + ;
2019-10-01 20:41:42 -04:00
}
}
}
2019-11-15 12:53:29 -05:00
2020-04-18 18:42:59 -04:00
void UDrawPolygonTool : : OnTick ( float DeltaTime )
2019-11-15 12:53:29 -05:00
{
2022-01-11 12:12:12 -05:00
if ( SnapProperties )
{
bool bSnappingEnabledInViewport = GetToolManager ( ) - > GetContextQueriesAPI ( )
- > GetCurrentSnappingSettings ( ) . bEnablePositionGridSnapping ;
if ( SnapProperties - > bSnapToWorldGrid ! = bSnappingEnabledInViewport )
{
SnapProperties - > bSnapToWorldGrid = bSnappingEnabledInViewport ;
NotifyOfPropertyChangeByTool ( SnapProperties ) ;
}
}
2019-11-15 12:53:29 -05:00
}
2019-10-01 20:41:42 -04:00
void DrawEdgeTicks ( FPrimitiveDrawInterface * PDI ,
2020-03-31 18:31:32 -04:00
const FSegment3d & Segment , float Height ,
const FVector3d & PlaneNormal ,
2019-10-01 20:41:42 -04:00
const FLinearColor & Color , uint8 DepthPriorityGroup , float LineThickness , bool bIsScreenSpace )
{
2020-03-31 18:31:32 -04:00
FVector3d Center = Segment . Center ;
FVector3d X = Segment . Direction ;
FVector3d Y = X . Cross ( PlaneNormal ) ;
2021-03-17 19:32:44 -04:00
UE : : Geometry : : Normalize ( Y ) ;
2020-03-31 18:31:32 -04:00
FVector3d A = Center - Height * 0.25 * X - Height * Y ;
FVector3d B = Center + Height * 0.25 * X + Height * Y ;
2019-12-19 18:07:47 -05:00
PDI - > DrawLine ( ( FVector ) A , ( FVector ) B , Color , DepthPriorityGroup , LineThickness , 0.0f , bIsScreenSpace ) ;
2020-03-31 18:31:32 -04:00
A + = Height * 0.5 * X ;
B + = Height * 0.5 * X ;
2019-12-19 18:07:47 -05:00
PDI - > DrawLine ( ( FVector ) A , ( FVector ) B , Color , DepthPriorityGroup , LineThickness , 0.0f , bIsScreenSpace ) ;
2019-10-01 20:41:42 -04:00
}
void UDrawPolygonTool : : Render ( IToolsContextRenderAPI * RenderAPI )
{
FPrimitiveDrawInterface * PDI = RenderAPI - > GetPrimitiveDrawInterface ( ) ;
2020-06-23 18:40:00 -04:00
// Cache here for usage during interaction, should probably happen in ::Tick() or elsewhere
2019-10-01 20:41:42 -04:00
GetToolManager ( ) - > GetContextQueriesAPI ( ) - > GetCurrentViewState ( CameraState ) ;
2020-06-23 18:40:00 -04:00
FViewCameraState RenderCameraState = RenderAPI - > GetCameraState ( ) ;
float PDIScale = RenderCameraState . GetPDIScalingFactor ( ) ;
2019-10-01 20:41:42 -04:00
if ( bPreviewUpdatePending )
{
UpdateLivePreview ( ) ;
bPreviewUpdatePending = false ;
}
2020-06-23 18:40:00 -04:00
double CurViewSizeFactor = ToolSceneQueriesUtil : : CalculateDimensionFromVisualAngleD ( RenderCameraState , PreviewVertex , 1.0 ) ;
2019-10-01 20:41:42 -04:00
2020-09-24 00:43:27 -04:00
FColor PreviewColor = FColor : : Green ;
FColor OpenPolygonColor = FColor : : Orange ;
FColor ClosedPolygonColor = FColor : : Yellow ;
FColor ErrorColor = FColor : : Magenta ;
2020-06-23 18:40:00 -04:00
float HiddenLineThickness = 1.0f * PDIScale ;
float LineThickness = 4.0f * PDIScale ;
2020-09-24 00:43:27 -04:00
FColor SnapLineColor = FColor : : Yellow ;
FColor SnapHighlightColor = SnapLineColor ;
2019-10-01 20:41:42 -04:00
float ElementSize = CurViewSizeFactor ;
2020-09-24 00:43:27 -04:00
bool bIsClosed = bInInteractiveExtrude
| | ( SnapEngine . HaveActiveSnap ( ) & & SnapEngine . GetActiveSnapTargetID ( ) = = StartPointSnapID ) ;
2019-10-01 20:41:42 -04:00
2020-09-24 00:43:27 -04:00
//
2022-11-16 11:40:11 -05:00
// Render the plane mechanic after correctly setting bShowGrid
2020-09-24 00:43:27 -04:00
//
2022-11-16 11:40:11 -05:00
PlaneMechanic - > bShowGrid = ! bInInteractiveExtrude ;
PlaneMechanic - > Render ( RenderAPI ) ;
2019-10-01 20:41:42 -04:00
2020-09-24 00:43:27 -04:00
//
// Generate the fixed polygon contour
//
if ( ( bInFixedPolygonMode ) & & ( FixedPolygonClickPoints . Num ( ) > 0 ) )
2019-10-01 20:41:42 -04:00
{
2020-09-24 00:43:27 -04:00
TArray < FVector3d > PreviewClickPoints = FixedPolygonClickPoints ;
if ( ! bInInteractiveExtrude ) { PreviewClickPoints . Add ( PreviewVertex ) ; }
GenerateFixedPolygon ( PreviewClickPoints , PolygonVertices , PolygonHolesVertices ) ;
2019-10-01 20:41:42 -04:00
}
2020-09-24 00:43:27 -04:00
bIsClosed | = bInFixedPolygonMode ;
2019-10-01 20:41:42 -04:00
int NumVerts = PolygonVertices . Num ( ) ;
2020-09-24 00:43:27 -04:00
//
// Render snap indicators
//
2019-10-01 20:41:42 -04:00
if ( SnapEngine . HaveActiveSnap ( ) )
{
2020-06-23 18:40:00 -04:00
PDI - > DrawPoint ( ( FVector ) SnapEngine . GetActiveSnapToPoint ( ) , ClosedPolygonColor , 10.0f * PDIScale , SDPG_Foreground ) ;
2020-09-24 00:43:27 -04:00
PDI - > DrawPoint ( ( FVector ) SnapEngine . GetActiveSnapFromPoint ( ) , SnapHighlightColor , 15.0f * PDIScale , SDPG_Foreground ) ;
2019-10-01 20:41:42 -04:00
PDI - > DrawLine ( ( FVector ) SnapEngine . GetActiveSnapToPoint ( ) , ( FVector ) SnapEngine . GetActiveSnapFromPoint ( ) ,
2020-06-23 18:40:00 -04:00
ClosedPolygonColor , SDPG_Foreground , 0.5f * PDIScale , 0.0f , true ) ;
2019-10-01 20:41:42 -04:00
if ( SnapEngine . GetActiveSnapTargetID ( ) = = CurrentSceneSnapID )
{
if ( LastSnapGeometry . PointCount = = 1 ) {
2020-06-23 18:40:00 -04:00
DrawCircle ( PDI , ( FVector ) LastSnapGeometry . Points [ 0 ] , RenderCameraState . Right ( ) , RenderCameraState . Up ( ) ,
SnapHighlightColor , ElementSize , 32 , SDPG_Foreground , 1.0f * PDIScale , 0.0f , true ) ;
2020-09-24 00:43:27 -04:00
}
2019-10-01 20:41:42 -04:00
else
{
PDI - > DrawLine ( ( FVector ) LastSnapGeometry . Points [ 0 ] , ( FVector ) LastSnapGeometry . Points [ 1 ] ,
2020-06-23 18:40:00 -04:00
SnapHighlightColor , SDPG_Foreground , 1.0f * PDIScale , 0.0f , true ) ;
2019-10-01 20:41:42 -04:00
}
}
2019-11-11 16:57:51 -05:00
else if ( SnapEngine . GetActiveSnapTargetID ( ) = = CurrentGridSnapID )
{
2020-06-23 18:40:00 -04:00
DrawCircle ( PDI , ( FVector ) LastGridSnapPoint , RenderCameraState . Right ( ) , RenderCameraState . Up ( ) ,
SnapHighlightColor , ElementSize , 4 , SDPG_Foreground , 1.0f * PDIScale , 0.0f , true ) ;
2019-11-11 16:57:51 -05:00
}
2019-10-01 20:41:42 -04:00
if ( SnapEngine . HaveActiveSnapLine ( ) )
{
2020-09-24 00:43:27 -04:00
// clip this line to the view plane because if it goes through the view plane the pixel-line-thickness
// calculation appears to fail
FLine3d DrawSnapLine = SnapEngine . GetActiveSnapLine ( ) ;
2021-03-30 21:25:22 -04:00
FVector3d P0 ( DrawSnapLine . PointAt ( - 99999.0 ) ) , P1 ( DrawSnapLine . PointAt ( 99999.0 ) ) ; // should be smarter here...
2020-09-24 00:43:27 -04:00
if ( RenderCameraState . bIsOrthographic = = false )
{
2021-03-30 21:25:22 -04:00
UE : : Geometry : : FPlane3d CameraPlane ( ( FVector3d ) RenderCameraState . Forward ( ) , ( FVector3d ) RenderCameraState . Position + 1.0 * ( FVector3d ) RenderCameraState . Forward ( ) ) ;
2020-09-24 00:43:27 -04:00
CameraPlane . ClipSegment ( P0 , P1 ) ;
}
PDI - > DrawLine ( ( FVector ) P0 , ( FVector ) P1 , SnapLineColor , SDPG_Foreground , 0.5 * PDIScale , 0.0f , true ) ;
2019-10-01 20:41:42 -04:00
if ( SnapEngine . HaveActiveSnapDistance ( ) )
{
int iSegment = SnapEngine . GetActiveSnapDistanceID ( ) ;
2020-03-31 18:31:32 -04:00
TArray < FVector3d > & HistoryPoints = ( bInFixedPolygonMode ) ? FixedPolygonClickPoints : PolygonVertices ;
2022-11-16 11:40:11 -05:00
FVector3d UseNormal = PlaneMechanic - > Plane . Rotation . AxisZ ( ) ;
2020-03-31 18:31:32 -04:00
DrawEdgeTicks ( PDI , FSegment3d ( HistoryPoints [ iSegment ] , HistoryPoints [ iSegment + 1 ] ) ,
2020-06-23 18:40:00 -04:00
0.75f * ElementSize , UseNormal , SnapHighlightColor , SDPG_Foreground , 1.0f * PDIScale , true ) ;
2020-03-31 18:31:32 -04:00
DrawEdgeTicks ( PDI , FSegment3d ( HistoryPoints [ HistoryPoints . Num ( ) - 1 ] , PreviewVertex ) ,
2020-06-23 18:40:00 -04:00
0.75f * ElementSize , UseNormal , SnapHighlightColor , SDPG_Foreground , 1.0f * PDIScale , true ) ;
2020-09-24 00:43:27 -04:00
// Drawing a highlight
2020-03-31 18:31:32 -04:00
PDI - > DrawLine ( ( FVector ) HistoryPoints [ iSegment ] , ( FVector ) HistoryPoints [ iSegment + 1 ] ,
2020-09-24 00:43:27 -04:00
SnapHighlightColor , SDPG_Foreground , 2.0f * PDIScale , 1.0f , true ) ;
2019-10-01 20:41:42 -04:00
}
}
}
2020-09-24 00:43:27 -04:00
//
// Draw Surface Hit Indicator
//
2019-10-01 20:41:42 -04:00
if ( bHaveSurfaceHit )
{
2020-06-23 18:40:00 -04:00
PDI - > DrawPoint ( ( FVector ) SurfaceHitPoint , ClosedPolygonColor , 10 * PDIScale , SDPG_Foreground ) ;
2021-10-20 20:41:00 -04:00
if ( SnapProperties - > SnapToSurfacesOffset ! = 0 )
2019-10-01 20:41:42 -04:00
{
2020-06-23 18:40:00 -04:00
PDI - > DrawPoint ( ( FVector ) SurfaceOffsetPoint , OpenPolygonColor , 15 * PDIScale , SDPG_Foreground ) ;
2019-10-01 20:41:42 -04:00
PDI - > DrawLine ( ( FVector ) SurfaceOffsetPoint , ( FVector ) SurfaceHitPoint ,
2020-06-23 18:40:00 -04:00
ClosedPolygonColor , SDPG_Foreground , 0.5f * PDIScale , 0.0f , true ) ;
2019-10-01 20:41:42 -04:00
}
PDI - > DrawLine ( ( FVector ) SurfaceOffsetPoint , ( FVector ) PreviewVertex ,
2020-06-23 18:40:00 -04:00
ClosedPolygonColor , SDPG_Foreground , 0.5f * PDIScale , 0.0f , true ) ;
2019-10-01 20:41:42 -04:00
}
2020-09-24 00:43:27 -04:00
//
// Draw the polygon contour preview
//
2019-10-01 20:41:42 -04:00
if ( PolygonVertices . Num ( ) > 0 )
{
2020-09-24 00:43:27 -04:00
FColor UseColor = bIsClosed ? ClosedPolygonColor
: bHaveSelfIntersection ? ErrorColor : OpenPolygonColor ;
FColor LastSegmentColor = bIsClosed ? ClosedPolygonColor
: bHaveSelfIntersection ? ErrorColor : PreviewColor ;
FVector3d UseLastVertex = bIsClosed ? PolygonVertices [ 0 ] : PreviewVertex ;
2019-10-01 20:41:42 -04:00
2020-03-31 18:31:32 -04:00
auto DrawVertices = [ & PDI , & UseColor ] ( const TArray < FVector3d > & Vertices , ESceneDepthPriorityGroup Group , float Thickness )
2019-09-12 13:55:17 -04:00
{
2019-11-01 20:48:07 -04:00
for ( int lasti = Vertices . Num ( ) - 1 , i = 0 , NumVertices = Vertices . Num ( ) ; i < NumVertices ; lasti = i + + )
2020-04-18 18:42:59 -04:00
2019-11-01 20:48:07 -04:00
{
2020-03-31 18:31:32 -04:00
PDI - > DrawLine ( ( FVector ) Vertices [ lasti ] , ( FVector ) Vertices [ i ] , UseColor , Group , Thickness , 0.0f , true ) ;
2019-11-01 20:48:07 -04:00
}
} ;
2019-09-12 13:55:17 -04:00
2020-09-24 00:43:27 -04:00
// draw thin no-depth (x-ray draw)
2019-11-03 15:54:44 -05:00
//DrawVertices(PolygonVertices, SDPG_Foreground, HiddenLineThickness);
2019-10-01 20:41:42 -04:00
for ( int i = 0 ; i < NumVerts - 1 ; + + i )
{
2020-03-31 18:31:32 -04:00
PDI - > DrawLine ( ( FVector ) PolygonVertices [ i ] , ( FVector ) PolygonVertices [ i + 1 ] ,
2019-10-01 20:41:42 -04:00
UseColor , SDPG_Foreground , HiddenLineThickness , 0.0f , true ) ;
}
2020-03-31 18:31:32 -04:00
PDI - > DrawLine ( ( FVector ) PolygonVertices [ NumVerts - 1 ] , ( FVector ) UseLastVertex ,
2020-09-24 00:43:27 -04:00
LastSegmentColor , SDPG_Foreground , HiddenLineThickness , 0.0f , true ) ;
2019-11-01 20:48:07 -04:00
for ( int HoleIdx = 0 ; HoleIdx < PolygonHolesVertices . Num ( ) ; HoleIdx + + )
{
DrawVertices ( PolygonHolesVertices [ HoleIdx ] , SDPG_Foreground , HiddenLineThickness ) ;
}
2019-10-01 20:41:42 -04:00
// draw thick depth-tested
2019-11-03 15:54:44 -05:00
//DrawVertices(PolygonVertices, SDPG_World, LineThickness);
for ( int i = 0 ; i < NumVerts - 1 ; + + i )
2019-10-01 20:41:42 -04:00
{
2020-03-31 18:31:32 -04:00
PDI - > DrawLine ( ( FVector ) PolygonVertices [ i ] , ( FVector ) PolygonVertices [ i + 1 ] ,
2019-10-01 20:41:42 -04:00
UseColor , SDPG_World , LineThickness , 0.0f , true ) ;
}
2020-03-31 18:31:32 -04:00
PDI - > DrawLine ( ( FVector ) PolygonVertices [ NumVerts - 1 ] , ( FVector ) UseLastVertex ,
2020-09-24 00:43:27 -04:00
LastSegmentColor , SDPG_World , LineThickness , 0.0f , true ) ;
2019-11-01 20:48:07 -04:00
for ( int HoleIdx = 0 ; HoleIdx < PolygonHolesVertices . Num ( ) ; HoleIdx + + )
2019-09-12 13:55:17 -04:00
{
2019-11-01 20:48:07 -04:00
DrawVertices ( PolygonHolesVertices [ HoleIdx ] , SDPG_World , LineThickness ) ;
2019-09-12 13:55:17 -04:00
}
2019-10-01 20:41:42 -04:00
2020-09-24 00:43:27 -04:00
// Intersection point
if ( bHaveSelfIntersection & & ! bInInteractiveExtrude )
2019-10-01 20:41:42 -04:00
{
2020-09-24 00:43:27 -04:00
PDI - > DrawPoint ( ( FVector ) SelfIntersectionPoint , SnapHighlightColor , 12 * PDIScale , SDPG_Foreground ) ;
2019-10-01 20:41:42 -04:00
}
}
// draw preview vertex
2020-09-24 00:43:27 -04:00
if ( ! bInInteractiveExtrude )
{
PDI - > DrawPoint ( ( FVector ) PreviewVertex , PreviewColor , 10 * PDIScale , SDPG_Foreground ) ;
}
2019-10-01 20:41:42 -04:00
2020-01-27 20:11:15 -05:00
// draw height preview stuff
2019-10-01 20:41:42 -04:00
if ( bInInteractiveExtrude )
{
2020-01-27 20:11:15 -05:00
HeightMechanic - > Render ( RenderAPI ) ;
2019-10-01 20:41:42 -04:00
}
}
void UDrawPolygonTool : : ResetPolygon ( )
{
PolygonVertices . Reset ( ) ;
2019-11-01 20:48:07 -04:00
PolygonHolesVertices . Reset ( ) ;
2019-10-01 20:41:42 -04:00
SnapEngine . Reset ( ) ;
bHaveSurfaceHit = false ;
bInFixedPolygonMode = false ;
2020-03-10 14:00:36 -04:00
bHaveSelfIntersection = false ;
2020-03-06 14:44:21 -05:00
CurrentCurveTimestamp + + ;
2019-10-01 20:41:42 -04:00
}
2020-03-31 18:31:32 -04:00
void UDrawPolygonTool : : UpdatePreviewVertex ( const FVector3d & PreviewVertexIn )
2019-10-01 20:41:42 -04:00
{
PreviewVertex = PreviewVertexIn ;
// update length and angle
if ( PolygonVertices . Num ( ) > 0 )
{
2021-10-20 20:41:00 -04:00
const FVector3d LastVertex = PolygonVertices [ PolygonVertices . Num ( ) - 1 ] ;
2021-11-07 23:43:01 -05:00
if ( bInFixedPolygonMode )
{
double FixedDistance = 0 ; // get a representative distance for the shape, to show to the user
if ( FixedPolygonClickPoints . Num ( ) > 0 )
{
// Build standard polygon parameters
TArray < FVector3d > PreviewClickPoints = FixedPolygonClickPoints ;
PreviewClickPoints . Add ( PreviewVertex ) ;
FVector2d FirstReferencePt , BoxSize ;
double YSign , AngleRad ;
GetPolygonParametersFromFixedPoints ( PreviewClickPoints , FirstReferencePt , BoxSize , YSign , AngleRad ) ;
double Width = BoxSize . X , Height = BoxSize . Y ;
// For rectangles, interface uses width for earlier click, height for later
if ( PolygonProperties - > PolygonDrawMode = = EDrawPolygonDrawMode : : Rectangle | | PolygonProperties - > PolygonDrawMode = = EDrawPolygonDrawMode : : RoundedRectangle )
{
if ( PreviewClickPoints . Num ( ) = = 2 )
{
FixedDistance = Width ;
}
else
{
FixedDistance = Height ;
}
}
else // For all else (circles, discs and squares), only width is used
{
FixedDistance = Width ;
}
}
PolygonProperties - > Distance = ( float ) FixedDistance ;
}
else
{
PolygonProperties - > Distance = Distance ( LastVertex , PreviewVertex ) ;
}
2019-10-01 20:41:42 -04:00
}
}
2020-03-31 18:31:32 -04:00
void UDrawPolygonTool : : AppendVertex ( const FVector3d & Vertex )
2019-10-01 20:41:42 -04:00
{
PolygonVertices . Add ( Vertex ) ;
}
2020-03-31 18:31:32 -04:00
bool UDrawPolygonTool : : FindDrawPlaneHitPoint ( const FInputDeviceRay & ClickPos , FVector3d & HitPosOut )
2019-10-01 20:41:42 -04:00
{
bHaveSurfaceHit = false ;
2022-11-16 11:40:11 -05:00
const FFrame3d & Frame = PlaneMechanic - > Plane ;
2019-10-01 20:41:42 -04:00
FVector3d HitPos ;
2021-03-30 21:25:22 -04:00
bool bHit = Frame . RayPlaneIntersection ( ( FVector3d ) ClickPos . WorldRay . Origin , ( FVector3d ) ClickPos . WorldRay . Direction , 2 , HitPos ) ;
2019-10-01 20:41:42 -04:00
if ( bHit = = false )
{
return false ;
}
// if we found a scene snap point, add to snap set
if ( bIgnoreSnappingToggle | | SnapProperties - > bEnableSnapping = = false )
{
2021-11-07 23:43:01 -05:00
// if snapping is disabled, still snap to the first vertex (so the polygon can be closed)
2020-09-01 14:07:48 -04:00
SnapEngine . Reset ( ) ;
2021-11-07 23:43:01 -05:00
if ( bInFixedPolygonMode = = false & & PolygonVertices . Num ( ) > 0 )
{
SnapEngine . AddPointTarget ( PolygonVertices [ 0 ] , StartPointSnapID , 1 ) ;
}
2019-10-01 20:41:42 -04:00
}
else
{
2022-01-11 12:12:12 -05:00
FVector3d WorldGridSnapPos ;
if ( ToolSceneQueriesUtil : : FindWorldGridSnapPoint ( this , HitPos , WorldGridSnapPos ) )
2019-10-01 20:41:42 -04:00
{
2022-01-11 12:12:12 -05:00
WorldGridSnapPos = Frame . ToPlane ( WorldGridSnapPos , 2 ) ;
SnapEngine . AddPointTarget ( WorldGridSnapPos , CurrentGridSnapID ,
FBasePositionSnapSolver3 : : FCustomMetric : : Replace ( 999 ) , SnapEngine . MinInternalPriority ( ) - 5 ) ;
LastGridSnapPoint = WorldGridSnapPos ;
2019-11-11 16:57:51 -05:00
}
if ( SnapProperties - > bSnapToVertices | | SnapProperties - > bSnapToEdges )
{
FVector3d SceneSnapPos ;
if ( ToolSceneQueriesUtil : : FindSceneSnapPoint ( this , HitPos , SceneSnapPos , SnapProperties - > bSnapToVertices , SnapProperties - > bSnapToEdges , 0 , & LastSnapGeometry ) )
{
SnapEngine . AddPointTarget ( SceneSnapPos , CurrentSceneSnapID , SnapEngine . MinInternalPriority ( ) - 10 ) ;
}
2019-10-01 20:41:42 -04:00
}
2021-10-20 20:41:00 -04:00
const TArray < FVector3d > & HistoryPoints = ( bInFixedPolygonMode ) ? FixedPolygonClickPoints : PolygonVertices ;
2019-10-01 20:41:42 -04:00
SnapEngine . UpdatePointHistory ( HistoryPoints ) ;
2021-10-20 20:41:00 -04:00
if ( SnapProperties - > bSnapToAxes )
2019-10-01 20:41:42 -04:00
{
SnapEngine . RegenerateTargetLines ( true , true ) ;
}
SnapEngine . bEnableSnapToKnownLengths = SnapProperties - > bSnapToLengths ;
}
2021-11-07 23:43:01 -05:00
// ignore snapping to start point unless we have at least 3 vertices
if ( bInFixedPolygonMode = = false & & PolygonVertices . Num ( ) > 0 )
{
if ( PolygonVertices . Num ( ) < 3 )
{
SnapEngine . AddIgnoreTarget ( StartPointSnapID ) ;
}
else
{
SnapEngine . RemoveIgnoreTarget ( StartPointSnapID ) ;
}
}
2019-10-01 20:41:42 -04:00
SnapEngine . UpdateSnappedPoint ( HitPos ) ;
// remove scene snap point
SnapEngine . RemovePointTargetsByID ( CurrentSceneSnapID ) ;
2019-11-11 16:57:51 -05:00
SnapEngine . RemovePointTargetsByID ( CurrentGridSnapID ) ;
2019-10-01 20:41:42 -04:00
if ( SnapEngine . HaveActiveSnap ( ) )
{
2020-03-31 18:31:32 -04:00
HitPosOut = SnapEngine . GetActiveSnapToPoint ( ) ;
2019-10-01 20:41:42 -04:00
return true ;
}
2022-01-11 12:12:12 -05:00
// if not yet snapped and we want to hit objects, do that
if ( SnapProperties - > bSnapToSurfaces & & ! bIgnoreSnappingToggle )
2019-10-01 20:41:42 -04:00
{
FHitResult Result ;
2021-12-09 14:46:09 -05:00
bool bWorldHit = ToolSceneQueriesUtil : : FindNearestVisibleObjectHit ( this , Result , ClickPos . WorldRay ) ;
2019-10-01 20:41:42 -04:00
if ( bWorldHit )
{
bHaveSurfaceHit = true ;
2021-03-30 21:25:22 -04:00
SurfaceHitPoint = ( FVector3d ) Result . ImpactPoint ;
2021-10-20 20:41:00 -04:00
const FVector3d UseHitPos = Result . ImpactPoint + static_cast < double > ( SnapProperties - > SnapToSurfacesOffset ) * Result . Normal ;
2020-03-31 18:31:32 -04:00
HitPos = Frame . ToPlane ( UseHitPos , 2 ) ;
2019-10-01 20:41:42 -04:00
SurfaceOffsetPoint = UseHitPos ;
}
}
2020-03-31 18:31:32 -04:00
HitPosOut = HitPos ;
2019-10-01 20:41:42 -04:00
return true ;
}
void UDrawPolygonTool : : OnBeginSequencePreview ( const FInputDeviceRay & DevicePos )
{
// just update snapped point preview
2020-03-31 18:31:32 -04:00
FVector3d HitPos ;
2019-10-01 20:41:42 -04:00
if ( FindDrawPlaneHitPoint ( DevicePos , HitPos ) )
{
PreviewVertex = HitPos ;
}
}
bool UDrawPolygonTool : : CanBeginClickSequence ( const FInputDeviceRay & ClickPos )
{
return true ;
}
void UDrawPolygonTool : : OnBeginClickSequence ( const FInputDeviceRay & ClickPos )
{
ResetPolygon ( ) ;
2020-03-31 18:31:32 -04:00
FVector3d HitPos ;
2019-10-01 20:41:42 -04:00
bool bHit = FindDrawPlaneHitPoint ( ClickPos , HitPos ) ;
if ( bHit = = false )
{
bAbortActivePolygonDraw = true ;
return ;
}
if ( ToolSceneQueriesUtil : : IsPointVisible ( CameraState , HitPos ) = = false )
{
bAbortActivePolygonDraw = true ;
return ; // cannot start a poly an a point that is not visible, this is almost certainly an error due to draw plane
}
UpdatePreviewVertex ( HitPos ) ;
2021-10-20 20:41:00 -04:00
bInFixedPolygonMode = ( PolygonProperties - > PolygonDrawMode ! = EDrawPolygonDrawMode : : Freehand ) ;
2019-10-01 20:41:42 -04:00
FixedPolygonClickPoints . Reset ( ) ;
2020-09-24 00:43:27 -04:00
// Actually process the click.
// TODO: This slightly awkward organization is a reflection of an earlier time when
// MultiClickSequenceInputBehavior issued a duplicate OnNextSequenceClick() call
// immediately after OnBeginClickSequence(). The code could be cleaned up.
OnNextSequenceClick ( ClickPos ) ;
2019-10-01 20:41:42 -04:00
}
void UDrawPolygonTool : : OnNextSequencePreview ( const FInputDeviceRay & ClickPos )
{
if ( bInInteractiveExtrude )
{
2020-01-27 20:11:15 -05:00
HeightMechanic - > UpdateCurrentDistance ( ClickPos . WorldRay ) ;
PolygonProperties - > ExtrudeHeight = HeightMechanic - > CurrentHeight ;
2019-10-01 20:41:42 -04:00
bPreviewUpdatePending = true ;
return ;
}
2020-03-31 18:31:32 -04:00
FVector3d HitPos ;
2019-10-01 20:41:42 -04:00
bool bHit = FindDrawPlaneHitPoint ( ClickPos , HitPos ) ;
if ( bHit = = false )
{
return ;
}
if ( bInFixedPolygonMode )
{
UpdatePreviewVertex ( HitPos ) ;
bPreviewUpdatePending = true ;
return ;
}
2020-03-05 20:34:19 -05:00
UpdatePreviewVertex ( HitPos ) ;
2020-03-10 14:00:36 -04:00
UpdateSelfIntersection ( ) ;
2019-10-01 20:41:42 -04:00
if ( PolygonVertices . Num ( ) > 2 )
{
bPreviewUpdatePending = true ;
}
}
bool UDrawPolygonTool : : OnNextSequenceClick ( const FInputDeviceRay & ClickPos )
{
if ( bInInteractiveExtrude )
{
EndInteractiveExtrude ( ) ;
return false ;
}
2020-03-31 18:31:32 -04:00
FVector3d HitPos ;
2019-10-01 20:41:42 -04:00
bool bHit = FindDrawPlaneHitPoint ( ClickPos , HitPos ) ;
if ( bHit = = false )
{
return true ; // ignore click but continue accepting clicks
}
2020-10-09 22:42:26 -04:00
// Construct the change now for the undo queue so it reflects the current state. We might not do anything, in which
// case we will not emit the change
TUniquePtr < FDrawPolygonStateChange > Change =
MakeUnique < FDrawPolygonStateChange > ( CurrentCurveTimestamp , FixedPolygonClickPoints , PolygonVertices ) ;
2021-10-20 20:41:00 -04:00
bool bDonePolygon ;
2019-10-01 20:41:42 -04:00
if ( bInFixedPolygonMode )
{
// ignore very close click points
2020-03-05 20:34:19 -05:00
if ( FixedPolygonClickPoints . Num ( ) > 0 & & ToolSceneQueriesUtil : : PointSnapQuery ( this , FixedPolygonClickPoints [ FixedPolygonClickPoints . Num ( ) - 1 ] , HitPos ) )
2019-10-01 20:41:42 -04:00
{
return true ;
}
FixedPolygonClickPoints . Add ( HitPos ) ;
2021-10-20 20:41:00 -04:00
int NumTargetPoints = ( PolygonProperties - > PolygonDrawMode = = EDrawPolygonDrawMode : : Rectangle | | PolygonProperties - > PolygonDrawMode = = EDrawPolygonDrawMode : : RoundedRectangle ) ? 3 : 2 ;
2019-10-01 20:41:42 -04:00
bDonePolygon = ( FixedPolygonClickPoints . Num ( ) = = NumTargetPoints ) ;
if ( bDonePolygon )
{
2019-11-01 20:48:07 -04:00
GenerateFixedPolygon ( FixedPolygonClickPoints , PolygonVertices , PolygonHolesVertices ) ;
2019-10-01 20:41:42 -04:00
}
2020-10-09 22:42:26 -04:00
}
2019-10-01 20:41:42 -04:00
else
{
// ignore very close click points
2020-03-05 20:34:19 -05:00
if ( PolygonVertices . Num ( ) > 0 & & ToolSceneQueriesUtil : : PointSnapQuery ( this , PolygonVertices [ PolygonVertices . Num ( ) - 1 ] , HitPos ) )
2019-10-01 20:41:42 -04:00
{
return true ;
}
if ( bHaveSelfIntersection )
{
2022-01-27 17:29:26 -05:00
// If the self-intersection point is coincident with a polygon vertex, don't add that point twice (it would produce a degenerate polygon edge)
if ( SelfIntersectSegmentIdx < PolygonVertices . Num ( ) - 1 & & FVector3d : : PointsAreSame ( SelfIntersectionPoint , PolygonVertices [ SelfIntersectSegmentIdx + 1 ] ) )
{
+ + SelfIntersectSegmentIdx ;
}
2019-10-01 20:41:42 -04:00
// discard vertex in segments before intersection (this is redundant if idx is 0)
for ( int j = SelfIntersectSegmentIdx ; j < PolygonVertices . Num ( ) ; + + j )
{
PolygonVertices [ j - SelfIntersectSegmentIdx ] = PolygonVertices [ j ] ;
}
PolygonVertices . SetNum ( PolygonVertices . Num ( ) - SelfIntersectSegmentIdx ) ;
2021-10-20 20:41:00 -04:00
PolygonVertices [ 0 ] = PreviewVertex = SelfIntersectionPoint ;
2019-10-01 20:41:42 -04:00
bDonePolygon = true ;
}
2021-10-20 20:41:00 -04:00
else
{
// close polygon if we clicked on start point
bDonePolygon = SnapEngine . HaveActiveSnap ( ) & & SnapEngine . GetActiveSnapTargetID ( ) = = StartPointSnapID ;
}
2019-10-01 20:41:42 -04:00
}
2020-10-09 22:42:26 -04:00
// emit change event
GetToolManager ( ) - > EmitObjectChange ( this , MoveTemp ( Change ) , LOCTEXT ( " DrawPolyAddPoint " , " Add Point " ) ) ;
2019-10-01 20:41:42 -04:00
if ( bDonePolygon )
{
2020-03-10 14:00:36 -04:00
//SnapEngine.Reset();
2019-10-01 20:41:42 -04:00
bHaveSurfaceHit = false ;
2021-10-21 17:57:49 -04:00
if ( PolygonProperties - > ExtrudeMode = = EDrawPolygonExtrudeMode : : Interactive )
2019-10-01 20:41:42 -04:00
{
BeginInteractiveExtrude ( ) ;
PreviewMesh - > ClearPreview ( ) ;
PreviewMesh - > SetVisible ( true ) ;
return true ;
}
else
{
EmitCurrentPolygon ( ) ;
PreviewMesh - > ClearPreview ( ) ;
PreviewMesh - > SetVisible ( false ) ;
return false ;
}
}
AppendVertex ( HitPos ) ;
2020-03-05 20:34:19 -05:00
2021-11-07 23:43:01 -05:00
// if we are starting a freehand poly, add start point as snap target.
// Note that logic in FindDrawPlaneHitPoint will ignore it until we get 3 verts
2020-03-05 20:34:19 -05:00
if ( bInFixedPolygonMode = = false & & PolygonVertices . Num ( ) = = 1 )
{
SnapEngine . AddPointTarget ( PolygonVertices [ 0 ] , StartPointSnapID , 1 ) ;
2019-10-01 20:41:42 -04:00
}
UpdatePreviewVertex ( HitPos ) ;
return true ;
}
void UDrawPolygonTool : : OnTerminateClickSequence ( )
{
ResetPolygon ( ) ;
}
bool UDrawPolygonTool : : RequestAbortClickSequence ( )
{
if ( bAbortActivePolygonDraw )
{
bAbortActivePolygonDraw = false ;
return true ;
}
return false ;
}
void UDrawPolygonTool : : OnUpdateModifierState ( int ModifierID , bool bIsOn )
{
if ( ModifierID = = IgnoreSnappingModifier )
{
bIgnoreSnappingToggle = bIsOn ;
}
else if ( ModifierID = = AngleSnapModifier )
{
}
}
bool UDrawPolygonTool : : UpdateSelfIntersection ( )
{
bHaveSelfIntersection = false ;
if ( bInFixedPolygonMode | | PolygonProperties - > bAllowSelfIntersections = = true )
{
return false ;
}
int NumVertices = PolygonVertices . Num ( ) ;
2020-03-10 14:00:36 -04:00
if ( NumVertices < 3 )
{
return false ;
}
2019-10-01 20:41:42 -04:00
2022-11-16 11:40:11 -05:00
const FFrame3d & DrawFrame = PlaneMechanic - > Plane ;
2020-03-31 18:31:32 -04:00
FSegment2d PreviewSegment ( DrawFrame . ToPlaneUV ( PolygonVertices [ NumVertices - 1 ] , 2 ) , DrawFrame . ToPlaneUV ( PreviewVertex , 2 ) ) ;
2019-10-01 20:41:42 -04:00
2020-03-31 18:31:32 -04:00
double BestIntersectionParameter = FMathd : : MaxReal ;
2019-10-01 20:41:42 -04:00
for ( int k = 0 ; k < NumVertices - 2 ; + + k )
{
2020-03-31 18:31:32 -04:00
FSegment2d Segment ( DrawFrame . ToPlaneUV ( PolygonVertices [ k ] , 2 ) , DrawFrame . ToPlaneUV ( PolygonVertices [ k + 1 ] , 2 ) ) ;
FIntrSegment2Segment2d Intersection ( PreviewSegment , Segment ) ;
2019-10-01 20:41:42 -04:00
if ( Intersection . Find ( ) )
{
bHaveSelfIntersection = true ;
2019-11-06 14:33:56 -05:00
if ( Intersection . Parameter0 < BestIntersectionParameter )
{
BestIntersectionParameter = Intersection . Parameter0 ;
SelfIntersectSegmentIdx = k ;
SelfIntersectionPoint = DrawFrame . FromPlaneUV ( Intersection . Point0 , 2 ) ;
}
2019-10-01 20:41:42 -04:00
}
}
2019-11-06 14:33:56 -05:00
return bHaveSelfIntersection ;
2019-10-01 20:41:42 -04:00
}
2020-03-31 18:31:32 -04:00
void UDrawPolygonTool : : GetPolygonParametersFromFixedPoints ( const TArray < FVector3d > & FixedPoints , FVector2d & FirstReferencePt , FVector2d & BoxSize , double & YSign , double & AngleRad )
2019-10-01 20:41:42 -04:00
{
2019-11-06 20:53:34 -05:00
if ( FixedPoints . Num ( ) < 2 )
{
return ;
}
2019-11-01 20:48:07 -04:00
2022-11-16 11:40:11 -05:00
const FFrame3d & DrawFrame = PlaneMechanic - > Plane ;
2019-11-06 20:53:34 -05:00
FirstReferencePt = DrawFrame . ToPlaneUV ( FixedPoints [ 0 ] , 2 ) ;
2020-03-31 18:31:32 -04:00
FVector2d EdgePt = DrawFrame . ToPlaneUV ( FixedPoints [ 1 ] , 2 ) ;
FVector2d Delta = EdgePt - FirstReferencePt ;
AngleRad = FMathd : : Atan2 ( Delta . Y , Delta . X ) ;
2019-11-06 20:53:34 -05:00
2020-03-31 18:31:32 -04:00
double Radius = Delta . Length ( ) ;
2023-04-26 16:56:54 -04:00
FVector2d AxisX = Radius ! = 0 ? Delta / Radius
: FVector2d ( 1 , 0 ) ; // arbitrary if delta was 0 vector
2021-03-18 02:31:40 -04:00
FVector2d AxisY = - UE : : Geometry : : PerpCW ( AxisX ) ;
2020-03-31 18:31:32 -04:00
FVector2d HeightPt = DrawFrame . ToPlaneUV ( ( FixedPoints . Num ( ) = = 3 ) ? FixedPoints [ 2 ] : FixedPoints [ 1 ] , 2 ) ;
FVector2d HeightDelta = HeightPt - FirstReferencePt ;
YSign = FMathd : : Sign ( HeightDelta . Dot ( AxisY ) ) ;
2019-11-06 20:53:34 -05:00
BoxSize . X = Radius ;
2020-03-31 18:31:32 -04:00
BoxSize . Y = FMathd : : Abs ( HeightDelta . Dot ( AxisY ) ) ;
2019-11-06 20:53:34 -05:00
}
2020-03-31 18:31:32 -04:00
void UDrawPolygonTool : : GenerateFixedPolygon ( const TArray < FVector3d > & FixedPoints , TArray < FVector3d > & VerticesOut , TArray < TArray < FVector3d > > & HolesVerticesOut )
2019-11-06 20:53:34 -05:00
{
2020-03-31 18:31:32 -04:00
FVector2d FirstReferencePt , BoxSize ;
double YSign , AngleRad ;
2019-11-06 20:53:34 -05:00
GetPolygonParametersFromFixedPoints ( FixedPoints , FirstReferencePt , BoxSize , YSign , AngleRad ) ;
2020-03-31 18:31:32 -04:00
double Width = BoxSize . X , Height = BoxSize . Y ;
FMatrix2d RotationMat = FMatrix2d : : RotationRad ( AngleRad ) ;
2019-10-01 20:41:42 -04:00
2020-03-31 18:31:32 -04:00
FPolygon2d Polygon ;
TArray < FPolygon2d > PolygonHoles ;
2021-10-20 20:41:00 -04:00
if ( PolygonProperties - > PolygonDrawMode = = EDrawPolygonDrawMode : : Square )
2019-10-01 20:41:42 -04:00
{
2020-03-31 18:31:32 -04:00
Polygon = FPolygon2d : : MakeRectangle ( FVector2d : : Zero ( ) , 2 * Width , 2 * Width ) ;
2019-10-01 20:41:42 -04:00
}
2021-10-20 20:41:00 -04:00
else if ( PolygonProperties - > PolygonDrawMode = = EDrawPolygonDrawMode : : Rectangle | | PolygonProperties - > PolygonDrawMode = = EDrawPolygonDrawMode : : RoundedRectangle )
2019-10-01 20:41:42 -04:00
{
2021-10-20 20:41:00 -04:00
if ( PolygonProperties - > PolygonDrawMode = = EDrawPolygonDrawMode : : Rectangle )
2019-11-01 20:48:07 -04:00
{
2020-03-31 18:31:32 -04:00
Polygon = FPolygon2d : : MakeRectangle ( FVector2d ( Width / 2 , YSign * Height / 2 ) , Width , Height ) ;
2019-11-01 20:48:07 -04:00
}
2021-10-20 20:41:00 -04:00
else // PolygonProperties->PolygonDrawMode == EDrawPolygonDrawMode::RoundedRectangle
2019-11-01 20:48:07 -04:00
{
2021-10-20 20:41:00 -04:00
Polygon = FPolygon2d : : MakeRoundedRectangle ( FVector2d ( Width / 2 , YSign * Height / 2 ) , Width , Height , FMathd : : Min ( Width , Height ) * FMathd : : Clamp ( PolygonProperties - > FeatureSizeRatio , .01 , .99 ) * .5 , PolygonProperties - > RadialSlices ) ;
2019-11-01 20:48:07 -04:00
}
2019-10-01 20:41:42 -04:00
}
2021-10-20 20:41:00 -04:00
else // Circle or Ring
2019-10-01 20:41:42 -04:00
{
2021-10-20 20:41:00 -04:00
Polygon = FPolygon2d : : MakeCircle ( Width , PolygonProperties - > RadialSlices , 0 ) ;
if ( PolygonProperties - > PolygonDrawMode = = EDrawPolygonDrawMode : : Ring )
2019-11-01 20:48:07 -04:00
{
2021-10-20 20:41:00 -04:00
PolygonHoles . Add ( FPolygon2d : : MakeCircle ( Width * FMathd : : Clamp ( PolygonProperties - > FeatureSizeRatio , .01 , .99 ) , PolygonProperties - > RadialSlices , 0 ) ) ;
2019-11-01 20:48:07 -04:00
}
2019-10-01 20:41:42 -04:00
}
2020-03-31 18:31:32 -04:00
Polygon . Transform ( [ RotationMat ] ( const FVector2d & Pt ) { return RotationMat * Pt ; } ) ;
for ( FPolygon2d & Hole : PolygonHoles )
2019-11-01 20:48:07 -04:00
{
2020-03-31 18:31:32 -04:00
Hole . Transform ( [ RotationMat ] ( const FVector2d & Pt ) { return RotationMat * Pt ; } ) ;
2019-11-01 20:48:07 -04:00
}
2019-10-01 20:41:42 -04:00
2022-11-16 11:40:11 -05:00
const FFrame3d & DrawFrame = PlaneMechanic - > Plane ;
2019-11-01 20:48:07 -04:00
VerticesOut . SetNum ( Polygon . VertexCount ( ) ) ;
2019-10-01 20:41:42 -04:00
for ( int k = 0 ; k < Polygon . VertexCount ( ) ; + + k )
{
2020-03-31 18:31:32 -04:00
FVector2d NewPt = FirstReferencePt + Polygon [ k ] ;
VerticesOut [ k ] = DrawFrame . FromPlaneUV ( NewPt , 2 ) ;
2019-11-01 20:48:07 -04:00
}
HolesVerticesOut . SetNum ( PolygonHoles . Num ( ) ) ;
for ( int HoleIdx = 0 ; HoleIdx < PolygonHoles . Num ( ) ; HoleIdx + + )
{
int NumHoleVerts = PolygonHoles [ HoleIdx ] . VertexCount ( ) ;
HolesVerticesOut [ HoleIdx ] . SetNum ( NumHoleVerts ) ;
for ( int k = 0 ; k < NumHoleVerts ; + + k )
{
2020-03-31 18:31:32 -04:00
FVector2d NewPt = FirstReferencePt + PolygonHoles [ HoleIdx ] [ k ] ;
HolesVerticesOut [ HoleIdx ] [ k ] = DrawFrame . FromPlaneUV ( NewPt , 2 ) ;
2019-11-01 20:48:07 -04:00
}
2019-10-01 20:41:42 -04:00
}
}
2020-01-27 20:11:15 -05:00
2019-10-01 20:41:42 -04:00
void UDrawPolygonTool : : BeginInteractiveExtrude ( )
{
bInInteractiveExtrude = true ;
2021-11-23 10:39:20 -05:00
bHasSavedExtrudeHeight = true ;
SavedExtrudeHeight = PolygonProperties - > ExtrudeHeight ;
2020-09-24 00:43:27 -04:00
SnapEngine . ResetActiveSnap ( ) ;
2019-10-01 20:41:42 -04:00
2020-01-27 20:11:15 -05:00
HeightMechanic = NewObject < UPlaneDistanceFromHitMechanic > ( this ) ;
HeightMechanic - > Setup ( this ) ;
HeightMechanic - > WorldHitQueryFunc = [ this ] ( const FRay & WorldRay , FHitResult & HitResult )
{
2020-10-22 19:19:16 -04:00
if ( this - > bIgnoreSnappingToggle = = false )
{
2021-12-09 14:46:09 -05:00
return ToolSceneQueriesUtil : : FindNearestVisibleObjectHit ( this , HitResult , WorldRay ) ;
2020-10-22 19:19:16 -04:00
}
return false ;
2020-01-27 20:11:15 -05:00
} ;
HeightMechanic - > WorldPointSnapFunc = [ this ] ( const FVector3d & WorldPos , FVector3d & SnapPos )
{
2022-01-11 12:12:12 -05:00
if ( bIgnoreSnappingToggle = = false & & SnapProperties - > bEnableSnapping )
2020-01-27 20:11:15 -05:00
{
return ToolSceneQueriesUtil : : FindWorldGridSnapPoint ( this , WorldPos , SnapPos ) ;
}
return false ;
} ;
HeightMechanic - > CurrentHeight = 1.0f ; // initialize to something non-zero...prob should be based on polygon bounds maybe?
FDynamicMesh3 HeightMesh ;
2020-03-31 18:31:32 -04:00
FFrame3d WorldMeshFrame ;
GeneratePolygonMesh ( PolygonVertices , PolygonHolesVertices , & HeightMesh , WorldMeshFrame , false , 99999 , true ) ;
HeightMechanic - > Initialize ( MoveTemp ( HeightMesh ) , WorldMeshFrame , false ) ;
2019-10-01 20:41:42 -04:00
ShowExtrudeMessage ( ) ;
}
void UDrawPolygonTool : : EndInteractiveExtrude ( )
{
EmitCurrentPolygon ( ) ;
PreviewMesh - > ClearPreview ( ) ;
PreviewMesh - > SetVisible ( false ) ;
bInInteractiveExtrude = false ;
2020-01-27 20:11:15 -05:00
HeightMechanic = nullptr ;
2019-10-01 20:41:42 -04:00
ShowStartupMessage ( ) ;
}
2021-11-07 23:43:01 -05:00
bool UDrawPolygonTool : : AllowDrawPlaneUpdates ( )
{
if ( bInInteractiveExtrude )
{
return false ;
}
if ( bInFixedPolygonMode )
{
return FixedPolygonClickPoints . IsEmpty ( ) ;
}
else
{
return PolygonVertices . IsEmpty ( ) ;
}
}
2019-10-01 20:41:42 -04:00
void UDrawPolygonTool : : EmitCurrentPolygon ( )
{
2021-10-21 17:57:49 -04:00
FString BaseName = ( PolygonProperties - > ExtrudeMode = = EDrawPolygonExtrudeMode : : Flat ) ?
2019-10-01 20:41:42 -04:00
TEXT ( " Polygon " ) : TEXT ( " Extrude " ) ;
// generate new mesh
FFrame3d PlaneFrameOut ;
FDynamicMesh3 Mesh ;
2021-10-21 17:57:49 -04:00
const double ExtrudeDist = ( PolygonProperties - > ExtrudeMode = = EDrawPolygonExtrudeMode : : Flat ) ?
2019-10-01 20:41:42 -04:00
0 : PolygonProperties - > ExtrudeHeight ;
2019-11-06 14:33:56 -05:00
bool bSucceeded = GeneratePolygonMesh ( PolygonVertices , PolygonHolesVertices , & Mesh , PlaneFrameOut , false , ExtrudeDist , false ) ;
if ( ! bSucceeded ) // somehow made a polygon with no valid triangulation; just throw it away ...
{
ResetPolygon ( ) ;
return ;
}
2022-08-25 11:51:02 -04:00
UE : : Geometry : : FMeshTangentsf : : ComputeDefaultOverlayTangents ( Mesh ) ;
2019-10-01 20:41:42 -04:00
GetToolManager ( ) - > BeginUndoTransaction ( LOCTEXT ( " CreatePolygon " , " Create Polygon " ) ) ;
2021-06-02 15:58:00 -04:00
FCreateMeshObjectParams NewMeshObjectParams ;
NewMeshObjectParams . TargetWorld = TargetWorld ;
NewMeshObjectParams . Transform = PlaneFrameOut . ToFTransform ( ) ;
NewMeshObjectParams . BaseName = BaseName ;
NewMeshObjectParams . Materials . Add ( MaterialProperties - > Material . Get ( ) ) ;
NewMeshObjectParams . SetMesh ( & Mesh ) ;
ModelingTools: add support for creating Volumes directly from DrawPolygon, DrawRevolve, DrawPolyPath, and AddPrimitive, CombineMeshes, CutMeshWithMesh, PlaneCut, BaseCreateFromSelected Tools. Improve support for Editing volumes, eg handling mesh/volume interactions, and add configurable auto-simplification for volumes to avoid painful Editor hangs.
- Move ToolTarget implementations, DynamicMeshToVolume to ModelingComponentsEditorOnly module
- move VolumeToDynamicMesh, DynamicMeshProvider/Commiter interfaces to ModelingComponents module
- Add UCreateMeshObjectTypeProperties property set to expose mesh/volume options
- Add FCreateMeshObjectParams::TypeHintClass to allow AVolume type (or other UClass hints) to be passed to creation APIs
- Add UE::ToolTarget::ConfigureCreateMeshObjectParams() util function in ModelingToolTargetUtil, tries to determine output type in a FCreateMeshObjectParams based on input ToolTarget
- Add UEditorModelingObjectsCreationAPI::CreateVolume() implementation
- Add UEditorModelingObjectsCreationAPI::FilterMaterials() that strips out any internal materials and replaces with WorldGridMaterial. This occurs when (eg) subtracting a Volume from a StaticMesh, because the temporary volume mesh gets assigned internal materials, but the Tools don't know this. Use in EditorModelingObjectsCreationAPI when creating new objects. UStaticMeshComponentToolTarget also does this filtering in ::CommitMaterialSetUpdate().
- Add ::ComponentTypeSupportsCollision() function to ComponentCollisionUtil, use to avoid checks/ensures for Volume targets
- Add support for automatic mesh simplification in DynamicMeshToVolume. Add CVar to VolumeDynamicMeshToolTarget.h to control max triangle count (default 500). Apply auto-simplify when creating or updating an AVolume. This prevents the Editor from blocking for long periods on meshes that are too high-res for volumes (even 500 is quite high).
- DynamicMeshToVolume now emits polygroup-faces that contain holes (ie multiple boundary loops) as a set of triangles, rather than emitting separate overlapping faces for each boundary loop
#rb none
#rnx
#jira none
#preflight 60ba50632c42ea0001cb54c5
[CL 16561742 by Ryan Schmidt in ue5-main branch]
2021-06-04 16:04:03 -04:00
OutputTypeProperties - > ConfigureCreateMeshObjectParams ( NewMeshObjectParams ) ;
2021-06-02 15:58:00 -04:00
FCreateMeshObjectResult Result = UE : : Modeling : : CreateMeshObject ( GetToolManager ( ) , MoveTemp ( NewMeshObjectParams ) ) ;
if ( Result . IsOK ( ) & & Result . NewActor ! = nullptr )
2020-01-27 20:11:15 -05:00
{
2021-06-02 15:58:00 -04:00
ToolSelectionUtil : : SetNewActorSelection ( GetToolManager ( ) , Result . NewActor ) ;
2020-01-27 20:11:15 -05:00
}
2019-10-01 20:41:42 -04:00
GetToolManager ( ) - > EndUndoTransaction ( ) ;
2021-06-02 15:58:00 -04:00
2021-11-23 10:39:20 -05:00
if ( bHasSavedExtrudeHeight )
{
PolygonProperties - > ExtrudeHeight = SavedExtrudeHeight ;
bHasSavedExtrudeHeight = false ;
}
2019-10-01 20:41:42 -04:00
ResetPolygon ( ) ;
}
void UDrawPolygonTool : : UpdateLivePreview ( )
{
int NumVerts = PolygonVertices . Num ( ) ;
2019-11-06 14:33:56 -05:00
if ( NumVerts < 2 | | PreviewMesh = = nullptr | | PreviewMesh - > IsVisible ( ) = = false )
2019-10-01 20:41:42 -04:00
{
return ;
}
FFrame3d PlaneFrame ;
FDynamicMesh3 Mesh ;
2021-10-21 17:57:49 -04:00
const double ExtrudeDist = ( PolygonProperties - > ExtrudeMode = = EDrawPolygonExtrudeMode : : Flat ) ?
2019-10-01 20:41:42 -04:00
0 : PolygonProperties - > ExtrudeHeight ;
2019-11-06 14:33:56 -05:00
if ( GeneratePolygonMesh ( PolygonVertices , PolygonHolesVertices , & Mesh , PlaneFrame , false , ExtrudeDist , false ) )
{
PreviewMesh - > SetTransform ( PlaneFrame . ToFTransform ( ) ) ;
2020-10-09 22:42:26 -04:00
PreviewMesh - > SetMaterial ( MaterialProperties - > Material . Get ( ) ) ;
2021-10-18 14:21:53 -04:00
PreviewMesh - > EnableWireframe ( MaterialProperties - > bShowWireframe ) ;
2019-11-06 14:33:56 -05:00
PreviewMesh - > UpdatePreview ( & Mesh ) ;
}
2019-10-01 20:41:42 -04:00
}
2020-03-31 18:31:32 -04:00
bool UDrawPolygonTool : : GeneratePolygonMesh ( const TArray < FVector3d > & Polygon , const TArray < TArray < FVector3d > > & PolygonHoles , FDynamicMesh3 * ResultMeshOut , FFrame3d & WorldFrameOut , bool bIncludePreviewVtx , double ExtrudeDistance , bool bExtrudeSymmetric )
2019-10-01 20:41:42 -04:00
{
// construct centered frame for polygon
2022-11-16 11:40:11 -05:00
WorldFrameOut = PlaneMechanic - > Plane ;
2019-10-01 20:41:42 -04:00
int NumVerts = Polygon . Num ( ) ;
2020-03-31 18:31:32 -04:00
FVector3d Centroid3d ( 0 , 0 , 0 ) ;
2019-10-01 20:41:42 -04:00
for ( int k = 0 ; k < NumVerts ; + + k )
{
2020-03-31 18:31:32 -04:00
Centroid3d + = Polygon [ k ] ;
2019-10-01 20:41:42 -04:00
}
2020-03-31 18:31:32 -04:00
Centroid3d / = ( double ) NumVerts ;
FVector2d CentroidInDrawPlane = WorldFrameOut . ToPlaneUV ( Centroid3d ) ;
WorldFrameOut . Origin = Centroid3d ;
2019-10-01 20:41:42 -04:00
2019-11-06 20:53:34 -05:00
// Compute outer polygon & bounds
2020-03-31 18:31:32 -04:00
auto VertexArrayToPolygon = [ & WorldFrameOut ] ( const TArray < FVector3d > & Vertices )
2019-10-01 20:41:42 -04:00
{
2019-11-01 20:48:07 -04:00
FPolygon2d OutPolygon ;
for ( int k = 0 , N = Vertices . Num ( ) ; k < N ; + + k )
{
OutPolygon . AppendVertex ( WorldFrameOut . ToPlaneUV ( Vertices [ k ] , 2 ) ) ;
}
return OutPolygon ;
} ;
FPolygon2d OuterPolygon = VertexArrayToPolygon ( Polygon ) ;
2019-10-01 20:41:42 -04:00
// add preview vertex
if ( bIncludePreviewVtx )
{
2021-03-30 21:25:22 -04:00
if ( Distance ( PreviewVertex , Polygon [ NumVerts - 1 ] ) > 0.1 )
2019-10-01 20:41:42 -04:00
{
2019-11-01 20:48:07 -04:00
OuterPolygon . AppendVertex ( WorldFrameOut . ToPlaneUV ( PreviewVertex , 2 ) ) ;
2019-10-01 20:41:42 -04:00
}
}
2019-11-06 20:53:34 -05:00
FAxisAlignedBox2d Bounds ( OuterPolygon . Bounds ( ) ) ;
2019-10-01 20:41:42 -04:00
2019-11-06 20:53:34 -05:00
// special case paths
2021-10-20 20:41:00 -04:00
if ( PolygonProperties - > PolygonDrawMode = = EDrawPolygonDrawMode : : Ring | | PolygonProperties - > PolygonDrawMode = = EDrawPolygonDrawMode : : Circle | | PolygonProperties - > PolygonDrawMode = = EDrawPolygonDrawMode : : RoundedRectangle )
2019-10-01 20:41:42 -04:00
{
2019-11-06 20:53:34 -05:00
// get polygon parameters
2020-03-31 18:31:32 -04:00
FVector2d FirstReferencePt , BoxSize ;
double YSign , AngleRad ;
2019-11-06 20:53:34 -05:00
GetPolygonParametersFromFixedPoints ( FixedPolygonClickPoints , FirstReferencePt , BoxSize , YSign , AngleRad ) ;
2020-03-31 18:31:32 -04:00
FirstReferencePt - = CentroidInDrawPlane ;
FMatrix2d RotationMat = FMatrix2d : : RotationRad ( AngleRad ) ;
2019-10-01 20:41:42 -04:00
2019-11-06 20:53:34 -05:00
// translate general polygon parameters to specific mesh generator parameters, and generate mesh
2021-10-20 20:41:00 -04:00
if ( PolygonProperties - > PolygonDrawMode = = EDrawPolygonDrawMode : : Ring )
2019-11-06 14:33:56 -05:00
{
2019-11-06 20:53:34 -05:00
FPuncturedDiscMeshGenerator HCGen ;
2021-10-20 20:41:00 -04:00
HCGen . AngleSamples = PolygonProperties - > RadialSlices ;
2019-11-06 20:53:34 -05:00
HCGen . RadialSamples = 1 ;
HCGen . Radius = BoxSize . X ;
2020-03-31 18:31:32 -04:00
HCGen . HoleRadius = BoxSize . X * FMathd : : Clamp ( PolygonProperties - > FeatureSizeRatio , .01f , .99f ) ;
2019-11-06 20:53:34 -05:00
ResultMeshOut - > Copy ( & HCGen . Generate ( ) ) ;
2019-11-06 14:33:56 -05:00
}
2021-10-20 20:41:00 -04:00
else if ( PolygonProperties - > PolygonDrawMode = = EDrawPolygonDrawMode : : Circle )
2019-11-06 14:33:56 -05:00
{
2019-11-06 20:53:34 -05:00
FDiscMeshGenerator CGen ;
2021-10-20 20:41:00 -04:00
CGen . AngleSamples = PolygonProperties - > RadialSlices ;
2019-11-06 20:53:34 -05:00
CGen . RadialSamples = 1 ;
CGen . Radius = BoxSize . X ;
ResultMeshOut - > Copy ( & CGen . Generate ( ) ) ;
}
2021-10-20 20:41:00 -04:00
else if ( PolygonProperties - > PolygonDrawMode = = EDrawPolygonDrawMode : : RoundedRectangle )
2019-11-06 20:53:34 -05:00
{
FRoundedRectangleMeshGenerator RRGen ;
2020-03-31 18:31:32 -04:00
FirstReferencePt + = RotationMat * ( FVector2d ( BoxSize . X , BoxSize . Y * YSign ) * .5f ) ;
2021-10-20 20:41:00 -04:00
RRGen . AngleSamples = PolygonProperties - > RadialSlices ;
2020-03-31 18:31:32 -04:00
RRGen . Radius = .5 * FMathd : : Min ( BoxSize . X , BoxSize . Y ) * FMathd : : Clamp ( PolygonProperties - > FeatureSizeRatio , .01f , .99f ) ;
2019-11-06 20:53:34 -05:00
RRGen . Height = BoxSize . Y - RRGen . Radius * 2. ;
RRGen . Width = BoxSize . X - RRGen . Radius * 2. ;
RRGen . WidthVertexCount = 1 ;
RRGen . HeightVertexCount = 1 ;
ResultMeshOut - > Copy ( & RRGen . Generate ( ) ) ;
}
// transform generated mesh
for ( int VertIdx : ResultMeshOut - > VertexIndicesItr ( ) )
{
FVector3d V = ResultMeshOut - > GetVertex ( VertIdx ) ;
2020-03-31 18:31:32 -04:00
FVector2d VTransformed = RotationMat * FVector2d ( V . X , V . Y ) + FirstReferencePt ;
2019-11-06 20:53:34 -05:00
ResultMeshOut - > SetVertex ( VertIdx , FVector3d ( VTransformed . X , VTransformed . Y , 0 ) ) ;
2019-11-06 14:33:56 -05:00
}
}
2019-11-06 20:53:34 -05:00
else // generic path: triangulate using polygon vertices
2019-11-06 14:33:56 -05:00
{
2019-11-06 20:53:34 -05:00
// triangulate polygon into the MeshDescription
FGeneralPolygon2d GeneralPolygon ;
FFlatTriangulationMeshGenerator TriangulationMeshGen ;
if ( OuterPolygon . IsClockwise ( ) = = false )
{
OuterPolygon . Reverse ( ) ;
}
GeneralPolygon . SetOuter ( OuterPolygon ) ;
for ( int HoleIdx = 0 ; HoleIdx < PolygonHoles . Num ( ) ; HoleIdx + + )
{
// attempt to add holes (skipping if safety checks fail)
GeneralPolygon . AddHole ( VertexArrayToPolygon ( PolygonHoles [ HoleIdx ] ) , true , false /*currently don't care about hole orientation; we'll just set the triangulation algo not to care*/ ) ;
}
FConstrainedDelaunay2d Triangulator ;
if ( PolygonProperties - > bAllowSelfIntersections )
{
FArrangement2d Arrangement ( OuterPolygon . Bounds ( ) ) ;
// arrangement2d builds a general 2d graph that discards orientation info ...
Triangulator . FillRule = FConstrainedDelaunay2d : : EFillRule : : Odd ;
Triangulator . bOrientedEdges = false ;
Triangulator . bSplitBowties = true ;
for ( FSegment2d Seg : GeneralPolygon . GetOuter ( ) . Segments ( ) )
{
Arrangement . Insert ( Seg ) ;
}
Triangulator . Add ( Arrangement . Graph ) ;
for ( const FPolygon2d & Hole : GeneralPolygon . GetHoles ( ) )
{
Triangulator . Add ( Hole , true ) ;
}
}
else
{
Triangulator . Add ( GeneralPolygon ) ;
}
2021-10-20 20:41:00 -04:00
Triangulator . Triangulate ( [ & GeneralPolygon ] ( const TArray < FVector2d > & Vertices , FIndex3i Tri )
2020-01-27 20:11:15 -05:00
{
// keep triangles based on the input polygon's winding
return GeneralPolygon . Contains ( ( Vertices [ Tri . A ] + Vertices [ Tri . B ] + Vertices [ Tri . C ] ) / 3.0 ) ;
} ) ;
2019-11-06 20:53:34 -05:00
// only truly fail if we got zero triangles back from the triangulator; if it just returned false it may still have managed to partially generate something
if ( Triangulator . Triangles . Num ( ) = = 0 )
{
return false ;
}
TriangulationMeshGen . Vertices2D = Triangulator . Vertices ;
TriangulationMeshGen . Triangles2D = Triangulator . Triangles ;
ResultMeshOut - > Copy ( & TriangulationMeshGen . Generate ( ) ) ;
2019-11-06 14:33:56 -05:00
}
2019-10-01 20:41:42 -04:00
// for symmetric extrude we translate the first poly by -dist along axis
if ( bExtrudeSymmetric )
{
FVector3d ShiftNormal = FVector3d : : UnitZ ( ) ;
for ( int vid : ResultMeshOut - > VertexIndicesItr ( ) )
{
FVector3d Pos = ResultMeshOut - > GetVertex ( vid ) ;
ResultMeshOut - > SetVertex ( vid , Pos - ExtrudeDistance * ShiftNormal ) ;
}
// double extrude dist
ExtrudeDistance * = 2.0 ;
}
if ( ExtrudeDistance ! = 0 )
{
FExtrudeMesh Extruder ( ResultMeshOut ) ;
Extruder . DefaultExtrudeDistance = ExtrudeDistance ;
2019-11-06 20:53:34 -05:00
Extruder . UVScaleFactor = 1.0 / Bounds . MaxDim ( ) ;
2019-10-01 20:41:42 -04:00
if ( ExtrudeDistance < 0 )
{
Extruder . IsPositiveOffset = false ;
}
FVector3d ExtrudeNormal = FVector3d : : UnitZ ( ) ;
Extruder . ExtrudedPositionFunc = [ & ExtrudeDistance , & ExtrudeNormal ] ( const FVector3d & Position , const FVector3f & Normal , int VertexID )
{
2022-02-14 18:32:46 -05:00
return Position + ExtrudeDistance * ( FVector3d ) ExtrudeNormal ;
2019-10-01 20:41:42 -04:00
} ;
Extruder . Apply ( ) ;
}
FDynamicMeshEditor Editor ( ResultMeshOut ) ;
2019-11-06 20:53:34 -05:00
float InitialUVScale = 1.0 / Bounds . MaxDim ( ) ; // this is the UV scale used by both the polymeshgen and the extruder above
2019-10-01 20:41:42 -04:00
// default global rescale -- initial scale doesn't factor in extrude distance; rescale so UVScale of 1.0 fits in the unit square texture
2021-01-19 18:41:21 -04:00
float GlobalUVRescale = MaterialProperties - > UVScale / FMathf : : Max ( 1.0f , FMathd : : Abs ( ExtrudeDistance ) * InitialUVScale ) ;
2019-10-01 20:41:42 -04:00
if ( MaterialProperties - > bWorldSpaceUVScale )
{
// since we know the initial uv scale, directly compute the global scale (relative to 1 meter as a standard scale)
GlobalUVRescale = MaterialProperties - > UVScale * .01 / InitialUVScale ;
}
Editor . RescaleAttributeUVs ( GlobalUVRescale , false ) ;
2019-11-06 14:33:56 -05:00
return true ;
2019-10-01 20:41:42 -04:00
}
void UDrawPolygonTool : : ShowStartupMessage ( )
{
GetToolManager ( ) - > DisplayMessage (
2022-01-28 10:35:32 -05:00
LOCTEXT ( " OnStartDraw " , " Draw a polygon on the drawing plane, and extrude it. Left-click to place polygon vertices. Hold Shift to ignore snapping while drawing. " ) ,
2019-10-01 20:41:42 -04:00
EToolMessageLevel : : UserNotification ) ;
}
void UDrawPolygonTool : : ShowExtrudeMessage ( )
{
GetToolManager ( ) - > DisplayMessage (
2021-10-21 17:57:49 -04:00
LOCTEXT ( " OnStartExtrude " , " Set the height of the extrusion by positioning the mouse over the extrusion volume, or over objects to snap to their heights. Hold Shift to ignore snapping. " ) ,
2019-10-01 20:41:42 -04:00
EToolMessageLevel : : UserNotification ) ;
}
2020-03-06 14:44:21 -05:00
2020-10-09 22:42:26 -04:00
void UDrawPolygonTool : : UndoCurrentOperation ( const TArray < FVector3d > & ClickPointsIn , const TArray < FVector3d > & PolygonVerticesIn )
2020-03-06 14:44:21 -05:00
{
if ( bInInteractiveExtrude )
{
PreviewMesh - > ClearPreview ( ) ;
PreviewMesh - > SetVisible ( false ) ;
bInInteractiveExtrude = false ;
}
2020-10-09 22:42:26 -04:00
ApplyUndoPoints ( ClickPointsIn , PolygonVerticesIn ) ;
2020-03-06 14:44:21 -05:00
}
void FDrawPolygonStateChange : : Revert ( UObject * Object )
{
2020-10-09 22:42:26 -04:00
Cast < UDrawPolygonTool > ( Object ) - > UndoCurrentOperation ( FixedVertexPoints , PolyPoints ) ;
2020-03-06 14:44:21 -05:00
bHaveDoneUndo = true ;
}
bool FDrawPolygonStateChange : : HasExpired ( UObject * Object ) const
{
return bHaveDoneUndo | | ( Cast < UDrawPolygonTool > ( Object ) - > CheckInCurve ( CurveTimestamp ) = = false ) ;
}
FString FDrawPolygonStateChange : : ToString ( ) const
{
return TEXT ( " FDrawPolygonStateChange " ) ;
}
2019-10-01 20:41:42 -04:00
# undef LOCTEXT_NAMESPACE
2022-09-28 01:06:15 -04:00