mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-04-19 05:48:07 -04:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
348 lines
7.7 KiB
C#
348 lines
7.7 KiB
C#
|
|
using Editor.NodeEditor;
|
|
using Sandbox.Resources;
|
|
using System.Text;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace Editor.ShaderGraph;
|
|
|
|
public interface IErroringNode
|
|
{
|
|
List<string> GetErrors();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Final result
|
|
/// </summary>
|
|
[Title( "Result" ), Icon( "output" )]
|
|
public sealed class FunctionResult : BaseResult, IErroringNode
|
|
{
|
|
[Title( "Outputs" )]
|
|
public List<FunctionOutput> FunctionOutputs { get; set; }
|
|
|
|
[Hide]
|
|
private List<IPlugIn> InternalInputs = new();
|
|
|
|
[Hide]
|
|
public override IEnumerable<IPlugIn> Inputs => InternalInputs;
|
|
|
|
[Hide, JsonIgnore]
|
|
int _lastHashCode = 0;
|
|
|
|
[Hide, JsonIgnore]
|
|
public override Color PrimaryColor => Color.Lerp( Theme.Blue, Color.White, 0.25f );
|
|
|
|
public override void OnFrame()
|
|
{
|
|
var hashCode = 0;
|
|
int index = 1;
|
|
foreach ( var output in FunctionOutputs )
|
|
{
|
|
hashCode += output.GetHashCode() * index;
|
|
index++;
|
|
}
|
|
if ( hashCode != _lastHashCode )
|
|
{
|
|
_lastHashCode = hashCode;
|
|
|
|
CreateInputs();
|
|
Update();
|
|
}
|
|
}
|
|
|
|
public void CreateInputs()
|
|
{
|
|
var plugs = new List<IPlugIn>();
|
|
if ( FunctionOutputs == null )
|
|
{
|
|
InternalInputs = new();
|
|
}
|
|
else
|
|
{
|
|
foreach ( var output in FunctionOutputs.OrderBy( x => x.Priority ) )
|
|
{
|
|
var outputType = output.Type;
|
|
if ( outputType == typeof( ColorTextureGenerator ) )
|
|
{
|
|
outputType = typeof( Color );
|
|
}
|
|
if ( outputType is null ) continue;
|
|
var info = new PlugInfo()
|
|
{
|
|
Id = output.Id,
|
|
Name = output.Name,
|
|
Type = outputType,
|
|
DisplayInfo = new()
|
|
{
|
|
Name = output.Name,
|
|
Fullname = outputType.FullName
|
|
}
|
|
};
|
|
var oldPlug = InternalInputs.FirstOrDefault( x => x is BasePlugIn plugIn && plugIn.Info.Id == info.Id ) as BasePlugIn;
|
|
if ( oldPlug is not null )
|
|
{
|
|
oldPlug.Info.Name = info.Name;
|
|
oldPlug.Info.Type = info.Type;
|
|
oldPlug.Info.DisplayInfo = info.DisplayInfo;
|
|
plugs.Add( oldPlug );
|
|
}
|
|
else
|
|
{
|
|
var plug = new BasePlugIn( this, info, info.Type );
|
|
plugs.Add( plug );
|
|
}
|
|
}
|
|
InternalInputs = plugs;
|
|
}
|
|
}
|
|
|
|
public List<string> GetErrors()
|
|
{
|
|
var errors = new List<string>();
|
|
if ( FunctionOutputs == null || FunctionOutputs.Count == 0 )
|
|
{
|
|
errors.Add( "No outputs defined" );
|
|
}
|
|
else
|
|
{
|
|
Dictionary<string, int> namesSoFar = new();
|
|
foreach ( var output in FunctionOutputs )
|
|
{
|
|
if ( output.Name is null )
|
|
{
|
|
errors.Add( $"{output.TypeName} Output has no name" );
|
|
continue;
|
|
}
|
|
if ( !namesSoFar.ContainsKey( output.Name ) )
|
|
{
|
|
namesSoFar.Add( output.Name, 1 );
|
|
}
|
|
else
|
|
{
|
|
namesSoFar[output.Name]++;
|
|
}
|
|
if ( string.IsNullOrEmpty( output.Name ) )
|
|
{
|
|
errors.Add( $"{output.TypeName} Output has no name" );
|
|
}
|
|
if ( string.IsNullOrEmpty( output.TypeName ) )
|
|
{
|
|
errors.Add( $"Output '{output.Name}' has no type" );
|
|
}
|
|
}
|
|
foreach ( var name in namesSoFar )
|
|
{
|
|
if ( name.Value > 1 )
|
|
{
|
|
errors.Add( $"Output name '{name.Key}' is used {name.Value} times" );
|
|
}
|
|
}
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
public override NodeInput GetAlbedo()
|
|
{
|
|
var input = GetInputFromPreview( FunctionOutput.PreviewType.Albedo );
|
|
if ( input is not null )
|
|
{
|
|
return input.Value;
|
|
}
|
|
return default;
|
|
}
|
|
|
|
public override NodeInput GetEmission()
|
|
{
|
|
var input = GetInputFromPreview( FunctionOutput.PreviewType.Emission );
|
|
if ( input is not null )
|
|
{
|
|
return input.Value;
|
|
}
|
|
return default;
|
|
}
|
|
|
|
public override NodeInput GetOpacity()
|
|
{
|
|
var input = GetInputFromPreview( FunctionOutput.PreviewType.Opacity );
|
|
if ( input is not null )
|
|
{
|
|
return input.Value;
|
|
}
|
|
return default;
|
|
}
|
|
|
|
public override NodeInput GetNormal()
|
|
{
|
|
var input = GetInputFromPreview( FunctionOutput.PreviewType.Normal );
|
|
if ( input is not null )
|
|
{
|
|
return input.Value;
|
|
}
|
|
return default;
|
|
}
|
|
|
|
public override NodeInput GetRoughness()
|
|
{
|
|
var input = GetInputFromPreview( FunctionOutput.PreviewType.Roughness );
|
|
if ( input is not null )
|
|
{
|
|
return input.Value;
|
|
}
|
|
return default;
|
|
}
|
|
|
|
public override NodeInput GetMetalness()
|
|
{
|
|
var input = GetInputFromPreview( FunctionOutput.PreviewType.Metalness );
|
|
if ( input is not null )
|
|
{
|
|
return input.Value;
|
|
}
|
|
return default;
|
|
}
|
|
|
|
public override NodeInput GetAmbientOcclusion()
|
|
{
|
|
var input = GetInputFromPreview( FunctionOutput.PreviewType.AmbientOcclusion );
|
|
if ( input is not null )
|
|
{
|
|
return input.Value;
|
|
}
|
|
return default;
|
|
}
|
|
|
|
public override NodeInput GetPositionOffset()
|
|
{
|
|
var input = GetInputFromPreview( FunctionOutput.PreviewType.PositionOffset );
|
|
if ( input is not null )
|
|
{
|
|
return input.Value;
|
|
}
|
|
return default;
|
|
}
|
|
|
|
public override Color GetDefaultAlbedo()
|
|
{
|
|
return base.GetDefaultAlbedo();
|
|
}
|
|
|
|
public void AddMaterialOutputs( GraphCompiler compiler, StringBuilder sb, HashSet<string> visited )
|
|
{
|
|
if ( !visited.Contains( "Albedo" ) )
|
|
{
|
|
var albedoResult = GetAlbedoResult( compiler );
|
|
sb.AppendLine( $"m.Albedo = {albedoResult.Cast( 3 )};" );
|
|
}
|
|
if ( !visited.Contains( "Emission" ) )
|
|
{
|
|
var emissionResult = GetEmissionResult( compiler );
|
|
sb.AppendLine( $"m.Emission = {emissionResult.Cast( 3 )};" );
|
|
}
|
|
if ( !visited.Contains( "Opacity" ) )
|
|
{
|
|
var opacityResult = GetOpacityResult( compiler );
|
|
sb.AppendLine( $"m.Opacity = {opacityResult.Cast( 1 )};" );
|
|
}
|
|
if ( !visited.Contains( "Normal" ) )
|
|
{
|
|
var normalResult = GetNormalResult( compiler );
|
|
sb.AppendLine( $"m.Normal = {normalResult.Cast( 3 )};" );
|
|
}
|
|
if ( !visited.Contains( "Roughness" ) )
|
|
{
|
|
var roughnessResult = GetRoughnessResult( compiler );
|
|
sb.AppendLine( $"m.Roughness = {roughnessResult.Cast( 1 )};" );
|
|
}
|
|
if ( !visited.Contains( "Metalness" ) )
|
|
{
|
|
var metalnessResult = GetMetalnessResult( compiler );
|
|
sb.AppendLine( $"m.Metalness = {metalnessResult.Cast( 1 )};" );
|
|
}
|
|
if ( !visited.Contains( "AmbientOcclusion" ) )
|
|
{
|
|
var ambientOcclusionResult = GetAmbientOcclusionResult( compiler );
|
|
sb.AppendLine( $"m.AmbientOcclusion = {ambientOcclusionResult.Cast( 1 )};" );
|
|
}
|
|
}
|
|
|
|
private NodeInput? GetInputFromPreview( FunctionOutput.PreviewType previewType )
|
|
{
|
|
var albedoOutput = FunctionOutputs.FirstOrDefault( x => x.Preview == previewType );
|
|
if ( albedoOutput is not null )
|
|
{
|
|
var input = Inputs.FirstOrDefault( x => x is BasePlugIn plugIn && plugIn.Info.Id == albedoOutput.Id );
|
|
if ( input is BasePlugIn plugIn )
|
|
{
|
|
if ( plugIn.Info.ConnectedPlug is not null )
|
|
{
|
|
return new NodeInput
|
|
{
|
|
Identifier = plugIn.Info.ConnectedPlug.Node.Identifier,
|
|
Output = plugIn.Info.ConnectedPlug.Identifier
|
|
};
|
|
}
|
|
return plugIn.Info.GetInput( plugIn.Node );
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public class FunctionOutput
|
|
{
|
|
[Hide]
|
|
public Guid Id { get; } = Guid.NewGuid();
|
|
|
|
[KeyProperty]
|
|
public string Name { get; set; }
|
|
|
|
[Hide, JsonIgnore]
|
|
public Type Type
|
|
{
|
|
get
|
|
{
|
|
if ( string.IsNullOrEmpty( TypeName ) ) return null;
|
|
var typeName = TypeName;
|
|
if ( typeName == "float" ) typeName = typeof( float ).FullName;
|
|
if ( typeName == "int" ) typeName = typeof( int ).FullName;
|
|
if ( typeName == "bool" ) typeName = typeof( bool ).FullName;
|
|
var type = TypeLibrary.GetType( typeName ).TargetType;
|
|
return type;
|
|
}
|
|
}
|
|
|
|
[KeyProperty, Editor( "shadertype" ), JsonPropertyName( "Type" )]
|
|
public string TypeName { get; set; }
|
|
|
|
public PreviewType Preview { get; set; }
|
|
|
|
public int Priority { get; set; }
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return System.HashCode.Combine( Id, Name, TypeName, Priority );
|
|
}
|
|
|
|
public enum PreviewType
|
|
{
|
|
[Icon( "clear" )]
|
|
None,
|
|
[Icon( "palette" )]
|
|
Albedo,
|
|
[Icon( "brightness_5" )]
|
|
Emission,
|
|
[Icon( "opacity" )]
|
|
Opacity,
|
|
[Icon( "texture" )]
|
|
Normal,
|
|
[Icon( "terrain" )]
|
|
Roughness,
|
|
[Icon( "auto_awesome" )]
|
|
Metalness,
|
|
[Icon( "tonality" )]
|
|
AmbientOcclusion,
|
|
[Icon( "arrow_forward" )]
|
|
PositionOffset
|
|
}
|
|
}
|