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

555 lines
15 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 "HoudiniSplineComponent.h"
#include "HoudiniEngineRuntimePrivatePCH.h"
#include "HoudiniAssetComponent.h"
#include "HoudiniEngineRuntime.h"
#include "HoudiniEngineRuntimeUtils.h"
#include "HoudiniInput.h"
#include "HoudiniInputObject.h"
#include "HoudiniPluginSerializationVersion.h"
#include "Components/MeshComponent.h"
#include "Algo/Reverse.h"
#include "HoudiniPluginSerializationVersion.h"
#include "HoudiniCompatibilityHelpers.h"
#include "UObject/DevObjectVersion.h"
#include "Serialization/CustomVersion.h"
void
UHoudiniSplineComponent::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 HOUDINI_ENGINE_ENABLE_BACKWARD_COMPATIBILITY
const UHoudiniRuntimeSettings * HoudiniRuntimeSettings = GetDefault<UHoudiniRuntimeSettings>();
bool bEnableBackwardCompatibility = HoudiniRuntimeSettings->bEnableBackwardCompatibility;
if (bEnableBackwardCompatibility)
{
HOUDINI_LOG_WARNING(TEXT("Loading deprecated version of UHoudiniSplineComponent : converting v1 object to v2."));
Super::Serialize(Ar);
UHoudiniSplineComponent_V1* CompatibilitySC = NewObject<UHoudiniSplineComponent_V1>();
CompatibilitySC->Serialize(Ar);
CompatibilitySC->UpdateFromLegacyData(this);
Construct(CompatibilitySC->CurveDisplayPoints);
}
else
{
HOUDINI_LOG_WARNING(TEXT("Loading deprecated version of UHoudiniSplineComponent : 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);
}
}
UHoudiniSplineComponent::UHoudiniSplineComponent(const FObjectInitializer & ObjectInitializer)
: Super(ObjectInitializer)
, bClosed(false)
, bReversed(false)
, bIsHoudiniSplineVisible(true)
, CurveType(EHoudiniCurveType::Polygon)
, CurveMethod(EHoudiniCurveMethod::CVs)
, bHasChanged(false)
, bNeedsToTriggerUpdate(false)
, bIsInputCurve(false)
, bIsEditableOutputCurve(false)
, NodeId(-1)
{
// Add two default points to the curve
FTransform defaultPoint = FTransform::Identity;
// Set this component to not tick?
// SetComponentTickEnabled(false);
// Default curve.
CurvePoints.Add(defaultPoint);
DisplayPoints.Add(defaultPoint.GetLocation());
defaultPoint.SetTranslation(FVector(200.f, 0.f, 0.f));
CurvePoints.Add(defaultPoint);
DisplayPoints.Add(defaultPoint.GetLocation());
bIsOutputCurve = false;
bCookOnCurveChanged = true;
#if WITH_EDITOR
bPostUndo = false;
#endif
}
void
UHoudiniSplineComponent::Construct(TArray<FVector>& InCurveDisplayPoints, int32 InsertedPoint)
{
DisplayPoints.Empty();
DisplayPointIndexDivider.Empty();
float DisplayPointStepSize;
// Resample the display points for linear curve.
if (InCurveDisplayPoints.Num() <= 0)
return;
// Add an additional displaypoint to the end for closed curve
if (bClosed && InCurveDisplayPoints.Num() > 2)
{
FVector & FirstPoint = InCurveDisplayPoints[0];
FVector ClosingPoint;
ClosingPoint.X = FirstPoint.X;
ClosingPoint.Y = FirstPoint.Y;
ClosingPoint.Z = FirstPoint.Z;
InCurveDisplayPoints.Add(ClosingPoint);
}
if (CurveType == EHoudiniCurveType::Polygon)
{
FVector Pt1, Pt2;
Pt1 = InCurveDisplayPoints[0];
int32 CurrentDisplayPointIndex = 0;
for (int Index = 1; Index < InCurveDisplayPoints.Num(); ++Index)
{
DisplayPointStepSize = 10.f;
Pt2 = InCurveDisplayPoints[Index];
FVector Direction = Pt2 - Pt1;
float SegmentLength = Direction.Size();
int32 NumOfDisplayPt = SegmentLength / DisplayPointStepSize;
// Make sure there are at least 20 display points on a segment.
while( NumOfDisplayPt < 20 && SegmentLength > 0.01)
{
DisplayPointStepSize /= 2.f;
NumOfDisplayPt = SegmentLength / DisplayPointStepSize;
}
Direction.Normalize(0.01f);
FVector StepVector = Direction * DisplayPointStepSize;
// Always add the start point of a line segment
FVector NextDisplayPt = Pt1;
if (NumOfDisplayPt == 0) DisplayPoints.Add(NextDisplayPt);
for (int32 itr = 0; itr < NumOfDisplayPt; ++itr)
{
DisplayPoints.Add(NextDisplayPt);
NextDisplayPt += StepVector;
CurrentDisplayPointIndex += 1;
}
DisplayPointIndexDivider.Add(CurrentDisplayPointIndex);
Pt1 = Pt2;
}
// Add the ending point
DisplayPoints.Add(Pt1);
// Duplicate the last index, to make the DisplaPointyIndexDivider array matches the length of DP array
DisplayPointIndexDivider.Add(CurrentDisplayPointIndex + 1);
}
else if (CurveType == EHoudiniCurveType::Points)
{
// do not add display points for Points curve type, just show the CVs
}
else
{
// Needs a better algorithm to divide the display points
// Refined display points does not strictly interpolate the curve points.
FVector Pt1, Pt2;
Pt1 = InCurveDisplayPoints[0];
int Itr = 1;
int32 ClosestIndex = -1;
float ClosestDistance = -1.f;
for (int32 Index = 1; Index < InCurveDisplayPoints.Num(); ++Index)
{
if (Itr >= CurvePoints.Num()) break;
Pt2 = InCurveDisplayPoints[Index];
FVector ClosestPointOnSegment = FMath::ClosestPointOnSegment(CurvePoints[Itr].GetLocation(), Pt1, Pt2);
float Distance = (ClosestPointOnSegment - CurvePoints[Itr].GetLocation()).Size();
if (ClosestDistance < 0.f || Distance < ClosestDistance)
{
ClosestDistance = Distance;
ClosestIndex = Index;
}
else
{
Itr += 1;
if (Itr >= CurvePoints.Num()) break;
DisplayPointIndexDivider.Add(Index-1);
ClosestPointOnSegment = FMath::ClosestPointOnSegment(CurvePoints[Itr].GetLocation(), Pt1, Pt2);
ClosestDistance = (ClosestPointOnSegment - CurvePoints[Itr].GetLocation()).Size();
}
}
DisplayPointIndexDivider.Add(InCurveDisplayPoints.Num());
DisplayPoints = InCurveDisplayPoints;
}
}
void
UHoudiniSplineComponent::CopyHoudiniData(const UHoudiniSplineComponent* OtherHoudiniSplineComponent)
{
if (!OtherHoudiniSplineComponent)
return;
CurvePoints = OtherHoudiniSplineComponent->CurvePoints;
DisplayPoints = OtherHoudiniSplineComponent->DisplayPoints;
DisplayPointIndexDivider = OtherHoudiniSplineComponent->DisplayPointIndexDivider;
CurveType = OtherHoudiniSplineComponent->CurveType;
CurveMethod = OtherHoudiniSplineComponent->CurveMethod;
bClosed = OtherHoudiniSplineComponent->bClosed;
#if WITH_EDITORONLY_DATA
bVisualizeComponent = OtherHoudiniSplineComponent->bVisualizeComponent;
#endif
bReversed = OtherHoudiniSplineComponent->bReversed;
SetVisibility(OtherHoudiniSplineComponent->IsVisible());
HoudiniSplineName = OtherHoudiniSplineComponent->HoudiniSplineName;
}
UHoudiniSplineComponent::~UHoudiniSplineComponent()
{}
void
UHoudiniSplineComponent::AppendPoint(const FTransform& NewPoint)
{
CurvePoints.Add(NewPoint);
}
void
UHoudiniSplineComponent::InsertPointAtIndex(const FTransform& NewPoint, const int32& Index)
{
check(Index >= 0 && Index < CurvePoints.Num());
CurvePoints.Insert(NewPoint, Index);
bHasChanged = true;
}
void
UHoudiniSplineComponent::RemovePointAtIndex(const int32& Index)
{
check(Index >= 0 && Index < CurvePoints.Num());
CurvePoints.RemoveAt(Index);
bHasChanged = true;
}
void
UHoudiniSplineComponent::SetReversed(const bool& InReversed)
{
// don't need to do anything if the reversed state doesn't change.
if (InReversed == bReversed)
return;
bReversed = InReversed;
ReverseCurvePoints();
MarkChanged(true);
}
void
UHoudiniSplineComponent::ReverseCurvePoints()
{
if (CurvePoints.Num() < 2)
return;
Algo::Reverse(CurvePoints);
}
void
UHoudiniSplineComponent::EditPointAtindex(const FTransform& NewPoint, const int32& Index)
{
if (!CurvePoints.IsValidIndex(Index))
return;
CurvePoints[Index] = NewPoint;
bHasChanged = true;
}
#if WITH_EDITOR
void
UHoudiniSplineComponent::PostEditChangeProperty(FPropertyChangedEvent& PeopertyChangedEvent)
{
Super::PostEditChangeProperty(PeopertyChangedEvent);
FName PropertyName = (PeopertyChangedEvent.Property != nullptr) ? PeopertyChangedEvent.Property->GetFName() : NAME_None;
// Responses to the uproperty changes
if (PropertyName == GET_MEMBER_NAME_CHECKED(UHoudiniSplineComponent, bClosed))
{
UE_LOG(LogTemp, Warning, TEXT("UPROPERTY Changed : bClosed"));
MarkChanged(true);
}
if (PropertyName == GET_MEMBER_NAME_CHECKED(UHoudiniSplineComponent, bReversed))
{
UE_LOG(LogTemp, Warning, TEXT("UPROPERTY Changed : bReversed"));
ReverseCurvePoints();
MarkChanged(true);
}
if (PropertyName == GET_MEMBER_NAME_CHECKED(UHoudiniSplineComponent, CurveType))
{
UE_LOG(LogTemp, Warning, TEXT("UPROPERTY Changed : CurveType"));
MarkChanged(true);
}
if (PropertyName == GET_MEMBER_NAME_CHECKED(UHoudiniSplineComponent, CurveMethod))
{
UE_LOG(LogTemp, Warning, TEXT("UPROPERTY Changed : CurveMethod"));
MarkChanged(true);
}
}
#endif
void
UHoudiniSplineComponent::PostLoad()
{
Super::PostLoad();
}
TStructOnScope<FActorComponentInstanceData>
UHoudiniSplineComponent::GetComponentInstanceData() const
{
TStructOnScope<FActorComponentInstanceData> ComponentInstanceData = MakeStructOnScope<FActorComponentInstanceData, FHoudiniSplineComponentInstanceData>(this);
FHoudiniSplineComponentInstanceData* InstanceData = ComponentInstanceData.Cast<FHoudiniSplineComponentInstanceData>();
return ComponentInstanceData;
}
void
UHoudiniSplineComponent::ApplyComponentInstanceData(
FHoudiniSplineComponentInstanceData* ComponentInstanceData, const bool bPostUCS)
{
check(ComponentInstanceData);
}
void
UHoudiniSplineComponent::CopyPropertiesFrom(UObject* FromObject)
{
// Capture properties that we want to preserve during copy
const int32 PrevNodeId = NodeId;
UActorComponent* FromComponent = Cast<UActorComponent>(FromObject);
check(FromComponent);
UHoudiniSplineComponent* FromSplineComponent = Cast<UHoudiniSplineComponent>(FromObject);
if (FromSplineComponent)
{
CurvePoints = FromSplineComponent->CurvePoints;
DisplayPoints = FromSplineComponent->DisplayPoints;
DisplayPointIndexDivider = FromSplineComponent->DisplayPointIndexDivider;
#if WITH_EDITORONLY_DATA
EditedControlPointsIndexes = FromSplineComponent->EditedControlPointsIndexes;
#endif
HoudiniSplineName = FromSplineComponent->HoudiniSplineName;
bClosed = FromSplineComponent->bClosed;
bIsHoudiniSplineVisible = FromSplineComponent->bIsHoudiniSplineVisible;
CurveType = FromSplineComponent->CurveType;
CurveMethod = FromSplineComponent->CurveMethod;
bIsInputCurve = FromSplineComponent->bIsInputCurve;
bIsOutputCurve = FromSplineComponent->bIsOutputCurve;
bIsEditableOutputCurve = FromSplineComponent->bIsEditableOutputCurve;
bCookOnCurveChanged = FromSplineComponent->bCookOnCurveChanged;
bHasChanged = FromSplineComponent->bHasChanged;
bNeedsToTriggerUpdate = FromSplineComponent->bNeedsToTriggerUpdate;
}
// Restore properties that we want to preserve
NodeId = PrevNodeId;
}
void
UHoudiniSplineComponent::OnUnregister()
{
Super::OnUnregister();
}
void
UHoudiniSplineComponent::OnComponentCreated()
{
Super::OnComponentCreated();
}
void
UHoudiniSplineComponent::OnComponentDestroyed(bool bDestroyingHierarchy)
{
Super::OnComponentDestroyed(bDestroyingHierarchy);
if (IsInputCurve())
{
// This component can't just come out of nowhere and decide to delete an input object!
// We have rules and regulations for this sort of thing. Protocols to follow, forms to fill out, in triplicate!
// InputObject->MarkPendingKill();
// if(NodeId > -1)
// FHoudiniEngineRuntime::Get().MarkNodeIdAsPendingDelete(NodeId);
SetNodeId(-1); // Set nodeId to invalid for reconstruct on re-do
}
}
#if WITH_EDITOR
void
UHoudiniSplineComponent::PostEditUndo()
{
Super::PostEditUndo();
bPostUndo = true;
MarkChanged(true);
}
#endif
void
UHoudiniSplineComponent::SetOffset(const float& Offset)
{
for (int n = 0; n < CurvePoints.Num(); ++n)
CurvePoints[n].AddToTranslation(FVector(0.f, Offset, 0.f));
for (int n = 0; n < DisplayPoints.Num(); ++n)
DisplayPoints[n] += FVector(0.f, Offset, 0.f);
}
void
UHoudiniSplineComponent::ResetCurvePoints()
{
CurvePoints.Empty();
}
void
UHoudiniSplineComponent::ResetDisplayPoints()
{
DisplayPoints.Empty();
}
void
UHoudiniSplineComponent::AddCurvePoints(const TArray<FTransform>& Points)
{
CurvePoints.Append(Points);
}
void
UHoudiniSplineComponent::AddDisplayPoints(const TArray<FVector>& Points)
{
DisplayPoints.Append(Points);
}
bool
UHoudiniSplineComponent::NeedsToTriggerUpdate() const
{
return bNeedsToTriggerUpdate;
}
void UHoudiniSplineComponent::SetNeedsToTriggerUpdate(const bool& NeedsToTriggerUpdate)
{
bNeedsToTriggerUpdate = NeedsToTriggerUpdate;
}
void UHoudiniSplineComponent::SetCurveType(const EHoudiniCurveType & NewCurveType)
{
CurveType = NewCurveType;
}
bool UHoudiniSplineComponent::HasChanged() const
{
return bHasChanged;
}
void UHoudiniSplineComponent::MarkChanged(const bool& Changed)
{
bHasChanged = Changed;
bNeedsToTriggerUpdate = Changed;
}
FHoudiniSplineComponentInstanceData::FHoudiniSplineComponentInstanceData()
{
}
FHoudiniSplineComponentInstanceData::FHoudiniSplineComponentInstanceData(const UHoudiniSplineComponent* SourceComponent)
: FActorComponentInstanceData(SourceComponent)
{
}