1247 lines
40 KiB
C#
1247 lines
40 KiB
C#
// Amplify Shader Editor - Visual Shader Editing Tool
|
|
// Copyright (c) Amplify Creations, Lda <info@amplify.pt>
|
|
|
|
//#define ADD_SHADER_FUNCTION_HEADERS
|
|
|
|
using UnityEngine;
|
|
using UnityEditor;
|
|
using System.Collections.Generic;
|
|
using System;
|
|
namespace AmplifyShaderEditor
|
|
{
|
|
[Serializable]
|
|
[NodeAttributes( "Function Node", "Functions", "Function Node", KeyCode.None, false, 0, int.MaxValue, typeof( AmplifyShaderFunction ) )]
|
|
public class FunctionNode : ParentNode
|
|
{
|
|
[SerializeField]
|
|
private AmplifyShaderFunction m_function;
|
|
|
|
[SerializeField]
|
|
private ParentGraph m_functionGraph;
|
|
|
|
[SerializeField]
|
|
private int m_functionGraphId = -1;
|
|
|
|
[SerializeField]
|
|
private List<FunctionInput> m_allFunctionInputs;
|
|
private Dictionary<int, FunctionInput> m_allFunctionInputsDict = new Dictionary<int, FunctionInput>();
|
|
|
|
[SerializeField]
|
|
private List<FunctionOutput> m_allFunctionOutputs;
|
|
private Dictionary<int, FunctionOutput> m_allFunctionOutputsDict = new Dictionary<int, FunctionOutput>();
|
|
|
|
[SerializeField]
|
|
private List<FunctionSwitch> m_allFunctionSwitches;
|
|
private Dictionary<int, FunctionSwitch> m_allFunctionSwitchesDict = new Dictionary<int, FunctionSwitch>();
|
|
|
|
[SerializeField]
|
|
private ReordenatorNode m_reordenator;
|
|
|
|
[SerializeField]
|
|
private string m_filename;
|
|
|
|
[SerializeField]
|
|
private string m_headerTitle = string.Empty;
|
|
|
|
[SerializeField]
|
|
private int m_orderIndex;
|
|
|
|
[SerializeField]
|
|
private string m_functionCheckSum;
|
|
|
|
[SerializeField]
|
|
private string m_functionGUID = string.Empty;
|
|
|
|
//[SerializeField]
|
|
//private List<string> m_includes = new List<string>();
|
|
|
|
//[SerializeField]
|
|
//private List<string> m_pragmas = new List<string>();
|
|
|
|
[SerializeField]
|
|
private List<AdditionalDirectiveContainer> m_directives = new List<AdditionalDirectiveContainer>();
|
|
|
|
private bool m_parametersFoldout = true;
|
|
[SerializeField]
|
|
private ParentGraph m_outsideGraph = null;
|
|
|
|
[SerializeField]
|
|
private FunctionOutput m_mainPreviewNode;
|
|
|
|
bool m_portsChanged = false;
|
|
//[SerializeField]
|
|
bool m_initialGraphDraw = false;
|
|
|
|
private bool m_refreshIdsRequired = false;
|
|
|
|
public string[] ReadOptionsHelper = new string[] { };
|
|
|
|
private bool m_lateRefresh = false;
|
|
|
|
private Dictionary<int, bool> m_duplicatesBuffer = new Dictionary<int, bool>();
|
|
string LastLine( string text )
|
|
{
|
|
string[] lines = text.Replace( "\r", "" ).Split( '\n' );
|
|
return lines[ lines.Length - 1 ];
|
|
}
|
|
|
|
public void CommonInit( AmplifyShaderFunction function, int uniqueId )
|
|
{
|
|
SetBaseUniqueId( uniqueId );
|
|
|
|
if( function == null )
|
|
return;
|
|
|
|
m_refreshIdsRequired = UIUtils.IsLoading && ( UIUtils.CurrentShaderVersion() < 14004 );
|
|
|
|
m_function = function;
|
|
|
|
if( Function.FunctionName.Length > 1 )
|
|
{
|
|
SetTitleText( GraphContextMenu.AddSpacesToSentence( Function.FunctionName ) );
|
|
}
|
|
else
|
|
{
|
|
SetTitleText( Function.FunctionName );
|
|
}
|
|
m_tooltipText = Function.Description;
|
|
m_hasTooltipLink = false;
|
|
if( m_functionGraph == null )
|
|
{
|
|
//m_functionGraph = new ParentGraph();
|
|
m_functionGraph = CreateInstance<ParentGraph>();
|
|
m_functionGraph.Init();
|
|
m_functionGraph.ParentWindow = ContainerGraph.ParentWindow;
|
|
}
|
|
|
|
if( string.IsNullOrEmpty( m_functionGUID ) )
|
|
{
|
|
m_functionGUID = AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath( m_function ) );
|
|
}
|
|
|
|
m_functionGraphId = Mathf.Max( m_functionGraphId, ContainerGraph.ParentWindow.GraphCount );
|
|
ContainerGraph.ParentWindow.GraphCount = m_functionGraphId + 1;
|
|
m_functionGraph.SetGraphId( m_functionGraphId );
|
|
|
|
ParentGraph cachedGraph = ContainerGraph.ParentWindow.CustomGraph;
|
|
ContainerGraph.ParentWindow.CustomGraph = m_functionGraph;
|
|
|
|
AmplifyShaderEditorWindow.LoadFromMeta( ref m_functionGraph, ContainerGraph.ParentWindow.ContextMenuInstance, Function.FunctionInfo );
|
|
//m_functionCheckSum = LastLine( m_function.FunctionInfo );
|
|
m_functionCheckSum = AssetDatabase.GetAssetDependencyHash( AssetDatabase.GetAssetPath( m_function ) ).ToString();
|
|
List<PropertyNode> propertyList = UIUtils.PropertyNodesList();
|
|
m_allFunctionInputs = UIUtils.FunctionInputList();
|
|
m_allFunctionOutputs = UIUtils.FunctionOutputList();
|
|
m_allFunctionSwitches = UIUtils.FunctionSwitchList();
|
|
|
|
ContainerGraph.ParentWindow.CustomGraph = cachedGraph;
|
|
|
|
m_allFunctionInputs.Sort( ( x, y ) => { return x.OrderIndex.CompareTo( y.OrderIndex ); } );
|
|
m_allFunctionOutputs.Sort( ( x, y ) => { return x.OrderIndex.CompareTo( y.OrderIndex ); } );
|
|
m_allFunctionSwitches.Sort( ( x, y ) => { return x.OrderIndex.CompareTo( y.OrderIndex ); } );
|
|
|
|
int inputCount = m_allFunctionInputs.Count;
|
|
for( int i = 0; i < inputCount; i++ )
|
|
{
|
|
if( m_refreshIdsRequired )
|
|
{
|
|
AddInputPort( m_allFunctionInputs[ i ].SelectedInputType, false, m_allFunctionInputs[ i ].InputName );
|
|
}
|
|
else
|
|
{
|
|
AddInputPort( m_allFunctionInputs[ i ].SelectedInputType, false, m_allFunctionInputs[ i ].InputName, -1, MasterNodePortCategory.Fragment, m_allFunctionInputs[ i ].UniqueId );
|
|
}
|
|
InputPortSwitchRestriction( m_inputPorts[ i ] );
|
|
|
|
if( !m_allFunctionInputs[ i ].InputPorts[ 0 ].IsConnected )
|
|
{
|
|
m_inputPorts[ i ].AutoDrawInternalData = true;
|
|
m_inputPorts[ i ].InternalData = m_allFunctionInputs[ i ].InputPorts[ 0 ].InternalData;
|
|
}
|
|
m_allFunctionInputs[ i ].Fnode = this;
|
|
}
|
|
|
|
int outputCount = m_allFunctionOutputs.Count;
|
|
FunctionOutput first = null;
|
|
for( int i = 0; i < outputCount; i++ )
|
|
{
|
|
if( i == 0 )
|
|
first = m_allFunctionOutputs[ i ];
|
|
|
|
if( m_allFunctionOutputs[ i ].PreviewNode )
|
|
{
|
|
m_mainPreviewNode = m_allFunctionOutputs[ i ];
|
|
}
|
|
|
|
if( m_refreshIdsRequired )
|
|
{
|
|
AddOutputPort( m_allFunctionOutputs[ i ].AutoOutputType, m_allFunctionOutputs[ i ].OutputName );
|
|
}
|
|
else
|
|
{
|
|
AddOutputPort( m_allFunctionOutputs[ i ].AutoOutputType, m_allFunctionOutputs[ i ].OutputName, m_allFunctionOutputs[ i ].UniqueId );
|
|
}
|
|
OutputPortSwitchRestriction( m_outputPorts[ i ] );
|
|
}
|
|
|
|
// make sure to hide the ports properly
|
|
CheckPortVisibility();
|
|
|
|
if( m_mainPreviewNode == null )
|
|
m_mainPreviewNode = first;
|
|
|
|
//create reordenator to main graph
|
|
bool inside = false;
|
|
if( ContainerGraph.ParentWindow.CustomGraph != null )
|
|
inside = true;
|
|
|
|
if( /*hasConnectedProperties*/propertyList.Count > 0 )
|
|
{
|
|
m_reordenator = ScriptableObject.CreateInstance<ReordenatorNode>();
|
|
m_reordenator.Init( "_" + Function.FunctionName, Function.FunctionName, propertyList, false );
|
|
m_reordenator.OrderIndex = m_orderIndex;
|
|
m_reordenator.HeaderTitle = Function.FunctionName;
|
|
m_reordenator.IsInside = inside;
|
|
}
|
|
|
|
if( m_reordenator != null )
|
|
{
|
|
cachedGraph = ContainerGraph.ParentWindow.CustomGraph;
|
|
ContainerGraph.ParentWindow.CustomGraph = null;
|
|
UIUtils.RegisterPropertyNode( m_reordenator );
|
|
ContainerGraph.ParentWindow.CustomGraph = cachedGraph;
|
|
|
|
if( inside )
|
|
{
|
|
UIUtils.RegisterPropertyNode( m_reordenator );
|
|
}
|
|
}
|
|
|
|
UIUtils.RegisterFunctionNode( this );
|
|
|
|
m_previewShaderGUID = "aca70c900c50c004e8ef0b47c4fac4d4";
|
|
m_useInternalPortData = false;
|
|
m_selectedLocation = function.PreviewPosition;
|
|
UIUtils.CurrentWindow.OutsideGraph.OnLODMasterNodesAddedEvent += OnLODMasterNodesAddedEvent;
|
|
}
|
|
|
|
public InputPort GetInput( FunctionInput input )
|
|
{
|
|
int index = m_allFunctionInputs.FindIndex( ( x ) => { return x.Equals( input ); } );
|
|
if( index >= 0 )
|
|
return InputPorts[ index ];
|
|
else
|
|
return null;
|
|
}
|
|
|
|
private void OnLODMasterNodesAddedEvent( int lod )
|
|
{
|
|
AddShaderFunctionDirectivesInternal( lod );
|
|
}
|
|
|
|
public void SetPreviewInput( InputPort input )
|
|
{
|
|
if( !HasPreviewShader || !m_initialized )
|
|
return;
|
|
|
|
if( input.IsConnected && input.InputNodeHasPreview( ContainerGraph ) )
|
|
{
|
|
input.SetPreviewInputTexture( ContainerGraph );
|
|
}
|
|
else
|
|
{
|
|
input.SetPreviewInputValue( ContainerGraph );
|
|
}
|
|
}
|
|
|
|
public override bool RecursivePreviewUpdate( Dictionary<string, bool> duplicatesDict = null )
|
|
{
|
|
if( duplicatesDict == null )
|
|
{
|
|
duplicatesDict = ContainerGraph.ParentWindow.VisitedChanged;
|
|
}
|
|
|
|
if( m_allFunctionOutputs == null || m_allFunctionOutputs.Count == 0 )
|
|
return false;
|
|
|
|
for( int i = 0; i < m_allFunctionOutputs.Count; i++ )
|
|
{
|
|
ParentNode outNode = m_allFunctionOutputs[ i ];
|
|
if( outNode != null )
|
|
{
|
|
if( !duplicatesDict.ContainsKey( outNode.OutputId ) )
|
|
{
|
|
bool result = outNode.RecursivePreviewUpdate();
|
|
if( result )
|
|
PreviewIsDirty = true;
|
|
}
|
|
else if( duplicatesDict[ outNode.OutputId ] )
|
|
{
|
|
PreviewIsDirty = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool needsUpdate = PreviewIsDirty;
|
|
RenderNodePreview();
|
|
if( !duplicatesDict.ContainsKey( OutputId ) )
|
|
duplicatesDict.Add( OutputId, needsUpdate );
|
|
return needsUpdate;
|
|
}
|
|
|
|
public override void RenderNodePreview()
|
|
{
|
|
if( m_outputPorts == null )
|
|
return;
|
|
|
|
if( !PreviewIsDirty && !m_continuousPreviewRefresh )
|
|
return;
|
|
|
|
// this is in the wrong place??
|
|
if( m_drawPreviewAsSphere != m_mainPreviewNode.SpherePreview )
|
|
{
|
|
m_drawPreviewAsSphere = m_mainPreviewNode.SpherePreview;
|
|
OnNodeChange();
|
|
}
|
|
|
|
int count = m_outputPorts.Count;
|
|
for( int i = 0; i < count; i++ )
|
|
{
|
|
m_outputPorts[ i ].OutputPreviewTexture = m_allFunctionOutputs[ i ].PreviewTexture;
|
|
}
|
|
|
|
if( PreviewIsDirty )
|
|
FinishPreviewRender = true;
|
|
|
|
PreviewIsDirty = false;
|
|
}
|
|
|
|
public override RenderTexture PreviewTexture
|
|
{
|
|
get
|
|
{
|
|
if( m_mainPreviewNode != null )
|
|
return m_mainPreviewNode.PreviewTexture;
|
|
else
|
|
return base.PreviewTexture;
|
|
}
|
|
}
|
|
|
|
private void AddShaderFunctionDirectivesInternal( int lod )
|
|
{
|
|
List<TemplateMultiPassMasterNode> nodes = ContainerGraph.ParentWindow.OutsideGraph.GetMultiPassMasterNodes( lod );
|
|
int count = nodes.Count;
|
|
for( int i = 0; i < count; i++ )
|
|
{
|
|
nodes[ i ].PassModule.AdditionalDirectives.AddShaderFunctionItems( OutputId, Function.AdditionalDirectives.DirectivesList );
|
|
}
|
|
}
|
|
|
|
public override void RefreshExternalReferences()
|
|
{
|
|
base.RefreshExternalReferences();
|
|
if( Function == null )
|
|
return;
|
|
|
|
//Debug.Log( "RefreshExternalReferences " + m_function.FunctionName + " " + UIUtils.CurrentWindow.IsShaderFunctionWindow );
|
|
|
|
Function.UpdateDirectivesList();
|
|
|
|
MasterNode masterNode = UIUtils.CurrentWindow.OutsideGraph.CurrentMasterNode;
|
|
StandardSurfaceOutputNode surface = masterNode as StandardSurfaceOutputNode;
|
|
|
|
|
|
|
|
if( surface != null )
|
|
{
|
|
//for( int i = 0; i < Function.AdditionalIncludes.IncludeList.Count; i++ )
|
|
//{
|
|
// //ContainerGraph.ParentWindow.OutsideGraph.CurrentStandardSurface.AdditionalIncludes.OutsideList.Add( Function.AdditionalIncludes.IncludeList[ i ] );
|
|
// ContainerGraph.ParentWindow.OutsideGraph.CurrentStandardSurface.AdditionalDirectives.AddShaderFunctionItem( AdditionalLineType.Include, Function.AdditionalIncludes.IncludeList[ i ] );
|
|
// m_includes.Add( Function.AdditionalIncludes.IncludeList[ i ] );
|
|
//}
|
|
|
|
//for( int i = 0; i < Function.AdditionalPragmas.PragmaList.Count; i++ )
|
|
//{
|
|
// //ContainerGraph.ParentWindow.OutsideGraph.CurrentStandardSurface.AdditionalPragmas.OutsideList.Add( Function.AdditionalPragmas.PragmaList[ i ] );
|
|
// ContainerGraph.ParentWindow.OutsideGraph.CurrentStandardSurface.AdditionalDirectives.AddShaderFunctionItem(AdditionalLineType.Pragma, Function.AdditionalPragmas.PragmaList[ i ] );
|
|
// m_pragmas.Add( Function.AdditionalPragmas.PragmaList[ i ] );
|
|
//}
|
|
surface.AdditionalDirectives.AddShaderFunctionItems( OutputId, Function.AdditionalDirectives.DirectivesList );
|
|
}
|
|
else
|
|
{
|
|
if( ContainerGraph.ParentWindow.OutsideGraph.MultiPassMasterNodes.Count > 0 )
|
|
{
|
|
for( int lod = -1; lod < ContainerGraph.ParentWindow.OutsideGraph.LodMultiPassMasternodes.Count; lod++ )
|
|
{
|
|
AddShaderFunctionDirectivesInternal( lod );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Assuring that we're not editing a Shader Function, as directives setup is not needed there
|
|
if( !UIUtils.CurrentWindow.IsShaderFunctionWindow )
|
|
{
|
|
// This function is nested inside a shader function itself and this method
|
|
// was called before the main output node was created.
|
|
// This is possible since all nodes RefreshExternalReferences(...) are called at the end
|
|
// of a LoadFromMeta
|
|
// Need to delay this setup to after all nodes are loaded to then setup the directives
|
|
m_lateRefresh = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
}
|
|
m_directives.AddRange( Function.AdditionalDirectives.DirectivesList );
|
|
|
|
if( m_refreshIdsRequired )
|
|
{
|
|
m_refreshIdsRequired = false;
|
|
int inputCount = m_inputPorts.Count;
|
|
for( int i = 0; i < inputCount; i++ )
|
|
{
|
|
m_inputPorts[ i ].ChangePortId( m_allFunctionInputs[ i ].UniqueId );
|
|
}
|
|
|
|
int outputCount = m_outputPorts.Count;
|
|
for( int i = 0; i < outputCount; i++ )
|
|
{
|
|
m_outputPorts[ i ].ChangePortId( m_allFunctionOutputs[ i ].UniqueId );
|
|
}
|
|
}
|
|
|
|
if( ContainerGraph.ParentWindow.CurrentGraph != m_functionGraph )
|
|
ContainerGraph.ParentWindow.CurrentGraph.InstancePropertyCount += m_functionGraph.InstancePropertyCount;
|
|
|
|
ParentGraph cachedGraph = ContainerGraph.ParentWindow.CustomGraph;
|
|
ContainerGraph.ParentWindow.CustomGraph = m_functionGraph;
|
|
|
|
if( ReadOptionsHelper.Length > 2 )
|
|
{
|
|
for( int i = 1; i < ReadOptionsHelper.Length; i += 2 )
|
|
{
|
|
int optionId = Convert.ToInt32( ReadOptionsHelper[ i ] );
|
|
int optionValue = Convert.ToInt32( ReadOptionsHelper[ i + 1 ] );
|
|
for( int j = 0; j < m_allFunctionSwitches.Count; j++ )
|
|
{
|
|
if( m_allFunctionSwitches[ j ].UniqueId == optionId )
|
|
{
|
|
m_allFunctionSwitches[ j ].SetCurrentSelectedInput( optionValue, m_allFunctionSwitches[ j ].GetCurrentSelectedInput() );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ContainerGraph.ParentWindow.CustomGraph = cachedGraph;
|
|
|
|
m_portsChanged = true;
|
|
}
|
|
|
|
void InputPortSwitchRestriction( WirePort port )
|
|
{
|
|
switch( port.DataType )
|
|
{
|
|
case WirePortDataType.OBJECT:
|
|
break;
|
|
case WirePortDataType.FLOAT:
|
|
case WirePortDataType.FLOAT2:
|
|
case WirePortDataType.FLOAT3:
|
|
case WirePortDataType.FLOAT4:
|
|
case WirePortDataType.COLOR:
|
|
case WirePortDataType.INT:
|
|
{
|
|
port.CreatePortRestrictions( WirePortDataType.FLOAT, WirePortDataType.FLOAT2, WirePortDataType.FLOAT3, WirePortDataType.FLOAT4, WirePortDataType.COLOR, WirePortDataType.INT, WirePortDataType.OBJECT );
|
|
}
|
|
break;
|
|
case WirePortDataType.FLOAT3x3:
|
|
case WirePortDataType.FLOAT4x4:
|
|
{
|
|
port.CreatePortRestrictions( WirePortDataType.FLOAT3x3, WirePortDataType.FLOAT4x4, WirePortDataType.OBJECT );
|
|
}
|
|
break;
|
|
case WirePortDataType.SAMPLER1D:
|
|
case WirePortDataType.SAMPLER2D:
|
|
case WirePortDataType.SAMPLER3D:
|
|
case WirePortDataType.SAMPLERCUBE:
|
|
case WirePortDataType.SAMPLER2DARRAY:
|
|
{
|
|
port.CreatePortRestrictions( WirePortDataType.SAMPLER1D, WirePortDataType.SAMPLER2D, WirePortDataType.SAMPLER3D, WirePortDataType.SAMPLERCUBE, WirePortDataType.SAMPLER2DARRAY, WirePortDataType.OBJECT );
|
|
}
|
|
break;
|
|
case WirePortDataType.SAMPLERSTATE:
|
|
{
|
|
port.CreatePortRestrictions( WirePortDataType.SAMPLERSTATE );
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void OutputPortSwitchRestriction( WirePort port )
|
|
{
|
|
switch( port.DataType )
|
|
{
|
|
case WirePortDataType.OBJECT:
|
|
break;
|
|
case WirePortDataType.FLOAT:
|
|
case WirePortDataType.FLOAT2:
|
|
case WirePortDataType.FLOAT3:
|
|
case WirePortDataType.FLOAT4:
|
|
case WirePortDataType.COLOR:
|
|
case WirePortDataType.INT:
|
|
case WirePortDataType.FLOAT3x3:
|
|
case WirePortDataType.FLOAT4x4:
|
|
{
|
|
port.AddPortForbiddenTypes( WirePortDataType.SAMPLER1D, WirePortDataType.SAMPLER2D, WirePortDataType.SAMPLER3D, WirePortDataType.SAMPLERCUBE, WirePortDataType.SAMPLER2DARRAY );
|
|
}
|
|
break;
|
|
case WirePortDataType.SAMPLER1D:
|
|
case WirePortDataType.SAMPLER2D:
|
|
case WirePortDataType.SAMPLER3D:
|
|
case WirePortDataType.SAMPLERCUBE:
|
|
case WirePortDataType.SAMPLER2DARRAY:
|
|
{
|
|
port.CreatePortRestrictions( WirePortDataType.SAMPLER1D, WirePortDataType.SAMPLER2D, WirePortDataType.SAMPLER3D, WirePortDataType.SAMPLERCUBE, WirePortDataType.SAMPLER2DARRAY, WirePortDataType.OBJECT );
|
|
}
|
|
break;
|
|
case WirePortDataType.SAMPLERSTATE:
|
|
{
|
|
port.CreatePortRestrictions( WirePortDataType.SAMPLERSTATE );
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
public override void PropagateNodeData( NodeData nodeData, ref MasterNodeDataCollector dataCollector )
|
|
{
|
|
ParentGraph cachedGraph = ContainerGraph.ParentWindow.CustomGraph;
|
|
m_outsideGraph = cachedGraph;
|
|
ContainerGraph.ParentWindow.CustomGraph = m_functionGraph;
|
|
|
|
for( int i = 0; i < m_allFunctionOutputs.Count; i++ )
|
|
{
|
|
m_allFunctionOutputs[ i ].PropagateNodeData( nodeData, ref dataCollector );
|
|
}
|
|
|
|
ContainerGraph.ParentWindow.CustomGraph = cachedGraph;
|
|
|
|
base.PropagateNodeData( nodeData, ref dataCollector );
|
|
}
|
|
|
|
protected override void OnUniqueIDAssigned()
|
|
{
|
|
base.OnUniqueIDAssigned();
|
|
UIUtils.RegisterFunctionNode( this );
|
|
}
|
|
|
|
public override void SetupFromCastObject( UnityEngine.Object obj )
|
|
{
|
|
base.SetupFromCastObject( obj );
|
|
AmplifyShaderFunction function = obj as AmplifyShaderFunction;
|
|
CommonInit( function, UniqueId );
|
|
RefreshExternalReferences();
|
|
}
|
|
|
|
public override void OnInputPortConnected( int portId, int otherNodeId, int otherPortId, bool activateNode = true )
|
|
{
|
|
base.OnInputPortConnected( portId, otherNodeId, otherPortId, activateNode );
|
|
FunctionInput functionInput = m_refreshIdsRequired ? m_allFunctionInputs[ portId ] : GetFunctionInputByUniqueId( portId );
|
|
functionInput.PreviewIsDirty = true;
|
|
if( functionInput.AutoCast )
|
|
{
|
|
InputPort inputPort = m_refreshIdsRequired ? m_inputPorts[ portId ] : GetInputPortByUniqueId( portId );
|
|
inputPort.MatchPortToConnection();
|
|
|
|
ParentGraph cachedGraph = ContainerGraph.ParentWindow.CustomGraph;
|
|
ContainerGraph.ParentWindow.CustomGraph = m_functionGraph;
|
|
functionInput.ChangeOutputType( inputPort.DataType, false );
|
|
ContainerGraph.ParentWindow.CustomGraph = cachedGraph;
|
|
}
|
|
|
|
for( int i = 0; i < m_allFunctionOutputs.Count; i++ )
|
|
{
|
|
m_outputPorts[ i ].ChangeType( m_allFunctionOutputs[ i ].InputPorts[ 0 ].DataType, false );
|
|
}
|
|
}
|
|
|
|
public override void OnInputPortDisconnected( int portId )
|
|
{
|
|
base.OnInputPortDisconnected( portId );
|
|
|
|
FunctionInput functionInput = m_refreshIdsRequired ? m_allFunctionInputs[ portId ] : GetFunctionInputByUniqueId( portId );
|
|
functionInput.PreviewIsDirty = true;
|
|
}
|
|
|
|
public override void OnConnectedOutputNodeChanges( int inputPortId, int otherNodeId, int otherPortId, string name, WirePortDataType type )
|
|
{
|
|
base.OnConnectedOutputNodeChanges( inputPortId, otherNodeId, otherPortId, name, type );
|
|
FunctionInput functionInput = m_refreshIdsRequired ? m_allFunctionInputs[ inputPortId ] : GetFunctionInputByUniqueId( inputPortId );
|
|
functionInput.PreviewIsDirty = true;
|
|
if( functionInput.AutoCast )
|
|
{
|
|
InputPort inputPort = m_refreshIdsRequired ? m_inputPorts[ inputPortId ] : GetInputPortByUniqueId( inputPortId );
|
|
inputPort.MatchPortToConnection();
|
|
|
|
ParentGraph cachedGraph = ContainerGraph.ParentWindow.CustomGraph;
|
|
ContainerGraph.ParentWindow.CustomGraph = m_functionGraph;
|
|
functionInput.ChangeOutputType( inputPort.DataType, false );
|
|
ContainerGraph.ParentWindow.CustomGraph = cachedGraph;
|
|
}
|
|
|
|
for( int i = 0; i < m_allFunctionOutputs.Count; i++ )
|
|
{
|
|
m_outputPorts[ i ].ChangeType( m_allFunctionOutputs[ i ].InputPorts[ 0 ].DataType, false );
|
|
}
|
|
}
|
|
|
|
public override void DrawProperties()
|
|
{
|
|
base.DrawProperties();
|
|
|
|
if( Function == null )
|
|
return;
|
|
|
|
if( Function.Description.Length > 0 || m_allFunctionSwitches.Count > 0 )
|
|
NodeUtils.DrawPropertyGroup( ref m_parametersFoldout, "Parameters", DrawDescription );
|
|
|
|
bool drawInternalDataUI = false;
|
|
int inputCount = m_inputPorts.Count;
|
|
if( inputCount > 0 )
|
|
{
|
|
for( int i = 0; i < inputCount; i++ )
|
|
{
|
|
if( m_inputPorts[ i ].Available && m_inputPorts[ i ].ValidInternalData && !m_inputPorts[ i ].IsConnected && m_inputPorts[ i ].AutoDrawInternalData /*&& ( m_inputPorts[ i ].AutoDrawInternalData || ( m_autoDrawInternalPortData && m_useInternalPortData ) )*/ /*&& m_inputPorts[ i ].AutoDrawInternalData*/ )
|
|
{
|
|
drawInternalDataUI = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( drawInternalDataUI )
|
|
NodeUtils.DrawPropertyGroup( ref m_internalDataFoldout, Constants.InternalDataLabelStr, () =>
|
|
{
|
|
for( int i = 0; i < m_inputPorts.Count; i++ )
|
|
{
|
|
if( m_inputPorts[ i ].ValidInternalData && !m_inputPorts[ i ].IsConnected && m_inputPorts[ i ].Visible && m_inputPorts[ i ].AutoDrawInternalData )
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
m_inputPorts[ i ].ShowInternalData( this );
|
|
if( EditorGUI.EndChangeCheck() )
|
|
{
|
|
m_allFunctionInputs[ i ].PreviewIsDirty = true;
|
|
}
|
|
}
|
|
}
|
|
} );
|
|
}
|
|
|
|
private void DrawDescription()
|
|
{
|
|
if( Function.Description.Length > 0 )
|
|
EditorGUILayout.HelpBox( Function.Description, MessageType.Info );
|
|
|
|
ParentGraph cachedGraph = ContainerGraph.ParentWindow.CustomGraph;
|
|
ContainerGraph.ParentWindow.CustomGraph = m_functionGraph;
|
|
for( int i = 0; i < m_allFunctionSwitches.Count; i++ )
|
|
{
|
|
m_allFunctionSwitches[ i ].AsDrawn = false;
|
|
}
|
|
|
|
for( int i = 0; i < m_allFunctionSwitches.Count; i++ )
|
|
{
|
|
if( m_allFunctionSwitches[ i ].DrawOption( this ) )
|
|
{
|
|
m_portsChanged = true;
|
|
}
|
|
}
|
|
ContainerGraph.ParentWindow.CustomGraph = cachedGraph;
|
|
}
|
|
|
|
private void RemoveShaderFunctionDirectivesInternal( int lod )
|
|
{
|
|
List<TemplateMultiPassMasterNode> nodes = ContainerGraph.ParentWindow.OutsideGraph.GetMultiPassMasterNodes( lod );
|
|
int count = nodes.Count;
|
|
for( int i = 0; i < count; i++ )
|
|
{
|
|
nodes[ i ].PassModule.AdditionalDirectives.RemoveShaderFunctionItems( OutputId );
|
|
}
|
|
}
|
|
|
|
public override void Destroy()
|
|
{
|
|
m_mainPreviewNode = null;
|
|
base.Destroy();
|
|
|
|
m_duplicatesBuffer.Clear();
|
|
m_duplicatesBuffer = null;
|
|
|
|
if( m_functionGraph != null && ContainerGraph.ParentWindow.CurrentGraph != m_functionGraph )
|
|
ContainerGraph.ParentWindow.CurrentGraph.InstancePropertyCount -= m_functionGraph.InstancePropertyCount;
|
|
|
|
if( ContainerGraph.ParentWindow.OutsideGraph.CurrentStandardSurface != null )
|
|
{
|
|
//for( int i = 0; i < m_includes.Count; i++ )
|
|
//{
|
|
// //if( ContainerGraph.ParentWindow.OutsideGraph.CurrentStandardSurface.AdditionalIncludes.OutsideList.Contains( m_includes[ i ] ) )
|
|
// //{
|
|
// // ContainerGraph.ParentWindow.OutsideGraph.CurrentStandardSurface.AdditionalIncludes.OutsideList.Remove( m_includes[ i ] );
|
|
// //}
|
|
// ContainerGraph.ParentWindow.OutsideGraph.CurrentStandardSurface.AdditionalDirectives.RemoveShaderFunctionItem( AdditionalLineType.Include, m_includes[ i ] );
|
|
//}
|
|
|
|
//for( int i = 0; i < m_pragmas.Count; i++ )
|
|
//{
|
|
// //if( ContainerGraph.ParentWindow.OutsideGraph.CurrentStandardSurface.AdditionalPragmas.OutsideList.Contains( m_pragmas[ i ] ) )
|
|
// //{
|
|
// // ContainerGraph.ParentWindow.OutsideGraph.CurrentStandardSurface.AdditionalPragmas.OutsideList.Remove( m_pragmas[ i ] );
|
|
// //}
|
|
// ContainerGraph.ParentWindow.OutsideGraph.CurrentStandardSurface.AdditionalDirectives.RemoveShaderFunctionItem( AdditionalLineType.Pragma, m_pragmas[ i ] );
|
|
//}
|
|
ContainerGraph.ParentWindow.OutsideGraph.CurrentStandardSurface.AdditionalDirectives.RemoveShaderFunctionItems( OutputId/*, m_directives */);
|
|
}
|
|
else
|
|
{
|
|
if( ContainerGraph.ParentWindow.OutsideGraph.MultiPassMasterNodes.Count > 0 )
|
|
{
|
|
for( int lod = -1; lod < ContainerGraph.ParentWindow.OutsideGraph.LodMultiPassMasternodes.Count; lod++ )
|
|
{
|
|
RemoveShaderFunctionDirectivesInternal( lod );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cannot GameObject.Destroy(m_directives[i]) since we would be removing them from
|
|
// the shader function asset itself
|
|
|
|
m_directives.Clear();
|
|
m_directives = null;
|
|
|
|
if( m_reordenator != null )
|
|
{
|
|
ParentGraph cachedGraph = ContainerGraph.ParentWindow.CustomGraph;
|
|
ContainerGraph.ParentWindow.CustomGraph = null;
|
|
UIUtils.UnregisterPropertyNode( m_reordenator );
|
|
ContainerGraph.ParentWindow.CustomGraph = cachedGraph;
|
|
|
|
m_reordenator.Destroy();
|
|
m_reordenator = null;
|
|
}
|
|
|
|
UIUtils.UnregisterFunctionNode( this );
|
|
|
|
ParentGraph cachedGraph2 = ContainerGraph.ParentWindow.CustomGraph;
|
|
ContainerGraph.ParentWindow.CustomGraph = m_functionGraph;
|
|
|
|
if( m_allFunctionInputs != null )
|
|
m_allFunctionInputs.Clear();
|
|
m_allFunctionInputs = null;
|
|
|
|
if( m_allFunctionOutputs != null )
|
|
m_allFunctionOutputs.Clear();
|
|
m_allFunctionOutputs = null;
|
|
|
|
if( m_functionGraph != null )
|
|
m_functionGraph.SoftDestroy();
|
|
m_functionGraph = null;
|
|
|
|
ContainerGraph.ParentWindow.CustomGraph = cachedGraph2;
|
|
m_function = null;
|
|
|
|
m_allFunctionOutputsDict.Clear();
|
|
m_allFunctionOutputsDict = null;
|
|
|
|
m_allFunctionSwitchesDict.Clear();
|
|
m_allFunctionSwitchesDict = null;
|
|
|
|
m_allFunctionInputsDict.Clear();
|
|
m_allFunctionInputsDict = null;
|
|
|
|
UIUtils.CurrentWindow.OutsideGraph.OnLODMasterNodesAddedEvent -= OnLODMasterNodesAddedEvent;
|
|
}
|
|
|
|
public override void OnNodeLogicUpdate( DrawInfo drawInfo )
|
|
{
|
|
if( m_lateRefresh )
|
|
{
|
|
m_lateRefresh = false;
|
|
RefreshExternalReferences();
|
|
}
|
|
|
|
CheckForChangesRecursively();
|
|
|
|
base.OnNodeLogicUpdate( drawInfo );
|
|
ParentGraph cachedGraph = ContainerGraph.ParentWindow.CustomGraph;
|
|
ContainerGraph.ParentWindow.CustomGraph = m_functionGraph;
|
|
|
|
if( m_functionGraph != null )
|
|
{
|
|
int nodeCount = m_functionGraph.AllNodes.Count;
|
|
for( int i = 0; i < nodeCount; i++ )
|
|
{
|
|
m_functionGraph.AllNodes[ i ].OnNodeLogicUpdate( drawInfo );
|
|
}
|
|
|
|
//if( !string.IsNullOrEmpty( FunctionGraph.CurrentFunctionOutput.SubTitle ) )
|
|
{
|
|
SetAdditonalTitleText( FunctionGraph.CurrentFunctionOutput.SubTitle );
|
|
}
|
|
}
|
|
|
|
ContainerGraph.ParentWindow.CustomGraph = cachedGraph;
|
|
if( m_portsChanged )
|
|
{
|
|
m_portsChanged = false;
|
|
for( int i = 0; i < m_allFunctionOutputs.Count; i++ )
|
|
{
|
|
m_outputPorts[ i ].ChangeType( m_allFunctionOutputs[ i ].InputPorts[ 0 ].DataType, false );
|
|
}
|
|
|
|
CheckPortVisibility();
|
|
}
|
|
}
|
|
|
|
public override void Draw( DrawInfo drawInfo )
|
|
{
|
|
//CheckForChangesRecursively();
|
|
|
|
if( !m_initialGraphDraw && drawInfo.CurrentEventType == EventType.Repaint )
|
|
{
|
|
m_initialGraphDraw = true;
|
|
ParentGraph cachedGraph = ContainerGraph.ParentWindow.CustomGraph;
|
|
ContainerGraph.ParentWindow.CustomGraph = m_functionGraph;
|
|
if( m_functionGraph != null )
|
|
{
|
|
for( int i = 0; i < m_functionGraph.AllNodes.Count; i++ )
|
|
{
|
|
ParentNode node = m_functionGraph.AllNodes[ i ];
|
|
if( node != null )
|
|
{
|
|
node.OnNodeLayout( drawInfo );
|
|
}
|
|
}
|
|
}
|
|
ContainerGraph.ParentWindow.CustomGraph = cachedGraph;
|
|
}
|
|
|
|
base.Draw( drawInfo );
|
|
}
|
|
|
|
public bool CheckForChanges( bool forceCheck = false, bool forceChange = false )
|
|
{
|
|
if( ( ContainerGraph.ParentWindow.CheckFunctions || forceCheck || forceChange ) && m_function != null )
|
|
{
|
|
//string newCheckSum = LastLine( m_function.FunctionInfo );
|
|
string newCheckSum = AssetDatabase.GetAssetDependencyHash( AssetDatabase.GetAssetPath( m_function ) ).ToString();
|
|
if( !m_functionCheckSum.Equals( newCheckSum ) || forceChange )
|
|
{
|
|
m_functionCheckSum = newCheckSum;
|
|
ContainerGraph.OnDuplicateEvent += DuplicateMe;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool CheckForChangesRecursively()
|
|
{
|
|
if( m_functionGraph == null )
|
|
return false;
|
|
|
|
bool result = false;
|
|
for( int i = 0; i < m_functionGraph.FunctionNodes.NodesList.Count; i++ )
|
|
{
|
|
if( m_functionGraph.FunctionNodes.NodesList[ i ].CheckForChangesRecursively() )
|
|
result = true;
|
|
}
|
|
if( CheckForChanges( false, result ) )
|
|
result = true;
|
|
|
|
return result;
|
|
}
|
|
|
|
public void DuplicateMe()
|
|
{
|
|
bool previewOpen = m_showPreview;
|
|
|
|
string allOptions = m_allFunctionSwitches.Count.ToString();
|
|
for( int i = 0; i < m_allFunctionSwitches.Count; i++ )
|
|
{
|
|
allOptions += "," + m_allFunctionSwitches[ i ].UniqueId + "," + m_allFunctionSwitches[ i ].GetCurrentSelectedInput();
|
|
}
|
|
|
|
ReadOptionsHelper = allOptions.Split( ',' );
|
|
|
|
ParentGraph cachedGraph = ContainerGraph.ParentWindow.CustomGraph;
|
|
ContainerGraph.ParentWindow.CustomGraph = null;
|
|
MasterNode masterNode = ContainerGraph.ParentWindow.CurrentGraph.CurrentMasterNode;
|
|
if( masterNode != null )
|
|
masterNode.InvalidateMaterialPropertyCount();
|
|
|
|
ContainerGraph.ParentWindow.CustomGraph = cachedGraph;
|
|
|
|
ParentNode newNode = ContainerGraph.CreateNode( m_function, false, Vec2Position );
|
|
newNode.ShowPreview = previewOpen;
|
|
( newNode as FunctionNode ).ReadOptionsHelper = ReadOptionsHelper;
|
|
newNode.RefreshExternalReferences();
|
|
if( ( newNode as FunctionNode ).m_reordenator && m_reordenator )
|
|
( newNode as FunctionNode ).m_reordenator.OrderIndex = m_reordenator.OrderIndex;
|
|
|
|
for( int i = 0; i < m_outputPorts.Count; i++ )
|
|
{
|
|
if( m_outputPorts[ i ].IsConnected )
|
|
{
|
|
OutputPort newOutputPort = newNode.GetOutputPortByUniqueId( m_outputPorts[ i ].PortId );
|
|
if( newNode.OutputPorts != null && newOutputPort != null )
|
|
{
|
|
for( int j = m_outputPorts[ i ].ExternalReferences.Count - 1; j >= 0; j-- )
|
|
{
|
|
ContainerGraph.CreateConnection( m_outputPorts[ i ].ExternalReferences[ j ].NodeId, m_outputPorts[ i ].ExternalReferences[ j ].PortId, newOutputPort.NodeId, newOutputPort.PortId );
|
|
}
|
|
}
|
|
}
|
|
//else
|
|
//{
|
|
//if( newNode.OutputPorts != null && newNode.OutputPorts[ i ] != null )
|
|
//{
|
|
// ContainerGraph.DeleteConnection( false, newNode.UniqueId, newNode.OutputPorts[ i ].PortId, false, false, false );
|
|
//}
|
|
//}
|
|
}
|
|
|
|
for( int i = 0; i < m_inputPorts.Count; i++ )
|
|
{
|
|
if( m_inputPorts[ i ].IsConnected )
|
|
{
|
|
InputPort newInputPort = newNode.GetInputPortByUniqueId( m_inputPorts[ i ].PortId );
|
|
if( newNode.InputPorts != null && newInputPort != null )
|
|
{
|
|
ContainerGraph.CreateConnection( newInputPort.NodeId, newInputPort.PortId, m_inputPorts[ i ].ExternalReferences[ 0 ].NodeId, m_inputPorts[ i ].ExternalReferences[ 0 ].PortId );
|
|
}
|
|
}
|
|
}
|
|
|
|
ContainerGraph.OnDuplicateEvent -= DuplicateMe;
|
|
|
|
if( Selected )
|
|
{
|
|
ContainerGraph.DeselectNode( this );
|
|
ContainerGraph.SelectNode( newNode, true, false );
|
|
}
|
|
|
|
ContainerGraph.DestroyNode( this, false );
|
|
}
|
|
|
|
private FunctionOutput GetFunctionOutputByUniqueId( int uniqueId )
|
|
{
|
|
int listCount = m_allFunctionOutputs.Count;
|
|
if( m_allFunctionOutputsDict.Count != m_allFunctionOutputs.Count )
|
|
{
|
|
m_allFunctionOutputsDict.Clear();
|
|
for( int i = 0; i < listCount; i++ )
|
|
{
|
|
m_allFunctionOutputsDict.Add( m_allFunctionOutputs[ i ].UniqueId, m_allFunctionOutputs[ i ] );
|
|
}
|
|
}
|
|
|
|
if( m_allFunctionOutputsDict.ContainsKey( uniqueId ) )
|
|
return m_allFunctionOutputsDict[ uniqueId ];
|
|
|
|
return null;
|
|
}
|
|
|
|
private FunctionInput GetFunctionInputByUniqueId( int uniqueId )
|
|
{
|
|
int listCount = m_allFunctionInputs.Count;
|
|
if( m_allFunctionInputsDict.Count != m_allFunctionInputs.Count )
|
|
{
|
|
m_allFunctionInputsDict.Clear();
|
|
for( int i = 0; i < listCount; i++ )
|
|
{
|
|
m_allFunctionInputsDict.Add( m_allFunctionInputs[ i ].UniqueId, m_allFunctionInputs[ i ] );
|
|
}
|
|
}
|
|
|
|
if( m_allFunctionInputsDict.ContainsKey( uniqueId ) )
|
|
return m_allFunctionInputsDict[ uniqueId ];
|
|
|
|
return null;
|
|
}
|
|
|
|
public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar )
|
|
{
|
|
OutputPort outputPort = GetOutputPortByUniqueId( outputId );
|
|
FunctionOutput functionOutput = GetFunctionOutputByUniqueId( outputId );
|
|
|
|
if( outputPort.IsLocalValue( dataCollector.PortCategory ) )
|
|
return outputPort.LocalValue( dataCollector.PortCategory );
|
|
|
|
m_functionGraph.CurrentPrecision = ContainerGraph.ParentWindow.CurrentGraph.CurrentPrecision;
|
|
ParentGraph cachedGraph = ContainerGraph.ParentWindow.CustomGraph;
|
|
m_outsideGraph = cachedGraph;
|
|
ContainerGraph.ParentWindow.CustomGraph = m_functionGraph;
|
|
#if ADD_SHADER_FUNCTION_HEADERS
|
|
if( m_reordenator != null && m_reordenator.RecursiveCount() > 0 && m_reordenator.HasTitle )
|
|
{
|
|
dataCollector.AddToProperties( UniqueId, "[Header(" + m_reordenator.HeaderTitle.Replace( "-", " " ) + ")]", m_reordenator.OrderIndex );
|
|
}
|
|
#endif
|
|
string result = string.Empty;
|
|
for( int i = 0; i < m_allFunctionInputs.Count; i++ )
|
|
{
|
|
if( !m_allFunctionInputs[ i ].InputPorts[ 0 ].IsConnected || m_inputPorts[ i ].IsConnected )
|
|
m_allFunctionInputs[ i ].OnPortGeneration += FunctionNodeOnPortGeneration;
|
|
}
|
|
|
|
result += functionOutput.GenerateShaderForOutput( outputId, ref dataCollector, ignoreLocalvar );
|
|
|
|
for( int i = 0; i < m_allFunctionInputs.Count; i++ )
|
|
{
|
|
if( !m_allFunctionInputs[ i ].InputPorts[ 0 ].IsConnected || m_inputPorts[ i ].IsConnected )
|
|
m_allFunctionInputs[ i ].OnPortGeneration -= FunctionNodeOnPortGeneration;
|
|
}
|
|
|
|
ContainerGraph.ParentWindow.CustomGraph = cachedGraph;
|
|
|
|
if( outputPort.ConnectionCount > 1 )
|
|
RegisterLocalVariable( outputId, result, ref dataCollector );
|
|
else
|
|
outputPort.SetLocalValue( result, dataCollector.PortCategory );
|
|
|
|
return outputPort.LocalValue( dataCollector.PortCategory );
|
|
}
|
|
|
|
private string FunctionNodeOnPortGeneration( ref MasterNodeDataCollector dataCollector, int index, ParentGraph graph )
|
|
{
|
|
ParentGraph cachedGraph = ContainerGraph.ParentWindow.CustomGraph;
|
|
ContainerGraph.ParentWindow.CustomGraph = m_outsideGraph;
|
|
string result = m_inputPorts[ index ].GeneratePortInstructions( ref dataCollector );
|
|
ContainerGraph.ParentWindow.CustomGraph = cachedGraph;
|
|
return result;
|
|
}
|
|
|
|
public override void WriteToString( ref string nodeInfo, ref string connectionsInfo )
|
|
{
|
|
base.WriteToString( ref nodeInfo, ref connectionsInfo );
|
|
|
|
if( Function != null )
|
|
IOUtils.AddFieldValueToString( ref nodeInfo, m_function.name );
|
|
else
|
|
IOUtils.AddFieldValueToString( ref nodeInfo, m_filename );
|
|
IOUtils.AddFieldValueToString( ref nodeInfo, m_reordenator != null ? m_reordenator.RawOrderIndex : -1 );
|
|
IOUtils.AddFieldValueToString( ref nodeInfo, m_headerTitle );
|
|
IOUtils.AddFieldValueToString( ref nodeInfo, m_functionGraphId );
|
|
IOUtils.AddFieldValueToString( ref nodeInfo, AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath( m_function ) ) );
|
|
|
|
int functionSwitchCount = m_allFunctionSwitches != null ? m_allFunctionSwitches.Count : 0;
|
|
string allOptions = functionSwitchCount.ToString();
|
|
for( int i = 0; i < functionSwitchCount; i++ )
|
|
{
|
|
allOptions += "," + m_allFunctionSwitches[ i ].UniqueId + "," + m_allFunctionSwitches[ i ].GetCurrentSelectedInput();
|
|
}
|
|
IOUtils.AddFieldValueToString( ref nodeInfo, allOptions );
|
|
}
|
|
|
|
public override void ReadFromString( ref string[] nodeParams )
|
|
{
|
|
base.ReadFromString( ref nodeParams );
|
|
m_filename = GetCurrentParam( ref nodeParams );
|
|
m_orderIndex = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
|
|
m_headerTitle = GetCurrentParam( ref nodeParams );
|
|
|
|
if( UIUtils.CurrentShaderVersion() > 7203 )
|
|
{
|
|
m_functionGraphId = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
|
|
}
|
|
|
|
if( UIUtils.CurrentShaderVersion() > 13704 )
|
|
{
|
|
m_functionGUID = GetCurrentParam( ref nodeParams );
|
|
}
|
|
|
|
AmplifyShaderFunction loaded = AssetDatabase.LoadAssetAtPath<AmplifyShaderFunction>( AssetDatabase.GUIDToAssetPath( m_functionGUID ) );
|
|
if( loaded != null )
|
|
{
|
|
CommonInit( loaded, UniqueId );
|
|
}
|
|
else
|
|
{
|
|
string[] guids = AssetDatabase.FindAssets( "t:AmplifyShaderFunction " + m_filename );
|
|
if( guids.Length > 0 )
|
|
{
|
|
string sfGuid = null;
|
|
|
|
foreach( string guid in guids )
|
|
{
|
|
string assetPath = AssetDatabase.GUIDToAssetPath( guid );
|
|
string name = System.IO.Path.GetFileNameWithoutExtension( assetPath );
|
|
if( name.Equals( m_filename, StringComparison.OrdinalIgnoreCase ) )
|
|
{
|
|
sfGuid = guid;
|
|
break;
|
|
}
|
|
}
|
|
loaded = AssetDatabase.LoadAssetAtPath<AmplifyShaderFunction>( AssetDatabase.GUIDToAssetPath( sfGuid ) );
|
|
|
|
if( loaded != null )
|
|
{
|
|
CommonInit( loaded, UniqueId );
|
|
}
|
|
else
|
|
{
|
|
SetTitleText( "ERROR" );
|
|
UIUtils.ShowMessage( UniqueId, string.Format( "Error loading {0} shader function from project folder", m_filename ), MessageSeverity.Error );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetTitleText( "Missing Function" );
|
|
UIUtils.ShowMessage( UniqueId, string.Format( "Missing {0} shader function on project folder", m_filename ), MessageSeverity.Error );
|
|
}
|
|
}
|
|
if( UIUtils.CurrentShaderVersion() > 14203 )
|
|
{
|
|
ReadOptionsHelper = GetCurrentParam( ref nodeParams ).Split( ',' );
|
|
}
|
|
}
|
|
|
|
public override void ReadOutputDataFromString( ref string[] nodeParams )
|
|
{
|
|
if( Function == null )
|
|
return;
|
|
|
|
base.ReadOutputDataFromString( ref nodeParams );
|
|
|
|
ConfigureInputportsAfterRead();
|
|
}
|
|
|
|
public override void OnNodeDoubleClicked( Vector2 currentMousePos2D )
|
|
{
|
|
if( Function == null )
|
|
return;
|
|
|
|
ContainerGraph.DeSelectAll();
|
|
this.Selected = true;
|
|
|
|
ContainerGraph.ParentWindow.OnLeftMouseUp();
|
|
AmplifyShaderEditorWindow.LoadShaderFunctionToASE( Function, true );
|
|
this.Selected = false;
|
|
}
|
|
|
|
private void ConfigureInputportsAfterRead()
|
|
{
|
|
if( InputPorts != null )
|
|
{
|
|
int inputCount = InputPorts.Count;
|
|
for( int i = 0; i < inputCount; i++ )
|
|
{
|
|
InputPorts[ i ].ChangeProperties( m_allFunctionInputs[ i ].InputName, m_allFunctionInputs[ i ].SelectedInputType, false );
|
|
}
|
|
}
|
|
|
|
if( OutputPorts != null )
|
|
{
|
|
int outputCount = OutputPorts.Count;
|
|
for( int i = 0; i < outputCount; i++ )
|
|
{
|
|
OutputPorts[ i ].ChangeProperties( m_allFunctionOutputs[ i ].OutputName, m_allFunctionOutputs[ i ].AutoOutputType, false );
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CheckPortVisibility()
|
|
{
|
|
bool changes = false;
|
|
if( InputPorts != null )
|
|
{
|
|
for( int i = 0; i < m_allFunctionInputs.Count; i++ )
|
|
{
|
|
if( m_inputPorts[ i ].Visible != m_allFunctionInputs[ i ].IsConnected )
|
|
{
|
|
m_inputPorts[ i ].Visible = m_allFunctionInputs[ i ].IsConnected;
|
|
changes = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( changes )
|
|
m_sizeIsDirty = true;
|
|
}
|
|
|
|
public bool HasProperties { get { return m_reordenator != null; } }
|
|
|
|
public ParentGraph FunctionGraph
|
|
{
|
|
get { return m_functionGraph; }
|
|
set { m_functionGraph = value; }
|
|
}
|
|
|
|
public AmplifyShaderFunction Function
|
|
{
|
|
get { return m_function; }
|
|
set { m_function = value; }
|
|
}
|
|
|
|
public override void RecordObjectOnDestroy( string Id )
|
|
{
|
|
base.RecordObjectOnDestroy( Id );
|
|
if( m_reordenator != null )
|
|
m_reordenator.RecordObject( Id );
|
|
|
|
if( m_functionGraph != null )
|
|
{
|
|
Undo.RegisterCompleteObjectUndo( m_functionGraph, Id );
|
|
for( int i = 0; i < m_functionGraph.AllNodes.Count; i++ )
|
|
{
|
|
m_functionGraph.AllNodes[ i ].RecordObject( Id );
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void SetContainerGraph( ParentGraph newgraph )
|
|
{
|
|
base.SetContainerGraph( newgraph );
|
|
if( m_functionGraph == null )
|
|
return;
|
|
for( int i = 0; i < m_functionGraph.AllNodes.Count; i++ )
|
|
{
|
|
m_functionGraph.AllNodes[ i ].SetContainerGraph( m_functionGraph );
|
|
}
|
|
}
|
|
|
|
public override void OnMasterNodeReplaced( MasterNode newMasterNode )
|
|
{
|
|
base.OnMasterNodeReplaced( newMasterNode );
|
|
if( m_functionGraph == null )
|
|
return;
|
|
|
|
m_functionGraph.FireMasterNodeReplacedEvent( newMasterNode );
|
|
|
|
StandardSurfaceOutputNode surface = newMasterNode as StandardSurfaceOutputNode;
|
|
if( surface != null )
|
|
{
|
|
surface.AdditionalDirectives.AddShaderFunctionItems( OutputId, Function.AdditionalDirectives.DirectivesList );
|
|
}
|
|
else
|
|
{
|
|
if( ContainerGraph.ParentWindow.OutsideGraph.MultiPassMasterNodes.Count > 0 )
|
|
{
|
|
for( int lod = -1; lod < ContainerGraph.ParentWindow.OutsideGraph.LodMultiPassMasternodes.Count; lod++ )
|
|
{
|
|
AddShaderFunctionDirectivesInternal( lod );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|