// Copyright UShaderLab. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "MaterialValueType.h" #include "Materials/MaterialExpressionCustomOutput.h" #include "MaterialExpressionShaderLabParameterAnchor.generated.h" /** * Internal ShaderLab node with two jobs, both keeping workaround machinery off the user's body nodes: * * 1. Anchors parameters so the Material Instance editor lists them. StaticBool parameters are consumed * only inside HLSL `#if`, so they would otherwise be unconnected; the instance editor's visibility * walk only reaches parameters connected to a material output or a CustomOutput. This is a * CustomOutput, so it is always traversed; each anchored parameter reaches one of its inputs (via * its static-switch selector). * * 2. Injects per-permutation static-switch `#define`s with ZERO engine modifications. Each input is a * StaticSwitch over two `#define 1` / `#define 0` Custom nodes. This node returns * ShouldCompileBeforeAttributes()==true, so FHLSLMaterialTranslator compiles it BEFORE the material * attributes (FrontMaterial / body). Its Compile() compiles each input, so the selected `#define` * (only the taken StaticSwitch branch is compiled) is emitted ahead of every body's `#if`. The * `#define` leaks forward (preprocessor is global) and the body's `#if ` sees the current * permutation's value — including a Material Instance's static override. * * It only ever lives in the editor graph (never serialized into a cooked package). */ UCLASS(MinimalAPI, collapsecategories, hidecategories = Object) class UMaterialExpressionShaderLabParameterAnchor : public UMaterialExpressionCustomOutput { GENERATED_UCLASS_BODY() /** One input per static-switch selector (a StaticSwitch over two `#define`-emitting Custom nodes). */ UPROPERTY() TArray Inputs; //~ Begin UMaterialExpressionCustomOutput Interface // One output so the translator actually compiles us (a zero-output CustomOutput is skipped). The // output value is unused; compiling us is purely to emit our inputs' `#define`s before attributes. virtual int32 GetNumOutputs() const override { return 1; } virtual FString GetFunctionName() const override { return TEXT("ShaderLabParameterAnchor"); } #if WITH_EDITOR virtual bool NeedsCustomOutputDefines() override { return false; } // don't emit NUM_MATERIAL_OUTPUTS_* virtual bool ShouldCompileBeforeAttributes() override { return true; } // emit #defines ahead of body #if #endif //~ End UMaterialExpressionCustomOutput Interface #if WITH_EDITOR //~ Begin UMaterialExpression Interface virtual TArrayView GetInputsView() override; virtual FExpressionInput* GetInput(int32 InputIndex) override; virtual FName GetInputName(int32 InputIndex) const override; virtual EMaterialValueType GetInputValueType(int32 InputIndex) override { return MCT_Float1; } virtual int32 Compile(class FMaterialCompiler* Compiler, int32 OutputIndex) override; virtual void GetCaption(TArray& OutCaptions) const override; //~ End UMaterialExpression Interface #endif private: /** Scratch pointer view rebuilt by GetInputsView(). */ TArray CachedInputs; };