433 lines
11 KiB
C++
433 lines
11 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.
|
|
*
|
|
* Produced by:
|
|
* Mykola Konyk
|
|
* Side Effects Software Inc
|
|
* 123 Front Street West, Suite 1401
|
|
* Toronto, Ontario
|
|
* Canada M5J 2M2
|
|
* 416-504-9876
|
|
*
|
|
*/
|
|
|
|
#include "HoudiniSplineComponent.h"
|
|
|
|
#include "HoudiniApi.h"
|
|
#include "HoudiniEngineRuntimePrivatePCH.h"
|
|
#include "HoudiniAssetComponent.h"
|
|
#include "HoudiniAssetInput.h"
|
|
#include "HoudiniEngineUtils.h"
|
|
#include "HoudiniEngine.h"
|
|
#include "HoudiniPluginSerializationVersion.h"
|
|
|
|
UHoudiniSplineComponent::UHoudiniSplineComponent( const FObjectInitializer & ObjectInitializer )
|
|
: Super( ObjectInitializer )
|
|
, HoudiniAssetInput( nullptr )
|
|
, CurveType( EHoudiniSplineComponentType::Polygon )
|
|
, CurveMethod( EHoudiniSplineComponentMethod::Breakpoints )
|
|
, bClosedCurve( false )
|
|
{
|
|
// By default we will create two points.
|
|
FTransform transf = FTransform::Identity;
|
|
CurvePoints.Add( transf );
|
|
transf.SetTranslation( FVector(200.0f, 0.0f, 0.0f) );
|
|
CurvePoints.Add( transf );
|
|
|
|
// Change the default mobility to static to avoid modifying the parent HAC's mobility to Moveable
|
|
Mobility = EComponentMobility::Static;
|
|
}
|
|
|
|
UHoudiniSplineComponent::~UHoudiniSplineComponent()
|
|
{}
|
|
|
|
void
|
|
UHoudiniSplineComponent::Serialize( FArchive & Ar )
|
|
{
|
|
Super::Serialize( Ar );
|
|
|
|
Ar.UsingCustomVersion( FHoudiniCustomSerializationVersion::GUID );
|
|
|
|
int32 Version = VER_HOUDINI_PLUGIN_SERIALIZATION_AUTOMATIC_VERSION;
|
|
Ar << Version;
|
|
|
|
Ar << HoudiniGeoPartObject;
|
|
|
|
if (Version < VER_HOUDINI_PLUGIN_SERIALIZATION_HOUDINI_SPLINE_TO_TRANSFORM)
|
|
{
|
|
// Before, curve points where stored as Vectors, not Transforms
|
|
TArray<FVector> OldCurvePoints;
|
|
Ar << OldCurvePoints;
|
|
|
|
CurvePoints.SetNumUninitialized(OldCurvePoints.Num());
|
|
|
|
FTransform trans = FTransform::Identity;
|
|
for (int32 n = 0; n < CurvePoints.Num(); n++)
|
|
{
|
|
trans.SetLocation(OldCurvePoints[n]);
|
|
CurvePoints[n] = trans;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Ar << CurvePoints;
|
|
}
|
|
|
|
Ar << CurveDisplayPoints;
|
|
|
|
SerializeEnumeration< EHoudiniSplineComponentType::Enum >( Ar, CurveType );
|
|
SerializeEnumeration< EHoudiniSplineComponentMethod::Enum >( Ar, CurveMethod );
|
|
Ar << bClosedCurve;
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
|
|
void
|
|
UHoudiniSplineComponent::PostEditUndo()
|
|
{
|
|
Super::PostEditUndo();
|
|
|
|
UpdateHoudiniComponents();
|
|
}
|
|
|
|
#endif // WITH_EDITOR
|
|
|
|
bool
|
|
UHoudiniSplineComponent::Construct(
|
|
const FHoudiniGeoPartObject & InHoudiniGeoPartObject,
|
|
const TArray< FTransform > & InCurvePoints,
|
|
const TArray< FVector > & InCurveDisplayPoints,
|
|
EHoudiniSplineComponentType::Enum InCurveType,
|
|
EHoudiniSplineComponentMethod::Enum InCurveMethod,
|
|
bool bInClosedCurve )
|
|
{
|
|
ResetCurvePoints();
|
|
AddPoints( InCurvePoints );
|
|
|
|
return Construct(
|
|
InHoudiniGeoPartObject,
|
|
InCurveDisplayPoints,
|
|
InCurveType,
|
|
InCurveMethod,
|
|
bInClosedCurve );
|
|
}
|
|
|
|
|
|
bool
|
|
UHoudiniSplineComponent::Construct(
|
|
const FHoudiniGeoPartObject & InHoudiniGeoPartObject,
|
|
const TArray< FVector > & InCurveDisplayPoints,
|
|
EHoudiniSplineComponentType::Enum InCurveType,
|
|
EHoudiniSplineComponentMethod::Enum InCurveMethod,
|
|
bool bInClosedCurve)
|
|
{
|
|
HoudiniGeoPartObject = InHoudiniGeoPartObject;
|
|
|
|
ResetCurveDisplayPoints();
|
|
AddDisplayPoints(InCurveDisplayPoints);
|
|
|
|
CurveType = InCurveType;
|
|
CurveMethod = InCurveMethod;
|
|
bClosedCurve = bInClosedCurve;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void
|
|
UHoudiniSplineComponent::SetHoudiniGeoPartObject( const FHoudiniGeoPartObject& InHoudiniGeoPartObject )
|
|
{
|
|
HoudiniGeoPartObject = InHoudiniGeoPartObject;
|
|
}
|
|
|
|
|
|
bool
|
|
UHoudiniSplineComponent::CopyFrom( UHoudiniSplineComponent* InSplineComponent )
|
|
{
|
|
if (!InSplineComponent || InSplineComponent->IsPendingKill() )
|
|
return false;
|
|
|
|
HoudiniGeoPartObject = FHoudiniGeoPartObject(InSplineComponent->HoudiniGeoPartObject);
|
|
|
|
ResetCurvePoints();
|
|
AddPoints(InSplineComponent->GetCurvePoints());
|
|
|
|
ResetCurveDisplayPoints();
|
|
AddDisplayPoints(InSplineComponent->CurveDisplayPoints);
|
|
|
|
CurveType = InSplineComponent->GetCurveType();
|
|
CurveMethod = InSplineComponent->GetCurveMethod();
|
|
bClosedCurve = InSplineComponent->IsClosedCurve();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
EHoudiniSplineComponentType::Enum
|
|
UHoudiniSplineComponent::GetCurveType() const
|
|
{
|
|
return CurveType;
|
|
}
|
|
|
|
EHoudiniSplineComponentMethod::Enum
|
|
UHoudiniSplineComponent::GetCurveMethod() const
|
|
{
|
|
return CurveMethod;
|
|
}
|
|
|
|
int32
|
|
UHoudiniSplineComponent::GetCurvePointCount() const
|
|
{
|
|
return CurvePoints.Num();
|
|
}
|
|
|
|
bool
|
|
UHoudiniSplineComponent::IsClosedCurve() const
|
|
{
|
|
return bClosedCurve;
|
|
}
|
|
|
|
void
|
|
UHoudiniSplineComponent::ResetCurvePoints()
|
|
{
|
|
CurvePoints.Empty();
|
|
}
|
|
|
|
void
|
|
UHoudiniSplineComponent::ResetCurveDisplayPoints()
|
|
{
|
|
CurveDisplayPoints.Empty();
|
|
}
|
|
|
|
void
|
|
UHoudiniSplineComponent::AddPoint( const FTransform & Point )
|
|
{
|
|
CurvePoints.Add( Point );
|
|
}
|
|
|
|
void
|
|
UHoudiniSplineComponent::AddPoints( const TArray< FTransform > & Points )
|
|
{
|
|
CurvePoints.Append( Points );
|
|
}
|
|
|
|
void
|
|
UHoudiniSplineComponent::AddDisplayPoints( const TArray< FVector > & Points )
|
|
{
|
|
CurveDisplayPoints.Append( Points );
|
|
}
|
|
|
|
bool
|
|
UHoudiniSplineComponent::IsValidCurve() const
|
|
{
|
|
if ( CurvePoints.Num() < 2 )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
UHoudiniSplineComponent::UpdatePoint( int32 PointIndex, const FTransform & Point )
|
|
{
|
|
check( PointIndex >= 0 && PointIndex < CurvePoints.Num() );
|
|
CurvePoints[ PointIndex ] = Point;
|
|
}
|
|
|
|
void
|
|
UHoudiniSplineComponent::UploadControlPoints()
|
|
{
|
|
HAPI_NodeId HostAssetId = -1;
|
|
HAPI_NodeId NodeId = -1;
|
|
if (HoudiniGeoPartObject.IsValid())
|
|
{
|
|
if ( IsInputCurve() )
|
|
{
|
|
HostAssetId = HoudiniAssetInput->GetConnectedAssetId();
|
|
NodeId = HoudiniGeoPartObject.HapiGeoGetNodeId();
|
|
}
|
|
else
|
|
{
|
|
// Grab component we are attached to.
|
|
UHoudiniAssetComponent * AttachedComponent = Cast< UHoudiniAssetComponent >( GetAttachParent() );
|
|
if ( AttachedComponent && !AttachedComponent->IsPendingKill() )
|
|
HostAssetId = AttachedComponent->GetAssetId();
|
|
|
|
NodeId = HoudiniGeoPartObject.HapiGeoGetNodeId( HostAssetId );
|
|
}
|
|
}
|
|
|
|
if ( ( NodeId < 0 ) || ( HostAssetId < 0 ) )
|
|
return;
|
|
|
|
// Extract positions rotations and scales and upload them to the curve node
|
|
TArray<FVector> Positions;
|
|
GetCurvePositions(Positions);
|
|
|
|
if ( IsInputCurve() )
|
|
{
|
|
// Only input curves support rotation and scale
|
|
TArray<FQuat> Rotations;
|
|
GetCurveRotations(Rotations);
|
|
|
|
TArray<FVector> Scales;
|
|
GetCurveScales(Scales);
|
|
|
|
FHoudiniEngineUtils::HapiCreateCurveInputNodeForData(
|
|
HostAssetId,
|
|
NodeId,
|
|
&Positions,
|
|
&Rotations,
|
|
&Scales,
|
|
nullptr);
|
|
|
|
// We need to cook the spline node.
|
|
FHoudiniApi::CookNode(FHoudiniEngine::Get().GetSession(), NodeId, nullptr);
|
|
}
|
|
else
|
|
{
|
|
FString PositionString = TEXT("");
|
|
FHoudiniEngineUtils::CreatePositionsString(Positions, PositionString);
|
|
|
|
// Get param id.
|
|
HAPI_ParmId ParmId = -1;
|
|
if (FHoudiniApi::GetParmIdFromName(
|
|
FHoudiniEngine::Get().GetSession(), NodeId,
|
|
HAPI_UNREAL_PARAM_CURVE_COORDS, &ParmId) != HAPI_RESULT_SUCCESS)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Update the new point positions
|
|
std::string ConvertedString = TCHAR_TO_UTF8(*PositionString);
|
|
if (FHoudiniApi::SetParmStringValue(
|
|
FHoudiniEngine::Get().GetSession(), NodeId,
|
|
ConvertedString.c_str(), ParmId, 0) != HAPI_RESULT_SUCCESS)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
UHoudiniSplineComponent::UpdateHoudiniComponents()
|
|
{
|
|
if ( IsInputCurve() )
|
|
{
|
|
if ( HoudiniAssetInput && !HoudiniAssetInput->IsPendingKill() )
|
|
HoudiniAssetInput->OnInputCurveChanged();
|
|
}
|
|
else
|
|
{
|
|
// If not an input curve, we need first to upload the new CVs
|
|
UploadControlPoints();
|
|
|
|
#if WITH_EDITOR
|
|
UHoudiniAssetComponent * HoudiniAssetComponent = Cast< UHoudiniAssetComponent >( GetAttachParent() );
|
|
if ( HoudiniAssetComponent && !HoudiniAssetComponent->IsPendingKill() )
|
|
HoudiniAssetComponent->NotifyHoudiniSplineChanged( this );
|
|
#endif
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
if ( GEditor )
|
|
GEditor->RedrawLevelEditingViewports( true );
|
|
#endif
|
|
}
|
|
|
|
void
|
|
UHoudiniSplineComponent::RemovePoint( int32 PointIndex )
|
|
{
|
|
check( PointIndex >= 0 && PointIndex < CurvePoints.Num() );
|
|
CurvePoints.RemoveAt( PointIndex );
|
|
}
|
|
|
|
void
|
|
UHoudiniSplineComponent::AddPoint( int32 PointIndex, const FTransform & Point )
|
|
{
|
|
check( PointIndex >= 0 && PointIndex < CurvePoints.Num() );
|
|
CurvePoints.Insert( Point, PointIndex );
|
|
}
|
|
|
|
bool
|
|
UHoudiniSplineComponent::IsInputCurve() const
|
|
{
|
|
return ( HoudiniAssetInput && !HoudiniAssetInput->IsPendingKill() );
|
|
}
|
|
|
|
void
|
|
UHoudiniSplineComponent::SetHoudiniAssetInput( UHoudiniAssetInput * InHoudiniAssetInput )
|
|
{
|
|
if ( !InHoudiniAssetInput || InHoudiniAssetInput->IsPendingKill() )
|
|
HoudiniAssetInput = nullptr;
|
|
else
|
|
HoudiniAssetInput = InHoudiniAssetInput;
|
|
}
|
|
|
|
|
|
const TArray< FTransform > &
|
|
UHoudiniSplineComponent::GetCurvePoints() const
|
|
{
|
|
return CurvePoints;
|
|
}
|
|
|
|
|
|
void
|
|
UHoudiniSplineComponent::GetCurvePositions(TArray<FVector>& Positions) const
|
|
{
|
|
Positions.SetNumUninitialized(CurvePoints.Num());
|
|
for (int32 n = 0; n < CurvePoints.Num(); n++)
|
|
{
|
|
Positions[n] = CurvePoints[n].GetLocation();
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
UHoudiniSplineComponent::GetCurveRotations(TArray<FQuat>& Rotations) const
|
|
{
|
|
Rotations.SetNumUninitialized(CurvePoints.Num());
|
|
for (int32 n = 0; n < CurvePoints.Num(); n++)
|
|
{
|
|
Rotations[n] = CurvePoints[n].GetRotation();
|
|
}
|
|
}
|
|
|
|
void
|
|
UHoudiniSplineComponent::GetCurveScales(TArray<FVector>& Scales) const
|
|
{
|
|
Scales.SetNumUninitialized(CurvePoints.Num());
|
|
for (int32 n = 0; n < CurvePoints.Num(); n++)
|
|
{
|
|
Scales[n] = CurvePoints[n].GetScale3D();
|
|
}
|
|
}
|
|
|
|
bool
|
|
UHoudiniSplineComponent::IsActive() const
|
|
{
|
|
if ( HoudiniAssetInput && !HoudiniAssetInput->IsPendingKill() )
|
|
{
|
|
if ( !HoudiniAssetInput->IsCurveAssetConnected() )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
} |