Files

570 lines
14 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 "HoudiniAssetParameter.h"
#include "HoudiniApi.h"
#include "HoudiniEngineRuntimePrivatePCH.h"
#include "HoudiniEngineUtils.h"
#include "HoudiniAssetComponent.h"
#include "HoudiniEngine.h"
#include "HoudiniAssetParameterMultiparm.h"
#include "HoudiniAssetParameterRamp.h"
#include "HoudiniPluginSerializationVersion.h"
#include "HoudiniEngineString.h"
#include "Misc/Variant.h"
#include "Internationalization/Internationalization.h"
#define LOCTEXT_NAMESPACE HOUDINI_LOCTEXT_NAMESPACE
uint32
GetTypeHash( const UHoudiniAssetParameter * HoudiniAssetParameter )
{
if ( HoudiniAssetParameter )
return HoudiniAssetParameter->GetTypeHash();
return 0;
}
UHoudiniAssetParameter::UHoudiniAssetParameter( const FObjectInitializer & ObjectInitializer )
: Super( ObjectInitializer )
, PrimaryObject( nullptr )
, ParentParameter( nullptr )
, NodeId( -1 )
, ParmId( -1 )
, ParmParentId( -1 )
, ChildIndex( 0 )
, TupleSize( 1 )
, ValuesIndex( -1 )
, MultiparmInstanceIndex( -1 )
, ActiveChildParameter( 0 )
, HoudiniAssetParameterFlagsPacked( 0u )
, HoudiniAssetParameterVersion( VER_HOUDINI_PLUGIN_SERIALIZATION_VERSION_BASE )
{
ParameterName = TEXT( "" );
ParameterLabel = TEXT( "" );
ParameterHelp = TEXT( "" );
}
bool
UHoudiniAssetParameter::CreateParameter(
UObject * InPrimaryObject,
UHoudiniAssetParameter * InParentParameter,
HAPI_NodeId InNodeId,
const HAPI_ParmInfo & ParmInfo )
{
// We need to reset child parameters.
ResetChildParameters();
// If parameter has changed, we do not need to recreate it.
if ( bChanged )
return false;
// If parameter is invisible, we cannot create it.
if ( !IsVisible( ParmInfo ) )
return false;
// Set name and label.
if ( !SetNameAndLabel( ParmInfo ) )
return false;
// Set the help
if ( !SetHelp( ParmInfo ) )
return false;
// If it is a Substance parameter, mark it as such.
bIsSubstanceParameter = ParameterName.StartsWith( HAPI_UNREAL_PARAM_SUBSTANCE_PREFIX );
// Set ids.
SetNodeParmIds( InNodeId, ParmInfo.id );
// Set parent id.
ParmParentId = ParmInfo.parentId;
// Set the index within parent.
ChildIndex = ParmInfo.childIndex;
// Set tuple count.
TupleSize = ParmInfo.size;
// Set the multiparm instance index.
MultiparmInstanceIndex = ParmInfo.instanceNum;
// Set spare flag.
bIsSpare = ParmInfo.spare;
// Set disabled flag.
bIsDisabled = ParmInfo.disabled;
// Set child of multiparm flag.
bIsChildOfMultiparm = ParmInfo.isChildOfMultiParm;
// Set ismultiparmflag
bIsMultiparm = ( ParmInfo.type == HAPI_PARMTYPE_MULTIPARMLIST );
// Set component.
PrimaryObject = InPrimaryObject;
// Store parameter parent.
ParentParameter = InParentParameter;
return true;
}
UHoudiniAssetParameter *
UHoudiniAssetParameter::Duplicate( UObject* InOuter )
{
return DuplicateObject<UHoudiniAssetParameter>(this, InOuter );
}
void
UHoudiniAssetParameter::NotifyChildParameterChanged( UHoudiniAssetParameter * HoudiniAssetParameter )
{
// Default implementation does nothing.
}
void
UHoudiniAssetParameter::NotifyChildParametersCreated()
{
// Default implementation does nothing.
}
bool
UHoudiniAssetParameter::UploadParameterValue()
{
// Mark this parameter as no longer changed.
bChanged = false;
return true;
}
bool
UHoudiniAssetParameter::SetParameterVariantValue( const FVariant& Variant, int32 Idx, bool bTriggerModify, bool bRecordUndo )
{
// Default implementation does nothing.
return false;
}
bool
UHoudiniAssetParameter::HasChanged() const
{
return bChanged;
}
void
UHoudiniAssetParameter::SetHoudiniAssetComponent( UHoudiniAssetComponent * InComponent )
{
PrimaryObject = InComponent;
}
void
UHoudiniAssetParameter::SetParentParameter( UHoudiniAssetParameter * InParentParameter )
{
if ( ParentParameter != InParentParameter )
{
ParentParameter = InParentParameter;
if ( ParentParameter && !ParentParameter->IsPendingKill() )
{
// Retrieve parent parameter id. We ignore folder lists, they are artificial parents created by us.
ParmParentId = ParentParameter->GetParmId();
// Add this parameter to parent collection of child parameters.
ParentParameter->AddChildParameter( this );
}
else
{
// Reset parent parm id.
ParmParentId = -1;
}
}
}
bool
UHoudiniAssetParameter::IsChildParameter() const
{
return ParentParameter != nullptr;
}
void
UHoudiniAssetParameter::AddChildParameter( UHoudiniAssetParameter * HoudiniAssetParameter )
{
if ( HoudiniAssetParameter )
ChildParameters.Add( HoudiniAssetParameter );
}
uint32
UHoudiniAssetParameter::GetTypeHash() const
{
// We do hashing based on parameter name.
return ::GetTypeHash( ParameterName );
}
HAPI_ParmId
UHoudiniAssetParameter::GetParmId() const
{
return ParmId;
}
HAPI_ParmId
UHoudiniAssetParameter::GetParmParentId() const
{
return ParmParentId;
}
void
UHoudiniAssetParameter::AddReferencedObjects( UObject * InThis, FReferenceCollector & Collector )
{
UHoudiniAssetParameter * HoudiniAssetParameter = Cast< UHoudiniAssetParameter >( InThis );
if ( HoudiniAssetParameter )
{
if ( HoudiniAssetParameter->PrimaryObject && !HoudiniAssetParameter->PrimaryObject->IsPendingKill() )
Collector.AddReferencedObject( HoudiniAssetParameter->PrimaryObject, InThis );
}
// Call base implementation.
Super::AddReferencedObjects( InThis, Collector );
}
void
UHoudiniAssetParameter::Serialize( FArchive & Ar )
{
// Call base implementation.
Super::Serialize( Ar );
Ar.UsingCustomVersion( FHoudiniCustomSerializationVersion::GUID );
HoudiniAssetParameterVersion = VER_HOUDINI_PLUGIN_SERIALIZATION_AUTOMATIC_VERSION;
Ar << HoudiniAssetParameterVersion;
Ar << HoudiniAssetParameterFlagsPacked;
if ( Ar.IsLoading() )
bChanged = false;
Ar << ParameterName;
Ar << ParameterLabel;
Ar << NodeId;
if( !Ar.IsTransacting() && Ar.IsLoading() )
{
// NodeId is invalid after load
NodeId = -1;
}
Ar << ParmId;
Ar << ParmParentId;
Ar << ChildIndex;
Ar << TupleSize;
Ar << ValuesIndex;
Ar << MultiparmInstanceIndex;
if( HoudiniAssetParameterVersion >= VER_HOUDINI_ENGINE_PARAM_ASSET_INSTANCE_MEMBER )
{
UObject* Dummy = nullptr;
Ar << Dummy;
}
if ( HoudiniAssetParameterVersion >= VER_HOUDINI_PLUGIN_SERIALIZATION_VERSION_ADDED_PARAM_HELP )
{
Ar << ParameterHelp;
}
else
{
ParameterHelp = TEXT( "" );
}
if ( Ar.IsTransacting() )
{
Ar << PrimaryObject;
Ar << ParentParameter;
}
}
#if WITH_EDITOR
void
UHoudiniAssetParameter::PostEditUndo()
{
Super::PostEditUndo();
MarkChanged();
}
#endif // WITH_EDITOR
void
UHoudiniAssetParameter::SetNodeParmIds( HAPI_NodeId InNodeId, HAPI_ParmId InParmId )
{
NodeId = InNodeId;
ParmId = InParmId;
}
bool
UHoudiniAssetParameter::HasValidNodeParmIds() const
{
return ( NodeId != -1 ) && ( ParmId != -1 );
}
bool
UHoudiniAssetParameter::IsVisible( const HAPI_ParmInfo & ParmInfo ) const
{
return ParmInfo.invisible == false;
}
bool
UHoudiniAssetParameter::SetNameAndLabel( const HAPI_ParmInfo & ParmInfo )
{
FHoudiniEngineString HoudiniEngineStringName( ParmInfo.nameSH );
FHoudiniEngineString HoudiniEngineStringLabel( ParmInfo.labelSH );
bool bresult = true;
bresult |= HoudiniEngineStringName.ToFString( ParameterName );
bresult |= HoudiniEngineStringLabel.ToFString( ParameterLabel );
return bresult;
}
bool
UHoudiniAssetParameter::SetNameAndLabel( HAPI_StringHandle StringHandle )
{
FHoudiniEngineString HoudiniEngineString( StringHandle );
bool bresult = true;
bresult |= HoudiniEngineString.ToFString( ParameterName );
bresult |= HoudiniEngineString.ToFString( ParameterLabel );
return bresult;
}
bool
UHoudiniAssetParameter::SetNameAndLabel( const FString & Name )
{
ParameterName = Name;
ParameterLabel = Name;
return true;
}
bool
UHoudiniAssetParameter::SetHelp( const HAPI_ParmInfo & ParmInfo )
{
FHoudiniEngineString HoudiniEngineStringHelp( ParmInfo.helpSH );
bool bresult = true;
bresult = HoudiniEngineStringHelp.ToFString( ParameterHelp );
return bresult;
}
void
UHoudiniAssetParameter::MarkChanged( bool bMarkAndTriggerUpdate )
{
// Set changed flag.
bChanged = true;
#if WITH_EDITOR
// Notify component about change.
if( bMarkAndTriggerUpdate )
{
if( UHoudiniAssetComponent* Component = Cast<UHoudiniAssetComponent>(PrimaryObject) )
if ( !Component->IsPendingKill() )
Component->NotifyParameterChanged( this );
// Notify parent parameter about change.
if( ParentParameter && !ParentParameter->IsPendingKill() )
ParentParameter->NotifyChildParameterChanged( this );
}
#endif // WITH_EDITOR
}
void
UHoudiniAssetParameter::UnmarkChanged()
{
bChanged = false;
}
void
UHoudiniAssetParameter::ResetChildParameters()
{
ChildParameters.Empty();
}
int32
UHoudiniAssetParameter::GetTupleSize() const
{
return TupleSize;
}
bool
UHoudiniAssetParameter::IsArray() const
{
return TupleSize > 1;
}
void
UHoudiniAssetParameter::SetValuesIndex( int32 InValuesIndex )
{
ValuesIndex = InValuesIndex;
}
int32
UHoudiniAssetParameter::GetActiveChildParameter() const
{
return ActiveChildParameter;
}
void UHoudiniAssetParameter::OnParamStateChanged()
{
#if WITH_EDITOR
if( UHoudiniAssetComponent* Comp = Cast<UHoudiniAssetComponent>( PrimaryObject ) )
{
if ( !Comp->IsPendingKill() )
Comp->UpdateEditorProperties( false );
}
#endif
}
bool
UHoudiniAssetParameter::HasChildParameters() const
{
return ChildParameters.Num() > 0;
}
bool
UHoudiniAssetParameter::IsSubstanceParameter() const
{
return bIsSubstanceParameter;
}
bool
UHoudiniAssetParameter::IsActiveChildParameter( UHoudiniAssetParameter * ChildParam ) const
{
if (!ChildParam || ChildParam->IsPendingKill())
return false;
if (!ChildParameters.IsValidIndex(ActiveChildParameter))
return false;
return ChildParameters[ ActiveChildParameter ] == ChildParam;
}
UHoudiniAssetParameter *
UHoudiniAssetParameter::GetParentParameter() const
{
return ParentParameter;
}
const FString &
UHoudiniAssetParameter::GetParameterName() const
{
return ParameterName;
}
const FString &
UHoudiniAssetParameter::GetParameterLabel() const
{
return ParameterLabel;
}
const FString &
UHoudiniAssetParameter::GetParameterHelp() const
{
return ParameterHelp;
}
void
UHoudiniAssetParameter::SetNodeId( HAPI_NodeId InNodeId )
{
NodeId = InNodeId;
}
bool
UHoudiniAssetParameter::IsSpare() const
{
return bIsSpare;
}
bool
UHoudiniAssetParameter::IsDisabled() const
{
return bIsDisabled;
}
const UHoudiniAssetComponent *
UHoudiniAssetParameter::GetHoudiniAssetComponent() const
{
return Cast<UHoudiniAssetComponent>(PrimaryObject);
}
FReply
UHoudiniAssetParameter::OnRevertParmToDefault(int32 AtIndex)
{
#if WITH_EDITOR
bool bReverted = true;
if (AtIndex < 0 || AtIndex >= TupleSize)
{
// Revert the whole parameter to its default value
if (HAPI_RESULT_SUCCESS != FHoudiniApi::RevertParmToDefaults(
FHoudiniEngine::Get().GetSession(), NodeId, TCHAR_TO_UTF8(*ParameterName)))
{
HOUDINI_LOG_WARNING(TEXT("Failed to revert parameter %s to its default value."), *ParameterName);
bReverted = false;
}
}
else
{
// Revert the parameter to its default value
if (HAPI_RESULT_SUCCESS != FHoudiniApi::RevertParmToDefault(
FHoudiniEngine::Get().GetSession(), NodeId, TCHAR_TO_UTF8(*ParameterName), AtIndex))
{
HOUDINI_LOG_WARNING(TEXT("Failed to revert parameter %s to its default value."), *ParameterName);
bReverted = false;
}
}
if (bReverted)
{
// We need to manually notify of the value change to trigger an update,
// As calling MarkChanged() would also cause the value to be reuploaded to the non default value
// Notify component about change.
UHoudiniAssetComponent* Component = Cast<UHoudiniAssetComponent>(PrimaryObject);
if (Component && !Component->IsPendingKill())
Component->NotifyParameterChanged(this);
// Notify parent parameter about change.
if (ParentParameter && !ParentParameter->IsPendingKill())
ParentParameter->NotifyChildParameterChanged(this);
}
#endif // WITH_EDITOR
return FReply::Handled();
}
#undef LOCTEXT_NAMESPACE