Editor/ShaderGraphPlus/Compiler/Templates/ShaderTypeInfo.cs

A record type ShaderTypeInfo used by the shader template system in the Editor. It stores title, icon, shader domain, a list of support strings and input plug definitions, provides helpers to query supports and plugs, and an implicit conversion from ShaderTemplateResource to populate defaults based on shader domain and template options.

Reflection
namespace ShaderGraphPlus;

public static partial class ShaderTemplate
{
	public sealed record ShaderTypeInfo( string Title, string Icon, ShaderDomain Domian, IEnumerable<string> SupportStrings, Dictionary<string, TemplateInputPlugInfo> InputPlugs ) : IValid
	{
		public bool IsValid => !string.IsNullOrWhiteSpace( Title ) && InputPlugs.Any();

		internal ShaderTypeInfo() : this( "", "", ShaderDomain.Surface, new List<string>(), new Dictionary<string, TemplateInputPlugInfo>() )
		{
		}

		/// <summary>
		/// Check to see if the provided support string exists.
		/// </summary>
		public bool HasSupport( string supportString ) => SupportStrings.Contains( supportString );

		/// <summary>
		/// Check to see if an input plug with the provided name exists.
		/// </summary>
		public bool HasInputPlug( string name ) => InputPlugs.ContainsKey( name );

		/// <summary>
		/// Try to get the named input plug.
		/// </summary>
		public bool TryGetInputPlug( string name, out TemplateInputPlugInfo plug )
		{
			return InputPlugs.TryGetValue( name, out plug );
		}

		public static implicit operator ShaderTypeInfo( ShaderTemplateResource userTemplate )
		{
			var templatePlugs = new Dictionary<string, TemplateInputPlugInfo>();
			var supportStrings = new List<string>();

			switch ( userTemplate.ShaderDomain )
			{
				case ShaderDomain.Surface:
					{
						if ( userTemplate.ShadingModel == ShadingModel.Lit )
						{
							templatePlugs = ShaderTemplateSurface.DefaultLitInputs;

							supportStrings.Add( SupportsLitShading );
						}
						else
						{
							templatePlugs = ShaderTemplateSurface.DefaultUnlitInputs;

							supportStrings.Add( SupportsUnlitShading );
						}

						if ( !userTemplate.Opacity )
						{
							templatePlugs.Remove( "Opacity" );
						}

						if ( !userTemplate.PositionOffset )
						{
							templatePlugs.Remove( "PositionOffset" );
						}

						if ( userTemplate.OpaqueBlend )
						{
							supportStrings.Add( SupportsOpaqueBlend );
						}
						if ( userTemplate.MaskedBlend )
						{
							supportStrings.Add( SupportsMaskedBlend );
						}
						if ( userTemplate.TranslucentBlend )
						{
							supportStrings.Add( SupportsTranslucentBlend );
						}

						break;
					}
				case ShaderDomain.Sky:
					{
						templatePlugs = ShaderTemplateSky.DefaultInputs;
						break;
					}
				case ShaderDomain.PostProcess:
					{
						templatePlugs = ShaderTemplatePostProcess.DefaultInputs;
						break;
					}
				default:
					throw new NotImplementedException( $"Unknown ShaderDomain '{userTemplate.ShaderDomain}'" );
			}

			if ( userTemplate.EnforceRenderFace )
			{
				switch ( userTemplate.RenderFace )
				{
					case RenderFace.Front:
						supportStrings.Add( SupportsRenderFaceFront );
						break;
					case RenderFace.Back:
						supportStrings.Add( SupportsRenderFaceBack );
						break;
					case RenderFace.Both:
						supportStrings.Add( SupportsRenderFaceBoth );
						break;
				}
			}
			else
			{
				supportStrings.Add( SupportsAllRenderFace );
			}

			return new ShaderTypeInfo(
				userTemplate.Title,
				userTemplate.Icon,
				userTemplate.ShaderDomain,
				supportStrings,
				templatePlugs
			);
		}
	}
}