Files
UnrealEngineUWP/Engine/Plugins/Runtime/MeshModelingToolset/Source/ModelingComponents/Private/BaseTools/BaseCreateFromSelectedTool.cpp
michael balzer 18526b3ec0 MeshModelingToolset: Cleanup Boolean tool
#rb jimmy.andrews
#preflight 617c9cd80451f40001ed06a7

#ROBOMERGE-AUTHOR: michael.balzer
#ROBOMERGE-SOURCE: CL 17991436 in //UE5/Release-5.0/... via CL 17991437
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v885-17909292)
#ROBOMERGE[STARSHIP]: UE5-Main

[CL 17991438 by michael balzer in ue5-release-engine-test branch]
2021-10-29 22:42:08 -04:00

384 lines
12 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "BaseTools/BaseCreateFromSelectedTool.h"
#include "InteractiveToolManager.h"
#include "ToolBuilderUtil.h"
#include "ToolSetupUtil.h"
#include "BaseGizmos/TransformGizmoUtil.h"
#include "DynamicMesh/MeshNormals.h"
#include "DynamicMesh/MeshTransforms.h"
#include "DynamicMeshToMeshDescription.h"
#include "ModelingObjectsCreationAPI.h"
#include "Selection/ToolSelectionUtil.h"
#include "TargetInterfaces/MeshDescriptionCommitter.h"
#include "TargetInterfaces/MeshDescriptionProvider.h"
#include "TargetInterfaces/PrimitiveComponentBackedTarget.h"
#include "TargetInterfaces/MaterialProvider.h"
#include "TargetInterfaces/AssetBackedTarget.h"
#include "ToolTargetManager.h"
#include "ModelingToolTargetUtil.h"
#define LOCTEXT_NAMESPACE "UBaseCreateFromSelectedTool"
using namespace UE::Geometry;
/*
* ToolBuilder
*/
const FToolTargetTypeRequirements& UBaseCreateFromSelectedToolBuilder::GetTargetRequirements() const
{
static FToolTargetTypeRequirements TypeRequirements({
UMeshDescriptionCommitter::StaticClass(),
UMeshDescriptionProvider::StaticClass(),
UPrimitiveComponentBackedTarget::StaticClass(),
UMaterialProvider::StaticClass()
});
return TypeRequirements;
}
bool UBaseCreateFromSelectedToolBuilder::CanBuildTool(const FToolBuilderState& SceneState) const
{
int32 ComponentCount = SceneState.TargetManager->CountSelectedAndTargetable(SceneState, GetTargetRequirements());
return ComponentCount >= MinComponentsSupported() && (!MaxComponentsSupported().IsSet() || ComponentCount <= MaxComponentsSupported().GetValue());
}
UInteractiveTool* UBaseCreateFromSelectedToolBuilder::BuildTool(const FToolBuilderState& SceneState) const
{
UBaseCreateFromSelectedTool* NewTool = MakeNewToolInstance(SceneState.ToolManager);
TArray<TObjectPtr<UToolTarget>> Targets = SceneState.TargetManager->BuildAllSelectedTargetable(SceneState, GetTargetRequirements());
NewTool->SetTargets(MoveTemp(Targets));
NewTool->SetWorld(SceneState.World);
return NewTool;
}
/*
* Tool
*/
void UBaseCreateFromSelectedTool::Setup()
{
UInteractiveTool::Setup();
// hide input StaticMeshComponents
for (int32 ComponentIdx = 0; ComponentIdx < Targets.Num(); ComponentIdx++)
{
TargetComponentInterface(ComponentIdx)->SetOwnerVisibility(false);
}
// initialize our properties
SetupProperties();
TransformProperties = NewObject<UTransformInputsToolProperties>(this);
TransformProperties->RestoreProperties(this);
AddToolPropertySource(TransformProperties);
OutputTypeProperties = NewObject<UCreateMeshObjectTypeProperties>(this);
OutputTypeProperties->InitializeDefaultWithAuto();
OutputTypeProperties->OutputType = UCreateMeshObjectTypeProperties::AutoIdentifier;
OutputTypeProperties->RestoreProperties(this, TEXT("OutputTypeFromInputTool"));
OutputTypeProperties->WatchProperty(OutputTypeProperties->OutputType, [this](FString) { OutputTypeProperties->UpdatePropertyVisibility(); });
AddToolPropertySource(OutputTypeProperties);
HandleSourcesProperties = NewObject<UBaseCreateFromSelectedHandleSourceProperties>(this);
HandleSourcesProperties->RestoreProperties(this);
AddToolPropertySource(HandleSourcesProperties);
Preview = NewObject<UMeshOpPreviewWithBackgroundCompute>(this);
Preview->Setup(this->TargetWorld, this);
ToolSetupUtil::ApplyRenderingConfigurationToPreview(Preview->PreviewMesh, nullptr);
SetPreviewCallbacks();
Preview->OnMeshUpdated.AddLambda(
[this](const UMeshOpPreviewWithBackgroundCompute* UpdatedPreview)
{
UpdateAcceptWarnings(UpdatedPreview->HaveEmptyResult() ? EAcceptWarning::EmptyForbidden : EAcceptWarning::NoWarning);
}
);
SetTransformGizmos();
ConvertInputsAndSetPreviewMaterials(true);
// output name fields
HandleSourcesProperties->OutputNewName = PrefixWithSourceNameIfSingleSelection(GetCreatedAssetName());
HandleSourcesProperties->WatchProperty(HandleSourcesProperties->OutputWriteTo, [&](EBaseCreateFromSelectedTargetType NewType)
{
SetToolPropertySourceEnabled(OutputTypeProperties, (NewType == EBaseCreateFromSelectedTargetType::NewObject));
if (NewType == EBaseCreateFromSelectedTargetType::NewObject)
{
HandleSourcesProperties->OutputExistingName = TEXT("");
UpdateGizmoVisibility();
}
else
{
int32 Index = (HandleSourcesProperties->OutputWriteTo == EBaseCreateFromSelectedTargetType::FirstInputObject) ? 0 : Targets.Num() - 1;
HandleSourcesProperties->OutputExistingName = UE::Modeling::GetComponentAssetBaseName(TargetComponentInterface(Index)->GetOwnerComponent(), false);
// Reset the hidden gizmo to its initial position
FTransform ComponentTransform = TargetComponentInterface(Index)->GetWorldTransform();
TransformGizmos[Index]->SetNewGizmoTransform(ComponentTransform, true);
UpdateGizmoVisibility();
}
});
Preview->InvalidateResult();
}
int32 UBaseCreateFromSelectedTool::GetHiddenGizmoIndex() const
{
if (HandleSourcesProperties->OutputWriteTo == EBaseCreateFromSelectedTargetType::NewObject)
{
return -1;
}
else
{
return (HandleSourcesProperties->OutputWriteTo == EBaseCreateFromSelectedTargetType::FirstInputObject) ? 0 : Targets.Num() - 1;
}
}
void UBaseCreateFromSelectedTool::SetWorld(UWorld* World)
{
this->TargetWorld = World;
}
void UBaseCreateFromSelectedTool::OnTick(float DeltaTime)
{
Preview->Tick(DeltaTime);
}
void UBaseCreateFromSelectedTool::UpdateGizmoVisibility()
{
for (int32 GizmoIndex = 0; GizmoIndex < TransformGizmos.Num(); GizmoIndex++)
{
UCombinedTransformGizmo* Gizmo = TransformGizmos[GizmoIndex];
Gizmo->SetVisibility(TransformProperties->bShowTransformGizmo && GizmoIndex != GetHiddenGizmoIndex());
}
}
void UBaseCreateFromSelectedTool::SetTransformGizmos()
{
UInteractiveGizmoManager* GizmoManager = GetToolManager()->GetPairedGizmoManager();
for (int ComponentIdx = 0; ComponentIdx < Targets.Num(); ComponentIdx++)
{
UTransformProxy* Proxy = TransformProxies.Add_GetRef(NewObject<UTransformProxy>(this));
UCombinedTransformGizmo* Gizmo = TransformGizmos.Add_GetRef(UE::TransformGizmoUtil::Create3AxisTransformGizmo(GizmoManager, this));
Proxy->SetTransform(TargetComponentInterface(ComponentIdx)->GetWorldTransform());
Gizmo->SetActiveTarget(Proxy, GetToolManager());
Proxy->OnTransformChanged.AddUObject(this, &UBaseCreateFromSelectedTool::TransformChanged);
}
UpdateGizmoVisibility();
}
void UBaseCreateFromSelectedTool::TransformChanged(UTransformProxy* Proxy, FTransform Transform)
{
Preview->InvalidateResult();
}
FText UBaseCreateFromSelectedTool::GetActionName() const
{
return LOCTEXT("BaseCreateFromSelectedTool", "Generated Mesh");
}
TArray<UMaterialInterface*> UBaseCreateFromSelectedTool::GetOutputMaterials() const
{
return Preview->StandardMaterials;
}
void UBaseCreateFromSelectedTool::GenerateAsset(const FDynamicMeshOpResult& OpResult)
{
if (OpResult.Mesh.Get() == nullptr) return;
FTransform3d NewTransform;
if (Targets.Num() == 1) // in the single-selection case, shove the result back into the original component space
{
FTransform3d ToSourceComponentSpace = (FTransform3d)TargetComponentInterface(0)->GetWorldTransform().Inverse();
MeshTransforms::ApplyTransform(*OpResult.Mesh, ToSourceComponentSpace);
NewTransform = (FTransform3d)TargetComponentInterface(0)->GetWorldTransform();
}
else // in the multi-selection case, center the pivot for the combined result
{
FVector3d Center = OpResult.Mesh->GetBounds().Center();
double Rescale = OpResult.Transform.GetScale().X;
FTransform3d LocalTransform(-Center * Rescale);
LocalTransform.SetScale(FVector3d(Rescale, Rescale, Rescale));
MeshTransforms::ApplyTransform(*OpResult.Mesh, LocalTransform);
NewTransform = OpResult.Transform;
NewTransform.SetScale(FVector3d::One());
NewTransform.SetTranslation(NewTransform.GetTranslation() + NewTransform.TransformVector(Center * Rescale));
}
// max len explicitly enforced here, would ideally notify user
FString UseBaseName = HandleSourcesProperties->OutputNewName.Left(250);
if (UseBaseName.IsEmpty())
{
UseBaseName = PrefixWithSourceNameIfSingleSelection(GetCreatedAssetName());
}
FCreateMeshObjectParams NewMeshObjectParams;
NewMeshObjectParams.TargetWorld = TargetWorld;
NewMeshObjectParams.Transform = (FTransform)NewTransform;
NewMeshObjectParams.BaseName = UseBaseName;
NewMeshObjectParams.Materials = GetOutputMaterials();
NewMeshObjectParams.SetMesh(OpResult.Mesh.Get());
if (OutputTypeProperties->OutputType == UCreateMeshObjectTypeProperties::AutoIdentifier)
{
UE::ToolTarget::ConfigureCreateMeshObjectParams(Targets[0], NewMeshObjectParams);
}
else
{
OutputTypeProperties->ConfigureCreateMeshObjectParams(NewMeshObjectParams);
}
FCreateMeshObjectResult Result = UE::Modeling::CreateMeshObject(GetToolManager(), MoveTemp(NewMeshObjectParams));
if (Result.IsOK() && Result.NewActor != nullptr)
{
ToolSelectionUtil::SetNewActorSelection(GetToolManager(), Result.NewActor);
}
}
void UBaseCreateFromSelectedTool::UpdateAsset(const FDynamicMeshOpResult& Result, UToolTarget* UpdateTarget)
{
check(Result.Mesh.Get() != nullptr);
IPrimitiveComponentBackedTarget* TargetComponent = Cast<IPrimitiveComponentBackedTarget>(UpdateTarget);
IMeshDescriptionCommitter* TargetMeshCommitter = Cast<IMeshDescriptionCommitter>(UpdateTarget);
IMaterialProvider* TargetMaterial = Cast<IMaterialProvider>(UpdateTarget);
FTransform3d TargetToWorld = (FTransform3d)TargetComponent->GetWorldTransform();
FTransform3d ResultTransform = Result.Transform;
MeshTransforms::ApplyTransform(*Result.Mesh, ResultTransform);
MeshTransforms::ApplyTransformInverse(*Result.Mesh, TargetToWorld);
TargetMeshCommitter->CommitMeshDescription([&](const IMeshDescriptionCommitter::FCommitterParams& CommitParams)
{
FDynamicMeshToMeshDescription Converter;
Converter.Convert(Result.Mesh.Get(), *CommitParams.MeshDescriptionOut);
});
FComponentMaterialSet MaterialSet;
MaterialSet.Materials = GetOutputMaterials();
TargetMaterial->CommitMaterialSetUpdate(MaterialSet, true);
}
FString UBaseCreateFromSelectedTool::PrefixWithSourceNameIfSingleSelection(const FString& AssetName) const
{
if (Targets.Num() == 1)
{
FString CurName = UE::Modeling::GetComponentAssetBaseName(TargetComponentInterface(0)->GetOwnerComponent());
return FString::Printf(TEXT("%s_%s"), *CurName, *AssetName);
}
else
{
return AssetName;
}
}
void UBaseCreateFromSelectedTool::OnPropertyModified(UObject* PropertySet, FProperty* Property)
{
if (Property && (Property->GetFName() == GET_MEMBER_NAME_CHECKED(UTransformInputsToolProperties, bShowTransformGizmo)))
{
UpdateGizmoVisibility();
}
else if (Property &&
( PropertySet == HandleSourcesProperties
))
{
// nothing
}
else
{
Preview->InvalidateResult();
}
}
void UBaseCreateFromSelectedTool::Shutdown(EToolShutdownType ShutdownType)
{
SaveProperties();
HandleSourcesProperties->SaveProperties(this);
OutputTypeProperties->SaveProperties(this, TEXT("OutputTypeFromInputTool"));
TransformProperties->SaveProperties(this);
FDynamicMeshOpResult Result = Preview->Shutdown();
// Restore (unhide) the source meshes
for (int32 ComponentIdx = 0; ComponentIdx < Targets.Num(); ComponentIdx++)
{
TargetComponentInterface(ComponentIdx)->SetOwnerVisibility(true);
}
if (ShutdownType == EToolShutdownType::Accept)
{
GetToolManager()->BeginUndoTransaction(GetActionName());
// Generate the result
AActor* KeepActor = nullptr;
if (HandleSourcesProperties->OutputWriteTo == EBaseCreateFromSelectedTargetType::NewObject)
{
GenerateAsset(Result);
}
else
{
int32 TargetIndex = (HandleSourcesProperties->OutputWriteTo == EBaseCreateFromSelectedTargetType::FirstInputObject) ? 0 : (Targets.Num() - 1);
KeepActor = TargetComponentInterface(TargetIndex)->GetOwnerActor();
UpdateAsset(Result, Targets[TargetIndex]);
}
TArray<AActor*> Actors;
for (int32 ComponentIdx = 0; ComponentIdx < Targets.Num(); ComponentIdx++)
{
AActor* Actor = TargetComponentInterface(ComponentIdx)->GetOwnerActor();
Actors.Add(Actor);
}
HandleSourcesProperties->ApplyMethod(Actors, GetToolManager(), KeepActor);
if (KeepActor != nullptr)
{
// select the actor we kept
ToolSelectionUtil::SetNewActorSelection(GetToolManager(), KeepActor);
}
GetToolManager()->EndUndoTransaction();
}
UInteractiveGizmoManager* GizmoManager = GetToolManager()->GetPairedGizmoManager();
GizmoManager->DestroyAllGizmosByOwner(this);
}
bool UBaseCreateFromSelectedTool::CanAccept() const
{
return Super::CanAccept() && Preview->HaveValidNonEmptyResult();
}
#undef LOCTEXT_NAMESPACE