Files
UnrealEngine/Engine/Plugins/Mutable/Source/CustomizableObject/Private/MuCO/CustomizableObjectInstanceDescriptor.cpp
2025-05-18 13:04:45 +08:00

2900 lines
94 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MuCO/CustomizableObjectInstanceDescriptor.h"
#include "MuCO/CustomizableObjectInstancePrivate.h"
#include "MuCO/CustomizableObjectSystemPrivate.h"
#include "MuCO/UnrealMutableImageProvider.h"
#include "MuCO/CustomizableObject.h"
#include "MuCO/CustomizableObjectPrivate.h"
#include "MuCO/MutableProjectorTypeUtils.h"
#include "MuR/Model.h"
#include "MuR/Parameters.h"
#include "MuR/Ptr.h"
#include "Engine/Texture2D.h"
#include "Engine/SkeletalMesh.h"
#if WITH_EDITOR
#include "Editor.h"
#endif
#include UE_INLINE_GENERATED_CPP_BY_NAME(CustomizableObjectInstanceDescriptor)
void CustomizableObjectNullErrorMessage()
{
UE_LOG(LogMutable, Error,
TEXT("Tried to perform actions on a CustomizableObjectInstance with no CustomizableObject set. Please set the CustomizableObject of the Instance before doing anything with it."));
}
FString GetAvailableOptionsString(const UCustomizableObject& CustomizableObject, const int32 ParameterIndexInObject)
{
FString OptionsString;
const int32 NumOptions = CustomizableObject.GetPrivate()->GetEnumParameterNumValues(ParameterIndexInObject);
for (int32 k = 0; k < NumOptions; ++k)
{
OptionsString += CustomizableObject.GetPrivate()->GetIntParameterAvailableOption(ParameterIndexInObject, k);
if (k < NumOptions - 1)
{
OptionsString += FString(", ");
}
}
return OptionsString;
}
FCustomizableObjectInstanceDescriptor::FCustomizableObjectInstanceDescriptor(UCustomizableObject& Object)
{
SetCustomizableObject(&Object);
}
void FCustomizableObjectInstanceDescriptor::SaveDescriptor(FArchive& Ar, bool bUseCompactDescriptor)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
Ar << bUseCompactDescriptor;
// Not sure if this is needed, but it is small.
Ar << State;
int32 ModelParameterCount = CustomizableObject->GetParameterCount();
if (!bUseCompactDescriptor)
{
Ar << ModelParameterCount;
}
for (int32 ModelParameterIndex = 0; ModelParameterIndex < ModelParameterCount; ++ModelParameterIndex)
{
const FString& Name = CustomizableObject->GetParameterName(ModelParameterIndex);
EMutableParameterType Type = CustomizableObject->GetParameterTypeByName(Name);
if (!bUseCompactDescriptor)
{
check(Ar.IsSaving());
Ar << const_cast<FString &>(Name);
}
switch (Type)
{
case EMutableParameterType::Bool:
{
bool Value = false;
for (const FCustomizableObjectBoolParameterValue& P: BoolParameters)
{
if (P.ParameterName == Name)
{
Value = P.ParameterValue;
break;
}
}
Ar << Value;
break;
}
case EMutableParameterType::Float:
{
float Value = 0.0f;
TArray<float> RangeValues;
for (const FCustomizableObjectFloatParameterValue& P : FloatParameters)
{
if (P.ParameterName == Name)
{
Value = P.ParameterValue;
RangeValues = P.ParameterRangeValues;
break;
}
}
Ar << Value;
Ar << RangeValues;
break;
}
case EMutableParameterType::Int:
{
int32 Value = 0;
FString ValueName;
TArray<int32> Values;
TArray<FString> ValueNames;
bool bIsParamMultidimensional = false;
const int32 IntParameterIndex = FindTypedParameterIndex(Name, EMutableParameterType::Int);
if (IntParameterIndex >= 0)
{
const FCustomizableObjectIntParameterValue & P = IntParameters[IntParameterIndex];
Value = CustomizableObject->GetPrivate()->FindIntParameterValue(ModelParameterIndex, P.ParameterValueName);
int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(IntParameters[IntParameterIndex].ParameterName);
bIsParamMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (bIsParamMultidimensional)
{
for (int32 i = 0; i < P.ParameterRangeValueNames.Num(); ++i)
{
ValueNames.Add(P.ParameterRangeValueNames[i]);
Values.Add(CustomizableObject->GetPrivate()->FindIntParameterValue(ModelParameterIndex, P.ParameterRangeValueNames[i]));
}
}
if (!bUseCompactDescriptor)
{
ValueName = P.ParameterValueName;
}
}
if (bUseCompactDescriptor)
{
Ar << Value;
if (bIsParamMultidimensional)
{
Ar << Values;
}
}
else
{
Ar << ValueName;
if (bIsParamMultidimensional)
{
Ar << ValueNames;
}
}
break;
}
case EMutableParameterType::Color:
{
FLinearColor Value(FLinearColor::Black);
for (const FCustomizableObjectVectorParameterValue& P : VectorParameters)
{
if (P.ParameterName == Name)
{
Value = P.ParameterValue;
break;
}
}
Ar << Value;
break;
}
case EMutableParameterType::Transform:
{
FTransform Value(FTransform::Identity);
for (const FCustomizableObjectTransformParameterValue& P : TransformParameters)
{
if (P.ParameterName == Name)
{
Value = P.ParameterValue;
break;
}
}
Ar << Value;
break;
}
case EMutableParameterType::Texture:
{
FString Value;
TArray<FString> RangeValues;
for (const FCustomizableObjectTextureParameterValue& P : TextureParameters)
{
if (P.ParameterName == Name)
{
Value = P.ParameterValue.GetPathName();
RangeValues.Empty(P.ParameterRangeValues.Num());
Algo::Transform(P.ParameterRangeValues, RangeValues, [](const TObjectPtr<UTexture>& Element)
{
return Element->GetPathName();
});
break;
}
}
Ar << Value;
Ar << RangeValues;
break;
}
case EMutableParameterType::SkeletalMesh:
{
FString Value;
TArray<FString> RangeValues;
for (const FCustomizableObjectSkeletalMeshParameterValue& P : SkeletalMeshParameters)
{
if (P.ParameterName == Name)
{
Value = P.ParameterValue.GetPathName();
RangeValues.Empty(P.ParameterRangeValues.Num());
Algo::Transform(P.ParameterRangeValues, RangeValues, [](const TObjectPtr<USkeletalMesh>& Element)
{
return Element->GetPathName();
});
break;
}
}
Ar << Value;
Ar << RangeValues;
break;
}
case EMutableParameterType::Projector:
{
FCustomizableObjectProjector Value;
TArray<FCustomizableObjectProjector> RangeValues;
for (const FCustomizableObjectProjectorParameterValue& P : ProjectorParameters)
{
if (P.ParameterName == Name)
{
Value = P.Value;
RangeValues = P.RangeValues;
break;
}
}
Ar << Value;
Ar << RangeValues;
break;
}
default:
// Parameter type replication not implemented.
check(false);
}
}
}
void FCustomizableObjectInstanceDescriptor::LoadDescriptor(FArchive& Ar)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
bool bUseCompactDescriptor;
Ar << bUseCompactDescriptor;
// Not sure if this is needed, but it is small.
Ar << State;
int32 ModelParameterCount = CustomizableObject->GetParameterCount();
if (!bUseCompactDescriptor)
{
Ar << ModelParameterCount;
}
for (int32 ParameterIndex = 0; ParameterIndex < ModelParameterCount; ++ParameterIndex)
{
FString Name;
EMutableParameterType Type;
int32 ModelParameterIndex = -1;
if (bUseCompactDescriptor)
{
ModelParameterIndex = ParameterIndex;
Name = CustomizableObject->GetParameterName(ModelParameterIndex);
Type = CustomizableObject->GetPrivate()->GetParameterType(ModelParameterIndex);
}
else
{
Ar << Name;
Type = CustomizableObject->GetParameterTypeByName(Name);
}
switch (Type)
{
case EMutableParameterType::Bool:
{
bool Value = false;
Ar << Value;
for (FCustomizableObjectBoolParameterValue& P : BoolParameters)
{
if (P.ParameterName == Name)
{
P.ParameterValue = Value;
break;
}
}
break;
}
case EMutableParameterType::Float:
{
float Value = 0.0f;
TArray<float> RangeValues;
Ar << Value;
Ar << RangeValues;
for (FCustomizableObjectFloatParameterValue& P : FloatParameters)
{
if (P.ParameterName == Name)
{
P.ParameterValue = Value;
P.ParameterRangeValues = RangeValues;
break;
}
}
break;
}
case EMutableParameterType::Int:
{
int32 Value = 0;
FString ValueName;
TArray<int32> Values;
TArray<FString> ValueNames;
const int32 IntParameterIndex = FindTypedParameterIndex(Name, EMutableParameterType::Int);
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(IntParameters[IntParameterIndex].ParameterName);
const bool bIsParamMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (bUseCompactDescriptor)
{
Ar << Value;
if (bIsParamMultidimensional)
{
Ar << Values;
}
}
else
{
Ar << ValueName;
if (bIsParamMultidimensional)
{
Ar << ValueNames;
}
}
for (FCustomizableObjectIntParameterValue& P : IntParameters)
{
if (P.ParameterName == Name)
{
if (bUseCompactDescriptor)
{
P.ParameterValueName = CustomizableObject->GetPrivate()->FindIntParameterValueName(ModelParameterIndex, Value);
//check((P.ParameterValueName.IsEmpty() && ValueName.Equals(FString("None"))) || P.ParameterValueName.Equals(ValueName));
P.ParameterRangeValueNames.SetNum(Values.Num());
for (int32 ParamIndex = 0; ParamIndex < Values.Num(); ++ParamIndex)
{
P.ParameterRangeValueNames[ParamIndex] = CustomizableObject->GetPrivate()->FindIntParameterValueName(ModelParameterIndex, Values[ParamIndex]);
}
}
else
{
P.ParameterValueName = ValueName;
P.ParameterRangeValueNames = ValueNames;
}
break;
}
}
break;
}
case EMutableParameterType::Color:
{
FLinearColor Value(FLinearColor::Black);
Ar << Value;
for (FCustomizableObjectVectorParameterValue& P : VectorParameters)
{
if (P.ParameterName == Name)
{
P.ParameterValue = Value;
break;
}
}
break;
}
case EMutableParameterType::Transform:
{
FTransform Value(FTransform::Identity);
Ar << Value;
for (FCustomizableObjectTransformParameterValue& P : TransformParameters)
{
if (P.ParameterName == Name)
{
P.ParameterValue = Value;
break;
}
}
break;
}
case EMutableParameterType::Texture:
{
FString Value;
TArray<FString> RangeValues;
Ar << Value;
Ar << RangeValues;
for (FCustomizableObjectTextureParameterValue& P : TextureParameters)
{
if (P.ParameterName == Name)
{
P.ParameterValue = ToObject<UTexture>(Value);
P.ParameterRangeValues.Empty(RangeValues.Num());
Algo::Transform(RangeValues, P.ParameterRangeValues, [](const FString& Element)
{
return ToObject<UTexture>(Element);
});
break;
}
}
break;
}
case EMutableParameterType::SkeletalMesh:
{
FString Value;
TArray<FString> RangeValues;
Ar << Value;
Ar << RangeValues;
for (FCustomizableObjectSkeletalMeshParameterValue& P : SkeletalMeshParameters)
{
if (P.ParameterName == Name)
{
P.ParameterValue = ToObject<USkeletalMesh>(Value);
P.ParameterRangeValues.Empty(RangeValues.Num());
Algo::Transform( RangeValues, P.ParameterRangeValues, [](const FString& Element)
{
return ToObject<USkeletalMesh>(Element);
});
break;
}
}
break;
}
case EMutableParameterType::Projector:
{
FCustomizableObjectProjector Value;
TArray<FCustomizableObjectProjector> RangeValues;
Ar << Value;
Ar << RangeValues;
for (FCustomizableObjectProjectorParameterValue& P : ProjectorParameters)
{
if (P.ParameterName == Name)
{
P.Value = Value;
P.RangeValues = RangeValues;
break;
}
}
break;
}
default:
// Parameter type replication not implemented.
check(false);
}
}
}
UCustomizableObject* FCustomizableObjectInstanceDescriptor::GetCustomizableObject() const
{
return CustomizableObject;
}
void FCustomizableObjectInstanceDescriptor::SetCustomizableObject(UCustomizableObject* InCustomizableObject)
{
CustomizableObject = InCustomizableObject;
ReloadParameters();
}
bool FCustomizableObjectInstanceDescriptor::GetBuildParameterRelevancy() const
{
#if WITH_EDITOR
// In editor, calculate the parameter relevancy by default.
bool bResultBuildRelevancy = true;
// However if we are in a PIE session, do it only if requested to simulate a more game-like performance.
if (GIsEditor)
{
FWorldContext* PIEWorldContext = GEditor->GetPIEWorldContext();
if (PIEWorldContext)
{
bResultBuildRelevancy = bBuildParameterRelevancy;
}
}
return bResultBuildRelevancy;
#else
return bBuildParameterRelevancy;
#endif
}
void FCustomizableObjectInstanceDescriptor::SetBuildParameterRelevancy(const bool Value)
{
bBuildParameterRelevancy = Value;
}
TSharedPtr<mu::FParameters> FCustomizableObjectInstanceDescriptor::GetParameters() const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return nullptr;
}
if (!CustomizableObject->IsCompiled())
{
return nullptr;
}
if (!CustomizableObject->GetPrivate()->GetModel())
{
return nullptr;
}
const UModelResources& ModelResources = CustomizableObject->GetPrivate()->GetModelResourcesChecked();
TSharedPtr<mu::FParameters> MutableParameters = mu::FModel::NewParameters(CustomizableObject->GetPrivate()->GetModel(),
nullptr,
&ModelResources.TextureParameterDefaultValues,
&ModelResources.SkeletalMeshParameterDefaultValues);
const int32 ParamCount = MutableParameters->GetCount();
for (int32 ParamIndex = 0; ParamIndex < ParamCount; ++ParamIndex)
{
const FString& Name = MutableParameters->GetName(ParamIndex);
const FGuid& Uid = MutableParameters->GetUid(ParamIndex);
const mu::EParameterType MutableType = MutableParameters->GetType(ParamIndex);
switch (MutableType)
{
case mu::EParameterType::Bool:
{
for (const FCustomizableObjectBoolParameterValue& BoolParameter : BoolParameters)
{
if (BoolParameter.ParameterName == Name || (Uid.IsValid() && BoolParameter.Id == Uid))
{
MutableParameters->SetBoolValue(ParamIndex, BoolParameter.ParameterValue);
break;
}
}
break;
}
case mu::EParameterType::Int:
{
for (const FCustomizableObjectIntParameterValue& IntParameter : IntParameters)
{
if (IntParameter.ParameterName.Equals(Name, ESearchCase::CaseSensitive) || (Uid.IsValid() && IntParameter.Id == Uid))
{
if (TSharedPtr<mu::FRangeIndex> RangeIdxPtr = MutableParameters->NewRangeIndex(ParamIndex))
{
for (int32 RangeIndex = 0; RangeIndex < IntParameter.ParameterRangeValueNames.Num(); ++RangeIndex)
{
RangeIdxPtr->SetPosition(0, RangeIndex);
const FString& RangeValueName = IntParameter.ParameterRangeValueNames[RangeIndex];
const int32 Value = CustomizableObject->GetPrivate()->FindIntParameterValue(ParamIndex, RangeValueName);
MutableParameters->SetIntValue(ParamIndex, Value, RangeIdxPtr.Get());
}
}
else
{
const int32 Value = CustomizableObject->GetPrivate()->FindIntParameterValue(ParamIndex, IntParameter.ParameterValueName);
MutableParameters->SetIntValue(ParamIndex, Value);
}
break;
}
}
break;
}
case mu::EParameterType::Float:
{
for (const FCustomizableObjectFloatParameterValue& FloatParameter : FloatParameters)
{
if (FloatParameter.ParameterName == Name || (Uid.IsValid() && FloatParameter.Id == Uid))
{
if (TSharedPtr<mu::FRangeIndex> RangeIdxPtr = MutableParameters->NewRangeIndex(ParamIndex))
{
for (int32 RangeIndex = 0; RangeIndex < FloatParameter.ParameterRangeValues.Num(); ++RangeIndex)
{
RangeIdxPtr->SetPosition(0, RangeIndex);
MutableParameters->SetFloatValue(ParamIndex, FloatParameter.ParameterRangeValues[RangeIndex], RangeIdxPtr.Get());
}
}
else
{
MutableParameters->SetFloatValue(ParamIndex, FloatParameter.ParameterValue);
}
break;
}
}
break;
}
case mu::EParameterType::Color:
{
for (const FCustomizableObjectVectorParameterValue& VectorParameter : VectorParameters)
{
if (VectorParameter.ParameterName == Name || (Uid.IsValid() && VectorParameter.Id == Uid))
{
MutableParameters->SetColourValue(ParamIndex, VectorParameter.ParameterValue);
break;
}
}
break;
}
case mu::EParameterType::Matrix:
{
for (const FCustomizableObjectTransformParameterValue& TransformParameter : TransformParameters)
{
if (TransformParameter.ParameterName == Name || (Uid.IsValid() && TransformParameter.Id == Uid))
{
MutableParameters->SetMatrixValue(ParamIndex, FMatrix44f(TransformParameter.ParameterValue.ToMatrixWithScale()));
break;
}
}
break;
}
case mu::EParameterType::Projector:
{
for (const auto& ProjectorParameter : ProjectorParameters)
{
if (ProjectorParameter.ParameterName == Name || (Uid.IsValid() && ProjectorParameter.Id == Uid))
{
auto CopyProjector = [&MutableParameters, ParamIndex](const FCustomizableObjectProjector& Value, const mu::FRangeIndex* RangeIdxPtr = nullptr)
{
switch (Value.ProjectionType)
{
case ECustomizableObjectProjectorType::Planar:
case ECustomizableObjectProjectorType::Wrapping:
MutableParameters->SetProjectorValue(ParamIndex,
Value.Position,
Value.Direction,
Value.Up,
Value.Scale,
Value.Angle,
RangeIdxPtr);
break;
case ECustomizableObjectProjectorType::Cylindrical:
{
// Apply strange swizzle for scales
// TODO: try to avoid this
const float Radius = FMath::Abs(Value.Scale[0] / 2.0f);
const float Height = Value.Scale[2];
// TODO: try to avoid this
MutableParameters->SetProjectorValue(ParamIndex,
Value.Position,
-Value.Direction,
-Value.Up,
FVector3f(-Height, Radius, Radius),
Value.Angle,
RangeIdxPtr);
break;
}
default:
check(false); // Not implemented.
}
};
CopyProjector(ProjectorParameter.Value);
if (const TSharedPtr<mu::FRangeIndex> RangeIdxPtr = MutableParameters->NewRangeIndex(ParamIndex))
{
for (int32 RangeIndex = 0; RangeIndex < ProjectorParameter.RangeValues.Num(); ++RangeIndex)
{
RangeIdxPtr->SetPosition(0, RangeIndex);
CopyProjector(ProjectorParameter.RangeValues[RangeIndex], RangeIdxPtr.Get());
}
}
}
}
break;
}
case mu::EParameterType::Image:
{
for (const FCustomizableObjectTextureParameterValue& TextureParameter : TextureParameters)
{
if (TextureParameter.ParameterName == Name || (Uid.IsValid() && TextureParameter.Id == Uid))
{
if (TSharedPtr<mu::FRangeIndex> RangeIdxPtr = MutableParameters->NewRangeIndex(ParamIndex))
{
for (int32 RangeIndex = 0; RangeIndex < TextureParameter.ParameterRangeValues.Num(); ++RangeIndex)
{
RangeIdxPtr->SetPosition(0, RangeIndex);
MutableParameters->SetImageValue(ParamIndex, TextureParameter.ParameterRangeValues[RangeIndex], RangeIdxPtr.Get());
}
}
else
{
MutableParameters->SetImageValue(ParamIndex, TextureParameter.ParameterValue);
}
break;
}
}
break;
}
case mu::EParameterType::Mesh:
{
for (const FCustomizableObjectSkeletalMeshParameterValue& MeshParameter : SkeletalMeshParameters)
{
if (MeshParameter.ParameterName == Name || (Uid.IsValid() && MeshParameter.Id == Uid))
{
if (TSharedPtr<mu::FRangeIndex> RangeIdxPtr = MutableParameters->NewRangeIndex(ParamIndex))
{
for (int32 RangeIndex = 0; RangeIndex < MeshParameter.ParameterRangeValues.Num(); ++RangeIndex)
{
RangeIdxPtr->SetPosition(0, RangeIndex);
MutableParameters->SetMeshValue(ParamIndex, MeshParameter.ParameterRangeValues[RangeIndex], RangeIdxPtr.Get());
}
}
else
{
MutableParameters->SetMeshValue(ParamIndex, MeshParameter.ParameterValue);
}
break;
}
}
break;
}
default:
check(false); // Missing case.
break;
}
}
return MutableParameters;
}
FString FCustomizableObjectInstanceDescriptor::ToString() const
{
const UScriptStruct* Struct = StaticStruct();
FString ExportedText;
Struct->ExportText(ExportedText, this, nullptr, nullptr, (PPF_ExportsNotFullyQualified | PPF_Copy | PPF_Delimited | PPF_IncludeTransient), nullptr);
return ExportedText;
}
void FCustomizableObjectInstanceDescriptor::ReloadParameters()
{
if (IsRunningCookCommandlet())
{
return;
}
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
if (!CustomizableObject->IsCompiled())
{
return;
}
SetState(FMath::Clamp(GetState(), 0, CustomizableObject->GetStateCount() - 1));
FirstRequestedLOD.Empty();
TArray<FCustomizableObjectBoolParameterValue> OldBoolParameters = BoolParameters;
TArray<FCustomizableObjectIntParameterValue> OldIntParameters = IntParameters;
TArray<FCustomizableObjectFloatParameterValue> OldFloatParameters = FloatParameters;
TArray<FCustomizableObjectTextureParameterValue> OldTextureParameters = TextureParameters;
TArray<FCustomizableObjectSkeletalMeshParameterValue> OldSkeletalMeshParameters = SkeletalMeshParameters;
TArray<FCustomizableObjectVectorParameterValue> OldVectorParameters = VectorParameters;
TArray<FCustomizableObjectProjectorParameterValue> OldProjectorParameters = ProjectorParameters;
TArray<FCustomizableObjectTransformParameterValue> OldTransformParameters = TransformParameters;
BoolParameters.Reset();
IntParameters.Reset();
FloatParameters.Reset();
TextureParameters.Reset();
SkeletalMeshParameters.Reset();
VectorParameters.Reset();
ProjectorParameters.Reset();
TransformParameters.Reset();
if (!CustomizableObject->GetPrivate()->GetModel())
{
UE_LOG(LogMutable, Warning, TEXT("[ReloadParametersFromObject] No model in object [%s], generated empty parameters for [%s] "), *CustomizableObject->GetName(), *CustomizableObject->GetName());
return;
}
const UModelResources* ModelResources = CustomizableObject->GetPrivate()->GetModelResources();
if(!CustomizableObject->GetPrivate()->GetModelResources())
{
UE_LOG(LogMutable, Warning, TEXT("[ReloadParametersFromObject] No model resources in object [%s], generated empty parameters for [%s] "), *CustomizableObject->GetName(), *CustomizableObject->GetName());
return;
}
TSharedPtr<mu::FParameters> MutableParameters = mu::FModel::NewParameters(
CustomizableObject->GetPrivate()->GetModel(),
nullptr,
&ModelResources->TextureParameterDefaultValues,
&ModelResources->SkeletalMeshParameterDefaultValues);
int32 ParamCount = MutableParameters->GetCount();
for (int32 ParamIndex = 0; ParamIndex < ParamCount; ++ParamIndex)
{
const FString& Name = MutableParameters->GetName(ParamIndex);
const FGuid& Uid = MutableParameters->GetUid(ParamIndex);
const mu::EParameterType MutableType = MutableParameters->GetType(ParamIndex);
switch (MutableType)
{
case mu::EParameterType::Bool:
{
FCustomizableObjectBoolParameterValue Param;
Param.ParameterName = Name;
Param.Id = Uid;
auto FindByNameAndUid = [&](const FCustomizableObjectBoolParameterValue& P)
{
return P.ParameterName == Name || (Uid.IsValid() && P.Id == Uid);
};
if (FCustomizableObjectBoolParameterValue* Result = OldBoolParameters.FindByPredicate(FindByNameAndUid))
{
Param.ParameterValue = Result->ParameterValue;
}
else // Not found in Instance Parameters. Use Mutable Parameters.
{
Param.ParameterValue = MutableParameters->GetBoolValue(ParamIndex);
}
BoolParameters.Add(Param);
break;
}
case mu::EParameterType::Int:
{
FCustomizableObjectIntParameterValue Param;
Param.ParameterName = Name;
Param.Id = Uid;
auto FindByNameAndUid = [&](const FCustomizableObjectIntParameterValue& P)
{
return P.ParameterName == Name || (Uid.IsValid() && P.Id == Uid);
};
if (FCustomizableObjectIntParameterValue* Result = OldIntParameters.FindByPredicate(FindByNameAndUid))
{
const int32 NumValueIndex = MutableParameters->GetIntPossibleValueCount(ParamIndex);
auto ValueExists = [&](const FString& ValueName)
{
for (int32 ValueIndex = 0; ValueIndex < NumValueIndex; ++ValueIndex)
{
if (ValueName == MutableParameters->GetIntPossibleValueName(ParamIndex, ValueIndex))
{
return true;
}
}
return false;
};
if (TSharedPtr<mu::FRangeIndex> RangeIdxPtr = MutableParameters->NewRangeIndex(ParamIndex)) // Is multidimensional
{
// Get num of ranges (layers) from the instance
int32 ValueCount = Result->ParameterRangeValueNames.Num();
Param.ParameterRangeValueNames.Reserve(ValueCount);
for (int32 RangeIndex = 0; RangeIndex < ValueCount; ++RangeIndex)
{
// Checking if the selected value still exists as option in the parameter
if (const FString& OldValue = Result->ParameterRangeValueNames[RangeIndex]; ValueExists(OldValue))
{
Param.ParameterRangeValueNames.Add(OldValue);
}
else
{
const int32 Value = MutableParameters->GetIntValue(ParamIndex, RangeIdxPtr.Get());
const FString AuxParameterValueName = CustomizableObject->GetPrivate()->FindIntParameterValueName(ParamIndex, Value);
Param.ParameterRangeValueNames.Add(AuxParameterValueName);
}
}
}
else
{
if (ValueExists(Result->ParameterValueName))
{
Param.ParameterValueName = Result->ParameterValueName;
}
else
{
const int32 ParamValue = MutableParameters->GetIntValue(ParamIndex);
Param.ParameterValueName = CustomizableObject->GetPrivate()->FindIntParameterValueName(ParamIndex, ParamValue);
}
// Multilayer ints with one option are not multidimensional parameters. However, we need to preserve the layer
// information in case that we add a new option to the parameter, and it is converted to multidimensional.
for (int32 RangeIndex = 0; RangeIndex < Result->ParameterRangeValueNames.Num(); ++RangeIndex)
{
const int32 Value = MutableParameters->GetIntValue(ParamIndex);
const FString AuxParameterValueName = CustomizableObject->GetPrivate()->FindIntParameterValueName(ParamIndex, Value);
Param.ParameterRangeValueNames.Add(AuxParameterValueName);
}
}
}
else // Not found in Instance Parameters. Use Mutable Parameters.
{
if (TSharedPtr<mu::FRangeIndex> RangeIdxPtr = MutableParameters->NewRangeIndex(ParamIndex))
{
const int32 ValueCount = MutableParameters->GetValueCount(ParamIndex);
for (int32 ValueIndex = 0; ValueIndex < ValueCount; ++ValueIndex)
{
const TSharedPtr<mu::FRangeIndex> RangeValueIdxPtr = MutableParameters->GetValueIndex(ParamIndex, ValueIndex);
const int32 RangeIndex = RangeValueIdxPtr->GetPosition(0);
if (!Param.ParameterRangeValueNames.IsValidIndex(RangeIndex))
{
Param.ParameterRangeValueNames.AddDefaulted(RangeIndex + 1 - Param.ParameterRangeValueNames.Num());
}
const int32 Value = MutableParameters->GetIntValue(ParamIndex, RangeValueIdxPtr.Get());
const FString AuxParameterValueName = CustomizableObject->GetPrivate()->FindIntParameterValueName(ParamIndex, Value);
Param.ParameterRangeValueNames[RangeIndex] = AuxParameterValueName;
}
}
else
{
const int32 ParamValue = MutableParameters->GetIntValue(ParamIndex);
Param.ParameterValueName = CustomizableObject->GetPrivate()->FindIntParameterValueName(ParamIndex, ParamValue);
}
}
IntParameters.Add(Param);
break;
}
case mu::EParameterType::Float:
{
FCustomizableObjectFloatParameterValue Param;
Param.ParameterName = Name;
Param.Id = Uid;
auto FindByNameAndUid = [&](const FCustomizableObjectFloatParameterValue& P)
{
return P.ParameterName == Name || (Uid.IsValid() && P.Id == Uid);
};
if (FCustomizableObjectFloatParameterValue* Result = OldFloatParameters.FindByPredicate(FindByNameAndUid))
{
if (TSharedPtr<mu::FRangeIndex> RangeIdxPtr = MutableParameters->NewRangeIndex(ParamIndex))
{
Param.ParameterRangeValues = Result->ParameterRangeValues;
}
else
{
Param.ParameterValue = Result->ParameterValue;
}
}
else // Not found in Instance Parameters. Use Mutable Parameters.
{
if (TSharedPtr<mu::FRangeIndex> RangeIdxPtr = MutableParameters->NewRangeIndex(ParamIndex))
{
const int32 ValueCount = MutableParameters->GetValueCount(ParamIndex);
for (int32 ValueIndex = 0; ValueIndex < ValueCount; ++ValueIndex)
{
TSharedPtr<mu::FRangeIndex> RangeValueIdxPtr = MutableParameters->GetValueIndex(ParamIndex, ValueIndex);
int32 RangeIndex = RangeValueIdxPtr->GetPosition(0);
if (!Param.ParameterRangeValues.IsValidIndex(RangeIndex))
{
Param.ParameterRangeValues.AddDefaulted(RangeIndex + 1 - Param.ParameterRangeValues.Num());
}
Param.ParameterRangeValues[RangeIndex] = MutableParameters->GetFloatValue(ParamIndex, RangeValueIdxPtr.Get());
}
}
else
{
Param.ParameterValue = MutableParameters->GetFloatValue(ParamIndex);
}
}
FloatParameters.Add(Param);
break;
}
case mu::EParameterType::Color:
{
FCustomizableObjectVectorParameterValue Param;
Param.ParameterName = Name;
Param.Id = Uid;
auto FindByNameAndUid = [&](const FCustomizableObjectVectorParameterValue& P)
{
return P.ParameterName == Name || (Uid.IsValid() && P.Id == Uid);
};
if (FCustomizableObjectVectorParameterValue* Result = OldVectorParameters.FindByPredicate(FindByNameAndUid))
{
Param.ParameterValue = Result->ParameterValue;
}
else // Not found in Instance Parameters. Use Mutable Parameters.
{
FVector4f V;
MutableParameters->GetColourValue(ParamIndex, V);
Param.ParameterValue = V;
}
VectorParameters.Add(Param);
break;
}
case mu::EParameterType::Matrix:
{
FCustomizableObjectTransformParameterValue Param;
Param.ParameterName = Name;
Param.Id = Uid;
auto FindByNameAndUid = [&](const FCustomizableObjectTransformParameterValue& P)
{
return P.ParameterName == Name || (Uid.IsValid() && P.Id == Uid);
};
if (FCustomizableObjectTransformParameterValue* Result = OldTransformParameters.FindByPredicate(FindByNameAndUid))
{
Param.ParameterValue = Result->ParameterValue;
}
else // Not found in Instance Parameters. Use Mutable Parameters.
{
FMatrix44f Matrix;
MutableParameters->GetMatrixValue(ParamIndex, Matrix);
Param.ParameterValue = FTransform(FMatrix(Matrix));
}
TransformParameters.Add(Param);
break;
}
case mu::EParameterType::Projector:
{
FCustomizableObjectProjectorParameterValue Param;
Param.ParameterName = Name;
Param.Id = Uid;
// Projector to check if the porojector's type has changed
FCustomizableObjectProjector DefaultProjectorValue = CustomizableObject->GetProjectorParameterDefaultValue(Name);
auto FindByNameAndUid = [&](const FCustomizableObjectProjectorParameterValue& P)
{
return P.ParameterName == Name || (Uid.IsValid() && P.Id == Uid);
};
if (FCustomizableObjectProjectorParameterValue* Result = OldProjectorParameters.FindByPredicate(FindByNameAndUid))
{
if (TSharedPtr<mu::FRangeIndex> RangeIdxPtr = MutableParameters->NewRangeIndex(ParamIndex))
{
Param.RangeValues = Result->RangeValues;
Param.Value.ProjectionType = DefaultProjectorValue.ProjectionType;
for (FCustomizableObjectProjector& Projector : Param.RangeValues)
{
Projector.ProjectionType = DefaultProjectorValue.ProjectionType;
}
}
else
{
Param.Value = Result->Value;
Param.Value.ProjectionType = DefaultProjectorValue.ProjectionType;
}
}
else // Not found in Instance Parameters. Use Mutable Parameters.
{
auto GetProjector = [&MutableParameters, ParamIndex](FCustomizableObjectProjector &Value, const TSharedPtr<mu::FRangeIndex> RangeIndex = nullptr)
{
mu::EProjectorType Type;
MutableParameters->GetProjectorValue(ParamIndex,
&Type,
&Value.Position,
&Value.Direction,
&Value.Up,
&Value.Scale,
&Value.Angle,
RangeIndex.Get());
Value.ProjectionType = ProjectorUtils::GetEquivalentProjectorType(Type);
if (Value.ProjectionType == ECustomizableObjectProjectorType::Cylindrical)
{
// Unapply strange swizzle for scales.
// TODO: try to avoid this
Value.Direction = -Value.Direction;
Value.Up = -Value.Up;
Value.Scale[2] = -Value.Scale[0];
Value.Scale[0] = Value.Scale[1] = Value.Scale[1] * 2.0f;
}
};
GetProjector(Param.Value);
if (TSharedPtr<mu::FRangeIndex> RangeIdxPtr = MutableParameters->NewRangeIndex(ParamIndex))
{
const int32 ValueCount = MutableParameters->GetValueCount(ParamIndex);
for (int32 ValueIndex = 0; ValueIndex < ValueCount; ++ValueIndex)
{
TSharedPtr<mu::FRangeIndex> RangeValueIdxPtr = MutableParameters->GetValueIndex(ParamIndex, ValueIndex);
int32 RangeIndex = RangeValueIdxPtr->GetPosition(0);
if (!Param.RangeValues.IsValidIndex(RangeIndex))
{
Param.RangeValues.AddDefaulted(RangeIndex + 1 - Param.RangeValues.Num());
}
GetProjector(Param.RangeValues[RangeIndex], RangeValueIdxPtr);
}
}
}
ProjectorParameters.Add(Param);
break;
}
case mu::EParameterType::Image:
{
FCustomizableObjectTextureParameterValue Param;
Param.ParameterName = Name;
Param.Id = Uid;
auto FindByNameAndUid = [&](const FCustomizableObjectTextureParameterValue& P)
{
return P.ParameterName == Name || (Uid.IsValid() && P.Id == Uid);
};
if (FCustomizableObjectTextureParameterValue* Result = OldTextureParameters.FindByPredicate(FindByNameAndUid))
{
if (TSharedPtr<mu::FRangeIndex> RangeIdxPtr = MutableParameters->NewRangeIndex(ParamIndex))
{
Param.ParameterRangeValues = Result->ParameterRangeValues;
}
else
{
Param.ParameterValue = Result->ParameterValue;
}
}
else // Not found in Instance Parameters. Use Mutable Parameters.
{
if (TSharedPtr<mu::FRangeIndex> RangeIdxPtr = MutableParameters->NewRangeIndex(ParamIndex))
{
const int32 ValueCount = MutableParameters->GetValueCount(ParamIndex);
for (int32 ValueIndex = 0; ValueIndex < ValueCount; ++ValueIndex)
{
TSharedPtr<mu::FRangeIndex> RangeValueIdxPtr = MutableParameters->GetValueIndex(ParamIndex, ValueIndex);
int32 RangeIndex = RangeValueIdxPtr->GetPosition(0);
if (!Param.ParameterRangeValues.IsValidIndex(RangeIndex))
{
const int32 PreviousNum = Param.ParameterRangeValues.Num();
Param.ParameterRangeValues.AddUninitialized(RangeIndex + 1 - Param.ParameterRangeValues.Num());
for (int32 Index = PreviousNum; Index < Param.ParameterRangeValues.Num(); ++Index)
{
Param.ParameterRangeValues[Index] = nullptr;
}
}
Param.ParameterRangeValues[RangeIndex] = MutableParameters->GetImageValue(ParamIndex, RangeValueIdxPtr.Get());
}
}
else
{
Param.ParameterValue = MutableParameters->GetImageValue(ParamIndex);
}
}
TextureParameters.Add(Param);
break;
}
case mu::EParameterType::Mesh:
{
FCustomizableObjectSkeletalMeshParameterValue Param;
Param.ParameterName = Name;
Param.Id = Uid;
auto FindByNameAndUid = [&](const FCustomizableObjectSkeletalMeshParameterValue& P)
{
return P.ParameterName == Name || (Uid.IsValid() && P.Id == Uid);
};
if (FCustomizableObjectSkeletalMeshParameterValue* Result = OldSkeletalMeshParameters.FindByPredicate(FindByNameAndUid))
{
if (TSharedPtr<mu::FRangeIndex> RangeIdxPtr = MutableParameters->NewRangeIndex(ParamIndex))
{
Param.ParameterRangeValues = Result->ParameterRangeValues;
}
else
{
Param.ParameterValue = Result->ParameterValue;
}
}
else // Not found in Instance Parameters. Use Mutable Parameters.
{
if (TSharedPtr<mu::FRangeIndex> RangeIdxPtr = MutableParameters->NewRangeIndex(ParamIndex))
{
const int32 ValueCount = MutableParameters->GetValueCount(ParamIndex);
for (int32 ValueIndex = 0; ValueIndex < ValueCount; ++ValueIndex)
{
TSharedPtr<mu::FRangeIndex> RangeValueIdxPtr = MutableParameters->GetValueIndex(ParamIndex, ValueIndex);
int32 RangeIndex = RangeValueIdxPtr->GetPosition(0);
if (!Param.ParameterRangeValues.IsValidIndex(RangeIndex))
{
const int32 PreviousNum = Param.ParameterRangeValues.Num();
Param.ParameterRangeValues.AddUninitialized(RangeIndex + 1 - Param.ParameterRangeValues.Num());
for (int32 Index = PreviousNum; Index < Param.ParameterRangeValues.Num(); ++Index)
{
Param.ParameterRangeValues[Index] = nullptr;
}
}
Param.ParameterRangeValues[RangeIndex] = MutableParameters->GetMeshValue(ParamIndex, RangeValueIdxPtr.Get());
}
}
else
{
Param.ParameterValue = MutableParameters->GetMeshValue(ParamIndex);
}
}
SkeletalMeshParameters.Add(Param);
break;
}
default:
check(false); // Missing case.
break;
}
}
}
void FCustomizableObjectInstanceDescriptor::SetFirstRequestedLOD(const TMap<FName, uint8>& InFirstRequestedLOD)
{
FirstRequestedLOD = InFirstRequestedLOD;
}
const TMap<FName, uint8>& FCustomizableObjectInstanceDescriptor::GetFirstRequestedLOD() const
{
return FirstRequestedLOD;
}
bool FCustomizableObjectInstanceDescriptor::HasAnyParameters() const
{
return !BoolParameters.IsEmpty() ||
!IntParameters.IsEmpty() ||
!FloatParameters.IsEmpty() ||
!TextureParameters.IsEmpty() ||
!ProjectorParameters.IsEmpty() ||
!TransformParameters.IsEmpty() ||
!VectorParameters.IsEmpty();
}
#if WITH_EDITOR
#define RETURN_ON_UNCOMPILED_CO(CustomizableObject, ErrorMessage) \
if (!CustomizableObject->IsCompiled()) \
{ \
FString AdditionalLoggingInfo = FString::Printf(TEXT("Calling function: %hs. %s"), __FUNCTION__, ErrorMessage); \
CustomizableObject->GetPrivate()->AddUncompiledCOWarning(AdditionalLoggingInfo);\
return; \
} \
#else
#define RETURN_ON_UNCOMPILED_CO(CustomizableObject, ErrorMessage) \
if (!ensureMsgf(CustomizableObject->IsCompiled(), TEXT("Customizable Object (%s) was not compiled."), *GetNameSafe(CustomizableObject))) \
{ \
FString AdditionalLoggingInfo = FString::Printf(TEXT("Calling function: %hs. %s"), __FUNCTION__, ErrorMessage); \
CustomizableObject->GetPrivate()->AddUncompiledCOWarning(AdditionalLoggingInfo);\
return; \
} \
#endif
void LogParameterNotFoundWarning(const FString& ParameterName, const int32 ObjectParameterIndex, const int32 InstanceParameterIndex, const UCustomizableObject* CustomizableObject, char const* CallingFunction)
{
UE_LOG(LogMutable, Error,
TEXT("%hs: Failed to find parameter (%s) on CO (%s). CO parameter index: (%d). COI parameter index: (%d)s"),
CallingFunction, *ParameterName, *GetNameSafe(CustomizableObject), ObjectParameterIndex, InstanceParameterIndex
);
}
const FString& FCustomizableObjectInstanceDescriptor::GetIntParameterSelectedOption(const FString& ParamName, const int32 RangeIndex) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return FCustomizableObjectBoolParameterValue::DEFAULT_PARAMETER_VALUE_NAME;
}
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(ParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(ParamName, EMutableParameterType::Int);
if (ParameterIndexInObject >= 0 && IntParameters.IsValidIndex(ParameterIndexInInstance))
{
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
return IntParameters[ParameterIndexInInstance].ParameterValueName;
}
else
{
if (IntParameters[ParameterIndexInInstance].ParameterRangeValueNames.IsValidIndex(RangeIndex))
{
return IntParameters[ParameterIndexInInstance].ParameterRangeValueNames[RangeIndex];
}
}
}
LogParameterNotFoundWarning(ParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return FCustomizableObjectBoolParameterValue::DEFAULT_PARAMETER_VALUE_NAME;
}
void FCustomizableObjectInstanceDescriptor::SetIntParameterSelectedOption(const int32 ParameterIndexInInstance, const FString& SelectedOption, const int32 RangeIndex)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
RETURN_ON_UNCOMPILED_CO(CustomizableObject, TEXT("Error: Cannot set Int parameter "));
const int32 ParameterIndexInObject = IntParameters.IsValidIndex(ParameterIndexInInstance) ? CustomizableObject->GetPrivate()->FindParameter(IntParameters[ParameterIndexInInstance].ParameterName) : INDEX_NONE; //-V781
if (ParameterIndexInObject < 0 || ParameterIndexInInstance < 0)
{
// Warn and early out since we could not find the parameter to set.
LogParameterNotFoundWarning(TEXT("Unknown Int Parmeter"), ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return;
}
const bool bValid = SelectedOption == TEXT("None") || CustomizableObject->GetPrivate()->FindIntParameterValue(ParameterIndexInObject, SelectedOption) >= 0;
if (!bValid)
{
#if !UE_BUILD_SHIPPING
const FString Message = FString::Printf(
TEXT("Tried to set the invalid value [%s] to parameter [%d, %s]! Value index=[%d]. Correct values=[%s]."),
*SelectedOption, ParameterIndexInObject,
*IntParameters[ParameterIndexInInstance].ParameterName,
CustomizableObject->GetPrivate()->FindIntParameterValue(ParameterIndexInObject, SelectedOption),
*GetAvailableOptionsString(*CustomizableObject, ParameterIndexInObject)
);
UE_LOG(LogMutable, Error, TEXT("%s"), *Message);
#endif
return;
}
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
IntParameters[ParameterIndexInInstance].ParameterValueName = SelectedOption;
}
else
{
// Contingency in case the RangeIndex can not be used as an index of the "ParameterRangeValueNames" array
if (!IntParameters[ParameterIndexInInstance].ParameterRangeValueNames.IsValidIndex(RangeIndex))
{
const int32 InsertionIndex = IntParameters[ParameterIndexInInstance].ParameterRangeValueNames.Num();
const int32 NumInsertedElements = RangeIndex + 1 - InsertionIndex;
IntParameters[ParameterIndexInInstance].ParameterRangeValueNames.InsertDefaulted(InsertionIndex, NumInsertedElements);
}
check(IntParameters[ParameterIndexInInstance].ParameterRangeValueNames.IsValidIndex(RangeIndex));
IntParameters[ParameterIndexInInstance].ParameterRangeValueNames[RangeIndex] = SelectedOption;
}
}
void FCustomizableObjectInstanceDescriptor::SetIntParameterSelectedOption(const FString& ParamName, const FString& SelectedOptionName, const int32 RangeIndex)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
RETURN_ON_UNCOMPILED_CO(CustomizableObject, TEXT("Error: Cannot set Int parameter "));
const int32 ParamIndexInInstance = FindTypedParameterIndex(ParamName, EMutableParameterType::Int);
if (ParamIndexInInstance == INDEX_NONE)
{
// Warn and early out since we could not find the parameter to set.
LogParameterNotFoundWarning(ParamName, ParamIndexInInstance, ParamIndexInInstance, CustomizableObject, __FUNCTION__);
return;
}
SetIntParameterSelectedOption(ParamIndexInInstance, SelectedOptionName, RangeIndex);
}
float FCustomizableObjectInstanceDescriptor::GetFloatParameterSelectedOption(const FString& FloatParamName, const int32 RangeIndex) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return FCustomizableObjectFloatParameterValue::DEFAULT_PARAMETER_VALUE;
}
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(FloatParamName);
const int32 FloatParamIndex = FindTypedParameterIndex(FloatParamName, EMutableParameterType::Float);
if (ParameterIndexInObject >= 0 && FloatParameters.IsValidIndex(FloatParamIndex))
{
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
return FloatParameters[FloatParamIndex].ParameterValue;
}
else
{
if (FloatParameters[FloatParamIndex].ParameterRangeValues.IsValidIndex(RangeIndex))
{
return FloatParameters[FloatParamIndex].ParameterRangeValues[RangeIndex];
}
}
}
LogParameterNotFoundWarning(FloatParamName, ParameterIndexInObject, FloatParamIndex, CustomizableObject, __FUNCTION__);
return FCustomizableObjectFloatParameterValue::DEFAULT_PARAMETER_VALUE;
}
void FCustomizableObjectInstanceDescriptor::SetFloatParameterSelectedOption(const FString& FloatParamName, const float FloatValue, const int32 RangeIndex)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
RETURN_ON_UNCOMPILED_CO(CustomizableObject, TEXT("Error: Cannot set Int parameter "));
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(FloatParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(FloatParamName, EMutableParameterType::Float);
if (ParameterIndexInObject < 0 || ParameterIndexInInstance < 0)
{
// Warn and early out since we could not find the parameter to set.
LogParameterNotFoundWarning(FloatParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return;
}
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
FloatParameters[ParameterIndexInInstance].ParameterValue = FloatValue;
}
else
{
if (!FloatParameters[ParameterIndexInInstance].ParameterRangeValues.IsValidIndex(RangeIndex))
{
const int32 InsertionIndex = FloatParameters[ParameterIndexInInstance].ParameterRangeValues.Num();
const int32 NumInsertedElements = RangeIndex + 1 - FloatParameters[ParameterIndexInInstance].ParameterRangeValues.Num();
FloatParameters[ParameterIndexInInstance].ParameterRangeValues.InsertDefaulted(InsertionIndex, NumInsertedElements);
}
check(FloatParameters[ParameterIndexInInstance].ParameterRangeValues.IsValidIndex(RangeIndex));
FloatParameters[ParameterIndexInInstance].ParameterRangeValues[RangeIndex] = FloatValue;
}
}
UTexture* FCustomizableObjectInstanceDescriptor::GetTextureParameterSelectedOption(const FString& TextureParamName, const int32 RangeIndex) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return nullptr;
}
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(TextureParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(TextureParamName, EMutableParameterType::Texture);
if (ParameterIndexInObject >= 0 && ParameterIndexInInstance >= 0)
{
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
return TextureParameters[ParameterIndexInInstance].ParameterValue;
}
else
{
if (TextureParameters[ParameterIndexInInstance].ParameterRangeValues.IsValidIndex(RangeIndex))
{
return TextureParameters[ParameterIndexInInstance].ParameterRangeValues[RangeIndex];
}
}
}
LogParameterNotFoundWarning(TextureParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return nullptr;
}
void FCustomizableObjectInstanceDescriptor::SetTextureParameterSelectedOption(const FString& TextureParamName, UTexture* TextureValue, const int32 RangeIndex)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
RETURN_ON_UNCOMPILED_CO(CustomizableObject, TEXT("Error: Cannot set Texture parameter "));
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(TextureParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(TextureParamName, EMutableParameterType::Texture);
if (ParameterIndexInObject < 0 || ParameterIndexInInstance < 0)
{
// Early out since we could not find the parameter to set.
LogParameterNotFoundWarning(TextureParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return;
}
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
TextureParameters[ParameterIndexInInstance].ParameterValue = TextureValue;
}
else
{
if (!TextureParameters[ParameterIndexInInstance].ParameterRangeValues.IsValidIndex(RangeIndex))
{
const int32 InsertionIndex = TextureParameters[ParameterIndexInInstance].ParameterRangeValues.Num();
const int32 NumInsertedElements = RangeIndex + 1 - TextureParameters[ParameterIndexInInstance].ParameterRangeValues.Num();
TextureParameters[ParameterIndexInInstance].ParameterRangeValues.InsertDefaulted(InsertionIndex, NumInsertedElements);
}
check(TextureParameters[ParameterIndexInInstance].ParameterRangeValues.IsValidIndex(RangeIndex));
TextureParameters[ParameterIndexInInstance].ParameterRangeValues[RangeIndex] = TextureValue;
}
}
USkeletalMesh* FCustomizableObjectInstanceDescriptor::GetSkeletalMeshParameterSelectedOption(const FString& SkeletalMeshParamName, int32 RangeIndex) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return nullptr;
}
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(SkeletalMeshParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(SkeletalMeshParamName, EMutableParameterType::SkeletalMesh);
if (ParameterIndexInObject >= 0 && ParameterIndexInInstance >= 0)
{
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
return SkeletalMeshParameters[ParameterIndexInInstance].ParameterValue;
}
else
{
if (SkeletalMeshParameters[ParameterIndexInInstance].ParameterRangeValues.IsValidIndex(RangeIndex))
{
return SkeletalMeshParameters[ParameterIndexInInstance].ParameterRangeValues[RangeIndex];
}
}
}
LogParameterNotFoundWarning(SkeletalMeshParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return nullptr;
}
void FCustomizableObjectInstanceDescriptor::SetSkeletalMeshParameterSelectedOption(const FString& SkeletalMeshParamName, USkeletalMesh* SkeletalMeshValue, int32 RangeIndex)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
RETURN_ON_UNCOMPILED_CO(CustomizableObject, TEXT("Error: Cannot set Skeletal Mesh parameter "));
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(SkeletalMeshParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(SkeletalMeshParamName, EMutableParameterType::SkeletalMesh);
if (ParameterIndexInObject < 0 || ParameterIndexInInstance < 0)
{
// Early out since we could not find the parameter to set.
LogParameterNotFoundWarning(SkeletalMeshParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return;
}
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
SkeletalMeshParameters[ParameterIndexInInstance].ParameterValue = SkeletalMeshValue;
}
else
{
if (!SkeletalMeshParameters[ParameterIndexInInstance].ParameterRangeValues.IsValidIndex(RangeIndex))
{
const int32 InsertionIndex = SkeletalMeshParameters[ParameterIndexInInstance].ParameterRangeValues.Num();
const int32 NumInsertedElements = RangeIndex + 1 - SkeletalMeshParameters[ParameterIndexInInstance].ParameterRangeValues.Num();
SkeletalMeshParameters[ParameterIndexInInstance].ParameterRangeValues.InsertDefaulted(InsertionIndex, NumInsertedElements);
}
check(SkeletalMeshParameters[ParameterIndexInInstance].ParameterRangeValues.IsValidIndex(RangeIndex));
SkeletalMeshParameters[ParameterIndexInInstance].ParameterRangeValues[RangeIndex] = SkeletalMeshValue;
}
}
FLinearColor FCustomizableObjectInstanceDescriptor::GetColorParameterSelectedOption(const FString& ColorParamName) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return FCustomizableObjectVectorParameterValue::DEFAULT_PARAMETER_VALUE;
}
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(ColorParamName);
const int32 ColorParamIndex = FindTypedParameterIndex(ColorParamName, EMutableParameterType::Color);
if (ColorParamIndex == INDEX_NONE)
{
LogParameterNotFoundWarning(ColorParamName, ParameterIndexInObject, ColorParamIndex, CustomizableObject, __FUNCTION__);
return FCustomizableObjectVectorParameterValue::DEFAULT_PARAMETER_VALUE;
}
// TODO: Multidimensional parameter support
return VectorParameters.IsValidIndex(ColorParamIndex) ? VectorParameters[ColorParamIndex].ParameterValue : FLinearColor();
}
void FCustomizableObjectInstanceDescriptor::SetColorParameterSelectedOption(const FString& ColorParamName, const FLinearColor& ColorValue)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
RETURN_ON_UNCOMPILED_CO(CustomizableObject, TEXT("Error: Cannot set Int parameter "));
// TODO: Multidimensional parameter support
SetVectorParameterSelectedOption(ColorParamName, ColorValue);
}
FTransform FCustomizableObjectInstanceDescriptor::GetTransformParameterSelectedOption(const FString& TransformParamName) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return FCustomizableObjectTransformParameterValue::DEFAULT_PARAMETER_VALUE;
}
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(TransformParamName);
const int32 TransformParamIndex = FindTypedParameterIndex(TransformParamName, EMutableParameterType::Transform);
if (TransformParamIndex == INDEX_NONE)
{
LogParameterNotFoundWarning(TransformParamName, ParameterIndexInObject, TransformParamIndex, CustomizableObject, __FUNCTION__);
return FCustomizableObjectTransformParameterValue::DEFAULT_PARAMETER_VALUE;
}
// TODO: Multidimensional parameter support
return TransformParameters.IsValidIndex(TransformParamIndex) ? TransformParameters[TransformParamIndex].ParameterValue : FTransform::Identity;
}
void FCustomizableObjectInstanceDescriptor::SetTransformParameterSelectedOption(const FString& TransformParamName, const FTransform& TransformValue)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
RETURN_ON_UNCOMPILED_CO(CustomizableObject, TEXT("Error: Cannot set Transform parameter "));
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(TransformParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(TransformParamName, EMutableParameterType::Transform);
if (ParameterIndexInObject < 0 || ParameterIndexInInstance < 0)
{
// Early out since we could not find the parameter to set.
LogParameterNotFoundWarning(TransformParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return;
}
// TODO: Multidimensional parameter support
TransformParameters[ParameterIndexInInstance].ParameterValue = TransformValue;
}
bool FCustomizableObjectInstanceDescriptor::GetBoolParameterSelectedOption(const FString& BoolParamName) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return FCustomizableObjectBoolParameterValue::DEFAULT_PARAMETER_VALUE;
}
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(BoolParamName);
const int32 BoolParamIndex = FindTypedParameterIndex(BoolParamName, EMutableParameterType::Bool);
if (BoolParamIndex == INDEX_NONE)
{
LogParameterNotFoundWarning(BoolParamName, ParameterIndexInObject, BoolParamIndex, CustomizableObject, __FUNCTION__);
return FCustomizableObjectBoolParameterValue::DEFAULT_PARAMETER_VALUE;
}
return BoolParameters[BoolParamIndex].ParameterValue;
}
void FCustomizableObjectInstanceDescriptor::SetBoolParameterSelectedOption(const FString& BoolParamName, const bool BoolValue)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
RETURN_ON_UNCOMPILED_CO(CustomizableObject, TEXT("Error: Cannot set Int parameter "));
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(BoolParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(BoolParamName, EMutableParameterType::Bool);
if (ParameterIndexInObject < 0 || ParameterIndexInInstance < 0)
{
// Early out since we could not find the parameter to set.
LogParameterNotFoundWarning(BoolParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return;
}
BoolParameters[ParameterIndexInInstance].ParameterValue = BoolValue;
}
void FCustomizableObjectInstanceDescriptor::SetVectorParameterSelectedOption(const FString& VectorParamName, const FLinearColor& VectorValue)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
RETURN_ON_UNCOMPILED_CO(CustomizableObject, TEXT("Error: Cannot set Int parameter "));
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(VectorParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(VectorParamName, EMutableParameterType::Color);
if (ParameterIndexInObject < 0 || ParameterIndexInInstance < 0)
{
// Early out since we could not find the parameter to set.
LogParameterNotFoundWarning(VectorParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return;
}
VectorParameters[ParameterIndexInInstance].ParameterValue = VectorValue;
}
void FCustomizableObjectInstanceDescriptor::SetProjectorValue(const FString& ProjectorParamName,
const FVector& Pos, const FVector& Direction, const FVector& Up, const FVector& Scale,
const float Angle,
const int32 RangeIndex)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
RETURN_ON_UNCOMPILED_CO(CustomizableObject, TEXT("Error: Cannot set Projector parameter "))
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(ProjectorParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(ProjectorParamName, EMutableParameterType::Projector);
if (ParameterIndexInObject < 0 || ParameterIndexInInstance < 0)
{
// Early out since we could not find the parameter to set.
LogParameterNotFoundWarning(ProjectorParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return;
}
// Parameter to modify
FCustomizableObjectProjectorParameterValue& ProjectorParameter = ProjectorParameters[ParameterIndexInInstance];
// New Value
FCustomizableObjectProjector ProjectorData;
ProjectorData.Position = static_cast<FVector3f>(Pos);
ProjectorData.Direction = static_cast<FVector3f>(Direction);
ProjectorData.Up = static_cast<FVector3f>(Up);
ProjectorData.Scale = static_cast<FVector3f>(Scale);
ProjectorData.Angle = Angle;
ProjectorData.ProjectionType = ProjectorParameter.Value.ProjectionType;
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
ProjectorParameter.Value = ProjectorData;
}
else
{
if (!ProjectorParameter.RangeValues.IsValidIndex(RangeIndex))
{
const int32 InsertionIndex = ProjectorParameter.RangeValues.Num();
const int32 NumInsertedElements = RangeIndex + 1 - ProjectorParameter.RangeValues.Num();
ProjectorParameter.RangeValues.InsertDefaulted(InsertionIndex, NumInsertedElements);
}
check(ProjectorParameter.RangeValues.IsValidIndex(RangeIndex));
ProjectorParameter.RangeValues[RangeIndex] = ProjectorData;
}
}
void FCustomizableObjectInstanceDescriptor::SetProjectorPosition(const FString& ProjectorParamName, const FVector& Pos, const int32 RangeIndex)
{
FVector DummyPos, Direction, Up, Scale;
float Angle;
ECustomizableObjectProjectorType Type;
GetProjectorValue(ProjectorParamName, DummyPos, Direction, Up, Scale, Angle, Type, RangeIndex);
SetProjectorValue(ProjectorParamName, static_cast<FVector>(Pos), Direction, Up, Scale, Angle, RangeIndex);
}
void FCustomizableObjectInstanceDescriptor::SetProjectorDirection(const FString& ProjectorParamName, const FVector& Direction, int32 RangeIndex)
{
FVector Position, DummyDirection, Up, Scale;
float Angle;
ECustomizableObjectProjectorType Type;
GetProjectorValue(ProjectorParamName, Position, DummyDirection, Up, Scale, Angle, Type, RangeIndex);
SetProjectorValue(ProjectorParamName, Position, Direction, Up, Scale, Angle, RangeIndex);
}
void FCustomizableObjectInstanceDescriptor::SetProjectorUp(const FString& ProjectorParamName, const FVector& Up, int32 RangeIndex)
{
FVector Position, Direction, DummyUp, Scale;
float Angle;
ECustomizableObjectProjectorType Type;
GetProjectorValue(ProjectorParamName, Position, Direction, DummyUp, Scale, Angle, Type, RangeIndex);
SetProjectorValue(ProjectorParamName, Position, Direction, Up, Scale, Angle, RangeIndex);
}
void FCustomizableObjectInstanceDescriptor::SetProjectorScale(const FString& ProjectorParamName, const FVector& Scale, int32 RangeIndex)
{
FVector Position, Direction, Up, DummyScale;
float Angle;
ECustomizableObjectProjectorType Type;
GetProjectorValue(ProjectorParamName, Position, Direction, Up, DummyScale, Angle, Type, RangeIndex);
SetProjectorValue(ProjectorParamName, Position, Direction, Up, Scale, Angle, RangeIndex);
}
void FCustomizableObjectInstanceDescriptor::SetProjectorAngle(const FString& ProjectorParamName, float Angle, int32 RangeIndex)
{
FVector Position, Direction, Up, Scale;
float DummyAngle;
ECustomizableObjectProjectorType Type;
GetProjectorValue(ProjectorParamName, Position, Direction, Up, Scale, DummyAngle, Type, RangeIndex);
SetProjectorValue(ProjectorParamName, Position, Direction, Up, Scale, Angle, RangeIndex);
}
void FCustomizableObjectInstanceDescriptor::GetProjectorValue(const FString& ProjectorParamName,
FVector& OutPos, FVector& OutDirection, FVector& OutUp, FVector& OutScale,
float& OutAngle, ECustomizableObjectProjectorType& OutType,
const int32 RangeIndex) const
{
FVector3f Pos, Direction, Up, Scale;
GetProjectorValueF(ProjectorParamName, Pos, Direction, Up, Scale, OutAngle, OutType, RangeIndex);
OutPos = static_cast<FVector>(Pos);
OutDirection = static_cast<FVector>(Direction);
OutUp = static_cast<FVector>(Up);
OutScale = static_cast<FVector>(Scale);
}
void FCustomizableObjectInstanceDescriptor::GetProjectorValueF(const FString& ProjectorParamName,
FVector3f& OutPos, FVector3f& OutDirection, FVector3f& OutUp, FVector3f& OutScale,
float& OutAngle, ECustomizableObjectProjectorType& OutType,
const int32 RangeIndex) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(ProjectorParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(ProjectorParamName, EMutableParameterType::Projector);
if (ParameterIndexInObject >= 0 && ParameterIndexInInstance >= 0)
{
const FCustomizableObjectProjectorParameterValue& ProjectorParameter = ProjectorParameters[ParameterIndexInInstance];
const FCustomizableObjectProjector* ProjectorData;
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
ProjectorData = &ProjectorParameter.Value;
}
else
{
check(ProjectorParameter.RangeValues.IsValidIndex(RangeIndex));
ProjectorData = &ProjectorParameter.RangeValues[RangeIndex];
}
if (ProjectorData)
{
OutPos = ProjectorData->Position;
OutDirection = ProjectorData->Direction;
OutUp = ProjectorData->Up;
OutScale = ProjectorData->Scale;
OutAngle = ProjectorData->Angle;
OutType = ProjectorData->ProjectionType;
}
}
else
{
LogParameterNotFoundWarning(ProjectorParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
}
}
FVector FCustomizableObjectInstanceDescriptor::GetProjectorPosition(const FString& ParamName, const int32 RangeIndex) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return FVector(-0.0, -0.0, -0.0);
}
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(ParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(ParamName, EMutableParameterType::Projector);
if (ParameterIndexInObject >= 0 && ParameterIndexInInstance >= 0)
{
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
return static_cast<FVector>(ProjectorParameters[ParameterIndexInInstance].Value.Position);
}
else if (ProjectorParameters[ParameterIndexInInstance].RangeValues.IsValidIndex(RangeIndex))
{
return static_cast<FVector>(ProjectorParameters[ParameterIndexInInstance].RangeValues[RangeIndex].Position);
}
}
LogParameterNotFoundWarning(ParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return FVector(-0.0,-0.0,-0.0);
}
FVector FCustomizableObjectInstanceDescriptor::GetProjectorDirection(const FString& ParamName, const int32 RangeIndex) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return FVector(-0.0, -0.0, -0.0);
}
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(ParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(ParamName, EMutableParameterType::Projector);
if (ParameterIndexInObject >= 0 && ParameterIndexInInstance >= 0)
{
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
return static_cast<FVector>(ProjectorParameters[ParameterIndexInInstance].Value.Direction);
}
else if (ProjectorParameters[ParameterIndexInInstance].RangeValues.IsValidIndex(RangeIndex))
{
return static_cast<FVector>(ProjectorParameters[ParameterIndexInInstance].RangeValues[RangeIndex].Direction);
}
}
LogParameterNotFoundWarning(ParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return FVector(-0.0, -0.0, -0.0);
}
FVector FCustomizableObjectInstanceDescriptor::GetProjectorUp(const FString& ParamName, const int32 RangeIndex) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return FVector(-0.0, -0.0, -0.0);
}
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(ParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(ParamName, EMutableParameterType::Projector);
if (ParameterIndexInObject >= 0 && ParameterIndexInInstance >= 0)
{
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
return static_cast<FVector>(ProjectorParameters[ParameterIndexInInstance].Value.Up);
}
else if (ProjectorParameters[ParameterIndexInInstance].RangeValues.IsValidIndex(RangeIndex))
{
return static_cast<FVector>(ProjectorParameters[ParameterIndexInInstance].RangeValues[RangeIndex].Up);
}
}
LogParameterNotFoundWarning(ParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return FVector(-0.0, -0.0, -0.0);
}
FVector FCustomizableObjectInstanceDescriptor::GetProjectorScale(const FString& ParamName, const int32 RangeIndex) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return FVector(-0.0, -0.0, -0.0);
}
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(ParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(ParamName, EMutableParameterType::Projector);
if (ParameterIndexInObject >= 0 && ParameterIndexInInstance >= 0)
{
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
return static_cast<FVector>(ProjectorParameters[ParameterIndexInInstance].Value.Scale);
}
else if (ProjectorParameters[ParameterIndexInInstance].RangeValues.IsValidIndex(RangeIndex))
{
return static_cast<FVector>(ProjectorParameters[ParameterIndexInInstance].RangeValues[RangeIndex].Scale);
}
}
LogParameterNotFoundWarning(ParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return FVector(-0.0, -0.0, -0.0);
}
float FCustomizableObjectInstanceDescriptor::GetProjectorAngle(const FString& ParamName, const int32 RangeIndex) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return 0.0;
}
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(ParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(ParamName, EMutableParameterType::Projector);
if (ParameterIndexInObject >= 0 && ParameterIndexInInstance >= 0)
{
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
return ProjectorParameters[ParameterIndexInInstance].Value.Angle;
}
else if (ProjectorParameters[ParameterIndexInInstance].RangeValues.IsValidIndex(RangeIndex))
{
return ProjectorParameters[ParameterIndexInInstance].RangeValues[RangeIndex].Angle;
}
}
LogParameterNotFoundWarning(ParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return 0.0;
}
ECustomizableObjectProjectorType FCustomizableObjectInstanceDescriptor::GetProjectorParameterType(const FString& ParamName, const int32 RangeIndex) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return ECustomizableObjectProjectorType::Planar;
}
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(ParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(ParamName, EMutableParameterType::Projector);
if (ParameterIndexInObject >= 0 && ParameterIndexInInstance >= 0)
{
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
return ProjectorParameters[ParameterIndexInInstance].Value.ProjectionType;
}
else if (ProjectorParameters[ParameterIndexInInstance].RangeValues.IsValidIndex(RangeIndex))
{
return ProjectorParameters[ParameterIndexInInstance].RangeValues[RangeIndex].ProjectionType;
}
}
LogParameterNotFoundWarning(ParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return ECustomizableObjectProjectorType::Planar;
}
FCustomizableObjectProjector FCustomizableObjectInstanceDescriptor::GetProjector(const FString& ParamName, const int32 RangeIndex) const
{
const int32 ParameterIndexInObject = CustomizableObject->GetPrivate()->FindParameter(ParamName);
const int32 ParameterIndexInInstance = FindTypedParameterIndex(ParamName, EMutableParameterType::Projector);
if (ParameterIndexInObject >= 0 && ParameterIndexInInstance >= 0)
{
// Due to optimizations a parameter may lose its multidimensionality (if it becomes constant).
// In that case it means there is only one possible option so it is ok to set it as if wasn't multidimensional.
bool bIsMultidimensional = CustomizableObject->GetPrivate()->IsParameterMultidimensional(ParameterIndexInObject);
if (!bIsMultidimensional || RangeIndex == INDEX_NONE)
{
return ProjectorParameters[ParameterIndexInInstance].Value;
}
else if (ProjectorParameters[ParameterIndexInInstance].RangeValues.IsValidIndex(RangeIndex))
{
return ProjectorParameters[ParameterIndexInInstance].RangeValues[RangeIndex];
}
}
LogParameterNotFoundWarning(ParamName, ParameterIndexInObject, ParameterIndexInInstance, CustomizableObject, __FUNCTION__);
return FCustomizableObjectProjectorParameterValue::DEFAULT_PARAMETER_VALUE;
}
int32 FCustomizableObjectInstanceDescriptor::FindTypedParameterIndex(const FString& ParamName, EMutableParameterType Type) const
{
return CustomizableObject ? CustomizableObject->GetPrivate()->FindParameterTyped(ParamName, Type) : INDEX_NONE;
}
int32 FCustomizableObjectInstanceDescriptor::GetProjectorValueRange(const FString& ParamName) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return -1;
}
const int32 ProjectorParamIndex = FindTypedParameterIndex(ParamName, EMutableParameterType::Projector);
if (ProjectorParamIndex < 0)
{
return -1;
}
return ProjectorParameters[ProjectorParamIndex].RangeValues.Num();
}
int32 FCustomizableObjectInstanceDescriptor::GetIntValueRange(const FString& ParamName) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return -1;
}
const int32 IntParamIndex = FindTypedParameterIndex(ParamName, EMutableParameterType::Int);
if (IntParamIndex < 0)
{
return -1;
}
return IntParameters[IntParamIndex].ParameterRangeValueNames.Num();
}
int32 FCustomizableObjectInstanceDescriptor::GetFloatValueRange(const FString& ParamName) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return -1;
}
const int32 FloatParamIndex = FindTypedParameterIndex(ParamName, EMutableParameterType::Float);
if (FloatParamIndex < 0)
{
return -1;
}
return FloatParameters[FloatParamIndex].ParameterRangeValues.Num();
}
int32 FCustomizableObjectInstanceDescriptor::GetTextureValueRange(const FString& ParamName) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return -1;
}
const int32 TextureParamIndex = FindTypedParameterIndex(ParamName, EMutableParameterType::Texture);
if (TextureParamIndex < 0)
{
return -1;
}
return TextureParameters[TextureParamIndex].ParameterRangeValues.Num();
}
int32 FCustomizableObjectInstanceDescriptor::AddValueToIntRange(const FString& ParamName)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return -1;
}
const int32 IntParameterIndex = FindTypedParameterIndex(ParamName, EMutableParameterType::Int);
if (IntParameterIndex != INDEX_NONE)
{
FCustomizableObjectIntParameterValue& IntParameter = IntParameters[IntParameterIndex];
const int32 ParamIndexInObject = CustomizableObject->GetPrivate()->FindParameter(IntParameter.ParameterName);
// TODO: Define the default option in the editor instead of taking the first available, like it's currently defined for GetProjectorDefaultValue()
const FString DefaultValue = CustomizableObject->GetPrivate()->GetIntParameterAvailableOption(ParamIndexInObject, 0);
return IntParameter.ParameterRangeValueNames.Add(DefaultValue);
}
return -1;
}
int32 FCustomizableObjectInstanceDescriptor::AddValueToFloatRange(const FString& ParamName)
{
const int32 FloatParameterIndex = FindTypedParameterIndex(ParamName, EMutableParameterType::Float);
if (FloatParameterIndex != INDEX_NONE)
{
FCustomizableObjectFloatParameterValue& FloatParameter = FloatParameters[FloatParameterIndex];
// TODO: Define the default float in the editor instead of [0.5f], like it's currently defined for GetProjectorDefaultValue()
return FloatParameter.ParameterRangeValues.Add(0.5f);
}
return -1;
}
int32 FCustomizableObjectInstanceDescriptor::AddValueToTextureRange(const FString& ParamName)
{
const int32 TextureParameterIndex = FindTypedParameterIndex(ParamName, EMutableParameterType::Texture);
if (TextureParameterIndex != INDEX_NONE)
{
FCustomizableObjectTextureParameterValue& TextureParameter = TextureParameters[TextureParameterIndex];
return TextureParameter.ParameterRangeValues.Add(nullptr);
}
return -1;
}
int32 FCustomizableObjectInstanceDescriptor::AddValueToProjectorRange(const FString& ParamName)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return -1;
}
const int32 ProjectorParameterIndex = FindTypedParameterIndex(ParamName, EMutableParameterType::Projector);
if (ProjectorParameterIndex != INDEX_NONE)
{
FCustomizableObjectProjectorParameterValue& ProjectorParameter = ProjectorParameters[ProjectorParameterIndex];
const FCustomizableObjectProjector Projector = GetCustomizableObject()->GetProjectorParameterDefaultValue(ParamName);
return ProjectorParameter.RangeValues.Add(Projector);
}
return -1;
}
int32 FCustomizableObjectInstanceDescriptor::RemoveValueFromIntRange(const FString& ParamName, const int32 RangeIndex)
{
const int32 IntParameterIndex = FindTypedParameterIndex(ParamName, EMutableParameterType::Int);
if (IntParameterIndex != INDEX_NONE)
{
FCustomizableObjectIntParameterValue& IntParameter = IntParameters[IntParameterIndex];
if (IntParameter.ParameterRangeValueNames.Num() > 0)
{
int32 IndexToRemove = IntParameter.ParameterRangeValueNames.IsValidIndex(RangeIndex) ? RangeIndex : IntParameter.ParameterRangeValueNames.Num() - 1;
IntParameter.ParameterRangeValueNames.RemoveAt(IndexToRemove);
return IntParameter.ParameterRangeValueNames.Num() - 1;
}
}
return -1;
}
int32 FCustomizableObjectInstanceDescriptor::RemoveValueFromFloatRange(const FString& ParamName, const int32 RangeIndex)
{
const int32 FloatParameterIndex = FindTypedParameterIndex(ParamName, EMutableParameterType::Float);
if (FloatParameterIndex != INDEX_NONE)
{
FCustomizableObjectFloatParameterValue& FloatParameter = FloatParameters[FloatParameterIndex];
if (FloatParameter.ParameterRangeValues.Num() > 0)
{
int32 IndexToRemove = FloatParameter.ParameterRangeValues.IsValidIndex(RangeIndex) ? RangeIndex : FloatParameter.ParameterRangeValues.Num() - 1;
FloatParameter.ParameterRangeValues.RemoveAt(IndexToRemove);
return FloatParameter.ParameterRangeValues.Num() - 1;
}
}
return -1;
}
int32 FCustomizableObjectInstanceDescriptor::RemoveValueFromTextureRange(const FString& ParamName)
{
const int32 TextureParameterIndex = FindTypedParameterIndex(ParamName, EMutableParameterType::Texture);
if (TextureParameterIndex != INDEX_NONE)
{
FCustomizableObjectTextureParameterValue& TextureParameter = TextureParameters[TextureParameterIndex];
if (TextureParameter.ParameterRangeValues.Num() > 0)
{
TextureParameter.ParameterRangeValues.Pop();
return TextureParameter.ParameterRangeValues.Num() - 1;
}
}
return -1;
}
int32 FCustomizableObjectInstanceDescriptor::RemoveValueFromTextureRange(const FString& ParamName, const int32 RangeIndex)
{
const int32 TextureParameterIndex = FindTypedParameterIndex(ParamName, EMutableParameterType::Texture);
if (TextureParameterIndex != INDEX_NONE)
{
FCustomizableObjectTextureParameterValue& TextureParameter = TextureParameters[TextureParameterIndex];
if (TextureParameter.ParameterRangeValues.Num() > 0)
{
TextureParameter.ParameterRangeValues.RemoveAt(RangeIndex);
return TextureParameter.ParameterRangeValues.Num() - 1;
}
}
return -1;
}
int32 FCustomizableObjectInstanceDescriptor::RemoveValueFromProjectorRange(const FString& ParamName, const int32 RangeIndex)
{
const int32 ProjectorParameterIndex = FindTypedParameterIndex(ParamName, EMutableParameterType::Projector);
if (ProjectorParameterIndex != INDEX_NONE)
{
FCustomizableObjectProjectorParameterValue& ProjectorParameter = ProjectorParameters[ProjectorParameterIndex];
if (ProjectorParameter.RangeValues.Num() > 0)
{
int32 IndexToRemove = ProjectorParameter.RangeValues.IsValidIndex(RangeIndex) ? RangeIndex : ProjectorParameter.RangeValues.Num() - 1;
ProjectorParameter.RangeValues.RemoveAt(IndexToRemove);
return ProjectorParameter.RangeValues.Num() - 1;
}
}
return -1;
}
int32 FCustomizableObjectInstanceDescriptor::GetState() const
{
return State;
}
FString FCustomizableObjectInstanceDescriptor::GetCurrentState() const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return FString();
}
return CustomizableObject->GetPrivate()->GetStateName(GetState());
}
void FCustomizableObjectInstanceDescriptor::SetState(const int32 InState)
{
State = InState;
}
void FCustomizableObjectInstanceDescriptor::SetCurrentState(const FString& StateName)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
RETURN_ON_UNCOMPILED_CO(CustomizableObject, TEXT("Error: Cannot set state"))
const int32 Result = CustomizableObject->GetPrivate()->FindState(StateName);
#if WITH_EDITOR
if (Result != INDEX_NONE)
#else
if (ensureMsgf(Result != INDEX_NONE, TEXT("Unknown %s state."), *StateName))
#endif
{
SetState(Result);
}
else
{
UE_LOG(LogMutable, Error, TEXT("%hs: Unknown %s state."), __FUNCTION__, *StateName);
}
}
void FCustomizableObjectInstanceDescriptor::SetRandomValues()
{
const int32 RandomSeed = FMath::SRand() * TNumericLimits<int32>::Max();
FRandomStream RandomStream{RandomSeed};
SetRandomValuesFromStream(RandomSeed);
}
void FCustomizableObjectInstanceDescriptor::SetRandomValuesFromStream(const FRandomStream& InStream)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
RETURN_ON_UNCOMPILED_CO(CustomizableObject, TEXT("Error: Cannot set random values"))
for (FCustomizableObjectFloatParameterValue& FloatParameter : FloatParameters)
{
FloatParameter.ParameterValue = InStream.GetFraction();
for (float& RangeValue : FloatParameter.ParameterRangeValues)
{
RangeValue = InStream.GetFraction();
}
}
for (FCustomizableObjectBoolParameterValue& BoolParameter : BoolParameters)
{
BoolParameter.ParameterValue = static_cast<bool>(InStream.RandRange(0, 1));
}
for (FCustomizableObjectIntParameterValue& IntParameter : IntParameters)
{
const int32 NumValues = CustomizableObject->GetEnumParameterNumValues(IntParameter.ParameterName);
if (NumValues)
{
IntParameter.ParameterValueName = CustomizableObject->GetEnumParameterValue(IntParameter.ParameterName, NumValues * InStream.GetFraction());
for (FString& RangeValue : IntParameter.ParameterRangeValueNames)
{
RangeValue = CustomizableObject->GetEnumParameterValue(IntParameter.ParameterName, NumValues * InStream.GetFraction());
}
}
}
for (FCustomizableObjectVectorParameterValue& VectorParameter : VectorParameters)
{
VectorParameter.ParameterValue.R = InStream.GetFraction();
VectorParameter.ParameterValue.G = InStream.GetFraction();
VectorParameter.ParameterValue.B = InStream.GetFraction();
VectorParameter.ParameterValue.A = InStream.GetFraction();
}
// Currently we are not randomizing the projectors since we do not know the valid range of values.
}
void FCustomizableObjectInstanceDescriptor::SetDefaultValue(int32 ParamIndex)
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
if (ParamIndex >= CustomizableObject->GetParameterCount())
{
return;
}
const FString ParamName = CustomizableObject->GetParameterName(ParamIndex);
const EMutableParameterType ParamType = CustomizableObject->GetPrivate()->GetParameterType(ParamIndex);
const int32 TypedIndex = FindTypedParameterIndex(ParamName, ParamType);
switch (ParamType)
{
case EMutableParameterType::Bool:
{
const bool DefaultValue = CustomizableObject->GetBoolParameterDefaultValue(ParamName);
BoolParameters[TypedIndex].ParameterValue = DefaultValue;
break;
}
case EMutableParameterType::Int:
{
const FString DefaultValue = CustomizableObject->GetPrivate()->FindIntParameterValueName(ParamIndex, CustomizableObject->GetEnumParameterDefaultValue(ParamName));
FCustomizableObjectIntParameterValue& IntParameter = IntParameters[TypedIndex];
IntParameter.ParameterValueName = DefaultValue;
IntParameter.ParameterRangeValueNames.Empty();
break;
}
case EMutableParameterType::Float:
{
const float DefaultValue = CustomizableObject->GetFloatParameterDefaultValue(ParamName);
FCustomizableObjectFloatParameterValue& FloatParameter = FloatParameters[TypedIndex];
FloatParameter.ParameterValue = DefaultValue;
FloatParameter.ParameterRangeValues.Empty();
break;
}
case EMutableParameterType::Color:
{
const FLinearColor DefaultValue = CustomizableObject->GetColorParameterDefaultValue(ParamName);
VectorParameters[TypedIndex].ParameterValue = DefaultValue;
break;
}
case EMutableParameterType::Transform:
{
const FTransform DefaultValue = CustomizableObject->GetTransformParameterDefaultValue(ParamName);
TransformParameters[TypedIndex].ParameterValue = DefaultValue;
break;
}
case EMutableParameterType::Projector:
{
const FCustomizableObjectProjector DefaultValue = CustomizableObject->GetProjectorParameterDefaultValue(ParamName);
FCustomizableObjectProjectorParameterValue& ProjectorParameter = ProjectorParameters[TypedIndex];
ProjectorParameter.Value = DefaultValue;
ProjectorParameter.RangeValues.Empty();
break;
}
case EMutableParameterType::Texture:
{
UTexture* DefaultValue = CustomizableObject->GetTextureParameterDefaultValue(ParamName);
if (ensure(TextureParameters.IsValidIndex(TypedIndex)))
{
FCustomizableObjectTextureParameterValue& TextureParameter = TextureParameters[TypedIndex];
TextureParameter.ParameterValue = DefaultValue;
TextureParameter.ParameterRangeValues.Empty();
}
break;
}
case EMutableParameterType::SkeletalMesh:
{
USkeletalMesh* DefaultValue = CustomizableObject->GetSkeletalMeshParameterDefaultValue(ParamName);
if (ensure(SkeletalMeshParameters.IsValidIndex(TypedIndex)))
{
FCustomizableObjectSkeletalMeshParameterValue& SkeletalMeshParameter = SkeletalMeshParameters[TypedIndex];
SkeletalMeshParameter.ParameterValue = DefaultValue;
SkeletalMeshParameter.ParameterRangeValues.Empty();
}
break;
}
default:
// Parameter type replication not implemented.
unimplemented();
}
}
void FCustomizableObjectInstanceDescriptor::SetDefaultValues()
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return;
}
const int32 NumParameters = CustomizableObject->GetParameterCount();
for (int32 ParamIndex = 0; ParamIndex < NumParameters; ++ParamIndex)
{
SetDefaultValue(ParamIndex);
}
}
bool FCustomizableObjectInstanceDescriptor::IsMultilayerProjector(const FString& ParamName) const
{
if (!CustomizableObject)
{
CustomizableObjectNullErrorMessage();
return false;
}
// Projector.
if (const int32 ProjectorParameterIndex = FindTypedParameterIndex(ParamName, EMutableParameterType::Projector);
ProjectorParameterIndex == INDEX_NONE)
{
ensureAlwaysMsgf(false, TEXT("%s"), *MULTILAYER_PROJECTOR_PARAMETERS_INVALID);
return false;
}
// Num layers.
if (const int32 FloatParameterIndex = FindTypedParameterIndex(ParamName + NUM_LAYERS_PARAMETER_POSTFIX, EMutableParameterType::Float);
FloatParameterIndex == INDEX_NONE)
{
ensureAlwaysMsgf(false, TEXT("%s"), *MULTILAYER_PROJECTOR_PARAMETERS_INVALID);
return false;
}
// Selected Image.
if (const int32 IntParameterIndex = FindTypedParameterIndex(ParamName + IMAGE_PARAMETER_POSTFIX, EMutableParameterType::Int);
IntParameterIndex == INDEX_NONE)
{
ensureAlwaysMsgf(false, TEXT("%s"), *MULTILAYER_PROJECTOR_PARAMETERS_INVALID);
return false;
}
// Opacity.
if (const int32 FloatParameterIndex = FindTypedParameterIndex(ParamName + OPACITY_PARAMETER_POSTFIX, EMutableParameterType::Float);
FloatParameterIndex == INDEX_NONE)
{
ensureAlwaysMsgf(false, TEXT("%s"), *MULTILAYER_PROJECTOR_PARAMETERS_INVALID);
return false;
}
return true;
}
int32 FCustomizableObjectInstanceDescriptor::NumProjectorLayers(const FName& ProjectorParamName) const
{
const FString ParamName = ProjectorParamName.ToString();
if (IsMultilayerProjector(ParamName))
{
return GetFloatParameterSelectedOption(ParamName + NUM_LAYERS_PARAMETER_POSTFIX);
}
return INDEX_NONE;
}
void FCustomizableObjectInstanceDescriptor::CreateLayer(const FName& ProjectorParamName, int32 RangeIndex)
{
const FString ParamName = ProjectorParamName.ToString();
if (!IsMultilayerProjector(ParamName))
{
return;
}
// Num Layers.
SetFloatParameterSelectedOption(ParamName + NUM_LAYERS_PARAMETER_POSTFIX, NumProjectorLayers(ProjectorParamName) + 1);
// Projector Range. New value is defaulted.
AddValueToProjectorRange(ParamName);
// Selected Image Range.
{
const FString ImageParamName = ParamName + IMAGE_PARAMETER_POSTFIX;
AddValueToTextureRange(ImageParamName);
const int32 DefaultValueIndex = CustomizableObject->GetEnumParameterDefaultValue(ImageParamName);
const FString DefaultValueName = CustomizableObject->GetEnumParameterValue(ImageParamName, DefaultValueIndex);
SetIntParameterSelectedOption(ImageParamName, DefaultValueName, RangeIndex);
}
// Opacity Range.
{
const FString OpacityParamName = ParamName + OPACITY_PARAMETER_POSTFIX;
AddValueToFloatRange(OpacityParamName);
const float DefaultValue = CustomizableObject->GetFloatParameterDefaultValue(OpacityParamName);
SetFloatParameterSelectedOption(OpacityParamName, DefaultValue, RangeIndex);
}
}
void FCustomizableObjectInstanceDescriptor::RemoveLayerAt(const FName& ProjectorParamName, int32 RangeIndex)
{
const FString ParamName = ProjectorParamName.ToString();
const int32 NumLayers = NumProjectorLayers(ProjectorParamName);
check(RangeIndex >= 0 && RangeIndex < NumLayers); // Layer out of range.
if (!IsMultilayerProjector(ParamName))
{
return;
}
// Num Layers.
SetFloatParameterSelectedOption(ParamName + NUM_LAYERS_PARAMETER_POSTFIX, NumLayers - 1);
// Projector Range.
RemoveValueFromProjectorRange(ParamName, RangeIndex);
// Selected Image Range.
RemoveValueFromIntRange(ParamName + IMAGE_PARAMETER_POSTFIX, RangeIndex);
// Opacity Range.
RemoveValueFromFloatRange(ParamName + OPACITY_PARAMETER_POSTFIX, RangeIndex);
}
FMultilayerProjectorLayer FCustomizableObjectInstanceDescriptor::GetLayer(const FName& ProjectorParamName, int32 Index) const
{
const FString ParamName = ProjectorParamName.ToString();
FMultilayerProjectorLayer ProjectorLayer;
if (IsMultilayerProjector(ParamName))
{
ProjectorLayer.Read(*this, ParamName, Index);
}
return ProjectorLayer;
}
void FCustomizableObjectInstanceDescriptor::UpdateLayer(const FName& ProjectorParamName, int32 Index, const FMultilayerProjectorLayer& Layer)
{
const FString& ParamName = ProjectorParamName.ToString();
if (!IsMultilayerProjector(ParamName))
{
return;
}
Layer.Write(*this, ParamName, Index);
}
#undef RETURN_ON_CO_UNCOMPILED