/* * 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(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(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( 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(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(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