// 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& InModel, const TSharedPtr& 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(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(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(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(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(Value); Stack.Push(StackValue); ResultsBool.Add(To, Value); } void CodeRunnerBegin::StoreInstance(const FCacheAddressInline& To, const TSharedPtr& Value) { if (!To.At) { return; } Executed.Add(To); FStackValue StackValue; StackValue.Set>(Value); Stack.Push(StackValue); ResultsInstance.Add(To, Value); } void CodeRunnerBegin::StoreString(const FCacheAddressInline& To, const TSharedPtr& Value) { if (!To.At) { return; } Executed.Add(To); FStackValue StackValue; StackValue.Set>(Value); Stack.Push(StackValue); ResultsString.Add(To, Value); } void CodeRunnerBegin::StoreExtensionData(const FCacheAddressInline& To, const TSharedPtr& Value) { if (!To.At) { return; } Executed.Add(To); FStackValue StackValue; StackValue.Set>(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(); } float CodeRunnerBegin::LoadFloat(const FCacheAddressInline& To) { if (!To.At) { return 0.0f; } return Stack.Pop().Get(); } bool CodeRunnerBegin::LoadBool(const FCacheAddressInline& To) { if (!To.At) { return false; } return Stack.Pop().Get(); } TSharedPtr CodeRunnerBegin::LoadInstance(const FCacheAddressInline& To) { if (!To.At) { return nullptr; } return Stack.Pop().Get>(); } TSharedPtr CodeRunnerBegin::LoadString(const FCacheAddressInline& To) { if (!To.At) { return nullptr; } return Stack.Pop().Get>(); } TSharedPtr CodeRunnerBegin::LoadExtensionData(const FCacheAddressInline& To) { if (!To.At) { return nullptr; } return Stack.Pop().Get>(); } TSharedPtr 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(ResultsBool[Item]); Stack.Push(Value); break; } case EDataType::Int: { FStackValue Value; Value.Set(ResultsInt[Item]); Stack.Push(Value); break; } case EDataType::Instance: { FStackValue Value; Value.Set>(ResultsInstance[Item]); Stack.Push(Value); break; } case EDataType::String: { FStackValue Value; Value.Set>(ResultsString[Item]); Stack.Push(Value); break; } case EDataType::ExtensionData: { FStackValue Value; Value.Set>(ResultsExtensionData[Item]); Stack.Push(Value); break; } case EDataType::Scalar: { FStackValue Value; Value.Set(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(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(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()); 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(Item.At); switch (Item.Stage) { case 0: { PushOp(FScheduledOpInline(Item, 1)); PushOp(FScheduledOpInline(Args.instance, Item)); break; } case 1: { TSharedPtr InInstance; if (Args.instance) { InInstance = LoadInstance(Args.instance); } TSharedPtr Instance; if (InInstance) { Instance = UE::Mutable::Private::CloneOrTakeOver(InInstance); } else { Instance = MakeShared(); } StoreInstance( Item, Instance); break; } default: unimplemented(); } break; } case EOpType::IN_ADDMESH: { OP::InstanceAddArgs Args = Program.GetOpArgs(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 InInstance; if (Args.instance) { InInstance = LoadInstance(Args.instance); } TSharedPtr Instance; if (InInstance) { Instance = UE::Mutable::Private::CloneOrTakeOver(InInstance); } else { Instance = MakeShared(); } 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(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 InInstance; if (Args.instance) { InInstance = LoadInstance(Args.instance); } TSharedPtr Instance; if (InInstance) { Instance = UE::Mutable::Private::CloneOrTakeOver(InInstance); } else { Instance = MakeShared(); } 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(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 InInstance; if (Args.Instance) { InInstance = LoadInstance(Args.Instance); } TSharedPtr Instance; if (InInstance) { Instance = UE::Mutable::Private::CloneOrTakeOver(InInstance); } else { Instance = MakeShared(); } 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(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 InInstance; if (Args.Instance) { InInstance = LoadInstance(Args.Instance); } TSharedPtr Instance; if (InInstance) { Instance = UE::Mutable::Private::CloneOrTakeOver(InInstance); } else { Instance = MakeShared(); } 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(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 InInstance; if (Args.instance) { InInstance = LoadInstance(Args.instance); } TSharedPtr Instance; if (InInstance) { Instance = UE::Mutable::Private::CloneOrTakeOver(InInstance); } else { Instance = MakeShared(); } if (Args.value) { TSharedPtr 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( 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 InInstance; if (Args.instance) { InInstance = LoadInstance(Args.instance); } TSharedPtr Instance; if (InInstance) { Instance = UE::Mutable::Private::CloneOrTakeOver(InInstance); } else { Instance = MakeShared(); } StoreInstance( Item, Instance ); break; } default: unimplemented(); } break; } case EOpType::IN_ADDSURFACE: { OP::InstanceAddArgs Args = Program.GetOpArgs(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 InInstance; if (Args.instance) { InInstance = LoadInstance(Args.instance); } TSharedPtr Instance; if (InInstance) { Instance = UE::Mutable::Private::CloneOrTakeOver(InInstance); } else { Instance = MakeShared(); } // Empty surfaces are ok, they still need to be created, because they may contain // additional information like internal or external IDs TSharedPtr 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 Result = MakeShared(); 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 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(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 InInstance; if (Args.Instance) { InInstance = LoadInstance(Args.Instance); } TSharedPtr Instance; if (InInstance) { Instance = UE::Mutable::Private::CloneOrTakeOver(InInstance); } else { Instance = MakeShared(); } if (TSharedPtr 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(Item.At); StoreBool(Item, Args.bValue); break; } case EOpType::BO_PARAMETER: { OP::ParameterArgs Args = Program.GetOpArgs(Item.At); FScheduledOp Op; Op.At = Item.At; Op.ExecutionIndex = Item.ExecutionIndex; TSharedPtr 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(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(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(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(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(Item.At); StoreFloat(Item, Args.Value); break; } case EOpType::SC_PARAMETER: { OP::ParameterArgs Args = Program.GetOpArgs(Item.At); FScheduledOp Op; Op.At = Item.At; Op.ExecutionIndex = Item.ExecutionIndex; TSharedPtr 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(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(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(Item.At); // Assume the ROM has been loaded previously TSharedPtr SourceConst; Program.GetExtensionDataConstant(Args.value, SourceConst); check(SourceConst); StoreExtensionData(Item, SourceConst); break; } case EOpType::ST_CONSTANT: { OP::ResourceConstantArgs Args = Program.GetOpArgs(Item.At); check(Args.value < static_cast(Model->GetPrivate()->Program.ConstantStrings.Num())); const FString& Result = Program.ConstantStrings[Args.value]; TSharedPtr Value = MakeShared(Result); StoreString(Item, Value); break; } case EOpType::ST_PARAMETER: { OP::ParameterArgs Args = Program.GetOpArgs(Item.At); FScheduledOp Op; Op.At = Item.At; Op.ExecutionIndex = Item.ExecutionIndex; TSharedPtr Index = BuildCurrentOpRangeIndex(Op, *Params, *Model.Get(), GetMemory(), Args.variable); FString Result; Params->GetStringValue(Args.variable, Result, Index.Get()); TSharedPtr Value = MakeShared(Result); StoreString(Item, Value); break; } case EOpType::NU_CONSTANT: { OP::IntConstantArgs Args = Program.GetOpArgs(Item.At); const int32 Value = Args.Value; StoreInt(Item, Value); break; } case EOpType::NU_PARAMETER: { OP::ParameterArgs Args = Program.GetOpArgs(Item.At); const int32 Value = Params->GetIntValue(Args.variable); StoreInt(Item, Value); break; } case EOpType::CO_ARITHMETIC: { OP::ArithmeticArgs Args = Program.GetOpArgs(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(Item.At); PushOp(FScheduledOpInline(Args.Image, Item)); StoreNone(Item); break; } case EOpType::CO_SWIZZLE: { OP::ColourSwizzleArgs Args = Program.GetOpArgs(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(Item.At); ME_SKELETON_ID.Push(Args.Skeleton); StoreNone(Item); break; } case EOpType::ME_REFERENCE: { OP::ResourceReferenceArgs Args = Program.GetOpArgs(Item.At); ME_REFERENCE_ID.Push(Args.ID); StoreNone(Item); break; } case EOpType::ME_APPLYLAYOUT: { OP::MeshApplyLayoutArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.Mesh, Item)); StoreNone(Item); break; } case EOpType::ME_PREPARELAYOUT: { OP::MeshPrepareLayoutArgs Args = Program.GetOpArgs(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(Item.At); PushOp(FScheduledOpInline(Args.Base, Item)); PushOp(FScheduledOpInline(Args.Added, Item)); StoreNone(Item); break; } case EOpType::ME_MASKCLIPMESH: { OP::MeshMaskClipMeshArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.source, Item)); PushOp(FScheduledOpInline(Args.clip, Item)); StoreNone(Item); break; } case EOpType::ME_MASKCLIPUVMASK: { OP::MeshMaskClipUVMaskArgs Args = Program.GetOpArgs(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(Item.At); PushOp(FScheduledOpInline(Args.Source, Item)); PushOp(FScheduledOpInline(Args.Fragment, Item)); StoreNone(Item); break; } case EOpType::ME_FORMAT: { OP::MeshFormatArgs Args = Program.GetOpArgs(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(Item.At); PushOp(FScheduledOpInline(Args.source, Item)); StoreNone(Item); break; } case EOpType::ME_CLIPMORPHPLANE: { OP::MeshClipMorphPlaneArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.Source, Item)); StoreNone(Item); break; } case EOpType::ME_CLIPWITHMESH: { OP::MeshClipWithMeshArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.Source, Item)); PushOp(FScheduledOpInline(Args.ClipMesh, Item)); StoreNone(Item); break; } case EOpType::ME_CLIPDEFORM: { OP::MeshClipDeformArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.mesh, Item)); PushOp(FScheduledOpInline(Args.clipShape, Item)); StoreNone(Item); break; } case EOpType::ME_APPLYPOSE: { OP::MeshApplyPoseArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.base, Item)); PushOp(FScheduledOpInline(Args.pose, Item)); StoreNone(Item); break; } case EOpType::ME_BINDSHAPE: { OP::MeshBindShapeArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.mesh, Item)); PushOp(FScheduledOpInline(Args.shape, Item)); StoreNone(Item); break; } case EOpType::ME_APPLYSHAPE: { OP::MeshApplyShapeArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.mesh, Item)); PushOp(FScheduledOpInline(Args.shape, Item)); StoreNone(Item); break; } case EOpType::ME_MORPHRESHAPE: { OP::MeshMorphReshapeArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.Morph, Item)); PushOp(FScheduledOpInline(Args.Reshape, Item)); StoreNone(Item); break; } case EOpType::ME_SETSKELETON: { OP::MeshSetSkeletonArgs Args = Program.GetOpArgs(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(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(Item.At); PushOp(FScheduledOpInline(Args.Mesh, Item)); PushOp(FScheduledOpInline(Args.Projector, Item)); StoreNone(Item); break; } case EOpType::ME_OPTIMIZESKINNING: { OP::MeshOptimizeSkinningArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.source, Item)); StoreNone(Item); break; } case EOpType::ME_TRANSFORMWITHMESH: { OP::MeshTransformWithinMeshArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.sourceMesh, Item)); PushOp(FScheduledOpInline(Args.boundingMesh, Item)); StoreNone(Item); break; } case EOpType::ME_TRANSFORMWITHBONE: { OP::MeshTransformWithBoneArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.SourceMesh, Item)); StoreNone(Item); break; } case EOpType::IM_REFERENCE: { OP::ResourceReferenceArgs Args = Program.GetOpArgs(Item.At); IM_REFERENCE_ID.Push(Args.ID); StoreNone(Item); break; } case EOpType::IM_LAYERCOLOUR: { OP::ImageLayerColourArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.base, Item)); PushOp(FScheduledOpInline(Args.mask, Item)); StoreNone(Item); break; } case EOpType::IM_LAYER: { OP::ImageLayerArgs Args = Program.GetOpArgs(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(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(Item.At); PushOp(FScheduledOpInline(Args.base, Item)); PushOp(FScheduledOpInline(Args.normal, Item)); StoreNone(Item); break; } case EOpType::IM_PIXELFORMAT: { OP::ImagePixelFormatArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.source, Item)); StoreNone(Item); break; } case EOpType::IM_MIPMAP: { OP::ImageMipmapArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.source, Item)); StoreNone(Item); break; } case EOpType::IM_RESIZE: { OP::ImageResizeArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.Source, Item)); StoreNone(Item); break; } case EOpType::IM_RESIZELIKE: { OP::ImageResizeLikeArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.Source, Item)); PushOp(FScheduledOpInline(Args.SizeSource, Item)); StoreNone(Item); break; } case EOpType::IM_RESIZEREL: { OP::ImageResizeRelArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.Source, Item)); StoreNone(Item); break; } case EOpType::IM_BLANKLAYOUT: { OP::ImageBlankLayoutArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.Layout, Item)); StoreNone(Item); break; } case EOpType::IM_COMPOSE: { OP::ImageComposeArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.base, Item)); PushOp(FScheduledOpInline(Args.blockImage, Item)); StoreNone(Item); break; } case EOpType::IM_INTERPOLATE: { OP::ImageInterpolateArgs Args = Program.GetOpArgs(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(Item.At); PushOp(FScheduledOpInline(Args.Base, Item)); StoreNone(Item); break; } case EOpType::IM_LUMINANCE: { OP::ImageLuminanceArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.Base, Item)); StoreNone(Item); break; } case EOpType::IM_SWIZZLE: { OP::ImageSwizzleArgs Args = Program.GetOpArgs(Item.At); TArray> 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(Item.At); PushOp(FScheduledOpInline(Args.Base, Item)); StoreNone(Item); break; } case EOpType::IM_BINARISE: { OP::ImageBinariseArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.Base, Item)); StoreNone(Item); break; } case EOpType::IM_INVERT: { OP::ImageInvertArgs Args = Program.GetOpArgs(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(Item.At); PushOp(FScheduledOpInline(Args.source, Item)); StoreNone(Item); break; } case EOpType::IM_PATCH: { OP::ImagePatchArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.base, Item)); PushOp(FScheduledOpInline(Args.patch, Item)); StoreNone(Item); break; } case EOpType::IM_RASTERMESH: { OP::ImageRasterMeshArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.mesh, Item)); StoreNone(Item); break; } case EOpType::IM_MAKEGROWMAP: { OP::ImageMakeGrowMapArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.mask, Item)); StoreNone(Item); break; } case EOpType::IM_DISPLACE: { OP::ImageDisplaceArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.Source, Item)); StoreNone(Item); break; } case EOpType::IM_TRANSFORM: { OP::ImageTransformArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.Base, Item)); StoreNone(Item); break; } case EOpType::LA_MERGE: { OP::LayoutMergeArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.Base, Item)); PushOp(FScheduledOpInline(Args.Added, Item)); StoreNone(Item); break; } case EOpType::LA_PACK: { OP::LayoutPackArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline( Args.Source, Item)); StoreNone(Item); break; } case EOpType::LA_FROMMESH: { OP::LayoutFromMeshArgs Args = Program.GetOpArgs(Item.At); PushOp(FScheduledOpInline(Args.Mesh, Item)); StoreNone(Item); break; } case EOpType::LA_REMOVEBLOCKS: { OP::LayoutRemoveBlocksArgs Args = Program.GetOpArgs(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(Item.At); TSharedPtr 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(Item.At); PushOp(FScheduledOpInline(Args.Material, Item)); StoreNone(Item); break; } default: unimplemented(); } } check(Stack.Num() <= 1); return Stack.Num() ? LoadInstance(Root) : MakeShared(); } }