198 lines
6.9 KiB
C++
198 lines
6.9 KiB
C++
/*
|
|
* Copyright (c) <2017> Side Effects Software Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
#include "HoudiniMeshSplitInstancerComponent.h"
|
|
|
|
#include "HoudiniApi.h"
|
|
#include "HoudiniAssetComponent.h"
|
|
#include "HoudiniEngineRuntimePrivatePCH.h"
|
|
|
|
#include "Components/StaticMeshComponent.h"
|
|
#if WITH_EDITOR
|
|
#include "LevelEditorViewport.h"
|
|
#include "MeshPaintHelpers.h"
|
|
#endif
|
|
|
|
#include "Internationalization/Internationalization.h"
|
|
#define LOCTEXT_NAMESPACE HOUDINI_LOCTEXT_NAMESPACE
|
|
|
|
UHoudiniMeshSplitInstancerComponent::UHoudiniMeshSplitInstancerComponent( const FObjectInitializer& ObjectInitializer )
|
|
: Super( ObjectInitializer )
|
|
, InstancedMesh( nullptr )
|
|
{
|
|
}
|
|
|
|
void
|
|
UHoudiniMeshSplitInstancerComponent::OnComponentDestroyed( bool bDestroyingHierarchy )
|
|
{
|
|
ClearInstances(0);
|
|
Super::OnComponentDestroyed( bDestroyingHierarchy );
|
|
}
|
|
|
|
void
|
|
UHoudiniMeshSplitInstancerComponent::Serialize( FArchive & Ar )
|
|
{
|
|
Super::Serialize( Ar );
|
|
Ar.UsingCustomVersion( FHoudiniCustomSerializationVersion::GUID );
|
|
|
|
Ar << InstancedMesh;
|
|
Ar << OverrideMaterial;
|
|
Ar << Instances;
|
|
}
|
|
|
|
void
|
|
UHoudiniMeshSplitInstancerComponent::AddReferencedObjects( UObject * InThis, FReferenceCollector & Collector )
|
|
{
|
|
UHoudiniMeshSplitInstancerComponent * ThisMSIC = Cast< UHoudiniMeshSplitInstancerComponent >(InThis);
|
|
if ( ThisMSIC && !ThisMSIC->IsPendingKill() )
|
|
{
|
|
Collector.AddReferencedObject(ThisMSIC->InstancedMesh, ThisMSIC);
|
|
Collector.AddReferencedObject(ThisMSIC->OverrideMaterial, ThisMSIC);
|
|
Collector.AddReferencedObjects(ThisMSIC->Instances, ThisMSIC);
|
|
}
|
|
}
|
|
|
|
void
|
|
UHoudiniMeshSplitInstancerComponent::SetInstances(
|
|
const TArray<FTransform>& InstanceTransforms,
|
|
const TArray<FLinearColor> & InstancedColors)
|
|
{
|
|
#if WITH_EDITOR
|
|
if ( Instances.Num() || InstanceTransforms.Num() )
|
|
{
|
|
if (!GetOwner() || GetOwner()->IsPendingKill())
|
|
return;
|
|
|
|
const FScopedTransaction Transaction( LOCTEXT( "UpdateInstances", "Update Instances" ) );
|
|
GetOwner()->Modify();
|
|
|
|
// Destroy previous instances while keeping some of the one that we'll be able to reuse
|
|
ClearInstances(InstanceTransforms.Num());
|
|
|
|
if( !InstancedMesh || InstancedMesh->IsPendingKill() )
|
|
{
|
|
HOUDINI_LOG_ERROR(TEXT("%s: Null InstancedMesh for split instanced mesh override"), *GetOwner()->GetName());
|
|
return;
|
|
}
|
|
|
|
TArray<FColor> InstanceColorOverride;
|
|
InstanceColorOverride.SetNumUninitialized(InstancedColors.Num());
|
|
for( int32 ix = 0; ix < InstancedColors.Num(); ++ix )
|
|
{
|
|
InstanceColorOverride[ix] = InstancedColors[ix].GetClamped().ToFColor(false);
|
|
}
|
|
|
|
// Only create new SMC for newly added instances
|
|
for (int32 iAdd = Instances.Num(); iAdd < InstanceTransforms.Num(); ++iAdd)
|
|
{
|
|
const FTransform& InstanceTransform = InstanceTransforms[iAdd];
|
|
|
|
UStaticMeshComponent* SMC = NewObject< UStaticMeshComponent >(
|
|
GetOwner(), UStaticMeshComponent::StaticClass(),
|
|
NAME_None, RF_Transactional);
|
|
|
|
SMC->SetRelativeTransform(InstanceTransform);
|
|
|
|
Instances.Add(SMC);
|
|
}
|
|
|
|
ensure(InstanceTransforms.Num() == Instances.Num());
|
|
if (InstanceTransforms.Num() == Instances.Num())
|
|
{
|
|
for (int32 iIns = 0; iIns < Instances.Num(); ++iIns)
|
|
{
|
|
UStaticMeshComponent* SMC = Instances[iIns];
|
|
const FTransform& InstanceTransform = InstanceTransforms[iIns];
|
|
|
|
if (!SMC || SMC->IsPendingKill())
|
|
continue;
|
|
|
|
SMC->SetRelativeTransform(InstanceTransform);
|
|
|
|
// Attach created static mesh component to this thing
|
|
SMC->AttachToComponent(this, FAttachmentTransformRules::KeepRelativeTransform);
|
|
|
|
SMC->SetStaticMesh(InstancedMesh);
|
|
SMC->SetVisibility(IsVisible());
|
|
SMC->SetMobility(Mobility);
|
|
if (OverrideMaterial && !OverrideMaterial->IsPendingKill())
|
|
{
|
|
int32 MeshMaterialCount = InstancedMesh->StaticMaterials.Num();
|
|
for (int32 Idx = 0; Idx < MeshMaterialCount; ++Idx)
|
|
SMC->SetMaterial(Idx, OverrideMaterial);
|
|
}
|
|
|
|
// If we have override colors, apply them
|
|
int32 InstIndex = Instances.Num();
|
|
if (InstanceColorOverride.IsValidIndex(InstIndex))
|
|
{
|
|
MeshPaintHelpers::FillStaticMeshVertexColors(SMC, -1, InstanceColorOverride[InstIndex], FColor::White);
|
|
//FIXME: How to get rid of the warning about fixup vertex colors on load?
|
|
//SMC->FixupOverrideColorsIfNecessary();
|
|
}
|
|
|
|
SMC->RegisterComponent();
|
|
|
|
// Adding to the array has been done above
|
|
// Instances.Add(SMC);
|
|
|
|
// Properties not being propagated to newly created UStaticMeshComponents
|
|
if (UHoudiniAssetComponent * pHoudiniAsset = Cast<UHoudiniAssetComponent>(GetAttachParent()))
|
|
{
|
|
pHoudiniAsset->CopyComponentPropertiesTo(SMC);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void
|
|
UHoudiniMeshSplitInstancerComponent::ClearInstances(int32 NumToKeep)
|
|
{
|
|
if (NumToKeep <= 0)
|
|
{
|
|
for (auto&& Instance : Instances)
|
|
{
|
|
if (Instance)
|
|
{
|
|
Instance->ConditionalBeginDestroy();
|
|
}
|
|
}
|
|
Instances.Empty();
|
|
}
|
|
else if (NumToKeep > 0 && NumToKeep < Instances.Num())
|
|
{
|
|
for (int32 i = NumToKeep; i < Instances.Num(); ++i)
|
|
{
|
|
UStaticMeshComponent * Instance = Instances[i];
|
|
if (Instance)
|
|
{
|
|
Instance->ConditionalBeginDestroy();
|
|
}
|
|
}
|
|
Instances.SetNum(NumToKeep);
|
|
}
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE |