2025-07-08 14:28:40 -04:00
// Amplify Shader Editor - Visual Shader Editing Tool
// Copyright (c) Amplify Creations, Lda <info@amplify.pt>
using UnityEngine ;
using UnityEditor ;
using System ;
using System.Linq ;
using System.Collections.Generic ;
namespace AmplifyShaderEditor
{
[Serializable]
public class ParentGraph : ScriptableObject , ISerializationCallbackReceiver
{
private const int MasterNodeLODIncrement = 100 ;
private const int MaxLodAmount = 9 ;
public enum NodeLOD
{
LOD0 ,
LOD1 ,
LOD2 ,
LOD3 ,
LOD4 ,
LOD5
}
[SerializeField]
private bool m_samplingThroughMacros = false ;
private NodeLOD m_lodLevel = NodeLOD . LOD0 ;
private GUIStyle nodeStyleOff ;
private GUIStyle nodeStyleOn ;
private GUIStyle nodeTitle ;
private GUIStyle commentaryBackground ;
public delegate void LODMasterNodesAdded ( int lod ) ;
public event LODMasterNodesAdded OnLODMasterNodesAddedEvent ;
public delegate void EmptyGraphDetected ( ParentGraph graph ) ;
public event EmptyGraphDetected OnEmptyGraphDetectedEvt ;
public delegate void NodeEvent ( ParentNode node ) ;
public event NodeEvent OnNodeEvent = null ;
public event NodeEvent OnNodeRemovedEvent ;
public delegate void DuplicateEvent ( ) ;
public event DuplicateEvent OnDuplicateEvent ;
public event MasterNode . OnMaterialUpdated OnMaterialUpdatedEvent ;
public event MasterNode . OnMaterialUpdated OnShaderUpdatedEvent ;
private bool m_afterDeserializeFlag = true ;
private bool m_lateOptionsRefresh = false ;
private bool m_foundDuplicates = false ;
//[SerializeField]
private AmplifyShaderEditorWindow m_parentWindow = null ;
[SerializeField]
private int m_validNodeId ;
[SerializeField]
private List < ParentNode > m_nodes = new List < ParentNode > ( ) ;
// Sampler Nodes registry
[SerializeField]
private UsageListSamplerNodes m_samplerNodes = new UsageListSamplerNodes ( ) ;
[SerializeField]
private UsageListFloatIntNodes m_floatNodes = new UsageListFloatIntNodes ( ) ;
[SerializeField]
private UsageListTexturePropertyNodes m_texturePropertyNodes = new UsageListTexturePropertyNodes ( ) ;
[SerializeField]
private UsageListTextureArrayNodes m_textureArrayNodes = new UsageListTextureArrayNodes ( ) ;
[SerializeField]
private UsageListPropertyNodes m_propertyNodes = new UsageListPropertyNodes ( ) ;
[SerializeField]
private UsageListPropertyNodes m_rawPropertyNodes = new UsageListPropertyNodes ( ) ;
[SerializeField]
private UsageListScreenColorNodes m_screenColorNodes = new UsageListScreenColorNodes ( ) ;
[SerializeField]
private UsageListRegisterLocalVarNodes m_localVarNodes = new UsageListRegisterLocalVarNodes ( ) ;
[SerializeField]
private UsageListGlobalArrayNodes m_globalArrayNodes = new UsageListGlobalArrayNodes ( ) ;
[SerializeField]
private UsageListFunctionInputNodes m_functionInputNodes = new UsageListFunctionInputNodes ( ) ;
[SerializeField]
private UsageListFunctionNodes m_functionNodes = new UsageListFunctionNodes ( ) ;
[SerializeField]
private UsageListFunctionOutputNodes m_functionOutputNodes = new UsageListFunctionOutputNodes ( ) ;
[SerializeField]
private UsageListFunctionSwitchNodes m_functionSwitchNodes = new UsageListFunctionSwitchNodes ( ) ;
[SerializeField]
private UsageListFunctionSwitchCopyNodes m_functionSwitchCopyNodes = new UsageListFunctionSwitchCopyNodes ( ) ;
[SerializeField]
private UsageListTemplateMultiPassMasterNodes m_multiPassMasterNodes = new UsageListTemplateMultiPassMasterNodes ( ) ;
[SerializeField]
private List < UsageListTemplateMultiPassMasterNodes > m_lodMultiPassMasterNodes ;
[SerializeField]
private UsageListCustomExpressionsOnFunctionMode m_customExpressionsOnFunctionMode = new UsageListCustomExpressionsOnFunctionMode ( ) ;
[SerializeField]
private UsageListStaticSwitchNodes m_staticSwitchNodes = new UsageListStaticSwitchNodes ( ) ;
2026-03-14 03:13:10 -04:00
[SerializeField]
private UsageListToggleSwitchNodes m_toggleSwitchNodes = new UsageListToggleSwitchNodes ( ) ;
2025-07-08 14:28:40 -04:00
[SerializeField]
private int m_masterNodeId = Constants . INVALID_NODE_ID ;
[SerializeField]
private bool m_isDirty ;
[SerializeField]
private bool m_saveIsDirty = false ;
[SerializeField]
private int m_nodeClicked ;
[SerializeField]
private int m_loadedShaderVersion ;
[SerializeField]
private int m_instancePropertyCount = 0 ;
[SerializeField]
private int m_virtualTextureCount = 0 ;
[SerializeField]
private int m_graphId = 0 ;
[SerializeField]
private PrecisionType m_currentPrecision = PrecisionType . Float ;
[SerializeField]
private NodeAvailability m_currentCanvasMode = NodeAvailability . SurfaceShader ;
[SerializeField]
private TemplateSRPType m_currentSRPType = TemplateSRPType . BiRP ;
//private List<ParentNode> m_visibleNodes = new List<ParentNode>();
private List < ParentNode > m_nodePreviewList = new List < ParentNode > ( ) ;
private Dictionary < int , ParentNode > m_nodesDict = new Dictionary < int , ParentNode > ( ) ;
[NonSerialized]
private List < ParentNode > m_selectedNodes = new List < ParentNode > ( ) ;
[NonSerialized]
private List < ParentNode > m_markedForDeletion = new List < ParentNode > ( ) ;
[SerializeField]
private List < WireReference > m_highlightedWires = new List < WireReference > ( ) ;
private System . Type m_masterNodeDefaultType ;
[SerializeField]
private List < PropertyNode > m_internalTemplateNodesList = new List < PropertyNode > ( ) ;
private Dictionary < int , PropertyNode > m_internalTemplateNodesDict = new Dictionary < int , PropertyNode > ( ) ;
private NodeGrid m_nodeGrid ;
private bool m_markedToDeSelect = false ;
private int m_markToSelect = - 1 ;
private bool m_markToReOrder = false ;
private bool m_hasUnConnectedNodes = false ;
private bool m_checkSelectedWireHighlights = false ;
// Bezier info
[SerializeField]
private List < WireBezierReference > m_bezierReferences ;
private const int MaxBezierReferences = 50 ;
private int m_wireBezierCount = 0 ;
protected int m_normalDependentCount = 0 ;
private bool m_forceCategoryRefresh = false ;
[SerializeField]
private bool m_forceRepositionCheck = false ;
private bool m_isLoading = false ;
private bool m_isDuplicating = false ;
private bool m_changedLightingModel = false ;
public void ResetEvents ( )
{
OnNodeEvent = null ;
OnMaterialUpdatedEvent = null ;
OnShaderUpdatedEvent = null ;
OnEmptyGraphDetectedEvt = null ;
OnNodeRemovedEvent = null ;
}
public void Init ( )
{
UndoUtils . RegisterUndoRedoCallback ( OnUndoRedoCallback ) ;
m_normalDependentCount = 0 ;
m_nodes = new List < ParentNode > ( ) ;
m_samplerNodes = new UsageListSamplerNodes ( ) ;
m_samplerNodes . ContainerGraph = this ;
m_samplerNodes . ReorderOnChange = true ;
m_floatNodes = new UsageListFloatIntNodes ( ) ;
m_floatNodes . ContainerGraph = this ;
m_texturePropertyNodes = new UsageListTexturePropertyNodes ( ) ;
m_texturePropertyNodes . ContainerGraph = this ;
m_textureArrayNodes = new UsageListTextureArrayNodes ( ) ;
m_textureArrayNodes . ContainerGraph = this ;
m_textureArrayNodes . ReorderOnChange = true ;
m_propertyNodes = new UsageListPropertyNodes ( ) ;
m_propertyNodes . ContainerGraph = this ;
m_rawPropertyNodes = new UsageListPropertyNodes ( ) ;
m_rawPropertyNodes . ContainerGraph = this ;
m_customExpressionsOnFunctionMode = new UsageListCustomExpressionsOnFunctionMode ( ) ;
m_customExpressionsOnFunctionMode . ContainerGraph = this ;
m_staticSwitchNodes = new UsageListStaticSwitchNodes ( ) ;
m_staticSwitchNodes . ContainerGraph = this ;
m_staticSwitchNodes . ReorderOnChange = true ;
2026-03-14 03:13:10 -04:00
m_toggleSwitchNodes = new UsageListToggleSwitchNodes ( ) ;
m_toggleSwitchNodes . ContainerGraph = this ;
m_toggleSwitchNodes . ReorderOnChange = true ;
2025-07-08 14:28:40 -04:00
m_screenColorNodes = new UsageListScreenColorNodes ( ) ;
m_screenColorNodes . ContainerGraph = this ;
m_screenColorNodes . ReorderOnChange = true ;
m_localVarNodes = new UsageListRegisterLocalVarNodes ( ) ;
m_localVarNodes . ContainerGraph = this ;
m_localVarNodes . ReorderOnChange = true ;
m_globalArrayNodes = new UsageListGlobalArrayNodes ( ) ;
m_globalArrayNodes . ContainerGraph = this ;
m_functionInputNodes = new UsageListFunctionInputNodes ( ) ;
m_functionInputNodes . ContainerGraph = this ;
m_functionNodes = new UsageListFunctionNodes ( ) ;
m_functionNodes . ContainerGraph = this ;
m_functionOutputNodes = new UsageListFunctionOutputNodes ( ) ;
m_functionOutputNodes . ContainerGraph = this ;
m_functionSwitchNodes = new UsageListFunctionSwitchNodes ( ) ;
m_functionSwitchNodes . ContainerGraph = this ;
m_functionSwitchCopyNodes = new UsageListFunctionSwitchCopyNodes ( ) ;
m_functionSwitchCopyNodes . ContainerGraph = this ;
m_multiPassMasterNodes = new UsageListTemplateMultiPassMasterNodes ( ) ;
m_multiPassMasterNodes . ContainerGraph = this ;
m_lodMultiPassMasterNodes = new List < UsageListTemplateMultiPassMasterNodes > ( MaxLodAmount ) ;
for ( int i = 0 ; i < MaxLodAmount ; i + + )
{
m_lodMultiPassMasterNodes . Add ( new UsageListTemplateMultiPassMasterNodes ( ) ) ;
}
m_selectedNodes = new List < ParentNode > ( ) ;
m_markedForDeletion = new List < ParentNode > ( ) ;
m_highlightedWires = new List < WireReference > ( ) ;
m_validNodeId = 0 ;
IsDirty = false ;
SaveIsDirty = false ;
m_masterNodeDefaultType = typeof ( StandardSurfaceOutputNode ) ;
m_bezierReferences = new List < WireBezierReference > ( MaxBezierReferences ) ;
for ( int i = 0 ; i < MaxBezierReferences ; i + + )
{
m_bezierReferences . Add ( new WireBezierReference ( ) ) ;
}
}
public void ActivatePreviews ( bool value )
{
int count = m_nodes . Count ;
if ( value )
{
for ( int i = 0 ; i < count ; i + + )
{
m_nodes [ i ] . PreviewIsDirty = true ;
}
}
else
{
//for( int i = 0 ; i < count ; i++ )
//{
// m_nodes[ i ].DisablePreview();
//}
}
}
private void OnUndoRedoCallback ( )
{
DeSelectAll ( ) ;
}
private void OnEnable ( )
{
hideFlags = HideFlags . HideAndDontSave ;
m_nodeGrid = new NodeGrid ( ) ;
m_internalTemplateNodesDict = new Dictionary < int , PropertyNode > ( ) ;
m_nodesDict = new Dictionary < int , ParentNode > ( ) ;
nodeStyleOff = UIUtils . GetCustomStyle ( CustomStyle . NodeWindowOff ) ;
nodeStyleOn = UIUtils . GetCustomStyle ( CustomStyle . NodeWindowOn ) ;
nodeTitle = UIUtils . GetCustomStyle ( CustomStyle . NodeHeader ) ;
commentaryBackground = UIUtils . GetCustomStyle ( CustomStyle . CommentaryBackground ) ;
}
public void UpdateRegisters ( )
{
m_samplerNodes . UpdateNodeArr ( ) ;
m_propertyNodes . UpdateNodeArr ( ) ;
m_rawPropertyNodes . UpdateNodeArr ( ) ;
m_customExpressionsOnFunctionMode . UpdateNodeArr ( ) ;
m_staticSwitchNodes . UpdateNodeArr ( ) ;
2026-03-14 03:13:10 -04:00
m_toggleSwitchNodes . UpdateNodeArr ( ) ;
2025-07-08 14:28:40 -04:00
m_functionInputNodes . UpdateNodeArr ( ) ;
m_functionNodes . UpdateNodeArr ( ) ;
m_functionOutputNodes . UpdateNodeArr ( ) ;
m_functionSwitchNodes . UpdateNodeArr ( ) ;
m_functionSwitchCopyNodes . UpdateNodeArr ( ) ;
m_multiPassMasterNodes . UpdateNodeArr ( ) ;
for ( int i = 0 ; i < m_lodMultiPassMasterNodes . Count ; i + + )
{
m_lodMultiPassMasterNodes [ i ] . UpdateNodeArr ( ) ;
}
m_texturePropertyNodes . UpdateNodeArr ( ) ;
m_textureArrayNodes . UpdateNodeArr ( ) ;
m_screenColorNodes . UpdateNodeArr ( ) ;
m_localVarNodes . UpdateNodeArr ( ) ;
m_globalArrayNodes . UpdateNodeArr ( ) ;
}
public int GetValidId ( )
{
return m_validNodeId + + ;
}
void UpdateIdFromNode ( ParentNode node )
{
if ( node . UniqueId > = m_validNodeId )
{
m_validNodeId = node . UniqueId + 1 ;
}
}
public void ResetNodeConnStatus ( )
{
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
if ( m_nodes [ i ] . ConnStatus = = NodeConnectionStatus . Connected )
{
m_nodes [ i ] . ConnStatus = NodeConnectionStatus . Not_Connected ;
}
}
}
public void CleanUnusedNodes ( )
{
List < ParentNode > unusedNodes = new List < ParentNode > ( ) ;
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
if ( m_nodes [ i ] . ConnStatus = = NodeConnectionStatus . Not_Connected )
{
unusedNodes . Add ( m_nodes [ i ] ) ;
}
}
for ( int i = 0 ; i < unusedNodes . Count ; i + + )
{
DestroyNode ( unusedNodes [ i ] ) ;
}
unusedNodes . Clear ( ) ;
unusedNodes = null ;
IsDirty = true ;
}
// Destroy all nodes excluding Master Node
public void ClearGraph ( )
{
List < ParentNode > list = new List < ParentNode > ( ) ;
int count = m_nodes . Count ;
for ( int i = 0 ; i < count ; i + + )
{
if ( m_nodes [ i ] . UniqueId ! = m_masterNodeId )
{
list . Add ( m_nodes [ i ] ) ;
}
}
while ( list . Count > 0 )
{
DestroyNode ( list [ 0 ] ) ;
list . RemoveAt ( 0 ) ;
}
}
public void CleanNodes ( )
{
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
if ( m_nodes [ i ] ! = null )
2026-03-14 03:13:10 -04:00
{
2025-07-08 14:28:40 -04:00
UndoUtils . ClearUndo ( m_nodes [ i ] ) ;
m_nodes [ i ] . Destroy ( ) ;
GameObject . DestroyImmediate ( m_nodes [ i ] ) ;
}
}
ClearInternalTemplateNodes ( ) ;
m_masterNodeId = Constants . INVALID_NODE_ID ;
m_validNodeId = 0 ;
m_instancePropertyCount = 0 ;
m_virtualTextureCount = 0 ;
m_nodesDict . Clear ( ) ;
m_nodes . Clear ( ) ;
m_samplerNodes . Clear ( ) ;
m_propertyNodes . Clear ( ) ;
m_rawPropertyNodes . Clear ( ) ;
m_customExpressionsOnFunctionMode . Clear ( ) ;
m_staticSwitchNodes . Clear ( ) ;
2026-03-14 03:13:10 -04:00
m_toggleSwitchNodes . Clear ( ) ;
2025-07-08 14:28:40 -04:00
m_functionInputNodes . Clear ( ) ;
m_functionNodes . Clear ( ) ;
m_functionOutputNodes . Clear ( ) ;
m_functionSwitchNodes . Clear ( ) ;
m_functionSwitchCopyNodes . Clear ( ) ;
m_multiPassMasterNodes . Clear ( ) ;
for ( int i = 0 ; i < m_lodMultiPassMasterNodes . Count ; i + + )
{
m_lodMultiPassMasterNodes [ i ] . Clear ( ) ;
}
2026-03-14 03:13:10 -04:00
2025-07-08 14:28:40 -04:00
m_texturePropertyNodes . Clear ( ) ;
m_textureArrayNodes . Clear ( ) ;
m_screenColorNodes . Clear ( ) ;
m_localVarNodes . Clear ( ) ;
m_globalArrayNodes . Clear ( ) ;
m_selectedNodes . Clear ( ) ;
m_markedForDeletion . Clear ( ) ;
}
public void ResetHighlightedWires ( )
{
for ( int i = 0 ; i < m_highlightedWires . Count ; i + + )
{
m_highlightedWires [ i ] . WireStatus = WireStatus . Default ;
}
m_highlightedWires . Clear ( ) ;
}
public void HighlightWiresStartingNode ( ParentNode node )
{
for ( int outputIdx = 0 ; outputIdx < node . OutputPorts . Count ; outputIdx + + )
{
for ( int extIdx = 0 ; extIdx < node . OutputPorts [ outputIdx ] . ExternalReferences . Count ; extIdx + + )
{
WireReference wireRef = node . OutputPorts [ outputIdx ] . ExternalReferences [ extIdx ] ;
ParentNode nextNode = GetNode ( wireRef . NodeId ) ;
if ( nextNode & & nextNode . ConnStatus = = NodeConnectionStatus . Connected )
{
InputPort port = nextNode . GetInputPortByUniqueId ( wireRef . PortId ) ;
if ( port . ExternalReferences . Count = = 0 | | port . ExternalReferences [ 0 ] . WireStatus = = WireStatus . Highlighted )
{
// if even one wire is already highlighted then this tells us that this node was already been analysed
return ;
}
port . ExternalReferences [ 0 ] . WireStatus = WireStatus . Highlighted ;
m_highlightedWires . Add ( port . ExternalReferences [ 0 ] ) ;
HighlightWiresStartingNode ( nextNode ) ;
}
}
}
RegisterLocalVarNode regNode = node as RegisterLocalVarNode ;
if ( ( object ) regNode ! = null )
{
int count = regNode . NodeReferences . Count ;
for ( int i = 0 ; i < count ; i + + )
{
HighlightWiresStartingNode ( regNode . NodeReferences [ i ] ) ;
}
}
}
void PropagateHighlightDeselection ( ParentNode node , int portId = - 1 )
{
if ( portId > - 1 )
{
InputPort port = node . GetInputPortByUniqueId ( portId ) ;
port . ExternalReferences [ 0 ] . WireStatus = WireStatus . Default ;
}
if ( node . Selected )
return ;
for ( int i = 0 ; i < node . InputPorts . Count ; i + + )
{
if ( node . InputPorts [ i ] . ExternalReferences . Count > 0 & & node . InputPorts [ i ] . ExternalReferences [ 0 ] . WireStatus = = WireStatus . Highlighted )
{
2026-03-14 03:13:10 -04:00
// even though node is deselected, it receives wire highlight from a previous one
2025-07-08 14:28:40 -04:00
return ;
}
}
for ( int outputIdx = 0 ; outputIdx < node . OutputPorts . Count ; outputIdx + + )
{
for ( int extIdx = 0 ; extIdx < node . OutputPorts [ outputIdx ] . ExternalReferences . Count ; extIdx + + )
{
WireReference wireRef = node . OutputPorts [ outputIdx ] . ExternalReferences [ extIdx ] ;
ParentNode nextNode = GetNode ( wireRef . NodeId ) ;
PropagateHighlightDeselection ( nextNode , wireRef . PortId ) ;
}
}
RegisterLocalVarNode regNode = node as RegisterLocalVarNode ;
if ( ( object ) regNode ! = null )
{
int count = regNode . NodeReferences . Count ;
for ( int i = 0 ; i < count ; i + + )
{
PropagateHighlightDeselection ( regNode . NodeReferences [ i ] , - 1 ) ;
}
}
}
public void ResetNodesData ( )
{
int count = m_nodes . Count ;
for ( int i = 0 ; i < count ; i + + )
{
m_nodes [ i ] . ResetNodeData ( ) ;
}
}
public void FullCleanUndoStack ( )
{
UndoUtils . ClearUndo ( this ) ;
int count = m_nodes . Count ;
for ( int i = 0 ; i < count ; i + + )
{
if ( m_nodes [ i ] ! = null )
{
UndoUtils . ClearUndo ( m_nodes [ i ] ) ;
}
}
}
public void FullRegisterOnUndoStack ( )
{
UndoUtils . RegisterCompleteObjectUndo ( this , Constants . UndoRegisterFullGrapId ) ;
int count = m_nodes . Count ;
for ( int i = 0 ; i < count ; i + + )
{
if ( m_nodes [ i ] ! = null )
{
UndoUtils . RegisterCompleteObjectUndo ( m_nodes [ i ] , Constants . UndoRegisterFullGrapId ) ;
}
}
}
public void CheckPropertiesAutoRegister ( ref MasterNodeDataCollector dataCollector )
{
List < PropertyNode > propertyNodesList = m_rawPropertyNodes . NodesList ;
int propertyCount = propertyNodesList . Count ;
for ( int i = 0 ; i < propertyCount ; i + + )
{
propertyNodesList [ i ] . CheckIfAutoRegister ( ref dataCollector ) ;
}
propertyNodesList = null ;
List < GlobalArrayNode > globalArrayNodeList = m_globalArrayNodes . NodesList ;
int globalArrayCount = globalArrayNodeList . Count ;
for ( int i = 0 ; i < globalArrayCount ; i + + )
{
globalArrayNodeList [ i ] . CheckIfAutoRegister ( ref dataCollector ) ;
}
globalArrayNodeList = null ;
//List<PropertyNode> propertyNodesList = m_propertyNodes.NodesList;
//int propertyCount = propertyNodesList.Count;
//for( int i = 0; i < propertyCount; i++ )
//{
// propertyNodesList[ i ].CheckIfAutoRegister( ref dataCollector );
//}
//propertyNodesList = null;
//List<ScreenColorNode> screenColorNodes = m_screenColorNodes.NodesList;
//int screenColorNodesCount = screenColorNodes.Count;
//for( int i = 0; i < screenColorNodesCount; i++ )
//{
// screenColorNodes[ i ].CheckIfAutoRegister( ref dataCollector );
//}
//screenColorNodes = null;
}
public void SoftDestroy ( )
{
OnNodeRemovedEvent = null ;
m_masterNodeId = Constants . INVALID_NODE_ID ;
m_validNodeId = 0 ;
2026-03-14 03:13:10 -04:00
2025-07-08 14:28:40 -04:00
m_nodeGrid . Destroy ( ) ;
//m_nodeGrid = null;
ClearInternalTemplateNodes ( ) ;
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
if ( m_nodes [ i ] ! = null )
{
m_nodes [ i ] . Destroy ( ) ;
GameObject . DestroyImmediate ( m_nodes [ i ] ) ;
}
}
m_instancePropertyCount = 0 ;
m_nodes . Clear ( ) ;
//m_nodes = null;
m_nodesDict . Clear ( ) ;
//m_nodesDict = null;
m_samplerNodes . Clear ( ) ;
//m_samplerNodes = null;
m_propertyNodes . Clear ( ) ;
m_rawPropertyNodes . Clear ( ) ;
//m_propertyNodes = null;
m_customExpressionsOnFunctionMode . Clear ( ) ;
m_staticSwitchNodes . Clear ( ) ;
2026-03-14 03:13:10 -04:00
m_toggleSwitchNodes . Clear ( ) ;
2025-07-08 14:28:40 -04:00
m_functionInputNodes . Clear ( ) ;
//m_functionInputNodes = null;
m_functionNodes . Clear ( ) ;
//m_functionNodes = null;
m_functionOutputNodes . Clear ( ) ;
//m_functionOutputNodes = null;
m_functionSwitchNodes . Clear ( ) ;
//m_functionSwitchNodes = null;
m_functionSwitchCopyNodes . Clear ( ) ;
//m_functionSwitchCopyNodes = null;
m_texturePropertyNodes . Clear ( ) ;
//m_texturePropertyNodes = null;
m_textureArrayNodes . Clear ( ) ;
//m_textureArrayNodes = null;
m_screenColorNodes . Clear ( ) ;
//m_screenColorNodes = null;
m_localVarNodes . Clear ( ) ;
//m_localVarNodes = null;
m_globalArrayNodes . Clear ( ) ;
m_selectedNodes . Clear ( ) ;
//m_selectedNodes = null;
m_markedForDeletion . Clear ( ) ;
//m_markedForDeletion = null;
m_nodePreviewList . Clear ( ) ;
//m_nodePreviewList = null;
IsDirty = true ;
OnNodeEvent = null ;
OnDuplicateEvent = null ;
//m_currentShaderFunction = null;
OnMaterialUpdatedEvent = null ;
OnShaderUpdatedEvent = null ;
OnEmptyGraphDetectedEvt = null ;
nodeStyleOff = null ;
nodeStyleOn = null ;
nodeTitle = null ;
commentaryBackground = null ;
OnLODMasterNodesAddedEvent = null ;
}
public void Destroy ( )
{
UndoUtils . UnregisterUndoRedoCallback ( OnUndoRedoCallback ) ;
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
if ( m_nodes [ i ] ! = null )
{
UndoUtils . ClearUndo ( m_nodes [ i ] ) ;
m_nodes [ i ] . Destroy ( ) ;
GameObject . DestroyImmediate ( m_nodes [ i ] ) ;
}
}
//Must be before m_propertyNodes.Destroy();
ClearInternalTemplateNodes ( ) ;
m_internalTemplateNodesDict = null ;
m_internalTemplateNodesList = null ;
OnNodeRemovedEvent = null ;
m_masterNodeId = Constants . INVALID_NODE_ID ;
m_validNodeId = 0 ;
m_instancePropertyCount = 0 ;
m_nodeGrid . Destroy ( ) ;
m_nodeGrid = null ;
m_nodes . Clear ( ) ;
m_nodes = null ;
m_samplerNodes . Destroy ( ) ;
m_samplerNodes = null ;
m_propertyNodes . Destroy ( ) ;
m_propertyNodes = null ;
m_rawPropertyNodes . Destroy ( ) ;
m_rawPropertyNodes = null ;
m_customExpressionsOnFunctionMode . Destroy ( ) ;
m_customExpressionsOnFunctionMode = null ;
m_staticSwitchNodes . Destroy ( ) ;
m_staticSwitchNodes = null ;
2026-03-14 03:13:10 -04:00
m_toggleSwitchNodes . Destroy ( ) ;
m_toggleSwitchNodes = null ;
2025-07-08 14:28:40 -04:00
m_functionInputNodes . Destroy ( ) ;
m_functionInputNodes = null ;
m_functionNodes . Destroy ( ) ;
m_functionNodes = null ;
m_functionOutputNodes . Destroy ( ) ;
m_functionOutputNodes = null ;
m_functionSwitchNodes . Destroy ( ) ;
m_functionSwitchNodes = null ;
m_functionSwitchCopyNodes . Destroy ( ) ;
m_functionSwitchCopyNodes = null ;
m_multiPassMasterNodes . Destroy ( ) ;
m_multiPassMasterNodes = null ;
for ( int i = 0 ; i < m_lodMultiPassMasterNodes . Count ; i + + )
{
m_lodMultiPassMasterNodes [ i ] . Destroy ( ) ;
m_lodMultiPassMasterNodes [ i ] = null ;
}
m_lodMultiPassMasterNodes . Clear ( ) ;
m_lodMultiPassMasterNodes = null ;
m_texturePropertyNodes . Destroy ( ) ;
m_texturePropertyNodes = null ;
m_textureArrayNodes . Destroy ( ) ;
m_textureArrayNodes = null ;
m_screenColorNodes . Destroy ( ) ;
m_screenColorNodes = null ;
m_localVarNodes . Destroy ( ) ;
m_localVarNodes = null ;
m_globalArrayNodes . Destroy ( ) ;
m_globalArrayNodes = null ;
m_selectedNodes . Clear ( ) ;
m_selectedNodes = null ;
m_markedForDeletion . Clear ( ) ;
m_markedForDeletion = null ;
m_nodesDict . Clear ( ) ;
m_nodesDict = null ;
m_nodePreviewList . Clear ( ) ;
m_nodePreviewList = null ;
IsDirty = true ;
OnNodeEvent = null ;
OnDuplicateEvent = null ;
//m_currentShaderFunction = null;
OnMaterialUpdatedEvent = null ;
OnShaderUpdatedEvent = null ;
OnEmptyGraphDetectedEvt = null ;
nodeStyleOff = null ;
nodeStyleOn = null ;
nodeTitle = null ;
commentaryBackground = null ;
OnLODMasterNodesAddedEvent = null ;
}
void OnNodeChangeSizeEvent ( ParentNode node )
{
m_nodeGrid . RemoveNodeFromGrid ( node , true ) ;
m_nodeGrid . AddNodeToGrid ( node ) ;
}
public void OnNodeFinishMoving ( ParentNode node , bool testOnlySelected , InteractionMode interactionMode )
{
if ( OnNodeEvent ! = null )
{
OnNodeEvent ( node ) ;
SaveIsDirty = true ;
}
m_nodeGrid . RemoveNodeFromGrid ( node , true ) ;
m_nodeGrid . AddNodeToGrid ( node ) ;
//if( testOnlySelected )
//{
// for( int i = m_visibleNodes.Count - 1; i > -1; i-- )
// {
// if( node.UniqueId != m_visibleNodes[ i ].UniqueId )
// {
// switch( interactionMode )
// {
// case InteractionMode.Target:
// {
// node.OnNodeInteraction( m_visibleNodes[ i ] );
// }
// break;
// case InteractionMode.Other:
// {
// m_visibleNodes[ i ].OnNodeInteraction( node );
// }
// break;
// case InteractionMode.Both:
// {
// node.OnNodeInteraction( m_visibleNodes[ i ] );
// m_visibleNodes[ i ].OnNodeInteraction( node );
// }
// break;
// }
// }
// }
//}
//else
{
for ( int i = m_nodes . Count - 1 ; i > - 1 ; i - - )
{
if ( node . UniqueId ! = m_nodes [ i ] . UniqueId )
{
switch ( interactionMode )
{
case InteractionMode . Target :
{
node . OnNodeInteraction ( m_nodes [ i ] ) ;
}
break ;
case InteractionMode . Other :
{
m_nodes [ i ] . OnNodeInteraction ( node ) ;
}
break ;
case InteractionMode . Both :
{
node . OnNodeInteraction ( m_nodes [ i ] ) ;
m_nodes [ i ] . OnNodeInteraction ( node ) ;
}
break ;
}
}
}
}
}
public void OnNodeReOrderEvent ( ParentNode node , int index )
{
if ( node . Depth < index )
{
Debug . LogWarning ( "Reorder canceled: This is a specific method for when reordering needs to be done and a its original index is higher than the new one" ) ;
}
else
{
m_nodes . Remove ( node ) ;
m_nodes . Insert ( index , node ) ;
m_markToReOrder = true ;
}
}
public void AddNode ( ParentNode node , bool updateId = false , bool addLast = true , bool registerUndo = true , bool fetchMaterialValues = true )
{
if ( registerUndo )
{
UIUtils . MarkUndoAction ( ) ;
UndoUtils . RegisterCompleteObjectUndo ( ParentWindow , Constants . UndoCreateNodeId ) ;
UndoUtils . RegisterCompleteObjectUndo ( this , Constants . UndoCreateNodeId ) ;
UndoUtils . RegisterCreatedObjectUndo ( node , Constants . UndoCreateNodeId ) ;
}
if ( OnNodeEvent ! = null )
{
OnNodeEvent ( node ) ;
}
if ( updateId )
{
node . UniqueId = GetValidId ( ) ;
}
else
{
UpdateIdFromNode ( node ) ;
}
if ( addLast )
{
m_nodes . Add ( node ) ;
node . Depth = m_nodes . Count ;
}
else
{
m_nodes . Insert ( 0 , node ) ;
node . Depth = 0 ;
}
if ( m_nodesDict . ContainsKey ( node . UniqueId ) )
{
//m_nodesDict[ node.UniqueId ] = node;
m_foundDuplicates = true ;
}
else
{
m_nodesDict . Add ( node . UniqueId , node ) ;
node . SetMaterialMode ( CurrentMaterial , fetchMaterialValues ) ;
}
m_nodeGrid . AddNodeToGrid ( node ) ;
node . OnNodeChangeSizeEvent + = OnNodeChangeSizeEvent ;
node . OnNodeReOrderEvent + = OnNodeReOrderEvent ;
IsDirty = true ;
}
public void CheckForDuplicates ( )
{
if ( m_foundDuplicates )
{
Debug . LogWarning ( "Found duplicates:" ) ;
m_foundDuplicates = false ;
m_nodesDict . Clear ( ) ;
int count = m_nodes . Count ;
for ( int i = 0 ; i < count ; i + + )
{
if ( m_nodesDict . ContainsKey ( m_nodes [ i ] . UniqueId ) )
{
m_nodes [ i ] . UniqueId = GetValidId ( ) ;
m_nodesDict . Add ( m_nodes [ i ] . UniqueId , m_nodes [ i ] ) ;
Debug . LogWarning ( "Assigning new ID to " + m_nodes [ i ] . TypeName ) ;
}
else
{
m_nodesDict . Add ( m_nodes [ i ] . UniqueId , m_nodes [ i ] ) ;
}
}
}
}
public ParentNode GetClickedNode ( )
{
if ( m_nodeClicked < 0 )
return null ;
return GetNode ( m_nodeClicked ) ;
}
public PropertyNode GetInternalTemplateNode ( int nodeId )
{
if ( m_internalTemplateNodesDict . Count ! = m_internalTemplateNodesList . Count )
{
m_internalTemplateNodesDict . Clear ( ) ;
int count = m_internalTemplateNodesList . Count ;
for ( int i = 0 ; i < m_internalTemplateNodesList . Count ; i + + )
{
if ( m_internalTemplateNodesList [ i ] ! = null )
m_internalTemplateNodesDict . Add ( m_internalTemplateNodesList [ i ] . UniqueId , m_internalTemplateNodesList [ i ] ) ;
}
}
if ( m_internalTemplateNodesDict . ContainsKey ( nodeId ) )
return m_internalTemplateNodesDict [ nodeId ] ;
return null ;
}
public PropertyNode GetInternalTemplateNode ( string propertyName )
{
return m_internalTemplateNodesList . Find ( ( x ) = > x . PropertyName . Equals ( propertyName ) ) ;
}
public void AddInternalTemplateNode ( TemplateShaderPropertyData data )
{
PropertyNode propertyNode = null ;
switch ( data . PropertyDataType )
{
case WirePortDataType . FLOAT :
propertyNode = CreateInstance < RangedFloatNode > ( ) ; break ;
case WirePortDataType . FLOAT4 :
propertyNode = CreateInstance < Vector4Node > ( ) ;
break ;
case WirePortDataType . COLOR :
propertyNode = CreateInstance < ColorNode > ( ) ;
break ;
case WirePortDataType . INT :
propertyNode = CreateInstance < IntNode > ( ) ; break ;
case WirePortDataType . SAMPLER1D :
case WirePortDataType . SAMPLER2D :
case WirePortDataType . SAMPLER3D :
case WirePortDataType . SAMPLERCUBE :
case WirePortDataType . SAMPLER2DARRAY :
propertyNode = CreateInstance < SamplerNode > ( ) ;
break ;
default : return ;
}
propertyNode . PropertyNameFromTemplate ( data ) ;
2026-03-14 03:13:10 -04:00
// Create a negative unique Id to separate it from
// the regular ids on the main nodes list
2025-07-08 14:28:40 -04:00
// Its begins at -2 since -1 is used to detect invalid values
int uniqueId = - ( m_internalTemplateNodesList . Count + 2 ) ;
propertyNode . SetBaseUniqueId ( uniqueId ) ;
//Register into Float/Int Nodes list to be available inline
2026-03-14 03:13:10 -04:00
// Unique Id must be already set at this point to properly
2025-07-08 14:28:40 -04:00
// create array
if ( data . PropertyDataType = = WirePortDataType . FLOAT | |
data . PropertyDataType = = WirePortDataType . INT )
m_floatNodes . AddNode ( propertyNode ) ;
m_internalTemplateNodesList . Add ( propertyNode ) ;
m_internalTemplateNodesDict . Add ( uniqueId , propertyNode ) ;
}
public void ClearInternalTemplateNodes ( )
{
if ( m_internalTemplateNodesList ! = null )
{
int count = m_internalTemplateNodesList . Count ;
for ( int i = 0 ; i < count ; i + + )
{
m_internalTemplateNodesList [ i ] . Destroy ( ) ;
GameObject . DestroyImmediate ( m_internalTemplateNodesList [ i ] ) ;
}
m_internalTemplateNodesList . Clear ( ) ;
m_internalTemplateNodesDict . Clear ( ) ;
}
}
public ParentNode GetNode ( int nodeId )
{
if ( m_nodesDict . Count ! = m_nodes . Count )
{
m_nodesDict . Clear ( ) ;
int count = m_nodes . Count ;
for ( int i = 0 ; i < count ; i + + )
{
if ( m_nodes [ i ] ! = null & & ! m_nodesDict . ContainsKey ( m_nodes [ i ] . UniqueId ) )
m_nodesDict . Add ( m_nodes [ i ] . UniqueId , m_nodes [ i ] ) ;
}
}
if ( m_nodesDict . ContainsKey ( nodeId ) )
return m_nodesDict [ nodeId ] ;
return null ;
}
public void ForceReOrder ( )
{
// @diogo: replaced Sort() with OrderBy() for stable sorting
m_nodes = m_nodes . OrderBy ( s = > s . Depth ) . ToList ( ) ;
}
public bool Draw ( DrawInfo drawInfo )
{
MasterNode masterNode = GetNode ( m_masterNodeId ) as MasterNode ;
if ( m_forceCategoryRefresh & & masterNode ! = null )
{
masterNode . RefreshAvailableCategories ( ) ;
m_forceCategoryRefresh = false ;
}
SaveIsDirty = false ;
if ( m_afterDeserializeFlag )
{
// this is now done after logic update... templates needs it this way
//m_afterDeserializeFlag = false;
CleanCorruptedNodes ( ) ;
if ( m_nodes . Count = = 0 )
{
//TODO: remove this temp from here
NodeAvailability cachedCanvas = CurrentCanvasMode ;
ParentWindow . CreateNewGraph ( "Empty" ) ;
CurrentCanvasMode = cachedCanvas ;
if ( OnEmptyGraphDetectedEvt ! = null )
{
OnEmptyGraphDetectedEvt ( this ) ;
SaveIsDirty = false ;
}
else
{
SaveIsDirty = true ;
}
}
//for( int i = 0; i < m_nodes.Count; i++ )
//{
// m_nodes[ i ].SetContainerGraph( this );
//}
}
if ( drawInfo . CurrentEventType = = EventType . Repaint )
{
if ( m_markedToDeSelect )
DeSelectAll ( ) ;
if ( m_markToSelect > - 1 )
{
AddToSelectedNodes ( GetNode ( m_markToSelect ) ) ;
m_markToSelect = - 1 ;
}
if ( m_markToReOrder )
{
m_markToReOrder = false ;
int nodesCount = m_nodes . Count ;
for ( int i = 0 ; i < nodesCount ; i + + )
{
m_nodes [ i ] . Depth = i ;
}
}
}
if ( drawInfo . CurrentEventType = = EventType . Repaint )
{
// Resizing Nods per LOD level
NodeLOD newLevel = NodeLOD . LOD0 ;
float referenceValue ;
if ( drawInfo . InvertedZoom > 0.5f )
{
newLevel = NodeLOD . LOD0 ;
referenceValue = 4 ;
}
else if ( drawInfo . InvertedZoom > 0.25f )
{
newLevel = NodeLOD . LOD1 ;
referenceValue = 2 ;
}
else if ( drawInfo . InvertedZoom > 0.15f )
{
newLevel = NodeLOD . LOD2 ;
referenceValue = 1 ;
}
else if ( drawInfo . InvertedZoom > 0.1f )
{
newLevel = NodeLOD . LOD3 ;
referenceValue = 0 ;
}
else if ( drawInfo . InvertedZoom > 0.07f )
{
newLevel = NodeLOD . LOD4 ;
referenceValue = 0 ;
}
else
{
newLevel = NodeLOD . LOD5 ;
referenceValue = 0 ;
}
// Just a sanity check
nodeStyleOff = UIUtils . GetCustomStyle ( CustomStyle . NodeWindowOff ) ;
nodeStyleOn = UIUtils . GetCustomStyle ( CustomStyle . NodeWindowOn ) ; //= UIUtils.GetCustomStyle( CustomStyle.NodeWindowOn );
nodeTitle = UIUtils . GetCustomStyle ( CustomStyle . NodeHeader ) ;
commentaryBackground = UIUtils . GetCustomStyle ( CustomStyle . CommentaryBackground ) ;
if ( newLevel ! = m_lodLevel | | ( UIUtils . MainSkin ! = null & & UIUtils . MainSkin . textField . border . left ! = referenceValue ) )
{
m_lodLevel = newLevel ;
switch ( m_lodLevel )
{
default :
case NodeLOD . LOD0 :
{
UIUtils . MainSkin . textField . border = UIUtils . RectOffsetFour ;
nodeStyleOff . border = UIUtils . RectOffsetSix ;
UIUtils . NodeWindowOffSquare . border = UIUtils . RectOffsetFour ;
nodeStyleOn . border = UIUtils . RectOffsetSix ;
UIUtils . NodeWindowOnSquare . border = UIUtils . RectOffsetSix ;
nodeTitle . border . left = 6 ;
nodeTitle . border . right = 6 ;
nodeTitle . border . top = 6 ;
nodeTitle . border . bottom = 4 ;
UIUtils . NodeHeaderSquare . border = UIUtils . RectOffsetFour ;
commentaryBackground . border = UIUtils . RectOffsetSix ;
}
break ;
case NodeLOD . LOD1 :
{
UIUtils . MainSkin . textField . border = UIUtils . RectOffsetTwo ;
nodeStyleOff . border = UIUtils . RectOffsetFive ;
UIUtils . NodeWindowOffSquare . border = UIUtils . RectOffsetFive ;
nodeStyleOn . border = UIUtils . RectOffsetFive ;
UIUtils . NodeWindowOnSquare . border = UIUtils . RectOffsetFour ;
nodeTitle . border . left = 5 ;
nodeTitle . border . right = 5 ;
nodeTitle . border . top = 5 ;
nodeTitle . border . bottom = 2 ;
UIUtils . NodeHeaderSquare . border = UIUtils . RectOffsetThree ;
commentaryBackground . border = UIUtils . RectOffsetFive ;
}
break ;
case NodeLOD . LOD2 :
{
UIUtils . MainSkin . textField . border = UIUtils . RectOffsetOne ;
nodeStyleOff . border . left = 2 ;
nodeStyleOff . border . right = 2 ;
nodeStyleOff . border . top = 2 ;
nodeStyleOff . border . bottom = 3 ;
UIUtils . NodeWindowOffSquare . border = UIUtils . RectOffsetThree ;
nodeStyleOn . border . left = 4 ;
nodeStyleOn . border . right = 4 ;
nodeStyleOn . border . top = 4 ;
nodeStyleOn . border . bottom = 3 ;
UIUtils . NodeWindowOnSquare . border = UIUtils . RectOffsetThree ;
nodeTitle . border = UIUtils . RectOffsetTwo ;
UIUtils . NodeHeaderSquare . border = UIUtils . RectOffsetTwo ;
commentaryBackground . border . left = 2 ;
commentaryBackground . border . right = 2 ;
commentaryBackground . border . top = 2 ;
commentaryBackground . border . bottom = 3 ;
}
break ;
case NodeLOD . LOD3 :
case NodeLOD . LOD4 :
case NodeLOD . LOD5 :
{
UIUtils . MainSkin . textField . border = UIUtils . RectOffsetZero ;
nodeStyleOff . border . left = 1 ;
nodeStyleOff . border . right = 1 ;
nodeStyleOff . border . top = 1 ;
nodeStyleOff . border . bottom = 2 ;
UIUtils . NodeWindowOffSquare . border = UIUtils . RectOffsetTwo ;
nodeStyleOn . border = UIUtils . RectOffsetTwo ;
UIUtils . NodeWindowOnSquare . border = UIUtils . RectOffsetTwo ;
nodeTitle . border = UIUtils . RectOffsetOne ;
UIUtils . NodeHeaderSquare . border = UIUtils . RectOffsetOne ;
commentaryBackground . border . left = 1 ;
commentaryBackground . border . right = 1 ;
commentaryBackground . border . top = 1 ;
commentaryBackground . border . bottom = 2 ;
}
break ;
}
}
}
//m_visibleNodes.Clear();
//int nullCount = 0;
m_hasUnConnectedNodes = false ;
bool repaint = false ;
Material currentMaterial = masterNode ! = null ? masterNode . CurrentMaterial : null ;
EditorGUI . BeginChangeCheck ( ) ;
bool repaintMaterialInspector = false ;
int nodeCount = m_nodes . Count ;
for ( int i = 0 ; i < nodeCount ; i + + )
{
m_nodes [ i ] . OnNodeLogicUpdate ( drawInfo ) ;
}
if ( m_afterDeserializeFlag | | m_lateOptionsRefresh )
{
m_afterDeserializeFlag = false ;
m_lateOptionsRefresh = false ;
if ( CurrentCanvasMode = = NodeAvailability . TemplateShader )
{
RefreshLinkedMasterNodes ( true ) ;
OnRefreshLinkedPortsComplete ( ) ;
//If clipboard has cached nodes then a master node replacement will take place
//We need to re-cache master nodes to ensure applied options are correctly cached
//As first cache happens before that
if ( m_parentWindow . ClipboardInstance . HasCachedMasterNodes )
{
m_parentWindow . ClipboardInstance . AddMultiPassNodesToClipboard ( MultiPassMasterNodes . NodesList , true , - 1 ) ;
for ( int i = 0 ; i < m_lodMultiPassMasterNodes . Count ; i + + )
{
if ( m_lodMultiPassMasterNodes [ i ] . Count > 0 )
m_parentWindow . ClipboardInstance . AddMultiPassNodesToClipboard ( m_lodMultiPassMasterNodes [ i ] . NodesList , false , i ) ;
}
}
//RepositionTemplateNodes( CurrentMasterNode );
}
}
if ( m_forceRepositionCheck )
{
RepositionTemplateNodes ( CurrentMasterNode ) ;
}
//for( int i = 0; i < m_functionNodes.NodesList.Count; i++ )
//{
// m_functionNodes.NodesList[ i ].LogicGraph();
//}
//for( int i = 0; i < UIUtils.FunctionSwitchCopyList().Count; i++ )
//{
// UIUtils.FunctionSwitchCopyList()[ i ].CheckReference();
//}
2026-03-14 03:13:10 -04:00
// @diogo: when loading we only need to call OnNodeChange once for every node, where branch connections to multiple inputs sometimes causes
// the same node to be visited multiple times; avoid it
var nodeCache = new NodeUpdateCache ( ) ;
2025-07-08 14:28:40 -04:00
// Dont use nodeCount variable because node count can change in this loop???
nodeCount = m_nodes . Count ;
ParentNode node = null ;
for ( int i = 0 ; i < nodeCount ; i + + )
{
node = m_nodes [ i ] ;
if ( ! node . IsOnGrid )
{
m_nodeGrid . AddNodeToGrid ( node ) ;
}
node . MovingInFrame = false ;
if ( drawInfo . CurrentEventType = = EventType . Repaint )
2026-03-14 03:13:10 -04:00
node . OnNodeLayout ( drawInfo , nodeCache ) ;
2025-07-08 14:28:40 -04:00
m_hasUnConnectedNodes = m_hasUnConnectedNodes | |
( node . ConnStatus ! = NodeConnectionStatus . Connected & & node . ConnStatus ! = NodeConnectionStatus . Island ) ;
if ( node . RequireMaterialUpdate & & currentMaterial ! = null )
{
node . UpdateMaterial ( currentMaterial ) ;
repaintMaterialInspector = true ;
}
//if( node.IsVisible )
// m_visibleNodes.Add( node );
IsDirty = ( m_isDirty | | node . IsDirty ) ;
SaveIsDirty = ( m_saveIsDirty | | node . SaveIsDirty ) ;
}
// Handles GUI controls
nodeCount = m_nodes . Count ;
for ( int i = nodeCount - 1 ; i > = 0 ; i - - )
//for ( int i = 0; i < nodeCount; i++ )
{
node = m_nodes [ i ] ;
bool restoreMouse = false ;
if ( drawInfo . CurrentEventType = = EventType . MouseDown & & m_nodeClicked > - 1 & & node . UniqueId ! = m_nodeClicked )
{
restoreMouse = true ;
drawInfo . CurrentEventType = EventType . Ignore ;
}
node . DrawGUIControls ( drawInfo ) ;
if ( restoreMouse )
{
drawInfo . CurrentEventType = EventType . MouseDown ;
}
}
// Draw connection wires
if ( drawInfo . CurrentEventType = = EventType . Repaint )
DrawWires ( ParentWindow . WireTexture , drawInfo , ParentWindow . WindowContextPallete . IsActive , ParentWindow . WindowContextPallete . CurrentPosition ) ;
// Master Draw
nodeCount = m_nodes . Count ;
for ( int i = 0 ; i < nodeCount ; i + + )
{
node = m_nodes [ i ] ;
bool restoreMouse = false ;
if ( drawInfo . CurrentEventType = = EventType . MouseDown & & m_nodeClicked > - 1 & & node . UniqueId ! = m_nodeClicked )
{
restoreMouse = true ;
drawInfo . CurrentEventType = EventType . Ignore ;
}
node . Draw ( drawInfo ) ;
if ( restoreMouse )
{
drawInfo . CurrentEventType = EventType . MouseDown ;
}
}
// Draw Tooltip
if ( drawInfo . CurrentEventType = = EventType . Repaint | | drawInfo . CurrentEventType = = EventType . MouseDown )
{
nodeCount = m_nodes . Count ;
for ( int i = nodeCount - 1 ; i > = 0 ; i - - )
{
node = m_nodes [ i ] ;
if ( node . IsVisible & & ! node . IsMoving )
{
bool showing = node . ShowTooltip ( drawInfo ) ;
if ( showing )
break ;
}
}
}
if ( repaintMaterialInspector )
{
2026-03-14 03:13:10 -04:00
if ( MaterialInspector . Instance ! = null )
2025-07-08 14:28:40 -04:00
{
2026-03-14 03:13:10 -04:00
MaterialInspector . Instance . Repaint ( ) ;
2025-07-08 14:28:40 -04:00
}
}
if ( m_checkSelectedWireHighlights )
{
m_checkSelectedWireHighlights = false ;
ResetHighlightedWires ( ) ;
for ( int i = 0 ; i < m_selectedNodes . Count ; i + + )
{
HighlightWiresStartingNode ( m_selectedNodes [ i ] ) ;
}
}
if ( EditorGUI . EndChangeCheck ( ) )
{
SaveIsDirty = true ;
repaint = true ;
}
if ( drawInfo . CurrentEventType = = EventType . Repaint )
{
// Revert LOD changes to LOD0 (only if it's different)
if ( UIUtils . MainSkin . textField . border . left ! = 4 )
{
UIUtils . MainSkin . textField . border = UIUtils . RectOffsetFour ;
nodeStyleOff . border = UIUtils . RectOffsetSix ;
UIUtils . NodeWindowOffSquare . border = UIUtils . RectOffsetFour ;
nodeStyleOn . border = UIUtils . RectOffsetSix ;
UIUtils . NodeWindowOnSquare . border = UIUtils . RectOffsetSix ;
nodeTitle . border . left = 6 ;
nodeTitle . border . right = 6 ;
nodeTitle . border . top = 6 ;
nodeTitle . border . bottom = 4 ;
UIUtils . NodeHeaderSquare . border = UIUtils . RectOffsetFour ;
commentaryBackground . border = UIUtils . RectOffsetSix ;
}
}
//if ( nullCount == m_nodes.Count )
// m_nodes.Clear();
ChangedLightingModel = false ;
return repaint ;
}
public bool UpdateMarkForDeletion ( )
{
if ( m_markedForDeletion . Count ! = 0 )
{
DeleteMarkedForDeletionNodes ( ) ;
return true ;
}
return false ;
}
public void DrawWires ( Texture2D wireTex , DrawInfo drawInfo , bool contextPaletteActive , Vector3 contextPalettePos )
{
//Handles.BeginGUI();
//Debug.Log(GUI.depth);
// Draw connected node wires
m_wireBezierCount = 0 ;
for ( int nodeIdx = 0 ; nodeIdx < m_nodes . Count ; nodeIdx + + )
{
ParentNode node = m_nodes [ nodeIdx ] ;
if ( ( object ) node = = null )
return ;
for ( int inputPortIdx = 0 ; inputPortIdx < node . InputPorts . Count ; inputPortIdx + + )
{
InputPort inputPort = node . InputPorts [ inputPortIdx ] ;
if ( inputPort . ExternalReferences . Count > 0 & & inputPort . Visible )
{
bool cleanInvalidConnections = false ;
for ( int wireIdx = 0 ; wireIdx < inputPort . ExternalReferences . Count ; wireIdx + + )
{
WireReference reference = inputPort . ExternalReferences [ wireIdx ] ;
if ( reference . NodeId ! = - 1 & & reference . PortId ! = - 1 )
{
ParentNode outputNode = GetNode ( reference . NodeId ) ;
if ( outputNode ! = null )
{
OutputPort outputPort = outputNode . GetOutputPortByUniqueId ( reference . PortId ) ;
Vector3 endPos = new Vector3 ( inputPort . Position . x , inputPort . Position . y ) ;
Vector3 startPos = new Vector3 ( outputPort . Position . x , outputPort . Position . y ) ;
float x = ( startPos . x < endPos . x ) ? startPos . x : endPos . x ;
float y = ( startPos . y < endPos . y ) ? startPos . y : endPos . y ;
float width = Mathf . Abs ( startPos . x - endPos . x ) + outputPort . Position . width ;
float height = Mathf . Abs ( startPos . y - endPos . y ) + outputPort . Position . height ;
Rect portsBoundingBox = new Rect ( x , y , width , height ) ;
bool isVisible = node . IsVisible | | outputNode . IsVisible ;
if ( ! isVisible )
{
isVisible = drawInfo . TransformedCameraArea . Overlaps ( portsBoundingBox ) ;
}
if ( isVisible )
{
Rect bezierBB = DrawBezier ( drawInfo . InvertedZoom , startPos , endPos , inputPort . DataType , outputPort . DataType , node . GetInputPortVisualDataTypeByArrayIdx ( inputPortIdx ) , outputNode . GetOutputPortVisualDataTypeById ( reference . PortId ) , reference . WireStatus , wireTex , node , outputNode ) ;
bezierBB . x - = Constants . OUTSIDE_WIRE_MARGIN ;
bezierBB . y - = Constants . OUTSIDE_WIRE_MARGIN ;
bezierBB . width + = Constants . OUTSIDE_WIRE_MARGIN * 2 ;
bezierBB . height + = Constants . OUTSIDE_WIRE_MARGIN * 2 ;
if ( m_wireBezierCount < m_bezierReferences . Count )
{
m_bezierReferences [ m_wireBezierCount ] . UpdateInfo ( ref bezierBB , inputPort . NodeId , inputPort . PortId , outputPort . NodeId , outputPort . PortId ) ;
}
else
{
m_bezierReferences . Add ( new WireBezierReference ( ref bezierBB , inputPort . NodeId , inputPort . PortId , outputPort . NodeId , outputPort . PortId ) ) ;
}
m_wireBezierCount + + ;
}
}
else
{
if ( DebugConsoleWindow . DeveloperMode )
UIUtils . ShowMessage ( "Detected Invalid connection from node " + node . UniqueId + " port " + inputPortIdx + " to Node " + reference . NodeId + " port " + reference . PortId , MessageSeverity . Error ) ;
cleanInvalidConnections = true ;
inputPort . ExternalReferences [ wireIdx ] . Invalidate ( ) ;
}
}
}
if ( cleanInvalidConnections )
{
inputPort . RemoveInvalidConnections ( ) ;
}
}
}
}
//Draw selected wire
if ( m_parentWindow . WireReferenceUtils . ValidReferences ( ) )
{
if ( m_parentWindow . WireReferenceUtils . InputPortReference . IsValid )
{
InputPort inputPort = GetNode ( m_parentWindow . WireReferenceUtils . InputPortReference . NodeId ) . GetInputPortByUniqueId ( m_parentWindow . WireReferenceUtils . InputPortReference . PortId ) ;
Vector3 endPos = Vector3 . zero ;
if ( m_parentWindow . WireReferenceUtils . SnapEnabled )
{
Vector2 pos = ( m_parentWindow . WireReferenceUtils . SnapPosition + drawInfo . CameraOffset ) * drawInfo . InvertedZoom ;
endPos = new Vector3 ( pos . x , pos . y ) + UIUtils . ScaledPortsDelta ;
}
else
{
endPos = contextPaletteActive ? contextPalettePos : new Vector3 ( Event . current . mousePosition . x , Event . current . mousePosition . y ) ;
}
Vector3 startPos = new Vector3 ( inputPort . Position . x , inputPort . Position . y ) ;
DrawBezier ( drawInfo . InvertedZoom , endPos , startPos , inputPort . DataType , inputPort . DataType , inputPort . DataType , inputPort . DataType , WireStatus . Default , wireTex ) ;
}
if ( m_parentWindow . WireReferenceUtils . OutputPortReference . IsValid )
{
OutputPort outputPort = GetNode ( m_parentWindow . WireReferenceUtils . OutputPortReference . NodeId ) . GetOutputPortByUniqueId ( m_parentWindow . WireReferenceUtils . OutputPortReference . PortId ) ;
Vector3 endPos = Vector3 . zero ;
if ( m_parentWindow . WireReferenceUtils . SnapEnabled )
{
Vector2 pos = ( m_parentWindow . WireReferenceUtils . SnapPosition + drawInfo . CameraOffset ) * drawInfo . InvertedZoom ;
endPos = new Vector3 ( pos . x , pos . y ) + UIUtils . ScaledPortsDelta ;
}
else
{
endPos = contextPaletteActive ? contextPalettePos : new Vector3 ( Event . current . mousePosition . x , Event . current . mousePosition . y ) ;
}
Vector3 startPos = new Vector3 ( outputPort . Position . x , outputPort . Position . y ) ;
DrawBezier ( drawInfo . InvertedZoom , startPos , endPos , outputPort . DataType , outputPort . DataType , outputPort . DataType , outputPort . DataType , WireStatus . Default , wireTex ) ;
}
}
//Handles.EndGUI();
}
Rect DrawBezier ( float invertedZoom , Vector3 startPos , Vector3 endPos , WirePortDataType inputDataType , WirePortDataType outputDataType , WirePortDataType inputVisualDataType , WirePortDataType outputVisualDataType , WireStatus wireStatus , Texture2D wireTex , ParentNode inputNode = null , ParentNode outputNode = null )
{
startPos + = UIUtils . ScaledPortsDelta ;
endPos + = UIUtils . ScaledPortsDelta ;
// Calculate the 4 points for bezier taking into account wire nodes and their automatic tangents
float mag = ( endPos - startPos ) . magnitude ;
float resizedMag = Mathf . Min ( mag * 0.66f , Constants . HORIZONTAL_TANGENT_SIZE * invertedZoom ) ;
Vector3 startTangent = new Vector3 ( startPos . x + resizedMag , startPos . y ) ;
Vector3 endTangent = new Vector3 ( endPos . x - resizedMag , endPos . y ) ;
if ( ( object ) inputNode ! = null & & inputNode . GetType ( ) = = typeof ( WireNode ) )
endTangent = endPos + ( ( inputNode as WireNode ) . TangentDirection ) * mag * 0.33f ;
if ( ( object ) outputNode ! = null & & outputNode . GetType ( ) = = typeof ( WireNode ) )
startTangent = startPos - ( ( outputNode as WireNode ) . TangentDirection ) * mag * 0.33f ;
///////////////Draw tangents
//Rect box1 = new Rect( new Vector2( startTangent.x, startTangent.y ), new Vector2( 10, 10 ) );
//box1.x -= box1.width * 0.5f;
//box1.y -= box1.height * 0.5f;
//GUI.Label( box1, string.Empty, UIUtils.Box );
//Rect box2 = new Rect( new Vector2( endTangent.x, endTangent.y ), new Vector2( 10, 10 ) );
//box2.x -= box2.width * 0.5f;
//box2.y -= box2.height * 0.5f;
//GUI.Label( box2, string.Empty, UIUtils.Box );
//m_auxRect.Set( 0, 0, UIUtils.CurrentWindow.position.width, UIUtils.CurrentWindow.position.height );
//GLDraw.BeginGroup( m_auxRect );
int ty = 1 ;
float wireThickness = 0 ;
if ( ParentWindow . Options . MultiLinePorts )
{
GLDraw . MultiLine = true ;
Shader . SetGlobalFloat ( "_InvertedZoom" , invertedZoom ) ;
WirePortDataType smallest = ( ( int ) outputDataType < ( int ) inputDataType ? outputDataType : inputDataType ) ;
smallest = ( ( int ) smallest < ( int ) outputVisualDataType ? smallest : outputVisualDataType ) ;
smallest = ( ( int ) smallest < ( int ) inputVisualDataType ? smallest : inputVisualDataType ) ;
switch ( smallest )
{
case WirePortDataType . FLOAT2 : ty = 2 ; break ;
case WirePortDataType . FLOAT3 : ty = 3 ; break ;
case WirePortDataType . FLOAT4 :
case WirePortDataType . COLOR :
{
ty = 4 ;
}
break ;
default : ty = 1 ; break ;
}
wireThickness = Mathf . Lerp ( Constants . WIRE_WIDTH * ( ty * invertedZoom * - 0.05f + 0.15f ) , Constants . WIRE_WIDTH * ( ty * invertedZoom * 0.175f + 0.3f ) , invertedZoom + 0.4f ) ;
}
else
{
GLDraw . MultiLine = false ;
wireThickness = Mathf . Lerp ( Constants . WIRE_WIDTH * ( invertedZoom * - 0.05f + 0.15f ) , Constants . WIRE_WIDTH * ( invertedZoom * 0.175f + 0.3f ) , invertedZoom + 0.4f ) ;
}
Rect boundBox = new Rect ( ) ;
int segments = 11 ;
if ( LodLevel < = ParentGraph . NodeLOD . LOD4 )
segments = Mathf . Clamp ( Mathf . FloorToInt ( mag * 0.2f * invertedZoom ) , 11 , 35 ) ;
else
segments = ( int ) ( invertedZoom * 14.28f * 11 ) ;
if ( ParentWindow . Options . ColoredPorts & & wireStatus ! = WireStatus . Highlighted )
boundBox = GLDraw . DrawBezier ( startPos , startTangent , endPos , endTangent , UIUtils . GetColorForDataType ( outputVisualDataType , false , false ) , UIUtils . GetColorForDataType ( inputVisualDataType , false , false ) , wireThickness , segments , ty ) ;
else
boundBox = GLDraw . DrawBezier ( startPos , startTangent , endPos , endTangent , UIUtils . GetColorFromWireStatus ( wireStatus ) , wireThickness , segments , ty ) ;
//GLDraw.EndGroup();
//GUI.Box( m_auxRect, string.Empty, UIUtils.CurrentWindow.CustomStylesInstance.Box );
//GUI.Box( boundBox, string.Empty, UIUtils.CurrentWindow.CustomStylesInstance.Box );
//if ( UIUtils.CurrentWindow.Options.ColoredPorts && wireStatus != WireStatus.Highlighted )
// Handles.DrawBezier( startPos, endPos, startTangent, endTangent, UIUtils.GetColorForDataType( outputDataType, false, false ), wireTex, wiresTickness );
//else
// Handles.DrawBezier( startPos, endPos, startTangent, endTangent, UIUtils.GetColorFromWireStatus( wireStatus ), wireTex, wiresTickness );
//Handles.DrawLine( startPos, startTangent );
//Handles.DrawLine( endPos, endTangent );
float extraBound = 30 * invertedZoom ;
boundBox . xMin - = extraBound ;
boundBox . xMax + = extraBound ;
boundBox . yMin - = extraBound ;
boundBox . yMax + = extraBound ;
return boundBox ;
}
public void DrawBezierBoundingBox ( )
{
for ( int i = 0 ; i < m_wireBezierCount ; i + + )
{
m_bezierReferences [ i ] . DebugDraw ( ) ;
}
}
public WireBezierReference GetWireBezierInPos ( Vector2 position )
{
for ( int i = 0 ; i < m_wireBezierCount ; i + + )
{
if ( m_bezierReferences [ i ] . Contains ( position ) )
return m_bezierReferences [ i ] ;
}
return null ;
}
public List < WireBezierReference > GetWireBezierListInPos ( Vector2 position )
{
List < WireBezierReference > list = new List < WireBezierReference > ( ) ;
for ( int i = 0 ; i < m_wireBezierCount ; i + + )
{
if ( m_bezierReferences [ i ] . Contains ( position ) )
list . Add ( m_bezierReferences [ i ] ) ;
}
return list ;
}
public void MoveSelectedNodes ( Vector2 delta , bool snap = false )
{
//bool validMovement = delta.magnitude > 0.001f;
//if ( validMovement )
//{
// UndoUtils.RegisterCompleteObjectUndo( ParentWindow, Constants.UndoMoveNodesId );
// for ( int i = 0; i < m_selectedNodes.Count; i++ )
// {
// if ( !m_selectedNodes[ i ].MovingInFrame )
// {
// UndoUtils.RecordObject( m_selectedNodes[ i ], Constants.UndoMoveNodesId );
// m_selectedNodes[ i ].Move( delta, snap );
// }
// }
// IsDirty = true;
//}
bool performUndo = delta . magnitude > 0.01f ;
if ( performUndo )
{
UndoUtils . RegisterCompleteObjectUndo ( ParentWindow , Constants . UndoMoveNodesId ) ;
UndoUtils . RegisterCompleteObjectUndo ( this , Constants . UndoMoveNodesId ) ;
}
for ( int i = 0 ; i < m_selectedNodes . Count ; i + + )
{
if ( ! m_selectedNodes [ i ] . MovingInFrame )
{
if ( performUndo )
m_selectedNodes [ i ] . RecordObject ( Constants . UndoMoveNodesId ) ;
m_selectedNodes [ i ] . Move ( delta , snap ) ;
}
}
IsDirty = true ;
}
public void SetConnection ( int InNodeId , int InPortId , int OutNodeId , int OutPortId )
{
ParentNode inNode = GetNode ( InNodeId ) ;
ParentNode outNode = GetNode ( OutNodeId ) ;
InputPort inputPort = null ;
OutputPort outputPort = null ;
if ( inNode ! = null & & outNode ! = null )
{
inputPort = inNode . GetInputPortByUniqueId ( InPortId ) ;
outputPort = outNode . GetOutputPortByUniqueId ( OutPortId ) ;
if ( inputPort ! = null & & outputPort ! = null )
{
if ( inputPort . IsConnectedTo ( OutNodeId , OutPortId ) | | outputPort . IsConnectedTo ( InNodeId , InPortId ) )
{
if ( DebugConsoleWindow . DeveloperMode )
UIUtils . ShowMessage ( "Node/Port already connected " + InNodeId , MessageSeverity . Error ) ;
return ;
}
if ( ! inputPort . CheckValidType ( outputPort . DataType ) )
{
if ( DebugConsoleWindow . DeveloperMode )
UIUtils . ShowIncompatiblePortMessage ( true , inNode , inputPort , outNode , outputPort ) ;
return ;
}
if ( ! outputPort . CheckValidType ( inputPort . DataType ) )
{
if ( DebugConsoleWindow . DeveloperMode )
UIUtils . ShowIncompatiblePortMessage ( false , outNode , outputPort , inNode , inputPort ) ;
return ;
}
if ( ! inputPort . Available | | ! outputPort . Available )
{
if ( DebugConsoleWindow . DeveloperMode )
UIUtils . ShowMessage ( "Ports not available to connection" , MessageSeverity . Warning ) ;
return ;
}
if ( inputPort . ConnectTo ( OutNodeId , OutPortId , outputPort . DataType , false ) )
{
inNode . OnInputPortConnected ( InPortId , OutNodeId , OutPortId ) ;
}
if ( outputPort . ConnectTo ( InNodeId , InPortId , inputPort . DataType , inputPort . TypeLocked ) )
{
outNode . OnOutputPortConnected ( OutPortId , InNodeId , InPortId ) ;
}
}
else if ( ( object ) inputPort = = null )
{
if ( DebugConsoleWindow . DeveloperMode )
UIUtils . ShowMessage ( "Input Port " + InPortId + " doesn't exist on node " + InNodeId , MessageSeverity . Error ) ;
}
else
{
if ( DebugConsoleWindow . DeveloperMode )
UIUtils . ShowMessage ( "Output Port " + OutPortId + " doesn't exist on node " + OutNodeId , MessageSeverity . Error ) ;
}
}
else if ( ( object ) inNode = = null )
{
if ( DebugConsoleWindow . DeveloperMode )
UIUtils . ShowMessage ( "Input node " + InNodeId + " doesn't exist" , MessageSeverity . Error ) ;
}
else
{
if ( DebugConsoleWindow . DeveloperMode )
UIUtils . ShowMessage ( "Output node " + OutNodeId + " doesn't exist" , MessageSeverity . Error ) ;
}
}
public void CreateConnection ( int inNodeId , int inPortId , int outNodeId , int outPortId , bool registerUndo = true )
{
ParentNode outputNode = GetNode ( outNodeId ) ;
if ( outputNode ! = null )
{
OutputPort outputPort = outputNode . GetOutputPortByUniqueId ( outPortId ) ;
if ( outputPort ! = null )
{
ParentNode inputNode = GetNode ( inNodeId ) ;
InputPort inputPort = inputNode . GetInputPortByUniqueId ( inPortId ) ;
if ( ! inputPort . CheckValidType ( outputPort . DataType ) )
{
UIUtils . ShowIncompatiblePortMessage ( true , inputNode , inputPort , outputNode , outputPort ) ;
return ;
}
if ( ! outputPort . CheckValidType ( inputPort . DataType ) )
{
UIUtils . ShowIncompatiblePortMessage ( false , outputNode , outputPort , inputNode , inputPort ) ;
return ;
}
inputPort . DummyAdd ( outputPort . NodeId , outputPort . PortId ) ;
outputPort . DummyAdd ( inNodeId , inPortId ) ;
if ( UIUtils . DetectNodeLoopsFrom ( inputNode , new Dictionary < int , int > ( ) ) )
{
inputPort . DummyRemove ( ) ;
outputPort . DummyRemove ( ) ;
m_parentWindow . WireReferenceUtils . InvalidateReferences ( ) ;
UIUtils . ShowMessage ( "Infinite Loop detected" ) ;
Event . current . Use ( ) ;
return ;
}
inputPort . DummyRemove ( ) ;
outputPort . DummyRemove ( ) ;
if ( inputPort . IsConnected )
{
DeleteConnection ( true , inNodeId , inPortId , true , false , registerUndo ) ;
}
//link output to input
if ( outputPort . ConnectTo ( inNodeId , inPortId , inputPort . DataType , inputPort . TypeLocked ) )
outputNode . OnOutputPortConnected ( outputPort . PortId , inNodeId , inPortId ) ;
//link input to output
if ( inputPort . ConnectTo ( outputPort . NodeId , outputPort . PortId , outputPort . DataType , inputPort . TypeLocked ) )
inputNode . OnInputPortConnected ( inPortId , outputNode . UniqueId , outputPort . PortId ) ;
MarkWireHighlights ( ) ;
}
SaveIsDirty = true ;
//ParentWindow.ShaderIsModified = true;
}
}
public void DeleteInvalidConnections ( )
{
int count = m_nodes . Count ;
for ( int nodeIdx = 0 ; nodeIdx < count ; nodeIdx + + )
{
{
int inputCount = m_nodes [ nodeIdx ] . InputPorts . Count ;
for ( int inputIdx = 0 ; inputIdx < inputCount ; inputIdx + + )
{
if ( ! m_nodes [ nodeIdx ] . InputPorts [ inputIdx ] . Visible & &
m_nodes [ nodeIdx ] . InputPorts [ inputIdx ] . IsConnected & &
! m_nodes [ nodeIdx ] . InputPorts [ inputIdx ] . IsDummy )
{
DeleteConnection ( true , m_nodes [ nodeIdx ] . UniqueId , m_nodes [ nodeIdx ] . InputPorts [ inputIdx ] . PortId , true , true ) ;
}
}
}
{
int outputCount = m_nodes [ nodeIdx ] . OutputPorts . Count ;
for ( int outputIdx = 0 ; outputIdx < outputCount ; outputIdx + + )
{
if ( ! m_nodes [ nodeIdx ] . OutputPorts [ outputIdx ] . Visible & & m_nodes [ nodeIdx ] . OutputPorts [ outputIdx ] . IsConnected )
{
DeleteConnection ( false , m_nodes [ nodeIdx ] . UniqueId , m_nodes [ nodeIdx ] . OutputPorts [ outputIdx ] . PortId , true , true ) ;
}
}
}
}
}
public void DeleteAllConnectionFromNode ( int nodeId , bool registerOnLog , bool propagateCallback , bool registerUndo )
{
ParentNode node = GetNode ( nodeId ) ;
if ( ( object ) node = = null )
return ;
DeleteAllConnectionFromNode ( node , registerOnLog , propagateCallback , registerUndo ) ;
}
public void DeleteAllConnectionFromNode ( ParentNode node , bool registerOnLog , bool propagateCallback , bool registerUndo )
{
for ( int i = 0 ; i < node . InputPorts . Count ; i + + )
{
if ( node . InputPorts [ i ] . IsConnected )
DeleteConnection ( true , node . UniqueId , node . InputPorts [ i ] . PortId , registerOnLog , propagateCallback , registerUndo ) ;
}
for ( int i = 0 ; i < node . OutputPorts . Count ; i + + )
{
if ( node . OutputPorts [ i ] . IsConnected )
DeleteConnection ( false , node . UniqueId , node . OutputPorts [ i ] . PortId , registerOnLog , propagateCallback , registerUndo ) ;
}
}
public void DeleteConnection ( bool isInput , int nodeId , int portId , bool registerOnLog , bool propagateCallback , bool registerUndo = true )
{
ParentNode node = GetNode ( nodeId ) ;
if ( ( object ) node = = null )
return ;
if ( registerUndo )
{
UIUtils . MarkUndoAction ( ) ;
UndoUtils . RegisterCompleteObjectUndo ( ParentWindow , Constants . UndoDeleteConnectionId ) ;
UndoUtils . RegisterCompleteObjectUndo ( this , Constants . UndoDeleteConnectionId ) ;
node . RecordObject ( Constants . UndoDeleteConnectionId ) ;
}
if ( isInput )
{
InputPort inputPort = node . GetInputPortByUniqueId ( portId ) ;
if ( inputPort ! = null & & inputPort . IsConnected )
{
if ( node . ConnStatus = = NodeConnectionStatus . Connected )
{
node . DeactivateInputPortNode ( portId , false ) ;
//inputPort.GetOutputNode().DeactivateNode( portId, false );
m_checkSelectedWireHighlights = true ;
}
for ( int i = 0 ; i < inputPort . ExternalReferences . Count ; i + + )
{
WireReference inputReference = inputPort . ExternalReferences [ i ] ;
ParentNode outputNode = GetNode ( inputReference . NodeId ) ;
if ( registerUndo )
outputNode . RecordObject ( Constants . UndoDeleteConnectionId ) ;
outputNode . GetOutputPortByUniqueId ( inputReference . PortId ) . InvalidateConnection ( inputPort . NodeId , inputPort . PortId ) ;
if ( propagateCallback )
outputNode . OnOutputPortDisconnected ( inputReference . PortId ) ;
}
inputPort . InvalidateAllConnections ( ) ;
if ( propagateCallback )
node . OnInputPortDisconnected ( portId ) ;
}
}
else
{
OutputPort outputPort = node . GetOutputPortByUniqueId ( portId ) ;
if ( outputPort ! = null & & outputPort . IsConnected )
{
if ( propagateCallback )
node . OnOutputPortDisconnected ( portId ) ;
for ( int i = 0 ; i < outputPort . ExternalReferences . Count ; i + + )
{
WireReference outputReference = outputPort . ExternalReferences [ i ] ;
ParentNode inputNode = GetNode ( outputReference . NodeId ) ;
if ( registerUndo )
inputNode . RecordObject ( Constants . UndoDeleteConnectionId ) ;
if ( inputNode . ConnStatus = = NodeConnectionStatus . Connected )
{
node . DeactivateNode ( portId , false ) ;
m_checkSelectedWireHighlights = true ;
}
inputNode . GetInputPortByUniqueId ( outputReference . PortId ) . InvalidateConnection ( outputPort . NodeId , outputPort . PortId ) ;
if ( propagateCallback )
{
// Removing WireNodes fires this after the rewiring ( and the OnInputPortConnected callback ) which causes incorrect behaviors
// If is connected is true then we're on that case so we don't fire the OnInputPortDisconnected
if ( ! inputNode . GetInputPortByUniqueId ( outputReference . PortId ) . IsConnected )
inputNode . OnInputPortDisconnected ( outputReference . PortId ) ;
}
}
outputPort . InvalidateAllConnections ( ) ;
}
}
IsDirty = true ;
SaveIsDirty = true ;
}
//public void DeleteSelectedNodes()
//{
// bool invalidateMasterNode = false;
// int count = m_selectedNodes.Count;
// for( int nodeIdx = 0; nodeIdx < count; nodeIdx++ )
// {
// ParentNode node = m_selectedNodes[ nodeIdx ];
// if( node.UniqueId == m_masterNodeId )
// {
// invalidateMasterNode = true;
// }
// else
// {
// DestroyNode( node );
// }
// }
// if( invalidateMasterNode )
// {
// CurrentOutputNode.Selected = false;
// }
// //Clear all references
// m_selectedNodes.Clear();
// IsDirty = true;
//}
public void DeleteNodesOnArray ( ref ParentNode [ ] nodeArray )
{
bool invalidateMasterNode = false ;
for ( int nodeIdx = 0 ; nodeIdx < nodeArray . Length ; nodeIdx + + )
{
ParentNode node = nodeArray [ nodeIdx ] ;
if ( node . UniqueId = = m_masterNodeId )
{
FunctionOutput fout = node as FunctionOutput ;
if ( fout ! = null )
{
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
FunctionOutput secondfout = m_nodes [ i ] as FunctionOutput ;
if ( secondfout ! = null & & secondfout ! = fout )
{
secondfout . Function = fout . Function ;
AssignMasterNode ( secondfout , false ) ;
DeselectNode ( fout ) ;
DestroyNode ( fout ) ;
break ;
}
}
}
invalidateMasterNode = true ;
}
else
{
DeselectNode ( node ) ;
DestroyNode ( node ) ;
}
nodeArray [ nodeIdx ] = null ;
}
if ( invalidateMasterNode & & CurrentMasterNode ! = null )
{
CurrentMasterNode . Selected = false ;
}
//Clear all references
nodeArray = null ;
IsDirty = true ;
}
public void MarkWireNodeSequence ( WireNode node , bool isInput )
{
if ( node = = null )
{
return ;
}
if ( m_markedForDeletion . Contains ( node ) )
return ;
m_markedForDeletion . Add ( node ) ;
if ( isInput & & node . InputPorts [ 0 ] . IsConnected )
{
MarkWireNodeSequence ( GetNode ( node . InputPorts [ 0 ] . ExternalReferences [ 0 ] . NodeId ) as WireNode , isInput ) ;
}
else if ( ! isInput & & node . OutputPorts [ 0 ] . IsConnected )
{
MarkWireNodeSequence ( GetNode ( node . OutputPorts [ 0 ] . ExternalReferences [ 0 ] . NodeId ) as WireNode , isInput ) ;
}
}
public void UndoableDeleteSelectedNodes ( List < ParentNode > nodeList )
{
if ( nodeList . Count = = 0 )
return ;
List < ParentNode > validNode = new List < ParentNode > ( ) ;
for ( int i = 0 ; i < nodeList . Count ; i + + )
{
if ( nodeList [ i ] ! = null & & nodeList [ i ] . UniqueId ! = m_masterNodeId )
{
validNode . Add ( nodeList [ i ] ) ;
}
}
UIUtils . ClearUndoHelper ( ) ;
ParentNode [ ] selectedNodes = new ParentNode [ validNode . Count ] ;
for ( int i = 0 ; i < selectedNodes . Length ; i + + )
{
if ( validNode [ i ] ! = null )
{
selectedNodes [ i ] = validNode [ i ] ;
UIUtils . CheckUndoNode ( selectedNodes [ i ] ) ;
}
}
//Check nodes connected to deleted nodes to preserve connections on undo
List < ParentNode > extraNodes = new List < ParentNode > ( ) ;
for ( int selectedNodeIdx = 0 ; selectedNodeIdx < selectedNodes . Length ; selectedNodeIdx + + )
{
// Check inputs
if ( selectedNodes [ selectedNodeIdx ] ! = null )
{
int inputIdxCount = selectedNodes [ selectedNodeIdx ] . InputPorts . Count ;
if ( inputIdxCount > 0 )
{
for ( int inputIdx = 0 ; inputIdx < inputIdxCount ; inputIdx + + )
{
if ( selectedNodes [ selectedNodeIdx ] . InputPorts [ inputIdx ] . IsConnected )
{
int nodeIdx = selectedNodes [ selectedNodeIdx ] . InputPorts [ inputIdx ] . ExternalReferences [ 0 ] . NodeId ;
if ( nodeIdx > - 1 )
{
ParentNode node = GetNode ( nodeIdx ) ;
if ( node ! = null & & UIUtils . CheckUndoNode ( node ) )
{
extraNodes . Add ( node ) ;
}
}
}
}
}
}
// Check outputs
if ( selectedNodes [ selectedNodeIdx ] ! = null )
{
int outputIdxCount = selectedNodes [ selectedNodeIdx ] . OutputPorts . Count ;
if ( outputIdxCount > 0 )
{
for ( int outputIdx = 0 ; outputIdx < outputIdxCount ; outputIdx + + )
{
int inputIdxCount = selectedNodes [ selectedNodeIdx ] . OutputPorts [ outputIdx ] . ExternalReferences . Count ;
if ( inputIdxCount > 0 )
{
for ( int inputIdx = 0 ; inputIdx < inputIdxCount ; inputIdx + + )
{
int nodeIdx = selectedNodes [ selectedNodeIdx ] . OutputPorts [ outputIdx ] . ExternalReferences [ inputIdx ] . NodeId ;
if ( nodeIdx > - 1 )
{
ParentNode node = GetNode ( nodeIdx ) ;
if ( UIUtils . CheckUndoNode ( node ) )
{
extraNodes . Add ( node ) ;
}
}
}
}
}
}
}
}
UIUtils . ClearUndoHelper ( ) ;
//Record deleted nodes
UIUtils . MarkUndoAction ( ) ;
UndoUtils . RegisterCompleteObjectUndo ( ParentWindow , Constants . UndoDeleteNodeId ) ;
UndoUtils . RegisterCompleteObjectUndo ( this , Constants . UndoDeleteNodeId ) ;
UndoUtils . RecordObjects ( selectedNodes , Constants . UndoDeleteNodeId ) ;
UndoUtils . RecordObjects ( extraNodes . ToArray ( ) , Constants . UndoDeleteNodeId ) ;
//Record deleting connections
for ( int i = 0 ; i < selectedNodes . Length ; i + + )
{
CurrentOutputNode . Selected = false ;
selectedNodes [ i ] . Alive = false ;
DeleteAllConnectionFromNode ( selectedNodes [ i ] , false , true , true ) ;
}
//Delete
DeleteNodesOnArray ( ref selectedNodes ) ;
extraNodes . Clear ( ) ;
extraNodes = null ;
EditorUtility . SetDirty ( ParentWindow ) ;
ParentWindow . ForceRepaint ( ) ;
}
public void DeleteMarkedForDeletionNodes ( )
{
UndoableDeleteSelectedNodes ( m_markedForDeletion ) ;
m_markedForDeletion . Clear ( ) ;
IsDirty = true ;
//bool invalidateMasterNode = false;
//int count = m_markedForDeletion.Count;
//for ( int nodeIdx = 0; nodeIdx < count; nodeIdx++ )
//{
// ParentNode node = m_markedForDeletion[ nodeIdx ];
// if ( node.UniqueId == m_masterNodeId )
// {
// invalidateMasterNode = true;
// }
// else
// {
// if ( node.Selected )
// {
// m_selectedNodes.Remove( node );
// node.Selected = false;
// }
// DestroyNode( node );
// }
//}
//if ( invalidateMasterNode )
//{
// CurrentMasterNode.Selected = false;
//}
////Clear all references
//m_markedForDeletion.Clear();
//IsDirty = true;
}
public void DestroyNode ( int nodeId )
{
ParentNode node = GetNode ( nodeId ) ;
DestroyNode ( node ) ;
}
public void DestroyNode ( ParentNode node , bool registerUndo = true , bool destroyMasterNode = false )
{
if ( node = = null )
{
UIUtils . ShowMessage ( "Attempting to destroying a inexistant node " , MessageSeverity . Warning ) ;
return ;
}
if ( node . ConnStatus = = NodeConnectionStatus . Connected & & ! m_checkSelectedWireHighlights )
{
ResetHighlightedWires ( ) ;
m_checkSelectedWireHighlights = true ;
}
//TODO: check better placement of this code (reconnects wires from wire nodes)
//if ( node.GetType() == typeof( WireNode ) )
//{
// if ( node.InputPorts[ 0 ].ExternalReferences != null && node.InputPorts[ 0 ].ExternalReferences.Count > 0 )
// {
// WireReference backPort = node.InputPorts[ 0 ].ExternalReferences[ 0 ];
// for ( int i = 0; i < node.OutputPorts[ 0 ].ExternalReferences.Count; i++ )
// {
// UIUtils.CurrentWindow.ConnectInputToOutput( node.OutputPorts[ 0 ].ExternalReferences[ i ].NodeId, node.OutputPorts[ 0 ].ExternalReferences[ i ].PortId, backPort.NodeId, backPort.PortId );
// }
// }
//}
if ( destroyMasterNode | | ( node . UniqueId ! = m_masterNodeId & & ! ( node is TemplateMultiPassMasterNode ) /*!m_multiPassMasterNodes.HasNode( node.UniqueId )*/ ) )
{
m_nodeGrid . RemoveNodeFromGrid ( node , false ) ;
//Send Deactivation signal if active
if ( node . ConnStatus = = NodeConnectionStatus . Connected )
{
node . DeactivateNode ( - 1 , true ) ;
}
//Invalidate references
//Invalidate input references
for ( int inputPortIdx = 0 ; inputPortIdx < node . InputPorts . Count ; inputPortIdx + + )
{
InputPort inputPort = node . InputPorts [ inputPortIdx ] ;
if ( inputPort . IsConnected )
{
for ( int wireIdx = 0 ; wireIdx < inputPort . ExternalReferences . Count ; wireIdx + + )
{
WireReference inputReference = inputPort . ExternalReferences [ wireIdx ] ;
ParentNode outputNode = GetNode ( inputReference . NodeId ) ;
outputNode . GetOutputPortByUniqueId ( inputReference . PortId ) . InvalidateConnection ( inputPort . NodeId , inputPort . PortId ) ;
outputNode . OnOutputPortDisconnected ( inputReference . PortId ) ;
}
inputPort . InvalidateAllConnections ( ) ;
}
}
//Invalidate output reference
for ( int outputPortIdx = 0 ; outputPortIdx < node . OutputPorts . Count ; outputPortIdx + + )
{
OutputPort outputPort = node . OutputPorts [ outputPortIdx ] ;
if ( outputPort . IsConnected )
{
for ( int wireIdx = 0 ; wireIdx < outputPort . ExternalReferences . Count ; wireIdx + + )
{
WireReference outputReference = outputPort . ExternalReferences [ wireIdx ] ;
ParentNode outnode = GetNode ( outputReference . NodeId ) ;
if ( outnode ! = null )
{
outnode . GetInputPortByUniqueId ( outputReference . PortId ) . InvalidateConnection ( outputPort . NodeId , outputPort . PortId ) ;
outnode . OnInputPortDisconnected ( outputReference . PortId ) ;
}
}
outputPort . InvalidateAllConnections ( ) ;
}
}
//Remove node from main list
//UndoUtils.RecordObject( node, "Destroying node " + ( node.Attributes != null? node.Attributes.Name: node.GetType().ToString() ) );
if ( registerUndo )
{
UIUtils . MarkUndoAction ( ) ;
UndoUtils . RegisterCompleteObjectUndo ( ParentWindow , Constants . UndoDeleteNodeId ) ;
UndoUtils . RegisterCompleteObjectUndo ( this , Constants . UndoDeleteNodeId ) ;
node . RecordObjectOnDestroy ( Constants . UndoDeleteNodeId ) ;
}
if ( OnNodeRemovedEvent ! = null )
OnNodeRemovedEvent ( node ) ;
m_nodes . Remove ( node ) ;
m_nodesDict . Remove ( node . UniqueId ) ;
node . Destroy ( ) ;
if ( registerUndo )
{
UndoUtils . DestroyObjectImmediate ( node ) ;
}
else
{
DestroyImmediate ( node ) ;
2026-03-14 03:13:10 -04:00
}
2025-07-08 14:28:40 -04:00
IsDirty = true ;
m_markToReOrder = true ;
}
//else if( node.UniqueId == m_masterNodeId && node.GetType() == typeof(FunctionOutput) )
//{
// Debug.Log( "Attempting to destroy a output node" );
// DeselectNode( node );
// UIUtils.ShowMessage( "Attempting to destroy a output node" );
//}
else
{
TemplateMultiPassMasterNode templateMasterNode = node as TemplateMultiPassMasterNode ;
if ( templateMasterNode ! = null & & templateMasterNode . InvalidNode )
{
DestroyNode ( node , false , true ) ;
return ;
}
DeselectNode ( node ) ;
UIUtils . ShowMessage ( "Attempting to destroy a master node" ) ;
}
}
void AddToSelectedNodes ( ParentNode node )
{
node . Selected = true ;
m_selectedNodes . Add ( node ) ;
node . OnNodeStoppedMovingEvent + = OnNodeFinishMoving ;
if ( node . ConnStatus = = NodeConnectionStatus . Connected )
{
HighlightWiresStartingNode ( node ) ;
}
}
void RemoveFromSelectedNodes ( ParentNode node )
{
node . Selected = false ;
m_selectedNodes . Remove ( node ) ;
node . OnNodeStoppedMovingEvent - = OnNodeFinishMoving ;
}
public void SelectNode ( ParentNode node , bool append , bool reorder )
{
if ( node = = null )
return ;
if ( append )
{
if ( ! m_selectedNodes . Contains ( node ) )
{
AddToSelectedNodes ( node ) ;
}
}
else
{
DeSelectAll ( ) ;
AddToSelectedNodes ( node ) ;
}
if ( reorder & & ! node . ReorderLocked )
{
m_nodes . Remove ( node ) ;
m_nodes . Add ( node ) ;
m_markToReOrder = true ;
}
}
public void MultipleSelection ( Rect selectionArea , bool appendSelection = true )
{
if ( ! appendSelection )
{
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
if ( selectionArea . Overlaps ( m_nodes [ i ] . Position , true ) )
{
RemoveFromSelectedNodes ( m_nodes [ i ] ) ;
}
}
m_markedToDeSelect = false ;
ResetHighlightedWires ( ) ;
}
else
{
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
if ( ! m_nodes [ i ] . Selected & & selectionArea . Overlaps ( m_nodes [ i ] . Position , true ) )
{
AddToSelectedNodes ( m_nodes [ i ] ) ;
}
}
}
// reorder nodes and highlight them
for ( int i = 0 ; i < m_selectedNodes . Count ; i + + )
{
if ( ! m_selectedNodes [ i ] . ReorderLocked )
{
m_nodes . Remove ( m_selectedNodes [ i ] ) ;
m_nodes . Add ( m_selectedNodes [ i ] ) ;
m_markToReOrder = true ;
if ( m_selectedNodes [ i ] . ConnStatus = = NodeConnectionStatus . Connected )
{
HighlightWiresStartingNode ( m_selectedNodes [ i ] ) ;
}
}
}
}
public void SelectAll ( )
{
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
if ( ! m_nodes [ i ] . Selected )
AddToSelectedNodes ( m_nodes [ i ] ) ;
}
}
public void SelectMasterNode ( )
{
if ( m_masterNodeId ! = Constants . INVALID_NODE_ID )
{
SelectNode ( CurrentMasterNode , false , false ) ;
}
}
public void SelectOutputNode ( )
{
if ( m_masterNodeId ! = Constants . INVALID_NODE_ID )
{
SelectNode ( CurrentOutputNode , false , false ) ;
}
}
public void DeselectNode ( int nodeId )
{
ParentNode node = GetNode ( nodeId ) ;
if ( node )
{
m_selectedNodes . Remove ( node ) ;
node . Selected = false ;
}
}
public void DeselectNode ( ParentNode node )
{
m_selectedNodes . Remove ( node ) ;
node . Selected = false ;
PropagateHighlightDeselection ( node ) ;
}
public void DeSelectAll ( )
{
m_markedToDeSelect = false ;
for ( int i = 0 ; i < m_selectedNodes . Count ; i + + )
{
m_selectedNodes [ i ] . Selected = false ;
m_selectedNodes [ i ] . OnNodeStoppedMovingEvent - = OnNodeFinishMoving ;
}
m_selectedNodes . Clear ( ) ;
ResetHighlightedWires ( ) ;
}
public void AssignMasterNode ( )
{
if ( m_selectedNodes . Count = = 1 )
{
OutputNode newOutputNode = m_selectedNodes [ 0 ] as OutputNode ;
MasterNode newMasterNode = newOutputNode as MasterNode ;
if ( newOutputNode ! = null )
{
if ( m_masterNodeId ! = Constants . INVALID_NODE_ID & & m_masterNodeId ! = newOutputNode . UniqueId )
{
OutputNode oldOutputNode = GetNode ( m_masterNodeId ) as OutputNode ;
MasterNode oldMasterNode = oldOutputNode as MasterNode ;
if ( oldOutputNode ! = null )
{
oldOutputNode . IsMainOutputNode = false ;
if ( oldMasterNode ! = null )
{
oldMasterNode . ClearUpdateEvents ( ) ;
}
}
}
m_masterNodeId = newOutputNode . UniqueId ;
newOutputNode . IsMainOutputNode = true ;
if ( newMasterNode ! = null )
{
newMasterNode . OnMaterialUpdatedEvent + = OnMaterialUpdatedEvent ;
newMasterNode . OnShaderUpdatedEvent + = OnShaderUpdatedEvent ;
}
}
}
IsDirty = true ;
}
public void AssignMasterNode ( OutputNode node , bool onlyUpdateGraphId )
{
AssignMasterNode ( node . UniqueId , onlyUpdateGraphId ) ;
MasterNode masterNode = node as MasterNode ;
if ( masterNode ! = null )
{
masterNode . OnMaterialUpdatedEvent + = OnMaterialUpdatedEvent ;
masterNode . OnShaderUpdatedEvent + = OnShaderUpdatedEvent ;
}
}
public void AssignMasterNode ( int nodeId , bool onlyUpdateGraphId )
{
if ( nodeId < 0 | | m_masterNodeId = = nodeId )
return ;
if ( m_masterNodeId > Constants . INVALID_NODE_ID )
{
OutputNode oldOutputNode = ( GetNode ( nodeId ) as OutputNode ) ;
MasterNode oldMasterNode = oldOutputNode as MasterNode ;
if ( oldOutputNode ! = null )
{
oldOutputNode . IsMainOutputNode = false ;
if ( oldMasterNode ! = null )
{
oldMasterNode . ClearUpdateEvents ( ) ;
}
}
}
if ( onlyUpdateGraphId )
{
m_masterNodeId = nodeId ;
}
else
{
OutputNode outputNode = ( GetNode ( nodeId ) as OutputNode ) ;
if ( outputNode ! = null )
{
outputNode . IsMainOutputNode = true ;
m_masterNodeId = nodeId ;
}
}
IsDirty = true ;
}
public void RefreshOnUndo ( )
{
if ( m_nodes ! = null )
{
int count = m_nodes . Count ;
for ( int i = 0 ; i < count ; i + + )
{
if ( m_nodes [ i ] ! = null )
{
m_nodes [ i ] . RefreshOnUndo ( ) ;
}
}
}
}
public void DrawGrid ( DrawInfo drawInfo )
{
m_nodeGrid . DrawGrid ( drawInfo ) ;
}
public float MaxNodeDist
{
get { return m_nodeGrid . MaxNodeDist ; }
}
public List < ParentNode > GetNodesInGrid ( Vector2 transformedMousePos )
{
return m_nodeGrid . GetNodesOn ( transformedMousePos ) ;
}
public void FireMasterNode ( Shader selectedShader )
{
( GetNode ( m_masterNodeId ) as MasterNode ) . Execute ( selectedShader ) ;
}
public Shader FireMasterNode ( string pathname , bool isFullPath )
{
return ( GetNode ( m_masterNodeId ) as MasterNode ) . Execute ( pathname , isFullPath ) ;
}
private void ForceSignalPropagationOnMasterNodeInternal ( UsageListTemplateMultiPassMasterNodes masterNodes )
{
int mpCount = masterNodes . Count ;
for ( int i = 0 ; i < mpCount ; i + + )
{
masterNodes . NodesList [ i ] . GenerateSignalPropagation ( ) ;
}
}
public void ForceSignalPropagationOnMasterNode ( )
{
if ( m_multiPassMasterNodes . Count > 0 )
{
ForceSignalPropagationOnMasterNodeInternal ( m_multiPassMasterNodes ) ;
for ( int i = 0 ; i < m_lodMultiPassMasterNodes . Count ; i + + )
{
ForceSignalPropagationOnMasterNodeInternal ( m_lodMultiPassMasterNodes [ i ] ) ;
}
}
else if ( CurrentOutputNode ! = null )
CurrentOutputNode . GenerateSignalPropagation ( ) ;
List < FunctionOutput > allOutputs = m_functionOutputNodes . NodesList ;
for ( int i = 0 ; i < allOutputs . Count ; i + + )
{
allOutputs [ i ] . GenerateSignalPropagation ( ) ;
}
//List<RegisterLocalVarNode> localVarNodes = m_localVarNodes.NodesList;
//int count = localVarNodes.Count;
//for( int i = 0; i < count; i++ )
//{
// localVarNodes[ i ].GenerateSignalPropagation();
//}
}
public void UpdateShaderOnMasterNode ( Shader newShader )
{
MasterNode mainMasterNode = ( GetNode ( m_masterNodeId ) as MasterNode ) ;
if ( mainMasterNode = = null )
{
Debug . LogError ( "No Master Node was detected. Aborting update!" ) ;
return ;
}
mainMasterNode . UpdateFromShader ( newShader ) ;
if ( HasLODs )
{
int passIdx = ( ( TemplateMultiPassMasterNode ) mainMasterNode ) . PassIdx ;
for ( int i = 0 ; i < m_lodMultiPassMasterNodes . Count ; i + + )
{
if ( m_lodMultiPassMasterNodes . Count ! = 0 & & m_lodMultiPassMasterNodes [ i ] . NodesList . Count > 0 )
{
if ( m_lodMultiPassMasterNodes [ i ] . NodesList [ passIdx ] ! = null )
{
m_lodMultiPassMasterNodes [ i ] . NodesList [ passIdx ] . UpdateFromShader ( newShader ) ;
}
else
{
Debug . LogError ( "Null master node detected. Aborting update!" ) ;
return ;
}
}
else break ;
}
}
}
public void CopyValuesFromMaterial ( Material material )
{
Material currMaterial = CurrentMaterial ;
if ( currMaterial = = material )
{
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
m_nodes [ i ] . ForceUpdateFromMaterial ( material ) ;
}
}
}
public void UpdateMaterialOnMasterNode ( Material material )
{
MasterNode mainMasterNode = ( GetNode ( m_masterNodeId ) as MasterNode ) ;
mainMasterNode . UpdateMasterNodeMaterial ( material ) ;
if ( HasLODs )
{
int passIdx = ( ( TemplateMultiPassMasterNode ) mainMasterNode ) . PassIdx ;
for ( int i = 0 ; i < m_lodMultiPassMasterNodes . Count ; i + + )
{
if ( m_lodMultiPassMasterNodes . Count ! = 0 & & m_lodMultiPassMasterNodes [ i ] . NodesList . Count > 0 )
{
m_lodMultiPassMasterNodes [ i ] . NodesList [ passIdx ] . UpdateMasterNodeMaterial ( material ) ;
}
else break ;
}
}
}
public void UpdateMaterialOnPropertyNodes ( Material material )
{
int propertyCount = m_propertyNodes . Count ;
for ( int i = 0 ; i < propertyCount ; i + + )
{
m_propertyNodes . NodesList [ i ] . UpdateMaterial ( material ) ;
}
}
public void SetMaterialModeOnGraph ( Material mat , bool fetchMaterialValues = true )
{
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
m_nodes [ i ] . SetMaterialMode ( mat , fetchMaterialValues ) ;
}
}
public ParentNode CheckNodeAt ( Vector3 pos , bool checkForRMBIgnore = false )
{
ParentNode selectedNode = null ;
// this is checked on the inverse order to give priority to nodes that are drawn on top ( last on the list )
for ( int i = m_nodes . Count - 1 ; i > - 1 ; i - - )
{
if ( m_nodes [ i ] . Contains ( pos ) )
{
if ( checkForRMBIgnore )
{
if ( ! m_nodes [ i ] . RMBIgnore )
{
selectedNode = m_nodes [ i ] ;
break ;
}
}
else
{
selectedNode = m_nodes [ i ] ;
break ;
}
}
}
return selectedNode ;
}
public void ResetNodesLocalVariables ( )
{
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
m_nodes [ i ] . Reset ( ) ;
m_nodes [ i ] . ResetOutputLocals ( ) ;
FunctionNode fnode = m_nodes [ i ] as FunctionNode ;
if ( fnode ! = null )
{
if ( fnode . Function ! = null )
fnode . FunctionGraph . ResetNodesLocalVariables ( ) ;
}
}
}
public void ResetNodesLocalVariablesIfNot ( MasterNodePortCategory category )
{
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
m_nodes [ i ] . Reset ( ) ;
m_nodes [ i ] . ResetOutputLocalsIfNot ( category ) ;
FunctionNode fnode = m_nodes [ i ] as FunctionNode ;
if ( fnode ! = null )
{
if ( fnode . Function ! = null )
fnode . FunctionGraph . ResetNodesLocalVariablesIfNot ( category ) ;
}
}
}
public void ResetNodesLocalVariables ( ParentNode node )
{
if ( node is GetLocalVarNode )
{
GetLocalVarNode localVarNode = node as GetLocalVarNode ;
if ( localVarNode . CurrentSelected ! = null )
{
node = localVarNode . CurrentSelected ;
}
}
node . Reset ( ) ;
node . ResetOutputLocals ( ) ;
int count = node . InputPorts . Count ;
for ( int i = 0 ; i < count ; i + + )
{
if ( node . InputPorts [ i ] . IsConnected )
{
ResetNodesLocalVariables ( m_nodesDict [ node . InputPorts [ i ] . GetConnection ( ) . NodeId ] ) ;
}
}
}
public void ResetNodesLocalVariablesIfNot ( ParentNode node , MasterNodePortCategory category )
{
if ( node is GetLocalVarNode )
{
GetLocalVarNode localVarNode = node as GetLocalVarNode ;
if ( localVarNode . CurrentSelected ! = null )
{
node = localVarNode . CurrentSelected ;
}
}
node . Reset ( ) ;
node . ResetOutputLocalsIfNot ( category ) ;
int count = node . InputPorts . Count ;
for ( int i = 0 ; i < count ; i + + )
{
if ( node . InputPorts [ i ] . IsConnected )
{
ResetNodesLocalVariablesIfNot ( m_nodesDict [ node . InputPorts [ i ] . GetConnection ( ) . NodeId ] , category ) ;
}
}
}
public override string ToString ( )
{
string dump = ( "Parent Graph \n" ) ;
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
dump + = ( m_nodes [ i ] + "\n" ) ;
}
return dump ;
}
public void OrderNodesByGraphDepth ( )
{
if ( CurrentMasterNode ! = null )
{
//CurrentMasterNode.SetupNodeCategories();
int count = m_nodes . Count ;
for ( int i = 0 ; i < count ; i + + )
{
if ( m_nodes [ i ] . ConnStatus = = NodeConnectionStatus . Island )
{
m_nodes [ i ] . CalculateCustomGraphDepth ( ) ;
}
}
}
else
{
//TODO: remove this dynamic list
List < OutputNode > allOutputs = new List < OutputNode > ( ) ;
for ( int i = 0 ; i < AllNodes . Count ; i + + )
{
OutputNode temp = AllNodes [ i ] as OutputNode ;
if ( temp ! = null )
allOutputs . Add ( temp ) ;
}
for ( int j = 0 ; j < allOutputs . Count ; j + + )
{
allOutputs [ j ] . SetupNodeCategories ( ) ;
int count = m_nodes . Count ;
for ( int i = 0 ; i < count ; i + + )
{
if ( m_nodes [ i ] . ConnStatus = = NodeConnectionStatus . Island )
{
m_nodes [ i ] . CalculateCustomGraphDepth ( ) ;
}
}
}
}
2026-03-14 03:13:10 -04:00
2025-07-08 14:28:40 -04:00
// @diogo: replaced Sort() with OrderBy() for stable sorting
m_nodes = m_nodes . OrderByDescending ( s = > s . GraphDepth ) . ToList ( ) ;
}
public void WriteToString ( ref string nodesInfo , ref string connectionsInfo )
{
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
m_nodes [ i ] . FullWriteToString ( ref nodesInfo , ref connectionsInfo ) ;
IOUtils . AddLineTerminator ( ref nodesInfo ) ;
}
}
public void Reset ( )
{
SaveIsDirty = false ;
IsDirty = false ;
}
public void OnBeforeSerialize ( )
{
//DeSelectAll();
}
public void OnAfterDeserialize ( )
{
m_afterDeserializeFlag = true ;
}
public void CleanCorruptedNodes ( )
{
for ( int i = 0 ; i < m_nodes . Count ; i + + )
{
if ( ( object ) m_nodes [ i ] = = null )
{
m_nodes . RemoveAt ( i ) ;
CleanCorruptedNodes ( ) ;
}
}
}
public void OnDuplicateEventWrapper ( )
{
if ( OnDuplicateEvent ! = null )
{
AmplifyShaderEditorWindow temp = UIUtils . CurrentWindow ;
UIUtils . CurrentWindow = ParentWindow ;
OnDuplicateEvent ( ) ;
UIUtils . CurrentWindow = temp ;
}
}
public ParentNode CreateNode ( AmplifyShaderFunction shaderFunction , bool registerUndo , int nodeId = - 1 , bool addLast = true )
{
FunctionNode newNode = ScriptableObject . CreateInstance < FunctionNode > ( ) ;
if ( newNode )
{
newNode . ContainerGraph = this ;
newNode . CommonInit ( shaderFunction , nodeId ) ;
newNode . UniqueId = nodeId ;
AddNode ( newNode , nodeId < 0 , addLast , registerUndo ) ;
}
return newNode ;
}
public ParentNode CreateNode ( AmplifyShaderFunction shaderFunction , bool registerUndo , Vector2 pos , int nodeId = - 1 , bool addLast = true )
{
ParentNode newNode = CreateNode ( shaderFunction , registerUndo , nodeId , addLast ) ;
if ( newNode )
{
newNode . Vec2Position = pos ;
}
return newNode ;
}
public TemplateMultiPassMasterNode CreateMultipassMasterNode ( int lodId , bool registerUndo , int nodeId = - 1 , bool addLast = true )
{
TemplateMultiPassMasterNode newNode = ScriptableObject . CreateInstance < TemplateMultiPassMasterNode > ( ) ;
if ( newNode )
{
newNode . LODIndex = lodId ;
newNode . ContainerGraph = this ;
if ( newNode . IsStubNode )
{
TemplateMultiPassMasterNode stubNode = newNode . ExecuteStubCode ( ) as TemplateMultiPassMasterNode ;
ScriptableObject . DestroyImmediate ( newNode , true ) ;
newNode = stubNode ;
}
else
{
newNode . UniqueId = nodeId ;
AddNode ( newNode , nodeId < 0 , addLast , registerUndo ) ;
}
}
return newNode ;
}
public ParentNode CreateNode ( System . Type type , bool registerUndo , int nodeId = - 1 , bool addLast = true )
{
ParentNode newNode = ScriptableObject . CreateInstance ( type ) as ParentNode ;
if ( newNode )
{
newNode . ContainerGraph = this ;
if ( newNode . IsStubNode )
{
ParentNode stubNode = newNode . ExecuteStubCode ( ) ;
ScriptableObject . DestroyImmediate ( newNode , true ) ;
newNode = stubNode ;
}
else
{
newNode . UniqueId = nodeId ;
AddNode ( newNode , nodeId < 0 , addLast , registerUndo ) ;
}
}
return newNode ;
}
public ParentNode CreateNode ( System . Type type , bool registerUndo , Vector2 pos , int nodeId = - 1 , bool addLast = true )
{
ParentNode newNode = CreateNode ( type , registerUndo , nodeId , addLast ) ;
if ( newNode )
{
newNode . Vec2Position = pos ;
}
return newNode ;
}
public void FireMasterNodeReplacedEvent ( )
{
MasterNode masterNode = CurrentMasterNode ;
int count = m_nodes . Count ;
for ( int i = 0 ; i < count ; i + + )
{
if ( m_nodes [ i ] . UniqueId ! = m_masterNodeId )
{
m_nodes [ i ] . OnMasterNodeReplaced ( masterNode ) ;
}
}
}
//Used over shader functions to propagate signal into their graphs
public void FireMasterNodeReplacedEvent ( MasterNode masterNode )
{
int count = m_nodes . Count ;
for ( int i = 0 ; i < count ; i + + )
{
if ( m_nodes [ i ] . UniqueId ! = masterNode . UniqueId )
{
m_nodes [ i ] . OnMasterNodeReplaced ( masterNode ) ;
}
}
}
public void CrossCheckTemplateNodes ( TemplateDataParent templateData , List < TemplateMultiPassMasterNode > mpNodesList , int lodId )
{
/*Paulo*/
DeSelectAll ( ) ;
TemplateMultiPassMasterNode newMasterNode = null ;
Dictionary < string , TemplateReplaceHelper > nodesDict = new Dictionary < string , TemplateReplaceHelper > ( ) ;
int mpNodeCount = mpNodesList . Count ;
for ( int i = 0 ; i < mpNodeCount ; i + + )
{
string masterNodeId = mpNodesList [ i ] . InvalidNode ? mpNodesList [ i ] . OriginalPassName + "ASEInvalidMasterNode" + i : mpNodesList [ i ] . OriginalPassName ;
nodesDict . Add ( masterNodeId , new TemplateReplaceHelper ( mpNodesList [ i ] ) ) ;
}
TemplateMultiPassMasterNode currMasterNode = GetNode ( m_masterNodeId ) as TemplateMultiPassMasterNode ;
TemplateMultiPass multipassData = templateData as TemplateMultiPass ;
m_currentSRPType = multipassData . SubShaders [ 0 ] . Modules . SRPType ;
bool sortTemplatesNodes = false ;
Vector2 currentPosition = currMasterNode . Vec2Position ;
for ( int subShaderIdx = 0 ; subShaderIdx < multipassData . SubShaders . Count ; subShaderIdx + + )
{
for ( int passIdx = 0 ; passIdx < multipassData . SubShaders [ subShaderIdx ] . Passes . Count ; passIdx + + )
{
string currPassName = multipassData . SubShaders [ subShaderIdx ] . Passes [ passIdx ] . PassNameContainer . Data ;
if ( nodesDict . ContainsKey ( currPassName ) )
{
bool wasMainNode = nodesDict [ currPassName ] . MasterNode . IsMainOutputNode ;
currentPosition . y + = nodesDict [ currPassName ] . MasterNode . Position . height + 10 ;
nodesDict [ currPassName ] . Used = true ;
nodesDict [ currPassName ] . MasterNode . SetTemplate ( multipassData , false , false , subShaderIdx , passIdx , SetTemplateSource . NewShader ) ;
if ( wasMainNode & & ! nodesDict [ currPassName ] . MasterNode . IsMainOutputNode )
{
nodesDict [ currPassName ] . MasterNode . ReleaseResources ( ) ;
}
else if ( ! wasMainNode & & nodesDict [ currPassName ] . MasterNode . IsMainOutputNode )
{
newMasterNode = nodesDict [ currPassName ] . MasterNode ;
}
}
else
{
sortTemplatesNodes = true ;
TemplateMultiPassMasterNode masterNode = CreateMultipassMasterNode ( lodId , false ) ;
if ( multipassData . SubShaders [ subShaderIdx ] . Passes [ passIdx ] . IsMainPass )
{
newMasterNode = masterNode ;
currMasterNode . ReleaseResources ( ) ;
}
masterNode . Vec2Position = currentPosition ;
masterNode . SetTemplate ( multipassData , true , true , subShaderIdx , passIdx , SetTemplateSource . NewShader ) ;
//currentPosition.y += masterNode.HeightEstimate + 10;
}
}
}
foreach ( KeyValuePair < string , TemplateReplaceHelper > kvp in nodesDict )
{
if ( ! kvp . Value . Used )
DestroyNode ( kvp . Value . MasterNode , false , true ) ;
}
nodesDict . Clear ( ) ;
if ( newMasterNode ! = null )
{
if ( lodId = = - 1 )
{
m_masterNodeId = newMasterNode . UniqueId ;
}
newMasterNode . OnMaterialUpdatedEvent + = OnMaterialUpdatedEvent ;
newMasterNode . OnShaderUpdatedEvent + = OnShaderUpdatedEvent ;
newMasterNode . IsMainOutputNode = true ;
}
if ( sortTemplatesNodes )
{
mpNodesList . Sort ( ( x , y ) = > ( x . PassIdx . CompareTo ( y . PassIdx ) ) ) ;
}
}
public void OnRefreshLinkedPortsComplete ( )
{
OnRefreshLinkedPortsCompleteInternal ( m_multiPassMasterNodes ) ;
for ( int i = 0 ; i < m_lodMultiPassMasterNodes . Count ; i + + )
{
OnRefreshLinkedPortsCompleteInternal ( m_lodMultiPassMasterNodes [ i ] ) ;
}
}
private void OnRefreshLinkedPortsCompleteInternal ( UsageListTemplateMultiPassMasterNodes masterNodes )
{
int mpCount = masterNodes . Count ;
for ( int i = 0 ; i < mpCount ; i + + )
{
masterNodes . NodesList [ i ] . OnRefreshLinkedPortsComplete ( ) ;
}
}
public void RefreshLinkedMasterNodes ( bool optionsUpdate = false )
{
if ( DebugConsoleWindow . DeveloperMode )
Debug . Log ( "Refresh linked master nodes" ) ;
RefreshLinkedMasterNodesInternal ( m_multiPassMasterNodes , optionsUpdate ) ;
for ( int i = 0 ; i < m_lodMultiPassMasterNodes . Count ; i + + )
{
RefreshLinkedMasterNodesInternal ( m_lodMultiPassMasterNodes [ i ] , optionsUpdate ) ;
}
}
private void RefreshLinkedMasterNodesInternal ( UsageListTemplateMultiPassMasterNodes masterNodes , bool optionsUpdate )
{
int mpCount = masterNodes . Count ;
if ( mpCount > 1 )
{
Dictionary < string , List < InputPort > > registeredLinks = new Dictionary < string , List < InputPort > > ( ) ;
for ( int i = 0 ; i < mpCount ; i + + )
{
CheckLinkedPorts ( ref registeredLinks , masterNodes . NodesList [ mpCount - 1 - i ] ) ;
}
foreach ( KeyValuePair < string , List < InputPort > > kvp in registeredLinks )
{
int linkCount = kvp . Value . Count ;
if ( linkCount = = 1 )
{
kvp . Value [ 0 ] . Visible = true ;
}
else
{
kvp . Value [ 0 ] . Visible = true ;
for ( int i = 1 ; i < linkCount ; i + + )
{
kvp . Value [ i ] . SetExternalLink ( kvp . Value [ 0 ] . NodeId , kvp . Value [ 0 ] . PortId ) ;
kvp . Value [ i ] . Visible = false ;
}
}
kvp . Value . Clear ( ) ;
}
registeredLinks . Clear ( ) ;
registeredLinks = null ;
}
masterNodes . NodesList . Sort ( ( x , y ) = > ( x . SubShaderIdx * 1000 + x . PassIdx ) . CompareTo ( y . SubShaderIdx * 1000 + y . PassIdx ) ) ;
masterNodes . UpdateNodeArr ( ) ;
m_parentWindow . TemplatesManagerInstance . ResetOptionsSetupData ( ) ;
for ( int i = 0 ; i < mpCount ; i + + )
{
int visiblePorts = 0 ;
for ( int j = 0 ; j < masterNodes . NodesList [ i ] . InputPorts . Count ; j + + )
{
if ( masterNodes . NodesList [ i ] . InputPorts [ j ] . Visible )
{
visiblePorts + + ;
}
}
if ( masterNodes . NodesList [ i ] . VisiblePorts ! = visiblePorts )
{
masterNodes . NodesList [ i ] . VisiblePorts = visiblePorts ;
ForceRepositionCheck = true ;
}
masterNodes . NodesList [ i ] . Docking = visiblePorts < = 0 ;
if ( optionsUpdate )
{
masterNodes . NodesList [ i ] . ForceOptionsRefresh ( ) ;
}
}
}
void CheckLinkedPorts ( ref Dictionary < string , List < InputPort > > registeredLinks , TemplateMultiPassMasterNode masterNode )
{
if ( masterNode . HasLinkPorts )
{
int inputCount = masterNode . InputPorts . Count ;
for ( int i = 0 ; i < inputCount ; i + + )
{
if ( ! string . IsNullOrEmpty ( masterNode . InputPorts [ i ] . ExternalLinkId ) )
{
string linkId = masterNode . InputPorts [ i ] . ExternalLinkId ;
if ( ! registeredLinks . ContainsKey ( masterNode . InputPorts [ i ] . ExternalLinkId ) )
{
registeredLinks . Add ( linkId , new List < InputPort > ( ) ) ;
}
if ( masterNode . IsMainOutputNode )
{
registeredLinks [ linkId ] . Insert ( 0 , masterNode . InputPorts [ i ] ) ;
}
else
{
registeredLinks [ linkId ] . Add ( masterNode . InputPorts [ i ] ) ;
}
}
else
{
masterNode . InputPorts [ i ] . Visible = true ;
}
}
}
else
{
int inputCount = masterNode . InputPorts . Count ;
for ( int i = 0 ; i < inputCount ; i + + )
{
masterNode . InputPorts [ i ] . Visible = true ;
}
}
2026-03-14 03:13:10 -04:00
2025-07-08 14:28:40 -04:00
}
public MasterNode ReplaceMasterNode ( AvailableShaderTypes newType , bool writeDefaultData = false , TemplateDataParent templateData = null )
{
DeSelectAll ( ) ;
ResetNodeConnStatus ( ) ;
MasterNode newMasterNode = null ;
List < TemplateMultiPassMasterNode > nodesToDelete = null ;
int mpNodeCount = m_multiPassMasterNodes . NodesList . Count ;
if ( mpNodeCount > 0 )
{
nodesToDelete = new List < TemplateMultiPassMasterNode > ( ) ;
for ( int i = 0 ; i < mpNodeCount ; i + + )
{
if ( m_multiPassMasterNodes . NodesList [ i ] . UniqueId ! = m_masterNodeId )
{
nodesToDelete . Add ( m_multiPassMasterNodes . NodesList [ i ] ) ;
}
}
for ( int lod = 0 ; lod < m_lodMultiPassMasterNodes . Count ; lod + + )
{
int lodNodeCount = m_lodMultiPassMasterNodes [ lod ] . Count ;
for ( int i = 0 ; i < lodNodeCount ; i + + )
{
nodesToDelete . Add ( m_lodMultiPassMasterNodes [ lod ] . NodesList [ i ] ) ;
}
}
}
MasterNode currMasterNode = GetNode ( m_masterNodeId ) as MasterNode ;
if ( currMasterNode ! = null )
{
currMasterNode . ReleaseResources ( ) ;
}
bool refreshLinkedMasterNodes = false ;
switch ( newType )
{
default :
case AvailableShaderTypes . SurfaceShader :
{
CurrentCanvasMode = NodeAvailability . SurfaceShader ;
m_currentSRPType = TemplateSRPType . BiRP ;
newMasterNode = CreateNode ( typeof ( StandardSurfaceOutputNode ) , false ) as MasterNode ;
}
break ;
case AvailableShaderTypes . Template :
{
CurrentCanvasMode = NodeAvailability . TemplateShader ;
if ( templateData . TemplateType = = TemplateDataType . LegacySinglePass )
{
newMasterNode = CreateNode ( typeof ( TemplateMasterNode ) , false ) as MasterNode ;
( newMasterNode as TemplateMasterNode ) . SetTemplate ( templateData as TemplateData , writeDefaultData , false ) ;
m_currentSRPType = TemplateSRPType . BiRP ;
}
else
{
/*Paulo*/
TemplateMultiPass multipassData = templateData as TemplateMultiPass ;
m_currentSRPType = multipassData . SubShaders [ 0 ] . Modules . SRPType ;
Vector2 currentPosition = currMasterNode . Vec2Position ;
for ( int subShaderIdx = 0 ; subShaderIdx < multipassData . SubShaders . Count ; subShaderIdx + + )
{
for ( int passIdx = 0 ; passIdx < multipassData . SubShaders [ subShaderIdx ] . Passes . Count ; passIdx + + )
{
TemplateMultiPassMasterNode masterNode = CreateNode ( typeof ( TemplateMultiPassMasterNode ) , false ) as TemplateMultiPassMasterNode ;
if ( multipassData . SubShaders [ subShaderIdx ] . Passes [ passIdx ] . IsMainPass )
{
newMasterNode = masterNode ;
ParentWindow . IsShaderFunctionWindow = false ;
CurrentCanvasMode = NodeAvailability . TemplateShader ;
}
masterNode . Vec2Position = currentPosition ;
masterNode . SetTemplate ( multipassData , true , true , subShaderIdx , passIdx , SetTemplateSource . NewShader ) ;
//currentPosition.y += masterNode.HeightEstimate + 10;
}
}
refreshLinkedMasterNodes = true ;
//RefreshLinkedMasterNodes();
}
}
break ;
}
if ( currMasterNode ! = null )
{
newMasterNode . CopyFrom ( currMasterNode ) ;
m_masterNodeId = - 1 ;
DestroyNode ( currMasterNode , false , true ) ;
}
if ( nodesToDelete ! = null )
{
for ( int i = 0 ; i < nodesToDelete . Count ; i + + )
{
DestroyNode ( nodesToDelete [ i ] , false , true ) ;
}
nodesToDelete . Clear ( ) ;
}
m_masterNodeId = newMasterNode . UniqueId ;
if ( refreshLinkedMasterNodes )
RefreshLinkedMasterNodes ( true ) ;
newMasterNode . OnMaterialUpdatedEvent + = OnMaterialUpdatedEvent ;
newMasterNode . OnShaderUpdatedEvent + = OnShaderUpdatedEvent ;
newMasterNode . IsMainOutputNode = true ;
OnRefreshLinkedPortsComplete ( ) ;
FullCleanUndoStack ( ) ;
return newMasterNode ;
}
private void RepositionTemplateNodes ( MasterNode newMasterNode )
{
m_forceRepositionCheck = false ;
int dockedElementsBefore = 0 ;
int dockedElementsAfter = 0 ;
int masterIndex = 0 ;
bool foundMaster = false ;
for ( int i = 0 ; i < MultiPassMasterNodes . Count ; i + + )
{
if ( MultiPassMasterNodes . NodesList [ i ] . UniqueId = = m_masterNodeId )
{
foundMaster = true ;
masterIndex = i ;
}
if ( ! MultiPassMasterNodes . NodesList [ i ] . IsInvisible & & MultiPassMasterNodes . NodesList [ i ] . Docking )
{
if ( foundMaster )
dockedElementsAfter + + ;
else
dockedElementsBefore + + ;
}
}
if ( dockedElementsBefore > 0 )
{
newMasterNode . UseSquareNodeTitle = true ;
}
for ( int i = masterIndex - 1 ; i > = 0 ; i - - )
{
float forwardTracking = 0 ;
for ( int j = i + 1 ; j < = masterIndex ; j + + )
{
if ( ! MultiPassMasterNodes . NodesList [ i ] . IsInvisible & & ! MultiPassMasterNodes . NodesList [ j ] . Docking )
{
forwardTracking + = MultiPassMasterNodes . NodesList [ j ] . HeightEstimate + 10 ;
}
}
MasterNode node = MultiPassMasterNodes . NodesList [ i ] ;
node . Vec2Position = new Vector2 ( node . Vec2Position . x , newMasterNode . Position . y - forwardTracking - 33 * ( dockedElementsBefore ) ) ;
}
for ( int i = masterIndex + 1 ; i < MultiPassMasterNodes . Count ; i + + )
{
if ( MultiPassMasterNodes . NodesList [ i ] . UniqueId = = newMasterNode . UniqueId | | MultiPassMasterNodes . NodesList [ i ] . Docking )
continue ;
float backTracking = 0 ;
for ( int j = i - 1 ; j > = masterIndex ; j - - )
{
if ( ! MultiPassMasterNodes . NodesList [ i ] . IsInvisible & & ! MultiPassMasterNodes . NodesList [ j ] . Docking )
{
backTracking + = MultiPassMasterNodes . NodesList [ j ] . HeightEstimate + 10 ;
}
}
MasterNode node = MultiPassMasterNodes . NodesList [ i ] ;
node . Vec2Position = new Vector2 ( node . Vec2Position . x , newMasterNode . Position . y + backTracking + 33 * ( dockedElementsAfter ) ) ;
}
}
public void CreateNewEmpty ( string name )
{
CleanNodes ( ) ;
if ( m_masterNodeDefaultType = = null )
m_masterNodeDefaultType = typeof ( StandardSurfaceOutputNode ) ;
MasterNode newMasterNode = CreateNode ( m_masterNodeDefaultType , false ) as MasterNode ;
newMasterNode . SetName ( name ) ;
m_masterNodeId = newMasterNode . UniqueId ;
ParentWindow . IsShaderFunctionWindow = false ;
CurrentCanvasMode = NodeAvailability . SurfaceShader ;
newMasterNode . OnMaterialUpdatedEvent + = OnMaterialUpdatedEvent ;
newMasterNode . OnShaderUpdatedEvent + = OnShaderUpdatedEvent ;
newMasterNode . IsMainOutputNode = true ;
LoadedShaderVersion = VersionInfo . FullNumber ;
}
public void CreateNewEmptyTemplate ( string templateGUID )
{
CleanNodes ( ) ;
TemplateDataParent templateData = m_parentWindow . TemplatesManagerInstance . GetTemplate ( templateGUID ) ;
if ( templateData . TemplateType = = TemplateDataType . LegacySinglePass )
{
TemplateMasterNode newMasterNode = CreateNode ( typeof ( TemplateMasterNode ) , false ) as TemplateMasterNode ;
m_masterNodeId = newMasterNode . UniqueId ;
ParentWindow . IsShaderFunctionWindow = false ;
CurrentCanvasMode = NodeAvailability . TemplateShader ;
m_currentSRPType = TemplateSRPType . BiRP ;
newMasterNode . OnMaterialUpdatedEvent + = OnMaterialUpdatedEvent ;
newMasterNode . OnShaderUpdatedEvent + = OnShaderUpdatedEvent ;
newMasterNode . IsMainOutputNode = true ;
newMasterNode . SetTemplate ( templateData as TemplateData , true , true ) ;
}
else
{
/*Paulo*/
TemplateMultiPass multipassData = templateData as TemplateMultiPass ;
m_currentSRPType = multipassData . SubShaders [ 0 ] . Modules . SRPType ;
Vector2 currentPosition = Vector2 . zero ;
for ( int subShaderIdx = 0 ; subShaderIdx < multipassData . SubShaders . Count ; subShaderIdx + + )
{
for ( int passIdx = 0 ; passIdx < multipassData . SubShaders [ subShaderIdx ] . Passes . Count ; passIdx + + )
{
TemplateMultiPassMasterNode newMasterNode = CreateNode ( typeof ( TemplateMultiPassMasterNode ) , false ) as TemplateMultiPassMasterNode ;
if ( multipassData . SubShaders [ subShaderIdx ] . Passes [ passIdx ] . IsMainPass )
{
m_masterNodeId = newMasterNode . UniqueId ;
ParentWindow . IsShaderFunctionWindow = false ;
CurrentCanvasMode = NodeAvailability . TemplateShader ;
newMasterNode . OnMaterialUpdatedEvent + = OnMaterialUpdatedEvent ;
newMasterNode . OnShaderUpdatedEvent + = OnShaderUpdatedEvent ;
newMasterNode . IsMainOutputNode = true ;
}
newMasterNode . Vec2Position = currentPosition ;
newMasterNode . SetTemplate ( multipassData , true , true , subShaderIdx , passIdx , SetTemplateSource . NewShader ) ;
//currentPosition.y += newMasterNode.HeightEstimate + 10;
}
}
2026-03-14 03:13:10 -04:00
2025-07-08 14:28:40 -04:00
RefreshLinkedMasterNodes ( false ) ;
OnRefreshLinkedPortsComplete ( ) ;
}
LoadedShaderVersion = VersionInfo . FullNumber ;
}
public void CreateNewEmptyFunction ( AmplifyShaderFunction shaderFunction )
{
CleanNodes ( ) ;
FunctionOutput newOutputNode = CreateNode ( typeof ( FunctionOutput ) , false ) as FunctionOutput ;
m_masterNodeId = newOutputNode . UniqueId ;
ParentWindow . IsShaderFunctionWindow = true ;
CurrentCanvasMode = NodeAvailability . ShaderFunction ;
newOutputNode . IsMainOutputNode = true ;
}
public void ForceCategoryRefresh ( ) { m_forceCategoryRefresh = true ; }
public void RefreshExternalReferences ( )
{
int count = m_nodes . Count ;
for ( int i = 0 ; i < count ; i + + )
{
m_nodes [ i ] . RefreshExternalReferences ( ) ;
}
}
public Vector2 SelectedNodesCentroid
{
get
{
if ( m_selectedNodes . Count = = 0 )
return Vector2 . zero ;
Vector2 pos = new Vector2 ( 0 , 0 ) ;
for ( int i = 0 ; i < m_selectedNodes . Count ; i + + )
{
pos + = m_selectedNodes [ i ] . Vec2Position ;
}
pos / = m_selectedNodes . Count ;
return pos ;
}
}
public void AddVirtualTextureCount ( )
{
m_virtualTextureCount + = 1 ;
}
public void RemoveVirtualTextureCount ( )
{
m_virtualTextureCount - = 1 ;
if ( m_virtualTextureCount < 0 )
{
Debug . LogWarning ( "Invalid virtual texture count" ) ;
}
}
2026-03-14 03:13:10 -04:00
public bool HasPassWithTag ( int lod , string tagKey , string tagValue = "" )
{
var passes = GetMultiPassMasterNodes ( lod ) ;
foreach ( TemplateMultiPassMasterNode pass in passes )
{
if ( pass . PassModule ! = null & & pass . PassModule . TagsHelper ! = null & & pass . PassModule . TagsHelper . HasTag ( tagKey , tagValue ) )
{
return true ;
}
}
return false ;
}
2025-07-08 14:28:40 -04:00
public bool HasVirtualTexture { get { return m_virtualTextureCount > 0 ; } }
public void AddInstancePropertyCount ( )
{
m_instancePropertyCount + = 1 ;
// Debug.Log( "AddInstancePropertyCount "+this.GetInstanceID() + " " + m_instancePropertyCount );
}
public void RemoveInstancePropertyCount ( )
{
m_instancePropertyCount - = 1 ;
// Debug.Log( "RemoveInstancePropertyCount " + this.GetInstanceID() + " " + m_instancePropertyCount );
if ( m_instancePropertyCount < 0 )
{
Debug . LogWarning ( "Invalid property instance count" ) ;
}
}
public int InstancePropertyCount { get { return m_instancePropertyCount ; } set { m_instancePropertyCount = value ; } }
public bool IsInstancedShader { get { return m_instancePropertyCount > 0 ; } }
public void AddNormalDependentCount ( ) { m_normalDependentCount + = 1 ; }
public void RemoveNormalDependentCount ( )
{
m_normalDependentCount - = 1 ;
if ( m_normalDependentCount < 0 )
{
Debug . LogWarning ( "Invalid normal dependentCount count" ) ;
}
}
public void SetModeFromMasterNode ( )
{
MasterNode masterNode = CurrentMasterNode ;
if ( masterNode ! = null )
{
switch ( masterNode . CurrentMasterNodeCategory )
{
default :
case AvailableShaderTypes . SurfaceShader :
{
if ( masterNode is StandardSurfaceOutputNode )
CurrentCanvasMode = ParentWindow . CurrentNodeAvailability ;
else
CurrentCanvasMode = NodeAvailability . SurfaceShader ;
}
break ;
case AvailableShaderTypes . Template :
{
CurrentCanvasMode = NodeAvailability . TemplateShader ;
}
break ;
}
}
else
{
CurrentCanvasMode = NodeAvailability . SurfaceShader ;
}
}
public void MarkToDelete ( ParentNode node )
{
m_markedForDeletion . Add ( node ) ;
}
public bool IsMasterNode ( ParentNode node )
{
return ( node . UniqueId = = m_masterNodeId ) | |
m_multiPassMasterNodes . HasNode ( node . UniqueId ) ;
}
public TemplateMultiPassMasterNode GetMainMasterNodeOfLOD ( int lod )
{
if ( lod = = - 1 )
return CurrentMasterNode as TemplateMultiPassMasterNode ;
return m_lodMultiPassMasterNodes [ lod ] . NodesList . Find ( x = > x . IsMainOutputNode ) ;
}
public TemplateMultiPassMasterNode GetMasterNodeOfPass ( string passName , int lod )
{
if ( lod = = - 1 )
return m_multiPassMasterNodes . NodesList . Find ( x = > x . PassName . Equals ( passName ) ) ;
return m_lodMultiPassMasterNodes [ lod ] . NodesList . Find ( x = > x . PassName . Equals ( passName ) ) ;
}
public void ForceMultiPassMasterNodesRefresh ( )
{
int mainOutputId = 0 ;
int count = m_multiPassMasterNodes . Count ;
for ( int i = 0 ; i < count ; i + + )
{
m_multiPassMasterNodes . NodesList [ i ] . ForceTemplateRefresh ( ) ;
if ( m_multiPassMasterNodes . NodesList [ i ] . IsMainOutputNode )
mainOutputId = i ;
}
int lodCount = m_lodMultiPassMasterNodes . Count ;
for ( int i = 0 ; i < lodCount ; i + + )
{
if ( m_lodMultiPassMasterNodes [ i ] ! = null )
{
count = m_lodMultiPassMasterNodes [ i ] . Count ;
for ( int j = 0 ; j < count ; j + + )
{
m_lodMultiPassMasterNodes [ i ] . NodesList [ j ] . ForceTemplateRefresh ( ) ;
}
}
}
m_multiPassMasterNodes . NodesList [ mainOutputId ] . CheckTemplateChanges ( ) ;
}
public void SetLateOptionsRefresh ( )
{
m_lateOptionsRefresh = true ;
}
public void CreateLodMasterNodes ( TemplateMultiPass templateMultiPass , int index , Vector2 initialPosition )
{
for ( int lod = 0 ; lod < m_lodMultiPassMasterNodes . Count ; lod + + )
{
if ( m_lodMultiPassMasterNodes [ lod ] . Count = = 0 )
{
TemplateMultiPassMasterNode reference = CurrentMasterNode as TemplateMultiPassMasterNode ;
int shaderLod = - 1 ;
if ( lod = = 0 )
{
shaderLod = reference . ShaderLOD - MasterNodeLODIncrement ;
}
else
{
//index == -2 is when user clicks on +/- buttons over the foldout UI
if ( index = = - 2 )
{
shaderLod = m_lodMultiPassMasterNodes [ lod - 1 ] . NodesList [ reference . PassIdx ] . ShaderLOD - MasterNodeLODIncrement ;
}
//index == -1 is when user clicks on + button over the main lod master node
else if ( index = = - 1 )
{
int mainShaderLOD = m_lodMultiPassMasterNodes [ 0 ] . NodesList [ reference . PassIdx ] . ShaderLOD ;
shaderLod = ( reference . ShaderLOD + mainShaderLOD ) / 2 ;
}
else
{
if ( m_lodMultiPassMasterNodes [ index ] . Count > 0 )
{
if ( m_lodMultiPassMasterNodes [ index + 1 ] . Count > 0 )
{
shaderLod = ( m_lodMultiPassMasterNodes [ index ] . NodesList [ reference . PassIdx ] . ShaderLOD +
m_lodMultiPassMasterNodes [ index + 1 ] . NodesList [ reference . PassIdx ] . ShaderLOD ) / 2 ;
}
else
{
shaderLod = m_lodMultiPassMasterNodes [ index ] . NodesList [ reference . PassIdx ] . ShaderLOD - MasterNodeLODIncrement ;
}
}
}
}
int nodeId = 0 ;
TemplateMultiPassMasterNode mainMasterNode = null ;
for ( int subShaderIdx = 0 ; subShaderIdx < templateMultiPass . SubShaders . Count ; subShaderIdx + + )
{
for ( int passIdx = 0 ; passIdx < templateMultiPass . SubShaders [ subShaderIdx ] . Passes . Count ; passIdx + + )
{
TemplateMultiPassMasterNode masterNode = ScriptableObject . CreateInstance ( typeof ( TemplateMultiPassMasterNode ) ) as TemplateMultiPassMasterNode ;
masterNode . LODIndex = lod ;
masterNode . ContainerGraph = this ;
masterNode . Vec2Position = initialPosition ;
AddNode ( masterNode , true ) ;
masterNode . SetTemplate ( templateMultiPass , true , true , subShaderIdx , passIdx , SetTemplateSource . NewShader ) ;
masterNode . CopyOptionsFrom ( m_multiPassMasterNodes . NodesList [ nodeId + + ] ) ;
if ( masterNode . IsMainOutputNode | | ( subShaderIdx = = 0 & & passIdx = = 0 ) )
{
masterNode . SetShaderLODValueAndLabel ( shaderLod ) ;
mainMasterNode = masterNode ;
}
}
}
mainMasterNode . ForceOptionsRefresh ( ) ;
SortLODMasterNodes ( ) ;
if ( OnLODMasterNodesAddedEvent ! = null )
{
OnLODMasterNodesAddedEvent ( lod ) ;
}
TemplateMultiPassMasterNode lodMainMasterNode = CurrentMasterNode as TemplateMultiPassMasterNode ;
lodMainMasterNode . SetShaderLODValueAndLabel ( lodMainMasterNode . ShaderLOD ) ;
return ;
}
}
}
public void DestroyLodMasterNodes ( int index )
{
if ( index < 0 )
{
for ( int lod = m_lodMultiPassMasterNodes . Count - 1 ; lod > = 0 ; lod - - )
{
if ( m_lodMultiPassMasterNodes [ lod ] . Count > 0 )
{
while ( m_lodMultiPassMasterNodes [ lod ] . Count > 0 )
{
DestroyNode ( m_lodMultiPassMasterNodes [ lod ] . NodesList [ 0 ] , false , true ) ;
}
break ;
}
}
}
else
{
while ( m_lodMultiPassMasterNodes [ index ] . Count > 0 )
{
DestroyNode ( m_lodMultiPassMasterNodes [ index ] . NodesList [ 0 ] , false , true ) ;
}
}
SortLODMasterNodes ( ) ;
TemplateMultiPassMasterNode lodMainMasterNode = CurrentMasterNode as TemplateMultiPassMasterNode ;
lodMainMasterNode . SetShaderLODValueAndLabel ( lodMainMasterNode . ShaderLOD ) ;
}
public void SortLODMasterNodes ( )
{
int idx = ( CurrentMasterNode as TemplateMultiPassMasterNode ) . PassIdx ;
m_lodMultiPassMasterNodes . Sort ( ( x , y ) = >
{
if ( x . Count > 0 )
{
if ( y . Count > 0 )
{
return - x . NodesList [ idx ] . ShaderLOD . CompareTo ( y . NodesList [ idx ] . ShaderLOD ) ;
}
else
{
return - 1 ;
}
}
else
{
if ( y . Count > 0 )
{
return 1 ;
}
}
return 0 ;
} ) ;
2026-03-14 03:13:10 -04:00
2025-07-08 14:28:40 -04:00
for ( int lodIdx = 0 ; lodIdx < m_lodMultiPassMasterNodes . Count ; lodIdx + + )
{
for ( int nodeIdx = 0 ; nodeIdx < m_lodMultiPassMasterNodes [ lodIdx ] . Count ; nodeIdx + + )
{
m_lodMultiPassMasterNodes [ lodIdx ] . NodesList [ nodeIdx ] . LODIndex = lodIdx ;
2026-03-14 03:13:10 -04:00
}
2025-07-08 14:28:40 -04:00
}
}
public List < TemplateMultiPassMasterNode > GetMultiPassMasterNodes ( int lod )
{
if ( lod = = - 1 )
return m_multiPassMasterNodes . NodesList ;
return m_lodMultiPassMasterNodes [ lod ] . NodesList ;
}
public bool IsNormalDependent { get { return m_normalDependentCount > 0 ; } }
public void MarkToDeselect ( ) { m_markedToDeSelect = true ; }
public void MarkToSelect ( int nodeId ) { m_markToSelect = nodeId ; }
public void MarkWireHighlights ( ) { m_checkSelectedWireHighlights = true ; }
public List < ParentNode > SelectedNodes { get { return m_selectedNodes ; } }
public List < ParentNode > MarkedForDeletionNodes { get { return m_markedForDeletion ; } }
public int CurrentMasterNodeId { get { return m_masterNodeId ; } set { m_masterNodeId = value ; } }
public Shader CurrentShader
{
get
{
MasterNode masterNode = GetNode ( m_masterNodeId ) as MasterNode ;
if ( masterNode ! = null )
return masterNode . CurrentShader ;
return null ;
}
}
public Material CurrentMaterial
{
get
{
MasterNode masterNode = GetNode ( m_masterNodeId ) as MasterNode ;
if ( masterNode ! = null )
return masterNode . CurrentMaterial ;
return null ;
}
}
2026-03-14 03:13:10 -04:00
2025-07-08 14:28:40 -04:00
public NodeAvailability CurrentCanvasMode { get { return m_currentCanvasMode ; } set { m_currentCanvasMode = value ; ParentWindow . LateRefreshAvailableNodes ( ) ; } }
public OutputNode CurrentOutputNode { get { return GetNode ( m_masterNodeId ) as OutputNode ; } }
public FunctionOutput CurrentFunctionOutput { get { return GetNode ( m_masterNodeId ) as FunctionOutput ; } }
public MasterNode CurrentMasterNode { get { return GetNode ( m_masterNodeId ) as MasterNode ; } }
public StandardSurfaceOutputNode CurrentStandardSurface { get { return GetNode ( m_masterNodeId ) as StandardSurfaceOutputNode ; } }
public List < ParentNode > AllNodes { get { return m_nodes ; } }
public int NodeCount { get { return m_nodes . Count ; } }
//public List<ParentNode> VisibleNodes { get { return m_visibleNodes; } }
public int NodeClicked
{
set { m_nodeClicked = value ; }
get { return m_nodeClicked ; }
}
public bool IsDirty
{
set { m_isDirty = value & & UIUtils . DirtyMask ; }
get
{
bool value = m_isDirty ;
m_isDirty = false ;
return value ;
}
}
public bool SaveIsDirty
{
set { m_saveIsDirty = value & & UIUtils . DirtyMask ; }
get { return m_saveIsDirty ; }
}
public int LoadedShaderVersion
{
get { return m_loadedShaderVersion ; }
set { m_loadedShaderVersion = value ; }
}
public AmplifyShaderFunction CurrentShaderFunction
{
get { if ( CurrentFunctionOutput ! = null ) return CurrentFunctionOutput . Function ; else return null ; }
set { if ( CurrentFunctionOutput ! = null ) CurrentFunctionOutput . Function = value ; }
}
public bool HasUnConnectedNodes { get { return m_hasUnConnectedNodes ; } }
public UsageListSamplerNodes SamplerNodes { get { return m_samplerNodes ; } }
public UsageListFloatIntNodes FloatIntNodes { get { return m_floatNodes ; } }
public UsageListTexturePropertyNodes TexturePropertyNodes { get { return m_texturePropertyNodes ; } }
public UsageListTextureArrayNodes TextureArrayNodes { get { return m_textureArrayNodes ; } }
public UsageListPropertyNodes PropertyNodes { get { return m_propertyNodes ; } }
public UsageListPropertyNodes RawPropertyNodes { get { return m_rawPropertyNodes ; } }
public UsageListCustomExpressionsOnFunctionMode CustomExpressionOnFunctionMode { get { return m_customExpressionsOnFunctionMode ; } }
public UsageListStaticSwitchNodes StaticSwitchNodes { get { return m_staticSwitchNodes ; } }
2026-03-14 03:13:10 -04:00
public UsageListToggleSwitchNodes ToggleSwitchNodes { get { return m_toggleSwitchNodes ; } }
2025-07-08 14:28:40 -04:00
public UsageListScreenColorNodes ScreenColorNodes { get { return m_screenColorNodes ; } }
public UsageListRegisterLocalVarNodes LocalVarNodes { get { return m_localVarNodes ; } }
public UsageListGlobalArrayNodes GlobalArrayNodes { get { return m_globalArrayNodes ; } }
public UsageListFunctionInputNodes FunctionInputNodes { get { return m_functionInputNodes ; } }
public UsageListFunctionNodes FunctionNodes { get { return m_functionNodes ; } }
public UsageListFunctionOutputNodes FunctionOutputNodes { get { return m_functionOutputNodes ; } }
public UsageListFunctionSwitchNodes FunctionSwitchNodes { get { return m_functionSwitchNodes ; } }
public UsageListFunctionSwitchCopyNodes FunctionSwitchCopyNodes { get { return m_functionSwitchCopyNodes ; } }
public UsageListTemplateMultiPassMasterNodes MultiPassMasterNodes { get { return m_multiPassMasterNodes ; } set { m_multiPassMasterNodes = value ; } }
public List < UsageListTemplateMultiPassMasterNodes > LodMultiPassMasternodes { get { return m_lodMultiPassMasterNodes ; } }
public PrecisionType CurrentPrecision
{
get { return m_currentPrecision ; }
set { m_currentPrecision = value ; }
}
public NodeLOD LodLevel
{
get { return m_lodLevel ; }
}
public List < ParentNode > NodePreviewList { get { return m_nodePreviewList ; } set { m_nodePreviewList = value ; } }
public void SetGraphId ( int id )
{
m_graphId = id ;
}
public int GraphId
{
get { return m_graphId ; }
}
public AmplifyShaderEditorWindow ParentWindow
{
get { return m_parentWindow ; }
set { m_parentWindow = value ; }
}
public bool ChangedLightingModel
{
get { return m_changedLightingModel ; }
set { m_changedLightingModel = value ; }
}
public bool ForceRepositionCheck
{
get { return m_forceRepositionCheck ; }
set { m_forceRepositionCheck = value ; }
}
public bool IsLoading { get { return m_isLoading ; } set { m_isLoading = value ; } }
public bool IsDuplicating { get { return m_isDuplicating ; } set { m_isDuplicating = value ; } }
public TemplateSRPType CurrentSRPType { get { return m_currentSRPType ; } set { m_currentSRPType = value ; } }
public bool IsSRP { get { return m_currentSRPType = = TemplateSRPType . URP | | m_currentSRPType = = TemplateSRPType . HDRP ; } }
public bool IsHDRP { get { return m_currentSRPType = = TemplateSRPType . HDRP ; } }
public bool IsLWRP { get { return m_currentSRPType = = TemplateSRPType . URP ; } }
public bool IsStandardSurface { get { return GetNode ( m_masterNodeId ) is StandardSurfaceOutputNode ; } }
2026-03-14 03:13:10 -04:00
public bool SamplingMacros {
2025-07-08 14:28:40 -04:00
get { return m_samplingThroughMacros ; }
2026-03-14 03:13:10 -04:00
set { m_samplingThroughMacros = value ; }
2025-07-08 14:28:40 -04:00
}
public bool HasLODs { get { return m_lodMultiPassMasterNodes [ 0 ] . Count > 0 ; } }
//public bool HasLodMultiPassNodes
//{
// get
// {
// for( int i = 0; i < m_lodMultiPassMasterNodes.Count; i++ )
// {
// if( m_lodMultiPassMasterNodes[ i ].Count > 0 )
// return true;
// }
// return false;
// }
//}
}
}