// Copyright UShaderLab. All Rights Reserved. #pragma once #include "CoreMinimal.h" class UMaterial; class UMaterialExpression; struct FShaderLabModel; /** * One body of HLSL scanned for capability triggers: the verbatim text plus its 1-based `.usl` source line * (so a capability can map a contract violation back to the exact authored line). Covers a shader's own * pixel/vertex bodies AND every reachable `.uslfunc` library-function body, since a library function called * from a body is inlined into the same Custom node and can equally reference a raw scene-texture helper. */ struct FShaderLabScannedBody { /** Non-owning pointer to the body text (lives in the FShaderLabModel / resolved program). */ const FString* Text = nullptr; /** 1-based source line of the body's first character, for error line-mapping. */ int32 SourceLine = 0; }; /** Everything a capability needs to detect usage, validate it, and create its hidden anchor node(s). */ struct FShaderLabAnchorCapabilityContext { /** The material being built (target of MakeNode). */ UMaterial& Material; /** The parsed shader model (domain / blend mode live here for per-id domain validation). */ const FShaderLabModel& Model; /** Shader bodies + reachable library-function bodies to scan. */ const TArray& Bodies; /** The shader's `.usl` absolute path (`#line` directive target for mapped errors). */ const FString& SourcePath; /** * Create a material expression of `Class`, add it to the material's expression collection, and lay it * out on the canvas — the capability then sets any type-specific fields (e.g. SceneTextureId) on the * CastChecked<> result. Mirrors the builder's internal NewExpr helper. */ TFunction MakeNode; }; /** * A "capability" that a raw-HLSL body helper depends on: the helper (e.g. `SceneTextureLookup`, * `GetDistanceToNearestSurfaceGlobal`) compiles fine as bare HLSL inside a Custom node, but the runtime * resource binding it needs is only established as a side effect of compiling a matching UMaterialExpression * (via `UseSceneTextureId` / `bUsesGlobalDistanceField` / ...). Because the Custom body bypasses that node, * we synthesize a hidden expression, wired into the before-attributes ParameterAnchor, purely for the * side effect. This registry is the general mechanism; each dynamic-input helper family registers one entry. * * (Helpers with NO dynamic body input — e.g. EyeAdaptation — do not need this: they are exposed as ordinary * `UE_` wired intrinsics whose real node is connected into the Custom input, so its Compile side effect fires * naturally. This mechanism is only for helpers that take a body-computed argument, which cannot be fed into * a node from inside the opaque Custom body.) */ struct FShaderLabAnchorCapability { /** Identifier for diagnostics / tests (e.g. "SceneTexture", "GlobalDistanceField"). */ FName Id; /** * HLSL tokens whose presence in any scanned body activates this capability (e.g. "UE_SceneTexture", * "UE_SceneDepth"). Matched delimited by non-identifier characters. */ TArray TriggerTokens; /** * Emit the hidden before-attributes node(s) for this capability into OutNodes. Runs only when at least * one TriggerToken is present. Returns false and appends `.usl`-mapped messages to OutErrors on a * contract violation (e.g. a non-literal id) or an illegal domain — contract style, aborting the build. */ TFunction& /*OutNodes*/, TArray& /*OutErrors*/)> Emit; }; /** * Open registry of anchor side-effect capabilities. ShaderLab seeds its builtins (SceneTexture, Global * Distance Field) on first use; other editor modules may register their own from their StartupModule via * Get().Register(...). The graph builder queries it once per build. */ class USHADERLABBUILDER_API FShaderLabAnchorCapabilityRegistry { public: static FShaderLabAnchorCapabilityRegistry& Get(); /** Register (or override, by Id) a capability. */ void Register(FShaderLabAnchorCapability Capability); /** Visit every registered capability. */ void ForEach(TFunctionRef Fn) const; private: FShaderLabAnchorCapabilityRegistry(); void RegisterBuiltins(); TArray Capabilities; };