// Amplify Shader Editor - Visual Shader Editing Tool // Copyright (c) Amplify Creations, Lda using UnityEngine; using UnityEditor; using System; 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 m_nodes = new List(); // 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 m_lodMultiPassMasterNodes; [SerializeField] private UsageListCustomExpressionsOnFunctionMode m_customExpressionsOnFunctionMode = new UsageListCustomExpressionsOnFunctionMode(); [SerializeField] private UsageListStaticSwitchNodes m_staticSwitchNodes = new UsageListStaticSwitchNodes(); [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.BuiltIn; //private List m_visibleNodes = new List(); private List m_nodePreviewList = new List(); private Dictionary m_nodesDict = new Dictionary(); [NonSerialized] private List m_selectedNodes = new List(); [NonSerialized] private List m_markedForDeletion = new List(); [SerializeField] private List m_highlightedWires = new List(); private System.Type m_masterNodeDefaultType; [SerializeField] private List m_internalTemplateNodesList = new List(); private Dictionary m_internalTemplateNodesDict = new Dictionary(); 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 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() { Undo.undoRedoPerformed += OnUndoRedoCallback; m_normalDependentCount = 0; m_nodes = new List(); 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; 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( MaxLodAmount ); for( int i = 0; i < MaxLodAmount; i++ ) { m_lodMultiPassMasterNodes.Add( new UsageListTemplateMultiPassMasterNodes() ); } m_selectedNodes = new List(); m_markedForDeletion = new List(); m_highlightedWires = new List(); m_validNodeId = 0; IsDirty = false; SaveIsDirty = false; m_masterNodeDefaultType = typeof( StandardSurfaceOutputNode ); m_bezierReferences = new List( MaxBezierReferences ); for( int i = 0; i < MaxBezierReferences; i++ ) { m_bezierReferences.Add( new WireBezierReference() ); } } private void OnUndoRedoCallback() { DeSelectAll(); } private void OnEnable() { hideFlags = HideFlags.HideAndDontSave; m_nodeGrid = new NodeGrid(); m_internalTemplateNodesDict = new Dictionary(); m_nodesDict = new Dictionary(); 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(); 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 unusedNodes = new List(); 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 list = new List(); 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 ) { Undo.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(); 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(); } 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 ) { // even though node is deselected, it receives wire highlight from a previous one 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() { Undo.ClearUndo( this ); int count = m_nodes.Count; for( int i = 0; i < count; i++ ) { if( m_nodes[ i ] != null ) { Undo.ClearUndo( m_nodes[ i ] ); } } } public void FullRegisterOnUndoStack() { Undo.RegisterCompleteObjectUndo( this, Constants.UndoRegisterFullGrapId ); int count = m_nodes.Count; for( int i = 0; i < count; i++ ) { if( m_nodes[ i ] != null ) { Undo.RegisterCompleteObjectUndo( m_nodes[ i ], Constants.UndoRegisterFullGrapId ); } } } public void CheckPropertiesAutoRegister( ref MasterNodeDataCollector dataCollector ) { List propertyNodesList = m_rawPropertyNodes.NodesList; int propertyCount = propertyNodesList.Count; for( int i = 0; i < propertyCount; i++ ) { propertyNodesList[ i ].CheckIfAutoRegister( ref dataCollector ); } propertyNodesList = null; List globalArrayNodeList = m_globalArrayNodes.NodesList; int globalArrayCount = globalArrayNodeList.Count; for( int i = 0; i < globalArrayCount; i++ ) { globalArrayNodeList[ i ].CheckIfAutoRegister( ref dataCollector ); } globalArrayNodeList = null; //List propertyNodesList = m_propertyNodes.NodesList; //int propertyCount = propertyNodesList.Count; //for( int i = 0; i < propertyCount; i++ ) //{ // propertyNodesList[ i ].CheckIfAutoRegister( ref dataCollector ); //} //propertyNodesList = null; //List 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; 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(); 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() { Undo.undoRedoPerformed -= OnUndoRedoCallback; for( int i = 0; i < m_nodes.Count; i++ ) { if( m_nodes[ i ] != null ) { Undo.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; 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(); Undo.RegisterCompleteObjectUndo( ParentWindow, Constants.UndoCreateNodeId ); Undo.RegisterCompleteObjectUndo( this, Constants.UndoCreateNodeId ); Undo.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(); break; case WirePortDataType.FLOAT4: propertyNode = CreateInstance(); break; case WirePortDataType.COLOR: propertyNode = CreateInstance(); break; case WirePortDataType.INT: propertyNode = CreateInstance(); break; case WirePortDataType.SAMPLER1D: case WirePortDataType.SAMPLER2D: case WirePortDataType.SAMPLER3D: case WirePortDataType.SAMPLERCUBE: case WirePortDataType.SAMPLER2DARRAY: propertyNode = CreateInstance(); break; default: return; } propertyNode.PropertyNameFromTemplate( data ); // Create a negative unique Id to separate it from // the regular ids on the main nodes list // 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 // Unique Id must be already set at this point to properly // 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() { m_nodes.Sort( ( x, y ) => x.Depth.CompareTo( y.Depth ) ); } 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 ); } //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(); //} // 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 ) node.OnNodeLayout( drawInfo ); 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 ) { if( ASEMaterialInspector.Instance != null ) { ASEMaterialInspector.Instance.Repaint(); } } 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 GetWireBezierListInPos( Vector2 position ) { List list = new List(); 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 ) //{ // Undo.RegisterCompleteObjectUndo( ParentWindow, Constants.UndoMoveNodesId ); // for ( int i = 0; i < m_selectedNodes.Count; i++ ) // { // if ( !m_selectedNodes[ i ].MovingInFrame ) // { // Undo.RecordObject( m_selectedNodes[ i ], Constants.UndoMoveNodesId ); // m_selectedNodes[ i ].Move( delta, snap ); // } // } // IsDirty = true; //} bool performUndo = delta.magnitude > 0.01f; if( performUndo ) { Undo.RegisterCompleteObjectUndo( ParentWindow, Constants.UndoMoveNodesId ); Undo.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() ) ) { 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(); Undo.RegisterCompleteObjectUndo( ParentWindow, Constants.UndoDeleteConnectionId ); Undo.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 nodeList ) { if( nodeList.Count == 0 ) return; List validNode = new List(); 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 extraNodes = new List(); 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(); Undo.RegisterCompleteObjectUndo( ParentWindow, Constants.UndoDeleteNodeId ); Undo.RegisterCompleteObjectUndo( this, Constants.UndoDeleteNodeId ); Undo.RecordObjects( selectedNodes, Constants.UndoDeleteNodeId ); Undo.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 //Undo.RecordObject( node, "Destroying node " + ( node.Attributes != null? node.Attributes.Name: node.GetType().ToString() ) ); if( registerUndo ) { UIUtils.MarkUndoAction(); Undo.RegisterCompleteObjectUndo( ParentWindow, Constants.UndoDeleteNodeId ); Undo.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 ) Undo.DestroyObjectImmediate( node ); else DestroyImmediate( node ); 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 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 allOutputs = m_functionOutputNodes.NodesList; for( int i = 0; i < allOutputs.Count; i++ ) { allOutputs[ i ].GenerateSignalPropagation(); } //List 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 allOutputs = new List(); 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(); } } } } m_nodes.Sort( ( x, y ) => { return y.GraphDepth.CompareTo( x.GraphDepth ); } ); } 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(); 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 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; 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 ) { /*Paulo*/ DeSelectAll(); TemplateMultiPassMasterNode newMasterNode = null; Dictionary nodesDict = new Dictionary(); int mpNodeCount = m_multiPassMasterNodes.NodesList.Count; for( int i = 0; i < mpNodeCount; i++ ) { nodesDict.Add( m_multiPassMasterNodes.NodesList[ i ].OriginalPassName, new TemplateReplaceHelper( m_multiPassMasterNodes.NodesList[ 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 = CreateNode( typeof( TemplateMultiPassMasterNode ), false ) as TemplateMultiPassMasterNode; 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 kvp in nodesDict ) { if( !kvp.Value.Used ) DestroyNode( kvp.Value.MasterNode, false, true ); } nodesDict.Clear(); if( newMasterNode != null ) { m_masterNodeId = newMasterNode.UniqueId; newMasterNode.OnMaterialUpdatedEvent += OnMaterialUpdatedEvent; newMasterNode.OnShaderUpdatedEvent += OnShaderUpdatedEvent; newMasterNode.IsMainOutputNode = true; } if( sortTemplatesNodes ) { m_multiPassMasterNodes.NodesList.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> registeredLinks = new Dictionary>(); for( int i = 0; i < mpCount; i++ ) { CheckLinkedPorts( ref registeredLinks, masterNodes.NodesList[ mpCount - 1 - i ] ); } foreach( KeyValuePair> 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> 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() ); } 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; } } } public MasterNode ReplaceMasterNode( AvailableShaderTypes newType, bool writeDefaultData = false, TemplateDataParent templateData = null ) { DeSelectAll(); ResetNodeConnStatus(); MasterNode newMasterNode = null; List nodesToDelete = null; int mpNodeCount = m_multiPassMasterNodes.NodesList.Count; if( mpNodeCount > 0 ) { nodesToDelete = new List(); 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.BuiltIn; 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.BuiltIn; } 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.BuiltIn; 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; } } 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" ); } } 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; }); 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; } } } public List 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 SelectedNodes { get { return m_selectedNodes; } } public List 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; } } 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 AllNodes { get { return m_nodes; } } public int NodeCount { get { return m_nodes.Count; } } //public List 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; } } 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 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 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.Lightweight || m_currentSRPType == TemplateSRPType.HD; } } public bool IsHDRP { get { return m_currentSRPType == TemplateSRPType.HD; } } public bool IsLWRP { get { return m_currentSRPType == TemplateSRPType.Lightweight; } } public bool IsStandardSurface { get { return GetNode( m_masterNodeId ) is StandardSurfaceOutputNode; } } public bool SamplingMacros { get { return m_samplingThroughMacros; } set { m_samplingThroughMacros = value; } } 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; // } //} } }