// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Containers/Map.h" #include "HAL/PlatformMath.h" #include "Misc/AssertionMacros.h" #include "MuR/Image.h" #include "MuR/Mesh.h" #include "MuR/MutableMath.h" #include "MuR/Operations.h" #include "MuR/Parameters.h" #include "MuR/Ptr.h" #include "MuR/RefCounted.h" #include "MuR/System.h" #include "MuT/AST.h" #include "MuT/ASTOpSwitch.h" #include "MuT/CodeGenerator_FirstPass.h" #include "MuT/Compiler.h" #include "MuT/ErrorLog.h" #include "MuT/Node.h" #include "MuT/NodeBool.h" #include "MuT/NodeColourSampleImage.h" #include "MuT/NodeComponentEdit.h" #include "MuT/NodeComponentNew.h" #include "MuT/NodeComponentSwitch.h" #include "MuT/NodeExtensionData.h" #include "MuT/NodeImageProject.h" #include "MuT/NodeLOD.h" #include "MuT/NodeLayout.h" #include "MuT/NodeMeshTable.h" #include "MuT/NodeObjectGroup.h" #include "MuT/NodeObjectNew.h" #include "MuT/NodeProjector.h" #include "MuT/NodeString.h" #include "MuT/NodeSurfaceNew.h" #include "MuT/NodeModifierSurfaceEdit.h" #include "MuT/Table.h" #include "MuT/TablePrivate.h" #include "Templates/TypeHash.h" #include "Tasks/Pipe.h" namespace mu { class ASTOpParameter; class FLayout; class NodeColourArithmeticOperation; class NodeColourConstant; class NodeColourFromScalars; class NodeColourParameter; class NodeColourSwitch; class NodeColourTable; class NodeColourVariation; class NodeImageBinarise; class NodeImageColourMap; class NodeImageConditional; class NodeImageConstant; class NodeImageFormat; class NodeImageInterpolate; class NodeImageInvert; class NodeImageLayer; class NodeImageLayerColour; class NodeImageLuminance; class NodeImageMipmap; class NodeImageMultiLayer; class NodeImageNormalComposite; class NodeImageParameter; class NodeImagePlainColour; class NodeImageResize; class NodeImageSaturate; class NodeImageSwitch; class NodeImageSwizzle; class NodeImageTable; class NodeImageTransform; class NodeImageVariation; class NodeMeshApplyPose; class NodeMeshClipDeform; class NodeMeshClipMorphPlane; class NodeMeshClipWithMesh; class NodeMeshConstant; class NodeMeshFormat; class NodeMeshFragment; class NodeMeshMakeMorph; class NodeMeshMorph; class NodeMeshReshape; class NodeMeshSwitch; class NodeMeshTransform; class NodeMeshVariation; class NodeMeshParameter; class NodeRange; class NodeScalarArithmeticOperation; class NodeScalarConstant; class NodeScalarCurve; class NodeScalarEnumParameter; class NodeScalarParameter; class NodeScalarSwitch; class NodeScalarTable; class NodeScalarVariation; class NodeStringConstant; class NodeStringParameter; class NodeMatrix; class NodeMatrixConstant; class NodeMatrixParameter; struct FObjectState; struct FProgram; /** Converts mu::Node graphs into ASTOp graphs. */ class CodeGenerator { friend class FirstPassGenerator; public: CodeGenerator( CompilerOptions::Private*, TFunction& InWaitCallback ); //! Data will be stored in States void GenerateRoot( const Ptr ); public: /** This function will be called repeatedly in case a synchronization between threads is necessary. * It can be called from any thread. */ TFunction WaitCallback; struct FGenericGenerationOptions { friend FORCEINLINE uint32 GetTypeHash(const FGenericGenerationOptions& InKey) { uint32 KeyHash = 0; KeyHash = HashCombineFast(KeyHash, ::GetTypeHash(InKey.State)); KeyHash = HashCombineFast(KeyHash, ::GetTypeHash(InKey.ActiveTags.Num())); return KeyHash; } bool operator==(const FGenericGenerationOptions& InKey) const = default; int32 State = -1; TArray ActiveTags; // Variable to identify if an operation will end up generating an image. bool bIsImage = false; }; struct FObjectGenerationOptions : public FGenericGenerationOptions { const NodeObjectNew* ParentObjectNode = nullptr; /** Condition that enables a specific object. */ Ptr CurrentObjectCondition; }; struct FComponentGenerationOptions : public FGenericGenerationOptions { FComponentGenerationOptions(const FGenericGenerationOptions& BaseOptions, const Ptr& InBaseInstance ) { BaseInstance = InBaseInstance; State = BaseOptions.State; ActiveTags = BaseOptions.ActiveTags; } /** Instance to which the possibly generated components should be added. */ Ptr BaseInstance; }; struct FLODGenerationOptions : public FGenericGenerationOptions { FLODGenerationOptions(const FGenericGenerationOptions& BaseOptions, int32 InLODIndex, const NodeComponentNew* InComponent) { Component = InComponent; LODIndex = InLODIndex; State = BaseOptions.State; ActiveTags = BaseOptions.ActiveTags; } const NodeComponentNew* Component = nullptr; int32 LODIndex; }; struct FSurfaceGenerationOptions : public FGenericGenerationOptions { explicit FSurfaceGenerationOptions(const FGenericGenerationOptions& BaseOptions) { Component = nullptr; LODIndex = -1; State = BaseOptions.State; ActiveTags = BaseOptions.ActiveTags; } explicit FSurfaceGenerationOptions(const FLODGenerationOptions& BaseOptions) { Component = BaseOptions.Component; LODIndex = BaseOptions.LODIndex; State = BaseOptions.State; ActiveTags = BaseOptions.ActiveTags; } const NodeComponentNew* Component = nullptr; int32 LODIndex = -1; }; struct FGeneratedCacheKey { Ptr Node; FGenericGenerationOptions Options; friend FORCEINLINE uint32 GetTypeHash(const FGeneratedCacheKey& InKey) { uint32 KeyHash = 0; KeyHash = HashCombineFast(KeyHash, ::GetTypeHash(InKey.Node.get())); KeyHash = HashCombineFast(KeyHash, GetTypeHash(InKey.Options)); return KeyHash; } FORCEINLINE bool operator==(const FGeneratedCacheKey& Other) const = default; }; void GenerateGeneric(const FGenericGenerationOptions& Options, FGenericGenerationResult& OutResult, const Ptr InNode); /** Launch the tasks to generate a LOD subgraph. * Since LODs need to be generated in order a dependency task representing the previous LOD generation can be specified. */ FLODTask GenerateLOD(const FLODGenerationOptions&, const NodeLOD*, FLODTask PreviousLODTask); /** Launch the tasks to generate a Surface subgraph. */ FSurfaceTask GenerateSurface(const FSurfaceGenerationOptions&, Ptr, FLODTask PreviousLODTask); struct FGeneratedObjectCacheKey { Ptr Node; FObjectGenerationOptions Options; friend FORCEINLINE uint32 GetTypeHash(const FGeneratedObjectCacheKey& InKey) { uint32 KeyHash = 0; KeyHash = HashCombineFast(KeyHash, ::GetTypeHash(InKey.Node.get())); KeyHash = HashCombineFast(KeyHash, GetTypeHash(InKey.Options)); return KeyHash; } FORCEINLINE bool operator==(const FGeneratedObjectCacheKey& Other) const { return Node == Other.Node && Options == Other.Options; } }; struct FObjectGenerationResult : public FGenericGenerationResult { /** List of additional components to add to an object that come from child objects. * The index is the object and lod that should receive the components. */ struct FAdditionalComponentKey { const NodeObjectNew* ObjectNode = nullptr; FORCEINLINE bool operator==(const FAdditionalComponentKey& Other) const { return ObjectNode == Other.ObjectNode; } friend FORCEINLINE uint32 GetTypeHash(const FAdditionalComponentKey& InKey) { uint32 KeyHash = ::GetTypeHash(InKey.ObjectNode); return KeyHash; } }; struct FAdditionalComponentData { Ptr ComponentOp; Ptr PlaceholderOp; }; TMultiMap< FAdditionalComponentKey, TArray > AdditionalComponents; }; typedef TMap FGeneratedObjectsMap; FGeneratedObjectsMap GeneratedObjects; void GenerateObject(const FObjectGenerationOptions&, FObjectGenerationResult&, const NodeObject*); void GenerateObject_New(const FObjectGenerationOptions&, FObjectGenerationResult&, const NodeObjectNew*); void GenerateObject_Group(const FObjectGenerationOptions&, FObjectGenerationResult&, const NodeObjectGroup*); public: /** */ const CompilerOptions::Private* CompilerOptions = nullptr; /** */ FirstPassGenerator FirstPass; /** Used to accumulate all generation error messages. */ TSharedPtr ErrorLog; /** After the entire code generation this contains the information about all the states. */ typedef TArray< TPair> > FStateList; FStateList States; private: /** Any task accessing generic CodeGenerator members or "serial" data should run in this pipe. */ UE::Tasks::FPipe LocalPipe; /** This struct contains the generation state that can only be accessed when generating NodeMeshConstants. * It should only be accessed from tasks running in the specific FPipe below. */ struct FGenerateMeshConstantState { /** Container of meshes generated to be able to reuse them. * They are sorted by a cheap hash to speed up searches. */ struct FGeneratedConstantMesh { TSharedPtr Mesh; Ptr LastMeshOp; }; TMap> GeneratedConstantMeshes; }; FGenerateMeshConstantState GenerateMeshConstantState; /** List of already used vertex ID for meshes that must be unique. */ struct FUniqueMeshIds { uint32 EnsureUnique(uint32 Id); private: UE::FMutex Mutex; TSet Map; }; FUniqueMeshIds UniqueMeshIds; /** Any task accessing GenerateMeshConstantState should run in this pipe. */ UE::Tasks::FPipe GenerateMeshConstantPipe; /** The key for generated tables is made of the source table and a parameter name. */ struct FTableCacheKey { Ptr Table; FString ParameterName; friend FORCEINLINE uint32 GetTypeHash(const FTableCacheKey& InKey) { uint32 KeyHash = ::GetTypeHash(InKey.Table.get()); KeyHash = HashCombineFast(KeyHash, GetTypeHash(InKey.ParameterName)); return KeyHash; } FORCEINLINE bool operator==(const FTableCacheKey& InKey) const { if (Table != InKey.Table) return false; if (ParameterName != InKey.ParameterName) return false; return true; } }; struct FGeneratedTableNodes { UE::FMutex Mutex; TMap< FTableCacheKey, Ptr > Map; }; FGeneratedTableNodes GeneratedTableNodes; struct FConditionalExtensionDataOp { Ptr Condition; Ptr ExtensionDataOp; FString ExtensionDataName; }; TArray ConditionalExtensionDataOps; struct FGeneratedComponentCacheKey { Ptr Node; FGenericGenerationOptions Options; friend FORCEINLINE uint32 GetTypeHash(const FGeneratedComponentCacheKey& InKey) { uint32 KeyHash = 0; KeyHash = HashCombineFast(KeyHash, ::GetTypeHash(InKey.Node.get())); KeyHash = HashCombineFast(KeyHash, GetTypeHash(InKey.Options)); return KeyHash; } FORCEINLINE bool operator==(const FGeneratedComponentCacheKey& Other) const { return Node == Other.Node && Options == Other.Options; } }; typedef TMap FGeneratedComponentMap; FGeneratedComponentMap GeneratedComponents; void GenerateComponent(const FComponentGenerationOptions&, FGenericGenerationResult&, const NodeComponent*); void GenerateComponent_New(const FComponentGenerationOptions&, FGenericGenerationResult&, const NodeComponentNew*); void GenerateComponent_Switch(const FComponentGenerationOptions&, FGenericGenerationResult&, const NodeComponentSwitch*); void GenerateComponent_Variation(const FComponentGenerationOptions&, FGenericGenerationResult&, const NodeComponentVariation*); /** */ Ptr GenerateTableVariableNode(Ptr, const FTableCacheKey&, bool bAddNoneOption, const FString& DefaultRowName); //! Ptr GenerateMissingBoolCode(const TCHAR* strWhere, bool value, const void* errorContext ); //! template Ptr GenerateTableSwitch( const NODE_TABLE& node, F&& GenerateOption ); template void GenerateTableSwitchNode(const NODE_TABLE& node, Ptr& OutResult, F&& GenerateOption); //----------------------------------------------------------------------------------------- // Images /** Options that affect the generation of images. It is like list of what required data we want while parsing down the image node graph. */ struct FImageGenerationOptions : public FGenericGenerationOptions { FImageGenerationOptions(int32 InComponentId, int32 InLODIndex) : ComponentId(InComponentId) , LODIndex(InLODIndex) { bIsImage = true; } /** The id of the component that we are currently generating. */ int32 ComponentId = -1; /** The LOD being generated. */ int32 LODIndex = -1; /** */ CompilerOptions::TextureLayoutStrategy ImageLayoutStrategy = CompilerOptions::TextureLayoutStrategy::None; /** If different than {0,0} this is the mandatory size of the image that needs to be generated. */ UE::Math::TIntVector2 RectSize = {0, 0}; /** Layout block that we are trying to generate if any. */ uint64 LayoutBlockId = FLayoutBlock::InvalidBlockId; TSharedPtr LayoutToApply; friend FORCEINLINE uint32 GetTypeHash(const FImageGenerationOptions& InKey) { uint32 KeyHash = GetTypeHash((FGenericGenerationOptions&)InKey); KeyHash = HashCombineFast(KeyHash, ::GetTypeHash(InKey.ComponentId)); KeyHash = HashCombineFast(KeyHash, ::GetTypeHash(InKey.LODIndex)); KeyHash = HashCombineFast(KeyHash, ::GetTypeHash(InKey.ImageLayoutStrategy)); KeyHash = HashCombineFast(KeyHash, GetTypeHash(InKey.RectSize)); KeyHash = HashCombineFast(KeyHash, ::GetTypeHash(InKey.LayoutBlockId)); KeyHash = HashCombineFast(KeyHash, ::GetTypeHash(InKey.LayoutToApply.Get())); return KeyHash; } FORCEINLINE bool operator==(const FImageGenerationOptions& Other) const = default; }; /** */ struct FImageGenerationResult { Ptr op; }; /** */ struct FGeneratedImageCacheKey { FGeneratedImageCacheKey(const FImageGenerationOptions& InOptions, const NodeImagePtrConst& InNode) : Node(InNode) , Options(InOptions) { } Ptr Node; FImageGenerationOptions Options; friend FORCEINLINE uint32 GetTypeHash(const FGeneratedImageCacheKey& InKey) { uint32 KeyHash = 0; KeyHash = HashCombineFast(KeyHash, ::GetTypeHash(InKey.Node.get())); KeyHash = HashCombineFast(KeyHash, GetTypeHash(InKey.Options)); return KeyHash; } FORCEINLINE bool operator==(const FGeneratedImageCacheKey& Other) const = default; }; typedef TMap FGeneratedImagesMap; struct FGeneratedImages { UE::FMutex Mutex; FGeneratedImagesMap Map; }; FGeneratedImages GeneratedImages; void GenerateImage(const FImageGenerationOptions&, FImageGenerationResult& result, const NodeImagePtrConst& node); void GenerateImage_Constant(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageConstant*); void GenerateImage_Interpolate(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageInterpolate*); void GenerateImage_Saturate(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageSaturate*); void GenerateImage_Table(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageTable*); void GenerateImage_Swizzle(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageSwizzle*); void GenerateImage_ColourMap(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageColourMap*); void GenerateImage_Binarise(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageBinarise*); void GenerateImage_Luminance(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageLuminance*); void GenerateImage_Layer(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageLayer*); void GenerateImage_LayerColour(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageLayerColour*); void GenerateImage_Resize(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageResize*); void GenerateImage_PlainColour(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImagePlainColour*); void GenerateImage_Project(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageProject*); void GenerateImage_Mipmap(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageMipmap*); void GenerateImage_Switch(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageSwitch*); void GenerateImage_Conditional(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageConditional*); void GenerateImage_Format(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageFormat*); void GenerateImage_Parameter(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageParameter*); void GenerateImage_MultiLayer(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageMultiLayer*); void GenerateImage_Invert(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageInvert*); void GenerateImage_Variation(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageVariation*); void GenerateImage_NormalComposite(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageNormalComposite*); void GenerateImage_Transform(const FImageGenerationOptions&, FImageGenerationResult&, const NodeImageTransform*); /** */ TSharedPtr GenerateMissingImage(EImageFormat); /** */ Ptr GenerateMissingImageCode(const TCHAR* strWhere, EImageFormat, const void* errorContext, const FImageGenerationOptions& Options); /** */ Ptr GeneratePlainImageCode(const FVector4f& Color, const FImageGenerationOptions& Options); /** */ Ptr GenerateImageFormat(Ptr, EImageFormat); /** */ Ptr GenerateImageUncompressed(Ptr); /** */ Ptr GenerateImageSize(Ptr, UE::Math::TIntVector2); /** Evaluate if the image to generate is big enough to be split in separate operations and tiled afterwards. */ Ptr ApplyTiling(Ptr Source, UE::Math::TIntVector2 Size, EImageFormat Format); /** Generate a layout block-sized image with a mask including all pixels in the blocks defined in the patch node. */ TSharedPtr GenerateImageBlockPatchMask(const NodeModifierSurfaceEdit::FTexture&, FIntPoint GridSize, int32 BlockPixelsX, int32 BlockPixelsY, box RectInCells); /** Generate all the operations to apply the block patching on top of the BlockOp, and masking with PatchMask. */ Ptr GenerateImageBlockPatch(Ptr BlockOp, const NodeModifierSurfaceEdit::FTexture&, TSharedPtr PatchMask, Ptr ConditionOp, const FImageGenerationOptions&); //----------------------------------------------------------------------------------------- // Meshes /** Options that affect the generation of meshes. It is like list of what required data we want * while parsing down the mesh node graph. */ struct FMeshGenerationStaticOptions : public FGenericGenerationOptions { FMeshGenerationStaticOptions(int32 InComponentId, int32 InLODIndex) : ComponentId(InComponentId) , LODIndex(InLODIndex) { } /** The id of the component that we are currently generating. */ int32 ComponentId = -1; /** The LOD being generated. */ int32 LODIndex = -1; /** List of midifiers that shouldn't be applied in the processing of the current subgraph. * This is usually because they have been processed already in the generation so far. */ TArray ModifiersToIgnore; }; /** Options that affect the generation of meshes. It is like list of what required data we want * while parsing down the mesh node graph. */ struct FMeshGenerationDynamicOptions { /** The meshes at the leaves will need their own layout block data. */ bool bLayouts = false; /** If true, Ensure UV Islands are not split between two or more blocks. UVs shared between multiple * layout blocks will be clamped to fit the one with more vertices belonging to the UV island. * Mainly used to keep consistent layouts when reusing textures between LODs. */ bool bClampUVIslands = false; /** If true, UVs will be normalized. Normalize UVs should be done in cases where we operate with Images and Layouts */ bool bNormalizeUVs = false; /** If true, assign vertices without layout to the first block. */ bool bEnsureAllVerticesHaveLayoutBlock = true; /** If this has something the layouts in constant meshes will be ignored, because * they are supposed to match some other set of layouts. If the array is empty, layouts * are generated normally. */ TArray OverrideLayouts; /** Optional context to use instead of the node error context. * Be careful since it is not used everywhere. Check usages before assigning a value to it. */ TOptional OverrideContext; }; using FMeshOptionsTask = UE::Tasks::TTask; struct FSharedMeshOptions { /** Use this mutex to control acces to the SharedMeshOptionsMap attribute from any thread. * The task dependency will make sure that the actual order for data insert and retrieval is correct, but unrelated data can be added while * unrelated data is being retrieved so we need the mutex. */ UE::FMutex Mutex; /** Store the mesh generation data for surfaces that we intend to share across LODs. * The key is the SharedSurfaceId. */ TMap Map; }; FSharedMeshOptions SharedMeshOptions; /** This struct contains the generation state that can only be accessed when generating constant layouts. * It should only be accessed after locking the included mutex. */ struct FGenerateLayoutConstantState { UE::FMutex Mutex; /** Map of layouts found in the code already generated.The map is from the source layout node to the generated layout. */ struct FGeneratedLayoutKey { Ptr SourceLayout; uint32 MeshIdPrefix; friend FORCEINLINE uint32 GetTypeHash(const FGeneratedLayoutKey& InKey) { uint32 KeyHash = ::GetTypeHash(InKey.SourceLayout.get()); KeyHash = HashCombineFast(KeyHash, GetTypeHash(InKey.MeshIdPrefix)); return KeyHash; } FORCEINLINE bool operator==(const FGeneratedLayoutKey& Other) const = default; }; TMap> GeneratedLayouts; }; FGenerateLayoutConstantState GenerateLayoutConstantState; FMeshTask GenerateMesh(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const Ptr&); FMeshTask GenerateMesh_Constant(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const NodeMeshConstant* ); FMeshTask GenerateMesh_Format(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const NodeMeshFormat* ); FMeshTask GenerateMesh_Morph(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const NodeMeshMorph* ); FMeshTask GenerateMesh_MakeMorph(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const NodeMeshMakeMorph* ); FMeshTask GenerateMesh_Fragment(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const NodeMeshFragment* ); FMeshTask GenerateMesh_Switch(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const NodeMeshSwitch* ); FMeshTask GenerateMesh_Transform(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const NodeMeshTransform* ); FMeshTask GenerateMesh_ClipMorphPlane(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const NodeMeshClipMorphPlane* ); FMeshTask GenerateMesh_ClipWithMesh(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const NodeMeshClipWithMesh* ); FMeshTask GenerateMesh_ApplyPose(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const NodeMeshApplyPose* ); FMeshTask GenerateMesh_Variation(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const NodeMeshVariation* ); FMeshTask GenerateMesh_Table(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const NodeMeshTable*); FMeshTask GenerateMesh_Reshape(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const NodeMeshReshape*); FMeshTask GenerateMesh_ClipDeform(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const NodeMeshClipDeform*); FMeshTask GenerateMesh_Parameter(const FMeshGenerationStaticOptions&, FMeshOptionsTask, const NodeMeshParameter*); Ptr GenerateLayoutOpsAndResult(const FMeshGenerationDynamicOptions&, Ptr LastMeshOp, const TArray>& OriginalLayouts, uint32 MeshId, FMeshGenerationResult& OutResult); //----------------------------------------------------------------------------------------- //! TSharedPtr GenerateLayout(Ptr SourceLayout, uint32 MeshIDPrefix); struct FExtensionDataGenerationResult { Ptr Op; }; typedef const NodeExtensionData* FGeneratedExtensionDataCacheKey; typedef TMap FGeneratedExtensionDataMap; FGeneratedExtensionDataMap GeneratedExtensionData; void GenerateExtensionData(FExtensionDataGenerationResult& OutResult, const FGenericGenerationOptions&, const Ptr&); void GenerateExtensionData_Constant(FExtensionDataGenerationResult& OutResult, const FGenericGenerationOptions&, const class NodeExtensionDataConstant*); void GenerateExtensionData_Switch(FExtensionDataGenerationResult& OutResult, const FGenericGenerationOptions&, const class NodeExtensionDataSwitch*); void GenerateExtensionData_Variation(FExtensionDataGenerationResult& OutResult, const FGenericGenerationOptions&, const class NodeExtensionDataVariation*); Ptr GenerateMissingExtensionDataCode(const TCHAR* StrWhere, const void* ErrorContext); //----------------------------------------------------------------------------------------- // Projectors struct FProjectorGenerationResult { Ptr op; EProjectorType type; }; typedef TMap FGeneratedProjectorsMap; struct FGeneratedProjectors { UE::FMutex Mutex; FGeneratedProjectorsMap Map; }; FGeneratedProjectors GeneratedProjectors; void GenerateProjector( FProjectorGenerationResult&, const FGenericGenerationOptions&, const Ptr& ); void GenerateProjector_Constant( FProjectorGenerationResult&, const FGenericGenerationOptions&, const Ptr& ); void GenerateProjector_Parameter( FProjectorGenerationResult&, const FGenericGenerationOptions&, const Ptr& ); void GenerateMissingProjectorCode( FProjectorGenerationResult&, const void* errorContext ); //----------------------------------------------------------------------------------------- // Bools struct FBoolGenerationResult { Ptr op; }; typedef TMap FGeneratedBoolsMap; struct FGeneratedBools { UE::FMutex Mutex; FGeneratedBoolsMap Map; }; FGeneratedBools GeneratedBools; void GenerateBool(FBoolGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateBool_Constant(FBoolGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateBool_Parameter(FBoolGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateBool_Not(FBoolGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateBool_And(FBoolGenerationResult&, const FGenericGenerationOptions&, const Ptr&); //----------------------------------------------------------------------------------------- // Scalars struct FScalarGenerationResult { Ptr op; }; typedef TMap FGeneratedScalarsMap; struct FGeneratedScalars { UE::FMutex Mutex; FGeneratedScalarsMap Map; }; FGeneratedScalars GeneratedScalars; void GenerateScalar(FScalarGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateScalar_Constant(FScalarGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateScalar_Parameter(FScalarGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateScalar_Switch(FScalarGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateScalar_EnumParameter(FScalarGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateScalar_Curve(FScalarGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateScalar_Arithmetic(FScalarGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateScalar_Variation(FScalarGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateScalar_Table(FScalarGenerationResult&, const FGenericGenerationOptions&, const Ptr&); Ptr GenerateMissingScalarCode(const TCHAR* strWhere, float value, const void* errorContext); //----------------------------------------------------------------------------------------- // Colors struct FColorGenerationResult { Ptr op; }; typedef TMap FGeneratedColorsMap; struct FGeneratedColors { UE::FMutex Mutex; FGeneratedColorsMap Map; }; FGeneratedColors GeneratedColors; void GenerateColor(FColorGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateColor_Constant(FColorGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateColor_Parameter(FColorGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateColor_Switch(FColorGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateColor_SampleImage(FColorGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateColor_FromScalars(FColorGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateColor_Arithmetic(FColorGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateColor_Variation(FColorGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateColor_Table(FColorGenerationResult&, const FGenericGenerationOptions&, const Ptr&); Ptr GenerateMissingColourCode(const TCHAR* strWhere, const void* errorContext); //----------------------------------------------------------------------------------------- // Strings struct FStringGenerationResult { Ptr op; }; typedef TMap FGeneratedStringsMap; struct FGeneratedStrings { UE::FMutex Mutex; FGeneratedStringsMap Map; }; FGeneratedStrings GeneratedStrings; void GenerateString(FStringGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateString_Constant(FStringGenerationResult&, const FGenericGenerationOptions& Options, const Ptr&); void GenerateString_Parameter(FStringGenerationResult&, const FGenericGenerationOptions& Options, const Ptr&); //----------------------------------------------------------------------------------------- // Transforms struct FMatrixGenerationResult { Ptr op; }; typedef TMap FGeneratedMatrixMap; struct FGeneratedMatrices { UE::FMutex Mutex; FGeneratedMatrixMap Map; }; FGeneratedMatrices GeneratedMatrices; void GenerateMatrix(FMatrixGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateMatrix_Constant(FMatrixGenerationResult&, const FGenericGenerationOptions&, const Ptr&); void GenerateMatrix_Parameter(FMatrixGenerationResult&, const FGenericGenerationOptions&, const Ptr&); //----------------------------------------------------------------------------------------- // Ranges struct FRangeGenerationResult { // Ptr sizeOp; // FString rangeName; // FString rangeUID; }; typedef TMap FGeneratedRangeMap; struct FGeneratedRanges { UE::FMutex Mutex; FGeneratedRangeMap Map; }; FGeneratedRanges GeneratedRanges; void GenerateRange(FRangeGenerationResult&, const FGenericGenerationOptions&, Ptr); //----------------------------------------------------------------------------------------- struct FLayoutBlockDesc { EImageFormat FinalFormat = EImageFormat::None; int32 BlockPixelsX = 0; int32 BlockPixelsY = 0; bool bBlocksHaveMips = false; }; void UpdateLayoutBlockDesc(FLayoutBlockDesc& Out, FImageDesc BlockDesc, FIntVector2 LayoutCellSize); // Get the modifiers that have to be applied to elements with a specific tag. void GetModifiersFor(int32 ComponentId, const TArray& SurfaceTags, bool bModifiersForBeforeOperations, TArray& OutModifiers) const; // Apply the required mesh modifiers to the given operation. FMeshTask ApplyMeshModifiers( const TArray&, const FMeshGenerationStaticOptions&, FMeshOptionsTask DynamicOptionsTask, FMeshTask BaseTask, int32 SharedSurfaceId, const void* ErrorContext, const NodeMeshConstant* OriginalMeshNode); Ptr ApplyImageBlockModifiers( const TArray&, const FImageGenerationOptions&, Ptr BaseImageOp, const NodeSurfaceNew::FImageData& ImageData, FIntPoint GridSize, const FLayoutBlockDesc& LayoutBlockDesc, box< FIntVector2 > RectInCells, const void* ErrorContext); Ptr ApplyImageExtendModifiers( const TArray&, const FMeshGenerationStaticOptions& Options, const FMeshGenerationResult& BaseMeshResults, Ptr ImageAd, CompilerOptions::TextureLayoutStrategy ImageLayoutStrategy, int32 LayoutIndex, const NodeSurfaceNew::FImageData& ImageData, FIntPoint GridSize, CodeGenerator::FLayoutBlockDesc& InOutLayoutBlockDesc, const void* ModifiedNodeErrorContext); void CheckModifiersForSurface(const NodeSurfaceNew&, const TArray&, int32 LODIndex); }; //--------------------------------------------------------------------------------------------- template Ptr CodeGenerator::GenerateTableSwitch( const NODE_TABLE& node, F&& GenerateOption ) { Ptr NodeTable = node.Table; Ptr Variable; Ptr VariableNode; FTableCacheKey CacheKey = FTableCacheKey{ node.Table, node.ParameterName }; { UE::TUniqueLock Lock(GeneratedTableNodes.Mutex); Ptr* Found = GeneratedTableNodes.Map.Find(CacheKey); if (Found) { VariableNode = *Found; } if (!VariableNode) { // Create the table variable expression VariableNode = GenerateTableVariableNode(&node, CacheKey, node.bNoneOption, node.DefaultRowName); GeneratedTableNodes.Map.Add(CacheKey, VariableNode); } } FGenericGenerationOptions ScalarOptions; FScalarGenerationResult ScalarResult; GenerateScalar(ScalarResult, ScalarOptions, VariableNode); Variable = ScalarResult.op; int32 NumRows = NodeTable->GetPrivate()->Rows.Num(); // Verify that the table column is the right type int32 ColIndex = NodeTable->FindColumn( node.ColumnName ); if (NumRows == 0) { ErrorLog->Add("The table has no rows.", ELMT_ERROR, node.GetMessageContext()); return nullptr; } else if (ColIndex < 0) { ErrorLog->Add("Table column not found.", ELMT_ERROR, node.GetMessageContext()); return nullptr; } if (NodeTable->GetPrivate()->Columns[ ColIndex ].Type != TYPE ) { ErrorLog->Add("Table column type is not the right type.", ELMT_ERROR, node.GetMessageContext()); return nullptr; } // Create the switch to cover all the options Ptr lastSwitch; Ptr SwitchOp = new ASTOpSwitch(); SwitchOp->Type = OPTYPE; SwitchOp->Variable = Variable; SwitchOp->Default = nullptr; for (int32 RowIndex = 0; RowIndex < NumRows; ++RowIndex) { check(RowIndex <= 0xFFFF); auto Condition = (uint16)RowIndex; Ptr Branch = GenerateOption( node, ColIndex, RowIndex, ErrorLog.Get() ); if (Branch || TYPE != ETableColumnType::Mesh) { SwitchOp->Cases.Add(ASTOpSwitch::FCase(Condition, SwitchOp, Branch)); } } return SwitchOp; } //--------------------------------------------------------------------------------------------- template void CodeGenerator::GenerateTableSwitchNode( const NODE_TABLE& node, Ptr& OutResult, F&& GenerateOption ) { OutResult = nullptr; Ptr NodeTable = node.Table; Ptr Variable; FTableCacheKey CacheKey = FTableCacheKey{ node.Table, node.ParameterName }; { UE::TUniqueLock Lock(GeneratedTableNodes.Mutex); Ptr* Found = GeneratedTableNodes.Map.Find(CacheKey); if (Found) { Variable = *Found; } if (!Variable) { // Create the table variable expression Variable = GenerateTableVariableNode(&node, CacheKey, node.bNoneOption, node.DefaultRowName); GeneratedTableNodes.Map.Add(CacheKey, Variable); } } int32 NumRows = NodeTable->GetPrivate()->Rows.Num(); // Verify that the table column is the right type int32 ColIndex = NodeTable->FindColumn( node.ColumnName ); if (NumRows == 0) { ErrorLog->Add("The table has no rows.", ELMT_ERROR, node.GetMessageContext()); return; } else if (ColIndex < 0) { ErrorLog->Add("Table column not found.", ELMT_ERROR, node.GetMessageContext()); return; } if (NodeTable->GetPrivate()->Columns[ ColIndex ].Type != TYPE ) { ErrorLog->Add("Table column type is not the right type.", ELMT_ERROR, node.GetMessageContext()); return; } // Create the switch node Ptr SwitchNode = new NODE_SWITCH_TYPE; SwitchNode->Parameter = Variable; SwitchNode->Options.SetNum(NumRows); for (int32 RowIndex = 0; RowIndex < NumRows; ++RowIndex) { check(RowIndex <= 0xFFFF); Ptr BranchNode = GenerateOption( node, ColIndex, RowIndex, ErrorLog.Get() ); SwitchNode->Options[RowIndex] = BranchNode; } OutResult = SwitchNode; } }