// Copyright Epic Games, Inc. All Rights Reserved. #include "MuT/ASTOpMeshApplyLayout.h" #include "MuT/ASTOpSwitch.h" #include "MuT/ASTOpMeshAddMetadata.h" #include "HAL/PlatformMath.h" #include "MuR/ModelPrivate.h" #include "MuR/RefCounted.h" #include "MuR/Types.h" namespace mu { ASTOpMeshApplyLayout::ASTOpMeshApplyLayout() : Mesh(this) , Layout(this) { } ASTOpMeshApplyLayout::~ASTOpMeshApplyLayout() { // Explicit call needed to avoid recursive destruction ASTOp::RemoveChildren(); } bool ASTOpMeshApplyLayout::IsEqual(const ASTOp& OtherUntyped) const { if (OtherUntyped.GetOpType()==GetOpType()) { const ASTOpMeshApplyLayout* Other = static_cast(&OtherUntyped); return Mesh == Other->Mesh && Layout == Other->Layout && Channel == Other->Channel; } return false; } uint64 ASTOpMeshApplyLayout::Hash() const { uint64 Result = std::hash()(Mesh.child().get()); hash_combine(Result, Layout.child().get()); hash_combine(Result, Channel); return Result; } Ptr ASTOpMeshApplyLayout::Clone(MapChildFuncRef MapChild) const { Ptr New = new ASTOpMeshApplyLayout(); New->Mesh = MapChild(Mesh.child()); New->Layout = MapChild(Layout.child()); New->Channel = Channel; return New; } void ASTOpMeshApplyLayout::ForEachChild(const TFunctionRef Func) { Func(Mesh); Func(Layout); } void ASTOpMeshApplyLayout::Link(FProgram& Program, FLinkerOptions*) { // Already linked? if (!linkedAddress) { OP::MeshApplyLayoutArgs Args; FMemory::Memzero(Args); if (Mesh) Args.Mesh = Mesh->linkedAddress; if (Layout) Args.Layout = Layout->linkedAddress; Args.Channel = Channel; linkedAddress = (OP::ADDRESS)Program.OpAddress.Num(); Program.OpAddress.Add(Program.ByteCode.Num()); AppendCode(Program.ByteCode, GetOpType()); AppendCode(Program.ByteCode, Args); } } Ptr ASTOpMeshApplyLayout::OptimiseSink(const FModelOptimizationOptions&, FOptimizeSinkContext&) const { Ptr NewOp; Ptr MeshAt = Mesh.child(); if (!MeshAt) { return nullptr; } EOpType MeshOpType = MeshAt->GetOpType(); bool bLayoutIsConstant = !Layout || Layout->GetOpType() == EOpType::LA_CONSTANT; switch (MeshOpType) { case EOpType::ME_ADDMETADATA: { Ptr New = mu::Clone(MeshAt); if (New->Source) { Ptr NewApplyPose = mu::Clone(this); NewApplyPose->Mesh = New->Source.child(); New->Source = NewApplyPose; } NewOp = New; break; } case EOpType::ME_SWITCH: { if (bLayoutIsConstant) { // Move the apply down all the paths Ptr NewSwitch = mu::Clone(MeshAt); if (NewSwitch->Default) { Ptr defOp = mu::Clone(this); defOp->Mesh = NewSwitch->Default.child(); NewSwitch->Default = defOp; } // We need to copy the options because we change them for (int32 CaseIndex = 0; CaseIndex < NewSwitch->Cases.Num(); ++CaseIndex) { if (NewSwitch->Cases[CaseIndex].Branch) { Ptr bOp = mu::Clone(this); bOp->Mesh = NewSwitch->Cases[CaseIndex].Branch.child(); NewSwitch->Cases[CaseIndex].Branch = bOp; } } NewOp = NewSwitch; } break; } default: break; } return NewOp; } FSourceDataDescriptor ASTOpMeshApplyLayout::GetSourceDataDescriptor(FGetSourceDataDescriptorContext* Context) const { if (Mesh) { return Mesh->GetSourceDataDescriptor(Context); } return {}; } }