Editor/ShaderGraphPlus/Compiler/NodeResult.cs
namespace ShaderGraphPlus;
public enum ResultType
{
Invalid,
Bool,
Int,
Float,
Vector2,
Vector3,
Vector4,
Float2x2,
Float3x3,
Float4x4,
Sampler,
Texture2D,
TextureCube,
Gradient,
VoidFunction,
}
internal enum MetadataType
{
ComboSwitchBody
}
public struct NodeResult : IValid
{
public delegate NodeResult Func( GraphCompiler compiler );
public string Code { get; private set; }
public ResultType ResultType { get; private set; } = ResultType.Invalid;
public string[] Errors { get; private init; }
public string[] Warnings { get; private init; }
public int Components { get; private set; }
public int PreviewID { get; private set; }
public string VoidLocalTargetID { get; private set; }
public readonly bool IsValid
{
get
{
if ( IsMetaDataResult )
{
return ResultType != ResultType.Invalid && Metadata.Any();
}
else
{
return ResultType != ResultType.Invalid && !string.IsNullOrWhiteSpace( Code );
}
}
}
public readonly bool CanPreview
{
get
{
switch ( ResultType )
{
case ResultType.Bool:
return false;
case ResultType.Int:
return true;
case ResultType.Float:
return true;
case ResultType.Vector2:
return true;
case ResultType.Vector3:
return true;
case ResultType.Vector4:
return true;
case ResultType.Float2x2:
return false;
case ResultType.Float3x3:
return false;
case ResultType.Float4x4:
return false;
case ResultType.Sampler:
return false;
case ResultType.Texture2D:
return false;
case ResultType.TextureCube:
return false;
case ResultType.Gradient:
return false;
case ResultType.VoidFunction:
return false;
case ResultType.Invalid:
throw new Exception( "Result Type Is Invalid!" );
default:
return false;
}
}
}
public readonly bool CanCast => ResultType switch
{
ResultType.Int => true,
ResultType.Float => true,
ResultType.Vector2 => true,
ResultType.Vector3 => true,
ResultType.Vector4 => true,
_ => false,
};
public readonly string TypeName => ResultType switch
{
ResultType.Bool => "bool",
ResultType.Int => "int",
ResultType.Float => "float",
ResultType.Vector2 => "float2",
ResultType.Vector3 => "float3",
ResultType.Vector4 => "float4",
ResultType.Float2x2 => "float2x2",
ResultType.Float3x3 => "float3x3",
ResultType.Float4x4 => "float4x4",
ResultType.Sampler => "SamplerState",
ResultType.Texture2D => "Texture2D",
ResultType.TextureCube => "TextureCube",
ResultType.Gradient => "Gradient",
_ => throw new Exception( $"Unsupported ResultType `{ResultType}`" )
};
public bool Constant { get; set; }
public bool ShouldPreview { get; set; }
public bool IsMetaDataResult { get; set; } = false;
/// <summary>
/// Generic-Ish metadata related to this NodeResult.
/// </summary>
internal Dictionary<string, object> Metadata { get; private set; }
public NodeResult( ResultType resultType, string code, bool constant = false, Dictionary<string, object> metadata = null )
{
ResultType = resultType;
Code = code;
Constant = constant;
IsMetaDataResult = false;
if ( metadata == null )
{
Metadata = new();
}
else
{
Metadata = metadata;
}
Components = ResultType switch
{
ResultType.Bool => 1,
ResultType.Int => 1,
ResultType.Float => 1,
ResultType.Vector2 => 2,
ResultType.Vector3 => 3,
ResultType.Vector4 => 4,
ResultType.VoidFunction => 0,
_ => 0
};
}
public static NodeResult Error( params string[] errors ) => new() { Errors = errors };
public static NodeResult Warning( params string[] warnings ) => new() { Warnings = warnings };
public static NodeResult MissingInput( string name ) => Error( $"Missing required input '{name}'." );
public static NodeResult IncorrectInputType( string name, ResultType correctResultType ) => Error( $"Input '{name}' must be of ResultType '{correctResultType}'" );
public void SetPreviewID( int previewid ) { PreviewID = previewid; }
public void SetVoidLocalTargetID( string voidLocalTargetID ) { VoidLocalTargetID = voidLocalTargetID; }
#region Metdata
internal T GetMetadata<T>( string metaName, bool ignoreException = false )
{
if ( Metadata.TryGetValue( metaName, out var actualData ) )
{
if ( typeof( T ) == actualData.GetType() )
{
return (T)actualData;
}
else
{
throw new InvalidCastException( $"Generic type of `{typeof( T )}` is not of metadata actual data type `{actualData.GetType()}`" );
}
}
if ( !ignoreException )
{
throw new Exception( $"Unable to get metadata with name `{metaName}`" );
}
return default( T );
}
internal bool TryGetMetaData<T>( string metaName, out T data )
{
data = default;
if ( Metadata.TryGetValue( metaName, out var actualData ) )
{
if ( typeof( T ) == actualData.GetType() )
{
data = (T)actualData;
return true;
}
else
{
return false;
//throw new InvalidCastException( $"Generic type of `{typeof( T )}` is not of metadata actual data type `{actualData.GetType()}`" );
}
}
return false;
}
internal void AddMetadataEntry( string metaName, object actualData )
{
if ( !Metadata.ContainsKey( metaName ) )
{
Metadata.Add( metaName, actualData );
}
else
{
throw new Exception( "Metadata entry already exists!" );
}
}
#endregion Metdata
/// <summary>
/// "Cast" this result to different float types
/// </summary>
public string Cast( int components, float defaultValue = 0.0f )
{
if ( components > 4 )
{
throw new Exception( $"There is no float type with a component count of `{components}`" );
}
if ( !CanCast )
{
throw new Exception( $"ResultType `{ResultType}` cannot be cast." );
}
if ( ResultType == ResultType.Int )
{
if ( Components == components )
{
return $"{Code}";
}
return $"float{components}( {string.Join( ", ", Enumerable.Repeat( Code, components ) )} )";
}
if ( Components == components )
{
return Code;
}
if ( Components > components )
{
return $"{Code}.{"xyzw"[..components]}";
}
else if ( Components == 1 )
{
return $"float{components}( {string.Join( ", ", Enumerable.Repeat( Code, components ) )} )";
}
else
{
if ( !string.IsNullOrWhiteSpace( Code ) )
return $"float{components}( {Code}, {string.Join( ", ", Enumerable.Repeat( $"{defaultValue}", components - Components ) )} )";
return $"float{components}( {string.Join( ", ", Enumerable.Repeat( $"{defaultValue}", components ) )} )";
}
}
public readonly bool IsFloatTypeResult()
{
return ResultType switch
{
ResultType.Float => true,
ResultType.Vector2 => true,
ResultType.Vector3 => true,
ResultType.Vector4 => true,
_ => false,
};
}
public readonly bool IsMatrixResult()
{
return ResultType switch
{
ResultType.Float2x2 => true,
ResultType.Float3x3 => true,
ResultType.Float4x4 => true,
_ => false,
};
}
public readonly bool IsTextureResult()
{
return ResultType switch
{
ResultType.Texture2D => true,
ResultType.TextureCube => true,
_ => false,
};
}
public override readonly string ToString()
{
return Code;
}
}