2020-04-18 18:42:59 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "CSGMeshesTool.h"
2021-10-29 22:42:08 -04:00
# include "MeshDescriptionToDynamicMesh.h"
2020-04-18 18:42:59 -04:00
# include "ToolSetupUtil.h"
2021-11-23 09:42:40 -05:00
# include "ModelingToolTargetUtil.h"
2021-05-20 16:39:39 -04:00
# include "BaseGizmos/TransformProxy.h"
2021-10-29 22:42:08 -04:00
# include "CompositionOps/BooleanMeshesOp.h"
2021-06-13 00:36:02 -04:00
# include "DynamicMesh/DynamicMesh3.h"
2020-04-18 18:42:59 -04:00
2021-11-23 09:42:40 -05:00
# include "TargetInterfaces/MeshDescriptionProvider.h"
# include "TargetInterfaces/PrimitiveComponentBackedTarget.h"
2021-03-09 19:33:56 -04:00
using namespace UE : : Geometry ;
2020-04-18 18:42:59 -04:00
# define LOCTEXT_NAMESPACE "UCSGMeshesTool"
2021-10-29 22:42:08 -04:00
2020-12-02 15:36:50 -04:00
void UCSGMeshesTool : : EnableTrimMode ( )
{
check ( OriginalDynamicMeshes . Num ( ) = = 0 ) ; // must not have been initialized!
bTrimMode = true ;
}
2020-04-18 18:42:59 -04:00
2020-08-11 01:36:57 -04:00
void UCSGMeshesTool : : SetupProperties ( )
2020-04-18 18:42:59 -04:00
{
2020-08-11 01:36:57 -04:00
Super : : SetupProperties ( ) ;
2020-04-18 18:42:59 -04:00
2020-12-02 15:36:50 -04:00
if ( bTrimMode )
{
TrimProperties = NewObject < UTrimMeshesToolProperties > ( this ) ;
TrimProperties - > RestoreProperties ( this ) ;
AddToolPropertySource ( TrimProperties ) ;
2020-09-24 00:43:27 -04:00
2021-03-09 21:27:22 -04:00
TrimProperties - > WatchProperty ( TrimProperties - > WhichMesh , [ this ] ( ETrimOperation )
{
UpdateGizmoVisibility ( ) ;
UpdatePreviewsVisibility ( ) ;
} ) ;
TrimProperties - > WatchProperty ( TrimProperties - > bShowTrimmingMesh , [ this ] ( bool )
{
UpdatePreviewsVisibility ( ) ;
} ) ;
2021-03-18 20:23:14 -04:00
TrimProperties - > WatchProperty ( TrimProperties - > ColorOfTrimmingMesh , [ this ] ( FLinearColor )
{
UpdatePreviewsMaterial ( ) ;
} ) ;
TrimProperties - > WatchProperty ( TrimProperties - > OpacityOfTrimmingMesh , [ this ] ( float )
{
UpdatePreviewsMaterial ( ) ;
} ) ;
2021-03-09 21:27:22 -04:00
2021-02-08 17:02:09 -04:00
SetToolDisplayName ( LOCTEXT ( " TrimMeshesToolName " , " Trim " ) ) ;
2020-12-02 15:36:50 -04:00
GetToolManager ( ) - > DisplayMessage (
LOCTEXT ( " OnStartTrimTool " , " Trim one mesh with another. Use the transform gizmos to tweak the positions of the input objects (can help to resolve errors/failures) " ) ,
EToolMessageLevel : : UserNotification ) ;
}
else
{
CSGProperties = NewObject < UCSGMeshesToolProperties > ( this ) ;
CSGProperties - > RestoreProperties ( this ) ;
AddToolPropertySource ( CSGProperties ) ;
2021-03-09 21:27:22 -04:00
CSGProperties - > WatchProperty ( CSGProperties - > Operation , [ this ] ( ECSGOperation )
{
UpdateGizmoVisibility ( ) ;
UpdatePreviewsVisibility ( ) ;
} ) ;
CSGProperties - > WatchProperty ( CSGProperties - > bShowSubtractedMesh , [ this ] ( bool )
{
UpdatePreviewsVisibility ( ) ;
} ) ;
2021-10-29 22:42:08 -04:00
CSGProperties - > WatchProperty ( CSGProperties - > SubtractedMeshColor , [ this ] ( FLinearColor )
2021-03-18 20:23:14 -04:00
{
UpdatePreviewsMaterial ( ) ;
} ) ;
2021-10-29 22:42:08 -04:00
CSGProperties - > WatchProperty ( CSGProperties - > SubtractedMeshOpacity , [ this ] ( float )
2021-03-18 20:23:14 -04:00
{
UpdatePreviewsMaterial ( ) ;
} ) ;
2021-03-09 21:27:22 -04:00
2021-10-29 22:42:08 -04:00
SetToolDisplayName ( LOCTEXT ( " CSGMeshesToolName " , " Mesh Boolean " ) ) ;
2020-12-02 15:36:50 -04:00
GetToolManager ( ) - > DisplayMessage (
2021-10-29 22:42:08 -04:00
LOCTEXT ( " OnStartTool " , " Perform Boolean operations on the input meshes; any interior faces will be removed. Use the transform gizmos to modify the position and orientation of the input objects. " ) ,
2020-12-02 15:36:50 -04:00
EToolMessageLevel : : UserNotification ) ;
}
2020-08-11 01:36:57 -04:00
}
2020-04-18 18:42:59 -04:00
2021-03-18 20:23:14 -04:00
void UCSGMeshesTool : : UpdatePreviewsMaterial ( )
{
if ( ! PreviewsGhostMaterial )
{
PreviewsGhostMaterial = ToolSetupUtil : : GetSimpleCustomMaterial ( GetToolManager ( ) , FLinearColor : : Black , .2 ) ;
}
FLinearColor Color ;
float Opacity ;
if ( bTrimMode )
{
Color = TrimProperties - > ColorOfTrimmingMesh ;
Opacity = TrimProperties - > OpacityOfTrimmingMesh ;
}
else
{
2021-10-29 22:42:08 -04:00
Color = CSGProperties - > SubtractedMeshColor ;
Opacity = CSGProperties - > SubtractedMeshOpacity ;
2021-03-18 20:23:14 -04:00
}
PreviewsGhostMaterial - > SetVectorParameterValue ( TEXT ( " Color " ) , Color ) ;
PreviewsGhostMaterial - > SetScalarParameterValue ( TEXT ( " Opacity " ) , Opacity ) ;
}
2021-03-09 21:27:22 -04:00
void UCSGMeshesTool : : UpdatePreviewsVisibility ( )
{
int32 ShowPreviewIdx = - 1 ;
if ( bTrimMode & & TrimProperties - > bShowTrimmingMesh )
{
ShowPreviewIdx = TrimProperties - > WhichMesh = = ETrimOperation : : TrimA ? OriginalMeshPreviews . Num ( ) - 1 : 0 ;
}
else if ( ! bTrimMode & & CSGProperties - > bShowSubtractedMesh )
{
if ( CSGProperties - > Operation = = ECSGOperation : : DifferenceAB )
{
ShowPreviewIdx = OriginalMeshPreviews . Num ( ) - 1 ;
}
else if ( CSGProperties - > Operation = = ECSGOperation : : DifferenceBA )
{
ShowPreviewIdx = 0 ;
}
}
for ( int32 MeshIdx = 0 ; MeshIdx < OriginalMeshPreviews . Num ( ) ; MeshIdx + + )
{
OriginalMeshPreviews [ MeshIdx ] - > SetVisible ( ShowPreviewIdx = = MeshIdx ) ;
}
}
int32 UCSGMeshesTool : : GetHiddenGizmoIndex ( ) const
{
int32 ParentHiddenIndex = Super : : GetHiddenGizmoIndex ( ) ;
if ( ParentHiddenIndex ! = - 1 )
{
return ParentHiddenIndex ;
}
if ( bTrimMode )
{
return TrimProperties - > WhichMesh = = ETrimOperation : : TrimA ? 0 : 1 ;
}
else if ( CSGProperties - > Operation = = ECSGOperation : : DifferenceAB )
{
return 0 ;
}
else if ( CSGProperties - > Operation = = ECSGOperation : : DifferenceBA )
{
return 1 ;
}
else
{
return - 1 ;
}
}
2020-08-11 01:36:57 -04:00
void UCSGMeshesTool : : SaveProperties ( )
{
Super : : SaveProperties ( ) ;
2020-12-02 15:36:50 -04:00
if ( bTrimMode )
{
TrimProperties - > SaveProperties ( this ) ;
}
else
{
CSGProperties - > SaveProperties ( this ) ;
}
2020-04-18 18:42:59 -04:00
}
2020-08-11 01:36:57 -04:00
void UCSGMeshesTool : : ConvertInputsAndSetPreviewMaterials ( bool bSetPreviewMesh )
2020-04-18 18:42:59 -04:00
{
2021-03-11 11:40:03 -04:00
OriginalDynamicMeshes . SetNum ( Targets . Num ( ) ) ;
2020-04-18 18:42:59 -04:00
FComponentMaterialSet AllMaterialSet ;
TMap < UMaterialInterface * , int > KnownMaterials ;
2021-03-11 11:40:03 -04:00
TArray < TArray < int > > MaterialRemap ; MaterialRemap . SetNum ( Targets . Num ( ) ) ;
2020-04-22 21:12:20 -04:00
2021-10-29 22:42:08 -04:00
if ( bTrimMode | | ! CSGProperties - > bUseFirstMeshMaterials )
2020-04-18 18:42:59 -04:00
{
2021-03-11 11:40:03 -04:00
for ( int ComponentIdx = 0 ; ComponentIdx < Targets . Num ( ) ; ComponentIdx + + )
2020-04-18 18:42:59 -04:00
{
2021-11-23 09:42:40 -05:00
const FComponentMaterialSet ComponentMaterialSet = UE : : ToolTarget : : GetMaterialSet ( Targets [ ComponentIdx ] ) ;
2020-04-22 21:12:20 -04:00
for ( UMaterialInterface * Mat : ComponentMaterialSet . Materials )
2020-04-18 18:42:59 -04:00
{
2020-04-22 21:12:20 -04:00
int * FoundMatIdx = KnownMaterials . Find ( Mat ) ;
int MatIdx ;
if ( FoundMatIdx )
{
MatIdx = * FoundMatIdx ;
}
else
{
MatIdx = AllMaterialSet . Materials . Add ( Mat ) ;
KnownMaterials . Add ( Mat , MatIdx ) ;
}
MaterialRemap [ ComponentIdx ] . Add ( MatIdx ) ;
2020-04-18 18:42:59 -04:00
}
}
}
2020-04-22 21:12:20 -04:00
else
{
2021-11-23 09:42:40 -05:00
AllMaterialSet = UE : : ToolTarget : : GetMaterialSet ( Targets [ 0 ] ) ;
2020-04-22 21:12:20 -04:00
for ( int MatIdx = 0 ; MatIdx < AllMaterialSet . Materials . Num ( ) ; MatIdx + + )
{
MaterialRemap [ 0 ] . Add ( MatIdx ) ;
}
2021-03-11 11:40:03 -04:00
for ( int ComponentIdx = 1 ; ComponentIdx < Targets . Num ( ) ; ComponentIdx + + )
2020-04-22 21:12:20 -04:00
{
2021-11-23 09:42:40 -05:00
MaterialRemap [ ComponentIdx ] . Init ( 0 , Cast < IMaterialProvider > ( Targets [ ComponentIdx ] ) - > GetNumMaterials ( ) ) ;
2020-04-22 21:12:20 -04:00
}
}
2020-04-18 18:42:59 -04:00
2021-03-18 20:23:14 -04:00
UpdatePreviewsMaterial ( ) ;
2021-03-11 11:40:03 -04:00
for ( int ComponentIdx = 0 ; ComponentIdx < Targets . Num ( ) ; ComponentIdx + + )
2020-04-18 18:42:59 -04:00
{
2021-02-17 11:50:23 -04:00
OriginalDynamicMeshes [ ComponentIdx ] = MakeShared < FDynamicMesh3 , ESPMode : : ThreadSafe > ( ) ;
2020-04-18 18:42:59 -04:00
FMeshDescriptionToDynamicMesh Converter ;
2021-11-23 09:42:40 -05:00
Converter . Convert ( UE : : ToolTarget : : GetMeshDescription ( Targets [ ComponentIdx ] ) , * OriginalDynamicMeshes [ ComponentIdx ] ) ;
2020-04-18 18:42:59 -04:00
// ensure materials and attributes are always enabled
OriginalDynamicMeshes [ ComponentIdx ] - > EnableAttributes ( ) ;
OriginalDynamicMeshes [ ComponentIdx ] - > Attributes ( ) - > EnableMaterialID ( ) ;
FDynamicMeshMaterialAttribute * MaterialIDs = OriginalDynamicMeshes [ ComponentIdx ] - > Attributes ( ) - > GetMaterialID ( ) ;
for ( int TID : OriginalDynamicMeshes [ ComponentIdx ] - > TriangleIndicesItr ( ) )
{
MaterialIDs - > SetValue ( TID , MaterialRemap [ ComponentIdx ] [ MaterialIDs - > GetValue ( TID ) ] ) ;
}
2021-03-09 21:27:22 -04:00
2021-04-15 11:13:12 -04:00
if ( bSetPreviewMesh )
{
UPreviewMesh * OriginalMeshPreview = OriginalMeshPreviews . Add_GetRef ( NewObject < UPreviewMesh > ( ) ) ;
2022-01-28 10:18:10 -05:00
OriginalMeshPreview - > CreateInWorld ( GetTargetWorld ( ) , ( FTransform ) UE : : ToolTarget : : GetLocalToWorldTransform ( Targets [ ComponentIdx ] ) ) ;
2021-04-15 11:13:12 -04:00
OriginalMeshPreview - > UpdatePreview ( OriginalDynamicMeshes [ ComponentIdx ] . Get ( ) ) ;
2021-03-18 20:23:14 -04:00
2021-04-15 11:13:12 -04:00
OriginalMeshPreview - > SetMaterial ( 0 , PreviewsGhostMaterial ) ;
OriginalMeshPreview - > SetVisible ( false ) ;
TransformProxies [ ComponentIdx ] - > AddComponent ( OriginalMeshPreview - > GetRootComponent ( ) ) ;
}
2020-04-18 18:42:59 -04:00
}
2020-04-22 21:12:20 -04:00
Preview - > ConfigureMaterials ( AllMaterialSet . Materials , ToolSetupUtil : : GetDefaultWorkingMaterial ( GetToolManager ( ) ) ) ;
}
2020-04-18 18:42:59 -04:00
2020-04-22 21:12:20 -04:00
2020-08-11 01:36:57 -04:00
void UCSGMeshesTool : : SetPreviewCallbacks ( )
{
2020-04-18 18:42:59 -04:00
DrawnLineSet = NewObject < ULineSetComponent > ( Preview - > PreviewMesh - > GetRootComponent ( ) ) ;
DrawnLineSet - > SetupAttachment ( Preview - > PreviewMesh - > GetRootComponent ( ) ) ;
DrawnLineSet - > SetLineMaterial ( ToolSetupUtil : : GetDefaultLineComponentMaterial ( GetToolManager ( ) ) ) ;
DrawnLineSet - > RegisterComponent ( ) ;
Preview - > OnOpCompleted . AddLambda (
[ this ] ( const FDynamicMeshOperator * Op )
{
const FBooleanMeshesOp * BooleanOp = ( const FBooleanMeshesOp * ) ( Op ) ;
CreatedBoundaryEdges = BooleanOp - > GetCreatedBoundaryEdges ( ) ;
}
) ;
Preview - > OnMeshUpdated . AddLambda (
[ this ] ( const UMeshOpPreviewWithBackgroundCompute * )
{
GetToolManager ( ) - > PostInvalidation ( ) ;
UpdateVisualization ( ) ;
}
) ;
}
2020-08-11 01:36:57 -04:00
2020-04-18 18:42:59 -04:00
void UCSGMeshesTool : : UpdateVisualization ( )
{
FColor BoundaryEdgeColor ( 240 , 15 , 15 ) ;
float BoundaryEdgeThickness = 2.0 ;
float BoundaryEdgeDepthBias = 2.0f ;
const FDynamicMesh3 * TargetMesh = Preview - > PreviewMesh - > GetPreviewDynamicMesh ( ) ;
FVector3d A , B ;
DrawnLineSet - > Clear ( ) ;
2021-10-29 22:42:08 -04:00
if ( ! bTrimMode & & CSGProperties - > bShowNewBoundaries )
2020-04-18 18:42:59 -04:00
{
for ( int EID : CreatedBoundaryEdges )
{
TargetMesh - > GetEdgeV ( EID , A , B ) ;
DrawnLineSet - > AddLine ( ( FVector ) A , ( FVector ) B , BoundaryEdgeColor , BoundaryEdgeThickness , BoundaryEdgeDepthBias ) ;
}
}
}
TUniquePtr < FDynamicMeshOperator > UCSGMeshesTool : : MakeNewOperator ( )
{
TUniquePtr < FBooleanMeshesOp > BooleanOp = MakeUnique < FBooleanMeshesOp > ( ) ;
2020-12-02 15:36:50 -04:00
BooleanOp - > bTrimMode = bTrimMode ;
if ( bTrimMode )
{
2021-11-18 15:27:14 -05:00
BooleanOp - > WindingThreshold = TrimProperties - > WindingThreshold ;
2020-12-02 15:36:50 -04:00
BooleanOp - > TrimOperation = TrimProperties - > WhichMesh ;
BooleanOp - > TrimSide = TrimProperties - > TrimSide ;
BooleanOp - > bAttemptFixHoles = false ;
2020-12-09 14:18:38 -04:00
BooleanOp - > bTryCollapseExtraEdges = false ;
2020-12-02 15:36:50 -04:00
}
else
{
2021-11-18 15:27:14 -05:00
BooleanOp - > WindingThreshold = CSGProperties - > WindingThreshold ;
2020-12-02 15:36:50 -04:00
BooleanOp - > CSGOperation = CSGProperties - > Operation ;
2021-10-29 22:42:08 -04:00
BooleanOp - > bAttemptFixHoles = CSGProperties - > bTryFixHoles ;
BooleanOp - > bTryCollapseExtraEdges = CSGProperties - > bTryCollapseEdges ;
2020-12-02 15:36:50 -04:00
}
2020-04-18 18:42:59 -04:00
check ( OriginalDynamicMeshes . Num ( ) = = 2 ) ;
2021-03-11 11:40:03 -04:00
check ( Targets . Num ( ) = = 2 ) ;
2020-04-18 18:42:59 -04:00
BooleanOp - > Transforms . SetNum ( 2 ) ;
BooleanOp - > Meshes . SetNum ( 2 ) ;
for ( int Idx = 0 ; Idx < 2 ; Idx + + )
{
BooleanOp - > Meshes [ Idx ] = OriginalDynamicMeshes [ Idx ] ;
2021-02-03 19:00:42 -04:00
BooleanOp - > Transforms [ Idx ] = TransformProxies [ Idx ] - > GetTransform ( ) ;
2020-04-18 18:42:59 -04:00
}
return BooleanOp ;
}
void UCSGMeshesTool : : OnPropertyModified ( UObject * PropertySet , FProperty * Property )
{
2021-10-29 22:42:08 -04:00
if ( Property & & ( Property - > GetFName ( ) = = GET_MEMBER_NAME_CHECKED ( UCSGMeshesToolProperties , bUseFirstMeshMaterials ) ) )
2020-04-22 21:12:20 -04:00
{
2020-11-24 18:42:39 -04:00
if ( ! AreAllTargetsValid ( ) )
{
GetToolManager ( ) - > DisplayMessage ( LOCTEXT ( " InvalidTargets " , " Target meshes are no longer valid " ) , EToolMessageLevel : : UserWarning ) ;
return ;
}
2020-08-11 01:36:57 -04:00
ConvertInputsAndSetPreviewMaterials ( false ) ;
2020-04-22 21:12:20 -04:00
Preview - > InvalidateResult ( ) ;
}
2021-10-29 22:42:08 -04:00
else if ( Property & & ( Property - > GetFName ( ) = = GET_MEMBER_NAME_CHECKED ( UCSGMeshesToolProperties , bShowNewBoundaries ) ) )
2020-04-18 18:42:59 -04:00
{
GetToolManager ( ) - > PostInvalidation ( ) ;
UpdateVisualization ( ) ;
}
else
{
2020-08-11 01:36:57 -04:00
Super : : OnPropertyModified ( PropertySet , Property ) ;
2020-04-18 18:42:59 -04:00
}
}
2020-08-11 01:36:57 -04:00
FString UCSGMeshesTool : : GetCreatedAssetName ( ) const
2020-04-18 18:42:59 -04:00
{
2020-12-02 15:36:50 -04:00
if ( bTrimMode )
{
return TEXT ( " Trim " ) ;
}
else
{
return TEXT ( " Boolean " ) ;
}
2020-04-18 18:42:59 -04:00
}
2020-08-11 01:36:57 -04:00
FText UCSGMeshesTool : : GetActionName ( ) const
2020-04-18 18:42:59 -04:00
{
2020-12-02 15:36:50 -04:00
if ( bTrimMode )
{
2022-02-07 20:07:14 -05:00
return LOCTEXT ( " TrimActionName " , " Trim Meshes " ) ;
2020-12-02 15:36:50 -04:00
}
else
{
2022-02-07 20:07:14 -05:00
return LOCTEXT ( " BooleanActionName " , " Boolean Meshes " ) ;
2020-12-02 15:36:50 -04:00
}
2020-04-18 18:42:59 -04:00
}
2022-01-28 18:40:54 -05:00
void UCSGMeshesTool : : OnShutdown ( EToolShutdownType ShutdownType )
2021-03-09 21:27:22 -04:00
{
2022-01-28 18:40:54 -05:00
Super : : OnShutdown ( ShutdownType ) ;
2020-04-18 18:42:59 -04:00
2021-03-09 21:27:22 -04:00
for ( UPreviewMesh * MeshPreview : OriginalMeshPreviews )
{
MeshPreview - > SetVisible ( false ) ;
MeshPreview - > Disconnect ( ) ;
MeshPreview = nullptr ;
}
}
2020-08-11 01:36:57 -04:00
2020-04-18 18:42:59 -04:00
# undef LOCTEXT_NAMESPACE