Files
Andron666 9c38e93fa4 part7
2022-12-05 20:31:35 +05:00

248 lines
7.4 KiB
C++

/*
* Copyright (c) <2021> Side Effects Software Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. The name of Side Effects Software may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "HoudiniInstancedActorComponent.h"
#include "HoudiniMeshSplitInstancerComponent.h"
#include "HoudiniRuntimeSettings.h"
#include "HoudiniEngineRuntimePrivatePCH.h"
#include "HoudiniPluginSerializationVersion.h"
#include "HoudiniCompatibilityHelpers.h"
#include "UObject/DevObjectVersion.h"
#include "Serialization/CustomVersion.h"
#include "Components/InstancedStaticMeshComponent.h"
#include "Components/HierarchicalInstancedStaticMeshComponent.h"
#include "Internationalization/Internationalization.h"
#define LOCTEXT_NAMESPACE HOUDINI_LOCTEXT_NAMESPACE
UHoudiniInstancedActorComponent::UHoudiniInstancedActorComponent( const FObjectInitializer& ObjectInitializer )
: Super( ObjectInitializer )
, InstancedObject( nullptr )
{
//
// Set default component properties.
//
Mobility = EComponentMobility::Static;
bCanEverAffectNavigation = true;
bNeverNeedsRenderUpdate = false;
Bounds = FBox(ForceInitToZero);
}
void
UHoudiniInstancedActorComponent::Serialize(FArchive& Ar)
{
int64 InitialOffset = Ar.Tell();
bool bLegacyComponent = false;
if (Ar.IsLoading())
{
int32 Ver = Ar.CustomVer(FHoudiniCustomSerializationVersion::GUID);
if (Ver < VER_HOUDINI_PLUGIN_SERIALIZATION_VERSION_V2_BASE && Ver >= VER_HOUDINI_PLUGIN_SERIALIZATION_VERSION_BASE)
{
bLegacyComponent = true;
}
}
if (bLegacyComponent)
{
// Legacy serialization
// Either try to convert or skip depending on the setting value
const UHoudiniRuntimeSettings * HoudiniRuntimeSettings = GetDefault<UHoudiniRuntimeSettings>();
bool bEnableBackwardCompatibility = HoudiniRuntimeSettings->bEnableBackwardCompatibility;
if (bEnableBackwardCompatibility)
{
HOUDINI_LOG_WARNING(TEXT("Loading deprecated version of UHoudiniInstancedActorComponent : converting v1 object to v2."));
Super::Serialize(Ar);
UHoudiniInstancedActorComponent_V1* CompatibilityIAC = NewObject<UHoudiniInstancedActorComponent_V1>();
CompatibilityIAC->Serialize(Ar);
CompatibilityIAC->UpdateFromLegacyData(this);
}
else
{
HOUDINI_LOG_WARNING(TEXT("Loading deprecated version of UHoudiniInstancedActorComponent : serialization will be skipped."));
Super::Serialize(Ar);
// Skip v1 Serialized data
if (FLinker* Linker = Ar.GetLinker())
{
int32 const ExportIndex = this->GetLinkerIndex();
FObjectExport& Export = Linker->ExportMap[ExportIndex];
Ar.Seek(InitialOffset + Export.SerialSize);
return;
}
}
}
else
{
// Normal v2 serialization
Super::Serialize(Ar);
}
}
void UHoudiniInstancedActorComponent::OnComponentDestroyed( bool bDestroyingHierarchy )
{
ClearAllInstances();
Super::OnComponentDestroyed( bDestroyingHierarchy );
}
void
UHoudiniInstancedActorComponent::AddReferencedObjects(UObject * InThis, FReferenceCollector & Collector )
{
UHoudiniInstancedActorComponent * ThisHIAC = Cast< UHoudiniInstancedActorComponent >(InThis);
if ( ThisHIAC && !ThisHIAC->IsPendingKill() )
{
if ( ThisHIAC->InstancedObject && !ThisHIAC->InstancedObject->IsPendingKill() )
Collector.AddReferencedObject( ThisHIAC->InstancedObject, ThisHIAC );
Collector.AddReferencedObjects(ThisHIAC->InstancedActors, ThisHIAC );
}
}
int32
UHoudiniInstancedActorComponent::AddInstance(const FTransform& InstanceTransform, AActor * NewActor)
{
if (!NewActor || NewActor->IsPendingKill())
return -1;
NewActor->AttachToComponent(this, FAttachmentTransformRules::KeepRelativeTransform);
NewActor->SetActorRelativeTransform(InstanceTransform);
return InstancedActors.Add(NewActor);
}
bool
UHoudiniInstancedActorComponent::SetInstanceAt(const int32& Idx, const FTransform& InstanceTransform, AActor * NewActor)
{
if (!NewActor || NewActor->IsPendingKill())
return false;
if (!InstancedActors.IsValidIndex(Idx))
return false;
NewActor->AttachToComponent(this, FAttachmentTransformRules::KeepRelativeTransform);
NewActor->SetActorRelativeTransform(InstanceTransform);
NewActor->RegisterAllComponents();
InstancedActors[Idx] = NewActor;
return true;
}
bool
UHoudiniInstancedActorComponent::SetInstanceTransformAt(const int32& Idx, const FTransform& InstanceTransform)
{
if (!InstancedActors.IsValidIndex(Idx))
return false;
InstancedActors[Idx]->AttachToComponent(this, FAttachmentTransformRules::KeepRelativeTransform);
InstancedActors[Idx]->SetActorRelativeTransform(InstanceTransform);
return true;
}
void
UHoudiniInstancedActorComponent::ClearAllInstances()
{
for ( AActor* Instance : InstancedActors )
{
if ( Instance && !Instance->IsPendingKill() )
Instance->Destroy();
}
InstancedActors.Empty();
}
void
UHoudiniInstancedActorComponent::SetNumberOfInstances(const int32& NewInstanceNum)
{
int32 OldInstanceNum = InstancedActors.Num();
// If we want less instances than we already have, destroy the extra properly
if (NewInstanceNum < OldInstanceNum)
{
for (int32 Idx = NewInstanceNum - 1; Idx < InstancedActors.Num(); Idx++)
{
AActor* Instance = InstancedActors.IsValidIndex(Idx) ? InstancedActors[Idx] : nullptr;
if (Instance && !Instance->IsPendingKill())
Instance->Destroy();
}
}
// Grow the array with nulls if needed
InstancedActors.SetNumZeroed(NewInstanceNum);
}
void
UHoudiniInstancedActorComponent::OnComponentCreated()
{
Super::OnComponentCreated();
// If our instances are parented to another actor we should duplicate them
bool bNeedDuplicate = false;
for (auto CurrentInstance : InstancedActors)
{
if ( !CurrentInstance || CurrentInstance->IsPendingKill() )
continue;
if ( CurrentInstance->GetAttachParentActor() != GetOwner() )
bNeedDuplicate = true;
}
if ( !bNeedDuplicate )
return;
// TODO: CHECK ME!
// We need to duplicate our instances
TArray<AActor*> SourceInstances = InstancedActors;
InstancedActors.Empty();
for (AActor* CurrentInstance : SourceInstances)
{
if ( !CurrentInstance || CurrentInstance->IsPendingKill() )
continue;
FTransform InstanceTransform;
if ( CurrentInstance->GetRootComponent() )
InstanceTransform = CurrentInstance->GetRootComponent()->GetRelativeTransform();
// AddInstance( InstanceTransform );
}
}
#undef LOCTEXT_NAMESPACE