436 lines
13 KiB
C++
436 lines
13 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 "HoudiniAssetParameterChoice.h"
|
|
|
|
#include "HoudiniApi.h"
|
|
#include "HoudiniEngineRuntimePrivatePCH.h"
|
|
#include "HoudiniAssetComponent.h"
|
|
#include "HoudiniEngine.h"
|
|
#include "HoudiniEngineUtils.h"
|
|
#include "HoudiniEngineString.h"
|
|
|
|
#include "Misc/Variant.h"
|
|
#include "Internationalization/Internationalization.h"
|
|
#define LOCTEXT_NAMESPACE HOUDINI_LOCTEXT_NAMESPACE
|
|
|
|
UHoudiniAssetParameterChoice::UHoudiniAssetParameterChoice( const FObjectInitializer & ObjectInitializer )
|
|
: Super( ObjectInitializer )
|
|
, CurrentValue( 0 )
|
|
, bStringChoiceList( false )
|
|
{
|
|
StringValue = TEXT( "" );
|
|
}
|
|
|
|
UHoudiniAssetParameterChoice *
|
|
UHoudiniAssetParameterChoice::Create(
|
|
UObject * InPrimaryObject,
|
|
UHoudiniAssetParameter * InParentParameter,
|
|
HAPI_NodeId InNodeId,
|
|
const HAPI_ParmInfo & ParmInfo )
|
|
{
|
|
UObject * Outer = InPrimaryObject;
|
|
if ( !Outer )
|
|
{
|
|
Outer = InParentParameter;
|
|
if ( !Outer )
|
|
{
|
|
// Must have either component or parent not null.
|
|
check( false );
|
|
}
|
|
}
|
|
|
|
UHoudiniAssetParameterChoice * HoudiniAssetParameterChoice = NewObject<UHoudiniAssetParameterChoice>(
|
|
Outer, UHoudiniAssetParameterChoice::StaticClass(), NAME_None, RF_Public | RF_Transactional );
|
|
|
|
HoudiniAssetParameterChoice->CreateParameter( InPrimaryObject, InParentParameter, InNodeId, ParmInfo );
|
|
return HoudiniAssetParameterChoice;
|
|
}
|
|
|
|
bool
|
|
UHoudiniAssetParameterChoice::CreateParameter(
|
|
UObject * InPrimaryObject,
|
|
UHoudiniAssetParameter * InParentParameter,
|
|
HAPI_NodeId InNodeId,
|
|
const HAPI_ParmInfo & ParmInfo )
|
|
{
|
|
if ( !Super::CreateParameter( InPrimaryObject, InParentParameter, InNodeId, ParmInfo ) )
|
|
return false;
|
|
|
|
// Choice lists can be only integer or string.
|
|
if ( ParmInfo.type != HAPI_PARMTYPE_INT && ParmInfo.type != HAPI_PARMTYPE_STRING )
|
|
return false;
|
|
|
|
// Get the actual value for this property.
|
|
CurrentValue = 0;
|
|
|
|
if ( ParmInfo.type == HAPI_PARMTYPE_INT )
|
|
{
|
|
// This is an integer choice list.
|
|
bStringChoiceList = false;
|
|
|
|
// Assign internal Hapi values index.
|
|
SetValuesIndex( ParmInfo.intValuesIndex );
|
|
|
|
if ( FHoudiniApi::GetParmIntValues(
|
|
FHoudiniEngine::Get().GetSession(), NodeId, &CurrentValue,
|
|
ValuesIndex, TupleSize) != HAPI_RESULT_SUCCESS )
|
|
{
|
|
return false;
|
|
}
|
|
if( CurrentValue >= ParmInfo.choiceCount )
|
|
{
|
|
HOUDINI_LOG_WARNING(TEXT("parm '%s' has an invalid value %d, menu tokens are not supported for choice menus"), *GetParameterName(), CurrentValue);
|
|
CurrentValue = 0;
|
|
}
|
|
}
|
|
else if ( ParmInfo.type == HAPI_PARMTYPE_STRING )
|
|
{
|
|
// This is a string choice list.
|
|
bStringChoiceList = true;
|
|
|
|
// Assign internal Hapi values index.
|
|
SetValuesIndex( ParmInfo.stringValuesIndex );
|
|
|
|
HAPI_StringHandle StringHandle;
|
|
if ( FHoudiniApi::GetParmStringValues(
|
|
FHoudiniEngine::Get().GetSession(), NodeId, false,
|
|
&StringHandle, ValuesIndex, TupleSize ) != HAPI_RESULT_SUCCESS )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Get the actual string value.
|
|
FHoudiniEngineString HoudiniEngineString( StringHandle );
|
|
if ( !HoudiniEngineString.ToFString( StringValue ) )
|
|
return false;
|
|
}
|
|
|
|
// Get choice descriptors.
|
|
TArray< HAPI_ParmChoiceInfo > ParmChoices;
|
|
ParmChoices.SetNumUninitialized( ParmInfo.choiceCount );
|
|
for (int32 Idx = 0; Idx < ParmChoices.Num(); Idx++)
|
|
FHoudiniApi::ParmChoiceInfo_Init(&(ParmChoices[Idx]));
|
|
|
|
if ( FHoudiniApi::GetParmChoiceLists(
|
|
FHoudiniEngine::Get().GetSession(), NodeId, &ParmChoices[ 0 ],
|
|
ParmInfo.choiceIndex, ParmInfo.choiceCount ) != HAPI_RESULT_SUCCESS )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Get string values for all available choices.
|
|
StringChoiceValues.Empty();
|
|
StringChoiceLabels.Empty();
|
|
|
|
bool bMatchedSelectionLabel = false;
|
|
for ( int32 ChoiceIdx = 0; ChoiceIdx < ParmChoices.Num(); ++ChoiceIdx )
|
|
{
|
|
FString * ChoiceValue = new FString();
|
|
FString * ChoiceLabel = new FString();
|
|
|
|
{
|
|
FHoudiniEngineString HoudiniEngineString( ParmChoices[ ChoiceIdx ].valueSH );
|
|
if ( !HoudiniEngineString.ToFString( *ChoiceValue ) )
|
|
return false;
|
|
|
|
StringChoiceValues.Add( TSharedPtr< FString >( ChoiceValue ) );
|
|
}
|
|
|
|
{
|
|
FHoudiniEngineString HoudiniEngineString( ParmChoices[ ChoiceIdx ].labelSH );
|
|
if ( !HoudiniEngineString.ToFString( *ChoiceLabel ) )
|
|
return false;
|
|
|
|
StringChoiceLabels.Add( TSharedPtr< FString >( ChoiceLabel ) );
|
|
}
|
|
|
|
// If this is a string choice list, we need to match name with corresponding selection label.
|
|
if ( bStringChoiceList && !bMatchedSelectionLabel && ChoiceValue->Equals( StringValue ) )
|
|
{
|
|
StringValue = *ChoiceLabel;
|
|
bMatchedSelectionLabel = true;
|
|
CurrentValue = ChoiceIdx;
|
|
}
|
|
else if ( !bStringChoiceList && ChoiceIdx == CurrentValue )
|
|
{
|
|
StringValue = *ChoiceLabel;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
TOptional< TSharedPtr< FString > >
|
|
UHoudiniAssetParameterChoice::GetValue( int32 Idx ) const
|
|
{
|
|
if ( Idx == 0 && StringChoiceValues.IsValidIndex(CurrentValue) )
|
|
return TOptional< TSharedPtr< FString > >( StringChoiceValues[ CurrentValue ] );
|
|
|
|
return TOptional< TSharedPtr< FString > >();
|
|
}
|
|
|
|
int32
|
|
UHoudiniAssetParameterChoice::GetParameterValueInt() const
|
|
{
|
|
return CurrentValue;
|
|
}
|
|
|
|
const FString &
|
|
UHoudiniAssetParameterChoice::GetParameterValueString() const
|
|
{
|
|
return StringValue;
|
|
}
|
|
|
|
bool
|
|
UHoudiniAssetParameterChoice::IsStringChoiceList() const
|
|
{
|
|
return bStringChoiceList;
|
|
}
|
|
|
|
void
|
|
UHoudiniAssetParameterChoice::SetValueInt( int32 Value, bool bTriggerModify, bool bRecordUndo )
|
|
{
|
|
#if WITH_EDITOR
|
|
|
|
FScopedTransaction Transaction(
|
|
TEXT( HOUDINI_MODULE_RUNTIME ),
|
|
LOCTEXT( "HoudiniAssetParameterChoiceChange", "Houdini Parameter Choice: Changing a value" ),
|
|
PrimaryObject );
|
|
Modify();
|
|
|
|
if ( !bRecordUndo )
|
|
Transaction.Cancel();
|
|
|
|
#endif // WITH_EDITOR
|
|
|
|
CurrentValue = Value;
|
|
|
|
MarkChanged( bTriggerModify );
|
|
}
|
|
|
|
bool
|
|
UHoudiniAssetParameterChoice::UploadParameterValue()
|
|
{
|
|
if ( bStringChoiceList )
|
|
{
|
|
// Get corresponding value.
|
|
FString* ChoiceValue = StringChoiceValues.IsValidIndex(CurrentValue) ? StringChoiceValues[ CurrentValue ].Get() : nullptr;
|
|
std::string String = TCHAR_TO_UTF8( *( *ChoiceValue ) );
|
|
FHoudiniApi::SetParmStringValue( FHoudiniEngine::Get().GetSession(), NodeId, String.c_str(), ParmId, 0 );
|
|
}
|
|
else
|
|
{
|
|
// This is an int choice list.
|
|
FHoudiniApi::SetParmIntValues( FHoudiniEngine::Get().GetSession(), NodeId, &CurrentValue, ValuesIndex, TupleSize );
|
|
}
|
|
|
|
return Super::UploadParameterValue();
|
|
}
|
|
|
|
bool
|
|
UHoudiniAssetParameterChoice::SetParameterVariantValue( const FVariant & Variant, int32 Idx, bool bTriggerModify, bool bRecordUndo )
|
|
{
|
|
EVariantTypes VariantType = Variant.GetType();
|
|
int32 VariantValue = 0;
|
|
|
|
switch ( VariantType )
|
|
{
|
|
case EVariantTypes::String:
|
|
{
|
|
if ( bStringChoiceList )
|
|
{
|
|
bool bLabelFound = false;
|
|
const FString & VariantStringValue = Variant.GetValue< FString >();
|
|
|
|
// We need to match selection based on label.
|
|
int32 LabelIdx = 0;
|
|
for ( ; LabelIdx < StringChoiceLabels.Num(); ++LabelIdx )
|
|
{
|
|
FString * ChoiceLabel = StringChoiceLabels[ LabelIdx ].Get();
|
|
|
|
if ( ChoiceLabel->Equals( VariantStringValue ) )
|
|
{
|
|
VariantValue = LabelIdx;
|
|
bLabelFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !bLabelFound )
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case EVariantTypes::Int8:
|
|
case EVariantTypes::Int16:
|
|
case EVariantTypes::Int32:
|
|
case EVariantTypes::Int64:
|
|
case EVariantTypes::UInt8:
|
|
case EVariantTypes::UInt16:
|
|
case EVariantTypes::UInt32:
|
|
case EVariantTypes::UInt64:
|
|
{
|
|
if ( CurrentValue >= 0 && CurrentValue < StringChoiceValues.Num() )
|
|
{
|
|
VariantValue = Variant.GetValue< int32 >();
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
|
|
FScopedTransaction Transaction(
|
|
TEXT( HOUDINI_MODULE_RUNTIME ),
|
|
LOCTEXT( "HoudiniAssetParameterChoiceChange", "Houdini Parameter Choice: Changing a value" ),
|
|
PrimaryObject );
|
|
|
|
Modify();
|
|
|
|
if ( !bRecordUndo )
|
|
Transaction.Cancel();
|
|
|
|
#endif // WITH_EDITOR
|
|
|
|
CurrentValue = VariantValue;
|
|
MarkChanged( bTriggerModify );
|
|
|
|
return false;
|
|
}
|
|
|
|
void
|
|
UHoudiniAssetParameterChoice::Serialize( FArchive & Ar )
|
|
{
|
|
// Call base implementation.
|
|
Super::Serialize( Ar );
|
|
|
|
Ar.UsingCustomVersion( FHoudiniCustomSerializationVersion::GUID );
|
|
|
|
if ( Ar.IsLoading() )
|
|
{
|
|
StringChoiceValues.Empty();
|
|
StringChoiceLabels.Empty();
|
|
}
|
|
|
|
int32 NumChoices = StringChoiceValues.Num();
|
|
Ar << NumChoices;
|
|
|
|
int32 NumLabels = StringChoiceLabels.Num();
|
|
Ar << NumLabels;
|
|
|
|
if ( Ar.IsSaving() )
|
|
{
|
|
for ( int32 ChoiceIdx = 0; ChoiceIdx < StringChoiceValues.Num(); ++ChoiceIdx )
|
|
Ar << *( StringChoiceValues[ ChoiceIdx ].Get() );
|
|
|
|
for ( int32 LabelIdx = 0; LabelIdx < StringChoiceLabels.Num(); ++LabelIdx )
|
|
Ar << *( StringChoiceLabels[ LabelIdx ].Get() );
|
|
}
|
|
else if ( Ar.IsLoading() )
|
|
{
|
|
FString Temp;
|
|
|
|
for ( int32 ChoiceIdx = 0; ChoiceIdx < NumChoices; ++ChoiceIdx )
|
|
{
|
|
Ar << Temp;
|
|
FString * ChoiceName = new FString( Temp );
|
|
StringChoiceValues.Add( TSharedPtr< FString >( ChoiceName ) );
|
|
}
|
|
|
|
for ( int32 LabelIdx = 0; LabelIdx < NumLabels; ++LabelIdx )
|
|
{
|
|
Ar << Temp;
|
|
FString * ChoiceLabel = new FString( Temp );
|
|
StringChoiceLabels.Add( TSharedPtr< FString >( ChoiceLabel ) );
|
|
}
|
|
}
|
|
|
|
Ar << StringValue;
|
|
Ar << CurrentValue;
|
|
|
|
Ar << bStringChoiceList;
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
|
|
void
|
|
UHoudiniAssetParameterChoice::OnChoiceChange( TSharedPtr< FString > NewChoice )
|
|
{
|
|
bool bLocalChanged = false;
|
|
StringValue = *( NewChoice.Get() );
|
|
|
|
// We need to match selection based on label.
|
|
int32 LabelIdx = 0;
|
|
for ( ; LabelIdx < StringChoiceLabels.Num(); ++LabelIdx )
|
|
{
|
|
FString * ChoiceLabel = StringChoiceLabels[ LabelIdx ].Get();
|
|
|
|
if ( ChoiceLabel->Equals( StringValue ) )
|
|
{
|
|
bLocalChanged = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( bLocalChanged )
|
|
{
|
|
// Record undo information.
|
|
FScopedTransaction Transaction(
|
|
TEXT( HOUDINI_MODULE_RUNTIME ),
|
|
LOCTEXT( "HoudiniAssetParameterChoiceChange", "Houdini Parameter Choice: Changing a value" ),
|
|
PrimaryObject );
|
|
Modify();
|
|
|
|
CurrentValue = LabelIdx;
|
|
|
|
// Mark this property as changed.
|
|
MarkChanged();
|
|
}
|
|
}
|
|
|
|
FText
|
|
UHoudiniAssetParameterChoice::HandleChoiceContentText() const
|
|
{
|
|
return FText::FromString( StringValue );
|
|
}
|
|
|
|
#endif // WITH_EDITOR
|
|
|
|
#undef LOCTEXT_NAMESPACE |