// Amplify Shader Editor - Visual Shader Editing Tool // Copyright (c) Amplify Creations, Lda using System; using System.Collections.Generic; using UnityEngine; using UnityEditor; namespace AmplifyShaderEditor { public enum PropertyType { Constant = 0, Property, InstancedProperty, Global } public enum VariableMode { Create = 0, Fetch } [Serializable] public class PropertyAttributes { public string Name; public string Attribute; public bool HasDeprecatedValue; public string DeprecatedValue; public PropertyAttributes( string name, string attribute , string deprecated = null ) { Name = name; Attribute = attribute; DeprecatedValue = deprecated; HasDeprecatedValue = deprecated != null; } } [Serializable] public class PropertyNode : ParentNode { private const string LongNameEnder = "... )"; protected int m_longNameSize = 200; //private const string InstancedPropertyWarning = "Instanced Property option shouldn't be used on official SRP templates as all property variables are already declared as instanced inside a CBuffer.\nPlease consider changing to Property option."; private const string TooltipFormatter = "{0}\n\nName: {1}\nValue: {2}"; private const string InvalidAttributeFormatter = "Attribute {0} not found on node {1}. Please click on this message to select node and review its attributes section"; protected string GlobalTypeWarningText = "Global variables must be set via a C# script using the Shader.SetGlobal{0}(...) method.\nPlease note that setting a global variable will affect all shaders which are using it."; private const string HybridInstancedStr = "Hybrid Instanced"; private const string AutoRegisterStr = "Auto-Register"; private const string IgnoreVarDeclarationStr = "Variable Mode"; private const string IsPropertyStr = "Is Property"; private const string PropertyNameStr = "Property Name"; private const string PropertyInspectorStr = "Name"; protected const string EnumsStr = "Enums"; protected const string CustomAttrStr = "Custom Attributes"; protected const string HeaderAttrStr = "Headers"; protected const string ParameterTypeStr = "Type"; private const string PropertyTextfieldControlName = "PropertyName"; private const string PropertyInspTextfieldControlName = "PropertyInspectorName"; private const string OrderIndexStr = "Order Index"; protected const double MaxTimestamp = 2; private const double MaxPropertyTimestamp = 2; private const double MaxGlobalFetchTimestamp = 2; protected readonly string[] LabelToolbarTitle = { "Material", "Default" }; protected readonly string[] EnumModesStr = { "Create Enums", "Use Engine Enum Class" }; protected readonly int[] EnumModeIntValues = { 0, 1 }; private const string FetchToCreateDuplicatesMsg = "Reverting property name from '{0}' to '{1}' as it is registered to another property node."; private const string FetchToCreateOnDuplicateNodeMsg = "Setting new property name '{0}' as '{1}' is registered to another property node."; private const string HeaderId = "Header"; private const string EnumId = "Enum"; [SerializeField] protected PropertyType m_currentParameterType; [SerializeField] private PropertyType m_lastParameterType; [SerializeField] protected string m_propertyName = string.Empty; [SerializeField] protected string m_propertyInspectorName = string.Empty; [SerializeField] protected string m_precisionString; protected bool m_drawPrecisionUI = true; [SerializeField] private int m_orderIndex = -1; [SerializeField] protected VariableMode m_variableMode = VariableMode.Create; [SerializeField] protected bool m_autoGlobalName = true; [SerializeField] protected bool m_hybridInstanced = false; [SerializeField] protected bool m_autoRegister = false; [SerializeField] protected bool m_registerPropertyOnInstancing = true; [SerializeField] private List m_enumNames = new List(); [SerializeField] private List m_enumValues = new List(); [SerializeField] private int m_enumCount = 0; [SerializeField] private int m_enumModeInt = 0; [SerializeField] private int m_customAttrCount = 0; [SerializeField] private List m_customAttr = new List(); [SerializeField] private bool m_hasHeaders = false; [SerializeField] private List m_headerAttributeValues = new List(); [SerializeField] private string m_enumClassName = string.Empty; private bool m_hasEnum = false; protected bool m_showTitleWhenNotEditing = true; private int m_orderIndexOffset = 0; protected bool m_drawAttributes = true; protected bool m_underscoredGlobal = false; protected bool m_globalDefaultBehavior = true; protected bool m_freeName; protected bool m_freeType; protected bool m_showVariableMode = false; protected bool m_propertyNameIsDirty; protected bool m_showAutoRegisterUI = true; protected bool m_showHybridInstancedUI = false; protected bool m_useVarSubtitle = false; protected bool m_propertyFromInspector; protected double m_propertyFromInspectorTimestamp; protected bool m_checkDuplicateProperty; protected double m_checkDuplicatePropertyTimestamp; protected double m_globalFetchTimestamp; protected bool m_delayedDirtyProperty; protected double m_delayedDirtyPropertyTimestamp; protected string m_defaultPropertyName; protected string m_oldName = string.Empty; private bool m_reRegisterName = false; protected bool m_allowPropertyDuplicates = false; //protected bool m_useCustomPrefix = false; protected string m_customPrefix = null; protected int m_propertyTab = 0; [SerializeField] private string m_uniqueName; // Property Attributes private const float ButtonLayoutWidth = 15; protected bool m_visibleAttribsFoldout; protected bool m_visibleEnumsFoldout; protected bool m_visibleCustomAttrFoldout; protected bool m_visibleHeaderAttrFoldout; protected List m_availableAttribs = new List(); private string[] m_availableAttribsArr; [SerializeField] private bool[] m_selectedAttribsArr; [SerializeField] protected List m_selectedAttribs = new List(); //Title editing protected bool m_isEditing; protected bool m_stopEditing; protected bool m_startEditing; protected double m_clickTime; protected double m_doubleClickTime = 0.3; private Rect m_titleClickArea; protected bool m_srpBatcherCompatible = false; protected bool m_excludeUniform = false; [SerializeField] private bool m_addGlobalToSRPBatcher = false; public PropertyNode() : base() { } public PropertyNode( int uniqueId, float x, float y, float width, float height ) : base( uniqueId, x, y, width, height ) { } protected override void CommonInit( int uniqueId ) { base.CommonInit( uniqueId ); m_textLabelWidth = 105; if( UIUtils.CurrentWindow != null && UIUtils.CurrentWindow.CurrentGraph != null ) m_orderIndex = UIUtils.GetPropertyNodeAmount(); m_currentParameterType = PropertyType.Constant; m_freeType = true; m_freeName = true; m_propertyNameIsDirty = true; m_customPrecision = true; m_availableAttribs.Add( new PropertyAttributes( "Hide in Inspector", "[HideInInspector]" ) ); m_availableAttribs.Add( new PropertyAttributes( "HDR", "[HDR]" ) ); m_availableAttribs.Add( new PropertyAttributes( "Gamma", "[Gamma]" ) ); m_availableAttribs.Add( new PropertyAttributes( "Per Renderer Data", "[PerRendererData]" ) ); m_availableAttribs.Add( new PropertyAttributes( "Header", "[Header]" ) ); } public override void AfterCommonInit() { base.AfterCommonInit(); if( PaddingTitleLeft == 0 && m_freeType ) { PaddingTitleLeft = Constants.PropertyPickerWidth + Constants.IconsLeftRightMargin; if( PaddingTitleRight == 0 ) PaddingTitleRight = Constants.PropertyPickerWidth + Constants.IconsLeftRightMargin; } m_hasLeftDropdown = m_freeType; } protected void BeginDelayedDirtyProperty() { m_delayedDirtyProperty = true; m_delayedDirtyPropertyTimestamp = EditorApplication.timeSinceStartup; } public void CheckDelayedDirtyProperty() { if( m_delayedDirtyProperty ) { if( ( EditorApplication.timeSinceStartup - m_delayedDirtyPropertyTimestamp ) > MaxPropertyTimestamp ) { m_delayedDirtyProperty = false; m_propertyNameIsDirty = true; m_sizeIsDirty = true; } } } public void BeginPropertyFromInspectorCheck() { m_propertyFromInspector = true; m_propertyFromInspectorTimestamp = EditorApplication.timeSinceStartup; } public virtual void CheckPropertyFromInspector( bool forceUpdate = false ) { if( m_propertyFromInspector ) { if( forceUpdate || ( EditorApplication.timeSinceStartup - m_propertyFromInspectorTimestamp ) > MaxTimestamp ) { m_propertyFromInspector = false; bool autoGlobal = m_autoGlobalName || m_currentParameterType == PropertyType.Global; RegisterPropertyName( true, m_propertyInspectorName, autoGlobal, m_underscoredGlobal ); m_propertyNameIsDirty = true; } } } public void CheckDuplicateProperty() { if( m_checkDuplicateProperty && ( EditorApplication.timeSinceStartup - m_checkDuplicatePropertyTimestamp ) > MaxTimestamp ) { m_checkDuplicateProperty = false; m_propertyName = UIUtils.GeneratePropertyName( m_propertyName, PropertyType.Global, false ); if( UIUtils.IsNumericName( m_propertyName ) ) { UIUtils.ShowMessage( UniqueId, string.Format( "Invalid property name '{0}' as it cannot start with numbers. Reverting to previous name.", m_propertyName ), MessageSeverity.Warning ); m_propertyName = m_oldName; GUI.FocusControl( string.Empty ); return; } if( !m_propertyName.Equals( m_oldName ) ) { if( UIUtils.IsUniformNameAvailable( m_propertyName ) || m_allowPropertyDuplicates ) { UIUtils.ReleaseUniformName( UniqueId, m_oldName ); m_oldName = m_propertyName; m_propertyNameIsDirty = true; m_reRegisterName = false; UIUtils.RegisterUniformName( UniqueId, m_propertyName ); OnPropertyNameChanged(); } else { GUI.FocusControl( string.Empty ); RegisterFirstAvailablePropertyName( true, true ); UIUtils.ShowMessage( UniqueId, string.Format( "Duplicate property name found on edited node.\nAssigning first valid one {0}", m_propertyName ) ); } } } } protected override void OnUniqueIDAssigned() { if( m_variableMode == VariableMode.Create ) RegisterFirstAvailablePropertyName( false ); if( m_nodeAttribs != null ) m_uniqueName = m_nodeAttribs.Name + UniqueId; UIUtils.RegisterRawPropertyNode( this ); } public bool CheckLocalVariable( ref MasterNodeDataCollector dataCollector ) { bool addToLocalValue = false; int count = 0; for( int i = 0; i < m_outputPorts.Count; i++ ) { if( m_outputPorts[ i ].IsConnected ) { if( m_outputPorts[ i ].ConnectionCount > 1 ) { addToLocalValue = true; break; } count += 1; if( count > 1 ) { addToLocalValue = true; break; } } } if( addToLocalValue ) { ConfigureLocalVariable( ref dataCollector ); } return addToLocalValue; } public virtual void ConfigureLocalVariable( ref MasterNodeDataCollector dataCollector ) { } public virtual void CopyDefaultsToMaterial() { } public override void SetupFromCastObject( UnityEngine.Object obj ) { RegisterPropertyName( true, obj.name, true, m_underscoredGlobal ); } public void ChangeParameterType( PropertyType parameterType ) { Undo.RegisterCompleteObjectUndo( m_containerGraph.ParentWindow, Constants.UndoChangePropertyTypeNodesId ); Undo.RegisterCompleteObjectUndo( m_containerGraph, Constants.UndoChangePropertyTypeNodesId ); Undo.RecordObject( this, Constants.UndoChangePropertyTypeNodesId ); if( m_currentParameterType == PropertyType.Constant || m_currentParameterType == PropertyType.Global ) { CopyDefaultsToMaterial(); } if( parameterType == PropertyType.InstancedProperty ) { //if( m_containerGraph.IsSRP ) //{ // UIUtils.ShowMessage( InstancedPropertyWarning,MessageSeverity.Warning ); //} UIUtils.CurrentWindow.OutsideGraph.AddInstancePropertyCount(); } else if( m_currentParameterType == PropertyType.InstancedProperty ) { UIUtils.CurrentWindow.OutsideGraph.RemoveInstancePropertyCount(); } if( ( parameterType == PropertyType.Property || parameterType == PropertyType.InstancedProperty ) && m_currentParameterType != PropertyType.Property && m_currentParameterType != PropertyType.InstancedProperty ) { UIUtils.RegisterPropertyNode( this ); } if( ( parameterType != PropertyType.Property && parameterType != PropertyType.InstancedProperty ) && ( m_currentParameterType == PropertyType.Property || m_currentParameterType == PropertyType.InstancedProperty ) ) { UIUtils.UnregisterPropertyNode( this ); } m_currentParameterType = parameterType; if( parameterType == PropertyType.Constant ) { CurrentVariableMode = VariableMode.Create; } } void InitializeAttribsArray() { m_availableAttribsArr = new string[ m_availableAttribs.Count ]; m_selectedAttribsArr = new bool[ m_availableAttribs.Count ]; for( int i = 0; i < m_availableAttribsArr.Length; i++ ) { m_availableAttribsArr[ i ] = m_availableAttribs[ i ].Name; m_selectedAttribsArr[ i ] = false; if( m_selectedAttribs.FindIndex( x => x == i ) > -1 ) { m_selectedAttribsArr[ i ] = true; m_visibleAttribsFoldout = true; } } } protected virtual void OnAtrributesChanged() { CheckEnumAttribute(); CheckHeaderAttribute(); } void DrawAttributesAddRemoveButtons() { if( m_availableAttribsArr == null ) { InitializeAttribsArray(); } int attribCount = m_selectedAttribs.Count; // Add new port if( GUILayout.Button( string.Empty, UIUtils.PlusStyle, GUILayout.Width( ButtonLayoutWidth ) ) ) { m_visibleAttribsFoldout = true; m_selectedAttribs.Add( 0 ); OnAtrributesChanged(); } //Remove port if( GUILayout.Button( string.Empty, UIUtils.MinusStyle, GUILayout.Width( ButtonLayoutWidth ) ) ) { if( attribCount > 0 ) { m_selectedAttribs.RemoveAt( attribCount - 1 ); OnAtrributesChanged(); } } } void CheckEnumAttribute() { m_hasEnum = false; foreach( var item in m_selectedAttribs ) { if( m_availableAttribsArr[ item ].Equals( "Enum" ) ) m_hasEnum = true; } } protected void CheckHeaderAttribute() { m_hasHeaders = false; foreach( var item in m_selectedAttribs ) { if( m_availableAttribsArr[ item ].Equals( HeaderId ) ) { m_hasHeaders = true; } } } void DrawEnumAddRemoveButtons() { // Add new port if( GUILayout.Button( string.Empty, UIUtils.PlusStyle, GUILayout.Width( ButtonLayoutWidth ) ) && m_enumModeInt == 0 ) { m_enumNames.Add( "Option" + ( m_enumValues.Count + 1 ) ); m_enumValues.Add( m_enumValues.Count ); m_enumCount++; m_visibleEnumsFoldout = true; } //Remove port if( GUILayout.Button( string.Empty, UIUtils.MinusStyle, GUILayout.Width( ButtonLayoutWidth ) ) && m_enumModeInt == 0 ) { if( m_enumNames.Count - 1 > -1 ) { m_enumNames.RemoveAt( m_enumNames.Count - 1 ); m_enumValues.RemoveAt( m_enumValues.Count - 1 ); m_enumCount--; } } } protected void DrawEnums() { m_enumModeInt = EditorGUILayout.IntPopup( "Mode", m_enumModeInt, EnumModesStr, EnumModeIntValues ); if( m_enumModeInt == 0 ) { if( m_enumNames.Count == 0 ) EditorGUILayout.HelpBox( "Your list is Empty!\nUse the plus button to add more.", MessageType.Info ); float cacheLabelSize = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = 50; for( int i = 0; i < m_enumNames.Count; i++ ) { EditorGUI.BeginChangeCheck(); EditorGUILayout.BeginHorizontal(); m_enumNames[ i ] = EditorGUILayoutTextField( "Name", m_enumNames[ i ] ); m_enumValues[ i ] = EditorGUILayoutIntField( "Value", m_enumValues[ i ], GUILayout.Width( 100 ) ); EditorGUILayout.EndHorizontal(); if( EditorGUI.EndChangeCheck() ) { m_enumNames[ i ] = UIUtils.RemoveInvalidEnumCharacters( m_enumNames[ i ] ); if( string.IsNullOrEmpty( m_enumNames[ i ] ) ) { m_enumNames[ i ] = "Option" + ( i + 1 ); } } } EditorGUIUtility.labelWidth = cacheLabelSize; if( m_enumNames.Count > 0 ) { EditorGUILayout.BeginHorizontal(); GUILayout.Label( " " ); DrawEnumAddRemoveButtons(); EditorGUILayout.EndHorizontal(); } } else { EditorGUILayout.BeginHorizontal(); m_enumClassName = EditorGUILayoutTextField( "Class Name", m_enumClassName ); if( GUILayout.Button( string.Empty, UIUtils.InspectorPopdropdownFallback, GUILayout.Width( 17 ), GUILayout.Height( 19 ) ) ) { GenericMenu menu = new GenericMenu(); AddMenuItem( menu, "UnityEngine.Rendering.CullMode" ); AddMenuItem( menu, "UnityEngine.Rendering.ColorWriteMask" ); AddMenuItem( menu, "UnityEngine.Rendering.CompareFunction" ); AddMenuItem( menu, "UnityEngine.Rendering.StencilOp" ); AddMenuItem( menu, "UnityEngine.Rendering.BlendMode" ); AddMenuItem( menu, "UnityEngine.Rendering.BlendOp" ); menu.ShowAsContext(); } EditorGUILayout.EndHorizontal(); } } private void AddMenuItem( GenericMenu menu, string newClass ) { menu.AddItem( new GUIContent( newClass ), m_enumClassName.Equals( newClass ), OnSelection, newClass ); } private void OnSelection( object newClass ) { m_enumClassName = (string)newClass; } protected void DrawCustomAttrAddRemoveButtons() { // Add new port if( GUILayout.Button( string.Empty, UIUtils.PlusStyle, GUILayout.Width( ButtonLayoutWidth ) ) ) { m_customAttr.Add( "" ); m_customAttrCount++; //m_enumCount++; m_visibleCustomAttrFoldout = true; } //Remove port if( GUILayout.Button( string.Empty, UIUtils.MinusStyle, GUILayout.Width( ButtonLayoutWidth ) ) ) { if( m_customAttr.Count - 1 > -1 ) { m_customAttr.RemoveAt( m_customAttr.Count - 1 ); m_customAttrCount--; } } } protected void DrawCustomAttributes() { for( int i = 0; i < m_customAttrCount; i++ ) { EditorGUI.BeginChangeCheck(); m_customAttr[ i ] = EditorGUILayoutTextField( "Attribute " + i, m_customAttr[ i ] ); if( EditorGUI.EndChangeCheck() ) { m_customAttr[ i ] = UIUtils.RemoveInvalidAttrCharacters( m_customAttr[ i ] ); } } if( m_customAttrCount <= 0 ) { EditorGUILayout.HelpBox( "Your list is Empty!\nUse the plus button to add more.", MessageType.Info ); return; } EditorGUILayout.BeginHorizontal(); GUILayout.Label( " " ); DrawCustomAttrAddRemoveButtons(); EditorGUILayout.EndHorizontal(); } protected void DrawHeaderAttrAddRemoveButtons() { // Add new port if( GUILayout.Button( string.Empty, UIUtils.PlusStyle, GUILayout.Width( ButtonLayoutWidth ) ) ) { m_headerAttributeValues.Add( "" ); m_visibleHeaderAttrFoldout = true; } //Remove port if( GUILayout.Button( string.Empty, UIUtils.MinusStyle, GUILayout.Width( ButtonLayoutWidth ) ) ) { if( m_headerAttributeValues.Count > 0 ) { m_headerAttributeValues.RemoveAt( m_headerAttributeValues.Count - 1 ); } } } protected void DrawHeaderAttributes() { int count = m_headerAttributeValues.Count; for( int i = 0; i < count; i++ ) { EditorGUI.BeginChangeCheck(); m_headerAttributeValues[ i ] = EditorGUILayoutTextField( "Header " + i, m_headerAttributeValues[ i ] ); if( EditorGUI.EndChangeCheck() ) { m_headerAttributeValues[ i ] = UIUtils.RemoveHeaderAttrCharacters( m_headerAttributeValues[ i ] ); } } if( count <= 0 ) { EditorGUILayout.HelpBox( "Your list is Empty!\nUse the plus button to add more.", MessageType.Info ); return; } EditorGUILayout.BeginHorizontal(); GUILayout.Label( " " ); DrawHeaderAttrAddRemoveButtons(); EditorGUILayout.EndHorizontal(); } public virtual void DrawAttributes() { int attribCount = m_selectedAttribs.Count; EditorGUI.BeginChangeCheck(); if( m_availableAttribsArr == null ) { InitializeAttribsArray(); } for( int i = 0; i < m_availableAttribsArr.Length; i++ ) { m_selectedAttribsArr[ i ] = EditorGUILayoutToggleLeft( m_availableAttribsArr[ i ], m_selectedAttribsArr[ i ] ); } if( EditorGUI.EndChangeCheck() ) { m_selectedAttribs.Clear(); for( int i = 0; i < m_selectedAttribsArr.Length; i++ ) { if( m_selectedAttribsArr[ i ] ) m_selectedAttribs.Add( i ); } OnAtrributesChanged(); } bool customAttr = EditorGUILayoutToggleLeft( "Custom", m_customAttrCount == 0 ? false : true ); if( !customAttr ) { m_customAttrCount = 0; } else if( customAttr && m_customAttrCount < 1 ) { if( m_customAttr.Count == 0 ) m_customAttr.Add( "" ); m_customAttrCount = m_customAttr.Count; } //m_customAttrCount = EditorGUILayoutToggleLeft( "Custom Attribute", m_customAttrCount == 0 ? false : true ) == 0 ? false : true; //if( attribCount == 0 ) //{ // EditorGUILayout.HelpBox( "Your list is Empty!\nUse the plus button to add more.", MessageType.Info ); //} //bool actionAllowed = true; //int deleteItem = -1; //for ( int i = 0; i < attribCount; i++ ) //{ // EditorGUI.BeginChangeCheck(); // { // m_selectedAttribs[ i ] = EditorGUILayoutPopup( m_selectedAttribs[ i ], m_availableAttribsArr ); // } // if ( EditorGUI.EndChangeCheck() ) // { // OnAtrributesChanged(); // } // EditorGUILayout.BeginHorizontal(); // GUILayout.Label( " " ); // // Add After // if ( GUILayout.Button( string.Empty, UIUtils.PlusStyle, GUILayout.Width( ButtonLayoutWidth ) ) ) // { // if ( actionAllowed ) // { // m_selectedAttribs.Insert( i, m_selectedAttribs[ i ] ); // actionAllowed = false; // OnAtrributesChanged(); // } // } // // Remove Current // if ( GUILayout.Button( string.Empty, UIUtils.MinusStyle, GUILayout.Width( ButtonLayoutWidth ) ) ) // { // if ( actionAllowed ) // { // actionAllowed = false; // deleteItem = i; // } // } // EditorGUILayout.EndHorizontal(); //} //if ( deleteItem > -1 ) //{ // m_selectedAttribs.RemoveAt( deleteItem ); // OnAtrributesChanged(); //} } public virtual void DrawMainPropertyBlock() { EditorGUILayout.BeginVertical(); { if( m_freeType ) { PropertyType parameterType = (PropertyType)EditorGUILayoutEnumPopup( ParameterTypeStr, m_currentParameterType ); if( parameterType != m_currentParameterType ) { ChangeParameterType( parameterType ); BeginPropertyFromInspectorCheck(); } } if( m_freeName ) { switch( m_currentParameterType ) { case PropertyType.Property: case PropertyType.InstancedProperty: { ShowPropertyInspectorNameGUI(); ShowPropertyNameGUI( true ); ShowVariableMode(); ShowHybridInstanced(); ShowAutoRegister(); ShowPrecision(); ShowToolbar(); } break; case PropertyType.Global: { ShowPropertyInspectorNameGUI(); ShowPropertyNameGUI( false ); ShowVariableMode(); ShowAutoRegister(); ShowPrecision(); ShowDefaults(); } break; case PropertyType.Constant: { ShowPropertyInspectorNameGUI(); ShowPrecision(); ShowDefaults(); } break; } } } EditorGUILayout.EndVertical(); } public void DrawMainPropertyBlockNoPrecision() { EditorGUILayout.BeginVertical(); { if( m_freeType ) { PropertyType parameterType = (PropertyType)EditorGUILayoutEnumPopup( ParameterTypeStr, m_currentParameterType ); if( parameterType != m_currentParameterType ) { ChangeParameterType( parameterType ); BeginPropertyFromInspectorCheck(); } } if( m_freeName ) { switch( m_currentParameterType ) { case PropertyType.Property: case PropertyType.InstancedProperty: { ShowPropertyInspectorNameGUI(); ShowPropertyNameGUI( true ); ShowToolbar(); } break; case PropertyType.Global: { ShowPropertyInspectorNameGUI(); ShowPropertyNameGUI( false ); ShowDefaults(); } break; case PropertyType.Constant: { ShowPropertyInspectorNameGUI(); ShowDefaults(); } break; } } } EditorGUILayout.EndVertical(); } public override void DrawProperties() { base.DrawProperties(); if( m_freeType || m_freeName ) { NodeUtils.DrawPropertyGroup( ref m_propertiesFoldout, Constants.ParameterLabelStr, DrawMainPropertyBlock ); if( m_drawAttributes ) NodeUtils.DrawPropertyGroup( ref m_visibleAttribsFoldout, Constants.AttributesLaberStr, DrawAttributes ); if( m_hasEnum ) { if( m_enumModeInt == 0 ) NodeUtils.DrawPropertyGroup( ref m_visibleEnumsFoldout, EnumsStr, DrawEnums, DrawEnumAddRemoveButtons ); else NodeUtils.DrawPropertyGroup( ref m_visibleEnumsFoldout, EnumsStr, DrawEnums ); } if( m_drawAttributes ) { if( m_hasHeaders ) NodeUtils.DrawPropertyGroup( ref m_visibleHeaderAttrFoldout, HeaderAttrStr, DrawHeaderAttributes, DrawHeaderAttrAddRemoveButtons ); if( m_customAttrCount > 0 ) NodeUtils.DrawPropertyGroup( ref m_visibleCustomAttrFoldout, CustomAttrStr, DrawCustomAttributes, DrawCustomAttrAddRemoveButtons ); } CheckPropertyFromInspector(); } } public void ShowPrecision() { if( m_drawPrecisionUI ) { bool guiEnabled = GUI.enabled; GUI.enabled = m_currentParameterType == PropertyType.Constant || m_variableMode == VariableMode.Create; EditorGUI.BeginChangeCheck(); DrawPrecisionProperty(); if( EditorGUI.EndChangeCheck() ) m_precisionString = UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType, m_outputPorts[ 0 ].DataType ); GUI.enabled = guiEnabled; } } public void ShowToolbar() { //if ( !CanDrawMaterial ) //{ // ShowDefaults(); // return; //} EditorGUILayout.BeginHorizontal(); GUILayout.Space( 20 ); m_propertyTab = GUILayout.Toolbar( m_propertyTab, LabelToolbarTitle ); EditorGUILayout.EndHorizontal(); switch( m_propertyTab ) { default: case 0: { EditorGUI.BeginChangeCheck(); DrawMaterialProperties(); if( EditorGUI.EndChangeCheck() ) { BeginDelayedDirtyProperty(); } } break; case 1: { ShowDefaults(); } break; } } public void ShowDefaults() { EditorGUI.BeginChangeCheck(); DrawSubProperties(); if( EditorGUI.EndChangeCheck() ) { BeginDelayedDirtyProperty(); } if( m_currentParameterType == PropertyType.Global && m_globalDefaultBehavior ) { if( DebugConsoleWindow.DeveloperMode ) { ShowGlobalValueButton(); } EditorGUILayout.HelpBox( GlobalTypeWarningText, MessageType.Warning ); } } public void ShowPropertyInspectorNameGUI() { EditorGUI.BeginChangeCheck(); m_propertyInspectorName = EditorGUILayoutTextField( PropertyInspectorStr, m_propertyInspectorName ); if( EditorGUI.EndChangeCheck() ) { if( m_propertyInspectorName.Length > 0 ) { BeginPropertyFromInspectorCheck(); } } } public void ShowPropertyNameGUI( bool isProperty ) { bool guiEnabledBuffer = GUI.enabled; if( isProperty ) { EditorGUILayout.BeginHorizontal(); GUI.enabled = !m_autoGlobalName; EditorGUI.BeginChangeCheck(); m_propertyName = EditorGUILayoutTextField( PropertyNameStr, m_propertyName ); if( EditorGUI.EndChangeCheck() ) { //BeginPropertyFromInspectorCheck(); m_checkDuplicateProperty = true; m_checkDuplicatePropertyTimestamp = EditorApplication.timeSinceStartup; } GUI.enabled = guiEnabledBuffer; EditorGUI.BeginChangeCheck(); m_autoGlobalName = GUILayout.Toggle( m_autoGlobalName, ( m_autoGlobalName ? UIUtils.LockIconOpen : UIUtils.LockIconClosed ), "minibutton", GUILayout.Width( 22 ) ); if( EditorGUI.EndChangeCheck() ) { if( m_autoGlobalName ) BeginPropertyFromInspectorCheck(); } EditorGUILayout.EndHorizontal(); } else { GUI.enabled = false; m_propertyName = EditorGUILayoutTextField( PropertyNameStr, m_propertyName ); GUI.enabled = guiEnabledBuffer; } } public void ShowVariableMode() { if( m_showVariableMode || m_freeType ) CurrentVariableMode = (VariableMode)EditorGUILayoutEnumPopup( IgnoreVarDeclarationStr, m_variableMode ); } public void ShowHybridInstanced() { if( m_showHybridInstancedUI && CurrentParameterType == PropertyType.Property && ( m_containerGraph.IsSRP || m_containerGraph.CurrentShaderFunction != null ) ) { m_hybridInstanced = EditorGUILayoutToggle( HybridInstancedStr, m_hybridInstanced ); } } public void ShowAutoRegister() { if( m_showAutoRegisterUI && CurrentParameterType != PropertyType.Constant ) { m_autoRegister = EditorGUILayoutToggle( AutoRegisterStr, m_autoRegister ); } } public virtual string GetPropertyValStr() { return string.Empty; } public override bool OnClick( Vector2 currentMousePos2D ) { bool singleClick = base.OnClick( currentMousePos2D ); m_propertyTab = m_materialMode ? 0 : 1; return singleClick; } public override void OnNodeDoubleClicked( Vector2 currentMousePos2D ) { if( currentMousePos2D.y - m_globalPosition.y > ( Constants.NODE_HEADER_HEIGHT + Constants.NODE_HEADER_EXTRA_HEIGHT ) * ContainerGraph.ParentWindow.CameraDrawInfo.InvertedZoom ) { ContainerGraph.ParentWindow.ParametersWindow.IsMaximized = !ContainerGraph.ParentWindow.ParametersWindow.IsMaximized; } } public override void DrawTitle( Rect titlePos ) { //base.DrawTitle( titlePos ); } public override void Draw( DrawInfo drawInfo ) { base.Draw( drawInfo ); // Custom Editable Title if( ContainerGraph.LodLevel <= ParentGraph.NodeLOD.LOD3 ) { if( !m_isEditing && ( ( !ContainerGraph.ParentWindow.MouseInteracted && drawInfo.CurrentEventType == EventType.MouseDown && m_titleClickArea.Contains( drawInfo.MousePosition ) ) ) ) { if( ( EditorApplication.timeSinceStartup - m_clickTime ) < m_doubleClickTime ) m_startEditing = true; else GUI.FocusControl( null ); m_clickTime = EditorApplication.timeSinceStartup; } else if( m_isEditing && ( ( drawInfo.CurrentEventType == EventType.MouseDown && !m_titleClickArea.Contains( drawInfo.MousePosition ) ) || !EditorGUIUtility.editingTextField ) ) { m_stopEditing = true; } if( m_isEditing || m_startEditing ) { EditorGUI.BeginChangeCheck(); GUI.SetNextControlName( m_uniqueName ); m_propertyInspectorName = EditorGUITextField( m_titleClickArea, string.Empty, m_propertyInspectorName, UIUtils.GetCustomStyle( CustomStyle.NodeTitle ) ); if( EditorGUI.EndChangeCheck() ) { SetClippedTitle( m_propertyInspectorName, m_longNameSize ); m_sizeIsDirty = true; m_isDirty = true; if( m_propertyInspectorName.Length > 0 ) { BeginPropertyFromInspectorCheck(); } } if( m_startEditing ) EditorGUI.FocusTextInControl( m_uniqueName ); //if( m_stopEditing ) // GUI.FocusControl( null ); } if( drawInfo.CurrentEventType == EventType.Repaint ) { if( m_startEditing ) { m_startEditing = false; m_isEditing = true; } if( m_stopEditing ) { m_stopEditing = false; m_isEditing = false; GUI.FocusControl( null ); } } if( m_freeType ) { if( m_dropdownEditing ) { PropertyType parameterType = (PropertyType)EditorGUIEnumPopup( m_dropdownRect, m_currentParameterType, UIUtils.PropertyPopUp ); if( parameterType != m_currentParameterType ) { ChangeParameterType( parameterType ); BeginPropertyFromInspectorCheck(); DropdownEditing = false; } } } } } public override void OnNodeLayout( DrawInfo drawInfo ) { //base.OnNodeLayout( drawInfo ); if( m_reRegisterName ) { m_reRegisterName = false; UIUtils.RegisterUniformName( UniqueId, m_propertyName ); } CheckDelayedDirtyProperty(); if( m_currentParameterType != m_lastParameterType || m_propertyNameIsDirty ) { m_lastParameterType = m_currentParameterType; m_propertyNameIsDirty = false; OnDirtyProperty(); if( m_currentParameterType != PropertyType.Constant ) { SetClippedTitle( m_propertyInspectorName, m_longNameSize ); //bool globalHandler = false; //if( globalHandler ) //{ string currValue = ( m_currentParameterType == PropertyType.Global && m_globalDefaultBehavior ) ? "" : GetPropertyValStr(); SetClippedAdditionalTitle( string.Format( m_useVarSubtitle ? Constants.SubTitleVarNameFormatStr : Constants.SubTitleValueFormatStr, currValue ), m_longNameSize, LongNameEnder ); //} //else //{ // if( m_currentParameterType == PropertyType.Global ) // { // SetAdditonalTitleText( "Global" ); // } // else // { // SetAdditonalTitleText( string.Format( m_useVarSubtitle ? Constants.SubTitleVarNameFormatStr : Constants.SubTitleValueFormatStr, GetPropertyValStr() ) ); // } //} } else { SetClippedTitle( m_propertyInspectorName, m_longNameSize ); SetClippedAdditionalTitle( string.Format( Constants.SubTitleConstFormatStr, GetPropertyValStr() ), m_longNameSize, LongNameEnder ); } } CheckPropertyFromInspector(); CheckDuplicateProperty(); // RUN LAYOUT CHANGES AFTER TITLES CHANGE base.OnNodeLayout( drawInfo ); m_titleClickArea = m_titlePos; m_titleClickArea.height = Constants.NODE_HEADER_HEIGHT; } public override void OnNodeRepaint( DrawInfo drawInfo ) { base.OnNodeRepaint( drawInfo ); if( !m_isVisible ) return; // Fixed Title ( only renders when not editing ) if( m_showTitleWhenNotEditing && !m_isEditing && !m_startEditing && ContainerGraph.LodLevel <= ParentGraph.NodeLOD.LOD3 ) { GUI.Label( m_titleClickArea, m_content, UIUtils.GetCustomStyle( CustomStyle.NodeTitle ) ); } } public void RegisterFirstAvailablePropertyName( bool releaseOldOne, bool appendIndexToCurrOne = false ) { if( releaseOldOne ) UIUtils.ReleaseUniformName( UniqueId, m_oldName ); if( m_isNodeBeingCopied || appendIndexToCurrOne ) { if( string.IsNullOrEmpty( m_propertyName ) ) return; string newPropertyName = UIUtils.GetUniqueUniformName( m_propertyName ); if( newPropertyName != m_propertyName ) { UIUtils.RegisterUniformName( UniqueId, newPropertyName ); m_propertyName = newPropertyName; } else { if( UIUtils.IsUniformNameAvailable( m_propertyName ) ) UIUtils.RegisterUniformName( UniqueId, m_propertyName ); else UIUtils.GetFirstAvailableName( UniqueId, m_outputPorts[ 0 ].DataType, out m_propertyName, out m_propertyInspectorName, !string.IsNullOrEmpty( m_customPrefix ), m_customPrefix ); } } else { UIUtils.GetFirstAvailableName( UniqueId, m_outputPorts[ 0 ].DataType, out m_propertyName, out m_propertyInspectorName, !string.IsNullOrEmpty( m_customPrefix ), m_customPrefix ); } m_oldName = m_propertyName; m_propertyNameIsDirty = true; m_reRegisterName = false; OnPropertyNameChanged(); } public void SetRawPropertyName( string name ) { m_propertyName = name; } public void RegisterPropertyName( bool releaseOldOne, string newName, bool autoGlobal = true, bool forceUnderscore = false ) { if( m_currentParameterType != PropertyType.Constant && m_variableMode == VariableMode.Fetch ) { string localPropertyName = string.Empty; if( autoGlobal ) localPropertyName = UIUtils.GeneratePropertyName( newName, m_currentParameterType, forceUnderscore ); else { localPropertyName = UIUtils.GeneratePropertyName( m_propertyName, PropertyType.Global, forceUnderscore ); if( UIUtils.IsNumericName( localPropertyName ) ) { m_propertyName = m_oldName; } } m_propertyName = localPropertyName; m_propertyInspectorName = newName; m_propertyNameIsDirty = true; m_reRegisterName = false; OnPropertyNameChanged(); return; } string propertyName = string.Empty; if( autoGlobal ) propertyName = UIUtils.GeneratePropertyName( newName, m_currentParameterType, forceUnderscore ); else { propertyName = UIUtils.GeneratePropertyName( m_propertyName, PropertyType.Global, forceUnderscore ); if( UIUtils.IsNumericName( propertyName ) ) { m_propertyName = m_oldName; } } if( m_propertyName.Equals( propertyName ) ) return; if( UIUtils.IsUniformNameAvailable( propertyName ) || m_allowPropertyDuplicates ) { if( releaseOldOne ) UIUtils.ReleaseUniformName( UniqueId, m_oldName ); m_oldName = propertyName; m_propertyName = propertyName; if( autoGlobal ) m_propertyInspectorName = newName; m_propertyNameIsDirty = true; m_reRegisterName = false; UIUtils.RegisterUniformName( UniqueId, propertyName ); OnPropertyNameChanged(); } else { GUI.FocusControl( string.Empty ); RegisterFirstAvailablePropertyName( releaseOldOne ); UIUtils.ShowMessage( UniqueId, string.Format( "Duplicate name found on edited node.\nAssigning first valid one {0}", m_propertyInspectorName ) ); } } protected string CreateLocalVarDec( string value ) { return string.Format( Constants.PropertyLocalVarDec, UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType, m_outputPorts[ 0 ].DataType ), m_propertyName, value ); } public virtual void CheckIfAutoRegister( ref MasterNodeDataCollector dataCollector ) { // Also testing inside shader function because node can be used indirectly over a custom expression and directly over a Function Output node // That isn't being used externaly making it to not be registered ( since m_connStatus it set to Connected by being connected to an output node if( CurrentParameterType != PropertyType.Constant && m_autoRegister && ( m_connStatus != NodeConnectionStatus.Connected || InsideShaderFunction ) ) { RegisterProperty( ref dataCollector ); } } virtual protected void RegisterProperty( ref MasterNodeDataCollector dataCollector ) { CheckPropertyFromInspector( true ); if( m_propertyName.Length == 0 ) { RegisterFirstAvailablePropertyName( false ); } switch( CurrentParameterType ) { case PropertyType.Property: { //Debug.Log( this.GetInstanceID()+" "+ OrderIndex+" "+GetPropertyValue() ); dataCollector.AddToProperties( UniqueId, GetPropertyValue(), OrderIndex ); string dataType = string.Empty; string dataName = string.Empty; bool fullValue = false; if( m_variableMode == VariableMode.Create && GetUniformData( out dataType, out dataName, ref fullValue ) ) { if( fullValue ) { dataCollector.AddToUniforms( UniqueId, dataName, m_srpBatcherCompatible ); } else { dataCollector.AddToUniforms( UniqueId, dataType, dataName, m_srpBatcherCompatible, m_excludeUniform ); } } if( m_hybridInstanced && dataCollector.IsTemplate && dataCollector.IsSRP ) { dataCollector.AddToDotsProperties( m_outputPorts[ 0 ].DataType, UniqueId, m_propertyName, OrderIndex, CurrentPrecisionType ); } //dataCollector.AddToUniforms( m_uniqueId, GetUniformValue() ); } break; case PropertyType.InstancedProperty: { dataCollector.AddToPragmas( UniqueId, IOUtils.InstancedPropertiesHeader ); if( m_registerPropertyOnInstancing ) dataCollector.AddToProperties( UniqueId, GetPropertyValue(), OrderIndex ); dataCollector.AddToInstancedProperties( m_outputPorts[ 0 ].DataType, UniqueId, GetInstancedUniformValue( dataCollector.IsTemplate, dataCollector.IsSRP ), OrderIndex ); } break; case PropertyType.Global: { string dataType = string.Empty; string dataName = string.Empty; bool fullValue = false; if( m_variableMode == VariableMode.Create && GetUniformData( out dataType, out dataName, ref fullValue ) ) { if( fullValue ) { dataCollector.AddToUniforms( UniqueId, dataName, m_addGlobalToSRPBatcher ); } else { dataCollector.AddToUniforms( UniqueId, dataType, dataName, m_addGlobalToSRPBatcher, m_excludeUniform ); } } //dataCollector.AddToUniforms( m_uniqueId, GetUniformValue() ); } break; case PropertyType.Constant: break; } dataCollector.AddPropertyNode( this ); if( m_currentParameterType == PropertyType.InstancedProperty && !m_outputPorts[ 0 ].IsLocalValue( dataCollector.PortCategory ) ) { string instancedVar = dataCollector.IsSRP ? //m_propertyName : string.Format( IOUtils.LWSRPInstancedPropertiesData, dataCollector.InstanceBlockName, m_propertyName ) : string.Format( IOUtils.InstancedPropertiesData, m_propertyName ); bool insideSF = InsideShaderFunction; ParentGraph cachedGraph = ContainerGraph.ParentWindow.CustomGraph; if( insideSF ) ContainerGraph.ParentWindow.CustomGraph = this.ContainerGraph; RegisterLocalVariable( 0, instancedVar, ref dataCollector, m_propertyName + "_Instance" ); if( insideSF ) ContainerGraph.ParentWindow.CustomGraph = cachedGraph; } } public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar ) { RegisterProperty( ref dataCollector ); return string.Empty; } public override void Destroy() { base.Destroy(); UIUtils.UnregisterRawPropertyNode( this ); if( !string.IsNullOrEmpty( m_propertyName ) && UniqueId >= 0 ) UIUtils.ReleaseUniformName( UniqueId, m_propertyName ); if( m_currentParameterType == PropertyType.InstancedProperty ) { UIUtils.CurrentWindow.OutsideGraph.RemoveInstancePropertyCount(); UIUtils.UnregisterPropertyNode( this ); } if( m_currentParameterType == PropertyType.Property ) { UIUtils.UnregisterPropertyNode( this ); } if( m_availableAttribs != null ) m_availableAttribs.Clear(); m_availableAttribs = null; } private const string HeaderFormatStr = "[Header({0})]"; string BuildHeader() { string result = string.Empty; for( int i = 0; i < m_headerAttributeValues.Count; i++ ) { result += string.Format( HeaderFormatStr, m_headerAttributeValues[ i ] ); } return result; } string BuildEnum() { string result = "[Enum("; if( m_enumModeInt == 0 ) { for( int i = 0; i < m_enumNames.Count; i++ ) { result += m_enumNames[ i ] + "," + m_enumValues[ i ]; if( i + 1 < m_enumNames.Count ) result += ","; } } else { result += m_enumClassName; } result += ")]"; return result; } public string PropertyAttributes { get { int attribCount = m_selectedAttribs.Count; if( m_selectedAttribs.Count == 0 && m_customAttrCount == 0 ) return string.Empty; string attribs = string.Empty; for( int i = 0; i < attribCount; i++ ) { if( m_availableAttribs[ m_selectedAttribs[ i ] ].Name.Equals( "Enum" ) ) attribs += BuildEnum(); else if( m_availableAttribs[ m_selectedAttribs[ i ] ].Name.Equals( HeaderId ) ) attribs += BuildHeader(); else attribs += m_availableAttribs[ m_selectedAttribs[ i ] ].Attribute; } for( int i = 0; i < m_customAttrCount; i++ ) { if( !string.IsNullOrEmpty( m_customAttr[ i ] ) ) attribs += "[" + m_customAttr[ i ] + "]"; } return attribs; } } public virtual void OnDirtyProperty() { } public virtual void OnPropertyNameChanged() { UIUtils.UpdatePropertyDataNode( UniqueId, PropertyInspectorName ); } public virtual void DrawSubProperties() { } public virtual void DrawMaterialProperties() { } public virtual string GetPropertyValue() { return string.Empty; } public string GetInstancedUniformValue( bool isTemplate, bool isSRP ) { if( isTemplate ) { if( isSRP ) { return string.Format( IOUtils.LWSRPInstancedPropertiesElement, UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType, m_outputPorts[ 0 ].DataType ), m_propertyName ); //return GetUniformValue(); } else { return string.Format( IOUtils.InstancedPropertiesElement, UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType, m_outputPorts[ 0 ].DataType ), m_propertyName ); } } else return string.Format( IOUtils.InstancedPropertiesElementTabs, UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType, m_outputPorts[ 0 ].DataType ), m_propertyName ); } public string GetInstancedUniformValue( bool isTemplate, bool isSRP, WirePortDataType dataType, string value ) { if( isTemplate ) { if( isSRP ) { //return GetUniformValue( dataType, value ); return string.Format( IOUtils.LWSRPInstancedPropertiesElement, UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType, dataType ), value ); } else { return string.Format( IOUtils.InstancedPropertiesElement, UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType, dataType ), value ); } } else return string.Format( IOUtils.InstancedPropertiesElementTabs, UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType, dataType ), value ); } public virtual string GetUniformValue() { bool excludeUniformKeyword = ( m_currentParameterType == PropertyType.InstancedProperty ) || m_containerGraph.IsSRP; int index = excludeUniformKeyword ? 1 : 0; return string.Format( Constants.UniformDec[ index ], UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType, m_outputPorts[ 0 ].DataType ), m_propertyName ); } public string GetUniformValue( WirePortDataType dataType, string value ) { bool excludeUniformKeyword = ( m_currentParameterType == PropertyType.InstancedProperty ) || m_containerGraph.IsSRP; int index = excludeUniformKeyword ? 1 : 0; return string.Format( Constants.UniformDec[ index ], UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType, dataType ), value ); } public virtual bool GetUniformData( out string dataType, out string dataName, ref bool fullValue ) { dataType = UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType, m_outputPorts[ 0 ].DataType ); dataName = m_propertyName; fullValue = false; return true; } public PropertyType CurrentParameterType { get { return m_currentParameterType; } set { m_currentParameterType = value; } } public override void WriteToString( ref string nodeInfo, ref string connectionsInfo ) { base.WriteToString( ref nodeInfo, ref connectionsInfo ); IOUtils.AddFieldValueToString( ref nodeInfo, m_currentParameterType ); IOUtils.AddFieldValueToString( ref nodeInfo, m_propertyName ); IOUtils.AddFieldValueToString( ref nodeInfo, m_propertyInspectorName ); IOUtils.AddFieldValueToString( ref nodeInfo, m_orderIndex ); int attribCount = m_selectedAttribs.Count; IOUtils.AddFieldValueToString( ref nodeInfo, attribCount ); if( attribCount > 0 ) { for( int i = 0; i < attribCount; i++ ) { IOUtils.AddFieldValueToString( ref nodeInfo, m_availableAttribs[ m_selectedAttribs[ i ] ].Attribute ); } } IOUtils.AddFieldValueToString( ref nodeInfo, m_variableMode ); IOUtils.AddFieldValueToString( ref nodeInfo, m_autoGlobalName ); int headerCount = m_headerAttributeValues.Count; IOUtils.AddFieldValueToString( ref nodeInfo, headerCount ); for( int i = 0; i < headerCount; i++ ) { IOUtils.AddFieldValueToString( ref nodeInfo, m_headerAttributeValues[ i ] ); } IOUtils.AddFieldValueToString( ref nodeInfo, m_enumCount ); for( int i = 0; i < m_enumCount; i++ ) { IOUtils.AddFieldValueToString( ref nodeInfo, m_enumNames[ i ] ); IOUtils.AddFieldValueToString( ref nodeInfo, m_enumValues[ i ] ); } IOUtils.AddFieldValueToString( ref nodeInfo, m_enumModeInt ); if( m_enumModeInt == 1 ) IOUtils.AddFieldValueToString( ref nodeInfo, m_enumClassName ); IOUtils.AddFieldValueToString( ref nodeInfo, m_autoRegister ); IOUtils.AddFieldValueToString( ref nodeInfo, m_customAttrCount ); if( m_customAttrCount > 0 ) { for( int i = 0; i < m_customAttrCount; i++ ) { IOUtils.AddFieldValueToString( ref nodeInfo, m_customAttr[ i ] ); } } IOUtils.AddFieldValueToString( ref nodeInfo, m_hybridInstanced ); } int IdForAttrib( string name ) { int attribCount = m_availableAttribs.Count; for( int i = 0; i < attribCount; i++ ) { if( m_availableAttribs[ i ].Attribute.Equals( name ) || (m_availableAttribs[ i ].HasDeprecatedValue && m_availableAttribs[ i ].DeprecatedValue.Equals( name ) ) ) return i; } return -1; } public override void ReadFromString( ref string[] nodeParams ) { base.ReadFromString( ref nodeParams ); if( UIUtils.CurrentShaderVersion() < 2505 ) { string property = GetCurrentParam( ref nodeParams ); m_currentParameterType = property.Equals( "Uniform" ) ? PropertyType.Global : (PropertyType)Enum.Parse( typeof( PropertyType ), property ); } else { m_currentParameterType = (PropertyType)Enum.Parse( typeof( PropertyType ), GetCurrentParam( ref nodeParams ) ); } if( m_currentParameterType == PropertyType.InstancedProperty ) { UIUtils.CurrentWindow.OutsideGraph.AddInstancePropertyCount(); UIUtils.RegisterPropertyNode( this ); } if( m_currentParameterType == PropertyType.Property ) { UIUtils.RegisterPropertyNode( this ); } m_propertyName = GetCurrentParam( ref nodeParams ); m_propertyInspectorName = GetCurrentParam( ref nodeParams ); if( UIUtils.CurrentShaderVersion() > 13 ) { m_orderIndex = Convert.ToInt32( GetCurrentParam( ref nodeParams ) ); } if( UIUtils.CurrentShaderVersion() > 4102 ) { int attribAmount = Convert.ToInt32( GetCurrentParam( ref nodeParams ) ); if( attribAmount > 0 ) { for( int i = 0; i < attribAmount; i++ ) { string attribute = GetCurrentParam( ref nodeParams ); int idForAttribute = IdForAttrib( attribute ); if( idForAttribute >= 0 ) { m_selectedAttribs.Add( idForAttribute ); } else { UIUtils.ShowMessage( UniqueId, string.Format( InvalidAttributeFormatter, attribute,m_propertyInspectorName ) , MessageSeverity.Warning ); } } m_visibleAttribsFoldout = true; } InitializeAttribsArray(); } if( UIUtils.CurrentShaderVersion() > 14003 ) { m_variableMode = (VariableMode)Enum.Parse( typeof( VariableMode ), GetCurrentParam( ref nodeParams ) ); } if( UIUtils.CurrentShaderVersion() > 14201 ) { m_autoGlobalName = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) ); } if( UIUtils.CurrentShaderVersion() > 18707 ) { if( UIUtils.CurrentShaderVersion() == 18708 ) { m_headerAttributeValues.Add( GetCurrentParam( ref nodeParams ) ); } else { int headerCount = Convert.ToInt32( GetCurrentParam( ref nodeParams ) ); for( int i = 0; i < headerCount; i++ ) { m_headerAttributeValues.Add( GetCurrentParam( ref nodeParams ) ); } } } if( UIUtils.CurrentShaderVersion() > 14403 ) { m_enumCount = Convert.ToInt32( GetCurrentParam( ref nodeParams ) ); for( int i = 0; i < m_enumCount; i++ ) { m_enumNames.Add( GetCurrentParam( ref nodeParams ) ); m_enumValues.Add( Convert.ToInt32( GetCurrentParam( ref nodeParams ) ) ); } } if( UIUtils.CurrentShaderVersion() > 14501 ) { m_enumModeInt = Convert.ToInt32( GetCurrentParam( ref nodeParams ) ); if( m_enumModeInt == 1 ) m_enumClassName = GetCurrentParam( ref nodeParams ); m_autoRegister = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) ); m_customAttrCount = Convert.ToInt32( GetCurrentParam( ref nodeParams ) ); for( int i = 0; i < m_customAttrCount; i++ ) { m_customAttr.Add( GetCurrentParam( ref nodeParams ) ); } if( m_customAttrCount > 0 ) { m_visibleCustomAttrFoldout = true; m_visibleAttribsFoldout = true; } } if( UIUtils.CurrentShaderVersion() > 18003 ) { m_hybridInstanced = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) ); } CheckEnumAttribute(); CheckHeaderAttribute(); if( m_enumCount > 0 ) m_visibleEnumsFoldout = true; m_propertyNameIsDirty = true; m_reRegisterName = false; if( !m_isNodeBeingCopied ) { if( m_variableMode != VariableMode.Fetch || m_currentParameterType == PropertyType.Constant ) { UIUtils.ReleaseUniformName( UniqueId, m_oldName ); UIUtils.RegisterUniformName( UniqueId, m_propertyName ); m_oldName = m_propertyName; } } else { m_oldName = m_propertyName; } ReleaseRansomedProperty(); } public virtual void ReleaseRansomedProperty() { if( m_variableMode == VariableMode.Fetch && m_autoGlobalName ) { CurrentVariableMode = VariableMode.Create; CurrentVariableMode = VariableMode.Fetch; } } void UpdateTooltip() { string currValue = string.Empty; if( m_currentParameterType != PropertyType.Constant ) { currValue = ( m_currentParameterType == PropertyType.Global && m_globalDefaultBehavior ) ? "" : GetPropertyValStr(); } else { currValue = GetPropertyValStr(); } m_tooltipText = string.Format( TooltipFormatter, m_nodeAttribs.Description, m_propertyInspectorName, currValue ); } public override void SetClippedTitle( string newText, int maxSize = 170, string endString = "..." ) { base.SetClippedTitle( newText, maxSize, endString ); UpdateTooltip(); } public override void SetClippedAdditionalTitle( string newText, int maxSize = 170, string endString = "..." ) { base.SetClippedAdditionalTitle( newText, maxSize, endString ); UpdateTooltip(); } public override void OnEnable() { base.OnEnable(); m_reRegisterName = true; } public bool CanDrawMaterial { get { return m_materialMode && m_currentParameterType != PropertyType.Constant; } } public int RawOrderIndex { get { return m_orderIndex; } } public int OrderIndex { get { return m_orderIndex + m_orderIndexOffset; } set { m_orderIndex = value; } } public int OrderIndexOffset { get { return m_orderIndexOffset; } set { m_orderIndexOffset = value; } } public VariableMode CurrentVariableMode { get { return m_variableMode; } set { if( value != m_variableMode ) { m_variableMode = value; if( value == VariableMode.Fetch ) { m_oldName = m_propertyName; } else { if( !m_propertyName.Equals( m_oldName ) ) { if( UIUtils.IsUniformNameAvailable( m_propertyName ) ) { UIUtils.ReleaseUniformName( UniqueId, m_oldName ); UIUtils.RegisterUniformName( UniqueId, m_propertyName ); } else { UIUtils.ShowMessage( UniqueId, string.Format( FetchToCreateDuplicatesMsg, m_propertyName, m_oldName ), MessageSeverity.Warning ); m_propertyName = m_oldName; } m_propertyNameIsDirty = true; OnPropertyNameChanged(); } else if( UIUtils.CheckUniformNameOwner( m_propertyName ) != UniqueId ) { string oldProperty = m_propertyName; RegisterFirstAvailablePropertyName( false ); UIUtils.ShowMessage( UniqueId, string.Format( FetchToCreateOnDuplicateNodeMsg, m_propertyName, oldProperty ), MessageSeverity.Warning ); } } } } } public string PropertyData( MasterNodePortCategory portCategory ) { return ( m_currentParameterType == PropertyType.InstancedProperty ) ? m_outputPorts[ 0 ].LocalValue( portCategory ) : m_propertyName; } public override void OnNodeLogicUpdate( DrawInfo drawInfo ) { base.OnNodeLogicUpdate( drawInfo ); if( m_currentParameterType == PropertyType.Global && m_globalDefaultBehavior && ( EditorApplication.timeSinceStartup - m_globalFetchTimestamp ) > MaxGlobalFetchTimestamp ) { FetchGlobalValue(); m_globalFetchTimestamp = EditorApplication.timeSinceStartup; } } public void ShowGlobalValueButton() { if( GUILayout.Button( "Set Global Value" ) ) { SetGlobalValue(); } } public override bool CheckFindText( string text ) { return base.CheckFindText( text ) || m_propertyName.IndexOf( text, StringComparison.CurrentCultureIgnoreCase ) >= 0 || m_propertyInspectorName.IndexOf( text, StringComparison.CurrentCultureIgnoreCase ) >= 0; } //This should only be used on template internal properties public void PropertyNameFromTemplate( TemplateShaderPropertyData data ) { m_propertyName = data.PropertyName; m_propertyInspectorName = data.PropertyInspectorName; } public virtual void GeneratePPSInfo( ref string propertyDeclaration, ref string propertySet ) { } public virtual void SetGlobalValue() { } public virtual void FetchGlobalValue() { } public virtual string PropertyName { get { return m_propertyName; } } public virtual string PropertyInspectorName { get { return m_propertyInspectorName; } } public bool FreeType { get { return m_freeType; } set { m_freeType = value; } } public bool ReRegisterName { get { return m_reRegisterName; } set { m_reRegisterName = value; } } public string CustomPrefix { get { return m_customPrefix; } set { m_customPrefix = value; } } public override void RefreshOnUndo() { base.RefreshOnUndo(); BeginPropertyFromInspectorCheck(); } public override string DataToArray { get { return PropertyInspectorName; } } public bool RegisterPropertyOnInstancing { get { return m_registerPropertyOnInstancing; } set { m_registerPropertyOnInstancing = value; } } public bool SrpBatcherCompatible { get { return m_srpBatcherCompatible; } } public bool AddGlobalToSRPBatcher { get { return m_addGlobalToSRPBatcher; } set { m_addGlobalToSRPBatcher = value; } } public bool AutoRegister { get { return m_autoRegister; } set { m_autoRegister = value; } } } }