Files
UShaderLab/Source/UShaderLab/Public/ShaderLabMaterialRegistry.h
2026-07-05 11:26:32 +08:00

78 lines
3.5 KiB
C++

// Copyright UShaderLab. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "ShaderLabModel.h"
class UPackage;
class UMaterial;
/**
* Broadcast when a base material shell has been created/located and needs its contents filled:
* in the editor the graph builder rebuilds the expression graph; at cooked runtime the shell
* builder applies settings + attaches the precompiled shader map.
*/
DECLARE_MULTICAST_DELEGATE_TwoParams(FOnShaderLabBuildMaterial, UMaterial& /*Material*/, const FShaderLabModel& /*Model*/);
/**
* Broadcast AFTER a base material's graph has been fully (re)built and compiled by the uncooked builder.
* Split from OnBuildMaterial so the editor-only reaction (refreshing open Material Instance editors) runs
* strictly after the build, without dragging the MaterialEditor dependency into the UncookedOnly builder
* module (which must load in `-game`, where editor-UI modules are absent). No listeners in `-game`.
*/
DECLARE_MULTICAST_DELEGATE_OneParam(FOnShaderLabMaterialGraphBuilt, UMaterial& /*Material*/);
/**
* Owns the in-memory base materials. They live in a compiled-in package named "/Script/UShaderLab"
* so that saved assets (MICs) can hard-reference them by object path and have that import resolve
* via FindObject in editor, cook AND cooked runtime without any .uasset on disk — the same trick
* the engine uses for all native /Script packages. Materials must be created before any referencing
* asset is resolved (cook start / early runtime).
*/
class USHADERLAB_API FShaderLabMaterialRegistry
{
public:
static FShaderLabMaterialRegistry& Get();
/** The compiled-in "/Script/UShaderLab" package (created on first use, kept rooted). */
UPackage* GetPackage();
/** Deterministic, UObject-safe object name for a shader name like "ShaderLab/RustyMetal". */
static FName MakeObjectName(const FString& ShaderName);
/** Full object path, e.g. "/Script/UShaderLab.ShaderLab_RustyMetal". */
static FString MakeObjectPath(const FString& ShaderName);
/**
* Convert an absolute `.usl` disk path to the stable DSL virtual shader path (e.g.
* "/Project/Examples/Basic.usl" or "/Plugin/ShaderLab/..."). Runtime-safe (uses the project/plugin
* `Shaders` root convention, not the editor-only shader mappings). Returns the forward-slashed
* absolute path unchanged if it is under no known root.
*/
static FString MakeVirtualShaderPath(const FString& AbsoluteSourcePath);
/** Find an already-created base material by shader name (nullptr if absent). */
UMaterial* FindMaterial(const FString& ShaderName) const;
/**
* Find-or-create the base material for `Model`, register it for path resolution, and
* broadcast OnBuildMaterial so a bound builder fills it in. Idempotent per shader name.
*/
UMaterial* RegisterFromModel(const FShaderLabModel& Model);
FOnShaderLabBuildMaterial& OnBuildMaterial() { return BuildMaterialDelegate; }
/** Fired by the uncooked builder once a base material's graph is built + compiled (see delegate doc). */
FOnShaderLabMaterialGraphBuilt& OnMaterialGraphBuilt() { return MaterialGraphBuiltDelegate; }
/** Models registered so far, keyed by object name (used by the instance factory picker and the example/validation commandlets). */
const TMap<FName, FShaderLabModel>& GetRegisteredModels() const { return RegisteredModels; }
private:
UPackage* Package = nullptr;
FOnShaderLabBuildMaterial BuildMaterialDelegate;
FOnShaderLabMaterialGraphBuilt MaterialGraphBuiltDelegate;
TMap<FName, FShaderLabModel> RegisteredModels;
};