Files
UnrealEngine/Engine/Plugins/Mutable/Source/MutableRuntime/Private/MuR/CodeRunnerBegin.cpp
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

2372 lines
54 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "CodeRunnerBegin.h"
#include "CodeRunner.h"
#include "MuR/MutableTrace.h"
#include "MuR/Operations.h"
#include "MuR/SystemPrivate.h"
namespace UE::Mutable::Private
{
CodeRunnerBegin::CodeRunnerBegin(FSystem& InSystem, const TSharedPtr<const FModel>& InModel, const TSharedPtr<const FParameters>& InParams, uint32 InLodMask) :
Model(InModel),
Params(InParams),
System(InSystem),
Program(InModel->GetPrivate()->Program),
LodMask(InLodMask),
Executed(InModel->GetPrivate()->Program.OpAddress.Num())
{
}
bool FScheduledOpInline::operator==(const FScheduledOpInline& Other) const
{
return At == Other.At && Stage == Other.Stage && ExecutionIndex == Other.ExecutionIndex;
}
uint32 GetTypeHash(const FScheduledOpInline& Op)
{
uint32 Hash = Op.At;
Hash = HashCombineFast(Hash, Op.Stage);
Hash = HashCombineFast(Hash, Op.ExecutionIndex);
return Hash;
}
uint32 GetTypeHash(const FCacheAddressInline& Address)
{
return HashCombineFast(Address.At, static_cast<uint32>(Address.ExecutionIndex));
}
FOpSet::FOpSet(int32 NumElements)
{
Index0.SetNum(NumElements, false);
}
bool FOpSet::Contains(const FCacheAddressInline& Item)
{
if (Item.ExecutionIndex == 0)
{
return Index0[Item.At];
}
else
{
return IndexOther.Contains(Item);
}
}
void FOpSet::Add(const FCacheAddressInline& Item)
{
if (Item.ExecutionIndex == 0)
{
Index0[Item.At] = true;
}
else
{
IndexOther.Add(Item);
}
}
FStackValue FStack::Pop()
{
return TArray::Pop(EAllowShrinking::No);
}
FProgramCache& CodeRunnerBegin::GetMemory() const
{
return *System.GetPrivate()->WorkingMemoryManager.CurrentInstanceCache;
}
FScheduledOpInline CodeRunnerBegin::PopOp()
{
return Items.Pop(EAllowShrinking::No);
}
void CodeRunnerBegin::PushOp(const FScheduledOpInline& Item)
{
check(Item.At < static_cast<uint32>(Program.OpAddress.Num()));
if (!Item.At)
{
return;
}
Items.Push(Item);
}
void CodeRunnerBegin::StoreInt(const FCacheAddressInline& To, int32 Value)
{
if (!To.At)
{
return;
}
Executed.Add(To);
FStackValue StackValue;
StackValue.Set<int32>(Value);
Stack.Push(StackValue);
ResultsInt.Add(To, Value);
}
void CodeRunnerBegin::StoreFloat(const FCacheAddressInline& To, float Value)
{
if (!To.At)
{
return;
}
Executed.Add(To);
FStackValue StackValue;
StackValue.Set<float>(Value);
Stack.Push(StackValue);
ResultsFloat.Add(To, Value);
}
void CodeRunnerBegin::StoreBool(const FCacheAddressInline& To, bool Value)
{
if (!To.At)
{
return;
}
Executed.Add(To);
FStackValue StackValue;
StackValue.Set<bool>(Value);
Stack.Push(StackValue);
ResultsBool.Add(To, Value);
}
void CodeRunnerBegin::StoreInstance(const FCacheAddressInline& To, const TSharedPtr<const FInstance>& Value)
{
if (!To.At)
{
return;
}
Executed.Add(To);
FStackValue StackValue;
StackValue.Set<TSharedPtr<const FInstance>>(Value);
Stack.Push(StackValue);
ResultsInstance.Add(To, Value);
}
void CodeRunnerBegin::StoreString(const FCacheAddressInline& To, const TSharedPtr<const String>& Value)
{
if (!To.At)
{
return;
}
Executed.Add(To);
FStackValue StackValue;
StackValue.Set<TSharedPtr<const String>>(Value);
Stack.Push(StackValue);
ResultsString.Add(To, Value);
}
void CodeRunnerBegin::StoreExtensionData(const FCacheAddressInline& To, const TSharedPtr<const FExtensionData>& Value)
{
if (!To.At)
{
return;
}
Executed.Add(To);
FStackValue StackValue;
StackValue.Set<TSharedPtr<const FExtensionData>>(Value);
Stack.Push(StackValue);
ResultsExtensionData.Add(To, Value);
}
void CodeRunnerBegin::StoreNone(const FCacheAddressInline& To)
{
if (!To.At)
{
return;
}
Executed.Add(To);
}
int32 CodeRunnerBegin::LoadInt(const FCacheAddressInline& To)
{
if (!To.At)
{
return 0;
}
return Stack.Pop().Get<int32>();
}
float CodeRunnerBegin::LoadFloat(const FCacheAddressInline& To)
{
if (!To.At)
{
return 0.0f;
}
return Stack.Pop().Get<float>();
}
bool CodeRunnerBegin::LoadBool(const FCacheAddressInline& To)
{
if (!To.At)
{
return false;
}
return Stack.Pop().Get<bool>();
}
TSharedPtr<const FInstance> CodeRunnerBegin::LoadInstance(const FCacheAddressInline& To)
{
if (!To.At)
{
return nullptr;
}
return Stack.Pop().Get<TSharedPtr<const FInstance>>();
}
TSharedPtr<const String> CodeRunnerBegin::LoadString(const FCacheAddressInline& To)
{
if (!To.At)
{
return nullptr;
}
return Stack.Pop().Get<TSharedPtr<const String>>();
}
TSharedPtr<const FExtensionData> CodeRunnerBegin::LoadExtensionData(const FCacheAddressInline& To)
{
if (!To.At)
{
return nullptr;
}
return Stack.Pop().Get<TSharedPtr<const FExtensionData>>();
}
TSharedPtr<const FInstance> CodeRunnerBegin::RunCode(const FScheduledOpInline& Root)
{
MUTABLE_CPUPROFILER_SCOPE(CodeRunnerBegin::RunCode);
PushOp(Root);
while (!Items.IsEmpty())
{
const FScheduledOpInline Item = PopOp();
const EOpType Type = Program.GetOpType(Item.At);
if (Executed.Contains(Item))
{
switch (GetOpDataType(Type))
{
case EDataType::Bool:
{
FStackValue Value;
Value.Set<bool>(ResultsBool[Item]);
Stack.Push(Value);
break;
}
case EDataType::Int:
{
FStackValue Value;
Value.Set<int32>(ResultsInt[Item]);
Stack.Push(Value);
break;
}
case EDataType::Instance:
{
FStackValue Value;
Value.Set<TSharedPtr<const FInstance>>(ResultsInstance[Item]);
Stack.Push(Value);
break;
}
case EDataType::String:
{
FStackValue Value;
Value.Set<TSharedPtr<const String>>(ResultsString[Item]);
Stack.Push(Value);
break;
}
case EDataType::ExtensionData:
{
FStackValue Value;
Value.Set<TSharedPtr<const FExtensionData>>(ResultsExtensionData[Item]);
Stack.Push(Value);
break;
}
case EDataType::Scalar:
{
FStackValue Value;
Value.Set<float>(ResultsFloat[Item]);
Stack.Push(Value);
break;
}
case EDataType::Color:
case EDataType::Projector:
case EDataType::Mesh:
case EDataType::Image:
case EDataType::Layout:
case EDataType::Material:
break;
default:
unimplemented();
}
continue;
}
switch (Type)
{
case EOpType::CO_CONSTANT:
case EOpType::IM_CONSTANT:
case EOpType::LA_CONSTANT:
case EOpType::MA_CONSTANT:
case EOpType::PR_CONSTANT:
case EOpType::CO_PARAMETER:
case EOpType::MA_PARAMETER:
case EOpType::PR_PARAMETER:
case EOpType::ME_PARAMETER:
case EOpType::IM_PARAMETER:
case EOpType::MI_PARAMETER:
case EOpType::IM_PARAMETER_FROM_MATERIAL:
{
StoreNone(Item);
break;
}
case EOpType::CO_CONDITIONAL:
case EOpType::ED_CONDITIONAL:
case EOpType::IM_CONDITIONAL:
case EOpType::IN_CONDITIONAL:
case EOpType::LA_CONDITIONAL:
case EOpType::ME_CONDITIONAL:
case EOpType::SC_CONDITIONAL:
case EOpType::MI_CONDITIONAL:
{
OP::ConditionalArgs Args = Program.GetOpArgs<OP::ConditionalArgs>(Item.At);
switch(Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline( Item,1));
PushOp(FScheduledOpInline( Args.condition, Item));
break;
}
case 1:
{
const bool Value = LoadBool(Args.condition);
OP::ADDRESS ResultAt = Value ? Args.yes : Args.no;
// Schedule the end of this instruction if necessary
FScheduledOpInline NextStage(Item, 2);
NextStage.CustomState = ResultAt;
PushOp(NextStage);
PushOp(FScheduledOpInline(ResultAt, Item));
break;
}
case 2:
{
switch (GetOpDataType(Type))
{
case EDataType::Int:
StoreInt(Item, LoadInt(Item.CustomState));
break;
case EDataType::String:
StoreString(Item, LoadString(Item.CustomState));
break;
case EDataType::Instance:
StoreInstance(Item, LoadInstance(Item.CustomState));
break;
case EDataType::ExtensionData:
StoreExtensionData(Item, LoadExtensionData(Item.CustomState));
break;
case EDataType::Scalar:
StoreFloat(Item, LoadFloat(Item.CustomState));
break;
case EDataType::Color:
case EDataType::Projector:
case EDataType::Mesh:
case EDataType::Image:
case EDataType::Layout:
case EDataType::Material:
StoreNone(Item);
break;
case EDataType::Bool:
check(false);
default:
unimplemented();
}
break;
}
default:
unimplemented();
}
break;
}
case EOpType::NU_CONDITIONAL:
{
OP::ConditionalArgs Args = Program.GetOpArgs<OP::ConditionalArgs>(Item.At);
switch(Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item,1));
PushOp(FScheduledOpInline(Args.condition, Item));
break;
}
case 1:
{
const bool Value = LoadBool(Args.condition);
OP::ADDRESS ResultAt = Value ? Args.yes : Args.no;
PushOp(FScheduledOpInline(ResultAt, Item));
StoreNone(Item);
break;
}
default:
unimplemented();
}
break;
}
case EOpType::CO_SWITCH:
case EOpType::ED_SWITCH:
case EOpType::IM_SWITCH:
case EOpType::IN_SWITCH:
case EOpType::LA_SWITCH:
case EOpType::ME_SWITCH:
case EOpType::NU_SWITCH:
case EOpType::SC_SWITCH:
case EOpType::MI_SWITCH:
{
const uint8* Data = Program.GetOpArgsPointer(Item.At);
OP::ADDRESS VarAddress;
FMemory::Memcpy(&VarAddress, Data, sizeof(OP::ADDRESS));
Data += sizeof(OP::ADDRESS);
OP::ADDRESS DefAddress;
FMemory::Memcpy(&DefAddress, Data, sizeof(OP::ADDRESS));
Data += sizeof(OP::ADDRESS);
OP::FSwitchCaseDescriptor CaseDesc;
FMemory::Memcpy(&CaseDesc, Data, sizeof(OP::FSwitchCaseDescriptor));
Data += sizeof(OP::FSwitchCaseDescriptor);
switch (Item.Stage)
{
case 0:
{
if (VarAddress)
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(VarAddress, Item));
}
else
{
switch (GetOpDataType(Type))
{
case EDataType::Bool:
StoreBool(Item, false);
break;
case EDataType::Int:
StoreInt(Item, 0);
break;
case EDataType::Instance:
StoreInstance(Item, nullptr);
break;
case EDataType::String:
StoreString(Item, nullptr);
break;
case EDataType::ExtensionData:
StoreExtensionData(Item, MakeShared<FExtensionData>());
break;
case EDataType::Scalar:
StoreFloat(Item, 0.0f);
break;
case EDataType::Color:
case EDataType::Projector:
case EDataType::Mesh:
case EDataType::Image:
case EDataType::Layout:
case EDataType::Material:
StoreNone(Item);
break;
default:
unimplemented()
}
}
break;
}
case 1:
{
// Get the variable result
int32 Var = LoadInt(VarAddress);
OP::ADDRESS ValueAt = DefAddress;
if (!CaseDesc.bUseRanges)
{
for (uint32 C = 0; C < CaseDesc.Count; ++C)
{
int32 Condition;
FMemory::Memcpy(&Condition, Data, sizeof(int32));
Data += sizeof(int32);
OP::ADDRESS CaseAt;
FMemory::Memcpy(&CaseAt, Data, sizeof(OP::ADDRESS));
Data += sizeof(OP::ADDRESS);
if (CaseAt && Var == (int32)Condition)
{
ValueAt = CaseAt;
break;
}
}
}
else
{
for (uint32 C = 0; C < CaseDesc.Count; ++C)
{
int32 ConditionStart;
FMemory::Memcpy(&ConditionStart, Data, sizeof(int32));
Data += sizeof(int32);
uint32 RangeSize;
FMemory::Memcpy(&RangeSize, Data, sizeof(uint32));
Data += sizeof(uint32);
OP::ADDRESS CaseAt;
FMemory::Memcpy(&CaseAt, Data, sizeof(OP::ADDRESS));
Data += sizeof(OP::ADDRESS);
if (CaseAt && Var >= ConditionStart && Var < int32(ConditionStart + RangeSize))
{
ValueAt = CaseAt;
break;
}
}
}
// Schedule the end of this instruction if necessary
FScheduledOpInline NextStage(Item, 2);
NextStage.CustomState = ValueAt;
PushOp(NextStage);
PushOp(FScheduledOpInline(ValueAt, Item));
break;
}
case 2:
{
switch (GetOpDataType(Type))
{
case EDataType::Bool:
StoreBool(Item, LoadBool(Item.CustomState));
break;
case EDataType::Int:
StoreInt(Item, LoadInt(Item.CustomState));
break;
case EDataType::Instance:
StoreInstance(Item, LoadInstance(Item.CustomState));
break;
case EDataType::String:
StoreString(Item, LoadString(Item.CustomState));
break;
case EDataType::ExtensionData:
StoreExtensionData(Item, LoadExtensionData(Item.CustomState));
break;
case EDataType::Scalar:
StoreFloat(Item, LoadFloat(Item.CustomState));
break;
case EDataType::Color:
case EDataType::Projector:
case EDataType::Mesh:
case EDataType::Image:
case EDataType::Layout:
case EDataType::Material:
StoreNone(Item);
break;
default:
unimplemented();
}
break;
}
default:
unimplemented();
}
break;
}
case EOpType::IN_ADDVECTOR:
case EOpType::IN_ADDSCALAR:
{
OP::InstanceAddArgs Args = Program.GetOpArgs<OP::InstanceAddArgs>(Item.At);
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.instance, Item));
break;
}
case 1:
{
TSharedPtr<const FInstance> InInstance;
if (Args.instance)
{
InInstance = LoadInstance(Args.instance);
}
TSharedPtr<FInstance> Instance;
if (InInstance)
{
Instance = UE::Mutable::Private::CloneOrTakeOver<FInstance>(InInstance);
}
else
{
Instance = MakeShared<FInstance>();
}
StoreInstance( Item, Instance);
break;
}
default:
unimplemented();
}
break;
}
case EOpType::IN_ADDMESH:
{
OP::InstanceAddArgs Args = Program.GetOpArgs<OP::InstanceAddArgs>(Item.At);
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.instance, Item));
PushOp(FScheduledOpInline(Args.value, Item));
break;
}
case 1:
{
TSharedPtr<const FInstance> InInstance;
if (Args.instance)
{
InInstance = LoadInstance(Args.instance);
}
TSharedPtr<FInstance> Instance;
if (InInstance)
{
Instance = UE::Mutable::Private::CloneOrTakeOver<FInstance>(InInstance);
}
else
{
Instance = MakeShared<FInstance>();
}
if (Args.value)
{
FMeshId MeshId = System.GetPrivate()->WorkingMemoryManager.GetMeshId(Model, Params.Get(), Args.RelevantParametersListIndex, Args.value);
OP::ADDRESS NameAd = Args.name;
check(NameAd < (uint32)Program.ConstantStrings.Num());
const FString& Name = Program.ConstantStrings[NameAd];
Instance->SetMesh(0, 0, MeshId, FName(Name));
}
StoreInstance(Item, Instance);
break;
}
default:
unimplemented();
}
break;
}
case EOpType::IN_ADDIMAGE:
{
OP::InstanceAddArgs Args = Program.GetOpArgs<OP::InstanceAddArgs>(Item.At);
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.instance, Item));
PushOp(FScheduledOpInline(Args.value, Item));
break;
}
case 1:
{
TSharedPtr<const FInstance> InInstance;
if (Args.instance)
{
InInstance = LoadInstance(Args.instance);
}
TSharedPtr<FInstance> Instance;
if (InInstance)
{
Instance = UE::Mutable::Private::CloneOrTakeOver<FInstance>(InInstance);
}
else
{
Instance = MakeShared<FInstance>();
}
if (Args.value)
{
FImageId ImageId = System.GetPrivate()->WorkingMemoryManager.GetImageId(Model, Params.Get(), Args.RelevantParametersListIndex, Args.value);
OP::ADDRESS NameAd = Args.name;
check(NameAd < (uint32)Program.ConstantStrings.Num());
const FString& Name = Program.ConstantStrings[NameAd];
Instance->AddImage(0, 0, 0, ImageId, FName(Name) );
}
StoreInstance(Item, Instance);
break;
}
default:
unimplemented();
}
break;
}
case EOpType::IN_ADDMATERIAL:
{
OP::InstanceAddMaterialArgs Args = Program.GetOpArgs<OP::InstanceAddMaterialArgs>(Item.At);
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.Instance, Item));
PushOp(FScheduledOpInline(Args.Material, Item));
break;
}
case 1:
{
TSharedPtr<const FInstance> InInstance;
if (Args.Instance)
{
InInstance = LoadInstance(Args.Instance);
}
TSharedPtr<FInstance> Instance;
if (InInstance)
{
Instance = UE::Mutable::Private::CloneOrTakeOver<FInstance>(InInstance);
}
else
{
Instance = MakeShared<FInstance>();
}
if (Args.Material)
{
FMaterialId MaterialId = System.GetPrivate()->WorkingMemoryManager.GetMaterialId(Model, Params.Get(), Args.RelevantParametersListIndex, Args.Material);
Instance->SetMaterialId(0, 0, 0, MaterialId);
}
StoreInstance( Item, Instance);
break;
}
default:
unimplemented();
}
break;
}
case EOpType::IN_ADDOVERLAYMATERIAL:
{
OP::InstanceAddMaterialArgs Args = Program.GetOpArgs<OP::InstanceAddMaterialArgs>(Item.At);
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.Instance, Item));
PushOp(FScheduledOpInline(Args.Material, Item));
break;
}
case 1:
{
TSharedPtr<const FInstance> InInstance;
if (Args.Instance)
{
InInstance = LoadInstance(Args.Instance);
}
TSharedPtr<FInstance> Instance;
if (InInstance)
{
Instance = UE::Mutable::Private::CloneOrTakeOver<FInstance>(InInstance);
}
else
{
Instance = MakeShared<FInstance>();
}
if (Args.Material)
{
FMaterialId MaterialId = System.GetPrivate()->WorkingMemoryManager.GetMaterialId(Model, Params.Get(), Args.RelevantParametersListIndex, Args.Material);
Instance->SetOverlayMaterialId(0, MaterialId);
}
StoreInstance( Item, Instance);
break;
}
default:
unimplemented();
}
break;
}
case EOpType::IN_ADDCOMPONENT:
{
OP::InstanceAddArgs Args = Program.GetOpArgs<OP::InstanceAddArgs>(Item.At);
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.instance, Item));
PushOp(FScheduledOpInline(Args.value, Item));
break;
}
case 1:
{
TSharedPtr<const FInstance> InInstance;
if (Args.instance)
{
InInstance = LoadInstance(Args.instance);
}
TSharedPtr<FInstance> Instance;
if (InInstance)
{
Instance = UE::Mutable::Private::CloneOrTakeOver<FInstance>(InInstance);
}
else
{
Instance = MakeShared<FInstance>();
}
if (Args.value)
{
TSharedPtr<const FInstance> pComp = LoadInstance(Args.value);
int32 NewComponentIndex = Instance->AddComponent();
if ( !pComp->Components.IsEmpty() )
{
Instance->Components[NewComponentIndex] = pComp->Components[0];
// Id
Instance->Components[NewComponentIndex].Id = Args.ExternalId;
}
}
StoreInstance(Item, Instance);
break;
}
default:
unimplemented();
}
break;
}
case EOpType::IN_ADDSTRING:
{
OP::InstanceAddArgs Args = Program.GetOpArgs<OP::InstanceAddArgs>( Item.At );
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.instance, Item));
PushOp(FScheduledOpInline(Args.value, Item));
break;
}
case 1:
{
TSharedPtr<const FInstance> InInstance;
if (Args.instance)
{
InInstance = LoadInstance(Args.instance);
}
TSharedPtr<FInstance> Instance;
if (InInstance)
{
Instance = UE::Mutable::Private::CloneOrTakeOver<FInstance>(InInstance);
}
else
{
Instance = MakeShared<FInstance>();
}
StoreInstance( Item, Instance );
break;
}
default:
unimplemented();
}
break;
}
case EOpType::IN_ADDSURFACE:
{
OP::InstanceAddArgs Args = Program.GetOpArgs<OP::InstanceAddArgs>(Item.At);
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.instance, Item));
PushOp(FScheduledOpInline(Args.value, Item));
break;
}
case 1:
{
TSharedPtr<const FInstance> InInstance;
if (Args.instance)
{
InInstance = LoadInstance(Args.instance);
}
TSharedPtr<FInstance> Instance;
if (InInstance)
{
Instance = UE::Mutable::Private::CloneOrTakeOver<FInstance>(InInstance);
}
else
{
Instance = MakeShared<FInstance>();
}
// Empty surfaces are ok, they still need to be created, because they may contain
// additional information like internal or external IDs
TSharedPtr<const FInstance> Value;
if (Args.value)
{
Value = LoadInstance(Args.value);
}
int32 SurfaceIndex = Instance->AddSurface(0, 0);
// Surface data
if (Value &&
Value->Components.Num() &&
Value->Components[0].LODs.Num() &&
Value->Components[0].LODs[0].Surfaces.Num())
{
Instance->Components[0].LODs[0].Surfaces[SurfaceIndex] = Value->Components[0].LODs[0].Surfaces[0];
}
// Name
OP::ADDRESS nameAd = Args.name;
check( nameAd < (uint32)Program.ConstantStrings.Num() );
const FString& Name = Program.ConstantStrings[ nameAd ];
Instance->SetSurfaceName( 0, 0, SurfaceIndex, FName(Name) );
// IDs
Instance->Components[0].LODs[0].Surfaces[SurfaceIndex].InternalId = Args.id;
Instance->Components[0].LODs[0].Surfaces[SurfaceIndex].ExternalId = Args.ExternalId;
Instance->Components[0].LODs[0].Surfaces[SurfaceIndex].SharedId = Args.SharedSurfaceId;
StoreInstance(Item, Instance);
break;
}
default:
check(false);
}
break;
}
case EOpType::IN_ADDLOD:
{
const uint8* Data = Program.GetOpArgsPointer(Item.At);
uint8 LODCount;
FMemory::Memcpy(&LODCount, Data, sizeof(uint8));
Data += sizeof(uint8);
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline( Item, 1));
for (uint8 LODIndex = 0; LODIndex < LODCount; ++LODIndex)
{
OP::ADDRESS LODAddress;
FMemory::Memcpy(&LODAddress, Data, sizeof(OP::ADDRESS));
Data += sizeof(OP::ADDRESS);
if (LODAddress)
{
const bool bSelectedLod = ((1 << LODIndex) & LodMask) != 0;
if (bSelectedLod)
{
PushOp(FScheduledOpInline(LODAddress, Item));
}
}
}
break;
}
case 1:
{
// Assemble result
TSharedPtr<FInstance> Result = MakeShared<FInstance>();
int32 ComponentIndex = Result->AddComponent();
for (uint8 LODIndex = 0; LODIndex < LODCount; ++LODIndex)
{
OP::ADDRESS LODAddress;
FMemory::Memcpy(&LODAddress, Data, sizeof(OP::ADDRESS));
Data += sizeof(OP::ADDRESS);
if (LODAddress)
{
bool bIsSelectedLod = ((1 << LODIndex) & LodMask ) != 0;
// Add an empty LOD even if not selected.
int32 InstanceLODIndex = Result->AddLOD(ComponentIndex);
if (bIsSelectedLod)
{
TSharedPtr<const FInstance> LOD = LoadInstance(LODAddress);
// In a degenerated case, the returned pLOD may not have an LOD inside
if (!LOD->Components.IsEmpty() &&
!LOD->Components[0].LODs.IsEmpty())
{
Result->Components[ComponentIndex].LODs[InstanceLODIndex] = LOD->Components[0].LODs[0];
}
}
}
}
StoreInstance(Item, Result);
break;
}
default:
unimplemented();
}
break;
}
case EOpType::IN_ADDEXTENSIONDATA:
{
OP::InstanceAddExtensionDataArgs Args = Program.GetOpArgs<OP::InstanceAddExtensionDataArgs>(Item.At);
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.Instance, Item));
PushOp(FScheduledOpInline(Args.ExtensionData, Item));
break;
}
case 1:
{
TSharedPtr<const FInstance> InInstance;
if (Args.Instance)
{
InInstance = LoadInstance(Args.Instance);
}
TSharedPtr<FInstance> Instance;
if (InInstance)
{
Instance = UE::Mutable::Private::CloneOrTakeOver<FInstance>(InInstance);
}
else
{
Instance = MakeShared<FInstance>();
}
if (TSharedPtr<const FExtensionData> ExtensionData = LoadExtensionData(Args.ExtensionData))
{
const OP::ADDRESS NameAddress = Args.ExtensionDataName;
check(NameAddress < (uint32)Program.ConstantStrings.Num());
const FString& NameString = Program.ConstantStrings[NameAddress];
Instance->SetExtensionData(ExtensionData.ToSharedRef(), FName(NameString));
}
StoreInstance(Item, Instance);
break;
}
default:
unimplemented();
}
break;
}
case EOpType::BO_CONSTANT:
{
OP::BoolConstantArgs Args = Program.GetOpArgs<OP::BoolConstantArgs>(Item.At);
StoreBool(Item, Args.bValue);
break;
}
case EOpType::BO_PARAMETER:
{
OP::ParameterArgs Args = Program.GetOpArgs<OP::ParameterArgs>(Item.At);
FScheduledOp Op;
Op.At = Item.At;
Op.ExecutionIndex = Item.ExecutionIndex;
TSharedPtr<FRangeIndex> Index = BuildCurrentOpRangeIndex(Op, *Params, *Model.Get(), GetMemory(), Args.variable);
const bool Value = Params->GetBoolValue(Args.variable, Index.Get());
StoreBool(Item, Value);
break;
}
case EOpType::BO_AND:
{
OP::BoolBinaryArgs Args = Program.GetOpArgs<OP::BoolBinaryArgs>(Item.At);
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.A, Item));
PushOp(FScheduledOpInline(Args.B, Item));
break;
}
case 1:
{
const bool ValueB = LoadBool(Args.A);
const bool ValueA = LoadBool(Args.B);
const bool Result = ValueA && ValueB;
StoreBool(Item, Result);
break;
}
default:
unimplemented();
}
break;
}
case EOpType::BO_OR:
{
OP::BoolBinaryArgs Args = Program.GetOpArgs<OP::BoolBinaryArgs>(Item.At);
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.A, Item));
PushOp(FScheduledOpInline(Args.B, Item));
break;
}
case 1:
{
const bool ValueB = LoadBool(Args.A);
const bool ValueA = LoadBool(Args.B);
const bool Result = ValueA || ValueB;
StoreBool(Item, Result);
break;
}
default:
unimplemented();
}
break;
}
case EOpType::BO_NOT:
{
OP::BoolNotArgs Args = Program.GetOpArgs<OP::BoolNotArgs>(Item.At);
switch ( Item.Stage )
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.A, Item));
break;
}
case 1:
{
const bool Value = LoadBool(Args.A);
const bool Result = !Value;
StoreBool(Item, Result);
break;
}
default:
unimplemented();
}
break;
}
case EOpType::BO_EQUAL_INT_CONST:
{
OP::BoolEqualScalarConstArgs Args = Program.GetOpArgs<OP::BoolEqualScalarConstArgs>(Item.At);
switch ( Item.Stage )
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.Value, Item));
break;
}
case 1:
{
const int32 Value = LoadInt(Args.Value);
const bool Result = Value == Args.Constant;
StoreBool(Item, Result);
break;
}
default:
unimplemented();
}
break;
}
case EOpType::SC_CONSTANT:
{
OP::ScalarConstantArgs Args = Program.GetOpArgs<OP::ScalarConstantArgs>(Item.At);
StoreFloat(Item, Args.Value);
break;
}
case EOpType::SC_PARAMETER:
{
OP::ParameterArgs Args = Program.GetOpArgs<OP::ParameterArgs>(Item.At);
FScheduledOp Op;
Op.At = Item.At;
Op.ExecutionIndex = Item.ExecutionIndex;
TSharedPtr<FRangeIndex> Index = BuildCurrentOpRangeIndex(Op, *Params, *Model.Get(), GetMemory(), Args.variable);
const float Result = Params->GetFloatValue( Args.variable, Index.Get());
StoreFloat(Item, Result);
break;
}
case EOpType::SC_ARITHMETIC:
{
OP::ArithmeticArgs Args = Program.GetOpArgs<OP::ArithmeticArgs>(Item.At);
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.A, Item));
PushOp(FScheduledOpInline(Args.B, Item));
break;
}
case 1:
{
float ValueA = LoadFloat(Args.A);
float ValueB = LoadFloat(Args.B);
float Result = 1.0f;
switch (Args.Operation)
{
case OP::ArithmeticArgs::ADD:
Result = ValueA + ValueB;
break;
case OP::ArithmeticArgs::MULTIPLY:
Result = ValueA * ValueB;
break;
case OP::ArithmeticArgs::SUBTRACT:
Result = ValueA - ValueB;
break;
case OP::ArithmeticArgs::DIVIDE:
Result = ValueA / ValueB;
break;
default:
unimplemented();
}
StoreFloat(Item, Result);
break;
}
default:
unimplemented();
}
break;
}
case EOpType::SC_CURVE:
{
OP::ScalarCurveArgs Args = Program.GetOpArgs<OP::ScalarCurveArgs>(Item.At);
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.time, Item));
break;
}
case 1:
{
const float Time = LoadFloat(Args.time);
const FRichCurve& Curve = Program.ConstantCurves[Args.curve];
float Result = Curve.Eval(Time);
StoreFloat(Item, Result);
break;
}
default:
unimplemented();
}
break;
}
case EOpType::ED_CONSTANT:
{
OP::ResourceConstantArgs Args = Program.GetOpArgs<OP::ResourceConstantArgs>(Item.At);
// Assume the ROM has been loaded previously
TSharedPtr<const FExtensionData> SourceConst;
Program.GetExtensionDataConstant(Args.value, SourceConst);
check(SourceConst);
StoreExtensionData(Item, SourceConst);
break;
}
case EOpType::ST_CONSTANT:
{
OP::ResourceConstantArgs Args = Program.GetOpArgs<OP::ResourceConstantArgs>(Item.At);
check(Args.value < static_cast<uint32>(Model->GetPrivate()->Program.ConstantStrings.Num()));
const FString& Result = Program.ConstantStrings[Args.value];
TSharedPtr<const String> Value = MakeShared<String>(Result);
StoreString(Item, Value);
break;
}
case EOpType::ST_PARAMETER:
{
OP::ParameterArgs Args = Program.GetOpArgs<OP::ParameterArgs>(Item.At);
FScheduledOp Op;
Op.At = Item.At;
Op.ExecutionIndex = Item.ExecutionIndex;
TSharedPtr<FRangeIndex> Index = BuildCurrentOpRangeIndex(Op, *Params, *Model.Get(), GetMemory(), Args.variable);
FString Result;
Params->GetStringValue(Args.variable, Result, Index.Get());
TSharedPtr<const String> Value = MakeShared<String>(Result);
StoreString(Item, Value);
break;
}
case EOpType::NU_CONSTANT:
{
OP::IntConstantArgs Args = Program.GetOpArgs<OP::IntConstantArgs>(Item.At);
const int32 Value = Args.Value;
StoreInt(Item, Value);
break;
}
case EOpType::NU_PARAMETER:
{
OP::ParameterArgs Args = Program.GetOpArgs<OP::ParameterArgs>(Item.At);
const int32 Value = Params->GetIntValue(Args.variable);
StoreInt(Item, Value);
break;
}
case EOpType::CO_ARITHMETIC:
{
OP::ArithmeticArgs Args = Program.GetOpArgs<OP::ArithmeticArgs>(Item.At);
PushOp(FScheduledOpInline(Args.A, Item));
PushOp(FScheduledOpInline(Args.B, Item));
StoreNone(Item);
break;
}
case EOpType::CO_FROMSCALARS:
{
StoreNone(Item);
break;
}
case EOpType::CO_SAMPLEIMAGE:
{
OP::ColourSampleImageArgs Args = Program.GetOpArgs<OP::ColourSampleImageArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Image, Item));
StoreNone(Item);
break;
}
case EOpType::CO_SWIZZLE:
{
OP::ColourSwizzleArgs Args = Program.GetOpArgs<OP::ColourSwizzleArgs>(Item.At);
PushOp(FScheduledOpInline(Args.sources[0], Item));
PushOp(FScheduledOpInline(Args.sources[1], Item));
PushOp(FScheduledOpInline(Args.sources[2], Item));
PushOp(FScheduledOpInline(Args.sources[3], Item));
StoreNone(Item);
break;
}
case EOpType::ME_CONSTANT:
{
OP::MeshConstantArgs Args = Program.GetOpArgs<OP::MeshConstantArgs>(Item.At);
ME_SKELETON_ID.Push(Args.Skeleton);
StoreNone(Item);
break;
}
case EOpType::ME_REFERENCE:
{
OP::ResourceReferenceArgs Args = Program.GetOpArgs<OP::ResourceReferenceArgs>(Item.At);
ME_REFERENCE_ID.Push(Args.ID);
StoreNone(Item);
break;
}
case EOpType::ME_APPLYLAYOUT:
{
OP::MeshApplyLayoutArgs Args = Program.GetOpArgs<OP::MeshApplyLayoutArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Mesh, Item));
StoreNone(Item);
break;
}
case EOpType::ME_PREPARELAYOUT:
{
OP::MeshPrepareLayoutArgs Args = Program.GetOpArgs<OP::MeshPrepareLayoutArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Mesh, Item));
StoreNone(Item);
break;
}
case EOpType::ME_DIFFERENCE:
{
const uint8* data = Program.GetOpArgsPointer(Item.At);
OP::ADDRESS BaseAt = 0;
FMemory::Memcpy(&BaseAt, data, sizeof(OP::ADDRESS));
data += sizeof(OP::ADDRESS);
OP::ADDRESS TargetAt = 0;
FMemory::Memcpy(&TargetAt, data, sizeof(OP::ADDRESS));
data += sizeof(OP::ADDRESS);
PushOp(FScheduledOpInline(BaseAt, Item));
PushOp(FScheduledOpInline(TargetAt, Item));
StoreNone(Item);
break;
}
case EOpType::ME_MORPH:
{
const uint8* Data = Program.GetOpArgsPointer(Item.At);
OP::CONSTANT_STRING_ADDRESS NameAt = 0;
FMemory::Memcpy(&NameAt, Data, sizeof(OP::CONSTANT_STRING_ADDRESS));
Data += sizeof(OP::CONSTANT_STRING_ADDRESS);
OP::ADDRESS FactorAt = 0;
FMemory::Memcpy(&FactorAt, Data, sizeof(OP::ADDRESS));
Data += sizeof(OP::ADDRESS);
OP::ADDRESS BaseAt = 0;
FMemory::Memcpy(&BaseAt, Data, sizeof(OP::ADDRESS));
Data += sizeof(OP::ADDRESS);
OP::ADDRESS TargetAt = 0;
FMemory::Memcpy(&TargetAt, Data, sizeof(OP::ADDRESS));
Data += sizeof(OP::ADDRESS);
PushOp(FScheduledOpInline(BaseAt, Item));
PushOp(FScheduledOpInline(TargetAt, Item));
StoreNone(Item);
break;
}
case EOpType::ME_MERGE:
{
OP::MeshMergeArgs Args = Program.GetOpArgs<OP::MeshMergeArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Base, Item));
PushOp(FScheduledOpInline(Args.Added, Item));
StoreNone(Item);
break;
}
case EOpType::ME_MASKCLIPMESH:
{
OP::MeshMaskClipMeshArgs Args = Program.GetOpArgs<OP::MeshMaskClipMeshArgs>(Item.At);
PushOp(FScheduledOpInline(Args.source, Item));
PushOp(FScheduledOpInline(Args.clip, Item));
StoreNone(Item);
break;
}
case EOpType::ME_MASKCLIPUVMASK:
{
OP::MeshMaskClipUVMaskArgs Args = Program.GetOpArgs<OP::MeshMaskClipUVMaskArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Source, Item));
PushOp(FScheduledOpInline(Args.UVSource, Item));
PushOp(FScheduledOpInline(Args.MaskImage, Item));
PushOp(FScheduledOpInline(Args.LayoutIndex, Item));
StoreNone(Item);
break;
}
case EOpType::ME_MASKDIFF:
{
OP::MeshMaskDiffArgs Args = Program.GetOpArgs<OP::MeshMaskDiffArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Source, Item));
PushOp(FScheduledOpInline(Args.Fragment, Item));
StoreNone(Item);
break;
}
case EOpType::ME_FORMAT:
{
OP::MeshFormatArgs Args = Program.GetOpArgs<OP::MeshFormatArgs>(Item.At);
PushOp(FScheduledOpInline(Args.source, Item));
PushOp(FScheduledOpInline(Args.format, Item));
StoreNone(Item);
break;
}
case EOpType::ME_EXTRACTLAYOUTBLOCK:
{
const uint8* Data = Program.GetOpArgsPointer(Item.At);
OP::ADDRESS Source;
FMemory::Memcpy( &Source, Data, sizeof(OP::ADDRESS) );
Data += sizeof(OP::ADDRESS);
PushOp(FScheduledOpInline(Source, Item));
StoreNone(Item);
break;
}
case EOpType::ME_TRANSFORM:
{
OP::MeshTransformArgs Args = Program.GetOpArgs<OP::MeshTransformArgs>(Item.At);
PushOp(FScheduledOpInline(Args.source, Item));
StoreNone(Item);
break;
}
case EOpType::ME_CLIPMORPHPLANE:
{
OP::MeshClipMorphPlaneArgs Args = Program.GetOpArgs<OP::MeshClipMorphPlaneArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Source, Item));
StoreNone(Item);
break;
}
case EOpType::ME_CLIPWITHMESH:
{
OP::MeshClipWithMeshArgs Args = Program.GetOpArgs<OP::MeshClipWithMeshArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Source, Item));
PushOp(FScheduledOpInline(Args.ClipMesh, Item));
StoreNone(Item);
break;
}
case EOpType::ME_CLIPDEFORM:
{
OP::MeshClipDeformArgs Args = Program.GetOpArgs<OP::MeshClipDeformArgs>(Item.At);
PushOp(FScheduledOpInline(Args.mesh, Item));
PushOp(FScheduledOpInline(Args.clipShape, Item));
StoreNone(Item);
break;
}
case EOpType::ME_APPLYPOSE:
{
OP::MeshApplyPoseArgs Args = Program.GetOpArgs<OP::MeshApplyPoseArgs>(Item.At);
PushOp(FScheduledOpInline(Args.base, Item));
PushOp(FScheduledOpInline(Args.pose, Item));
StoreNone(Item);
break;
}
case EOpType::ME_BINDSHAPE:
{
OP::MeshBindShapeArgs Args = Program.GetOpArgs<OP::MeshBindShapeArgs>(Item.At);
PushOp(FScheduledOpInline(Args.mesh, Item));
PushOp(FScheduledOpInline(Args.shape, Item));
StoreNone(Item);
break;
}
case EOpType::ME_APPLYSHAPE:
{
OP::MeshApplyShapeArgs Args = Program.GetOpArgs<OP::MeshApplyShapeArgs>(Item.At);
PushOp(FScheduledOpInline(Args.mesh, Item));
PushOp(FScheduledOpInline(Args.shape, Item));
StoreNone(Item);
break;
}
case EOpType::ME_MORPHRESHAPE:
{
OP::MeshMorphReshapeArgs Args = Program.GetOpArgs<OP::MeshMorphReshapeArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Morph, Item));
PushOp(FScheduledOpInline(Args.Reshape, Item));
StoreNone(Item);
break;
}
case EOpType::ME_SETSKELETON:
{
OP::MeshSetSkeletonArgs Args = Program.GetOpArgs<OP::MeshSetSkeletonArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Source, Item));
PushOp(FScheduledOpInline(Args.Skeleton, Item));
StoreNone(Item);
break;
}
case EOpType::ME_REMOVEMASK:
{
const uint8* Data = Program.GetOpArgsPointer(Item.At);
OP::ADDRESS Source;
FMemory::Memcpy(&Source,Data,sizeof(OP::ADDRESS));
Data += sizeof(OP::ADDRESS);
PushOp(FScheduledOpInline(Source, Item));
EFaceCullStrategy FaceCullStrategy;
FMemory::Memcpy(&FaceCullStrategy, Data, sizeof(EFaceCullStrategy));
Data += sizeof(EFaceCullStrategy);
uint16 NumRemoves;
FMemory::Memcpy(&NumRemoves,Data,sizeof(uint16));
Data += sizeof(uint16);
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
for (uint16 Index = 0; Index < NumRemoves; ++Index)
{
OP::ADDRESS Condition;
FMemory::Memcpy(&Condition, Data, sizeof(OP::ADDRESS));
Data += sizeof(OP::ADDRESS);
if (Condition)
{
PushOp(FScheduledOpInline(Condition, Item));
}
OP::ADDRESS Mask;
FMemory::Memcpy(&Mask, Data,sizeof(OP::ADDRESS));
Data += sizeof(OP::ADDRESS);
}
break;
}
case 1:
{
for (uint16 Index = 0; Index < NumRemoves; ++Index)
{
OP::ADDRESS Condition;
FMemory::Memcpy(&Condition,Data,sizeof(OP::ADDRESS));
Data += sizeof(OP::ADDRESS);
OP::ADDRESS Mask;
FMemory::Memcpy(&Mask,Data,sizeof(OP::ADDRESS));
Data += sizeof(OP::ADDRESS);
bool bValue = true;
if (Condition)
{
bValue = LoadBool(Condition);
}
if (bValue)
{
PushOp(FScheduledOpInline(Mask, Item));
}
}
StoreNone(Item);
break;
}
default:
unimplemented()
}
break;
}
case EOpType::ME_ADDMETADATA:
{
const OP::MeshAddMetadataArgs OpArgs = Program.GetOpArgs<OP::MeshAddMetadataArgs>(Item.At);
PushOp(FScheduledOpInline(OpArgs.Source, Item));
using OpEnumFlags = OP::MeshAddMetadataArgs::EnumFlags;
const bool bIsSkeletonList = EnumHasAnyFlags(OpArgs.Flags, OpEnumFlags::IsSkeletonList);
if (bIsSkeletonList)
{
if (Program.ConstantUInt32Lists.IsValidIndex(OpArgs.SkeletonIds.ListAddress))
{
ME_SKELETON_ID.Append(Program.ConstantUInt32Lists[OpArgs.SkeletonIds.ListAddress]);
}
else
{
check(false);
}
}
else
{
ME_SKELETON_ID.Push(OpArgs.SkeletonIds.SkeletonId);
}
StoreNone(Item);
break;
}
case EOpType::ME_PROJECT:
{
OP::MeshProjectArgs Args = Program.GetOpArgs<OP::MeshProjectArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Mesh, Item));
PushOp(FScheduledOpInline(Args.Projector, Item));
StoreNone(Item);
break;
}
case EOpType::ME_OPTIMIZESKINNING:
{
OP::MeshOptimizeSkinningArgs Args = Program.GetOpArgs<OP::MeshOptimizeSkinningArgs>(Item.At);
PushOp(FScheduledOpInline(Args.source, Item));
StoreNone(Item);
break;
}
case EOpType::ME_TRANSFORMWITHMESH:
{
OP::MeshTransformWithinMeshArgs Args = Program.GetOpArgs<OP::MeshTransformWithinMeshArgs>(Item.At);
PushOp(FScheduledOpInline(Args.sourceMesh, Item));
PushOp(FScheduledOpInline(Args.boundingMesh, Item));
StoreNone(Item);
break;
}
case EOpType::ME_TRANSFORMWITHBONE:
{
OP::MeshTransformWithBoneArgs Args = Program.GetOpArgs<OP::MeshTransformWithBoneArgs>(Item.At);
PushOp(FScheduledOpInline(Args.SourceMesh, Item));
StoreNone(Item);
break;
}
case EOpType::IM_REFERENCE:
{
OP::ResourceReferenceArgs Args = Program.GetOpArgs<OP::ResourceReferenceArgs>(Item.At);
IM_REFERENCE_ID.Push(Args.ID);
StoreNone(Item);
break;
}
case EOpType::IM_LAYERCOLOUR:
{
OP::ImageLayerColourArgs Args = Program.GetOpArgs<OP::ImageLayerColourArgs>(Item.At);
PushOp(FScheduledOpInline(Args.base, Item));
PushOp(FScheduledOpInline(Args.mask, Item));
StoreNone(Item);
break;
}
case EOpType::IM_LAYER:
{
OP::ImageLayerArgs Args = Program.GetOpArgs<OP::ImageLayerArgs>(Item.At);
PushOp(FScheduledOpInline(Args.base, Item));
PushOp(FScheduledOpInline(Args.mask, Item));
PushOp(FScheduledOpInline(Args.blended, Item));
StoreNone(Item);
break;
}
case EOpType::IM_MULTILAYER:
{
OP::ImageMultiLayerArgs Args = Program.GetOpArgs<OP::ImageMultiLayerArgs>(Item.At);
switch (Item.Stage)
{
case 0:
{
PushOp(FScheduledOpInline(Item, 1));
PushOp(FScheduledOpInline(Args.rangeSize, Item));
PushOp(FScheduledOpInline(Args.base, Item));
break;
}
case 1:
{
int32 NumIterations = 0;
if (Args.rangeSize)
{
const EDataType RangeSizeType = GetOpDataType(Model->GetPrivate()->Program.GetOpType(Args.rangeSize) );
if (RangeSizeType == EDataType::Int)
{
NumIterations = LoadInt(Args.rangeSize);
}
else if (RangeSizeType == EDataType::Scalar)
{
NumIterations = LoadFloat(Args.rangeSize);
}
}
for (int32 IterationIndex = 0; IterationIndex < NumIterations; ++IterationIndex)
{
ExecutionIndex Index = GetMemory().GetRangeIndex(Item.ExecutionIndex);
Index.SetFromModelRangeIndex(Args.rangeId, IterationIndex);
FScheduledOpInline ItemCopy = Item;
ItemCopy.ExecutionIndex = GetMemory().GetRangeIndexIndex(Index);
PushOp(FScheduledOpInline(Args.mask, Item));
PushOp(FScheduledOpInline(Args.blended, Item));
}
StoreNone(Item);
break;
}
default:
unimplemented()
}
break;
}
case EOpType::IM_NORMALCOMPOSITE:
{
OP::ImageNormalCompositeArgs Args = Program.GetOpArgs<OP::ImageNormalCompositeArgs>(Item.At);
PushOp(FScheduledOpInline(Args.base, Item));
PushOp(FScheduledOpInline(Args.normal, Item));
StoreNone(Item);
break;
}
case EOpType::IM_PIXELFORMAT:
{
OP::ImagePixelFormatArgs Args = Program.GetOpArgs<OP::ImagePixelFormatArgs>(Item.At);
PushOp(FScheduledOpInline(Args.source, Item));
StoreNone(Item);
break;
}
case EOpType::IM_MIPMAP:
{
OP::ImageMipmapArgs Args = Program.GetOpArgs<OP::ImageMipmapArgs>(Item.At);
PushOp(FScheduledOpInline(Args.source, Item));
StoreNone(Item);
break;
}
case EOpType::IM_RESIZE:
{
OP::ImageResizeArgs Args = Program.GetOpArgs<OP::ImageResizeArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Source, Item));
StoreNone(Item);
break;
}
case EOpType::IM_RESIZELIKE:
{
OP::ImageResizeLikeArgs Args = Program.GetOpArgs<OP::ImageResizeLikeArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Source, Item));
PushOp(FScheduledOpInline(Args.SizeSource, Item));
StoreNone(Item);
break;
}
case EOpType::IM_RESIZEREL:
{
OP::ImageResizeRelArgs Args = Program.GetOpArgs<OP::ImageResizeRelArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Source, Item));
StoreNone(Item);
break;
}
case EOpType::IM_BLANKLAYOUT:
{
OP::ImageBlankLayoutArgs Args = Program.GetOpArgs<OP::ImageBlankLayoutArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Layout, Item));
StoreNone(Item);
break;
}
case EOpType::IM_COMPOSE:
{
OP::ImageComposeArgs Args = Program.GetOpArgs<OP::ImageComposeArgs>(Item.At);
PushOp(FScheduledOpInline(Args.base, Item));
PushOp(FScheduledOpInline(Args.blockImage, Item));
StoreNone(Item);
break;
}
case EOpType::IM_INTERPOLATE:
{
OP::ImageInterpolateArgs Args = Program.GetOpArgs<OP::ImageInterpolateArgs>(Item.At);
for (int32 ImageIndex = 0; ImageIndex < MUTABLE_OP_MAX_INTERPOLATE_COUNT; ++ImageIndex)
{
if (!Args.Targets[ImageIndex])
{
break;
}
PushOp(FScheduledOpInline(Args.Targets[ImageIndex], Item));
}
StoreNone(Item);
break;
}
case EOpType::IM_SATURATE:
{
OP::ImageSaturateArgs Args = Program.GetOpArgs<OP::ImageSaturateArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Base, Item));
StoreNone(Item);
break;
}
case EOpType::IM_LUMINANCE:
{
OP::ImageLuminanceArgs Args = Program.GetOpArgs<OP::ImageLuminanceArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Base, Item));
StoreNone(Item);
break;
}
case EOpType::IM_SWIZZLE:
{
OP::ImageSwizzleArgs Args = Program.GetOpArgs<OP::ImageSwizzleArgs>(Item.At);
TArray<OP::ADDRESS, TFixedAllocator<4>> ValidArgs;
for (int32 SourceIndex = 0; SourceIndex < 4; ++SourceIndex)
{
if (Args.sources[SourceIndex])
{
PushOp(FScheduledOpInline(Args.sources[SourceIndex], Item));
}
}
StoreNone(Item);
break;
}
case EOpType::IM_COLOURMAP:
{
OP::ImageColourMapArgs Args = Program.GetOpArgs<OP::ImageColourMapArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Base, Item));
StoreNone(Item);
break;
}
case EOpType::IM_BINARISE:
{
OP::ImageBinariseArgs Args = Program.GetOpArgs<OP::ImageBinariseArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Base, Item));
StoreNone(Item);
break;
}
case EOpType::IM_INVERT:
{
OP::ImageInvertArgs Args = Program.GetOpArgs<OP::ImageInvertArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Base, Item));
StoreNone(Item);
break;
}
case EOpType::IM_PLAINCOLOUR:
{
StoreNone(Item);
break;
}
case EOpType::IM_CROP:
{
OP::ImageCropArgs Args = Program.GetOpArgs<OP::ImageCropArgs>(Item.At);
PushOp(FScheduledOpInline(Args.source, Item));
StoreNone(Item);
break;
}
case EOpType::IM_PATCH:
{
OP::ImagePatchArgs Args = Program.GetOpArgs<OP::ImagePatchArgs>(Item.At);
PushOp(FScheduledOpInline(Args.base, Item));
PushOp(FScheduledOpInline(Args.patch, Item));
StoreNone(Item);
break;
}
case EOpType::IM_RASTERMESH:
{
OP::ImageRasterMeshArgs Args = Program.GetOpArgs<OP::ImageRasterMeshArgs>(Item.At);
PushOp(FScheduledOpInline(Args.mesh, Item));
StoreNone(Item);
break;
}
case EOpType::IM_MAKEGROWMAP:
{
OP::ImageMakeGrowMapArgs Args = Program.GetOpArgs<OP::ImageMakeGrowMapArgs>(Item.At);
PushOp(FScheduledOpInline(Args.mask, Item));
StoreNone(Item);
break;
}
case EOpType::IM_DISPLACE:
{
OP::ImageDisplaceArgs Args = Program.GetOpArgs<OP::ImageDisplaceArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Source, Item));
StoreNone(Item);
break;
}
case EOpType::IM_TRANSFORM:
{
OP::ImageTransformArgs Args = Program.GetOpArgs<OP::ImageTransformArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Base, Item));
StoreNone(Item);
break;
}
case EOpType::LA_MERGE:
{
OP::LayoutMergeArgs Args = Program.GetOpArgs<OP::LayoutMergeArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Base, Item));
PushOp(FScheduledOpInline(Args.Added, Item));
StoreNone(Item);
break;
}
case EOpType::LA_PACK:
{
OP::LayoutPackArgs Args = Program.GetOpArgs<OP::LayoutPackArgs>(Item.At);
PushOp(FScheduledOpInline( Args.Source, Item));
StoreNone(Item);
break;
}
case EOpType::LA_FROMMESH:
{
OP::LayoutFromMeshArgs Args = Program.GetOpArgs<OP::LayoutFromMeshArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Mesh, Item));
StoreNone(Item);
break;
}
case EOpType::LA_REMOVEBLOCKS:
{
OP::LayoutRemoveBlocksArgs Args = Program.GetOpArgs<OP::LayoutRemoveBlocksArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Source, Item));
PushOp(FScheduledOpInline(Args.ReferenceLayout, Item));
StoreNone(Item);
break;
}
case EOpType::NONE:
{
check(Item.At == 0);
StoreNone(Item);
break;
}
case EOpType::MI_CONSTANT:
{
OP::ResourceConstantArgs Args = Program.GetOpArgs<OP::ResourceConstantArgs>(Item.At);
TSharedPtr<const FMaterial> SourceConst = Program.ConstantMaterials[Args.value];
MI_REFERENCE_ID.Add(SourceConst->ReferenceID);
StoreNone(Item);
break;
}
case EOpType::IM_MATERIAL_BREAK:
case EOpType::SC_MATERIAL_BREAK:
case EOpType::CO_MATERIAL_BREAK:
{
OP::MaterialBreakArgs Args = Program.GetOpArgs<OP::MaterialBreakArgs>(Item.At);
PushOp(FScheduledOpInline(Args.Material, Item));
StoreNone(Item);
break;
}
default:
unimplemented();
}
}
check(Stack.Num() <= 1);
return Stack.Num() ? LoadInstance(Root) : MakeShared<FInstance>();
}
}