Editor/ShaderGraphPlus/Nodes/PostProcessing/BorderNode.cs

namespace ShaderGraphPlus.Nodes;

/// <summary>
/// Adds a black border surrounding the edges of the screen.
/// </summary>
[Title( "Border" ), Category( "PostProcessing/Effects" ), Icon( "crop_square" )]
public class BorderNode : ShaderNodePlus
{
	[Hide]
	public static string Border => @"
float Border( float2 vUV , float flWarpAmount )
{
	float radius = min( flWarpAmount, 0.08f );
	radius = max( min( min( abs( radius * 2.0f ), abs( 1.0f ) ), abs( 1.0f ) ) , 1e-5 );
	float2 abs_uv = abs( vUV * 2.0f - 1.0f ) - float2( 1.0f, 1.0f ) + radius;
	float dist = length( max( float2( 0.0f, 0.0f ), abs_uv ) ) / radius;
	float square = smoothstep( 0.96f, 1.0f, dist );
	return clamp( 1.0f - square, 0.0f, 1.0f );
}
";

	[Input( typeof( Vector2 ) ), Title( "Coords" )]
	[Hide]
	public NodeInput ScreenUVInput { get; set; }

	[Input( typeof( float ) ), Title( "Warp Amount" )]
	[Hide]
	public NodeInput WarpAmountInput { get; set; }

	[InputDefault( nameof( WarpAmountInput ) )]
	[Title( "Warp Amount" )]
	[Sandbox.Range( 0f, 0.08f ), Sandbox.Step( 0.01f )]
	public float DefaultWarpAmount { get; set; } = 1.0f;

	[Output( typeof( float ) )]
	[Hide]
	public NodeResult.Func Result => ( GraphCompiler compiler ) =>
	{
		if ( compiler.Graph.Domain != ShaderDomain.PostProcess )
		{
			return NodeResult.Error( $"'{DisplayInfo.Name}' node is only ment to be used in the '{ShaderDomain.PostProcess}' domain." );
		}

		var coords = compiler.Result( ScreenUVInput );
		var warpamount = compiler.ResultOrDefault( WarpAmountInput, DefaultWarpAmount );

		string func = compiler.RegisterHLSLFunction( Border, "Border" );
		string funcCall = compiler.ResultHLSLFunction( func, $"{(coords.IsValid ? $"{coords.Cast( 2 )}" : "i.vPositionSs.xy / g_vRenderTargetSize")}, {warpamount}" );

		return new NodeResult( ResultType.Float, funcCall );
	};
}