You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
This adds a new interface, IISMPartitionInstanceManager, which is the ISM partition actor equivalent of ISMInstanceManager, but works on ISM partition client instances rather than ISMC instances. Internally APartitionActor will forward the underlying ISMC edit request to the appropriate IISMPartitionInstanceManager, if any. An ISM partition client that wants to provide editing support for its instances must either register a manager via APartitionActor::RegisterClientInstanceManager, or a proxy that can provide a manager via APartitionActor::RegisterClientInstanceManagerProvider. If the manager/provider instance registered is a UObject, then that reference will be serialized and loaded again automatically. If the manager/provider is a normal C++ instance, then the client owner must re-register it manually post-load. Unlike ISMC instances, which are always editable unless their owner actor disables it, ISM partition actor instances are only editable if a client registers a manager as described above. This is because only the client has enough knowledge to safely edit its instances. ISM partition actors also required supporting a new editing feature; instance selection groups. This is due to an ISM partition client instance potentially being made up of several ISMC instances that must be treated as a single logical entity for editing. To achieve this we've added an ISMInstanceManager::ForEachSMInstanceInSelectionGroup function that can be overridden by any manager that needs to provide instance grouping, and which is implemented by APartitionActor to group together all the ISMC instances that belong to a given ISM partition client instance. Our proof-of-concept for ISM partition actor instance editing is foliage, available when the CVar "TypedElements.EnableFoliageInstanceElements" is enabled. This takes the proof-of-concept work that was already done for ISMC foliage and moves it to a common implementation that works on FFoliageInfo, which both FFoliageStaticMesh (for ISMC foliage) and FFoliageISMActor (for ISM partition actor foliage) call into from their respective manager interfaces. Misc changes: - AISMPartitionActor::SelectISMInstances no longer dirties the component, as the selection state is transient and not serialized on the component. - Added a PostSerialize and PostLoad function to foliage implementations, to allow fixing up the IFA and other data. - Fixed FFoliageISMActor failing to register its delegates post-load. - Fixed FFoliageISMActor crashing due to FoliageTypeActor being null post-load. - Fixed FFoliageStaticMesh and FFoliageISMActor leaving raw delegates bound post-destruction. - Added the ability for instance managers to override the display name and tooltip used for instances in the details panel. #jira UETOOL-3785 #rb Brooke.Hubert, Patrick.Enfedaque #preflight 61016d790bf6fc0001313bf7 [CL 17057600 by Jamie Dale in ue5-main branch]
598 lines
19 KiB
C++
598 lines
19 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "FoliageISMActor.h"
|
|
#include "InstancedFoliageActor.h"
|
|
#include "FoliageType.h"
|
|
#include "FoliageType_Actor.h"
|
|
#include "FoliageHelper.h"
|
|
#include "Engine/Engine.h"
|
|
#include "Engine/World.h"
|
|
#include "GameFramework/Actor.h"
|
|
#include "Components/StaticMeshComponent.h"
|
|
#include "ISMPartition/ISMComponentDescriptor.h"
|
|
#include "FoliageInstancedStaticMeshComponent.h"
|
|
#include "Elements/Framework/EngineElementsLibrary.h"
|
|
#include "Math/Box.h"
|
|
|
|
FFoliageISMActor::~FFoliageISMActor()
|
|
{
|
|
#if WITH_EDITOR
|
|
UnregisterDelegates();
|
|
#endif
|
|
}
|
|
|
|
void FFoliageISMActor::Serialize(FArchive& Ar)
|
|
{
|
|
#if WITH_EDITORONLY_DATA
|
|
Ar << Guid;
|
|
ClientHandle.Serialize(Ar);
|
|
Ar << ISMDefinition;
|
|
Ar << ActorClass;
|
|
#endif
|
|
}
|
|
|
|
void FFoliageISMActor::PostSerialize(FArchive& Ar)
|
|
{
|
|
FFoliageImpl::PostSerialize(Ar);
|
|
#if WITH_EDITOR
|
|
if (GIsEditor && IsInitialized() && Ar.IsLoading())
|
|
{
|
|
GetIFA()->RegisterClientInstanceManager(ClientHandle, this);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void FFoliageISMActor::PostLoad()
|
|
{
|
|
FFoliageImpl::PostLoad();
|
|
#if WITH_EDITOR
|
|
if (GIsEditor && IsInitialized())
|
|
{
|
|
RegisterDelegates();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
void FFoliageISMActor::AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector)
|
|
{
|
|
Collector.AddReferencedObject(ActorClass, InThis);
|
|
}
|
|
|
|
bool FFoliageISMActor::IsInitialized() const
|
|
{
|
|
return ClientHandle.IsValid();
|
|
}
|
|
|
|
void InitDescriptorFromFoliageType(FISMComponentDescriptor& Descriptor, const UFoliageType* FoliageType)
|
|
{
|
|
const UFoliageType_Actor* FoliageTypeActor = Cast<UFoliageType_Actor>(FoliageType);
|
|
Descriptor.ComponentClass = FoliageTypeActor->StaticMeshOnlyComponentClass != nullptr ? FoliageTypeActor->StaticMeshOnlyComponentClass.Get() : UFoliageInstancedStaticMeshComponent::StaticClass();
|
|
|
|
Descriptor.Mobility = FoliageType->Mobility;
|
|
Descriptor.InstanceStartCullDistance = FoliageType->CullDistance.Min;
|
|
Descriptor.InstanceEndCullDistance = FoliageType->CullDistance.Max;
|
|
Descriptor.bCastShadow = FoliageType->CastShadow;
|
|
Descriptor.bCastDynamicShadow = FoliageType->bCastDynamicShadow;
|
|
Descriptor.bCastStaticShadow = FoliageType->bCastStaticShadow;
|
|
Descriptor.bCastContactShadow = FoliageType->bCastContactShadow;
|
|
Descriptor.RuntimeVirtualTextures = FoliageType->RuntimeVirtualTextures;
|
|
Descriptor.VirtualTextureRenderPassType = FoliageType->VirtualTextureRenderPassType;
|
|
Descriptor.VirtualTextureCullMips = FoliageType->VirtualTextureCullMips;
|
|
Descriptor.TranslucencySortPriority = FoliageType->TranslucencySortPriority;
|
|
Descriptor.bAffectDynamicIndirectLighting = FoliageType->bAffectDynamicIndirectLighting;
|
|
Descriptor.bAffectDistanceFieldLighting = FoliageType->bAffectDistanceFieldLighting;
|
|
Descriptor.bCastShadowAsTwoSided = FoliageType->bCastShadowAsTwoSided;
|
|
Descriptor.bReceivesDecals = FoliageType->bReceivesDecals;
|
|
Descriptor.bOverrideLightMapRes = FoliageType->bOverrideLightMapRes;
|
|
Descriptor.OverriddenLightMapRes = FoliageType->OverriddenLightMapRes;
|
|
Descriptor.LightmapType = FoliageType->LightmapType;
|
|
Descriptor.bUseAsOccluder = FoliageType->bUseAsOccluder;
|
|
Descriptor.bEnableDensityScaling = FoliageType->bEnableDensityScaling;
|
|
Descriptor.LightingChannels = FoliageType->LightingChannels;
|
|
Descriptor.bRenderCustomDepth = FoliageType->bRenderCustomDepth;
|
|
Descriptor.CustomDepthStencilWriteMask = FoliageType->CustomDepthStencilWriteMask;
|
|
Descriptor.CustomDepthStencilValue = FoliageType->CustomDepthStencilValue;
|
|
Descriptor.bIncludeInHLOD = FoliageType->bIncludeInHLOD;
|
|
Descriptor.BodyInstance.CopyBodyInstancePropertiesFrom(&FoliageType->BodyInstance);
|
|
|
|
Descriptor.bHasCustomNavigableGeometry = FoliageType->CustomNavigableGeometry;
|
|
Descriptor.bEnableDiscardOnLoad = FoliageType->bEnableDiscardOnLoad;
|
|
}
|
|
|
|
void FFoliageISMActor::Initialize(const UFoliageType* FoliageType)
|
|
{
|
|
check(!IsInitialized());
|
|
|
|
AInstancedFoliageActor* IFA = GetIFA();
|
|
|
|
const UFoliageType_Actor* FoliageTypeActor = Cast<const UFoliageType_Actor>(FoliageType);
|
|
ActorClass = FoliageTypeActor->ActorClass ? FoliageTypeActor->ActorClass.Get() : AActor::StaticClass();
|
|
|
|
FActorSpawnParameters SpawnParams;
|
|
SpawnParams.bCreateActorPackage = false;
|
|
SpawnParams.bNoFail = true;
|
|
SpawnParams.bHideFromSceneOutliner = true;
|
|
SpawnParams.bTemporaryEditorActor = true;
|
|
SpawnParams.ObjectFlags &= ~RF_Transactional;
|
|
SpawnParams.ObjectFlags |= RF_Transient;
|
|
AActor* SpawnedActor = IFA->GetWorld()->SpawnActor<AActor>(ActorClass, SpawnParams);
|
|
FTransform ActorTransform = SpawnedActor->GetActorTransform();
|
|
TArray<UStaticMeshComponent*> StaticMeshComponents;
|
|
SpawnedActor->GetComponents<UStaticMeshComponent>(StaticMeshComponents);
|
|
|
|
ClientHandle = IFA->RegisterClient(Guid);
|
|
IFA->RegisterClientInstanceManager(ClientHandle, this);
|
|
|
|
for (UStaticMeshComponent* StaticMeshComponent : StaticMeshComponents)
|
|
{
|
|
FISMComponentDescriptor Descriptor;
|
|
// Avoid initializing the body instance as we are going to do it in the InitDescriptorFromFoliageType and that Copy of BodyInstance on a registered components will fail.
|
|
Descriptor.InitFrom(StaticMeshComponent, /*bInitBodyInstance*/ false);
|
|
InitDescriptorFromFoliageType(Descriptor, FoliageTypeActor);
|
|
Descriptor.ComputeHash();
|
|
|
|
int32 DescriptorIndex = IFA->RegisterISMComponentDescriptor(Descriptor);
|
|
TArray<FTransform>& Transforms = ISMDefinition.FindOrAdd(DescriptorIndex);
|
|
if (UInstancedStaticMeshComponent* ISMComponent = Cast<UInstancedStaticMeshComponent>(StaticMeshComponent))
|
|
{
|
|
for (int32 InstanceIndex = 0; InstanceIndex < ISMComponent->GetInstanceCount(); ++InstanceIndex)
|
|
{
|
|
FTransform InstanceTransform;
|
|
if (ensure(ISMComponent->GetInstanceTransform(InstanceIndex, InstanceTransform, /*bWorldSpace=*/ true)))
|
|
{
|
|
FTransform LocalTransform = InstanceTransform.GetRelativeTransform(ActorTransform);
|
|
Transforms.Add(LocalTransform);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FTransform LocalTransform = StaticMeshComponent->GetComponentTransform().GetRelativeTransform(ActorTransform);
|
|
Transforms.Add(LocalTransform);
|
|
}
|
|
}
|
|
|
|
IFA->GetWorld()->DestroyActor(SpawnedActor);
|
|
|
|
RegisterDelegates();
|
|
}
|
|
|
|
void FFoliageISMActor::Uninitialize()
|
|
{
|
|
check(IsInitialized());
|
|
UnregisterDelegates();
|
|
GetIFA()->UnregisterClient(ClientHandle);
|
|
ISMDefinition.Empty();
|
|
}
|
|
|
|
void FFoliageISMActor::RegisterDelegates()
|
|
{
|
|
if (ActorClass)
|
|
{
|
|
if (UBlueprint* Blueprint = Cast<UBlueprint>(ActorClass->ClassGeneratedBy))
|
|
{
|
|
Blueprint->OnCompiled().AddRaw(this, &FFoliageISMActor::OnBlueprintChanged);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FFoliageISMActor::UnregisterDelegates()
|
|
{
|
|
if (ActorClass)
|
|
{
|
|
if (UBlueprint* Blueprint = Cast<UBlueprint>(ActorClass->ClassGeneratedBy))
|
|
{
|
|
Blueprint->OnCompiled().RemoveAll(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FFoliageISMActor::OnBlueprintChanged(UBlueprint* InBlueprint)
|
|
{
|
|
const UFoliageType_Actor* FoliageTypeActor = Cast<UFoliageType_Actor>(GetIFA()->GetFoliageTypeForInfo(Info));
|
|
if (FoliageTypeActor)
|
|
{
|
|
Reapply(FoliageTypeActor);
|
|
}
|
|
else if (IsInitialized())
|
|
{
|
|
Uninitialize();
|
|
}
|
|
}
|
|
|
|
void FFoliageISMActor::Reapply(const UFoliageType* FoliageType)
|
|
{
|
|
if (IsInitialized())
|
|
{
|
|
{
|
|
// We can't meaningfully re-instance the old static mesh instances to the new within this function, as)
|
|
// 1) The old instances are destroyed prior to creating the new ones, so they are no longer available to map
|
|
// 2) The new instances may not be a 1:1 mapping to the old, as they may now be a completely different structure
|
|
// Instead we just re-instance the old static mesh instances to nothing, so that anything referencing them is cleaned-up
|
|
TMap<FSMInstanceId, FSMInstanceId> ReplacementSMInstanceIds;
|
|
GetIFA()->ForEachClientSMInstance(ClientHandle, [&ReplacementSMInstanceIds](FSMInstanceId OldSMInstanceId)
|
|
{
|
|
ReplacementSMInstanceIds.Add(OldSMInstanceId, FSMInstanceId());
|
|
return true;
|
|
});
|
|
UEngineElementsLibrary::ReplaceEditorSMInstanceElementHandles(ReplacementSMInstanceIds);
|
|
}
|
|
|
|
Uninitialize();
|
|
}
|
|
Initialize(FoliageType);
|
|
check(IsInitialized());
|
|
|
|
BeginUpdate();
|
|
for (const FFoliageInstance& Instance : Info->Instances)
|
|
{
|
|
AddInstance(Instance);
|
|
}
|
|
EndUpdate();
|
|
}
|
|
|
|
int32 FFoliageISMActor::GetInstanceCount() const
|
|
{
|
|
return Info->Instances.Num();
|
|
}
|
|
|
|
void FFoliageISMActor::PreAddInstances(const UFoliageType* FoliageType, int32 AddedInstanceCount)
|
|
{
|
|
if (!IsInitialized())
|
|
{
|
|
Initialize(FoliageType);
|
|
check(IsInitialized());
|
|
}
|
|
|
|
GetIFA()->ReserveISMInstances(ClientHandle, AddedInstanceCount, ISMDefinition);
|
|
}
|
|
|
|
void FFoliageISMActor::AddInstance(const FFoliageInstance& NewInstance)
|
|
{
|
|
GetIFA()->AddISMInstance(ClientHandle, NewInstance.GetInstanceWorldTransform(), ISMDefinition);
|
|
}
|
|
|
|
void FFoliageISMActor::RemoveInstance(int32 InstanceIndex)
|
|
{
|
|
bool bOutIsEmpty = false;
|
|
GetIFA()->RemoveISMInstance(ClientHandle, InstanceIndex, &bOutIsEmpty);
|
|
|
|
if(bOutIsEmpty)
|
|
{
|
|
Uninitialize();
|
|
}
|
|
}
|
|
|
|
void FFoliageISMActor::BeginUpdate()
|
|
{
|
|
GetIFA()->BeginUpdate();
|
|
}
|
|
|
|
void FFoliageISMActor::EndUpdate()
|
|
{
|
|
GetIFA()->EndUpdate();
|
|
}
|
|
|
|
void FFoliageISMActor::SetInstanceWorldTransform(int32 InstanceIndex, const FTransform& Transform, bool bTeleport)
|
|
{
|
|
GetIFA()->SetISMInstanceTransform(ClientHandle, InstanceIndex, Transform, bTeleport, ISMDefinition);
|
|
}
|
|
|
|
FTransform FFoliageISMActor::GetInstanceWorldTransform(int32 InstanceIndex) const
|
|
{
|
|
return Info->Instances[InstanceIndex].GetInstanceWorldTransform();
|
|
}
|
|
|
|
bool FFoliageISMActor::IsOwnedComponent(const UPrimitiveComponent* Component) const
|
|
{
|
|
return GetIFA()->IsISMComponent(Component);
|
|
}
|
|
|
|
void FFoliageISMActor::Refresh(bool bAsync, bool bForce)
|
|
{
|
|
GetIFA()->UpdateHISMTrees(bAsync, bForce);
|
|
}
|
|
|
|
void FFoliageISMActor::OnHiddenEditorViewMaskChanged(uint64 InHiddenEditorViews)
|
|
{
|
|
if (!IsInitialized())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// This can give weird results if toggling the visibility of 2 foliage types that share the same meshes. The last one wins for now.
|
|
GetIFA()->ForEachClientComponent(ClientHandle, [InHiddenEditorViews](UInstancedStaticMeshComponent* Component)
|
|
{
|
|
if (UFoliageInstancedStaticMeshComponent* FoliageComponent = Cast<UFoliageInstancedStaticMeshComponent>(Component))
|
|
{
|
|
FoliageComponent->FoliageHiddenEditorViews = InHiddenEditorViews;
|
|
FoliageComponent->MarkRenderStateDirty();
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
|
|
void FFoliageISMActor::PreEditUndo(UFoliageType* FoliageType)
|
|
{
|
|
FFoliageImpl::PreEditUndo(FoliageType);
|
|
UnregisterDelegates();
|
|
}
|
|
|
|
void FFoliageISMActor::PostEditUndo(FFoliageInfo* InInfo, UFoliageType* FoliageType)
|
|
{
|
|
FFoliageImpl::PostEditUndo(InInfo, FoliageType);
|
|
RegisterDelegates();
|
|
}
|
|
|
|
void FFoliageISMActor::NotifyFoliageTypeWillChange(UFoliageType* FoliageType)
|
|
{
|
|
UnregisterDelegates();
|
|
}
|
|
|
|
void FFoliageISMActor::NotifyFoliageTypeChanged(UFoliageType* FoliageType, bool bSourceChanged)
|
|
{
|
|
if (!IsInitialized())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (UFoliageType_Actor* InFoliageTypeActor = Cast<UFoliageType_Actor>(FoliageType))
|
|
{
|
|
// Implementation should change
|
|
if (!InFoliageTypeActor->bStaticMeshOnly)
|
|
{
|
|
Uninitialize();
|
|
return;
|
|
}
|
|
}
|
|
|
|
AInstancedFoliageActor* IFA = GetIFA();
|
|
|
|
// Go through descriptors and see if they changed
|
|
if (!bSourceChanged)
|
|
{
|
|
for (const auto& Pair : ISMDefinition)
|
|
{
|
|
const FISMComponentDescriptor& RegisteredDescriptor = IFA->GetISMComponentDescriptor(Pair.Key);
|
|
FISMComponentDescriptor NewDescriptor(RegisteredDescriptor);
|
|
InitDescriptorFromFoliageType(NewDescriptor, FoliageType);
|
|
NewDescriptor.ComputeHash();
|
|
|
|
if (RegisteredDescriptor != NewDescriptor)
|
|
{
|
|
bSourceChanged = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bSourceChanged)
|
|
{
|
|
Reapply(FoliageType);
|
|
ApplySelection(true, Info->SelectedIndices);
|
|
}
|
|
else
|
|
{
|
|
RegisterDelegates();
|
|
}
|
|
}
|
|
|
|
void FFoliageISMActor::SelectAllInstances(bool bSelect)
|
|
{
|
|
TSet<int32> Indices;
|
|
Indices.Reserve(Info->Instances.Num());
|
|
for (int32 i = 0; i < Info->Instances.Num(); ++i)
|
|
{
|
|
Indices.Add(i);
|
|
}
|
|
SelectInstances(bSelect, Indices);
|
|
}
|
|
|
|
void FFoliageISMActor::SelectInstance(bool bSelect, int32 Index)
|
|
{
|
|
SelectInstances(bSelect, { Index });
|
|
}
|
|
|
|
void FFoliageISMActor::SelectInstances(bool bSelect, const TSet<int32>& SelectedIndices)
|
|
{
|
|
GetIFA()->SelectISMInstances(ClientHandle, bSelect, SelectedIndices);
|
|
}
|
|
|
|
int32 FFoliageISMActor::GetInstanceIndexFrom(const UPrimitiveComponent* PrimitiveComponent, int32 ComponentIndex) const
|
|
{
|
|
if (IsInitialized() && ComponentIndex != INDEX_NONE)
|
|
{
|
|
if (const UInstancedStaticMeshComponent* ISMComponent = Cast<UInstancedStaticMeshComponent>(PrimitiveComponent))
|
|
{
|
|
return GetIFA()->GetISMInstanceIndex(ClientHandle, ISMComponent, ComponentIndex);
|
|
}
|
|
}
|
|
return INDEX_NONE;
|
|
}
|
|
|
|
FBox FFoliageISMActor::GetSelectionBoundingBox(const TSet<int32>& SelectedIndices) const
|
|
{
|
|
return GetIFA()->GetISMInstanceBounds(ClientHandle, SelectedIndices);
|
|
}
|
|
void FFoliageISMActor::ApplySelection(bool bApply, const TSet<int32>& SelectedIndices)
|
|
{
|
|
// Going in and out of Folaige with an Empty/Unregistered impl.
|
|
if (!IsInitialized())
|
|
{
|
|
return;
|
|
}
|
|
|
|
SelectAllInstances(false);
|
|
if (bApply)
|
|
{
|
|
SelectInstances(true, SelectedIndices);
|
|
}
|
|
}
|
|
|
|
void FFoliageISMActor::ClearSelection(const TSet<int32>& SelectedIndices)
|
|
{
|
|
SelectAllInstances(false);
|
|
}
|
|
|
|
void FFoliageISMActor::ForEachSMInstance(TFunctionRef<bool(FSMInstanceId)> Callback) const
|
|
{
|
|
if (ClientHandle)
|
|
{
|
|
GetIFA()->ForEachClientSMInstance(ClientHandle, Callback);
|
|
}
|
|
}
|
|
|
|
void FFoliageISMActor::ForEachSMInstance(int32 InstanceIndex, TFunctionRef<bool(FSMInstanceId)> Callback) const
|
|
{
|
|
if (ClientHandle)
|
|
{
|
|
GetIFA()->ForEachClientSMInstance(ClientHandle, InstanceIndex, Callback);
|
|
}
|
|
}
|
|
|
|
#endif // WITH_EDITOR
|
|
|
|
FText FFoliageISMActor::GetISMPartitionInstanceDisplayName(const FISMClientInstanceId& InstanceId) const
|
|
{
|
|
#if WITH_EDITOR
|
|
const FFoliageInstanceId FoliageInstanceId = ISMClientInstanceIdToFoliageInstanceId(InstanceId);
|
|
const FText OwnerDisplayName = FText::FromString(ActorClass ? ActorClass->GetName() : GetIFA()->GetName());
|
|
return FText::Format(NSLOCTEXT("FoliageISMActor", "DisplayNameFmt", "{0} - Instance {1}"), OwnerDisplayName, FoliageInstanceId.Index);
|
|
#else
|
|
return FText();
|
|
#endif
|
|
}
|
|
|
|
FText FFoliageISMActor::GetISMPartitionInstanceTooltip(const FISMClientInstanceId& InstanceId) const
|
|
{
|
|
#if WITH_EDITOR
|
|
const FFoliageInstanceId FoliageInstanceId = ISMClientInstanceIdToFoliageInstanceId(InstanceId);
|
|
const FText OwnerDisplayPath = FText::FromString(GetIFA()->GetPathName(GetIFA()->GetWorld())); // stops the path at the level of the world the object is in
|
|
return FText::Format(NSLOCTEXT("FoliageISMActor", "TooltipFmt", "Instance {0} on {1}"), FoliageInstanceId.Index, OwnerDisplayPath);
|
|
#else
|
|
return FText();
|
|
#endif
|
|
}
|
|
|
|
bool FFoliageISMActor::CanEditISMPartitionInstance(const FISMClientInstanceId& InstanceId) const
|
|
{
|
|
#if WITH_EDITOR
|
|
const FFoliageInstanceId FoliageInstanceId = ISMClientInstanceIdToFoliageInstanceId(InstanceId);
|
|
return GetIFA()->CanEditFoliageInstance(FoliageInstanceId);
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool FFoliageISMActor::CanMoveISMPartitionInstance(const FISMClientInstanceId& InstanceId, const ETypedElementWorldType InWorldType) const
|
|
{
|
|
#if WITH_EDITOR
|
|
const FFoliageInstanceId FoliageInstanceId = ISMClientInstanceIdToFoliageInstanceId(InstanceId);
|
|
return GetIFA()->CanMoveFoliageInstance(FoliageInstanceId, InWorldType);
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool FFoliageISMActor::GetISMPartitionInstanceTransform(const FISMClientInstanceId& InstanceId, FTransform& OutInstanceTransform, bool bWorldSpace) const
|
|
{
|
|
#if WITH_EDITOR
|
|
const FFoliageInstanceId FoliageInstanceId = ISMClientInstanceIdToFoliageInstanceId(InstanceId);
|
|
return GetIFA()->GetFoliageInstanceTransform(FoliageInstanceId, OutInstanceTransform, bWorldSpace);
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool FFoliageISMActor::SetISMPartitionInstanceTransform(const FISMClientInstanceId& InstanceId, const FTransform& InstanceTransform, bool bWorldSpace, bool bTeleport)
|
|
{
|
|
#if WITH_EDITOR
|
|
const FFoliageInstanceId FoliageInstanceId = ISMClientInstanceIdToFoliageInstanceId(InstanceId);
|
|
return GetIFA()->SetFoliageInstanceTransform(FoliageInstanceId, InstanceTransform, bWorldSpace, bTeleport);
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
void FFoliageISMActor::NotifyISMPartitionInstanceMovementStarted(const FISMClientInstanceId& InstanceId)
|
|
{
|
|
#if WITH_EDITOR
|
|
const FFoliageInstanceId FoliageInstanceId = ISMClientInstanceIdToFoliageInstanceId(InstanceId);
|
|
GetIFA()->NotifyFoliageInstanceMovementStarted(FoliageInstanceId);
|
|
#endif
|
|
}
|
|
|
|
void FFoliageISMActor::NotifyISMPartitionInstanceMovementOngoing(const FISMClientInstanceId& InstanceId)
|
|
{
|
|
#if WITH_EDITOR
|
|
const FFoliageInstanceId FoliageInstanceId = ISMClientInstanceIdToFoliageInstanceId(InstanceId);
|
|
GetIFA()->NotifyFoliageInstanceMovementOngoing(FoliageInstanceId);
|
|
#endif
|
|
}
|
|
|
|
void FFoliageISMActor::NotifyISMPartitionInstanceMovementEnded(const FISMClientInstanceId& InstanceId)
|
|
{
|
|
#if WITH_EDITOR
|
|
const FFoliageInstanceId FoliageInstanceId = ISMClientInstanceIdToFoliageInstanceId(InstanceId);
|
|
GetIFA()->NotifyFoliageInstanceMovementEnded(FoliageInstanceId);
|
|
#endif
|
|
}
|
|
|
|
void FFoliageISMActor::NotifyISMPartitionInstanceSelectionChanged(const FISMClientInstanceId& InstanceId, const bool bIsSelected)
|
|
{
|
|
#if WITH_EDITOR
|
|
const FFoliageInstanceId FoliageInstanceId = ISMClientInstanceIdToFoliageInstanceId(InstanceId);
|
|
GetIFA()->NotifyFoliageInstanceSelectionChanged(FoliageInstanceId, bIsSelected);
|
|
#endif
|
|
}
|
|
|
|
bool FFoliageISMActor::DeleteISMPartitionInstances(TArrayView<const FISMClientInstanceId> InstanceIds)
|
|
{
|
|
#if WITH_EDITOR
|
|
const TArray<FFoliageInstanceId> FoliageInstanceIds = ISMClientInstanceIdsToFoliageInstanceIds(InstanceIds);
|
|
return GetIFA()->DeleteFoliageInstances(FoliageInstanceIds);
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool FFoliageISMActor::DuplicateISMPartitionInstances(TArrayView<const FISMClientInstanceId> InstanceIds, TArray<FISMClientInstanceId>& OutNewInstanceIds)
|
|
{
|
|
#if WITH_EDITOR
|
|
const TArray<FFoliageInstanceId> FoliageInstanceIds = ISMClientInstanceIdsToFoliageInstanceIds(InstanceIds);
|
|
|
|
TArray<FFoliageInstanceId> NewFoliageInstanceIds;
|
|
const bool bDidDuplicate = GetIFA()->DuplicateFoliageInstances(FoliageInstanceIds, NewFoliageInstanceIds);
|
|
|
|
OutNewInstanceIds.Reset(NewFoliageInstanceIds.Num());
|
|
for (const FFoliageInstanceId& NewFoliageInstanceId : NewFoliageInstanceIds)
|
|
{
|
|
OutNewInstanceIds.Add(FISMClientInstanceId{ static_cast<FFoliageISMActor&>(*NewFoliageInstanceId.Info->Implementation).ClientHandle, NewFoliageInstanceId.Index });
|
|
}
|
|
|
|
return bDidDuplicate;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
FFoliageInstanceId FFoliageISMActor::ISMClientInstanceIdToFoliageInstanceId(const FISMClientInstanceId& InstanceId) const
|
|
{
|
|
check(InstanceId.Handle == ClientHandle);
|
|
return FFoliageInstanceId{ Info, InstanceId.Index };
|
|
}
|
|
|
|
TArray<FFoliageInstanceId> FFoliageISMActor::ISMClientInstanceIdsToFoliageInstanceIds(TArrayView<const FISMClientInstanceId> InstanceIds) const
|
|
{
|
|
TArray<FFoliageInstanceId> FoliageInstanceIds;
|
|
FoliageInstanceIds.Reserve(InstanceIds.Num());
|
|
for (const FISMClientInstanceId& InstanceId : InstanceIds)
|
|
{
|
|
FoliageInstanceIds.Add(ISMClientInstanceIdToFoliageInstanceId(InstanceId));
|
|
}
|
|
return FoliageInstanceIds;
|
|
}
|
|
#endif
|