diff options
Diffstat (limited to 'Assets/AmplifyShaderEditor/Plugins/Editor/Templates')
92 files changed, 23882 insertions, 0 deletions
diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalDefinesHelper.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalDefinesHelper.cs new file mode 100644 index 00000000..fb4d7569 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalDefinesHelper.cs @@ -0,0 +1,31 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateAdditionalDefinesHelper : TemplateAdditionalParentHelper + { + public TemplateAdditionalDefinesHelper() : base( "Additional Defines" ) + { + m_helpBoxMessage = "Please add your defines without the #define keywords"; + } + + public override void AddToDataCollector( ref MasterNodeDataCollector dataCollector, TemplateIncludePragmaContainter nativesContainer ) + { + for( int i = 0; i < m_additionalItems.Count; i++ ) + { + if( !string.IsNullOrEmpty( m_additionalItems[ i ] ) && !nativesContainer.HasDefine( m_additionalItems[ i ] ) ) + dataCollector.AddToDefines( -1, m_additionalItems[ i ] ); + } + + for( int i = 0; i < m_outsideItems.Count; i++ ) + { + if( !string.IsNullOrEmpty( m_outsideItems[ i ] ) && !nativesContainer.HasDefine( m_outsideItems[ i ] ) ) + dataCollector.AddToDefines( -1, m_outsideItems[ i ] ); + } + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalDefinesHelper.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalDefinesHelper.cs.meta new file mode 100644 index 00000000..3194a2ab --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalDefinesHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 35a7fdfdb9a6b0048aa322a9fe58a371 +timeCreated: 1520275148 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalDirectivesHelper.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalDirectivesHelper.cs new file mode 100644 index 00000000..31c03b59 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalDirectivesHelper.cs @@ -0,0 +1,837 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using System.IO; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using UnityEditorInternal; + +namespace AmplifyShaderEditor +{ + public enum AdditionalLineType + { + Include, + Define, + Pragma, + Custom + } + + public enum AdditionalContainerOrigin + { + Native, + ShaderFunction, + Custom + } + + + [Serializable] + public class AdditionalDirectiveContainerSaveItem + { + public AdditionalLineType LineType = AdditionalLineType.Include; + public string LineValue = string.Empty; + public bool GUIDToggle = false; + public string GUIDValue = string.Empty; + public AdditionalContainerOrigin Origin = AdditionalContainerOrigin.Custom; + public AdditionalDirectiveContainerSaveItem( AdditionalLineType lineType, string lineValue, bool guidToggle, string guidValue, AdditionalContainerOrigin origin ) + { + LineType = lineType; + LineValue = lineValue; + GUIDToggle = guidToggle; + GUIDValue = guidValue; + Origin = origin; + } + + public AdditionalDirectiveContainerSaveItem( AdditionalDirectiveContainer container ) + { + LineType = container.LineType; + LineValue = container.LineValue; + GUIDToggle = container.GUIDToggle; + GUIDValue = container.GUIDValue; + Origin = container.Origin; + } + } + + [Serializable] + public class AdditionalDirectiveContainer : ScriptableObject + { + public AdditionalLineType LineType = AdditionalLineType.Include; + public string LineValue = string.Empty; + public bool GUIDToggle = false; + public string GUIDValue = string.Empty; + public AdditionalContainerOrigin Origin = AdditionalContainerOrigin.Custom; + public TextAsset LibObject = null; + public string OwnerId = string.Empty; + + public void Init( string ownerId, AdditionalDirectiveContainer item ) + { + LineType = item.LineType; + LineValue = item.LineValue; + GUIDToggle = item.GUIDToggle; + GUIDValue = item.GUIDValue; + Origin = item.Origin; + LibObject = item.LibObject; + OwnerId = ownerId; + } + + public void Init( AdditionalDirectiveContainerSaveItem item ) + { + LineType = item.LineType; + LineValue = item.LineValue; + GUIDToggle = item.GUIDToggle; + GUIDValue = item.GUIDValue; + Origin = item.Origin; + if( GUIDToggle ) + { + LibObject = AssetDatabase.LoadAssetAtPath<TextAsset>( AssetDatabase.GUIDToAssetPath( GUIDValue ) ); + } + } + + public void OnDestroy() + { + //Debug.Log( "Destoying directives" ); + LibObject = null; + } + + public string Value + { + get + { + switch( LineType ) + { + case AdditionalLineType.Include: + { + if( GUIDToggle ) + { + string shaderPath = AssetDatabase.GUIDToAssetPath( GUIDValue ); + if( !string.IsNullOrEmpty( shaderPath ) ) + return shaderPath; + } + return LineValue; + } + case AdditionalLineType.Define: return LineValue; + case AdditionalLineType.Pragma: return LineValue; + } + return LineValue; + } + } + + public string FormattedValue + { + get + { + switch( LineType ) + { + case AdditionalLineType.Include: + { + if( GUIDToggle ) + { + string shaderPath = AssetDatabase.GUIDToAssetPath( GUIDValue ); + if( !string.IsNullOrEmpty( shaderPath ) ) + return string.Format( Constants.IncludeFormat, shaderPath ); + } + + return string.Format( Constants.IncludeFormat, LineValue ); + } + case AdditionalLineType.Define: + return string.Format( Constants.DefineFormat, LineValue ); + case AdditionalLineType.Pragma: + return string.Format( Constants.PragmaFormat, LineValue ); + } + return LineValue; + } + } + } + + + + public enum ReordableAction + { + None, + Add, + Remove + } + + [Serializable] + public sealed class TemplateAdditionalDirectivesHelper : TemplateModuleParent + { + private string NativeFoldoutStr = "Native"; + + [SerializeField] + private List<AdditionalDirectiveContainer> m_additionalDirectives = new List<AdditionalDirectiveContainer>(); + + [SerializeField] + private List<AdditionalDirectiveContainer> m_shaderFunctionDirectives = new List<AdditionalDirectiveContainer>(); + + [SerializeField] + private List<string> m_nativeDirectives = new List<string>(); + + [SerializeField] + private int m_nativeDirectivesIndex = -1; + + [SerializeField] + private bool m_nativeDirectivesFoldout = false; + + //ONLY USED BY SHADER FUNCTIONS + // Since AdditionalDirectiveContainer must be a ScriptableObject because of serialization shenanigans it will not serialize the info correctly into the shader function when saving it into a file ( it only saves the id ) + // For it to properly work, each AdditionalDirectiveContainer should be added to the SF asset, but that would make it to have children ( which are seen on the project inspector ) + // Must revisit this later on and come up with a proper solution + [SerializeField] + private List<AdditionalDirectiveContainerSaveItem> m_directivesSaveItems = new List<AdditionalDirectiveContainerSaveItem>(); + + + private ReordableAction m_actionType = ReordableAction.None; + private int m_actionIndex = 0; + private ReorderableList m_reordableList = null; + private GUIStyle m_propertyAdjustment; + private UndoParentNode m_currOwner; + private Rect m_nativeRect = Rect.zero; + + public TemplateAdditionalDirectivesHelper( string moduleName ) : base( moduleName ) { } + + //public void AddShaderFunctionItem( AdditionalLineType type, string item ) + //{ + // UpdateShaderFunctionDictionary(); + // string id = type + item; + // if( !m_shaderFunctionDictionary.ContainsKey( id ) ) + // { + // AdditionalDirectiveContainer newItem = ScriptableObject.CreateInstance<AdditionalDirectiveContainer>(); + // newItem.LineType = type; + // newItem.LineValue = item; + // newItem.hideFlags = HideFlags.HideAndDontSave; + // m_shaderFunctionDirectives.Add( newItem ); + // m_shaderFunctionDictionary.Add( id, newItem ); + // } + //} + + public void AddShaderFunctionItems( string ownerOutputId, List<AdditionalDirectiveContainer> functionList ) + { + RemoveShaderFunctionItems( ownerOutputId ); + if( functionList.Count > 0 ) + { + for( int i = 0; i < functionList.Count; i++ ) + { + AdditionalDirectiveContainer item = ScriptableObject.CreateInstance<AdditionalDirectiveContainer>(); + item.Init( ownerOutputId, functionList[ i ] ); + m_shaderFunctionDirectives.Add( item ); + } + } + //if( functionList.Count > 0 ) + //{ + + // m_shaderFunctionDirectives.AddRange( functionList ); + //} + } + + public void RemoveShaderFunctionItems( string ownerOutputId/*, List<AdditionalDirectiveContainer> functionList */) + { + List<AdditionalDirectiveContainer> list = m_shaderFunctionDirectives.FindAll( ( x ) => x.OwnerId.Equals( ownerOutputId )); + for( int i = 0; i < list.Count; i++ ) + { + m_shaderFunctionDirectives.Remove( list[ i ] ); + ScriptableObject.DestroyImmediate( list[ i ] ); + } + list.Clear(); + list = null; + + //for( int i = 0; i < functionList.Count; i++ ) + //{ + // m_shaderFunctionDirectives.Remove( functionList[ i ] ); + //} + } + + //public void RemoveShaderFunctionItem( AdditionalLineType type, string item ) + //{ + // m_shaderFunctionDirectives.RemoveAll( x => x.LineType == type && x.LineValue.Equals( item ) ); + //} + + public void AddItems( AdditionalLineType type, List<string> items ) + { + int count = items.Count; + for( int i = 0; i < count; i++ ) + { + AdditionalDirectiveContainer newItem = ScriptableObject.CreateInstance<AdditionalDirectiveContainer>(); + newItem.LineType = type; + newItem.LineValue = items[ i ]; + newItem.hideFlags = HideFlags.HideAndDontSave; + m_additionalDirectives.Add( newItem ); + } + UpdateNativeIndex(); + } + + public void AddNativeContainer() + { + if( m_nativeDirectives.Count > 0 ) + { + if( m_additionalDirectives.FindIndex( x => x.Origin.Equals( AdditionalContainerOrigin.Native ) ) == -1 ) + { + AdditionalDirectiveContainer newItem = ScriptableObject.CreateInstance<AdditionalDirectiveContainer>(); + newItem.Origin = AdditionalContainerOrigin.Native; + newItem.hideFlags = HideFlags.HideAndDontSave; + //m_additionalDirectives.Add( newItem ); + //m_nativeDirectivesIndex = m_additionalDirectives.Count - 1; + m_additionalDirectives.Insert( 0, newItem ); + m_nativeDirectivesIndex = 0; + } + } + } + + public void FillNativeItems( List<string> nativeItems ) + { + m_nativeDirectives.Clear(); + m_nativeDirectives.AddRange( nativeItems ); + AddNativeContainer(); + } + + void DrawNativeItems() + { + EditorGUILayout.Separator(); + EditorGUI.indentLevel++; + int count = m_nativeDirectives.Count; + for( int i = 0; i < count; i++ ) + { + EditorGUILayout.LabelField( m_nativeDirectives[ i ] ); + } + EditorGUI.indentLevel--; + EditorGUILayout.Separator(); + } + + void DrawNativeItemsRect() + { + int count = m_nativeDirectives.Count; + m_nativeRect.y += EditorGUIUtility.singleLineHeight; + for( int i = 0; i < count; i++ ) + { + EditorGUI.LabelField( m_nativeRect, m_nativeDirectives[ i ] ); + m_nativeRect.y += EditorGUIUtility.singleLineHeight; + } + } + + void DrawButtons() + { + EditorGUILayout.Separator(); + + // Add keyword + if( GUILayout.Button( string.Empty, UIUtils.PlusStyle, GUILayout.Width( Constants.PlusMinusButtonLayoutWidth ) ) ) + { + AdditionalDirectiveContainer newItem = ScriptableObject.CreateInstance<AdditionalDirectiveContainer>(); + newItem.hideFlags = HideFlags.HideAndDontSave; + m_additionalDirectives.Add( newItem ); + UpdateNativeIndex(); + EditorGUI.FocusTextInControl( null ); + m_isDirty = true; + } + + //Remove keyword + if( GUILayout.Button( string.Empty, UIUtils.MinusStyle, GUILayout.Width( Constants.PlusMinusButtonLayoutWidth ) ) ) + { + if( m_additionalDirectives.Count > 0 ) + { + AdditionalDirectiveContainer itemToDelete = m_additionalDirectives[ m_additionalDirectives.Count - 1 ]; + m_additionalDirectives.RemoveAt( m_additionalDirectives.Count - 1 ); + ScriptableObject.DestroyImmediate( itemToDelete ); + EditorGUI.FocusTextInControl( null ); + } + m_isDirty = true; + } + } + + public override void Draw( UndoParentNode currOwner, bool style = true ) + { + m_currOwner = currOwner; + if( m_reordableList == null ) + { + m_reordableList = new ReorderableList( m_additionalDirectives, typeof( AdditionalDirectiveContainer ), true, false, false, false ) + { + headerHeight = 0, + footerHeight = 0, + showDefaultBackground = false, + elementHeightCallback = ( index ) => + { + if( m_additionalDirectives[ index ].Origin == AdditionalContainerOrigin.Native && m_nativeDirectivesFoldout ) + { + return ( m_nativeDirectives.Count + 1 ) * ( EditorGUIUtility.singleLineHeight ) + 5; + } + + return EditorGUIUtility.singleLineHeight + 5; + }, + drawElementCallback = ( Rect rect, int index, bool isActive, bool isFocused ) => + { + if( m_additionalDirectives[ index ].Origin == AdditionalContainerOrigin.Native && m_nativeDirectivesFoldout ) + { + rect.height = ( m_nativeDirectives.Count + 1 ) * ( EditorGUIUtility.singleLineHeight ) + 5; + } + + if( m_additionalDirectives[ index ] != null ) + { + float labelWidthStyleAdjust = 0; + if( style ) + { + rect.xMin -= 10; + labelWidthStyleAdjust = 15; + } + else + { + rect.xMin -= 1; + } + + float popUpWidth = style ? 75 : 60f; + float widthAdjust = m_additionalDirectives[ index ].LineType == AdditionalLineType.Include ? -14 : 0; + Rect popupPos = new Rect( rect.x, rect.y, popUpWidth, EditorGUIUtility.singleLineHeight ); + Rect GUIDTogglePos = m_additionalDirectives[ index ].LineType == AdditionalLineType.Include ? new Rect( rect.x + rect.width - 3 * Constants.PlusMinusButtonLayoutWidth, rect.y, Constants.PlusMinusButtonLayoutWidth, Constants.PlusMinusButtonLayoutWidth ) : new Rect(); + Rect buttonPlusPos = new Rect( rect.x + rect.width - 2 * Constants.PlusMinusButtonLayoutWidth, rect.y - 2, Constants.PlusMinusButtonLayoutWidth, Constants.PlusMinusButtonLayoutWidth ); + Rect buttonMinusPos = new Rect( rect.x + rect.width - Constants.PlusMinusButtonLayoutWidth, rect.y - 2, Constants.PlusMinusButtonLayoutWidth, Constants.PlusMinusButtonLayoutWidth ); + float labelWidthBuffer = EditorGUIUtility.labelWidth; + Rect labelPos = new Rect( rect.x + popupPos.width - labelWidthStyleAdjust, rect.y, labelWidthStyleAdjust + rect.width - popupPos.width - buttonPlusPos.width - buttonMinusPos.width + widthAdjust, EditorGUIUtility.singleLineHeight ); + + if( m_additionalDirectives[ index ].Origin == AdditionalContainerOrigin.Native ) + { + m_nativeRect = rect; +#if UNITY_2019_3_OR_NEWER + m_nativeRect.y -= ( m_nativeRect.height - ( EditorGUIUtility.singleLineHeight + 5 ) ) * 0.5f; +#endif + m_nativeRect.xMin += 2; + m_nativeRect.xMax -= 2; + m_nativeRect.yMax -= 2; + + NodeUtils.DrawNestedPropertyGroup( ref m_nativeDirectivesFoldout, rect, NativeFoldoutStr, DrawNativeItemsRect, 4 ); + return; + } + + m_additionalDirectives[ index ].LineType = (AdditionalLineType)m_currOwner.EditorGUIEnumPopup( popupPos, m_additionalDirectives[ index ].LineType ); + + if( m_additionalDirectives[ index ].LineType == AdditionalLineType.Include ) + { + if( m_additionalDirectives[ index ].GUIDToggle ) + { + //if( m_additionalDirectives[ index ].LibObject == null && !string.IsNullOrEmpty( m_additionalDirectives[ index ].GUIDValue ) ) + //{ + // m_additionalDirectives[ index ].LibObject = AssetDatabase.LoadAssetAtPath<TextAsset>( AssetDatabase.GUIDToAssetPath( m_additionalDirectives[ index ].GUIDValue ) ); + //} + + EditorGUI.BeginChangeCheck(); + TextAsset obj = m_currOwner.EditorGUIObjectField( labelPos, m_additionalDirectives[ index ].LibObject, typeof( TextAsset ), false ) as TextAsset; + if( EditorGUI.EndChangeCheck() ) + { + string pathName = AssetDatabase.GetAssetPath( obj ); + string extension = Path.GetExtension( pathName ); + extension = extension.ToLower(); + if( extension.Equals( ".cginc" ) || extension.Equals( ".hlsl" ) ) + { + m_additionalDirectives[ index ].LibObject = obj; + m_additionalDirectives[ index ].GUIDValue = AssetDatabase.AssetPathToGUID( pathName ); + } + } + } + else + { + m_additionalDirectives[ index ].LineValue = m_currOwner.EditorGUITextField( labelPos, string.Empty, m_additionalDirectives[ index ].LineValue ); + } + + if( GUI.Button( GUIDTogglePos, m_additionalDirectives[ index ].GUIDToggle ? UIUtils.FloatIntIconOFF : UIUtils.FloatIntIconON, UIUtils.FloatIntPickerONOFF ) ) + m_additionalDirectives[ index ].GUIDToggle = !m_additionalDirectives[ index ].GUIDToggle; + } + else + { + m_additionalDirectives[ index ].LineValue = m_currOwner.EditorGUITextField( labelPos, string.Empty, m_additionalDirectives[ index ].LineValue ); + } + + if( GUI.Button( buttonPlusPos, string.Empty, UIUtils.PlusStyle ) ) + { + m_actionType = ReordableAction.Add; + m_actionIndex = index; + } + + if( GUI.Button( buttonMinusPos, string.Empty, UIUtils.MinusStyle ) ) + { + m_actionType = ReordableAction.Remove; + m_actionIndex = index; + } + } + }, + onReorderCallback = ( ReorderableList list ) => + { + UpdateNativeIndex(); + } + }; + } + + if( m_actionType != ReordableAction.None ) + { + switch( m_actionType ) + { + case ReordableAction.Add: + { + AdditionalDirectiveContainer newItem = ScriptableObject.CreateInstance<AdditionalDirectiveContainer>(); + newItem.hideFlags = HideFlags.HideAndDontSave; + m_additionalDirectives.Insert( m_actionIndex + 1, newItem ); + } + break; + case ReordableAction.Remove: + AdditionalDirectiveContainer itemToDelete = m_additionalDirectives[ m_actionIndex ]; + m_additionalDirectives.RemoveAt( m_actionIndex ); + ScriptableObject.DestroyImmediate( itemToDelete ); + break; + } + m_isDirty = true; + m_actionType = ReordableAction.None; + EditorGUI.FocusTextInControl( null ); + } + bool foldoutValue = currOwner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedAdditionalDirectives; + if( style ) + { + NodeUtils.DrawPropertyGroup( ref foldoutValue, m_moduleName, DrawReordableList, DrawButtons ); + } + else + { + NodeUtils.DrawNestedPropertyGroup( ref foldoutValue, m_moduleName, DrawReordableList, DrawButtons ); + } + currOwner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedAdditionalDirectives = foldoutValue; + } + + void DrawReordableList() + { + if( m_reordableList != null ) + { + if( m_propertyAdjustment == null ) + { + m_propertyAdjustment = new GUIStyle(); + m_propertyAdjustment.padding.left = 17; + } + //EditorGUILayout.BeginVertical( m_propertyAdjustment ); + EditorGUILayout.Space(); + if( m_nativeDirectives.Count > 0 ) + { + //NodeUtils.DrawNestedPropertyGroup( ref m_nativeDirectivesFoldout, NativeFoldoutStr, DrawNativeItems, 4 ); + } + if( m_additionalDirectives.Count == 0 ) + { + EditorGUILayout.HelpBox( "Your list is Empty!\nUse the plus button to add one.", MessageType.Info ); + } + else + { + m_reordableList.DoLayoutList(); + } + EditorGUILayout.Space(); + //EditorGUILayout.EndVertical(); + } + } + + public void AddAllToDataCollector( ref MasterNodeDataCollector dataCollector, TemplateIncludePragmaContainter nativesContainer ) + { + //List<AdditionalDirectiveContainer> list = m_additionalDirectives; + //int count = list.FindIndex( x => x.Origin.Equals( AdditionalContainerOrigin.Native ) ); + //for( int i = 0; i < count; i++ ) + //{ + // switch( list[ i ].LineType ) + // { + // case AdditionalLineType.Include: + // { + // string value = list[ i ].Value; + // if( !string.IsNullOrEmpty( value ) && + // !nativesContainer.HasInclude( value ) ) + // { + // dataCollector.AddToMisc( list[ i ].FormattedValue ); + // } + // } + // break; + // case AdditionalLineType.Define: + // { + // if( !string.IsNullOrEmpty( list[ i ].LineValue ) && + // !nativesContainer.HasDefine( list[ i ].LineValue ) ) + // { + // dataCollector.AddToMisc( list[ i ].FormattedValue ); + // } + // } + // break; + // case AdditionalLineType.Pragma: + // { + // if( !string.IsNullOrEmpty( list[ i ].LineValue ) && + // !nativesContainer.HasPragma( list[ i ].LineValue ) ) + // { + // dataCollector.AddToMisc( list[ i ].FormattedValue ); + // } + // } + // break; + // default: + // case AdditionalLineType.Custom: + // dataCollector.AddToMisc( list[ i ].LineValue ); + // break; + // } + //} + + AddToDataCollector( ref dataCollector, nativesContainer, false ); + AddToDataCollector( ref dataCollector, nativesContainer, true ); + } + + public void AddAllToDataCollector( ref MasterNodeDataCollector dataCollector ) + { + AddToDataCollector( ref dataCollector, false ); + AddToDataCollector( ref dataCollector, true ); + } + + void AddToDataCollector( ref MasterNodeDataCollector dataCollector, TemplateIncludePragmaContainter nativesContainer, bool fromSF ) + { + List<AdditionalDirectiveContainer> list = fromSF ? m_shaderFunctionDirectives : m_additionalDirectives; + int count = list.Count; + for( int i = 0; i < count; i++ ) + { + int orderIdx = fromSF ? 1 : ( i > m_nativeDirectivesIndex ? 1 : -1 ); + switch( list[ i ].LineType ) + { + case AdditionalLineType.Include: + { + string value = list[ i ].Value; + if( !string.IsNullOrEmpty( value ) && + !nativesContainer.HasInclude( value ) ) + { + dataCollector.AddToDirectives( list[ i ].FormattedValue, orderIdx ); + } + } + break; + case AdditionalLineType.Define: + { + if( !string.IsNullOrEmpty( list[ i ].LineValue ) && + !nativesContainer.HasDefine( list[ i ].LineValue ) ) + { + dataCollector.AddToDirectives( list[ i ].FormattedValue, orderIdx ); + } + } + break; + case AdditionalLineType.Pragma: + { + if( !string.IsNullOrEmpty( list[ i ].LineValue ) && + !nativesContainer.HasPragma( list[ i ].LineValue ) ) + { + dataCollector.AddToDirectives( list[ i ].FormattedValue, orderIdx ); + } + } + break; + default: + case AdditionalLineType.Custom: + dataCollector.AddToDirectives( list[ i ].LineValue, orderIdx ); + break; + } + } + } + + void AddToDataCollector( ref MasterNodeDataCollector dataCollector, bool fromSF ) + { + List<AdditionalDirectiveContainer> list = fromSF ? m_shaderFunctionDirectives : m_additionalDirectives; + int orderIdx = 1; + int count = list.Count; + for( int i = 0; i < count; i++ ) + { + switch( list[ i ].LineType ) + { + case AdditionalLineType.Include: + { + string value = list[ i ].FormattedValue; + if( !string.IsNullOrEmpty( value ) ) + { + dataCollector.AddToDirectives( value, orderIdx ); + } + } + break; + case AdditionalLineType.Define: + { + if( !string.IsNullOrEmpty( list[ i ].LineValue ) ) + { + dataCollector.AddToDirectives( list[ i ].FormattedValue, orderIdx ); + } + } + break; + case AdditionalLineType.Pragma: + { + if( !string.IsNullOrEmpty( list[ i ].LineValue ) ) + { + dataCollector.AddToDirectives( list[ i ].FormattedValue, orderIdx ); + } + } + break; + default: + case AdditionalLineType.Custom: + dataCollector.AddToDirectives( list[ i ].LineValue, orderIdx ); + break; + } + } + } + + public override void ReadFromString( ref uint index, ref string[] nodeParams ) + { + try + { + m_nativeDirectivesIndex = -1; + int count = Convert.ToInt32( nodeParams[ index++ ] ); + m_additionalDirectives.Clear(); + for( int i = 0; i < count; i++ ) + { + AdditionalLineType lineType = (AdditionalLineType)Enum.Parse( typeof( AdditionalLineType ), nodeParams[ index++ ] ); + string lineValue = nodeParams[ index++ ]; + AdditionalDirectiveContainer newItem = ScriptableObject.CreateInstance<AdditionalDirectiveContainer>(); + newItem.hideFlags = HideFlags.HideAndDontSave; + newItem.LineType = lineType; + newItem.LineValue = lineValue.Replace( Constants.SemiColonSeparator, ';' ); + if( UIUtils.CurrentShaderVersion() > 15607 ) + { + newItem.GUIDToggle = Convert.ToBoolean( nodeParams[ index++ ] ); + newItem.GUIDValue = nodeParams[ index++ ]; + if( newItem.GUIDToggle ) + { + newItem.LibObject = AssetDatabase.LoadAssetAtPath<TextAsset>( AssetDatabase.GUIDToAssetPath( newItem.GUIDValue ) ); + if( newItem.LibObject == null ) + { + Debug.LogWarning( "Include file not found with GUID " + newItem.GUIDValue ); + } + } + } + AdditionalContainerOrigin origin = AdditionalContainerOrigin.Custom; + if( UIUtils.CurrentShaderVersion() > 16902 ) + { + origin = (AdditionalContainerOrigin)Enum.Parse( typeof( AdditionalContainerOrigin ), nodeParams[ index++ ] ); + newItem.Origin = origin; + } + + m_additionalDirectives.Add( newItem ); + + if( origin == AdditionalContainerOrigin.Native ) + { + m_nativeDirectivesIndex = i; + } + } + AddNativeContainer(); + } + catch( Exception e ) + { + Debug.LogException( e ); + } + } + + public override void WriteToString( ref string nodeInfo ) + { + if( m_additionalDirectives.Count == 1 && m_additionalDirectives[ 0 ].Origin == AdditionalContainerOrigin.Native ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, 0 ); + return; + } + + IOUtils.AddFieldValueToString( ref nodeInfo, m_additionalDirectives.Count ); + for( int i = 0; i < m_additionalDirectives.Count; i++ ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_additionalDirectives[ i ].LineType ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_additionalDirectives[ i ].LineValue.Replace( ';', Constants.SemiColonSeparator ) ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_additionalDirectives[ i ].GUIDToggle ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_additionalDirectives[ i ].GUIDValue ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_additionalDirectives[ i ].Origin ); + } + } + + // read comment on m_directivesSaveItems declaration + public void UpdateSaveItemsFromDirectives() + { + bool foundNull = false; + m_directivesSaveItems.Clear(); + for( int i = 0; i < m_additionalDirectives.Count; i++ ) + { + if( m_additionalDirectives[ i ] != null ) + { + m_directivesSaveItems.Add( new AdditionalDirectiveContainerSaveItem( m_additionalDirectives[ i ] ) ); + } + else + { + foundNull = true; + } + } + + if( foundNull ) + { + m_additionalDirectives.RemoveAll( item => item == null ); + } + } + + public void CleanNullDirectives() + { + m_additionalDirectives.RemoveAll( item => item == null ); + } + + public void ResetDirectivesOrigin() + { + for( int i = 0; i < m_directivesSaveItems.Count; i++ ) + { + m_directivesSaveItems[ i ].Origin = AdditionalContainerOrigin.Custom; + } + } + + // read comment on m_directivesSaveItems declaration + public void UpdateDirectivesFromSaveItems() + { + if( m_directivesSaveItems.Count > 0 ) + { + for( int i = 0; i < m_additionalDirectives.Count; i++ ) + { + if( m_additionalDirectives[ i ] != null ) + ScriptableObject.DestroyImmediate( m_additionalDirectives[ i ] ); + } + + m_additionalDirectives.Clear(); + + for( int i = 0; i < m_directivesSaveItems.Count; i++ ) + { + AdditionalDirectiveContainer newItem = ScriptableObject.CreateInstance<AdditionalDirectiveContainer>(); + newItem.hideFlags = HideFlags.HideAndDontSave; + newItem.Init( m_directivesSaveItems[ i ] ); + m_additionalDirectives.Add( newItem ); + } + UpdateNativeIndex(); + //m_directivesSaveItems.Clear(); + } + } + + void UpdateNativeIndex() + { + m_nativeDirectivesIndex = -1; + int count = m_additionalDirectives.Count; + for( int i = 0; i < count; i++ ) + { + if( m_additionalDirectives[ i ].Origin == AdditionalContainerOrigin.Native ) + { + m_nativeDirectivesIndex = i; + break; + } + } + } + + public override void Destroy() + { + base.Destroy(); + + m_nativeDirectives.Clear(); + m_nativeDirectives = null; + + for( int i = 0; i < m_additionalDirectives.Count; i++ ) + { + ScriptableObject.DestroyImmediate( m_additionalDirectives[ i ] ); + } + + m_additionalDirectives.Clear(); + m_additionalDirectives = null; + + for( int i = 0; i < m_shaderFunctionDirectives.Count; i++ ) + { + ScriptableObject.DestroyImmediate( m_shaderFunctionDirectives[ i ] ); + } + + m_shaderFunctionDirectives.Clear(); + m_shaderFunctionDirectives = null; + + + m_propertyAdjustment = null; + m_reordableList = null; + } + + + public List<AdditionalDirectiveContainer> DirectivesList { get { return m_additionalDirectives; } } + public bool IsValid { get { return m_validData; } set { m_validData = value; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalDirectivesHelper.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalDirectivesHelper.cs.meta new file mode 100644 index 00000000..43fdc898 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalDirectivesHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c6b57deeb826a674f9715fab4dfb4cb1 +timeCreated: 1528278077 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalIncludesHelper.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalIncludesHelper.cs new file mode 100644 index 00000000..7d58666b --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalIncludesHelper.cs @@ -0,0 +1,31 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateAdditionalIncludesHelper : TemplateAdditionalParentHelper + { + public TemplateAdditionalIncludesHelper() : base( "Additional Includes" ) + { + m_helpBoxMessage = "Please add your includes without the #include \"\" keywords"; + } + + public override void AddToDataCollector( ref MasterNodeDataCollector dataCollector , TemplateIncludePragmaContainter nativesContainer ) + { + for( int i = 0; i < m_additionalItems.Count; i++ ) + { + if( !string.IsNullOrEmpty( m_additionalItems[ i ] ) && !nativesContainer.HasInclude( m_additionalItems[ i ] ) ) + dataCollector.AddToIncludes( -1, m_additionalItems[ i ] ); + } + + for( int i = 0; i < m_outsideItems.Count; i++ ) + { + if( !string.IsNullOrEmpty( m_outsideItems[ i ] ) && !nativesContainer.HasInclude( m_outsideItems[ i ] ) ) + dataCollector.AddToIncludes( -1, m_outsideItems[ i ] ); + } + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalIncludesHelper.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalIncludesHelper.cs.meta new file mode 100644 index 00000000..9a454744 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalIncludesHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0ab4c474dfddce2429da08f56e651ed4 +timeCreated: 1520275148 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalParentHelper.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalParentHelper.cs new file mode 100644 index 00000000..da765cca --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalParentHelper.cs @@ -0,0 +1,193 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateAdditionalParentHelper : TemplateModuleParent + { + private string NativeFoldoutStr = "Native"; + + protected string m_helpBoxMessage = string.Empty; + private const float ShaderKeywordButtonLayoutWidth = 15; + private ParentNode m_currentOwner; + + [SerializeField] + protected List<string> m_nativeItems = new List<string>(); + + [SerializeField] + protected bool m_nativeItemsFoldout = false; + + [SerializeField] + protected List<string> m_additionalItems = new List<string>(); + + [SerializeField] + protected List<string> m_outsideItems = new List<string>(); + + public TemplateAdditionalParentHelper( string moduleName ) : base( moduleName ) { } + public bool IsValid { set{ m_validData = value; } get{ return m_validData; } } + + public void FillNativeItems( List<string> nativeItems ) + { + m_nativeItems.Clear(); + m_nativeItems.AddRange( nativeItems ); + } + + public void Draw( ParentNode owner ) + { + m_currentOwner = owner; + bool foldout = owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedAdditionalDefines; + NodeUtils.DrawNestedPropertyGroup( ref foldout, m_moduleName, DrawMainBody, DrawButtons ); + owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedAdditionalDefines = foldout; + } + + public void CopyFrom( TemplateAdditionalParentHelper other ) + { + m_additionalItems.Clear(); + m_outsideItems.Clear(); + int otherAdditionalItemsCount = other.ItemsList.Count; + for( int i = 0; i < otherAdditionalItemsCount; i++ ) + { + m_additionalItems.Add( other.ItemsList[ i ] ); + } + + int otherOusideItemsCount = other.OutsideList.Count; + for( int i = 0; i < otherOusideItemsCount; i++ ) + { + m_outsideItems.Add( other.OutsideList[ i ] ); + } + } + + void DrawButtons() + { + EditorGUILayout.Separator(); + + // Add keyword + if( GUILayout.Button( string.Empty, UIUtils.PlusStyle, GUILayout.Width( ShaderKeywordButtonLayoutWidth ) ) ) + { + m_additionalItems.Add( string.Empty ); + EditorGUI.FocusTextInControl( null ); + m_isDirty = true; + } + + //Remove keyword + if( GUILayout.Button( string.Empty, UIUtils.MinusStyle, GUILayout.Width( ShaderKeywordButtonLayoutWidth ) ) ) + { + if( m_additionalItems.Count > 0 ) + { + m_additionalItems.RemoveAt( m_additionalItems.Count - 1 ); + EditorGUI.FocusTextInControl( null ); + } + m_isDirty = true; + } + } + void DrawNativeItems() + { + EditorGUILayout.Separator(); + EditorGUI.indentLevel++; + int count = m_nativeItems.Count; + for ( int i = 0; i < count; i++ ) + { + EditorGUILayout.LabelField( m_nativeItems[i] ); + } + EditorGUI.indentLevel--; + EditorGUILayout.Separator(); + } + void DrawMainBody() + { + EditorGUILayout.Separator(); + + if( m_nativeItems.Count > 0 ) + { + NodeUtils.DrawNestedPropertyGroup( ref m_nativeItemsFoldout, NativeFoldoutStr, DrawNativeItems ,4); + } + + int itemCount = m_additionalItems.Count; + int markedToDelete = -1; + for( int i = 0; i < itemCount; i++ ) + { + EditorGUILayout.BeginHorizontal(); + { + EditorGUI.BeginChangeCheck(); + m_additionalItems[ i ] = EditorGUILayout.TextField( m_additionalItems[ i ] ); + if( EditorGUI.EndChangeCheck() ) + { + m_additionalItems[ i ] = UIUtils.RemoveShaderInvalidCharacters( m_additionalItems[ i ] ); + m_isDirty = true; + } + + // Add new port + if( m_currentOwner.GUILayoutButton( string.Empty, UIUtils.PlusStyle, GUILayout.Width( ShaderKeywordButtonLayoutWidth ) ) ) + { + m_additionalItems.Insert( i + 1, string.Empty ); + EditorGUI.FocusTextInControl( null ); + m_isDirty = true; + } + + //Remove port + if( m_currentOwner.GUILayoutButton( string.Empty, UIUtils.MinusStyle, GUILayout.Width( ShaderKeywordButtonLayoutWidth ) ) ) + { + markedToDelete = i; + m_isDirty = true; + } + } + EditorGUILayout.EndHorizontal(); + } + + if( markedToDelete > -1 ) + { + if( m_additionalItems.Count > markedToDelete ) + { + m_additionalItems.RemoveAt( markedToDelete ); + EditorGUI.FocusTextInControl( null ); + } + } + EditorGUILayout.Separator(); + EditorGUILayout.HelpBox( m_helpBoxMessage, MessageType.Info ); + } + + public override void ReadFromString( ref uint index, ref string[] nodeParams ) + { + try + { + int count = Convert.ToInt32( nodeParams[ index++ ] ); + for( int i = 0; i < count; i++ ) + { + m_additionalItems.Add( nodeParams[ index++ ] ); + } + } + catch( Exception e ) + { + Debug.LogException( e ); + } + } + + public override void WriteToString( ref string nodeInfo ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_additionalItems.Count ); + for( int i = 0; i < m_additionalItems.Count; i++ ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_additionalItems[ i ] ); + } + } + + public virtual void AddToDataCollector( ref MasterNodeDataCollector dataCollector , TemplateIncludePragmaContainter nativesContainer ) { } + + public override void Destroy() + { + m_additionalItems.Clear(); + m_additionalItems = null; + m_currentOwner = null; + m_nativeItems.Clear(); + m_nativeItems = null; + } + + public List<string> ItemsList { get { return m_additionalItems; } set { m_additionalItems = value; } } + public List<string> OutsideList { get { return m_outsideItems; } set { m_outsideItems = value; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalParentHelper.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalParentHelper.cs.meta new file mode 100644 index 00000000..6d0983fe --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalParentHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5360ba11600eeb44786246ca70212e25 +timeCreated: 1520332262 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalPragmasHelper.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalPragmasHelper.cs new file mode 100644 index 00000000..3c08f1a0 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalPragmasHelper.cs @@ -0,0 +1,31 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateAdditionalPragmasHelper : TemplateAdditionalParentHelper + { + public TemplateAdditionalPragmasHelper() : base( "Additional Pragmas" ) + { + m_helpBoxMessage = "Please add your pragmas without the #pragma keywords"; + } + + public override void AddToDataCollector( ref MasterNodeDataCollector dataCollector, TemplateIncludePragmaContainter nativesContainer ) + { + for( int i = 0; i < m_additionalItems.Count; i++ ) + { + if( !string.IsNullOrEmpty( m_additionalItems[ i ] ) && !nativesContainer.HasPragma( m_additionalItems[ i ] )) + dataCollector.AddToPragmas( -1, m_additionalItems[ i ] ); + } + + for( int i = 0; i < m_outsideItems.Count; i++ ) + { + if( !string.IsNullOrEmpty( m_outsideItems[ i ] ) && !nativesContainer.HasPragma( m_outsideItems[ i ] ) ) + dataCollector.AddToPragmas( -1, m_outsideItems[ i ] ); + } + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalPragmasHelper.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalPragmasHelper.cs.meta new file mode 100644 index 00000000..4abd0233 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateAdditionalPragmasHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: de89b62c2bd8eec4b915a0decba936fb +timeCreated: 1520275148 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateCodeSnippetBase.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateCodeSnippetBase.cs new file mode 100644 index 00000000..ea717e62 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateCodeSnippetBase.cs @@ -0,0 +1,102 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using UnityEngine; +using System.Collections.Generic; + +namespace AmplifyShaderEditor +{ + public enum TemplateCodeSnippetType + { + Toggle + }; + + + public enum TemplateCodeSnippetInfoIdx + { + Name = 0, + Type + }; + + [Serializable] + public class TemplateCodeSnippetElement + { + public string Id; + public string Snippet; + public TemplateCodeSnippetElement( string id, string snippet ) + { + Id = id; + Snippet = snippet; + } + } + + [Serializable] + public class TemplateCodeSnippetBase : ScriptableObject + { + [SerializeField] + private string m_nameId; + + [SerializeField] + private TemplateCodeSnippetType m_type; + + [SerializeField] + private List<TemplateCodeSnippetElement> m_elements = new List<TemplateCodeSnippetElement>(); + + public void Init( string nameId, TemplateCodeSnippetType type ) + { + m_nameId = nameId; + m_type = type; + } + + public void AddSnippet( TemplateCodeSnippetElement element ) + { + m_elements.Add( element ); + } + + public void Destroy() + { + for ( int i = 0; i < m_elements.Count; i++ ) + { + m_elements[ i ].Snippet = null; + } + m_elements.Clear(); + m_elements = null; + } + + public virtual void DrawProperties( ParentNode owner ) { } + public virtual bool CheckSnippet() { return true; } + + public void InsertSnippet( ref string shaderBody ) + { + bool insertSnippet = CheckSnippet(); + for ( int i = 0; i < m_elements.Count; i++ ) + { + shaderBody = shaderBody.Replace( m_elements[ i ].Id, ( insertSnippet ? m_elements[ i ].Snippet : string.Empty ) ); + } + } + public string NameId { get { return m_nameId; } } + public TemplateCodeSnippetType Type { get { return m_type; } } + public List<TemplateCodeSnippetElement> Elements { get { return m_elements; } } + } + + [Serializable] + public class TemplateCodeSnippetToggle : TemplateCodeSnippetBase + { + private const string Label = "Activate"; + [SerializeField] + private bool m_value = false; + + + public override bool CheckSnippet() + { + return m_value; + } + + public override void DrawProperties( ParentNode owner ) + { + m_value = owner.EditorGUILayoutToggle( Label, m_value ); + } + } + +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateCodeSnippetBase.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateCodeSnippetBase.cs.meta new file mode 100644 index 00000000..612a5536 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateCodeSnippetBase.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5fc48fb872ce5e74aa913f987a025ea4 +timeCreated: 1495113330 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateColorMaskModule.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateColorMaskModule.cs new file mode 100644 index 00000000..31739972 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateColorMaskModule.cs @@ -0,0 +1,184 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> +using System; +using UnityEngine; +using UnityEditor; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateColorMaskModule : TemplateModuleParent + { + private const string ColorMaskOp = "ColorMask "; + private const string ColorMaskOff = "ColorMask RGBA"; + private GUIContent ColorMaskContent = new GUIContent( "Color Mask", "Sets color channel writing mask, turning all off makes the object completely invisible\nDefault: RGBA" ); + private readonly char[] m_colorMaskChar = { 'R', 'G', 'B', 'A' }; + + private GUIStyle m_leftToggleColorMask; + private GUIStyle m_middleToggleColorMask; + private GUIStyle m_rightToggleColorMask; + + public TemplateColorMaskModule() : base( "Color Mask" ) { } + + [SerializeField] + private bool[] m_colorMask = { true, true, true, true }; + + [SerializeField] + private InlineProperty m_inlineColorMask = new InlineProperty(); + + public void CopyFrom( TemplateColorMaskModule other, bool allData ) + { + if( allData ) + m_independentModule = other.IndependentModule; + + for( int i = 0; i < m_colorMask.Length; i++ ) + { + m_colorMask[ i ] = other.ColorMask[ i ]; + } + m_inlineColorMask.CopyFrom( other.InlineColorMask ); + } + + public void ConfigureFromTemplateData( TemplateColorMaskData data ) + { + bool newValidData = ( data.DataCheck == TemplateDataCheck.Valid ); + if( newValidData && m_validData != newValidData ) + { + m_independentModule = data.IndependentModule; + if( string.IsNullOrEmpty( data.InlineData ) ) + { + for( int i = 0; i < 4; i++ ) + { + m_colorMask[ i ] = data.ColorMaskData[ i ]; + } + m_inlineColorMask.ResetProperty(); + } + else + { + m_inlineColorMask.SetInlineByName( data.InlineData ); + } + } + + m_validData = newValidData; + } + + public override void Draw( UndoParentNode owner, bool style = true ) + { + EditorGUI.BeginChangeCheck(); + { + m_inlineColorMask.CustomDrawer( ref owner, DrawColorMaskControls, ColorMaskContent.text ); + } + + if( EditorGUI.EndChangeCheck() ) + { + m_isDirty = true; + } + } + + private void DrawColorMaskControls( UndoParentNode owner ) + { + if( m_leftToggleColorMask == null || m_leftToggleColorMask.normal.background == null ) + { + m_leftToggleColorMask = GUI.skin.GetStyle( "ButtonLeft" ); + } + + if( m_middleToggleColorMask == null || m_middleToggleColorMask.normal.background == null ) + { + m_middleToggleColorMask = GUI.skin.GetStyle( "ButtonMid" ); + } + + if( m_rightToggleColorMask == null || m_rightToggleColorMask.normal.background == null ) + { + m_rightToggleColorMask = GUI.skin.GetStyle( "ButtonRight" ); + } + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField( ColorMaskContent, GUILayout.Width( 90 ) ); + + m_colorMask[ 0 ] = owner.GUILayoutToggle( m_colorMask[ 0 ], "R", m_leftToggleColorMask ); + m_colorMask[ 1 ] = owner.GUILayoutToggle( m_colorMask[ 1 ], "G", m_middleToggleColorMask ); + m_colorMask[ 2 ] = owner.GUILayoutToggle( m_colorMask[ 2 ], "B", m_middleToggleColorMask ); + m_colorMask[ 3 ] = owner.GUILayoutToggle( m_colorMask[ 3 ], "A", m_rightToggleColorMask ); + + EditorGUILayout.EndHorizontal(); + } + + public override string GenerateShaderData( bool isSubShader ) + { + if( m_inlineColorMask.IsValid ) + return ColorMaskOp + m_inlineColorMask.GetValueOrProperty(); + + int count = 0; + string colorMask = string.Empty; + for( int i = 0; i < m_colorMask.Length; i++ ) + { + if( m_colorMask[ i ] ) + { + count++; + colorMask += m_colorMaskChar[ i ]; + } + } + + if( count != m_colorMask.Length ) + { + return ColorMaskOp + ( ( count == 0 ) ? "0" : colorMask ); + } + + return ColorMaskOff; + } + + public override void ReadFromString( ref uint index, ref string[] nodeParams ) + { + bool validDataOnMeta = m_validData; + if( UIUtils.CurrentShaderVersion() > TemplatesManager.MPShaderVersion ) + { + validDataOnMeta = Convert.ToBoolean( nodeParams[ index++ ] ); + } + + if( validDataOnMeta ) + { + for( int i = 0; i < m_colorMask.Length; i++ ) + { + m_colorMask[ i ] = Convert.ToBoolean( nodeParams[ index++ ] ); + } + + if( UIUtils.CurrentShaderVersion() > 15303 ) + { + m_inlineColorMask.ReadFromString( ref index, ref nodeParams ); + } + } + } + + public override void WriteToString( ref string nodeInfo ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_validData ); + if( m_validData ) + { + for( int i = 0; i < m_colorMask.Length; i++ ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_colorMask[ i ] ); + } + m_inlineColorMask.WriteToString( ref nodeInfo ); + } + } + + public bool[] ColorMask + { + get { return m_colorMask; } + set + { + m_colorMask = value; + m_inlineColorMask.Active = false; + } + } + + public override void Destroy() + { + m_leftToggleColorMask = null; + m_middleToggleColorMask = null; + m_rightToggleColorMask = null; + m_inlineColorMask = null; + } + + public InlineProperty InlineColorMask { get { return m_inlineColorMask; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateColorMaskModule.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateColorMaskModule.cs.meta new file mode 100644 index 00000000..8cb1fbbb --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateColorMaskModule.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e1d9e34bd7946e247aa6d28b2859c6b1 +timeCreated: 1511259305 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateCullModeModule.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateCullModeModule.cs new file mode 100644 index 00000000..fed77dc0 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateCullModeModule.cs @@ -0,0 +1,125 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using UnityEngine; +using UnityEditor; +using System; + +namespace AmplifyShaderEditor +{ + [Serializable] + public sealed class TemplateCullModeModule : TemplateModuleParent + { + private const string CullModeFormatStr = "Cull "; + + public TemplateCullModeModule() : base("Cull Mode"){ } + + private static readonly string CullModeStr = "Cull Mode"; + + [SerializeField] + private CullMode m_cullMode = CullMode.Back; + + [SerializeField] + private InlineProperty m_inlineCullMode = new InlineProperty(); + + public void CopyFrom( TemplateCullModeModule other , bool allData ) + { + if( allData ) + m_independentModule = other.IndependentModule; + + m_cullMode = other.CurrentCullMode; + m_inlineCullMode.CopyFrom( other.CullInlineProperty ); + } + + public void ConfigureFromTemplateData( TemplateCullModeData data ) + { + bool newValidData = ( data.DataCheck == TemplateDataCheck.Valid ); + + if( newValidData && m_validData != newValidData ) + { + m_independentModule = data.IndependentModule; + if( string.IsNullOrEmpty( data.InlineData ) ) + { + m_cullMode = data.CullModeData; + m_inlineCullMode.IntValue = (int)m_cullMode; + m_inlineCullMode.ResetProperty(); + } + else + { + m_inlineCullMode.SetInlineByName( data.InlineData ); + } + } + + m_validData = newValidData; + } + + public override void Draw( UndoParentNode owner, bool style = true ) + { + EditorGUI.BeginChangeCheck(); + //m_cullMode = (CullMode)owner.EditorGUILayoutEnumPopup( CullModeStr, m_cullMode ); + m_inlineCullMode.CustomDrawer( ref owner, ( x ) => { m_cullMode = (CullMode)owner.EditorGUILayoutEnumPopup( CullModeStr, m_cullMode ); }, CullModeStr ); + if( EditorGUI.EndChangeCheck() ) + { + m_inlineCullMode.IntValue = (int)m_cullMode; + m_isDirty = true; + } + } + + public override void ReadFromString( ref uint index, ref string[] nodeParams ) + { + bool validDataOnMeta = m_validData; + if( UIUtils.CurrentShaderVersion() > TemplatesManager.MPShaderVersion ) + { + validDataOnMeta = Convert.ToBoolean( nodeParams[ index++ ] ); + } + + if( validDataOnMeta ) + { + if( UIUtils.CurrentShaderVersion() < 15304 ) + { + m_cullMode = (CullMode)Enum.Parse( typeof( CullMode ), nodeParams[ index++ ] ); + m_inlineCullMode.IntValue = (int)m_cullMode; + } + else + { + m_inlineCullMode.ReadFromString( ref index, ref nodeParams ); + m_cullMode = (CullMode)m_inlineCullMode.IntValue; + } + } + } + + public override void WriteToString( ref string nodeInfo ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_validData ); + if( m_validData ) + { + //IOUtils.AddFieldValueToString( ref nodeInfo, m_cullMode ); + m_inlineCullMode.WriteToString( ref nodeInfo ); + } + } + + public override string GenerateShaderData( bool isSubShader ) + { + //return CullModeFormatStr + m_cullMode.ToString(); + return CullModeFormatStr + m_inlineCullMode.GetValueOrProperty( m_cullMode.ToString()); + } + + public override void Destroy() + { + base.Destroy(); + m_inlineCullMode = null; + } + + public CullMode CurrentCullMode + { + get { return m_cullMode; } + set + { + m_cullMode = value; + m_inlineCullMode.IntValue = (int)value; + m_inlineCullMode.Active = false; + } + } + public InlineProperty CullInlineProperty { get { return m_inlineCullMode; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateCullModeModule.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateCullModeModule.cs.meta new file mode 100644 index 00000000..7b3fa309 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateCullModeModule.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: dcbce53ba2eeecd4a8f2c7f5f9a43b7a +timeCreated: 1511186525 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateData.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateData.cs new file mode 100644 index 00000000..f3c7b895 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateData.cs @@ -0,0 +1,1178 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +// THIS FILE IS DEPRECATED AND SHOULD NOT BE USED + +using System; +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateDataContainer + { + public int UNITY_VERSION = -1; + public TemplateData TemplateDataRef; + } + + [Serializable] + public class VertexDataContainer + { + [SerializeField] + private List<TemplateVertexData> m_vertexData; + + [SerializeField] + private string m_vertexDataId = string.Empty; + + [SerializeField] + private int m_vertexDataStartIdx = -1; + + public void Reload() + { + if( m_vertexData != null ) + { + m_vertexData.Clear(); + } + } + + public void Destroy() + { + if( m_vertexData != null ) + { + m_vertexData.Clear(); + m_vertexData = null; + } + } + + + public List<TemplateVertexData> VertexData { get { return m_vertexData; } set { m_vertexData = value; } } + public string VertexDataId { get { return m_vertexDataId; } set { m_vertexDataId = value; } } + public int VertexDataStartIdx { get { return m_vertexDataStartIdx; } set { m_vertexDataStartIdx = value; } } + } + + [Serializable] + public sealed class TemplateData : TemplateDataParent + { + [SerializeField] + private string m_templateBody = string.Empty; + + [SerializeField] + private string m_shaderNameId = string.Empty; + + [SerializeField] + private List<TemplateProperty> m_propertyList = new List<TemplateProperty>(); + private Dictionary<string, TemplateProperty> m_propertyDict = new Dictionary<string, TemplateProperty>(); + + [SerializeField] + private List<TemplateInputData> m_inputDataList = new List<TemplateInputData>(); + private Dictionary<int, TemplateInputData> m_inputDataDict = new Dictionary<int, TemplateInputData>(); + + //[SerializeField] + //private List<TemplateCodeSnippetBase> m_snippetElementsList = new List<TemplateCodeSnippetBase>(); + //private Dictionary<string, TemplateCodeSnippetBase> m_snippetElementsDict = new Dictionary<string, TemplateCodeSnippetBase>(); + + [SerializeField] + private List<TemplateLocalVarData> m_localVarsList = new List<TemplateLocalVarData>(); + + [SerializeField] + private VertexDataContainer m_vertexDataContainer = new VertexDataContainer(); + + [SerializeField] + private TemplateInterpData m_interpolatorDataContainer; + + [SerializeField] + private List<TemplateShaderPropertyData> m_availableShaderProperties = new List<TemplateShaderPropertyData>(); + + [SerializeField] + private TemplateFunctionData m_vertexFunctionData; + + [SerializeField] + private TemplateFunctionData m_fragmentFunctionData; + + [SerializeField] + private TemplateBlendData m_blendData = new TemplateBlendData(); + + [SerializeField] + private TemplateCullModeData m_cullModeData = new TemplateCullModeData(); + + [SerializeField] + private TemplateColorMaskData m_colorMaskData = new TemplateColorMaskData(); + + [SerializeField] + private TemplateStencilData m_stencilData = new TemplateStencilData(); + + [SerializeField] + private TemplateDepthData m_depthData = new TemplateDepthData(); + + [SerializeField] + private TemplateTagsModuleData m_tagData = new TemplateTagsModuleData(); + + public TemplateData() + { + m_templateType = TemplateDataType.LegacySinglePass; + } + + public TemplateData( string name ) + { + m_templateType = TemplateDataType.LegacySinglePass; + Name = name; + } + + public TemplateData( string name, string guid ) + { + m_templateType = TemplateDataType.LegacySinglePass; + m_communityTemplate = false; + if( !string.IsNullOrEmpty( guid ) ) + { + string datapath = AssetDatabase.GUIDToAssetPath( guid ); + if( string.IsNullOrEmpty( datapath ) ) + { + m_isValid = false; + return; + } + + string body = string.Empty; + try + { + body = IOUtils.LoadTextFileFromDisk( datapath ); + } + catch( Exception e ) + { + Debug.LogException( e ); + m_isValid = false; + return; + } + + if( !string.IsNullOrEmpty( body ) ) + { + LoadTemplateBody( body ); + Name = string.IsNullOrEmpty( name ) ? m_defaultShaderName : name; + m_guid = guid; + } + } + } + + public TemplateData( string name, string guid, string body ) + { + m_templateType = TemplateDataType.LegacySinglePass; + m_communityTemplate = true; + if( !string.IsNullOrEmpty( body ) ) + { + LoadTemplateBody( body ); + Name = string.IsNullOrEmpty( name ) ? m_defaultShaderName : name; + m_guid = guid; + } + } + + public override bool Reload() + { + if( m_vertexDataContainer != null ) + { + m_vertexDataContainer.Reload(); + } + + if( m_interpolatorDataContainer != null ) + { + m_interpolatorDataContainer.Destroy(); + } + + if( m_availableShaderProperties != null ) + { + m_availableShaderProperties.Clear(); + } + + if( m_propertyDict != null ) + { + m_propertyDict.Clear(); + } + + if( m_propertyList != null ) + { + m_propertyList.Clear(); + } + + if( m_inputDataDict != null ) + { + m_inputDataDict.Clear(); + } + + if( m_inputDataList != null ) + { + m_inputDataList.Clear(); + } + + if( m_localVarsList != null ) + { + m_localVarsList.Clear(); + } + + //if( m_snippetElementsDict != null ) + //{ + // m_snippetElementsDict.Clear(); + //} + + //if( m_snippetElementsList != null ) + //{ + // for( int i = 0; i < m_snippetElementsList.Count; i++ ) + // { + // GameObject.DestroyImmediate( m_snippetElementsList[ i ] ); + // m_snippetElementsList[ i ] = null; + // } + // m_snippetElementsList.Clear(); + //} + + string datapath = AssetDatabase.GUIDToAssetPath( m_guid ); + string body = string.Empty; + try + { + body = IOUtils.LoadTextFileFromDisk( datapath ); + body = body.Replace( "\r\n", "\n" ); + } + catch( Exception e ) + { + Debug.LogException( e ); + m_isValid = false; + } + LoadTemplateBody( body ); + if( m_communityTemplate ) + { + Name = m_defaultShaderName; + } + return true; + } + + void LoadTemplateBody( string body ) + { + + m_templateBody = body.Replace( "\r\n", "\n" ); ; + + if( m_templateBody.IndexOf( TemplatesManager.TemplateShaderNameBeginTag ) < 0 ) + { + m_isValid = false; + return; + } + + //Fetching common tags + FetchCommonTags(); + + //Fetch function code areas + FetchCodeAreas( TemplatesManager.TemplateVertexCodeBeginArea, MasterNodePortCategory.Vertex ); + FetchCodeAreas( TemplatesManager.TemplateFragmentCodeBeginArea, MasterNodePortCategory.Fragment ); + + //Fetching inputs + FetchInputs( MasterNodePortCategory.Fragment ); + FetchInputs( MasterNodePortCategory.Vertex ); + + + //Fetch local variables must be done after fetching code areas as it needs them to see is variable is on vertex or fragment + TemplateHelperFunctions.FetchLocalVars( m_templateBody, ref m_localVarsList, m_vertexFunctionData, m_fragmentFunctionData ); + + //Fetch snippets + } + + void FetchSubShaderProperties() + { + Match match = Regex.Match( m_templateBody, @"Pass\s*{" ); + if( match.Groups.Count == 0 ) + { + return; + } + + int beginSubShader = m_templateBody.IndexOf( "SubShader" ); + int endSubShader = match.Groups[ 0 ].Index; + if( beginSubShader > 0 && endSubShader > 0 && endSubShader > beginSubShader ) + { + // ADD A PLACE TO INSERT GRAB PASSES + int passIndex = m_templateBody.IndexOf( TemplatesManager.TemplatePassTag ); + if( passIndex < 0 ) + { + int currIdx = endSubShader - 1; + string identation = string.Empty; + for( ; currIdx > 0; currIdx-- ) + { + if( m_templateBody[ currIdx ] != '\n' ) + { + identation = m_templateBody[ currIdx ] + identation; + } + else + { + identation = m_templateBody[ currIdx ] + identation; + break; + } + } + if( currIdx > 0 ) + { + m_templateBody = m_templateBody.Insert( currIdx, identation + TemplatesManager.TemplatePassTag ); + } + } + + // GET ALL THE MODULES + string subBody = m_templateBody.Substring( beginSubShader, endSubShader - beginSubShader ); + //CULL MODE + { + int cullIdx = subBody.IndexOf( "Cull" ); + if( cullIdx > 0 ) + { + int end = subBody.IndexOf( TemplatesManager.TemplateNewLine, cullIdx ); + string cullParams = subBody.Substring( cullIdx, end - cullIdx ); + m_cullModeData.CullModeId = cullParams; + TemplateHelperFunctions.CreateCullMode( cullParams, ref m_cullModeData ); + if( m_cullModeData.DataCheck == TemplateDataCheck.Valid ) + AddId( cullParams, false, string.Empty ); + } + } + //COLOR MASK + { + int colorMaskIdx = subBody.IndexOf( "ColorMask" ); + if( colorMaskIdx > 0 ) + { + int end = subBody.IndexOf( TemplatesManager.TemplateNewLine, colorMaskIdx ); + string colorMaskParams = subBody.Substring( colorMaskIdx, end - colorMaskIdx ); + m_colorMaskData.ColorMaskId = colorMaskParams; + TemplateHelperFunctions.CreateColorMask( colorMaskParams, ref m_colorMaskData ); + if( m_colorMaskData.DataCheck == TemplateDataCheck.Valid ) + AddId( colorMaskParams, false ); + } + } + //BlEND MODE + { + int blendModeIdx = subBody.IndexOf( "Blend" ); + if( blendModeIdx > 0 ) + { + int end = subBody.IndexOf( TemplatesManager.TemplateNewLine, blendModeIdx ); + string blendParams = subBody.Substring( blendModeIdx, end - blendModeIdx ); + m_blendData.BlendModeId = blendParams; + TemplateHelperFunctions.CreateBlendMode( blendParams, ref m_blendData ); + if( m_blendData.ValidBlendMode ) + { + AddId( blendParams, false ); + } + } + } + //BLEND OP + { + int blendOpIdx = subBody.IndexOf( "BlendOp" ); + if( blendOpIdx > 0 ) + { + int end = subBody.IndexOf( TemplatesManager.TemplateNewLine, blendOpIdx ); + string blendOpParams = subBody.Substring( blendOpIdx, end - blendOpIdx ); + BlendData.BlendOpId = blendOpParams; + TemplateHelperFunctions.CreateBlendOp( blendOpParams, ref m_blendData ); + if( m_blendData.ValidBlendOp ) + { + AddId( blendOpParams, false ); + } + } + + m_blendData.DataCheck = ( m_blendData.ValidBlendMode || m_blendData.ValidBlendOp ) ? TemplateDataCheck.Valid : TemplateDataCheck.Invalid; + } + + //STENCIL + { + int stencilIdx = subBody.IndexOf( "Stencil" ); + if( stencilIdx > -1 ) + { + int stencilEndIdx = subBody.IndexOf( "}", stencilIdx ); + if( stencilEndIdx > 0 ) + { + string stencilParams = subBody.Substring( stencilIdx, stencilEndIdx + 1 - stencilIdx ); + m_stencilData.StencilBufferId = stencilParams; + TemplateHelperFunctions.CreateStencilOps( stencilParams, ref m_stencilData ); + if( m_stencilData.DataCheck == TemplateDataCheck.Valid ) + { + AddId( stencilParams, true ); + } + } + } + } + + //ZWRITE + { + int zWriteOpIdx = subBody.IndexOf( "ZWrite" ); + if( zWriteOpIdx > -1 ) + { + int zWriteEndIdx = subBody.IndexOf( TemplatesManager.TemplateNewLine, zWriteOpIdx ); + if( zWriteEndIdx > 0 ) + { + m_depthData.ZWriteModeId = subBody.Substring( zWriteOpIdx, zWriteEndIdx + 1 - zWriteOpIdx ); + TemplateHelperFunctions.CreateZWriteMode( m_depthData.ZWriteModeId, ref m_depthData ); + if( m_depthData.DataCheck == TemplateDataCheck.Valid ) + { + AddId( m_depthData.ZWriteModeId, true ); + } + } + } + } + + //ZTEST + { + int zTestOpIdx = subBody.IndexOf( "ZTest" ); + if( zTestOpIdx > -1 ) + { + int zTestEndIdx = subBody.IndexOf( TemplatesManager.TemplateNewLine, zTestOpIdx ); + if( zTestEndIdx > 0 ) + { + m_depthData.ZTestModeId = subBody.Substring( zTestOpIdx, zTestEndIdx + 1 - zTestOpIdx ); + TemplateHelperFunctions.CreateZTestMode( m_depthData.ZTestModeId, ref m_depthData ); + if( m_depthData.DataCheck == TemplateDataCheck.Valid ) + { + AddId( m_depthData.ZTestModeId, true ); + } + } + } + } + + //ZOFFSET + { + int zOffsetIdx = subBody.IndexOf( "Offset" ); + if( zOffsetIdx > -1 ) + { + int zOffsetEndIdx = subBody.IndexOf( TemplatesManager.TemplateNewLine, zOffsetIdx ); + if( zOffsetEndIdx > 0 ) + { + m_depthData.OffsetId = subBody.Substring( zOffsetIdx, zOffsetEndIdx + 1 - zOffsetIdx ); + TemplateHelperFunctions.CreateZOffsetMode( m_depthData.OffsetId, ref m_depthData ); + if( m_depthData.DataCheck == TemplateDataCheck.Valid ) + { + AddId( m_depthData.OffsetId, true ); + } + } + } + + m_depthData.SetDataCheck(); + } + + //TAGS + { + int tagsIdx = subBody.IndexOf( "Tags" ); + if( tagsIdx > -1 ) + { + int tagsEndIdx = subBody.IndexOf( "}", tagsIdx ); + if( tagsEndIdx > -1 ) + { + m_tagData.Reset(); + m_tagData.TagsId = subBody.Substring( tagsIdx, tagsEndIdx + 1 - tagsIdx ); + TemplateHelperFunctions.CreateTags( ref m_tagData, true ); + m_tagData.DataCheck = TemplateDataCheck.Valid; + AddId( m_tagData.TagsId, false ); + } + else + { + m_tagData.DataCheck = TemplateDataCheck.Invalid; + } + } + else + { + m_tagData.DataCheck = TemplateDataCheck.Invalid; + } + } + } + } + + void FetchCommonTags() + { + // Name + try + { + int nameBegin = m_templateBody.IndexOf( TemplatesManager.TemplateShaderNameBeginTag ); + if( nameBegin < 0 ) + { + // Not a template + return; + } + + int nameEnd = m_templateBody.IndexOf( TemplatesManager.TemplateFullEndTag, nameBegin ); + int defaultBegin = nameBegin + TemplatesManager.TemplateShaderNameBeginTag.Length; + int defaultLength = nameEnd - defaultBegin; + m_defaultShaderName = m_templateBody.Substring( defaultBegin, defaultLength ); + int[] nameIdx = m_defaultShaderName.AllIndexesOf( "\"" ); + nameIdx[ 0 ] += 1; // Ignore the " character from the string + m_defaultShaderName = m_defaultShaderName.Substring( nameIdx[ 0 ], nameIdx[ 1 ] - nameIdx[ 0 ] ); + m_shaderNameId = m_templateBody.Substring( nameBegin, nameEnd + TemplatesManager.TemplateFullEndTag.Length - nameBegin ); + AddId( m_shaderNameId, false ); + + } + catch( Exception e ) + { + Debug.LogException( e ); + m_isValid = false; + } + + FetchSubShaderProperties(); + // Vertex Data + { + int vertexDataTagBegin = m_templateBody.IndexOf( TemplatesManager.TemplateVertexDataTag ); + if( vertexDataTagBegin > -1 ) + { + m_vertexDataContainer.VertexDataStartIdx = vertexDataTagBegin; + int vertexDataTagEnd = m_templateBody.IndexOf( TemplatesManager.TemplateEndOfLine, vertexDataTagBegin ); + m_vertexDataContainer.VertexDataId = m_templateBody.Substring( vertexDataTagBegin, vertexDataTagEnd + TemplatesManager.TemplateEndOfLine.Length - vertexDataTagBegin ); + int dataBeginIdx = m_templateBody.LastIndexOf( '{', vertexDataTagBegin, vertexDataTagBegin ); + string vertexData = m_templateBody.Substring( dataBeginIdx + 1, vertexDataTagBegin - dataBeginIdx ); + + int parametersBegin = vertexDataTagBegin + TemplatesManager.TemplateVertexDataTag.Length; + string parameters = m_templateBody.Substring( parametersBegin, vertexDataTagEnd - parametersBegin ); + m_vertexDataContainer.VertexData = TemplateHelperFunctions.CreateVertexDataList( vertexData, parameters ); + AddId( m_vertexDataContainer.VertexDataId ); + } + } + + // Available interpolators + try + { + int interpDataBegin = m_templateBody.IndexOf( TemplatesManager.TemplateInterpolatorBeginTag ); + if( interpDataBegin > -1 ) + { + int interpDataEnd = m_templateBody.IndexOf( TemplatesManager.TemplateEndOfLine, interpDataBegin ); + string interpDataId = m_templateBody.Substring( interpDataBegin, interpDataEnd + TemplatesManager.TemplateEndOfLine.Length - interpDataBegin ); + + int dataBeginIdx = m_templateBody.LastIndexOf( '{', interpDataBegin, interpDataBegin ); + string interpData = m_templateBody.Substring( dataBeginIdx + 1, interpDataBegin - dataBeginIdx ); + + m_interpolatorDataContainer = TemplateHelperFunctions.CreateInterpDataList( interpData, interpDataId, 8 ); + m_interpolatorDataContainer.InterpDataId = interpDataId; + m_interpolatorDataContainer.InterpDataStartIdx = interpDataBegin; + AddId( interpDataId ); + } + } + catch( Exception e ) + { + Debug.LogException( e ); + m_isValid = false; + } + + + try + { + Dictionary<string, TemplateShaderPropertyData> duplicatesHelper = new Dictionary<string, TemplateShaderPropertyData>(); + m_availableShaderProperties = new List<TemplateShaderPropertyData>(); + + // Common Tags + for( int i = 0; i < TemplatesManager.CommonTags.Length; i++ ) + { + int idx = m_templateBody.IndexOf( TemplatesManager.CommonTags[ i ].Id ); + if( idx > -1 ) + { + string currentId = TemplatesManager.CommonTags[ i ].Id; + + TemplateCommonTagId commonTagId = (TemplateCommonTagId)i; + switch( commonTagId ) + { + // Properties + case TemplateCommonTagId.Property: + { + TemplateHelperFunctions.CreateShaderPropertiesList( m_templateBody.Substring( 0, idx + TemplatesManager.CommonTags[ i ].Id.Length ), ref m_availableShaderProperties, ref duplicatesHelper ); + } + break; + // Globals + case TemplateCommonTagId.Global: + { + TemplateHelperFunctions.CreateShaderGlobalsList( m_templateBody.Substring( 0, idx + TemplatesManager.CommonTags[ i ].Id.Length ), ref m_availableShaderProperties, ref duplicatesHelper ); + } + break; + + //Tags + //case TemplateCommonTagId.Tag: + //{ + // m_propertyList[ m_propertyList.Count - 1 ].Indentation = " "; + //} + //break; + //case TemplateCommonTagId.CullMode: + //{ + // int newId = idx + TemplatesManager.CommonTags[ i ].Id.Length; + // int end = m_templateBody.IndexOf( TemplatesManager.TemplateNewLine, newId ); + // string cullParams = m_templateBody.Substring( newId, end - newId ); + // currentId = m_templateBody.Substring( idx, end - idx ); + // m_cullModeData.CullModeId = currentId; + // TemplateHelperFunctions.CreateCullMode( cullParams, ref m_cullModeData ); + //} + //break; + //Blend Mode + //case TemplateCommonTagId.BlendMode: + //{ + // int newId = idx + TemplatesManager.CommonTags[ i ].Id.Length; + // int end = m_templateBody.IndexOf( TemplatesManager.TemplateNewLine, newId ); + // string blendParams = m_templateBody.Substring( newId, end - newId ); + // currentId = m_templateBody.Substring( idx, end - idx ); + // m_blendData.BlendModeId = currentId; + // TemplateHelperFunctions.CreateBlendMode( blendParams, ref m_blendData ); + //}break; + //case TemplateCommonTagId.BlendOp: + //{ + // int newId = idx + TemplatesManager.CommonTags[ i ].Id.Length; + // int end = m_templateBody.IndexOf( TemplatesManager.TemplateNewLine, newId ); + // currentId = m_templateBody.Substring( idx, end - idx ); + // BlendData.BlendOpId = currentId; + // TemplateHelperFunctions.CreateBlendOp( m_templateBody.Substring( newId, end - newId ), ref m_blendData ); + //}break; + //case TemplateCommonTagId.ColorMask: + //{ + // int newId = idx + TemplatesManager.CommonTags[ i ].Id.Length; + // int end = m_templateBody.IndexOf( TemplatesManager.TemplateNewLine, newId ); + // string colorMaskParams = m_templateBody.Substring( newId, end - newId ); + // currentId = m_templateBody.Substring( idx, end - idx ); + // m_colorMaskData.ColorMaskId = currentId; + // TemplateHelperFunctions.CreateColorMask( colorMaskParams, ref m_colorMaskData ); + //} + //break; + //case TemplateCommonTagId.StencilOp: + //{ + // int id = m_templateBody.LastIndexOf( "Stencil" ); + // if( id > -1 ) + // { + // string stencilParams = m_templateBody.Substring( id, idx - id ); + // currentId = stencilParams + TemplatesManager.TemplateStencilOpTag; + // m_stencilData.StencilBufferId = currentId; + // TemplateHelperFunctions.CreateStencilOps( stencilParams, ref m_stencilData ); + // } + + //} + //break; + default: + break; + } + + //AddId( TemplatesManager.CommonTags[ i ] ); + AddId( currentId, TemplatesManager.CommonTags[ i ].SearchIndentation, TemplatesManager.CommonTags[ i ].CustomIndentation ); + } + } + + duplicatesHelper.Clear(); + duplicatesHelper = null; + } + catch( Exception e ) + { + Debug.LogException( e ); + m_isValid = false; + } + } + + void FetchCodeAreas( string begin, MasterNodePortCategory category ) + { + int areaBeginIndexes = m_templateBody.IndexOf( begin ); + + if( areaBeginIndexes > -1 ) + { + int beginIdx = areaBeginIndexes + begin.Length; + int endIdx = m_templateBody.IndexOf( TemplatesManager.TemplateEndOfLine, beginIdx ); + int length = endIdx - beginIdx; + + string parameters = m_templateBody.Substring( beginIdx, length ); + + string[] parametersArr = parameters.Split( IOUtils.FIELD_SEPARATOR ); + + string id = m_templateBody.Substring( areaBeginIndexes, endIdx + TemplatesManager.TemplateEndOfLine.Length - areaBeginIndexes ); + string inParameters = parametersArr[ 0 ]; + string outParameters = ( parametersArr.Length > 1 ) ? parametersArr[ 1 ] : string.Empty; + if( category == MasterNodePortCategory.Fragment ) + { + m_fragmentFunctionData = new TemplateFunctionData(-1, string.Empty, id, areaBeginIndexes, inParameters, outParameters, category ); + } + else + { + m_vertexFunctionData = new TemplateFunctionData( -1, string.Empty,id, areaBeginIndexes, inParameters, outParameters, category ); + } + AddId( id, true ); + } + } + + void FetchInputs( MasterNodePortCategory portCategory ) + { + string beginTag = ( portCategory == MasterNodePortCategory.Fragment ) ? TemplatesManager.TemplateInputsFragBeginTag : TemplatesManager.TemplateInputsVertBeginTag; + int[] inputBeginIndexes = m_templateBody.AllIndexesOf( beginTag ); + if( inputBeginIndexes != null && inputBeginIndexes.Length > 0 ) + { + for( int i = 0; i < inputBeginIndexes.Length; i++ ) + { + int inputEndIdx = m_templateBody.IndexOf( TemplatesManager.TemplateEndSectionTag, inputBeginIndexes[ i ] ); + int defaultValueBeginIdx = inputEndIdx + TemplatesManager.TemplateEndSectionTag.Length; + int endLineIdx = m_templateBody.IndexOf( TemplatesManager.TemplateFullEndTag, defaultValueBeginIdx ); + + string defaultValue = m_templateBody.Substring( defaultValueBeginIdx, endLineIdx - defaultValueBeginIdx ); + string tagId = m_templateBody.Substring( inputBeginIndexes[ i ], endLineIdx + TemplatesManager.TemplateFullEndTag.Length - inputBeginIndexes[ i ] ); + + int beginIndex = inputBeginIndexes[ i ] + beginTag.Length; + int length = inputEndIdx - beginIndex; + string inputData = m_templateBody.Substring( beginIndex, length ); + string[] inputDataArray = inputData.Split( IOUtils.FIELD_SEPARATOR ); + if( inputDataArray != null && inputDataArray.Length > 0 ) + { + try + { + string portName = inputDataArray[ (int)TemplatePortIds.Name ]; + WirePortDataType dataType = (WirePortDataType)Enum.Parse( typeof( WirePortDataType ), inputDataArray[ (int)TemplatePortIds.DataType ].ToUpper() ); + + int portUniqueIDArrIdx = (int)TemplatePortIds.UniqueId; + int portUniqueId = ( portUniqueIDArrIdx < inputDataArray.Length ) ? Convert.ToInt32( inputDataArray[ portUniqueIDArrIdx ] ) : -1; + if( portUniqueId < 0 ) + portUniqueId = m_inputDataList.Count; + + int portOrderArrayIdx = (int)TemplatePortIds.OrderId; + int portOrderId = ( portOrderArrayIdx < inputDataArray.Length ) ? Convert.ToInt32( inputDataArray[ portOrderArrayIdx ] ) : -1; + if( portOrderId < 0 ) + portOrderId = m_inputDataList.Count; + + AddInput( inputBeginIndexes[ i ], tagId, portName, defaultValue, dataType, portCategory, portUniqueId, portOrderId ); + } + catch( Exception e ) + { + Debug.LogException( e ); + } + } + } + } + } + + //void FetchSnippets() + //{ + // int[] codeSnippetAttribBeginIndexes = m_templateBody.AllIndexesOf( TemplatesManager.TemplateCodeSnippetAttribBegin ); + // int[] codeSnippetAttribEndIndexes = m_templateBody.AllIndexesOf( TemplatesManager.TemplateCodeSnippetAttribEnd ); + // int[] codeSnippetEndIndexes = m_templateBody.AllIndexesOf( TemplatesManager.TemplateCodeSnippetEnd ); + + // if( codeSnippetAttribBeginIndexes != null && codeSnippetAttribBeginIndexes.Length > 0 && + // codeSnippetAttribEndIndexes != null && codeSnippetAttribEndIndexes.Length > 0 && + // codeSnippetEndIndexes != null && codeSnippetEndIndexes.Length > 0 && + // codeSnippetEndIndexes.Length == codeSnippetAttribBeginIndexes.Length && + // codeSnippetAttribBeginIndexes.Length == codeSnippetAttribEndIndexes.Length ) + // { + // for( int i = 0; i < codeSnippetAttribBeginIndexes.Length; i++ ) + // { + // // get attributes + // int startAttribIndex = codeSnippetAttribBeginIndexes[ i ] + TemplatesManager.TemplateCodeSnippetAttribBegin.Length; + // int lengthAttrib = codeSnippetAttribEndIndexes[ i ] - startAttribIndex; + // string snippetAttribs = m_templateBody.Substring( startAttribIndex, lengthAttrib ); + // string[] snippetAttribsArr = snippetAttribs.Split( IOUtils.FIELD_SEPARATOR ); + // if( snippetAttribsArr != null && snippetAttribsArr.Length > 0 ) + // { + // string attribName = snippetAttribsArr[ (int)TemplateCodeSnippetInfoIdx.Name ]; + // TemplateCodeSnippetType attribType = (TemplateCodeSnippetType)Enum.Parse( typeof( TemplateCodeSnippetType ), snippetAttribsArr[ (int)TemplateCodeSnippetInfoIdx.Type ] ); + // if( m_snippetElementsDict.ContainsKey( attribName ) ) + // { + // if( m_snippetElementsDict[ attribName ].Type != attribType ) + // { + // if( DebugConsoleWindow.DeveloperMode ) + // Debug.LogWarning( "Found incompatible types for snippet " + attribName ); + // } + // } + // else + // { + // switch( attribType ) + // { + // case TemplateCodeSnippetType.Toggle: + // { + // //Register must be done by first instantiang the correct type and register it on both containers + // //Overrides don't work if we use the container reference into the other + // TemplateCodeSnippetToggle newSnippet = ScriptableObject.CreateInstance<TemplateCodeSnippetToggle>(); + // newSnippet.Init( attribName, attribType ); + // m_snippetElementsDict.Add( attribName, newSnippet ); + // m_snippetElementsList.Add( newSnippet ); + // } + // break; + // } + + // } + // // Add initial tag indentation + // int indentationIndex = codeSnippetAttribBeginIndexes[ i ]; + // int lengthAdjust = 0; + // for( ; indentationIndex > 0; indentationIndex--, lengthAdjust++ ) + // { + // if( m_templateBody[ indentationIndex ] == TemplatesManager.TemplateNewLine ) + // { + // indentationIndex += 1; + // lengthAdjust -= 1; + // break; + // } + // } + + // if( indentationIndex > 0 ) + // { + // string snippetId = m_templateBody.Substring( indentationIndex, + // codeSnippetEndIndexes[ i ] + TemplatesManager.TemplateCodeSnippetEnd.Length - codeSnippetAttribBeginIndexes[ i ] + lengthAdjust ); + + // int snippetCodeStart = codeSnippetAttribEndIndexes[ i ] + TemplatesManager.TemplateCodeSnippetAttribEnd.Length; + // int snippetCodeLength = codeSnippetEndIndexes[ i ] - snippetCodeStart; + // //Remove possible identation characters present between tag and last instruction + // if( m_templateBody[ snippetCodeStart + snippetCodeLength - 1 ] != TemplatesManager.TemplateNewLine ) + // { + // for( ; snippetCodeLength > 0; snippetCodeLength-- ) + // { + // if( m_templateBody[ snippetCodeStart + snippetCodeLength - 1 ] == TemplatesManager.TemplateNewLine ) + // break; + // } + // } + + // if( snippetCodeLength > 0 ) + // { + // string snippetCode = m_templateBody.Substring( snippetCodeStart, snippetCodeLength ); + // TemplateCodeSnippetElement element = new TemplateCodeSnippetElement( snippetId, snippetCode ); + // m_snippetElementsDict[ attribName ].AddSnippet( element ); + // } + // } + // } + // } + // } + //} + + //void RefreshSnippetInfo() + //{ + // if( m_snippetElementsDict == null ) + // { + // m_snippetElementsDict = new Dictionary<string, TemplateCodeSnippetBase>(); + // } + + // if( m_snippetElementsDict.Count != m_snippetElementsList.Count ) + // { + // m_snippetElementsDict.Clear(); + // for( int i = 0; i < m_snippetElementsList.Count; i++ ) + // { + // m_snippetElementsDict.Add( m_snippetElementsList[ i ].NameId, m_snippetElementsList[ i ] ); + // } + // } + //} + + //public void DrawSnippetProperties( ParentNode owner ) + //{ + // for( int i = 0; i < m_snippetElementsList.Count; i++ ) + // { + // m_snippetElementsList[ i ].DrawProperties( owner ); + // } + //} + + //public void InsertSnippets( ref string shaderBody ) + //{ + // for( int i = 0; i < m_snippetElementsList.Count; i++ ) + // { + // m_snippetElementsList[ i ].InsertSnippet( ref shaderBody ); + // } + //} + + public void AddId( string ID, bool searchIndentation = true ) + { + AddId( ID, searchIndentation, string.Empty ); + } + + public void AddId( string ID, bool searchIndentation, string customIndentation ) + { + int propertyIndex = m_templateBody.IndexOf( ID ); + if( propertyIndex > -1 ) + { + if( searchIndentation ) + { + int indentationIndex = -1; + for( int i = propertyIndex; i > 0; i-- ) + { + if( m_templateBody[ i ] == TemplatesManager.TemplateNewLine ) + { + indentationIndex = i + 1; + break; + } + } + if( indentationIndex > -1 ) + { + int length = propertyIndex - indentationIndex; + string indentation = ( length > 0 ) ? m_templateBody.Substring( indentationIndex, length ) : string.Empty; + m_propertyList.Add( new TemplateProperty( ID, indentation, false ) ); + } + } + else + { + m_propertyList.Add( new TemplateProperty( ID, customIndentation, true ) ); + } + } + } + + void BuildInfo() + { + if( m_propertyDict == null ) + { + m_propertyDict = new Dictionary<string, TemplateProperty>(); + } + + if( m_propertyList.Count != m_propertyDict.Count ) + { + m_propertyDict.Clear(); + for( int i = 0; i < m_propertyList.Count; i++ ) + { + m_propertyDict.Add( m_propertyList[ i ].Id, m_propertyList[ i ] ); + } + } + } + + public void ResetTemplateUsageData() + { + BuildInfo(); + for( int i = 0; i < m_propertyList.Count; i++ ) + { + m_propertyList[ i ].Used = false; + } + } + + public void AddInput( int tagStartIdx, string tagId, string portName, string defaultValue, WirePortDataType dataType, MasterNodePortCategory portCategory, int portUniqueId, int portOrderId ) + { + TemplateInputData inputData = new TemplateInputData( tagStartIdx, tagStartIdx, tagId, portName, defaultValue, dataType, portCategory, portUniqueId, portOrderId, string.Empty ); + m_inputDataList.Add( inputData ); + m_inputDataDict.Add( inputData.PortUniqueId, inputData ); + AddId( tagId, false ); + } + + public override void Destroy() + { + if( m_vertexDataContainer != null ) + { + m_vertexDataContainer.Destroy(); + m_vertexDataContainer = null; + } + + if( m_interpolatorDataContainer != null ) + { + m_interpolatorDataContainer.Destroy(); + m_interpolatorDataContainer = null; + } + + if( m_availableShaderProperties != null ) + { + m_availableShaderProperties.Clear(); + m_availableShaderProperties = null; + } + + if( m_propertyDict != null ) + { + m_propertyDict.Clear(); + m_propertyDict = null; + } + + if( m_propertyList != null ) + { + m_propertyList.Clear(); + m_propertyList = null; + } + + if( m_inputDataDict != null ) + { + m_inputDataDict.Clear(); + m_inputDataDict = null; + } + + if( m_inputDataList != null ) + { + m_inputDataList.Clear(); + m_inputDataList = null; + } + + if( m_localVarsList != null ) + { + m_localVarsList.Clear(); + m_localVarsList = null; + } + //if( m_snippetElementsDict != null ) + //{ + // m_snippetElementsDict.Clear(); + // m_snippetElementsDict = null; + //} + + //if( m_snippetElementsList != null ) + //{ + // for( int i = 0; i < m_snippetElementsList.Count; i++ ) + // { + // GameObject.DestroyImmediate( m_snippetElementsList[ i ] ); + // m_snippetElementsList[ i ] = null; + // } + // m_snippetElementsList.Clear(); + // m_snippetElementsList = null; + //} + + m_cullModeData = null; + m_blendData = null; + m_colorMaskData = null; + m_stencilData = null; + if( m_tagData != null ) + { + m_tagData.Destroy(); + m_tagData = null; + } + } + + public void FillEmptyTags( ref string body ) + { + body = body.Replace( TemplatesManager.TemplateLocalVarTag, string.Empty ); + for( int i = 0; i < m_propertyList.Count; i++ ) + { + if( !m_propertyList[ i ].Used ) + { + if( m_propertyList[ i ].UseCustomIndentation ) + { + body = body.Replace( m_propertyList[ i ].Id, string.Empty ); + } + else + { + body = body.Replace( m_propertyList[ i ].Indentation + m_propertyList[ i ].Id, string.Empty ); + } + } + } + } + + public bool FillVertexInstructions( ref string body, params string[] values ) + { + if( m_vertexFunctionData != null && !string.IsNullOrEmpty( m_vertexFunctionData.Id ) ) + { + return FillTemplateBody( m_vertexFunctionData.Id, ref body, values ); + } + + if( values.Length > 0 ) + { + UIUtils.ShowMessage( "Attemping to add vertex instructions on a template with no assigned vertex code area", MessageSeverity.Error ); + return false; + } + return true; + } + + public bool FillFragmentInstructions( ref string body, params string[] values ) + { + if( m_fragmentFunctionData != null && !string.IsNullOrEmpty( m_fragmentFunctionData.Id ) ) + { + return FillTemplateBody( m_fragmentFunctionData.Id, ref body, values ); + } + + if( values.Length > 0 ) + { + UIUtils.ShowMessage( "Attemping to add fragment instructions on a template with no assigned vertex code area", MessageSeverity.Error ); + return false; + } + return true; + } + + // values must be unindented an without line feed + public bool FillTemplateBody( string id, ref string body, params string[] values ) + { + if( values.Length == 0 ) + { + return true; + } + + BuildInfo(); + + if( m_propertyDict.ContainsKey( id ) ) + { + string finalValue = string.Empty; + for( int i = 0; i < values.Length; i++ ) + { + + if( m_propertyDict[ id ].AutoLineFeed ) + { + string[] valuesArr = values[ i ].Split( '\n' ); + for( int j = 0; j < valuesArr.Length; j++ ) + { + //first value will be automatically indented by the string replace + finalValue += ( ( i == 0 && j == 0 ) ? string.Empty : m_propertyDict[ id ].Indentation ) + valuesArr[ j ]; + finalValue += TemplatesManager.TemplateNewLine; + } + + } + else + { + //first value will be automatically indented by the string replace + finalValue += ( i == 0 ? string.Empty : m_propertyDict[ id ].Indentation ) + values[ i ]; + } + } + + body = body.Replace( id, finalValue ); + m_propertyDict[ id ].Used = true; + return true; + } + + if( values.Length > 1 || !string.IsNullOrEmpty( values[ 0 ] ) ) + { + UIUtils.ShowMessage( string.Format( "Attempting to write data into inexistant tag {0}. Please review the template {1} body and consider adding the missing tag.", id, m_name ), MessageSeverity.Error ); + return false; + } + + return true; + + } + + public bool FillTemplateBody( string id, ref string body, List<PropertyDataCollector> values ) + { + if( values.Count == 0 ) + { + return true; + } + + string[] array = new string[ values.Count ]; + for( int i = 0; i < values.Count; i++ ) + { + array[ i ] = values[ i ].PropertyName; + } + return FillTemplateBody( id, ref body, array ); + } + + public TemplateInputData InputDataFromId( int id ) + { + if( m_inputDataDict == null ) + m_inputDataDict = new Dictionary<int, TemplateInputData>(); + + if( m_inputDataDict.Count != m_inputDataList.Count ) + { + m_inputDataDict.Clear(); + for( int i = 0; i < m_inputDataList.Count; i++ ) + { + m_inputDataDict.Add( m_inputDataList[ i ].PortUniqueId, m_inputDataList[ i ] ); + } + } + + if( m_inputDataDict.ContainsKey( id ) ) + return m_inputDataDict[ id ]; + + return null; + } + + public string GetVertexData( TemplateInfoOnSematics info ) + { + int count = m_vertexDataContainer.VertexData.Count; + for( int i = 0; i < count; i++ ) + { + if( m_vertexDataContainer.VertexData[ i ].DataInfo == info ) + { + return string.Format( TemplateHelperFunctions.TemplateVarFormat, m_vertexFunctionData.InVarName, m_vertexDataContainer.VertexData[ i ].VarName ); + } + } + return string.Empty; + } + + public string GetInterpolatedData( TemplateInfoOnSematics info ) + { + int count = m_interpolatorDataContainer.Interpolators.Count; + for( int i = 0; i < count; i++ ) + { + if( m_interpolatorDataContainer.Interpolators[ i ].DataInfo == info ) + { + return string.Format( TemplateHelperFunctions.TemplateVarFormat, m_fragmentFunctionData.InVarName, m_interpolatorDataContainer.Interpolators[ i ].VarName ); + } + } + return string.Empty; + } + + public string InterpDataId { get { return m_interpolatorDataContainer.InterpDataId; } } + public string VertexDataId { get { return m_vertexDataContainer.VertexDataId; } } + public string ShaderNameId { get { return m_shaderNameId; } set { m_shaderNameId = value; } } + public string TemplateBody { get { return m_templateBody; } set { m_templateBody = value; } } + public List<TemplateInputData> InputDataList { get { return m_inputDataList; } set { m_inputDataList = value; } } + public List<TemplateLocalVarData> LocalVarsList { get { return m_localVarsList; } } + public List<TemplateVertexData> VertexDataList { get { return m_vertexDataContainer.VertexData; } } + public TemplateInterpData InterpolatorData { get { return m_interpolatorDataContainer; } } + public TemplateFunctionData VertexFunctionData { get { return m_vertexFunctionData; } set { m_vertexFunctionData = value; } } + public TemplateFunctionData FragmentFunctionData { get { return m_fragmentFunctionData; } set { m_fragmentFunctionData = value; } } + public List<TemplateShaderPropertyData> AvailableShaderProperties { get { return m_availableShaderProperties; } set { m_availableShaderProperties = value; } } + public TemplateBlendData BlendData { get { return m_blendData; } set { m_blendData = value; } } + public TemplateCullModeData CullModeData { get { return m_cullModeData; } set { m_cullModeData = value; } } + public TemplateColorMaskData ColorMaskData { get { return m_colorMaskData; } set { m_colorMaskData = value; } } + public TemplateStencilData StencilData { get { return m_stencilData; } set { m_stencilData = value; } } + public TemplateDepthData DepthData { get { return m_depthData; } set { m_depthData = value; } } + public TemplateTagsModuleData TagData { get { return m_tagData; } set { m_tagData = value; } } + private List<TemplateProperty> PropertyList { get { return m_propertyList; } set { m_propertyList = value; } } + public VertexDataContainer VertexDataContainer { get { return m_vertexDataContainer; } set { m_vertexDataContainer = value; } } + public TemplateInterpData InterpolatorDataContainer { get { return m_interpolatorDataContainer; } set { m_interpolatorDataContainer = value; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateData.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateData.cs.meta new file mode 100644 index 00000000..2002009f --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateData.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b03340e569366ae4dbd502e14c62e225 +timeCreated: 1493904667 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDataCollector.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDataCollector.cs new file mode 100644 index 00000000..bc772311 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDataCollector.cs @@ -0,0 +1,2056 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using UnityEngine; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System; + +namespace AmplifyShaderEditor +{ + public enum NormalizeType + { + Off, + Regular, + Safe + } + + public class InterpDataHelper + { + public string VarName; + public WirePortDataType VarType; + public bool IsSingleComponent; + public bool SetAtCompileTime; + public InterpDataHelper( WirePortDataType varType, string varName, bool isSingleComponent = true , bool setAtCompileTime = false ) + { + VarName = varName; + VarType = varType; + IsSingleComponent = isSingleComponent; + SetAtCompileTime = setAtCompileTime; + } + } + + public class TemplateCustomData + { + public WirePortDataType DataType; + public string Name; + public bool IsVertex; + public bool IsFragment; + public TemplateCustomData( string name, WirePortDataType dataType ) + { + name = Name; + DataType = dataType; + IsVertex = false; + IsFragment = false; + } + } + + public class TemplateInputParameters + { + public WirePortDataType Type; + public string Name; + public string Declaration; + public TemplateSemantics Semantic; + public TemplateInputParameters( WirePortDataType type, PrecisionType precision, string name, TemplateSemantics semantic, string custom = null ) + { + Type = type; + Name = name; + Semantic = semantic; + Declaration = string.Format( "{0} {1} : {2}", UIUtils.PrecisionWirePortToCgType( precision, type ), Name, Semantic ); + if( !string.IsNullOrEmpty( custom ) ) + Declaration = custom; + } + } + + public class TemplateDataCollector + { +#if UNITY_2018_2_OR_NEWER + private const int MaxUV = 8; + private int[] m_UVUsage = { 0, 0, 0, 0, 0, 0, 0, 0 }; +#else + private const int MaxUV = 4; + private int[] m_UVUsage = { 0, 0, 0, 0 }; +#endif + private int m_multipassSubshaderIdx = 0; + private int m_multipassPassIdx = 0; + private TemplateMultiPass m_currentTemplate; + private TemplateSRPType m_currentSRPType = TemplateSRPType.BuiltIn; + + private Dictionary<string, TemplateCustomData> m_customInterpolatedData; + private Dictionary<string, TemplateVertexData> m_registeredVertexData; + + private Dictionary<TemplateInfoOnSematics, InterpDataHelper> m_availableFragData; + private Dictionary<TemplateInfoOnSematics, InterpDataHelper> m_availableVertData; + private TemplateInterpData m_interpolatorData; + private Dictionary<TemplateSemantics, TemplateVertexData> m_vertexDataDict; + private TemplateData m_currentTemplateData; + private MasterNodeDataCollector m_currentDataCollector; + public Dictionary<TemplateSemantics, TemplateInputParameters> m_vertexInputParams; + public Dictionary<TemplateSemantics, TemplateInputParameters> m_fragmentInputParams; + + private Dictionary<TemplateInfoOnSematics, TemplateLocalVarData> m_specialVertexLocalVars; + private Dictionary<TemplateInfoOnSematics, TemplateLocalVarData> m_specialFragmentLocalVars; + + private List<PropertyDataCollector> m_lateDirectivesList = new List<PropertyDataCollector>(); + private Dictionary<string, PropertyDataCollector> m_lateDirectivesDict = new Dictionary<string, PropertyDataCollector>(); + + private List<PropertyDataCollector> m_srpBatcherPropertiesList = new List<PropertyDataCollector>(); + private List<PropertyDataCollector> m_fullSrpBatcherPropertiesList = new List<PropertyDataCollector>(); + private Dictionary<string, PropertyDataCollector> m_srpBatcherPropertiesDict = new Dictionary<string, PropertyDataCollector>(); + + public void CopySRPPropertiesFromDataCollector( int nodeId, TemplateDataCollector dataCollector ) + { + for( int i = 0; i < dataCollector.SrpBatcherPropertiesList.Count; i++ ) + { + AddSRPBatcherProperty( nodeId, dataCollector.SrpBatcherPropertiesList[ i ].PropertyName ); + } + } + + public void AddSRPBatcherProperty( int nodeID, string property ) + { + if( !m_srpBatcherPropertiesDict.ContainsKey( property ) ) + { + PropertyDataCollector newValue = new PropertyDataCollector( nodeID, property ); + m_srpBatcherPropertiesDict.Add( property, newValue ); + m_srpBatcherPropertiesList.Add( newValue ); + } + } + + public void SetUVUsage( int uv, WirePortDataType type ) + { + if( uv >= 0 && uv < MaxUV ) + { + m_UVUsage[ uv ] = Mathf.Max( m_UVUsage[ uv ], TemplateHelperFunctions.DataTypeChannelUsage[ type ] ); + } + } + + public void SetUVUsage( int uv, int size ) + { + if( uv >= 0 && uv < MaxUV ) + { + m_UVUsage[ uv ] = Mathf.Max( m_UVUsage[ uv ], size ); + } + } + + public void CloseLateDirectives() + { + if( m_lateDirectivesList.Count > 0 ) + { + m_lateDirectivesList.Add( new PropertyDataCollector( -1, string.Empty ) ); + } + } + + public void AddHDLightInfo() + { +#if !UNITY_2018_3_OR_NEWER + AddLateDirective( AdditionalLineType.Custom, "#if (SHADERPASS != SHADERPASS_FORWARD) //On forward this info is already included" ); + AddLateDirective( AdditionalLineType.Include, "HDRP/Lighting/LightDefinition.cs.hlsl" ); + AddLateDirective( AdditionalLineType.Include, "HDRP/Lighting/LightLoop/Shadow.hlsl" ); + AddLateDirective( AdditionalLineType.Include, "HDRP/Lighting/LightLoop/LightLoopDef.hlsl" ); + AddLateDirective( AdditionalLineType.Custom, "#endif // End of light info includes" ); +#endif + } + + public void AddLateDirective( AdditionalLineType type, string value ) + { + + if( !m_lateDirectivesDict.ContainsKey( value ) ) + { + string formattedValue = string.Empty; + switch( type ) + { + case AdditionalLineType.Include: formattedValue = string.Format( Constants.IncludeFormat, value ); break; + case AdditionalLineType.Define: formattedValue = string.Format( Constants.DefineFormat, value ); break; + case AdditionalLineType.Pragma: formattedValue = string.Format( Constants.PragmaFormat, value ); break; + case AdditionalLineType.Custom: formattedValue = value; break; + } + PropertyDataCollector property = new PropertyDataCollector( -1, formattedValue ); + m_lateDirectivesDict.Add( value, property ); + m_lateDirectivesList.Add( property ); + } + } + + public void SetMultipassInfo( TemplateMultiPass currentTemplate, int subShaderIdx, int passIdx, TemplateSRPType currentSRPType ) + { + m_currentTemplate = currentTemplate; + m_multipassSubshaderIdx = subShaderIdx; + m_multipassPassIdx = passIdx; + m_currentSRPType = currentSRPType; + } + + public bool HasDirective( AdditionalLineType type, string value ) + { + switch( type ) + { + case AdditionalLineType.Include: + { + return m_currentTemplate.SubShaders[ m_multipassSubshaderIdx ].Modules.IncludePragmaContainer.HasInclude( value ) || + m_currentTemplate.SubShaders[ m_multipassSubshaderIdx ].Passes[ m_multipassPassIdx ].Modules.IncludePragmaContainer.HasInclude( value ); + } + case AdditionalLineType.Define: + { + return m_currentTemplate.SubShaders[ m_multipassSubshaderIdx ].Modules.IncludePragmaContainer.HasDefine( value ) || + m_currentTemplate.SubShaders[ m_multipassSubshaderIdx ].Passes[ m_multipassPassIdx ].Modules.IncludePragmaContainer.HasDefine( value ); + } + case AdditionalLineType.Pragma: + { + return m_currentTemplate.SubShaders[ m_multipassSubshaderIdx ].Modules.IncludePragmaContainer.HasPragma( value ) || + m_currentTemplate.SubShaders[ m_multipassSubshaderIdx ].Passes[ m_multipassPassIdx ].Modules.IncludePragmaContainer.HasPragma( value ); + } + } + + return false; + } + + public void FillSpecialVariables( TemplatePass currentPass ) + { + m_specialVertexLocalVars = new Dictionary<TemplateInfoOnSematics, TemplateLocalVarData>(); + m_specialFragmentLocalVars = new Dictionary<TemplateInfoOnSematics, TemplateLocalVarData>(); + int localVarAmount = currentPass.LocalVarsList.Count; + for( int i = 0; i < localVarAmount; i++ ) + { + if( currentPass.LocalVarsList[ i ].IsSpecialVar ) + { + if( currentPass.LocalVarsList[ i ].Category == MasterNodePortCategory.Vertex ) + { + m_specialVertexLocalVars.Add( currentPass.LocalVarsList[ i ].SpecialVarType, currentPass.LocalVarsList[ i ] ); + } + else + { + m_specialFragmentLocalVars.Add( currentPass.LocalVarsList[ i ].SpecialVarType, currentPass.LocalVarsList[ i ] ); + } + } + } + } + + public void BuildFromTemplateData( MasterNodeDataCollector dataCollector, TemplateData templateData ) + { + m_registeredVertexData = new Dictionary<string, TemplateVertexData>(); + m_customInterpolatedData = new Dictionary<string, TemplateCustomData>(); + + + m_currentDataCollector = dataCollector; + m_currentTemplateData = templateData; + + m_vertexDataDict = new Dictionary<TemplateSemantics, TemplateVertexData>(); + if( templateData.VertexDataList != null ) + { + for( int i = 0; i < templateData.VertexDataList.Count; i++ ) + { + m_vertexDataDict.Add( templateData.VertexDataList[ i ].Semantics, new TemplateVertexData( templateData.VertexDataList[ i ] ) ); + } + } + + m_availableFragData = new Dictionary<TemplateInfoOnSematics, InterpDataHelper>(); + if( templateData.InterpolatorData != null && templateData.FragmentFunctionData != null ) + { + m_interpolatorData = new TemplateInterpData( templateData.InterpolatorData ); + int fragCount = templateData.InterpolatorData.Interpolators.Count; + for( int i = 0; i < fragCount; i++ ) + { + string varName = string.Empty; + if( templateData.InterpolatorData.Interpolators[ i ].ExcludeStructPrefix ) + { + varName = templateData.InterpolatorData.Interpolators[ i ].VarName; + } + else if( templateData.InterpolatorData.Interpolators[ i ].IsSingleComponent ) + { + varName = string.Format( TemplateHelperFunctions.TemplateVarFormat, + templateData.FragmentFunctionData.InVarName, + templateData.InterpolatorData.Interpolators[ i ].VarNameWithSwizzle ); + } + else + { + varName = string.Format( templateData.InterpolatorData.Interpolators[ i ].VarNameWithSwizzle, templateData.FragmentFunctionData.InVarName ); + } + + m_availableFragData.Add( templateData.InterpolatorData.Interpolators[ i ].DataInfo, + new InterpDataHelper( templateData.InterpolatorData.Interpolators[ i ].SwizzleType, + varName, + templateData.InterpolatorData.Interpolators[ i ].IsSingleComponent ) ); + } + } + + + m_availableVertData = new Dictionary<TemplateInfoOnSematics, InterpDataHelper>(); + if( templateData.VertexFunctionData != null && templateData.VertexDataList != null ) + { + int vertCount = templateData.VertexDataList.Count; + for( int i = 0; i < vertCount; i++ ) + { + string varName = string.Empty; + if( templateData.VertexDataList[ i ].ExcludeStructPrefix ) + { + varName = templateData.VertexDataList[ i ].VarName; + } + else + { + varName = string.Format( TemplateHelperFunctions.TemplateVarFormat, templateData.VertexFunctionData.InVarName, templateData.VertexDataList[ i ].VarNameWithSwizzle ); + } + + m_availableVertData.Add( templateData.VertexDataList[ i ].DataInfo, + new InterpDataHelper( templateData.VertexDataList[ i ].SwizzleType, + varName, + templateData.VertexDataList[ i ].IsSingleComponent ) ); + } + } + } + + public void RegisterFragInputParams( WirePortDataType type, PrecisionType precision, string name, TemplateSemantics semantic, string custom ) + { + if( m_fragmentInputParams == null ) + m_fragmentInputParams = new Dictionary<TemplateSemantics, TemplateInputParameters>(); + + m_fragmentInputParams.Add( semantic, new TemplateInputParameters( type, precision, name, semantic, custom ) ); + } + + public void RegisterFragInputParams( WirePortDataType type, PrecisionType precision, string name, TemplateSemantics semantic ) + { + if( m_fragmentInputParams == null ) + m_fragmentInputParams = new Dictionary<TemplateSemantics, TemplateInputParameters>(); + + m_fragmentInputParams.Add( semantic, new TemplateInputParameters( type, precision, name, semantic ) ); + } + + public void RegisterVertexInputParams( WirePortDataType type, PrecisionType precision, string name, TemplateSemantics semantic ) + { + if( m_vertexInputParams == null ) + m_vertexInputParams = new Dictionary<TemplateSemantics, TemplateInputParameters>(); + + m_vertexInputParams.Add( semantic, new TemplateInputParameters( type, precision, name, semantic ) ); + } + + public string GetVertexId() + { + var precision = PrecisionType.Float; + bool useMasterNodeCategory = true; + MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment; + + WirePortDataType type = WirePortDataType.UINT; + if( HasInfo( TemplateInfoOnSematics.VERTEXID, useMasterNodeCategory, customCategory ) ) + { + InterpDataHelper info = GetInfo( TemplateInfoOnSematics.VERTEXID, useMasterNodeCategory, customCategory ); + return TemplateHelperFunctions.AutoSwizzleData( info.VarName, info.VarType, type, true ); + } + else + { + MasterNodePortCategory portCategory = useMasterNodeCategory ? m_currentDataCollector.PortCategory : customCategory; + string name = "ase_vertexID"; + return RegisterInfoOnSemantic( portCategory, TemplateInfoOnSematics.VERTEXID, TemplateSemantics.SV_VertexID, name, WirePortDataType.UINT, precision, true ); + } + + // need to review this later + //if( m_vertexInputParams != null && m_vertexInputParams.ContainsKey( TemplateSemantics.SV_VertexID ) ) + //{ + // if( m_currentDataCollector.PortCategory == MasterNodePortCategory.Vertex ) + // return m_vertexInputParams[ TemplateSemantics.SV_VertexID ].Name; + //} + //else + //{ + // RegisterVertexInputParams( WirePortDataType.UINT, PrecisionType.Float, TemplateHelperFunctions.SemanticsDefaultName[ TemplateSemantics.SV_VertexID ], TemplateSemantics.SV_VertexID ); + //} + + //if( m_currentDataCollector.PortCategory != MasterNodePortCategory.Vertex ) + // RegisterCustomInterpolatedData( m_vertexInputParams[ TemplateSemantics.SV_VertexID ].Name, WirePortDataType.INT, PrecisionType.Float, m_vertexInputParams[ TemplateSemantics.SV_VertexID ].Name ); + + //return m_vertexInputParams[ TemplateSemantics.SV_VertexID ].Name; + } +#if UNITY_EDITOR_WIN + public string GetPrimitiveId() + { + if( m_fragmentInputParams != null && m_fragmentInputParams.ContainsKey( TemplateSemantics.SV_PrimitiveID ) ) + return m_fragmentInputParams[ TemplateSemantics.SV_PrimitiveID ].Name; + + RegisterFragInputParams( WirePortDataType.UINT, PrecisionType.Half, TemplateHelperFunctions.SemanticsDefaultName[ TemplateSemantics.SV_PrimitiveID ], TemplateSemantics.SV_PrimitiveID ); + return m_fragmentInputParams[ TemplateSemantics.SV_PrimitiveID ].Name; + } +#endif + public string GetVFace( int uniqueId ) + { + #if UNITY_2018_3_OR_NEWER + if( IsHDRP && ASEPackageManagerHelper.CurrentHDVersion >= ASESRPVersions.ASE_SRP_6_9_0 ) + { + string result = string.Empty; + if( GetCustomInterpolatedData( TemplateInfoOnSematics.VFACE, WirePortDataType.FLOAT, PrecisionType.Float, ref result, true, MasterNodePortCategory.Fragment ) ) + { + m_currentDataCollector.AddToDirectives( "#if !defined(ASE_NEED_CULLFACE)" ); + m_currentDataCollector.AddToDirectives( "#define ASE_NEED_CULLFACE 1" ); + m_currentDataCollector.AddToDirectives( "#endif //ASE_NEED_CULLFACE" ); + return result; + } + else + { + if( m_fragmentInputParams != null && m_fragmentInputParams.ContainsKey( TemplateSemantics.VFACE ) ) + return m_fragmentInputParams[ TemplateSemantics.VFACE ].Name; + + string custom = "FRONT_FACE_TYPE "+ TemplateHelperFunctions.SemanticsDefaultName[ TemplateSemantics.VFACE ] + " : FRONT_FACE_SEMANTIC"; + RegisterFragInputParams( WirePortDataType.FLOAT, PrecisionType.Half, TemplateHelperFunctions.SemanticsDefaultName[ TemplateSemantics.VFACE ], TemplateSemantics.VFACE, custom ); + return m_fragmentInputParams[ TemplateSemantics.VFACE ].Name; + } + } + else + #endif + { + if( m_fragmentInputParams != null && m_fragmentInputParams.ContainsKey( TemplateSemantics.VFACE ) ) + return m_fragmentInputParams[ TemplateSemantics.VFACE ].Name; + + RegisterFragInputParams( WirePortDataType.FLOAT, PrecisionType.Half, TemplateHelperFunctions.SemanticsDefaultName[ TemplateSemantics.VFACE ], TemplateSemantics.VFACE ); + return m_fragmentInputParams[ TemplateSemantics.VFACE ].Name; + } + } + + public string GetShadowCoords( int uniqueId, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + // overriding precision + var precision = PrecisionType.Float; + + string worldPos = GetWorldPos( false, m_currentDataCollector.PortCategory ); + + string result = string.Empty; + if( GetCustomInterpolatedData( TemplateInfoOnSematics.SHADOWCOORDS, WirePortDataType.FLOAT4, precision, ref result, useMasterNodeCategory, customCategory ) ) + { + return result; + } + + string varName = GeneratorUtils.ShadowCoordsStr; + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + + string shadowCoordsValue = string.Format( "TransformWorldToShadowCoord({0})", worldPos ); + if( m_currentDataCollector.PortCategory == MasterNodePortCategory.Fragment ) + { + worldPos = GetWorldPos( false, MasterNodePortCategory.Vertex ); + m_currentDataCollector.AddLocalVariable( uniqueId, "#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR) //la" ); + RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT4, precision, string.Format( "TransformWorldToShadowCoord({0})", worldPos ), false, MasterNodePortCategory.Fragment ); + m_currentDataCollector.AddLocalVariable( uniqueId, "#elif defined(MAIN_LIGHT_CALCULATE_SHADOWS) //la" ); + m_currentDataCollector.AddLocalVariable( uniqueId, precision, WirePortDataType.FLOAT4, varName, shadowCoordsValue ); + m_currentDataCollector.AddLocalVariable( uniqueId, "#else //la" ); + m_currentDataCollector.AddLocalVariable( uniqueId, precision, WirePortDataType.FLOAT4, varName, "0" ); + m_currentDataCollector.AddLocalVariable( uniqueId, "#endif //la" ); + } else + { + m_currentDataCollector.AddLocalVariable( uniqueId, precision, WirePortDataType.FLOAT4, varName, shadowCoordsValue ); + } + return varName; + } + + public bool HasUV( int uvChannel ) + { + return ( m_currentDataCollector.PortCategory == MasterNodePortCategory.Fragment ) ? m_availableFragData.ContainsKey( TemplateHelperFunctions.IntToUVChannelInfo[ uvChannel ] ) : m_availableVertData.ContainsKey( TemplateHelperFunctions.IntToUVChannelInfo[ uvChannel ] ); + } + + public string GetUVName( int uvChannel, WirePortDataType dataType = WirePortDataType.FLOAT2 ) + { + InterpDataHelper info = ( m_currentDataCollector.PortCategory == MasterNodePortCategory.Fragment ) ? m_availableFragData[ TemplateHelperFunctions.IntToUVChannelInfo[ uvChannel ] ] : m_availableVertData[ TemplateHelperFunctions.IntToUVChannelInfo[ uvChannel ] ]; + if( dataType != info.VarType ) + return info.VarName + UIUtils.GetAutoSwizzle( dataType ); + else + return info.VarName; + } + + public string GetTextureCoord( int uvChannel, string propertyName, int uniqueId, PrecisionType precisionType ) + { + bool isVertex = ( m_currentDataCollector.PortCategory == MasterNodePortCategory.Vertex || m_currentDataCollector.PortCategory == MasterNodePortCategory.Tessellation ); + string uvChannelName = string.Empty; + string propertyHelperVar = propertyName + "_ST"; + m_currentDataCollector.AddToUniforms( uniqueId, "float4", propertyHelperVar, IsSRP ); + string uvName = string.Empty; + if( m_currentDataCollector.TemplateDataCollectorInstance.HasUV( uvChannel ) ) + { + uvName = m_currentDataCollector.TemplateDataCollectorInstance.GetUVName( uvChannel ); + } + else + { + uvName = m_currentDataCollector.TemplateDataCollectorInstance.RegisterUV( uvChannel ); + } + + uvChannelName = "uv" + propertyName; + if( isVertex ) + { + string value = string.Format( Constants.TilingOffsetFormat, uvName, propertyHelperVar + ".xy", propertyHelperVar + ".zw" ); + string lodLevel = "0"; + + value = "float4( " + value + ", 0 , " + lodLevel + " )"; + m_currentDataCollector.AddLocalVariable( uniqueId, precisionType, WirePortDataType.FLOAT4, uvChannelName, value ); + } + else + { + m_currentDataCollector.AddLocalVariable( uniqueId, precisionType, WirePortDataType.FLOAT2, uvChannelName, string.Format( Constants.TilingOffsetFormat, uvName, propertyHelperVar + ".xy", propertyHelperVar + ".zw" ) ); + } + return uvChannelName; + } + + public string GenerateAutoUVs( int uvChannel, WirePortDataType size = WirePortDataType.FLOAT2 ) + { + string uvName = string.Empty; + if( HasUV( uvChannel ) ) + { + uvName = GetUVName( uvChannel, size ); + } + else + { + uvName = RegisterUV( uvChannel, size ); + } + return uvName; + } + + public string GetUV( int uvChannel, MasterNodePortCategory category = MasterNodePortCategory.Fragment, WirePortDataType size = WirePortDataType.FLOAT4 ) + { + if( !HasUV( uvChannel ) ) + { + RegisterUV( uvChannel, size ); + } + + InterpDataHelper info = ( category == MasterNodePortCategory.Fragment ) ? m_availableFragData[ TemplateHelperFunctions.IntToUVChannelInfo[ uvChannel ] ] : m_availableVertData[ TemplateHelperFunctions.IntToUVChannelInfo[ uvChannel ] ]; + return info.VarName; + } + + public InterpDataHelper GetUVInfo( int uvChannel ) + { + return ( m_currentDataCollector.PortCategory == MasterNodePortCategory.Fragment ) ? m_availableFragData[ TemplateHelperFunctions.IntToUVChannelInfo[ uvChannel ] ] : m_availableVertData[ TemplateHelperFunctions.IntToUVChannelInfo[ uvChannel ] ]; + } + + public string RegisterUV( int UVChannel, WirePortDataType size = WirePortDataType.FLOAT2 ) + { + int channelsSize = TemplateHelperFunctions.DataTypeChannelUsage[ size ]; + if( m_UVUsage[ UVChannel ] > channelsSize ) + { + size = TemplateHelperFunctions.ChannelToDataType[ m_UVUsage[ UVChannel ] ]; + } + + if( m_currentDataCollector.PortCategory == MasterNodePortCategory.Vertex ) + { + TemplateSemantics semantic = TemplateHelperFunctions.IntToSemantic[ UVChannel ]; + + if( m_vertexDataDict.ContainsKey( semantic ) ) + { + return m_vertexDataDict[ semantic ].VarName; + } + + string varName = TemplateHelperFunctions.BaseInterpolatorName + ( ( UVChannel > 0 ) ? UVChannel.ToString() : string.Empty ); + m_availableVertData.Add( TemplateHelperFunctions.IntToUVChannelInfo[ UVChannel ], + new InterpDataHelper( WirePortDataType.FLOAT4, + string.Format( TemplateHelperFunctions.TemplateVarFormat, + m_currentTemplateData.VertexFunctionData.InVarName, + varName ) ) ); + + m_currentDataCollector.AddToVertexInput( + string.Format( TemplateHelperFunctions.TexFullSemantic, + varName, + semantic ) ); + RegisterOnVertexData( semantic, size, varName ); + string finalVarName = m_availableVertData[ TemplateHelperFunctions.IntToUVChannelInfo[ UVChannel ] ].VarName; + switch( size ) + { + case WirePortDataType.FLOAT: + case WirePortDataType.INT: + case WirePortDataType.UINT: + finalVarName += ".x"; + break; + case WirePortDataType.FLOAT2: + finalVarName += ".xy"; + break; + case WirePortDataType.FLOAT3: + finalVarName += ".xyz"; + break; + case WirePortDataType.FLOAT4: + case WirePortDataType.COLOR: + case WirePortDataType.OBJECT: + case WirePortDataType.FLOAT4x4: + case WirePortDataType.SAMPLER1D: + case WirePortDataType.SAMPLER2D: + case WirePortDataType.SAMPLER3D: + case WirePortDataType.SAMPLERCUBE: + case WirePortDataType.FLOAT3x3: + default: + break; + } + return finalVarName; + } + else + { + //search if the correct vertex data is set ... + TemplateInfoOnSematics info = TemplateHelperFunctions.IntToInfo[ UVChannel ]; + TemplateSemantics vertexSemantics = TemplateSemantics.NONE; + foreach( KeyValuePair<TemplateSemantics, TemplateVertexData> kvp in m_vertexDataDict ) + { + if( kvp.Value.DataInfo == info ) + { + vertexSemantics = kvp.Key; + break; + } + } + + // if not, add vertex data and create interpolator + if( vertexSemantics == TemplateSemantics.NONE ) + { + vertexSemantics = TemplateHelperFunctions.IntToSemantic[ UVChannel ]; + + if( !m_vertexDataDict.ContainsKey( vertexSemantics ) ) + { + string varName = TemplateHelperFunctions.BaseInterpolatorName + ( ( UVChannel > 0 ) ? UVChannel.ToString() : string.Empty ); + m_availableVertData.Add( TemplateHelperFunctions.IntToUVChannelInfo[ UVChannel ], + new InterpDataHelper( WirePortDataType.FLOAT4, + string.Format( TemplateHelperFunctions.TemplateVarFormat, + m_currentTemplateData.VertexFunctionData.InVarName, + varName ) ) ); + + m_currentDataCollector.AddToVertexInput( + string.Format( TemplateHelperFunctions.TexFullSemantic, + varName, + vertexSemantics ) ); + RegisterOnVertexData( vertexSemantics, size, varName ); + } + } + + // either way create interpolator + TemplateVertexData availableInterp = RequestNewInterpolator( size, false ); + if( availableInterp != null ) + { + bool isPosition = vertexSemantics == TemplateSemantics.POSITION || vertexSemantics == TemplateSemantics.POSITION; + + string interpVarName = m_currentTemplateData.VertexFunctionData.OutVarName + "." + availableInterp.VarNameWithSwizzle; + InterpDataHelper vertInfo = m_availableVertData[ TemplateHelperFunctions.IntToUVChannelInfo[ UVChannel ] ]; + string interpDecl = string.Format( TemplateHelperFunctions.TemplateVariableDecl, interpVarName, TemplateHelperFunctions.AutoSwizzleData( vertInfo.VarName, vertInfo.VarType, size , isPosition ) ); + m_currentDataCollector.AddToVertexInterpolatorsDecl( interpDecl ); + string finalVarName = m_currentTemplateData.FragmentFunctionData.InVarName + "." + availableInterp.VarNameWithSwizzle; + m_availableFragData.Add( TemplateHelperFunctions.IntToUVChannelInfo[ UVChannel ], new InterpDataHelper( size, finalVarName ) ); + return finalVarName; + } + } + return string.Empty; + } + //////////////////////////////////////////////////////////////////////////////////////////////// + bool IsSemanticUsedOnInterpolator( TemplateSemantics semantics ) + { + for( int i = 0; i < m_interpolatorData.Interpolators.Count; i++ ) + { + if( m_interpolatorData.Interpolators[ i ].Semantics == semantics ) + { + return true; + } + } + return false; + } + + public bool HasInfo( TemplateInfoOnSematics info, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + MasterNodePortCategory category = useMasterNodeCategory ? m_currentDataCollector.PortCategory : customCategory; + return ( category == MasterNodePortCategory.Fragment ) ? m_availableFragData.ContainsKey( info ) : m_availableVertData.ContainsKey( info ); + } + + public InterpDataHelper GetInfo( TemplateInfoOnSematics info, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + MasterNodePortCategory category = useMasterNodeCategory ? m_currentDataCollector.PortCategory : customCategory; + if( category == MasterNodePortCategory.Fragment ) + { + if( !m_availableFragData[ info ].SetAtCompileTime ) + { + string defineValue = string.Empty; + if( TemplateHelperFunctions.InfoToDefineFrag.TryGetValue( info, out defineValue ) ) + m_currentDataCollector.AddToDefines( -1, defineValue ); + } + return m_availableFragData[ info ]; + } + else + { + if( !m_availableVertData[ info ].SetAtCompileTime ) + { + string defineValue = string.Empty; + if( TemplateHelperFunctions.InfoToDefineVertex.TryGetValue( info, out defineValue ) ) + m_currentDataCollector.AddToDefines( -1, defineValue ); + } + return m_availableVertData[ info ]; + } + } + + public string RegisterInfoOnSemantic( TemplateInfoOnSematics info, TemplateSemantics semantic, string name, WirePortDataType dataType, PrecisionType precisionType, bool requestNewInterpolator, string dataName = null ) + { + return RegisterInfoOnSemantic( m_currentDataCollector.PortCategory, info, semantic, name, dataType, precisionType, requestNewInterpolator, dataName ); + } + // This should only be used to semantics outside the text coord set + public string RegisterInfoOnSemantic( MasterNodePortCategory portCategory, TemplateInfoOnSematics info, TemplateSemantics semantic, string name, WirePortDataType dataType, PrecisionType precisionType, bool requestNewInterpolator, string dataName = null ) + { + if( portCategory == MasterNodePortCategory.Vertex ) + { + if( m_vertexDataDict.ContainsKey( semantic ) ) + { + return m_vertexDataDict[ semantic ].VarName; + } + + m_availableVertData.Add( info, + new InterpDataHelper( dataType, + string.Format( TemplateHelperFunctions.TemplateVarFormat, + m_currentTemplateData.VertexFunctionData.InVarName, + name ),true,true ) ); + + string vertInputVarType = UIUtils.PrecisionWirePortToCgType( precisionType, dataType ); + m_currentDataCollector.AddToVertexInput( + string.Format( TemplateHelperFunctions.InterpFullSemantic, + vertInputVarType, + name, + semantic ) ); + RegisterOnVertexData( semantic, dataType, name ); + return m_availableVertData[ info ].VarName; + } + else + { + //search if the correct vertex data is set ... + TemplateSemantics vertexSemantics = TemplateSemantics.NONE; + foreach( KeyValuePair<TemplateSemantics, TemplateVertexData> kvp in m_vertexDataDict ) + { + if( kvp.Value.DataInfo == info ) + { + vertexSemantics = kvp.Key; + break; + } + } + + // if not, add vertex data and create interpolator + if( vertexSemantics == TemplateSemantics.NONE ) + { + vertexSemantics = semantic; + + if( !m_vertexDataDict.ContainsKey( vertexSemantics ) ) + { + m_availableVertData.Add( info, + new InterpDataHelper( dataType, + string.Format( TemplateHelperFunctions.TemplateVarFormat, + m_currentTemplateData.VertexFunctionData.InVarName, + name ),true,true ) ); + + string vertInputVarType = UIUtils.PrecisionWirePortToCgType( precisionType, dataType ); + m_currentDataCollector.AddToVertexInput( + string.Format( TemplateHelperFunctions.InterpFullSemantic, + vertInputVarType, + name, + vertexSemantics ) ); + RegisterOnVertexData( vertexSemantics, dataType, name ); + } + } + + // either way create interpolator + + TemplateVertexData availableInterp = null; + if( requestNewInterpolator || IsSemanticUsedOnInterpolator( semantic ) ) + { + availableInterp = RequestNewInterpolator( dataType, false, dataName ); + } + else + { + availableInterp = RegisterOnInterpolator( semantic, dataType, dataName ); + } + + if( availableInterp != null ) + { + bool isPosition = vertexSemantics == TemplateSemantics.POSITION || vertexSemantics == TemplateSemantics.POSITION; + + string interpVarName = m_currentTemplateData.VertexFunctionData.OutVarName + "." + availableInterp.VarNameWithSwizzle; + string interpDecl = string.Format( TemplateHelperFunctions.TemplateVariableDecl, interpVarName, TemplateHelperFunctions.AutoSwizzleData( m_availableVertData[ info ].VarName, m_availableVertData[ info ].VarType, dataType, isPosition ) ); + m_currentDataCollector.AddToVertexInterpolatorsDecl( interpDecl ); + string finalVarName = m_currentTemplateData.FragmentFunctionData.InVarName + "." + availableInterp.VarNameWithSwizzle; + m_availableFragData.Add( info, new InterpDataHelper( dataType, finalVarName ) ); + return finalVarName; + } + } + return string.Empty; + } + + TemplateVertexData RegisterOnInterpolator( TemplateSemantics semantics, WirePortDataType dataType, string vertexDataName = null ) + { + if( vertexDataName == null ) + { + if( TemplateHelperFunctions.SemanticsDefaultName.ContainsKey( semantics ) ) + { + vertexDataName = TemplateHelperFunctions.SemanticsDefaultName[ semantics ]; + } + else + { + vertexDataName = string.Empty; + Debug.LogError( "No valid name given to vertex data" ); + } + } + + TemplateVertexData data = new TemplateVertexData( semantics, dataType, vertexDataName ); + m_interpolatorData.Interpolators.Add( data ); + string interpolator = string.Format( TemplateHelperFunctions.InterpFullSemantic, UIUtils.WirePortToCgType( dataType ), data.VarName, data.Semantics ); + m_currentDataCollector.AddToInterpolators( interpolator ); + return data; + } + + public void RegisterOnVertexData( TemplateSemantics semantics, WirePortDataType dataType, string varName ) + { + m_vertexDataDict.Add( semantics, new TemplateVertexData( semantics, dataType, varName ) ); + } + + public TemplateVertexData RequestMacroInterpolator( string varName ) + { + if( varName != null && m_registeredVertexData.ContainsKey( varName ) ) + { + return m_registeredVertexData[ varName ]; + } + + for( int i = 0; i < m_interpolatorData.AvailableInterpolators.Count; i++ ) + { + if( !m_interpolatorData.AvailableInterpolators[ i ].IsFull ) + { + TemplateVertexData data = m_interpolatorData.AvailableInterpolators[ i ].RequestChannels( WirePortDataType.FLOAT4, false, varName ); + if( data != null ) + { + if( !m_registeredVertexData.ContainsKey( data.VarName ) ) + { + m_registeredVertexData.Add( data.VarName, data ); + } + if( m_interpolatorData.AvailableInterpolators[ i ].Usage == 1 ) + { + string interpolator = string.Format( TemplateHelperFunctions.InterpMacro, varName, TemplateHelperFunctions.SemanticToInt[ data.Semantics ] ); + m_currentDataCollector.AddToInterpolators( interpolator ); + } + return data; + } + } + } + return null; + } + + public bool HasRawInterpolatorOfName( string name ) + { + return m_interpolatorData.HasRawInterpolatorOfName( name ); + } + + public TemplateVertexData RequestNewInterpolator( WirePortDataType dataType, bool isColor, string varName = null ) + { + if( varName != null && m_registeredVertexData.ContainsKey( varName ) ) + { + return m_registeredVertexData[ varName ]; + } + + for( int i = 0; i < m_interpolatorData.AvailableInterpolators.Count; i++ ) + { + if( !m_interpolatorData.AvailableInterpolators[ i ].IsFull ) + { + TemplateVertexData data = m_interpolatorData.AvailableInterpolators[ i ].RequestChannels( dataType, isColor, varName ); + if( data != null ) + { + if( !m_registeredVertexData.ContainsKey( data.VarName ) ) + { + m_registeredVertexData.Add( data.VarName, data ); + } + + if( m_interpolatorData.AvailableInterpolators[ i ].Usage == 1 ) + { + // First time using this interpolator, so we need to register it + string interpolator = string.Format( TemplateHelperFunctions.TexFullSemantic, + data.VarName, data.Semantics ); + m_currentDataCollector.AddToInterpolators( interpolator ); + } + return data; + } + } + } + + // This area is reached if max available interpolators from shader model is reached + // Nevertheless, we register all new interpolators to that list so no imediate compilation errors are thrown + // A warning message is then thrown to warn the user about this + int newInterpId = 1 + TemplateHelperFunctions.SemanticToInt[ m_interpolatorData.AvailableInterpolators[ m_interpolatorData.AvailableInterpolators.Count - 1 ].Semantic ]; + if( TemplateHelperFunctions.IntToSemantic.ContainsKey( newInterpId ) ) + { + TemplateInterpElement item = new TemplateInterpElement( TemplateHelperFunctions.IntToSemantic[ newInterpId ] ); + m_interpolatorData.AvailableInterpolators.Add( item ); + TemplateVertexData data = item.RequestChannels( dataType, isColor, varName ); + if( data != null ) + { + if( !m_registeredVertexData.ContainsKey( data.VarName ) ) + { + m_registeredVertexData.Add( data.VarName, data ); + } + + if( item.Usage == 1 ) + { + string interpolator = string.Format( TemplateHelperFunctions.TexFullSemantic, data.VarName, data.Semantics ); + m_currentDataCollector.AddToInterpolators( interpolator ); + } + return data; + } + } + + UIUtils.ShowMessage( "Maximum amount of interpolators exceeded", MessageSeverity.Error ); + return null; + } + + // Unused channels in interpolators must be set to something so the compiler doesn't generate warnings + public List<string> GetInterpUnusedChannels() + { + List<string> resetInstrucctions = new List<string>(); + + if( m_interpolatorData != null ) + { + for( int i = 0; i < m_interpolatorData.AvailableInterpolators.Count; i++ ) + { + if( m_interpolatorData.AvailableInterpolators[ i ].Usage > 0 && !m_interpolatorData.AvailableInterpolators[ i ].IsFull ) + { + string channels = string.Empty; + bool[] availableChannels = m_interpolatorData.AvailableInterpolators[ i ].AvailableChannels; + for( int j = 0; j < availableChannels.Length; j++ ) + { + if( availableChannels[ j ] ) + { + channels += TemplateHelperFunctions.VectorSwizzle[ j ]; + } + } + + resetInstrucctions.Add( string.Format( "{0}.{1}.{2} = 0;", m_currentTemplateData.VertexFunctionData.OutVarName, m_interpolatorData.AvailableInterpolators[ i ].Name, channels ) ); + } + } + } + + if( resetInstrucctions.Count > 0 ) + { + resetInstrucctions.Insert( 0, "\n//setting value to unused interpolator channels and avoid initialization warnings" ); + } + + return resetInstrucctions; + } + + public bool GetCustomInterpolatedData( TemplateInfoOnSematics info, WirePortDataType type, PrecisionType precisionType, ref string result, bool useMasterNodeCategory, MasterNodePortCategory customCategory ) + { + bool isPosition = info == TemplateInfoOnSematics.POSITION || + info == TemplateInfoOnSematics.CLIP_POS || + info == TemplateInfoOnSematics.SCREEN_POSITION || + info == TemplateInfoOnSematics.SCREEN_POSITION_NORMALIZED || + info == TemplateInfoOnSematics.WORLD_POSITION || + info == TemplateInfoOnSematics.RELATIVE_WORLD_POS; + + + MasterNodePortCategory category = useMasterNodeCategory ? m_currentDataCollector.PortCategory : customCategory; + if( category == MasterNodePortCategory.Vertex ) + { + if( m_specialVertexLocalVars.ContainsKey( info ) ) + { + result = m_specialVertexLocalVars[ info ].LocalVarName; + if( m_specialVertexLocalVars[ info ].DataType != type ) + { + result = TemplateHelperFunctions.AutoSwizzleData( result, m_specialVertexLocalVars[ info ].DataType, type , isPosition ); + } + + string defineValue = string.Empty; + if( TemplateHelperFunctions.InfoToDefineVertex.TryGetValue( info, out defineValue ) ) + m_currentDataCollector.AddToDefines( -1, defineValue ); + + return true; + } + } + + if( category == MasterNodePortCategory.Fragment ) + { + if( m_specialFragmentLocalVars.ContainsKey( info ) ) + { + result = m_specialFragmentLocalVars[ info ].LocalVarName; + if( m_specialFragmentLocalVars[ info ].DataType != type ) + { + result = TemplateHelperFunctions.AutoSwizzleData( result, m_specialFragmentLocalVars[ info ].DataType, type, isPosition ); + } + + string defineValue = string.Empty; + if( TemplateHelperFunctions.InfoToDefineFrag.TryGetValue( info, out defineValue )) + m_currentDataCollector.AddToDefines( -1, defineValue ); + return true; + } + + if( m_availableFragData.ContainsKey( info ) ) + { + if( m_availableFragData[ info ].IsSingleComponent ) + { + result = m_availableFragData[ info ].VarName; + if( m_availableFragData[ info ].VarType != type ) + { + result = TemplateHelperFunctions.AutoSwizzleData( result, m_availableFragData[ info ].VarType, type, isPosition ); + } + return true; + } + else if( TemplateHelperFunctions.InfoToLocalVar.ContainsKey( info ) && TemplateHelperFunctions.InfoToWirePortType.ContainsKey( info ) ) + { + result = TemplateHelperFunctions.InfoToLocalVar[ info ]; + m_currentDataCollector.AddLocalVariable( -1, precisionType, TemplateHelperFunctions.InfoToWirePortType[ info ], result, m_availableFragData[ info ].VarName ); + return true; + } + } + } + return false; + } + + public string GetVertexPosition( WirePortDataType type, PrecisionType precisionType, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + if( HasInfo( TemplateInfoOnSematics.POSITION, useMasterNodeCategory, customCategory ) ) + { + InterpDataHelper info = GetInfo( TemplateInfoOnSematics.POSITION, useMasterNodeCategory, customCategory ); + if( type != WirePortDataType.OBJECT && type != info.VarType ) + return TemplateHelperFunctions.AutoSwizzleData( info.VarName, info.VarType, type,true ); + else + return info.VarName; + } + else + { + MasterNodePortCategory portCategory = useMasterNodeCategory ? m_currentDataCollector.PortCategory : customCategory; + string name = "ase_vertex_pos"; + string varName = RegisterInfoOnSemantic( portCategory, TemplateInfoOnSematics.POSITION, TemplateSemantics.POSITION, name, WirePortDataType.FLOAT4, precisionType, true ); + if( type != WirePortDataType.OBJECT && type != WirePortDataType.FLOAT4 ) + return TemplateHelperFunctions.AutoSwizzleData( varName, WirePortDataType.FLOAT4, type,true ); + else + return varName; + } + } + + private const string InstancingLibStandard = "UnityInstancing.cginc"; + private const string InstancingLibSRP = "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"; + + public void SetupInstancing() + { + if( !HasInfo( TemplateInfoOnSematics.INSTANCE_ID ) ) + { + m_currentDataCollector.AddToPragmas( -1, IOUtils.InstancedPropertiesHeader ); + m_currentDataCollector.AddToIncludes( -1, IsSRP ? InstancingLibSRP : InstancingLibStandard ); + m_currentDataCollector.AddToVertexInput( Constants.InstanceIdMacro ); + m_currentDataCollector.AddToInterpolators( Constants.InstanceIdMacro ); + m_currentDataCollector.AddToLocalVariables( MasterNodePortCategory.Vertex, -1, string.Format( "UNITY_SETUP_INSTANCE_ID({0});", m_currentTemplateData.VertexFunctionData.InVarName ) ); + m_currentDataCollector.AddToLocalVariables( MasterNodePortCategory.Vertex, -1, string.Format( "UNITY_TRANSFER_INSTANCE_ID({0}, {1});", m_currentTemplateData.VertexFunctionData.InVarName, m_currentTemplateData.VertexFunctionData.OutVarName ) ); + m_currentDataCollector.AddToLocalVariables( MasterNodePortCategory.Fragment, -1, string.Format( "UNITY_SETUP_INSTANCE_ID({0});", m_currentTemplateData.FragmentFunctionData.InVarName ) ); + } + } + + public string GetVertexColor( PrecisionType precisionType ) + { + if( HasInfo( TemplateInfoOnSematics.COLOR ) ) + { + return GetInfo( TemplateInfoOnSematics.COLOR ).VarName; + } + else + { + string name = "ase_color"; + return RegisterInfoOnSemantic( TemplateInfoOnSematics.COLOR, TemplateSemantics.COLOR, name, WirePortDataType.FLOAT4, precisionType, false ); + } + } + + public string GetVertexNormal( PrecisionType precisionType, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + if( HasInfo( TemplateInfoOnSematics.NORMAL, useMasterNodeCategory, customCategory ) ) + { + InterpDataHelper info = GetInfo( TemplateInfoOnSematics.NORMAL, useMasterNodeCategory, customCategory ); + return TemplateHelperFunctions.AutoSwizzleData( info.VarName, info.VarType, WirePortDataType.FLOAT3 , false); + } + else + { + MasterNodePortCategory category = useMasterNodeCategory ? m_currentDataCollector.PortCategory : customCategory; + string name = "ase_normal"; + return RegisterInfoOnSemantic( category, TemplateInfoOnSematics.NORMAL, TemplateSemantics.NORMAL, name, WirePortDataType.FLOAT3, precisionType, false ); + } + } + + public string GetWorldNormal( PrecisionType precisionType = PrecisionType.Float, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment, bool normalize = false ) + { + string result = string.Empty; + if( GetCustomInterpolatedData( TemplateInfoOnSematics.WORLD_NORMAL, WirePortDataType.FLOAT3, precisionType, ref result, useMasterNodeCategory, customCategory ) ) + { + if( normalize ) + return string.Format( "normalize( {0} )", result ); + else + return result; + } + + string varName = normalize ? "normalizeWorldNormal" : GeneratorUtils.WorldNormalStr; + + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + string worldNormalValue = string.Empty; + + if( !GetCustomInterpolatedData( TemplateInfoOnSematics.WORLD_NORMAL, WirePortDataType.FLOAT3, precisionType, ref worldNormalValue, false, MasterNodePortCategory.Vertex ) ) + { + string vertexNormal = GetVertexNormal( precisionType, false, MasterNodePortCategory.Vertex ); + string formatStr = string.Empty; + if( IsSRP ) + formatStr = "TransformObjectToWorldNormal({0})"; + else + formatStr = "UnityObjectToWorldNormal({0})"; + worldNormalValue = string.Format( formatStr, vertexNormal ); + } + + if( normalize ) + worldNormalValue = string.Format( "normalize( {0} )", worldNormalValue ); + + RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT3, precisionType, worldNormalValue, useMasterNodeCategory, customCategory ); + return varName; + } + + public string GetWorldNormal( int uniqueId, PrecisionType precisionType, string normal, string outputId ) + { + string tanToWorld0 = string.Empty; + string tanToWorld1 = string.Empty; + string tanToWorld2 = string.Empty; + + GetWorldTangentTf( precisionType, out tanToWorld0, out tanToWorld1, out tanToWorld2, true ); + + string tanNormal = "tanNormal" + outputId; + m_currentDataCollector.AddLocalVariable( uniqueId, "float3 " + tanNormal + " = " + normal + ";" ); + return string.Format( "float3(dot({1},{0}), dot({2},{0}), dot({3},{0}))", tanNormal, tanToWorld0, tanToWorld1, tanToWorld2 ); + } + + public string GetVertexTangent( WirePortDataType type, PrecisionType precisionType, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + if( HasInfo( TemplateInfoOnSematics.TANGENT, useMasterNodeCategory, customCategory ) ) + { + InterpDataHelper info = GetInfo( TemplateInfoOnSematics.TANGENT, useMasterNodeCategory, customCategory ); + if( type != WirePortDataType.OBJECT && type != info.VarType ) + return TemplateHelperFunctions.AutoSwizzleData( info.VarName, info.VarType, type , false); + else + return info.VarName; + } + else + { + MasterNodePortCategory category = useMasterNodeCategory ? m_currentDataCollector.PortCategory : customCategory; + string name = "ase_tangent"; + string varName = RegisterInfoOnSemantic( category, TemplateInfoOnSematics.TANGENT, TemplateSemantics.TANGENT, name, WirePortDataType.FLOAT4, precisionType, false ); + if( type != WirePortDataType.OBJECT && type != WirePortDataType.FLOAT4 ) + return TemplateHelperFunctions.AutoSwizzleData( varName, WirePortDataType.FLOAT4, type , false ); + else + return varName; + } + } + + public string GetVertexBitangent( PrecisionType precisionType, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + string varName = GeneratorUtils.VertexBitangentStr; + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + string tangentValue = GetVertexTangent( WirePortDataType.FLOAT3, precisionType, false, MasterNodePortCategory.Vertex ); + string normalValue = GetVertexNormal( precisionType, false, MasterNodePortCategory.Vertex ); + + string bitangentValue = string.Format( "cross({0},{1})", normalValue, tangentValue ); + RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT3, precisionType, bitangentValue, useMasterNodeCategory, customCategory ); + return varName; + } + + public string GetWorldTangent( PrecisionType precisionType, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + string result = string.Empty; + if( GetCustomInterpolatedData( TemplateInfoOnSematics.WORLD_TANGENT, WirePortDataType.FLOAT3, precisionType, ref result, useMasterNodeCategory, customCategory ) ) + { + return result; + } + + string varName = GeneratorUtils.WorldTangentStr; + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + string worldTangentValue = string.Empty; + if( !GetCustomInterpolatedData( TemplateInfoOnSematics.WORLD_TANGENT, WirePortDataType.FLOAT3, precisionType, ref worldTangentValue, false, MasterNodePortCategory.Vertex ) ) + { + string vertexTangent = GetVertexTangent( WirePortDataType.FLOAT4, precisionType, false, MasterNodePortCategory.Vertex ); + string formatStr = string.Empty; + + if( IsSRP ) + formatStr = "TransformObjectToWorldDir({0}.xyz)"; + else + formatStr = "UnityObjectToWorldDir({0})"; + + worldTangentValue = string.Format( formatStr, vertexTangent ); + } + RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT3, precisionType, worldTangentValue, useMasterNodeCategory, customCategory ); + return varName; + } + + public string GetTangentSign( PrecisionType precisionType, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + string varName = GeneratorUtils.VertexTangentSignStr; + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + string tangentValue = GetVertexTangent( WirePortDataType.FLOAT4, precisionType, false, MasterNodePortCategory.Vertex ); + string tangentSignValue = string.Format( "{0}.w * unity_WorldTransformParams.w", tangentValue ); + RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT, precisionType, tangentSignValue, useMasterNodeCategory, customCategory ); + return varName; + } + + + public string GetWorldBinormal( PrecisionType precisionType, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + string result = string.Empty; + if( GetCustomInterpolatedData( TemplateInfoOnSematics.WORLD_BITANGENT, WirePortDataType.FLOAT3, precisionType, ref result, useMasterNodeCategory, customCategory ) ) + { + return result; + } + + string varName = GeneratorUtils.WorldBitangentStr; + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + string worldBinormal = string.Empty; + if( !GetCustomInterpolatedData( TemplateInfoOnSematics.WORLD_BITANGENT, WirePortDataType.FLOAT3, precisionType, ref worldBinormal, false, MasterNodePortCategory.Vertex ) ) + { + string worldNormal = GetWorldNormal( precisionType, false, MasterNodePortCategory.Vertex ); + string worldtangent = GetWorldTangent( precisionType, false, MasterNodePortCategory.Vertex ); + string tangentSign = GetTangentSign( precisionType, false, MasterNodePortCategory.Vertex ); + worldBinormal = string.Format( "cross( {0}, {1} ) * {2}", worldNormal, worldtangent, tangentSign ); + } + + RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT3, PrecisionType.Float, worldBinormal, useMasterNodeCategory, customCategory ); + return varName; + } + + public string GetWorldReflection( PrecisionType precisionType, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment, bool normalize = false ) + { + string varName = GeneratorUtils.WorldReflectionStr;//UIUtils.GetInputValueFromType( SurfaceInputs.WORLD_REFL ); + if( normalize ) + varName = "normalized" + varName; + + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + string worldNormal = GetWorldNormal( precisionType ); + string worldViewDir = GetViewDir(); + string worldRefl = string.Format( "reflect(-{0}, {1})", worldViewDir, worldNormal ); + + if( normalize ) + worldRefl = string.Format( "normalize( {0} )", worldRefl ); + + m_currentDataCollector.AddLocalVariable( -1, precisionType, WirePortDataType.FLOAT3, varName, worldRefl ); + return varName; + } + + public string GetWorldReflection( PrecisionType precisionType, string normal ) + { + string tanToWorld0 = string.Empty; + string tanToWorld1 = string.Empty; + string tanToWorld2 = string.Empty; + + GetWorldTangentTf( precisionType, out tanToWorld0, out tanToWorld1, out tanToWorld2 ); + string worldRefl = GetViewDir(); + + return string.Format( "reflect( -{0}, float3( dot( {2}, {1} ), dot( {3}, {1} ), dot( {4}, {1} ) ) )", worldRefl, normal, tanToWorld0, tanToWorld1, tanToWorld2 ); + } + + public string GetLightAtten( int uniqueId, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + //string result = string.Empty; + //if( GetCustomInterpolatedData( TemplateInfoOnSematics.WORLD_POSITION, PrecisionType.Float, ref result, useMasterNodeCategory, customCategory ) ) + //{ + // return result; + //} + + //string varName = GeneratorUtils.WorldPositionStr;//UIUtils.GetInputValueFromType( SurfaceInputs.WORLD_POS ); + //if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + // return varName; + + //if( !m_availableVertData.ContainsKey( TemplateInfoOnSematics.POSITION ) ) + //{ + // UIUtils.ShowMessage( "Attempting to access inexisting vertex position to calculate world pos" ); + // return "fixed3(0,0,0)"; + //} + + //string vertexPos = m_availableVertData[ TemplateInfoOnSematics.POSITION ].VarName; + //string worldPosConversion = string.Format( "mul(unity_ObjectToWorld, {0}).xyz", vertexPos ); + + //RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT3, PrecisionType.Float, worldPosConversion, useMasterNodeCategory, customCategory ); + //return varName; + + m_currentDataCollector.AddToIncludes( uniqueId, Constants.UnityAutoLightLib ); + m_currentDataCollector.AddToDefines( uniqueId, "ASE_SHADOWS 1" ); +#if UNITY_5_6_OR_NEWER + RequestMacroInterpolator( "UNITY_SHADOW_COORDS" ); +#else + RequestMacroInterpolator( "SHADOW_COORDS" ); + m_currentDataCollector.AddToPragmas( uniqueId, "multi_compile_fwdbase" ); +#endif + //string vOutName = CurrentTemplateData.VertexFunctionData.OutVarName; + string fInName = CurrentTemplateData.FragmentFunctionData.InVarName; + string worldPos = GetWorldPos(); + m_currentDataCollector.AddLocalVariable( uniqueId, "UNITY_LIGHT_ATTENUATION(ase_atten, " + fInName + ", " + worldPos + ")" ); + return "ase_atten"; + + } + + public string GenerateRotationIndependentObjectScale( ref MasterNodeDataCollector dataCollector, int uniqueId ) + { + string value = string.Empty; + + if( m_currentSRPType != TemplateSRPType.BuiltIn ) + { + value = "float3( length( GetWorldToObjectMatrix()[ 0 ].xyz ), length( GetWorldToObjectMatrix()[ 1 ].xyz ), length( GetWorldToObjectMatrix()[ 2 ].xyz ) )"; + } + else + { + value = "float3( length( unity_WorldToObject[ 0 ].xyz ), length( unity_WorldToObject[ 1 ].xyz ), length( unity_WorldToObject[ 2 ].xyz ) )"; + } + value = "( 1.0 / "+ value +" )"; + dataCollector.AddLocalVariable( uniqueId, PrecisionType.Float, WirePortDataType.FLOAT3, GeneratorUtils.ParentObjectScaleStr, value ); + return GeneratorUtils.ParentObjectScaleStr; + } + + public string GenerateObjectScale( ref MasterNodeDataCollector dataCollector, int uniqueId ) + { + string value = string.Empty; + + if( m_currentSRPType != TemplateSRPType.BuiltIn ) + { + value = "float3( length( GetObjectToWorldMatrix()[ 0 ].xyz ), length( GetObjectToWorldMatrix()[ 1 ].xyz ), length( GetObjectToWorldMatrix()[ 2 ].xyz ) )"; + } + else + { + value = "float3( length( unity_ObjectToWorld[ 0 ].xyz ), length( unity_ObjectToWorld[ 1 ].xyz ), length( unity_ObjectToWorld[ 2 ].xyz ) )"; + } + dataCollector.AddLocalVariable( uniqueId, PrecisionType.Float, WirePortDataType.FLOAT3, GeneratorUtils.ObjectScaleStr, value ); + return GeneratorUtils.ObjectScaleStr; + } + + public string GetWorldPos( bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + // overriding precision + var precision = PrecisionType.Float; + + string result = string.Empty; + if( GetCustomInterpolatedData( TemplateInfoOnSematics.WORLD_POSITION, WirePortDataType.FLOAT3, precision, ref result, useMasterNodeCategory, customCategory ) ) + { + return result; + } + else if( m_currentSRPType == TemplateSRPType.HD ) + { + if( GetCustomInterpolatedData( TemplateInfoOnSematics.RELATIVE_WORLD_POS, WirePortDataType.FLOAT3, precision, ref result, useMasterNodeCategory, customCategory ) ) + { + string worldPosVarName = GeneratorUtils.WorldPositionStr; + string relWorldPosConversion = string.Format( "GetAbsolutePositionWS( {0} )", result ); + m_currentDataCollector.AddLocalVariable( -1, precision, WirePortDataType.FLOAT3, worldPosVarName, relWorldPosConversion ); + return worldPosVarName; + } + } + + string varName = GeneratorUtils.WorldPositionStr;//UIUtils.GetInputValueFromType( SurfaceInputs.WORLD_POS ); + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + if( !m_availableVertData.ContainsKey( TemplateInfoOnSematics.POSITION ) ) + { + UIUtils.ShowMessage( "Attempting to access inexisting vertex position to calculate world pos" ); + return "half3(0,0,0)"; + } + + string vertexPos = m_availableVertData[ TemplateInfoOnSematics.POSITION ].VarName; + + string worldPosConversion = string.Empty; + + //Check if world pos already defined in the vertex body + if( !GetCustomInterpolatedData( TemplateInfoOnSematics.WORLD_POSITION, WirePortDataType.FLOAT3, precision, ref worldPosConversion, false, MasterNodePortCategory.Vertex ) ) + { + if( m_currentSRPType == TemplateSRPType.HD ) + { +#if UNITY_2018_3_OR_NEWER + worldPosConversion = string.Format( "GetAbsolutePositionWS( TransformObjectToWorld( ({0}).xyz ) )", vertexPos ); +#else + worldPosConversion = string.Format( "GetAbsolutePositionWS( mul( GetObjectToWorldMatrix(), {0}).xyz )", vertexPos ); +#endif + } + else if( m_currentSRPType == TemplateSRPType.Lightweight ) + { + worldPosConversion = string.Format( "mul(GetObjectToWorldMatrix(), {0}).xyz", vertexPos ); + } + else + { + worldPosConversion = string.Format( "mul(unity_ObjectToWorld, {0}).xyz", vertexPos ); + } + } + RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT3, precision, worldPosConversion, useMasterNodeCategory, customCategory ); + return varName; + } + + public string GetClipPosForValue( string customVertexPos, string outputId, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + string varName = GeneratorUtils.ClipPositionStr + outputId; + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + if( !m_availableVertData.ContainsKey( TemplateInfoOnSematics.POSITION ) ) + { + UIUtils.ShowMessage( "Attempting to access inexisting vertex position to calculate clip pos" ); + return "half4(0,0,0,0)"; + } + + string formatStr = string.Empty; + switch( m_currentSRPType ) + { + default: + case TemplateSRPType.BuiltIn: + formatStr = "UnityObjectToClipPos({0})"; + break; + case TemplateSRPType.HD: + formatStr = "TransformWorldToHClip( TransformObjectToWorld({0}))"; + break; + case TemplateSRPType.Lightweight: + formatStr = "TransformObjectToHClip(({0}).xyz)"; + break; + } + + string clipSpaceConversion = string.Format( formatStr, customVertexPos ); + RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT4, PrecisionType.Float, clipSpaceConversion, useMasterNodeCategory, customCategory ); + return varName; + } + + public string GetClipPos( bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + string varName = GeneratorUtils.ClipPositionStr;// "clipPos"; + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + if( !m_availableVertData.ContainsKey( TemplateInfoOnSematics.POSITION ) ) + { + UIUtils.ShowMessage( "Attempting to access inexisting vertex position to calculate clip pos" ); + return "half4(0,0,0,0)"; + } + + string vertexPos = m_availableVertData[ TemplateInfoOnSematics.POSITION ].VarName; + + string formatStr = string.Empty; + switch( m_currentSRPType ) + { + default: + case TemplateSRPType.BuiltIn: + formatStr = "UnityObjectToClipPos({0})"; + break; + case TemplateSRPType.HD: + formatStr = "TransformWorldToHClip( TransformObjectToWorld({0}))"; + break; + case TemplateSRPType.Lightweight: + formatStr = "TransformObjectToHClip(({0}).xyz)"; + break; + } + + string clipSpaceConversion = string.Format( formatStr, vertexPos ); + RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT4, PrecisionType.Float, clipSpaceConversion, useMasterNodeCategory, customCategory ); + return varName; + } + + public string GetScreenPosForValue( PrecisionType precision, string customVertexPos, string outputId, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + // overriding precision + precision = PrecisionType.Float; + + string varName = UIUtils.GetInputValueFromType( SurfaceInputs.SCREEN_POS ) + outputId; + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + string clipSpacePos = GetClipPosForValue( customVertexPos, outputId, false, MasterNodePortCategory.Vertex ); + string screenPosConversion = string.Empty; + if( m_currentSRPType == TemplateSRPType.HD ) + { + screenPosConversion = string.Format( "ComputeScreenPos( {0} , _ProjectionParams.x )", clipSpacePos ); + } + else + { + screenPosConversion = string.Format( "ComputeScreenPos({0})", clipSpacePos ); + } + RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT4, precision, screenPosConversion, useMasterNodeCategory, customCategory ); + return varName; + } + + public string GetScreenPos( PrecisionType precision, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + // overriding precision + precision = PrecisionType.Float; + + string result = string.Empty; + if( GetCustomInterpolatedData( TemplateInfoOnSematics.SCREEN_POSITION, WirePortDataType.FLOAT4, precision, ref result, useMasterNodeCategory, customCategory ) ) + { + return result; + } + + string varName = UIUtils.GetInputValueFromType( SurfaceInputs.SCREEN_POS ); + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + string clipSpacePos = GetClipPos( false, MasterNodePortCategory.Vertex ); + string screenPosConversion = string.Empty; + if( m_currentSRPType == TemplateSRPType.HD ) + { + screenPosConversion = string.Format( "ComputeScreenPos( {0} , _ProjectionParams.x )", clipSpacePos ); + } + else + { + screenPosConversion = string.Format( "ComputeScreenPos({0})", clipSpacePos ); + } + RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT4, precision, screenPosConversion, useMasterNodeCategory, customCategory ); + return varName; + } + + public string GetScreenPosNormalized( PrecisionType precision, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + string result = string.Empty; + if( GetCustomInterpolatedData( TemplateInfoOnSematics.SCREEN_POSITION_NORMALIZED, WirePortDataType.FLOAT4, precision, ref result, useMasterNodeCategory, customCategory ) ) + { + return result; + } + + string varName = GeneratorUtils.ScreenPositionNormalizedStr;// "norm" + UIUtils.GetInputValueFromType( SurfaceInputs.SCREEN_POS ); + string screenPos = GetScreenPos( precision, useMasterNodeCategory, customCategory ); + string clipPlaneTestOp = string.Format( "{0}.z = ( UNITY_NEAR_CLIP_VALUE >= 0 ) ? {0}.z : {0}.z * 0.5 + 0.5;", varName ); + m_currentDataCollector.AddLocalVariable( -1, precision, WirePortDataType.FLOAT4, varName, string.Format( GeneratorUtils.NormalizedScreenPosFormat, screenPos ) ); + m_currentDataCollector.AddLocalVariable( -1, clipPlaneTestOp ); + return varName; + } + + public string GetViewDir( bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment, NormalizeType normalizeType = NormalizeType.Regular ) + { + // overriding precision + var precision = PrecisionType.Float; + + string result = string.Empty; + if( GetCustomInterpolatedData( TemplateInfoOnSematics.WORLD_VIEW_DIR, WirePortDataType.FLOAT3, precision, ref result, useMasterNodeCategory, customCategory ) ) + return result; + + string varName = GeneratorUtils.WorldViewDirectionStr;//UIUtils.GetInputValueFromType( SurfaceInputs.VIEW_DIR ); + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + string worldPos = GetWorldPos(); + + string formatStr = string.Empty; + if( IsSRP ) + formatStr = "( _WorldSpaceCameraPos.xyz - {0} )"; + else + formatStr = "UnityWorldSpaceViewDir({0})"; + + string viewDir = string.Format( formatStr, worldPos ); + m_currentDataCollector.AddLocalVariable( -1, precision, WirePortDataType.FLOAT3, varName, viewDir ); + + switch( normalizeType ) + { + default: + case NormalizeType.Off: + break; + case NormalizeType.Regular: + m_currentDataCollector.AddLocalVariable( -1, varName + " = normalize(" + varName + ");" ); + break; + case NormalizeType.Safe: + m_currentDataCollector.AddLocalVariable( -1, varName + " = " + TemplateHelperFunctions.SafeNormalize( m_currentDataCollector, varName ) + ";" ); + break; + } + + + //RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT3, PrecisionType.Float, viewDir, useMasterNodeCategory, customCategory ); + return varName; + } + + public string GetTangentViewDir( PrecisionType precisionType, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment, NormalizeType normalizeType = NormalizeType.Regular ) + { + string varName = GeneratorUtils.TangentViewDirectionStr; + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + string tanToWorld0 = string.Empty; + string tanToWorld1 = string.Empty; + string tanToWorld2 = string.Empty; + + GetWorldTangentTf( precisionType, out tanToWorld0, out tanToWorld1, out tanToWorld2 ); + string viewDir = GetViewDir(); + string tanViewDir = string.Format( " {0} * {3}.x + {1} * {3}.y + {2} * {3}.z", tanToWorld0, tanToWorld1, tanToWorld2, viewDir ); + + m_currentDataCollector.AddLocalVariable( -1, precisionType, WirePortDataType.FLOAT3, varName, tanViewDir ); + switch( normalizeType ) + { + default: + case NormalizeType.Off: break; + case NormalizeType.Regular: + m_currentDataCollector.AddLocalVariable( -1, varName + " = normalize(" + varName + ");" ); + break; + case NormalizeType.Safe: + m_currentDataCollector.AddLocalVariable( -1, varName + " = " + TemplateHelperFunctions.SafeNormalize( m_currentDataCollector, varName ) + ";" ); + break; + } + + return varName; + } + + public void GetWorldTangentTf( PrecisionType precisionType, out string tanToWorld0, out string tanToWorld1, out string tanToWorld2, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + tanToWorld0 = "tanToWorld0"; + tanToWorld1 = "tanToWorld1"; + tanToWorld2 = "tanToWorld2"; + + if( HasCustomInterpolatedData( tanToWorld0, useMasterNodeCategory, customCategory ) || + HasCustomInterpolatedData( tanToWorld1, useMasterNodeCategory, customCategory ) || + HasCustomInterpolatedData( tanToWorld2, useMasterNodeCategory, customCategory ) ) + return; + + string worldTangent = GetWorldTangent( precisionType, useMasterNodeCategory, customCategory ); + string worldNormal = GetWorldNormal( precisionType, useMasterNodeCategory, customCategory ); + string worldBinormal = GetWorldBinormal( precisionType, useMasterNodeCategory, customCategory ); + + string tanToWorldVar0 = string.Format( "float3( {0}.x, {1}.x, {2}.x )", worldTangent, worldBinormal, worldNormal ); + string tanToWorldVar1 = string.Format( "float3( {0}.y, {1}.y, {2}.y )", worldTangent, worldBinormal, worldNormal ); + string tanToWorldVar2 = string.Format( "float3( {0}.z, {1}.z, {2}.z )", worldTangent, worldBinormal, worldNormal ); + + if( customCategory == MasterNodePortCategory.Vertex ) + { + RegisterCustomInterpolatedData( tanToWorld0, WirePortDataType.FLOAT3, precisionType, tanToWorldVar0, useMasterNodeCategory, customCategory ); + RegisterCustomInterpolatedData( tanToWorld1, WirePortDataType.FLOAT3, precisionType, tanToWorldVar1, useMasterNodeCategory, customCategory ); + RegisterCustomInterpolatedData( tanToWorld2, WirePortDataType.FLOAT3, precisionType, tanToWorldVar2, useMasterNodeCategory, customCategory ); + } + else + { + m_currentDataCollector.AddLocalVariable( -1, precisionType, WirePortDataType.FLOAT3, tanToWorld0, tanToWorldVar0 ); + m_currentDataCollector.AddLocalVariable( -1, precisionType, WirePortDataType.FLOAT3, tanToWorld1, tanToWorldVar1 ); + m_currentDataCollector.AddLocalVariable( -1, precisionType, WirePortDataType.FLOAT3, tanToWorld2, tanToWorldVar2 ); + } + } + + public string GetTangentToWorldMatrixFast( PrecisionType precisionType, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + string worldTangent = GetWorldTangent( precisionType ); + string worldNormal = GetWorldNormal( precisionType ); + string worldBinormal = GetWorldBinormal( precisionType ); + + string varName = GeneratorUtils.TangentToWorldFastStr; + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + string result = string.Format( "float3x3({0}.x,{1}.x,{2}.x,{0}.y,{1}.y,{2}.y,{0}.z,{1}.z,{2}.z)", worldTangent, worldBinormal, worldNormal ); + m_currentDataCollector.AddLocalVariable( -1, precisionType, WirePortDataType.FLOAT3x3, GeneratorUtils.TangentToWorldFastStr, result ); + return GeneratorUtils.TangentToWorldFastStr; + } + + public string GetTangentToWorldMatrixPrecise( PrecisionType precisionType, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + string worldToTangent = GetWorldToTangentMatrix( precisionType, useMasterNodeCategory, customCategory ); + GeneratorUtils.Add3x3InverseFunction( ref m_currentDataCollector, UIUtils.PrecisionWirePortToCgType( precisionType, WirePortDataType.FLOAT ) ); + m_currentDataCollector.AddLocalVariable( -1, precisionType, WirePortDataType.FLOAT3x3, GeneratorUtils.TangentToWorldPreciseStr, string.Format( GeneratorUtils.Inverse3x3Header, worldToTangent ) ); + return GeneratorUtils.TangentToWorldPreciseStr; + } + + public string GetWorldToTangentMatrix( PrecisionType precisionType, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + string worldTangent = GetWorldTangent( precisionType ); + string worldNormal = GetWorldNormal( precisionType ); + string worldBinormal = GetWorldBinormal( precisionType ); + + string varName = GeneratorUtils.WorldToTangentStr;// "worldToTanMat"; + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + string worldTanMat = string.Format( "float3x3({0},{1},{2})", worldTangent, worldBinormal, worldNormal ); + + m_currentDataCollector.AddLocalVariable( -1, precisionType, WirePortDataType.FLOAT3x3, varName, worldTanMat ); + return varName; + } + + public string GetObjectToViewPos( PrecisionType precision, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + // overriding precision + precision = PrecisionType.Float; + + string varName = "objectToViewPos"; + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + string vertexPos = GetVertexPosition( WirePortDataType.FLOAT3, precision, false, MasterNodePortCategory.Vertex ); + + string formatStr = string.Empty; + if( IsSRP ) + formatStr = "TransformWorldToView(TransformObjectToWorld({0}))"; + else + formatStr = "UnityObjectToViewPos({0})"; + + string objectToViewPosValue = string.Format( formatStr, vertexPos ); + RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT3, precision, objectToViewPosValue, useMasterNodeCategory, customCategory ); + return varName; + } + + public string GetEyeDepth( PrecisionType precision, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment, int viewSpace = 0 ) + { + // overriding precision + precision = PrecisionType.Float; + + string varName = "eyeDepth"; + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + string objectToView = GetObjectToViewPos( precision, false, MasterNodePortCategory.Vertex ); + string eyeDepthValue = string.Format( "-{0}.z", objectToView ); + if( viewSpace == 1 ) + { + eyeDepthValue += " * _ProjectionParams.w"; + } + + RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT, precision, eyeDepthValue, useMasterNodeCategory, customCategory ); + return varName; + } + + public string GetObjectSpaceLightDir( PrecisionType precisionType, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + if( !IsSRP ) + { + m_currentDataCollector.AddToIncludes( -1, Constants.UnityLightingLib ); + m_currentDataCollector.AddToIncludes( -1, Constants.UnityAutoLightLib ); + } + + string varName = "objectSpaceLightDir"; + + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + string vertexPos = GetVertexPosition( WirePortDataType.FLOAT4, precisionType, false, MasterNodePortCategory.Vertex ); + + string objectSpaceLightDir = string.Empty; + switch( m_currentSRPType ) + { + default: + case TemplateSRPType.BuiltIn: + objectSpaceLightDir = string.Format( "ObjSpaceLightDir({0})", vertexPos ); + break; + case TemplateSRPType.HD: + string worldSpaceLightDir = GetWorldSpaceLightDir( precisionType, useMasterNodeCategory, customCategory ); + objectSpaceLightDir = string.Format( "mul( GetWorldToObjectMatrix(), {0} ).xyz", worldSpaceLightDir ); + break; + case TemplateSRPType.Lightweight: + objectSpaceLightDir = "mul( GetWorldToObjectMatrix(), _MainLightPosition ).xyz"; + break; + } + + RegisterCustomInterpolatedData( varName, WirePortDataType.FLOAT3, precisionType, objectSpaceLightDir, useMasterNodeCategory, customCategory ); + return varName; + } + + public string GetWorldSpaceLightDir( PrecisionType precision, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + if( !IsSRP ) + { + m_currentDataCollector.AddToIncludes( -1, Constants.UnityLightingLib ); + m_currentDataCollector.AddToIncludes( -1, Constants.UnityAutoLightLib ); + AddLateDirective( AdditionalLineType.Custom, "//This is a late directive" ); + } + else + { + + string lightVar; + if( m_currentSRPType == TemplateSRPType.HD ) + { + AddHDLightInfo(); + lightVar = "-" + string.Format( TemplateHelperFunctions.HDLightInfoFormat, "0", "forward" ); + } + else + { + lightVar = "_MainLightPosition.xyz"; + } + return m_currentDataCollector.SafeNormalizeLightDir ? string.Format( "SafeNormalize({0})", lightVar ) : lightVar; + } + + string varName = "worldSpaceLightDir"; + if( HasCustomInterpolatedData( varName, useMasterNodeCategory, customCategory ) ) + return varName; + + string worldPos = GetWorldPos( useMasterNodeCategory, customCategory ); + string worldSpaceLightDir = string.Format( "UnityWorldSpaceLightDir({0})", worldPos ); + if( m_currentDataCollector.SafeNormalizeLightDir ) + { + if( IsSRP ) + { + worldSpaceLightDir = string.Format( "SafeNormalize{0})", worldSpaceLightDir ); + } + else + { + m_currentDataCollector.AddToIncludes( -1, Constants.UnityBRDFLib ); + worldSpaceLightDir = string.Format( "Unity_SafeNormalize({0})", worldSpaceLightDir ); + } + } + + m_currentDataCollector.AddLocalVariable( -1, precision, WirePortDataType.FLOAT3, varName, worldSpaceLightDir ); + return varName; + } + + public void RegisterCustomInterpolatedData( string name, WirePortDataType dataType, PrecisionType precision, string vertexInstruction, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + bool addLocalVariable = !name.Equals( vertexInstruction ); + + MasterNodePortCategory category = useMasterNodeCategory ? m_currentDataCollector.PortCategory : customCategory; + + if( !m_customInterpolatedData.ContainsKey( name ) ) + { + m_customInterpolatedData.Add( name, new TemplateCustomData( name, dataType ) ); + } + + if( !m_customInterpolatedData[ name ].IsVertex ) + { + m_customInterpolatedData[ name ].IsVertex = true; + if( addLocalVariable ) + m_currentDataCollector.AddToVertexLocalVariables( -1, precision, dataType, name, vertexInstruction ); + } + + if( category == MasterNodePortCategory.Fragment ) + { + if( !m_customInterpolatedData[ name ].IsFragment ) + { + m_customInterpolatedData[ name ].IsFragment = true; + TemplateVertexData interpData = RequestNewInterpolator( dataType, false ); + if( interpData == null ) + { + Debug.LogErrorFormat( "Could not assign interpolator of type {0} to variable {1}", dataType, name ); + return; + } + + m_currentDataCollector.AddToVertexLocalVariables( -1, m_currentTemplateData.VertexFunctionData.OutVarName + "." + interpData.VarNameWithSwizzle, name ); + m_currentDataCollector.AddToLocalVariables( -1, precision, dataType, name, m_currentTemplateData.FragmentFunctionData.InVarName + "." + interpData.VarNameWithSwizzle ); + } + } + } + + public bool HasCustomInterpolatedData( string name, bool useMasterNodeCategory = true, MasterNodePortCategory customCategory = MasterNodePortCategory.Fragment ) + { + if( m_customInterpolatedData.ContainsKey( name ) ) + { + MasterNodePortCategory category = useMasterNodeCategory ? m_currentDataCollector.PortCategory : customCategory; + return ( category == MasterNodePortCategory.Fragment ) ? m_customInterpolatedData[ name ].IsFragment : m_customInterpolatedData[ name ].IsVertex; + } + return false; + } + + public bool HasFragmentInputParams + { + get + { + if( m_fragmentInputParams != null ) + return m_fragmentInputParams.Count > 0; + + return false; + } + } + + public string FragInputParamsStr + { + get + { + string value = string.Empty; + if( m_fragmentInputParams != null && m_fragmentInputParams.Count > 0 ) + { + int count = m_fragmentInputParams.Count; + if( count > 0 ) + { + value = ", "; + foreach( KeyValuePair<TemplateSemantics, TemplateInputParameters> kvp in m_fragmentInputParams ) + { + value += kvp.Value.Declaration; + + if( --count > 0 ) + { + value += " , "; + } + } + } + } + return value; + } + } + + public string VertexInputParamsStr + { + get + { + string value = string.Empty; + if( m_vertexInputParams != null && m_vertexInputParams.Count > 0 ) + { + int count = m_vertexInputParams.Count; + if( count > 0 ) + { + value = ", "; + foreach( KeyValuePair<TemplateSemantics, TemplateInputParameters> kvp in m_vertexInputParams ) + { + value += kvp.Value.Declaration; + + if( --count > 0 ) + { + value += " , "; + } + } + } + } + return value; + } + } + + public void Destroy() + { + m_currentTemplate = null; + + m_currentTemplateData = null; + + m_currentDataCollector = null; + + if( m_fullSrpBatcherPropertiesList != null ) + { + m_fullSrpBatcherPropertiesList.Clear(); + m_fullSrpBatcherPropertiesList = null; + } + + if( m_srpBatcherPropertiesList != null ) + { + m_srpBatcherPropertiesList.Clear(); + m_srpBatcherPropertiesList = null; + } + + if( m_srpBatcherPropertiesDict != null ) + { + m_srpBatcherPropertiesDict.Clear(); + m_srpBatcherPropertiesDict = null; + } + + if( m_lateDirectivesList != null ) + { + m_lateDirectivesList.Clear(); + m_lateDirectivesList = null; + } + + if( m_lateDirectivesDict != null ) + { + m_lateDirectivesDict.Clear(); + m_lateDirectivesDict = null; + } + + if( m_registeredVertexData != null ) + { + m_registeredVertexData.Clear(); + m_registeredVertexData = null; + } + + if( m_vertexInputParams != null ) + { + m_vertexInputParams.Clear(); + m_vertexInputParams = null; + } + + if( m_fragmentInputParams != null ) + { + m_fragmentInputParams.Clear(); + m_fragmentInputParams = null; + } + + if( m_vertexDataDict != null ) + { + m_vertexDataDict.Clear(); + m_vertexDataDict = null; + } + + if( m_interpolatorData != null ) + { + m_interpolatorData.Destroy(); + m_interpolatorData = null; + } + + if( m_availableFragData != null ) + { + m_availableFragData.Clear(); + m_availableFragData = null; + } + + if( m_availableVertData != null ) + { + m_availableVertData.Clear(); + m_availableVertData = null; + } + + if( m_customInterpolatedData != null ) + { + m_customInterpolatedData.Clear(); + m_customInterpolatedData = null; + } + + if( m_specialVertexLocalVars != null ) + { + m_specialVertexLocalVars.Clear(); + m_specialVertexLocalVars = null; + } + + if( m_specialFragmentLocalVars != null ) + { + m_specialFragmentLocalVars.Clear(); + m_specialFragmentLocalVars = null; + } + } + + public void BuildCBuffer( int nodeId ) + { + m_fullSrpBatcherPropertiesList.Clear(); + if( m_srpBatcherPropertiesList.Count > 0 ) + { + var regex = new Regex( @"(\d)\s+\b" ); + m_srpBatcherPropertiesList.Sort( ( a, b ) => + { + var matchA = regex.Match( a.PropertyName ); + int sizeA = 0; + if( matchA.Groups.Count > 1 && matchA.Groups[ 1 ].Value.Length > 0 ) + sizeA = Convert.ToInt32( matchA.Groups[ 1 ].Value, System.Globalization.CultureInfo.InvariantCulture ); + + var matchB = regex.Match( b.PropertyName ); + int sizeB = 0; + if( matchB.Groups.Count > 1 && matchB.Groups[ 1 ].Value.Length > 0 ) + sizeB = Convert.ToInt32( matchB.Groups[ 1 ].Value, System.Globalization.CultureInfo.InvariantCulture ); + + return sizeB.CompareTo( sizeA ); + } ); + + m_fullSrpBatcherPropertiesList.Insert(0, new PropertyDataCollector( nodeId, IOUtils.SRPCBufferPropertiesBegin )); + m_fullSrpBatcherPropertiesList.AddRange( m_srpBatcherPropertiesList ); + m_fullSrpBatcherPropertiesList.Add( new PropertyDataCollector( nodeId, IOUtils.SRPCBufferPropertiesEnd ) ); + } + } + + + public void DumpSRPBatcher() + { + for( int i = 0; i < m_srpBatcherPropertiesList.Count; i++ ) + { + Debug.Log( i + "::" + m_srpBatcherPropertiesList[ i ].PropertyName ); + } + } + + public const string GlobalMaxInterpolatorReachedMsg = "Maximum amount of interpolators reached!\nPlease consider optmizing your shader!"; + public const string MaxInterpolatorSMReachedMsg = "Maximum amount of interpolators reached for current shader model on pass {0}! Please consider increasing the shader model to {1}!"; + public void CheckInterpolatorOverflow( string currShaderModel, string passName ) + { + int maxInterpolatorAmount = TemplateHelperFunctions.AvailableInterpolators[ currShaderModel ]; + int currInterpolatorAmount = 1 + TemplateHelperFunctions.SemanticToInt[ InterpData.AvailableInterpolators[ InterpData.AvailableInterpolators.Count - 1 ].Semantic ]; + if( currInterpolatorAmount > maxInterpolatorAmount ) + { + string shaderModel = string.Empty; + if( TemplateHelperFunctions.GetShaderModelForInterpolatorAmount( currInterpolatorAmount, ref shaderModel ) ) + { + UIUtils.ShowMessage( string.Format( MaxInterpolatorSMReachedMsg, passName, shaderModel ), MessageSeverity.Error ); + } + else + { + UIUtils.ShowMessage( GlobalMaxInterpolatorReachedMsg, MessageSeverity.Error ); + } + } + } + + public Dictionary<TemplateSemantics, TemplateInputParameters> FragInputParameters { get { return m_fragmentInputParams; } } + + public bool HasVertexInputParams + { + get + { + if( m_vertexInputParams != null ) + return m_vertexInputParams.Count > 0; + + return false; + } + } + + public Dictionary<TemplateSemantics, TemplateInputParameters> VertexInputParameters { get { return m_vertexInputParams; } } + public TemplateData CurrentTemplateData { get { return m_currentTemplateData; } } + public int MultipassSubshaderIdx { get { return m_multipassSubshaderIdx; } } + public int MultipassPassIdx { get { return m_multipassPassIdx; } } + public TemplateSRPType CurrentSRPType { get { return m_currentSRPType; } set { m_currentSRPType = value; } } + public bool IsHDRP { get { return m_currentSRPType == TemplateSRPType.HD; } } + public bool IsLWRP { get { return m_currentSRPType == TemplateSRPType.Lightweight; } } + public bool IsSRP { get { return ( m_currentSRPType == TemplateSRPType.Lightweight || m_currentSRPType == TemplateSRPType.HD ); } } + public TemplateInterpData InterpData { get { return m_interpolatorData; } } + public List<PropertyDataCollector> LateDirectivesList { get { return m_lateDirectivesList; } } + public List<PropertyDataCollector> SrpBatcherPropertiesList { get { return m_srpBatcherPropertiesList; } } + public List<PropertyDataCollector> FullSrpBatcherPropertiesList { get { return m_fullSrpBatcherPropertiesList; } } + public Dictionary<TemplateSemantics, TemplateVertexData> VertexDataDict { get { return m_vertexDataDict; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDataCollector.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDataCollector.cs.meta new file mode 100644 index 00000000..9386f5fa --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDataCollector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c757602c408f7354b96c2a5eb21662a4 +timeCreated: 1495710491 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDataParent.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDataParent.cs new file mode 100644 index 00000000..b7c3fd02 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDataParent.cs @@ -0,0 +1,217 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace AmplifyShaderEditor +{ + public enum TemplateDataType + { + LegacySinglePass, + MultiPass + } + + [Serializable] + public class TemplateIncludePragmaContainter + { + [SerializeField] + private int m_nativeTopIndex = -1; + + [SerializeField] + private List<string> m_nativeDirectivesList = new List<string>(); + + [SerializeField] + private List<string> m_includesList = new List<string>(); + private Dictionary<string,string> m_includesDict = new Dictionary<string,string>(); + + [SerializeField] + private List<string> m_pragmasList = new List<string>(); + private Dictionary<string, string> m_pragmasDict = new Dictionary<string, string>(); + + [SerializeField] + private List<string> m_definesList = new List<string>(); + private Dictionary<string, string> m_definesDict = new Dictionary<string, string>(); + + public void RefreshIncludesList() + { + if ( m_includesDict.Count != m_includesList.Count ) + { + m_includesDict.Clear(); + int count = m_includesList.Count; + for ( int i = 0; i < count; i++ ) + { + m_includesDict.Add( m_includesList[ i ], m_includesList[ i ] ); + } + } + } + + public void RefreshPragmasList() + { + if ( m_pragmasDict.Count != m_pragmasList.Count ) + { + m_pragmasDict.Clear(); + int count = m_pragmasList.Count; + for ( int i = 0; i < count; i++ ) + { + m_pragmasDict.Add( m_pragmasList[ i ], m_pragmasList[ i ] ); + } + } + } + + + public void RefreshDefinesList() + { + if ( m_definesDict.Count != m_definesList.Count ) + { + m_definesDict.Clear(); + int count = m_definesList.Count; + for ( int i = 0; i < count; i++ ) + { + m_definesDict.Add( m_definesList[ i ], m_definesList[ i ] ); + } + } + } + + public bool HasInclude( string include ) + { + RefreshIncludesList(); + return m_includesDict.ContainsKey( include ); + } + + public bool HasPragma( string pragma ) + { + RefreshPragmasList(); + return m_pragmasDict.ContainsKey( pragma ); + } + + public bool HasDefine( string pragma ) + { + RefreshDefinesList(); + return m_definesDict.ContainsKey( pragma ); + } + + public void AddInclude( string include ) + { + RefreshIncludesList(); + if ( !m_includesDict.ContainsKey( include ) ) + { + m_includesList.Add( include ); + m_includesDict.Add( include, include ); + } + } + + public void AddPragma( string pragma ) + { + RefreshPragmasList(); + if ( !m_pragmasDict.ContainsKey( pragma ) ) + { + m_pragmasList.Add( pragma ); + m_pragmasDict.Add( pragma, pragma ); + } + } + + public void AddDefine( string define ) + { + RefreshDefinesList(); + if ( !m_definesDict.ContainsKey( define ) ) + { + m_definesList.Add( define ); + m_definesDict.Add( define, define ); + } + } + + public void AddNativeDirective( string native, int topIndex ) + { + m_nativeTopIndex = topIndex; + m_nativeDirectivesList.Add( native ); + } + + public void Destroy() + { + m_nativeDirectivesList.Clear(); + m_nativeDirectivesList = null; + + + m_includesList.Clear(); + m_includesDict.Clear(); + m_includesList = null; + m_includesDict = null; + + m_pragmasList.Clear(); + m_pragmasDict.Clear(); + m_pragmasList = null; + m_pragmasDict = null; + + m_definesList.Clear(); + m_definesDict.Clear(); + m_definesList = null; + m_definesDict = null; + } + + public List<string> IncludesList { get { return m_includesList; } } + public List<string> PragmasList { get { return m_pragmasList; } } + public List<string> DefinesList { get { return m_definesList; } } + public List<string> NativeDirectivesList { get { return m_nativeDirectivesList; } } + public int NativeTopIndex { get { return m_nativeTopIndex; } } + + } + + [Serializable] + public class TemplateInfoContainer + { + public string Id = string.Empty; + public string Data = string.Empty; + public int Index = -1; + public bool IsValid { get { return Index > -1; } } + public void Reset() + { + Id = string.Empty; + Data = string.Empty; + Index = -1; + } + } + + [Serializable] + public class TemplateDataParent : ScriptableObject + { + [SerializeField] + protected TemplateDataType m_templateType; + + [SerializeField] + protected string m_name; + + [SerializeField] + protected string m_guid; + + [SerializeField] + protected int m_orderId; + + [SerializeField] + protected string m_defaultShaderName = string.Empty; + + [SerializeField] + protected bool m_isValid = true; + + [SerializeField] + protected bool m_communityTemplate = false; + + public virtual void Destroy() { } + public virtual bool Reload() { return true; } + public string Name + { + get { return m_name; } + set + { + m_name = value.StartsWith( "Hidden/" ) ? value.Replace( "Hidden/", string.Empty ) : value; + } + } + public string GUID { get { return m_guid; } set { m_guid = value; } } + public int OrderId { get { return m_orderId; } set { m_orderId = value; } } + public string DefaultShaderName { get { return m_defaultShaderName; } set { m_defaultShaderName = value; } } + public bool IsValid { get { return m_isValid; } } + public TemplateDataType TemplateType { get { return m_templateType; } } + public virtual void Init( string name, string guid, bool isCommunity ) { m_communityTemplate = isCommunity; } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDataParent.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDataParent.cs.meta new file mode 100644 index 00000000..49aee2ac --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDataParent.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4e8f3788c7c239042b3cc3d086311227 +timeCreated: 1518720013 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDepthModule.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDepthModule.cs new file mode 100644 index 00000000..0ce4a1c1 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDepthModule.cs @@ -0,0 +1,391 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace AmplifyShaderEditor +{ + [Serializable] + public sealed class TemplateDepthModule : TemplateModuleParent + { + private const string ZWriteFormatter = "ZWrite {0}\n"; + private const string ZTestFormatter = "ZTest {0}\n"; + + [SerializeField] + private bool m_validZTest = false; + + [SerializeField] + private InlineProperty m_zTestMode = new InlineProperty( 0 ); + + [SerializeField] + private bool m_validZWrite = false; + + [SerializeField] + private InlineProperty m_zWriteMode = new InlineProperty( 0 ); + + [SerializeField] + private InlineProperty m_offsetFactor = new InlineProperty( 0 ); + + [SerializeField] + private InlineProperty m_offsetUnits = new InlineProperty( 0 ); + + [SerializeField] + private bool m_offsetEnabled = false; + + [SerializeField] + private bool m_validOffset = false; + + public TemplateDepthModule() : base( "Depth" ) { } + + public void CopyFrom( TemplateDepthModule other, bool allData ) + { + if( allData ) + { + m_independentModule = other.IndependentModule; + m_validZTest = other.ValidZTest; + m_validZWrite = other.ValidZWrite; + m_validOffset = other.ValidOffset; + } + + m_zTestMode.CopyFrom( other.ZTestMode ); + m_zWriteMode.CopyFrom( other.ZWriteMode ); + m_offsetFactor.CopyFrom( other.OffsetFactor ); + m_offsetUnits.CopyFrom( other.OffsetUnits ); + m_offsetEnabled = other.OffsetEnabled; + } + + public void ConfigureFromTemplateData( TemplateDepthData depthData ) + { + m_independentModule = depthData.IndependentModule; + if( depthData.ValidZTest && m_validZTest != depthData.ValidZTest ) + { + if( string.IsNullOrEmpty( depthData.ZTestInlineValue ) ) + { + m_zTestMode.IntValue = ZBufferOpHelper.ZTestModeDict[ depthData.ZTestModeValue ]; + m_zTestMode.ResetProperty(); + } + else + { + m_zTestMode.SetInlineByName( depthData.ZTestInlineValue ); + } + } + + + + if( depthData.ValidZWrite && m_validZWrite != depthData.ValidZWrite ) + { + if( string.IsNullOrEmpty( depthData.ZWriteInlineValue ) ) + { + m_zWriteMode.IntValue = ZBufferOpHelper.ZWriteModeDict[ depthData.ZWriteModeValue ]; + m_zWriteMode.ResetProperty(); + } + else + { + m_zWriteMode.SetInlineByName( depthData.ZWriteInlineValue ); + } + } + + if( depthData.ValidOffset && m_validOffset != depthData.ValidOffset ) + { + if( string.IsNullOrEmpty( depthData.OffsetFactorInlineValue ) ) + { + m_offsetFactor.FloatValue = depthData.OffsetFactor; + m_offsetFactor.ResetProperty(); + } + else + { + m_offsetFactor.SetInlineByName( depthData.OffsetFactorInlineValue ); + } + + if( string.IsNullOrEmpty( depthData.OffsetUnitsInlineValue ) ) + { + m_offsetUnits.FloatValue = depthData.OffsetUnits; + m_offsetUnits.ResetProperty(); + } + else + { + m_offsetUnits.SetInlineByName( depthData.OffsetUnitsInlineValue ); + } + m_offsetEnabled = depthData.ValidOffset; + } + + m_validZTest = depthData.ValidZTest; + m_validZWrite = depthData.ValidZWrite; + m_validOffset = depthData.ValidOffset; + m_validData = m_validZTest || m_validZWrite || m_validOffset; + } + + public override void ShowUnreadableDataMessage( ParentNode owner ) + { + bool foldoutValue = owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedDepth; + NodeUtils.DrawPropertyGroup( ref foldoutValue, ZBufferOpHelper.DepthParametersStr, base.ShowUnreadableDataMessage ); + owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedDepth = foldoutValue; + } + + public override void Draw( UndoParentNode owner, bool style = true ) + { + bool foldout = owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedDepth; + if( style ) + { + NodeUtils.DrawPropertyGroup( ref foldout, ZBufferOpHelper.DepthParametersStr, () => + { + EditorGUI.indentLevel++; + DrawBlock( owner ); + EditorGUI.indentLevel--; + } ); + } + else + { + NodeUtils.DrawNestedPropertyGroup( ref foldout, ZBufferOpHelper.DepthParametersStr, () => + { + DrawBlock( owner ); + } ); + } + owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedDepth = foldout; + } + + void DrawBlock( UndoParentNode owner ) + { + EditorGUI.BeginChangeCheck(); + Color cachedColor = GUI.color; + GUI.color = new Color( cachedColor.r, cachedColor.g, cachedColor.b, ( EditorGUIUtility.isProSkin ? 0.5f : 0.25f ) ); + //EditorGUILayout.BeginVertical( UIUtils.MenuItemBackgroundStyle ); + GUI.color = cachedColor; + + EditorGUILayout.Separator(); + + if( m_validZWrite ) + m_zWriteMode.EnumTypePopup( ref owner, ZBufferOpHelper.ZWriteModeStr, ZBufferOpHelper.ZWriteModeValues ); + + if( m_validZTest ) + m_zTestMode.EnumTypePopup( ref owner, ZBufferOpHelper.ZTestModeStr, ZBufferOpHelper.ZTestModeLabels ); + + + if( m_validOffset ) + { + m_offsetEnabled = owner.EditorGUILayoutToggle( ZBufferOpHelper.OffsetStr, m_offsetEnabled ); + if( m_offsetEnabled ) + { + EditorGUI.indentLevel++; + m_offsetFactor.FloatField( ref owner, ZBufferOpHelper.OffsetFactorStr ); + m_offsetUnits.FloatField( ref owner, ZBufferOpHelper.OffsetUnitsStr ); + EditorGUI.indentLevel--; + } + } + EditorGUILayout.Separator(); + + //EditorGUILayout.EndVertical(); + if( EditorGUI.EndChangeCheck() ) + { + m_isDirty = true; + } + } + + public void ReadZWriteFromString( ref uint index, ref string[] nodeParams ) + { + bool validDataOnMeta = m_validZWrite; + if( UIUtils.CurrentShaderVersion() > TemplatesManager.MPShaderVersion ) + { + validDataOnMeta = Convert.ToBoolean( nodeParams[ index++ ] ); + } + + if( validDataOnMeta ) + { + if( UIUtils.CurrentShaderVersion() < 15304 ) + { + m_zWriteMode.IntValue = Convert.ToInt32( nodeParams[ index++ ] ); + } + else + { + m_zWriteMode.ReadFromString( ref index, ref nodeParams ); + } + } + } + + public void ReadZTestFromString( ref uint index, ref string[] nodeParams ) + { + bool validDataOnMeta = m_validZTest; + if( UIUtils.CurrentShaderVersion() > TemplatesManager.MPShaderVersion ) + { + validDataOnMeta = Convert.ToBoolean( nodeParams[ index++ ] ); + } + + if( validDataOnMeta ) + { + if( UIUtils.CurrentShaderVersion() < 15304 ) + { + m_zTestMode.IntValue = Convert.ToInt32( nodeParams[ index++ ] ); + } + else + { + m_zTestMode.ReadFromString( ref index, ref nodeParams ); + } + } + } + + public void ReadOffsetFromString( ref uint index, ref string[] nodeParams ) + { + bool validDataOnMeta = m_validOffset; + if( UIUtils.CurrentShaderVersion() > TemplatesManager.MPShaderVersion ) + { + validDataOnMeta = Convert.ToBoolean( nodeParams[ index++ ] ); + } + + if( validDataOnMeta ) + { + m_offsetEnabled = Convert.ToBoolean( nodeParams[ index++ ] ); + if( UIUtils.CurrentShaderVersion() < 15304 ) + { + m_offsetFactor.FloatValue = Convert.ToSingle( nodeParams[ index++ ] ); + m_offsetUnits.FloatValue = Convert.ToSingle( nodeParams[ index++ ] ); + } + else + { + m_offsetFactor.ReadFromString( ref index, ref nodeParams, false ); + m_offsetUnits.ReadFromString( ref index, ref nodeParams, false ); + } + } + } + + public override void ReadFromString( ref uint index, ref string[] nodeParams ) + { + ReadZWriteFromString( ref index, ref nodeParams ); + ReadZTestFromString( ref index, ref nodeParams ); + ReadOffsetFromString( ref index, ref nodeParams ); + } + + public void WriteZWriteToString( ref string nodeInfo ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_validZWrite ); + if( m_validZWrite ) + m_zWriteMode.WriteToString( ref nodeInfo ); + } + + public void WriteZTestToString( ref string nodeInfo ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_validZTest ); + if( m_validZTest ) + m_zTestMode.WriteToString( ref nodeInfo ); + } + + public void WriteOffsetToString( ref string nodeInfo ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_validOffset ); + if( m_validOffset ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_offsetEnabled ); + m_offsetFactor.WriteToString( ref nodeInfo ); + m_offsetUnits.WriteToString( ref nodeInfo ); + } + } + + public override void WriteToString( ref string nodeInfo ) + { + WriteZWriteToString( ref nodeInfo ); + WriteZTestToString( ref nodeInfo ); + WriteOffsetToString( ref nodeInfo ); + } + + public bool IsActive { get { return ( m_zTestMode.IsValid || m_zTestMode.IntValue != 0 ) || ( m_zWriteMode.IsValid || m_zWriteMode.IntValue != 0 ) || m_offsetEnabled; } } + public string CurrentZWriteMode + { + get + { + if( m_zWriteMode.IsValid ) + { + return string.Format( ZWriteFormatter, m_zWriteMode.GetValueOrProperty() ); ; + } + + int finalZWrite = ( m_zWriteMode.IntValue == 0 ) ? 1 : m_zWriteMode.IntValue; + return string.Format( ZWriteFormatter, ZBufferOpHelper.ZWriteModeValues[ finalZWrite ] ); ; + } + } + public string CurrentZTestMode + { + get + { + if( m_zTestMode.IsValid ) + return string.Format( ZTestFormatter, m_zTestMode.GetValueOrProperty() ); + + int finalZTestMode = ( m_zTestMode.IntValue == 0 ) ? 3 : m_zTestMode.IntValue; + return string.Format( ZTestFormatter, ZBufferOpHelper.ZTestModeValues[ finalZTestMode ] ); + } + } + + public string CurrentOffset + { + get + { + if( m_offsetEnabled ) + return "Offset " + m_offsetFactor.GetValueOrProperty() + " , " + m_offsetUnits.GetValueOrProperty() + "\n"; + else + return "Offset 0,0\n"; + } + } + + public bool ValidZTest { get { return m_validZTest; } } + public bool ValidZWrite { get { return m_validZWrite; } } + public bool ValidOffset { get { return m_validOffset; } } + public InlineProperty ZTestMode { get { return m_zTestMode; } } + public InlineProperty ZWriteMode { get { return m_zWriteMode; } } + public InlineProperty OffsetFactor { get { return m_offsetFactor; } } + public InlineProperty OffsetUnits { get { return m_offsetUnits; } } + public bool OffsetEnabled { get { return m_offsetEnabled; } } + + + public ZTestMode ZTestModeValue + { + set + { + m_zTestMode.IntValue = ZBufferOpHelper.ZTestModeDict[ value ]; + m_zTestMode.Active = false; + } + get + { + return (ZTestMode)( m_zTestMode.IntValue - 1 ); + } + } + public ZWriteMode ZWriteModeValue + { + set + { + m_zWriteMode.IntValue = ZBufferOpHelper.ZWriteModeDict[ value ]; + m_zWriteMode.Active = false; + } + get + { + return (ZWriteMode)( m_zWriteMode.IntValue - 1 ); + } + } + public float OffsetFactorValue + { + set + { + m_offsetEnabled = true; + m_offsetFactor.FloatValue = value; + m_offsetFactor.Active = false; + } + get + { + return m_offsetFactor.FloatValue; + } + } + + public float OffsetUnitsValue + { + set + { + m_offsetEnabled = true; + m_offsetUnits.FloatValue = value; + m_offsetUnits.Active = false; + } + get + { + return m_offsetUnits.FloatValue; + } + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDepthModule.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDepthModule.cs.meta new file mode 100644 index 00000000..a559fe74 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateDepthModule.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 91bbf209a618780459e775d6816a4b06 +timeCreated: 1513873547 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateFragmentDataNode.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateFragmentDataNode.cs new file mode 100644 index 00000000..68d5f9f3 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateFragmentDataNode.cs @@ -0,0 +1,274 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> +using UnityEngine; +using UnityEditor; +using System; +using System.Collections.Generic; + +namespace AmplifyShaderEditor +{ + [Serializable] + [NodeAttributes( "Template Fragment Data", "Surface Data", "Select and use available interpolated fragment data from the template" )] + public class TemplateFragmentDataNode : TemplateNodeParent + { + private List<TemplateVertexData> m_interpolatorData = null; + + [SerializeField] + private int m_currentDataIdx = -1; + + [SerializeField] + private string m_dataName = string.Empty; + [SerializeField] + private string m_inVarName = string.Empty; + + private string[] m_dataLabels = null; + + private bool m_fetchDataId = false; + private UpperLeftWidgetHelper m_upperLeftWidgetHelper = new UpperLeftWidgetHelper(); + + void FetchDataId() + { + if( m_interpolatorData != null ) + { + m_currentDataIdx = 0; + int count = m_interpolatorData.Count; + m_dataLabels = new string[ count ]; + for( int i = 0; i < count; i++ ) + { + m_dataLabels[ i ] = m_interpolatorData[ i ].VarName; + if( m_interpolatorData[ i ].VarName.Equals( m_dataName ) ) + { + m_currentDataIdx = i; + } + } + UpdateFromId(); + } + else + { + m_currentDataIdx = -1; + } + } + + void UpdateFromId() + { + if( m_interpolatorData != null ) + { + if( m_interpolatorData.Count == 0 ) + { + for( int i = 0; i < 4; i++ ) + m_containerGraph.DeleteConnection( false, UniqueId, i, false, true ); + + m_headerColor = UIUtils.GetColorFromCategory( "Default" ); + m_content.text = "None"; + m_additionalContent.text = string.Empty; + m_outputPorts[ 0 ].ChangeProperties( "None", WirePortDataType.OBJECT, false ); + ConfigurePorts(); + return; + } + + bool areCompatible = TemplateHelperFunctions.CheckIfCompatibles( m_outputPorts[ 0 ].DataType, m_interpolatorData[ m_currentDataIdx ].DataType ); + switch( m_interpolatorData[ m_currentDataIdx ].DataType ) + { + default: + case WirePortDataType.INT: + case WirePortDataType.FLOAT: + m_outputPorts[ 0 ].ChangeProperties( Constants.EmptyPortValue, m_interpolatorData[ m_currentDataIdx ].DataType, false ); + break; + case WirePortDataType.FLOAT2: + m_outputPorts[ 0 ].ChangeProperties( "XY", m_interpolatorData[ m_currentDataIdx ].DataType, false ); + break; + case WirePortDataType.FLOAT3: + m_outputPorts[ 0 ].ChangeProperties( "XYZ", m_interpolatorData[ m_currentDataIdx ].DataType, false ); + break; + case WirePortDataType.FLOAT4: + m_outputPorts[ 0 ].ChangeProperties( "XYZW", m_interpolatorData[ m_currentDataIdx ].DataType, false ); + break; + case WirePortDataType.COLOR: + m_outputPorts[ 0 ].ChangeProperties( "RGBA", m_interpolatorData[ m_currentDataIdx ].DataType, false ); + break; + } + + ConfigurePorts(); + + if( !areCompatible ) + { + m_containerGraph.DeleteConnection( false, UniqueId, 0, false, true ); + } + + m_dataName = m_interpolatorData[ m_currentDataIdx ].VarName; + m_content.text = m_dataName; + m_sizeIsDirty = true; + CheckWarningState(); + } + } + + + public override void DrawProperties() + { + base.DrawProperties(); + if( m_multiPassMode ) + { + DrawMultipassProperties(); + } + + if( m_currentDataIdx > -1 ) + { + EditorGUI.BeginChangeCheck(); + m_currentDataIdx = EditorGUILayoutPopup( DataLabelStr, m_currentDataIdx, m_dataLabels ); + if( EditorGUI.EndChangeCheck() ) + { + UpdateFromId(); + } + } + } + + protected override void OnSubShaderChange() + { + base.OnSubShaderChange(); + FetchInterpolator(); + FetchDataId(); + } + + protected override void OnPassChange() + { + FetchInterpolator(); + FetchDataId(); + } + + void DrawMultipassProperties() + { + DrawSubShaderUI(); + DrawPassUI(); + } + + public override void Draw( DrawInfo drawInfo ) + { + base.Draw( drawInfo ); + if( m_containerGraph.CurrentCanvasMode != NodeAvailability.TemplateShader ) + return; + + if( m_interpolatorData == null || m_interpolatorData.Count == 0 ) + { + MasterNode masterNode = m_containerGraph.CurrentMasterNode; + FetchInterpolator( masterNode ); + } + + if( m_fetchDataId ) + { + m_fetchDataId = false; + FetchDataId(); + } + + if( m_currentDataIdx > -1 ) + { + EditorGUI.BeginChangeCheck(); + m_currentDataIdx = m_upperLeftWidgetHelper.DrawWidget( this, m_currentDataIdx, m_dataLabels ); + if( EditorGUI.EndChangeCheck() ) + { + UpdateFromId(); + } + } + } + + public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar ) + { + if( dataCollector.MasterNodeCategory != AvailableShaderTypes.Template ) + { + UIUtils.ShowMessage( UniqueId, "Template Fragmment Data node is only intended for templates use only" ); + return m_outputPorts[ 0 ].ErrorValue; + } + + if( !dataCollector.IsFragmentCategory ) + { + UIUtils.ShowMessage( UniqueId, "Template Fragment Data node node is only intended for fragment use use only" ); + return m_outputPorts[ 0 ].ErrorValue; + } + + if( m_multiPassMode ) + { + if( dataCollector.TemplateDataCollectorInstance.MultipassSubshaderIdx != SubShaderIdx || + dataCollector.TemplateDataCollectorInstance.MultipassPassIdx != PassIdx + ) + { + UIUtils.ShowMessage( UniqueId, string.Format( "{0} is only intended for subshader {1} and pass {2}", m_dataLabels[ m_currentDataIdx ], SubShaderIdx, PassIdx ) ); + return m_outputPorts[ outputId ].ErrorValue; + } + } + + return GetOutputVectorItem( 0, outputId, m_inVarName + m_dataName ); + } + + public override void ReadFromString( ref string[] nodeParams ) + { + base.ReadFromString( ref nodeParams ); + m_dataName = GetCurrentParam( ref nodeParams ); + m_fetchDataId = true; + } + + public override void WriteToString( ref string nodeInfo, ref string connectionsInfo ) + { + base.WriteToString( ref nodeInfo, ref connectionsInfo ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_dataName ); + } + + public override void OnMasterNodeReplaced( MasterNode newMasterNode ) + { + base.OnMasterNodeReplaced( newMasterNode ); + if( newMasterNode.CurrentMasterNodeCategory == AvailableShaderTypes.Template ) + { + FetchInterpolator( newMasterNode ); + } + else + { + m_interpolatorData = null; + m_currentDataIdx = -1; + } + } + + protected override bool ValidatePass( int passIdx ) + { + return ( m_templateMPData.SubShaders[ SubShaderIdx ].Passes[ passIdx ].FragmentFunctionData != null && + m_templateMPData.SubShaders[ SubShaderIdx ].Passes[ passIdx ].InterpolatorDataContainer != null ); + } + + void FetchInterpolator( MasterNode masterNode = null ) + { + FetchMultiPassTemplate( masterNode ); + if( m_multiPassMode ) + { + if( m_templateMPData != null ) + { + m_inVarName = m_templateMPData.SubShaders[ SubShaderIdx ].Passes[ PassIdx ].FragmentFunctionData.InVarName + "."; + m_interpolatorData = m_templateMPData.SubShaders[ SubShaderIdx ].Passes[ PassIdx ].InterpolatorDataContainer.RawInterpolators; + m_fetchDataId = true; + } + } + else + { + if( masterNode == null ) + masterNode = m_containerGraph.CurrentMasterNode; + + TemplateData currentTemplate = ( masterNode as TemplateMasterNode ).CurrentTemplate; + if( currentTemplate != null ) + { + m_inVarName = currentTemplate.FragmentFunctionData.InVarName + "."; + m_interpolatorData = currentTemplate.InterpolatorData.RawInterpolators; + FetchDataId(); + } + else + { + m_interpolatorData = null; + m_currentDataIdx = -1; + } + } + } + + public override void Destroy() + { + base.Destroy(); + m_dataLabels = null; + m_interpolatorData = null; + m_upperLeftWidgetHelper = null; + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateFragmentDataNode.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateFragmentDataNode.cs.meta new file mode 100644 index 00000000..8e3e69fc --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateFragmentDataNode.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2b53cc116abb0df45b028f41b8f0305e +timeCreated: 1506595629 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateHelperFunctions.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateHelperFunctions.cs new file mode 100644 index 00000000..d5fc6583 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateHelperFunctions.cs @@ -0,0 +1,2374 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using System.Text.RegularExpressions; +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; + +namespace AmplifyShaderEditor +{ + public enum CustomTemplatePropertyUIEnum + { + None, + HDPBR + } + + public enum TemplateSemantics + { + NONE, + POSITION, + SV_POSITION, + COLOR, + COLOR0, + COLOR1, + TEXCOORD0, + TEXCOORD1, + TEXCOORD2, + TEXCOORD3, + TEXCOORD4, + TEXCOORD5, + TEXCOORD6, + TEXCOORD7, + TEXCOORD8, + TEXCOORD9, + TEXCOORD10, + TEXCOORD11, + TEXCOORD12, + TEXCOORD13, + TEXCOORD14, + TEXCOORD15, + NORMAL, + TANGENT, + VFACE, + SV_VertexID, + SV_PrimitiveID, + SV_InstanceID, + INTERNALTESSPOS + } + + public enum TemplateInfoOnSematics + { + NONE, + POSITION, + CLIP_POS, + SCREEN_POSITION, + SCREEN_POSITION_NORMALIZED, + COLOR, + TEXTURE_COORDINATES0, + TEXTURE_COORDINATES1, + TEXTURE_COORDINATES2, + TEXTURE_COORDINATES3, + TEXTURE_COORDINATES4, + TEXTURE_COORDINATES5, + TEXTURE_COORDINATES6, + TEXTURE_COORDINATES7, + NORMAL, + TANGENT, + WORLD_NORMAL, + WORLD_TANGENT, + WORLD_BITANGENT, + WORLD_VIEW_DIR, + WORLD_POSITION, + RELATIVE_WORLD_POS, + INSTANCE_ID, + OTHER, + VFACE, + SHADOWCOORDS, + VERTEXID + } + + public enum TemplateShaderPropertiesIdx + { + Identation = 1, + Name = 3, + InspectorName, + Type + } + + public enum TemplateShaderGlobalsIdx + { + Type = 1, + Name = 2 + } + public enum TemplateDataCheck + { + Valid, + Invalid + } + + public enum InvisibleOptionsEnum + { + SyncProperties = 1 << 0 + } + + public enum TemplateSpecialTags + { + RenderType, + Queue, + None + } + + public class TemplateReplaceHelper + { + public TemplateMultiPassMasterNode MasterNode = null; + public bool Used = false; + public TemplateReplaceHelper( TemplateMultiPassMasterNode masterNode ) { MasterNode = masterNode; } + } + + [Serializable] + public class TemplatesTagData + { + public string Name; + public string Value; + public TemplatesTagData( string name, string value ) + { + Name = name; + Value = value; + } + } + + [Serializable] + public class TemplateModuleData + { + public bool IndependentModule = true; + public TemplateDataCheck DataCheck = TemplateDataCheck.Invalid; + public string InlineData = string.Empty; + public int StartIdx; + public bool IsValid { get { return DataCheck == TemplateDataCheck.Valid; } } + public virtual void SetAllModulesDefault() { IndependentModule = false; DataCheck = TemplateDataCheck.Valid; } + } + + [Serializable] + public sealed class TemplateTagsModuleData : TemplateModuleData + { + public string TagsId; + public List<TemplatesTagData> Tags = new List<TemplatesTagData>(); + public void Destroy() + { + Tags.Clear(); + Tags = null; + } + + public void Reset() + { + Tags.Clear(); + } + + public void Dump() + { + string dump = string.Empty; + for( int i = 0; i < Tags.Count; i++ ) + { + dump += string.Format( "[{0}] Name: {1} Value: {2}\n", i, Tags[ i ].Name, Tags[ i ].Value ); + } + Debug.Log( dump ); + } + } + + [Serializable] + public class TemplateShaderModelData : TemplateModuleData + { + public string Id = string.Empty; + public string Value = "2.5"; + public int InterpolatorAmount = 8; + public bool Encapsulate = false; + public override void SetAllModulesDefault() + { + base.SetAllModulesDefault(); + Id = string.Empty; + Value = "3.0"; + InterpolatorAmount = 10; + Encapsulate = true; + } + } + + [Serializable] + public sealed class TemplateDepthData : TemplateModuleData + { + public bool ValidZWrite; + public string ZWriteModeId; + public ZWriteMode ZWriteModeValue; + public int ZWriteStartIndex; + public string ZWriteInlineValue; + + + public bool ValidZTest; + public string ZTestModeId; + public ZTestMode ZTestModeValue; + public int ZTestStartIndex; + public string ZTestInlineValue; + + public bool ValidOffset; + public string OffsetId; + public float OffsetFactor; + public float OffsetUnits; + public int OffsetStartIndex; + public string OffsetFactorInlineValue; + public string OffsetUnitsInlineValue; + + public override void SetAllModulesDefault() + { + base.SetAllModulesDefault(); + ValidZWrite = true; + ZWriteModeId = string.Empty; + ZWriteModeValue = ZWriteMode.On; + ZWriteStartIndex = -1; + ZWriteInlineValue = string.Empty; + + + ValidZTest = true; + ZTestModeId = string.Empty; + ZTestModeValue = ZTestMode.LEqual; + ZTestStartIndex = -1; + ZTestInlineValue = string.Empty; + + ValidOffset = true; + OffsetId = string.Empty; + OffsetFactor = 0; + OffsetUnits = 0; + OffsetStartIndex = -1; + OffsetFactorInlineValue = string.Empty; + OffsetUnitsInlineValue = string.Empty; + } + + public void SetDataCheck() + { + DataCheck = ( ValidZWrite || ValidZTest || ValidOffset )?TemplateDataCheck.Valid:TemplateDataCheck.Invalid; + } + } + + [Serializable] + public sealed class TemplateStencilData : TemplateModuleData + { + public string StencilBufferId; + public bool Active = true; + + public int Reference; + public string ReferenceInline; + + public int ReadMask = 255; + public string ReadMaskInline; + + public int WriteMask = 255; + public string WriteMaskInline; + + public string ComparisonFront; + public string ComparisonFrontInline; + + public string PassFront; + public string PassFrontInline; + + public string FailFront; + public string FailFrontInline; + + public string ZFailFront; + public string ZFailFrontInline; + + public string ComparisonBack; + public string ComparisonBackInline; + + public string PassBack; + public string PassBackInline; + + public string FailBack; + public string FailBackInline; + + public string ZFailBack; + public string ZFailBackInline; + + public void SetDefaultValues() + { + Active = false; + + StencilBufferId = string.Empty; + + Reference = 255; + ReferenceInline = string.Empty; + + ReadMask = 255; + ReadMaskInline = string.Empty; + + WriteMask = 255; + WriteMaskInline = string.Empty; + + ComparisonFront = "always"; + ComparisonFrontInline = string.Empty; + + PassFront = "keep"; + PassFrontInline = string.Empty; + + FailFront = "keep"; + FailFrontInline = string.Empty; + + ZFailFront = "keep"; + ZFailFrontInline = string.Empty; + + + ComparisonBack = "always"; + ComparisonBackInline = string.Empty; + + PassBack = "keep"; + PassBackInline = string.Empty; + + FailBack = "keep"; + FailBackInline = string.Empty; + + ZFailBack = "keep"; + ZFailBackInline = string.Empty; + } + + public void SetIndependentDefault() + { + IndependentModule = true; + DataCheck = TemplateDataCheck.Valid; + SetDefaultValues(); + } + + public override void SetAllModulesDefault() + { + base.SetAllModulesDefault(); + SetDefaultValues(); + } + } + + [Serializable] + public sealed class TemplateBlendData : TemplateModuleData + { + public bool ValidBlendMode = false; + public bool BlendModeOff = true; + + public string BlendModeId; + public bool SeparateBlendFactors = false; + public AvailableBlendFactor SourceFactorRGB = AvailableBlendFactor.One; + public string SourceFactorRGBInline; + public AvailableBlendFactor DestFactorRGB = AvailableBlendFactor.Zero; + public string DestFactorRGBInline; + public int BlendModeStartIndex; + + public AvailableBlendFactor SourceFactorAlpha = AvailableBlendFactor.One; + public string SourceFactorAlphaInline; + public AvailableBlendFactor DestFactorAlpha = AvailableBlendFactor.Zero; + public string DestFactorAlphaInline; + + public bool ValidBlendOp = false; + public string BlendOpId; + public bool SeparateBlendOps = false; + public AvailableBlendOps BlendOpRGB = AvailableBlendOps.OFF; + public string BlendOpRGBInline; + public AvailableBlendOps BlendOpAlpha = AvailableBlendOps.OFF; + public string BlendOpAlphaInline; + public int BlendOpStartIndex; + + public bool IndependentAlphaToMask = false; + public bool ValidAlphaToMask = false; + public bool AlphaToMaskValue = false; + public string AlphaToMaskId; + + public override void SetAllModulesDefault() + { + base.SetAllModulesDefault(); + + if( !ValidAlphaToMask ) + { + ValidAlphaToMask = true; + AlphaToMaskValue = false; + AlphaToMaskId = string.Empty; + } + + if( !ValidBlendMode ) + { + ValidBlendMode = true; + BlendModeOff = true; + BlendModeId = string.Empty; + SeparateBlendFactors = false; + SourceFactorRGB = AvailableBlendFactor.One; + SourceFactorRGBInline = string.Empty; + DestFactorRGB = AvailableBlendFactor.Zero; + DestFactorRGBInline = string.Empty; + BlendModeStartIndex = -1; + SourceFactorAlpha = AvailableBlendFactor.One; + SourceFactorAlphaInline = string.Empty; + DestFactorAlpha = AvailableBlendFactor.Zero; + DestFactorAlphaInline = string.Empty; + } + + if( !ValidBlendOp ) + { + ValidBlendOp = true; + BlendOpId = string.Empty; + SeparateBlendOps = false; + BlendOpRGB = AvailableBlendOps.OFF; + BlendOpRGBInline = string.Empty; + BlendOpAlpha = AvailableBlendOps.OFF; + BlendOpAlphaInline = string.Empty; + BlendOpStartIndex = -1; + } + + DataCheck = TemplateDataCheck.Valid; + } + + } + + [Serializable] + public sealed class TemplateCullModeData : TemplateModuleData + { + public string CullModeId; + public CullMode CullModeData = CullMode.Back; + public override void SetAllModulesDefault() + { + base.SetAllModulesDefault(); + CullModeId = string.Empty; + CullModeData = CullMode.Back; + } + } + + [Serializable] + public sealed class TemplateColorMaskData : TemplateModuleData + { + public string ColorMaskId; + public bool[] ColorMaskData = { true, true, true, true }; + public override void SetAllModulesDefault() + { + base.SetAllModulesDefault(); + ColorMaskId = string.Empty; + for( int i = 0; i < ColorMaskData.Length; i++ ) + { + ColorMaskData[ i ] = true; + } + } + } + + public static class TemplateHelperFunctions + { + /* + struct DirectionalLightData + { + uint lightLayers; + float3 positionRWS; + float3 color; + int cookieIndex; + float volumetricDimmer; + float3 right; + float3 up; + float3 forward; + int tileCookie; + int shadowIndex; + int contactShadowIndex; + float4 shadowMaskSelector; + int nonLightmappedOnly; + float diffuseScale; + float specularScale; + }; + */ + public static string HDLightInfoFormat = "_DirectionalLightDatas[{0}].{1}"; + + public static string[] VectorSwizzle = { "x", "y", "z", "w" }; + public static string[] ColorSwizzle = { "r", "g", "b", "a" }; + + public static readonly Dictionary<string, CustomTemplatePropertyUIEnum> CustomTemplatePropertyUI = new Dictionary<string, CustomTemplatePropertyUIEnum> + { + { "None", CustomTemplatePropertyUIEnum.None}, + { "HDPBR", CustomTemplatePropertyUIEnum.HDPBR} + }; + + public static readonly Dictionary<string, InvisibleOptionsEnum> InvisibleOptions = new Dictionary<string, InvisibleOptionsEnum>() + { + { "SyncP", InvisibleOptionsEnum.SyncProperties } + }; + + public static readonly Dictionary<string, TemplateSpecialTags> StringToReservedTags = new Dictionary<string, TemplateSpecialTags>() + { + { TemplateSpecialTags.RenderType.ToString(), TemplateSpecialTags.RenderType}, + { TemplateSpecialTags.Queue.ToString(), TemplateSpecialTags.Queue}, + }; + + public static readonly Dictionary<string, RenderType> StringToRenderType = new Dictionary<string, RenderType> + { + {"Opaque",RenderType.Opaque}, + {"Transparent",RenderType.Transparent}, + {"TransparentCutout",RenderType.TransparentCutout}, + {"Background",RenderType.Background}, + {"Overlay",RenderType.Overlay}, + {"TreeOpaque",RenderType.TreeOpaque}, + {"TreeTransparentCutout",RenderType.TreeTransparentCutout}, + {"TreeBillboard",RenderType.TreeBillboard}, + {"Grass",RenderType.Grass}, + {"GrassBillboard",RenderType.GrassBillboard} + }; + + public static readonly Dictionary<string, RenderQueue> StringToRenderQueue = new Dictionary<string, RenderQueue> + { + {"Background",RenderQueue.Background }, + {"Geometry",RenderQueue.Geometry }, + {"AlphaTest",RenderQueue.AlphaTest }, + {"Transparent",RenderQueue.Transparent }, + {"Overlay",RenderQueue.Overlay } + }; + + public static readonly Dictionary<string, WirePortDataType> PropertyToWireType = new Dictionary<string, WirePortDataType> + { + {"Float",WirePortDataType.FLOAT}, + {"Range",WirePortDataType.FLOAT}, + {"Int",WirePortDataType.INT}, + {"Color",WirePortDataType.COLOR}, + {"Vector",WirePortDataType.FLOAT4}, + {"2D",WirePortDataType.SAMPLER2D}, + {"3D",WirePortDataType.SAMPLER3D}, + {"Cube",WirePortDataType.SAMPLERCUBE} + }; + + public static readonly Dictionary<WirePortDataType, int> DataTypeChannelUsage = new Dictionary<WirePortDataType, int> + { + {WirePortDataType.OBJECT,0 }, + {WirePortDataType.FLOAT,1 }, + {WirePortDataType.FLOAT2,2 }, + {WirePortDataType.FLOAT3,3 }, + {WirePortDataType.FLOAT4,4 }, + {WirePortDataType.FLOAT3x3,0 }, + {WirePortDataType.FLOAT4x4,0 }, + {WirePortDataType.COLOR,4 }, + {WirePortDataType.INT,1 }, + {WirePortDataType.UINT,1 }, + {WirePortDataType.SAMPLER1D,0 }, + {WirePortDataType.SAMPLER2D,0 }, + {WirePortDataType.SAMPLER3D,0 }, + {WirePortDataType.SAMPLERCUBE,0 } + }; + + public static readonly Dictionary<int, WirePortDataType> ChannelToDataType = new Dictionary<int, WirePortDataType> + { + {1,WirePortDataType.FLOAT}, + {2,WirePortDataType.FLOAT2}, + {3,WirePortDataType.FLOAT3}, + {4,WirePortDataType.FLOAT4} + }; + + public static readonly Dictionary<TemplateSemantics, string> SemanticsDefaultName = new Dictionary<TemplateSemantics, string> + { + {TemplateSemantics.COLOR ,"ase_color"}, + {TemplateSemantics.NORMAL ,"ase_normal"}, + {TemplateSemantics.POSITION ,"ase_position"}, + {TemplateSemantics.SV_POSITION ,"ase_sv_position"}, + {TemplateSemantics.TANGENT ,"ase_tangent"}, + {TemplateSemantics.VFACE ,"ase_vface"}, + {TemplateSemantics.SV_VertexID ,"ase_vertexId"}, + {TemplateSemantics.SV_PrimitiveID ,"ase_primitiveId"}, + {TemplateSemantics.INTERNALTESSPOS ,"ase_internalTessPos"}, + {TemplateSemantics.TEXCOORD0 ,"ase_tex_coord0"}, + {TemplateSemantics.TEXCOORD1 ,"ase_tex_coord1"}, + {TemplateSemantics.TEXCOORD2 ,"ase_tex_coord2"}, + {TemplateSemantics.TEXCOORD3 ,"ase_tex_coord3"}, + {TemplateSemantics.TEXCOORD4 ,"ase_tex_coord4"}, + {TemplateSemantics.TEXCOORD5 ,"ase_tex_coord5"}, + {TemplateSemantics.TEXCOORD6 ,"ase_tex_coord6"}, + {TemplateSemantics.TEXCOORD7 ,"ase_tex_coord7"}, + {TemplateSemantics.TEXCOORD8 ,"ase_tex_coord8"}, + {TemplateSemantics.TEXCOORD9 ,"ase_tex_coord9"}, + {TemplateSemantics.TEXCOORD10 ,"ase_tex_coord10"}, + {TemplateSemantics.TEXCOORD11 ,"ase_tex_coord11"}, + {TemplateSemantics.TEXCOORD12 ,"ase_tex_coord12"}, + {TemplateSemantics.TEXCOORD13 ,"ase_tex_coord13"}, + {TemplateSemantics.TEXCOORD14 ,"ase_tex_coord14"}, + {TemplateSemantics.TEXCOORD15 ,"ase_tex_coord15"}, + }; + + public static readonly Dictionary<int, TemplateInfoOnSematics> IntToInfo = new Dictionary<int, TemplateInfoOnSematics> + { + {0,TemplateInfoOnSematics.TEXTURE_COORDINATES0 }, + {1,TemplateInfoOnSematics.TEXTURE_COORDINATES1 }, + {2,TemplateInfoOnSematics.TEXTURE_COORDINATES2 }, + {3,TemplateInfoOnSematics.TEXTURE_COORDINATES3 }, + {4,TemplateInfoOnSematics.TEXTURE_COORDINATES4 }, + {5,TemplateInfoOnSematics.TEXTURE_COORDINATES5 }, + {6,TemplateInfoOnSematics.TEXTURE_COORDINATES6 }, + {7,TemplateInfoOnSematics.TEXTURE_COORDINATES7 }, + }; + + public static readonly Dictionary<string, TemplateInfoOnSematics> ShortcutToInfo = new Dictionary<string, TemplateInfoOnSematics> + { + {"p" ,TemplateInfoOnSematics.POSITION }, + {"sp" ,TemplateInfoOnSematics.CLIP_POS }, + {"spu" ,TemplateInfoOnSematics.SCREEN_POSITION }, + {"spn" ,TemplateInfoOnSematics.SCREEN_POSITION_NORMALIZED }, + {"c" ,TemplateInfoOnSematics.COLOR }, + {"uv0" ,TemplateInfoOnSematics.TEXTURE_COORDINATES0 }, + {"uv1" ,TemplateInfoOnSematics.TEXTURE_COORDINATES1 }, + {"uv2" ,TemplateInfoOnSematics.TEXTURE_COORDINATES2 }, + {"uv3" ,TemplateInfoOnSematics.TEXTURE_COORDINATES3 }, + {"uv4" ,TemplateInfoOnSematics.TEXTURE_COORDINATES4 }, + {"uv5" ,TemplateInfoOnSematics.TEXTURE_COORDINATES5 }, + {"uv6" ,TemplateInfoOnSematics.TEXTURE_COORDINATES6 }, + {"uv7" ,TemplateInfoOnSematics.TEXTURE_COORDINATES7 }, + {"n" ,TemplateInfoOnSematics.NORMAL }, + {"t" ,TemplateInfoOnSematics.TANGENT }, + {"wn" ,TemplateInfoOnSematics.WORLD_NORMAL}, + {"wt" ,TemplateInfoOnSematics.WORLD_TANGENT}, + {"wbt" ,TemplateInfoOnSematics.WORLD_BITANGENT}, + {"wvd" ,TemplateInfoOnSematics.WORLD_VIEW_DIR}, + {"wp" ,TemplateInfoOnSematics.WORLD_POSITION}, + {"rwp" ,TemplateInfoOnSematics.RELATIVE_WORLD_POS}, + {"vf" ,TemplateInfoOnSematics.VFACE}, + {"sc" ,TemplateInfoOnSematics.SHADOWCOORDS} + }; + + public static readonly Dictionary<TemplateInfoOnSematics, string> InfoToDefineFrag = new Dictionary<TemplateInfoOnSematics, string> + { + {TemplateInfoOnSematics.POSITION ,"ASE_NEEDS_FRAG_POSITION"}, + {TemplateInfoOnSematics.CLIP_POS ,"ASE_NEEDS_FRAG_CLIP_POS"}, + {TemplateInfoOnSematics.SCREEN_POSITION,"ASE_NEEDS_FRAG_SCREEN_POSITION" }, + {TemplateInfoOnSematics.SCREEN_POSITION_NORMALIZED,"ASE_NEEDS_FRAG_SCREEN_POSITION_NORMALIZED" }, + {TemplateInfoOnSematics.COLOR, "ASE_NEEDS_FRAG_COLOR"}, + {TemplateInfoOnSematics.TEXTURE_COORDINATES0,"ASE_NEEDS_FRAG_TEXTURE_COORDINATES0" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES1,"ASE_NEEDS_FRAG_TEXTURE_COORDINATES1" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES2,"ASE_NEEDS_FRAG_TEXTURE_COORDINATES2" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES3,"ASE_NEEDS_FRAG_TEXTURE_COORDINATES3" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES4,"ASE_NEEDS_FRAG_TEXTURE_COORDINATES4" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES5,"ASE_NEEDS_FRAG_TEXTURE_COORDINATES5" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES6,"ASE_NEEDS_FRAG_TEXTURE_COORDINATES6" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES7,"ASE_NEEDS_FRAG_TEXTURE_COORDINATES7" }, + {TemplateInfoOnSematics.NORMAL,"ASE_NEEDS_FRAG_NORMAL" }, + {TemplateInfoOnSematics.TANGENT ,"ASE_NEEDS_FRAG_TANGENT"}, + {TemplateInfoOnSematics.WORLD_NORMAL,"ASE_NEEDS_FRAG_WORLD_NORMAL"}, + {TemplateInfoOnSematics.WORLD_TANGENT,"ASE_NEEDS_FRAG_WORLD_TANGENT"}, + {TemplateInfoOnSematics.WORLD_BITANGENT,"ASE_NEEDS_FRAG_WORLD_BITANGENT"}, + {TemplateInfoOnSematics.WORLD_VIEW_DIR,"ASE_NEEDS_FRAG_WORLD_VIEW_DIR"}, + {TemplateInfoOnSematics.WORLD_POSITION,"ASE_NEEDS_FRAG_WORLD_POSITION"}, + {TemplateInfoOnSematics.RELATIVE_WORLD_POS,"ASE_NEEDS_FRAG_RELATIVE_WORLD_POS"}, + {TemplateInfoOnSematics.VFACE,"ASE_NEEDS_FRAG_VFACE"}, + {TemplateInfoOnSematics.SHADOWCOORDS,"ASE_NEEDS_FRAG_SHADOWCOORDS"} + }; + + public static readonly Dictionary<TemplateInfoOnSematics, string> InfoToDefineVertex = new Dictionary<TemplateInfoOnSematics, string> + { + {TemplateInfoOnSematics.POSITION ,"ASE_NEEDS_VERT_POSITION"}, + {TemplateInfoOnSematics.CLIP_POS ,"ASE_NEEDS_VERT_CLIP_POS"}, + {TemplateInfoOnSematics.SCREEN_POSITION,"ASE_NEEDS_VERT_SCREEN_POSITION" }, + {TemplateInfoOnSematics.SCREEN_POSITION_NORMALIZED,"ASE_NEEDS_VERT_SCREEN_POSITION_NORMALIZED" }, + {TemplateInfoOnSematics.COLOR, "ASE_NEEDS_VERT_COLOR"}, + {TemplateInfoOnSematics.TEXTURE_COORDINATES0,"ASE_NEEDS_VERT_TEXTURE_COORDINATES0" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES1,"ASE_NEEDS_VERT_TEXTURE_COORDINATES1" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES2,"ASE_NEEDS_VERT_TEXTURE_COORDINATES2" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES3,"ASE_NEEDS_VERT_TEXTURE_COORDINATES3" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES4,"ASE_NEEDS_VERT_TEXTURE_COORDINATES4" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES5,"ASE_NEEDS_VERT_TEXTURE_COORDINATES5" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES6,"ASE_NEEDS_VERT_TEXTURE_COORDINATES6" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES7,"ASE_NEEDS_VERT_TEXTURE_COORDINATES7" }, + {TemplateInfoOnSematics.NORMAL,"ASE_NEEDS_VERT_NORMAL" }, + {TemplateInfoOnSematics.TANGENT ,"ASE_NEEDS_VERT_TANGENT"}, + {TemplateInfoOnSematics.WORLD_NORMAL,"ASE_NEEDS_VERT_WORLD_NORMAL"}, + {TemplateInfoOnSematics.WORLD_TANGENT,"ASE_NEEDS_VERT_WORLD_TANGENT"}, + {TemplateInfoOnSematics.WORLD_BITANGENT,"ASE_NEEDS_VERT_WORLD_BITANGENT"}, + {TemplateInfoOnSematics.WORLD_VIEW_DIR,"ASE_NEEDS_VERT_WORLD_VIEW_DIR"}, + {TemplateInfoOnSematics.WORLD_POSITION,"ASE_NEEDS_VERT_WORLD_POSITION"}, + {TemplateInfoOnSematics.RELATIVE_WORLD_POS,"ASE_NEEDS_VERT_RELATIVE_WORLD_POS"}, + {TemplateInfoOnSematics.VFACE,"ASE_NEEDS_VERT_VFACE"}, + {TemplateInfoOnSematics.SHADOWCOORDS,"ASE_NEEDS_VERT_SHADOWCOORDS"} + }; + + public static readonly Dictionary<TemplateInfoOnSematics, string> InfoToLocalVar = new Dictionary<TemplateInfoOnSematics, string> + { + {TemplateInfoOnSematics.POSITION,GeneratorUtils.VertexPosition4Str }, + {TemplateInfoOnSematics.CLIP_POS,GeneratorUtils.ClipPositionStr }, + {TemplateInfoOnSematics.SCREEN_POSITION,GeneratorUtils.ScreenPositionStr }, + {TemplateInfoOnSematics.SCREEN_POSITION_NORMALIZED,GeneratorUtils.ScreenPositionNormalizedStr }, + {TemplateInfoOnSematics.COLOR, "ase_color" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES0, "ase_uv0" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES1, "ase_uv1" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES2, "ase_uv2" }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES3, "ase_uv3" }, + {TemplateInfoOnSematics.NORMAL, GeneratorUtils.VertexNormalStr }, + {TemplateInfoOnSematics.TANGENT, GeneratorUtils.VertexTangentStr }, + {TemplateInfoOnSematics.WORLD_NORMAL, GeneratorUtils.WorldNormalStr}, + {TemplateInfoOnSematics.WORLD_TANGENT, GeneratorUtils.WorldTangentStr}, + {TemplateInfoOnSematics.WORLD_BITANGENT, GeneratorUtils.WorldBitangentStr}, + {TemplateInfoOnSematics.WORLD_VIEW_DIR, GeneratorUtils.WorldViewDirectionStr}, + {TemplateInfoOnSematics.WORLD_POSITION, GeneratorUtils.WorldPositionStr}, + {TemplateInfoOnSematics.RELATIVE_WORLD_POS, GeneratorUtils.RelativeWorldPositionStr}, + {TemplateInfoOnSematics.VFACE, GeneratorUtils.VFaceStr}, + {TemplateInfoOnSematics.SHADOWCOORDS, GeneratorUtils.ShadowCoordsStr} + }; + + + public static readonly Dictionary<TemplateInfoOnSematics, WirePortDataType> InfoToWirePortType = new Dictionary<TemplateInfoOnSematics, WirePortDataType> + { + {TemplateInfoOnSematics.POSITION,WirePortDataType.FLOAT4 }, + {TemplateInfoOnSematics.CLIP_POS,WirePortDataType.FLOAT4 }, + {TemplateInfoOnSematics.SCREEN_POSITION,WirePortDataType.FLOAT4 }, + {TemplateInfoOnSematics.SCREEN_POSITION_NORMALIZED,WirePortDataType.FLOAT4 }, + {TemplateInfoOnSematics.COLOR, WirePortDataType.COLOR }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES0, WirePortDataType.FLOAT4 }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES1, WirePortDataType.FLOAT4 }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES2, WirePortDataType.FLOAT4 }, + {TemplateInfoOnSematics.TEXTURE_COORDINATES3, WirePortDataType.FLOAT4 }, + {TemplateInfoOnSematics.NORMAL, WirePortDataType.FLOAT3 }, + {TemplateInfoOnSematics.TANGENT, WirePortDataType.FLOAT4 }, + {TemplateInfoOnSematics.WORLD_NORMAL, WirePortDataType.FLOAT3}, + {TemplateInfoOnSematics.WORLD_TANGENT, WirePortDataType.FLOAT3}, + {TemplateInfoOnSematics.WORLD_BITANGENT, WirePortDataType.FLOAT3}, + {TemplateInfoOnSematics.WORLD_VIEW_DIR, WirePortDataType.FLOAT3}, + {TemplateInfoOnSematics.WORLD_POSITION, WirePortDataType.FLOAT3}, + {TemplateInfoOnSematics.RELATIVE_WORLD_POS, WirePortDataType.FLOAT3}, + {TemplateInfoOnSematics.VFACE, WirePortDataType.FLOAT}, + {TemplateInfoOnSematics.SHADOWCOORDS, WirePortDataType.FLOAT4}, + }; + public static readonly Dictionary<int, TemplateInfoOnSematics> IntToUVChannelInfo = new Dictionary<int, TemplateInfoOnSematics> + { + {0,TemplateInfoOnSematics.TEXTURE_COORDINATES0 }, + {1,TemplateInfoOnSematics.TEXTURE_COORDINATES1 }, + {2,TemplateInfoOnSematics.TEXTURE_COORDINATES2 }, + {3,TemplateInfoOnSematics.TEXTURE_COORDINATES3 }, + {4,TemplateInfoOnSematics.TEXTURE_COORDINATES4 }, + {5,TemplateInfoOnSematics.TEXTURE_COORDINATES5 }, + {6,TemplateInfoOnSematics.TEXTURE_COORDINATES6 }, + {7,TemplateInfoOnSematics.TEXTURE_COORDINATES7 } + }; + + public static readonly Dictionary<int, TemplateSemantics> IntToSemantic = new Dictionary<int, TemplateSemantics> + { + { 0,TemplateSemantics.TEXCOORD0 }, + { 1,TemplateSemantics.TEXCOORD1 }, + { 2,TemplateSemantics.TEXCOORD2 }, + { 3,TemplateSemantics.TEXCOORD3 }, + { 4,TemplateSemantics.TEXCOORD4 }, + { 5,TemplateSemantics.TEXCOORD5 }, + { 6,TemplateSemantics.TEXCOORD6 }, + { 7,TemplateSemantics.TEXCOORD7 }, + { 8,TemplateSemantics.TEXCOORD8 }, + { 9,TemplateSemantics.TEXCOORD9 }, + { 10,TemplateSemantics.TEXCOORD10 }, + { 11,TemplateSemantics.TEXCOORD11 }, + { 12,TemplateSemantics.TEXCOORD12 }, + { 13,TemplateSemantics.TEXCOORD13 }, + { 14,TemplateSemantics.TEXCOORD14 }, + { 15,TemplateSemantics.TEXCOORD15 } + }; + + public static readonly Dictionary<TemplateSemantics, int> SemanticToInt = new Dictionary<TemplateSemantics, int> + { + { TemplateSemantics.TEXCOORD0,0 }, + { TemplateSemantics.TEXCOORD1,1 }, + { TemplateSemantics.TEXCOORD2,2 }, + { TemplateSemantics.TEXCOORD3,3 }, + { TemplateSemantics.TEXCOORD4,4 }, + { TemplateSemantics.TEXCOORD5,5 }, + { TemplateSemantics.TEXCOORD6,6 }, + { TemplateSemantics.TEXCOORD7,7 }, + { TemplateSemantics.TEXCOORD8,8 }, + { TemplateSemantics.TEXCOORD9,9 }, + { TemplateSemantics.TEXCOORD10,10 }, + { TemplateSemantics.TEXCOORD11,11 }, + { TemplateSemantics.TEXCOORD12,12 }, + { TemplateSemantics.TEXCOORD13,13 }, + { TemplateSemantics.TEXCOORD14,14 }, + { TemplateSemantics.TEXCOORD15,15 }, + }; + + public static readonly Dictionary<string, TemplateSemantics> ShortcutToSemantic = new Dictionary<string, TemplateSemantics> + { + { "p" ,TemplateSemantics.POSITION }, + { "sp" ,TemplateSemantics.SV_POSITION }, + { "c" ,TemplateSemantics.COLOR }, + { "n" ,TemplateSemantics.NORMAL }, + { "t" ,TemplateSemantics.TANGENT }, + { "tc0" ,TemplateSemantics.TEXCOORD0 }, + { "tc1" ,TemplateSemantics.TEXCOORD1 }, + { "tc2" ,TemplateSemantics.TEXCOORD2 }, + { "tc3" ,TemplateSemantics.TEXCOORD3 }, + { "tc4" ,TemplateSemantics.TEXCOORD4 }, + { "tc5" ,TemplateSemantics.TEXCOORD5 }, + { "tc6" ,TemplateSemantics.TEXCOORD6 }, + { "tc7" ,TemplateSemantics.TEXCOORD7 }, + { "tc8" ,TemplateSemantics.TEXCOORD8 }, + { "tc9" ,TemplateSemantics.TEXCOORD9 }, + { "tc10" ,TemplateSemantics.TEXCOORD10 }, + { "tc11" ,TemplateSemantics.TEXCOORD11 }, + { "tc12" ,TemplateSemantics.TEXCOORD12 }, + { "tc13" ,TemplateSemantics.TEXCOORD13 }, + { "tc14" ,TemplateSemantics.TEXCOORD14 }, + { "tc15" ,TemplateSemantics.TEXCOORD15 } + }; + + public static readonly Dictionary<string, WirePortDataType> CgToWirePortType = new Dictionary<string, WirePortDataType>() + { + {"float" ,WirePortDataType.FLOAT}, + {"float2" ,WirePortDataType.FLOAT2}, + {"float3" ,WirePortDataType.FLOAT3}, + {"float4" ,WirePortDataType.FLOAT4}, + {"float3x3" ,WirePortDataType.FLOAT3x3}, + {"float4x4" ,WirePortDataType.FLOAT4x4}, + {"half" ,WirePortDataType.FLOAT}, + {"half2" ,WirePortDataType.FLOAT2}, + {"half3" ,WirePortDataType.FLOAT3}, + {"half4" ,WirePortDataType.FLOAT4}, + {"half3x3" ,WirePortDataType.FLOAT3x3}, + {"half4x4" ,WirePortDataType.FLOAT4x4}, + {"fixed" ,WirePortDataType.FLOAT}, + {"fixed2" ,WirePortDataType.FLOAT2}, + {"fixed3" ,WirePortDataType.FLOAT3}, + {"fixed4" ,WirePortDataType.FLOAT4}, + {"fixed3x3" ,WirePortDataType.FLOAT3x3}, + {"fixed4x4" ,WirePortDataType.FLOAT4x4}, + {"int" ,WirePortDataType.INT}, + {"uint" ,WirePortDataType.INT}, + {"sampler1D" ,WirePortDataType.SAMPLER1D}, + {"sampler2D" ,WirePortDataType.SAMPLER2D}, + {"sampler2D_float" ,WirePortDataType.SAMPLER2D}, + {"sampler3D" ,WirePortDataType.SAMPLER3D}, + {"samplerCUBE" ,WirePortDataType.SAMPLERCUBE} + }; + + public static readonly Dictionary<string, int> AvailableInterpolators = new Dictionary<string, int>() + { + {"2.0",8 }, + {"2.5",8 }, + {"3.0",10}, + {"3.5",10}, + {"4.0",16}, + {"4.5",16}, + {"4.6",16}, + {"5.0",16} + }; + + public static readonly string[] AvailableShaderModels = + { "2.0", "2.5", "3.0", "3.5", "4.0", "4.5", "4.6", "5.0" }; + + public static readonly Dictionary<string, int> ShaderModelToArrayIdx = new Dictionary<string, int>() + { + {"2.0",0}, + {"2.5",1}, + {"3.0",2}, + {"3.5",3}, + {"4.0",4}, + {"4.5",5}, + {"4.6",6}, + {"5.0",7} + }; + + public static readonly string HDPBRTag = "UNITY_MATERIAL_LIT"; + public static readonly Dictionary<string, TemplateSRPType> TagToRenderPipeline = new Dictionary<string, TemplateSRPType>() + { + { "UniversalPipeline",TemplateSRPType.Lightweight }, + { "LightweightPipeline",TemplateSRPType.Lightweight }, + { "HDRenderPipeline",TemplateSRPType.HD } + }; +#if UNITY_2018_3_OR_NEWER + public static string CoreColorLib = "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"; + public static string CoreCommonLib = "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"; +#else + public static string CoreCommonLib = "CoreRP/ShaderLibrary/Common.hlsl"; + public static string CoreColorLib = "CoreRP/ShaderLibrary/Color.hlsl"; +#endif + + public static string FetchSubShaderBody = @"(SubShader.*)\/\*ase_lod\*\/"; + public static string TemplateCustomUI = @"\/\*CustomNodeUI:(\w*)\*\/"; + public static string HidePassPattern = @"\/\*ase_hide_pass[:]*([a-zA-Z:]*)\*\/"; + public static string ASEPassPattern = @"\/\*ase_pass[:]*([a-zA-Z:]*)\*\/"; + public static string BlendWholeWordPattern = @"\bBlend\b"; + public static string BlendOpWholeWordPattern = @"\bBlendOp\b"; + public static string AlphaToMaskPattern = @"\bAlphaToMask (\w*)"; + public static string CullWholeWordPattern = @"\bCull\b"; + public static string ColorMaskWholeWordPattern = @"\bColorMask\b"; + public static string StencilWholeWordPattern = @"\bStencil\b"; + public static string ZWriteWholeWordPattern = @"\bZWrite\b"; + public static string ZTestWholeWordPattern = @"\bZTest\b"; + public static string ZOffsetWholeWordPattern = @"\bOffset\b"; + public static string TagsWholeWordPattern = @"\bTags\b"; + + + public static string CustomInspectorPattern = "^\\s*CustomEditor\\s+\\\"([\\w\\.]*)\\\""; + public static string FallbackPattern = "^\\s*Fallback\\s+\\\"([\\w\\/\\\\]*)\\\""; + public static string DefinesPattern = @"^\s*#define\s+([\w .]*)"; + public static string PragmasPattern = @"^\s*#pragma\s+([\w .]*)"; + public static string IncludesPattern = "^\\s*#include\\s+\"([\\w.\\/]*)\""; + public static string GlobalDirectivesPattern = "[#]+(define|pragma|include)\\s+([\\w .\\/\\\"]*)"; + public static string BeforePragmaPattern = @"(?:CGPROGRAM|HLSLPROGRAM|GLSLPROGRAM).*?\n(\s*)(.)"; + public static string GlobalTOPDirectivesPattern = @"(CGPROGRAM|CGINCLUDE|HLSLPROGRAM|HLSLINCLUDE).*?\n\s*(.)"; + + public static string VertexPragmaPattern = @"#pragma vertex\s+(\w+)"; + public static string FragmentPragmaPattern = @"#pragma fragment\s+(\w+)"; + public static string FunctionBodyStartPattern = @"\s+{0}\s*\("; + + public static string ShaderModelPattern = @"#pragma\s+target\s+([0-9]*[.]*[0-9]*)"; + + public static readonly string LocalVarPattern = @"\/\*ase_local_var[:]*(\w*)\*\/\s*(\w*)\s+(\w*)"; + + public static readonly string InlinePattern = @"\/\*ase_inline_begin\*\/(.*?)\/\*ase_inline_end\*\/"; + + public static readonly string SubShaderLODPattern = @"\sLOD\s+(\d+)"; + + public static readonly string PassNamePattern = "Name\\s+\\\"([\\w\\+\\-\\*\\/\\(\\) ]*)\\\""; + + public static readonly string TagsPattern = "\"(\\w+)\"\\s*=\\s*\"(\\w+\\+*\\w*)\""; + public static readonly string ZTestPattern = @"^\s*ZTest\s+(\[*\w+\]*)"; + public static readonly string ZWritePattern = @"^\s*ZWrite\s+(\[*\w+\]*)"; + //public static readonly string ZOffsetPattern = @"\s*Offset\s+([-+]?[0-9]*\.?[0-9]+)\s*,\s*([-+]?[0-9]*\.?[0-9]+)"; + public static readonly string ZOffsetPattern = @"^\s*Offset\s+([-+]?[0-9]*\.?[0-9]+|\[*\w+\]*)\s*,\s*([-+]?[0-9]*\.?[0-9]+|\[*\w+\]*)\s*"; + public static readonly string VertexDataPattern = @"(\w+)\s*(\w+)\s*:\s*([A-Z0-9_]+);"; + public static readonly string InterpRangePattern = @"ase_interp\((\d\.{0,1}\w{0,4}),(\d*)\)"; + //public static readonly string PropertiesPatternB = "(\\w*)\\s*\\(\\s*\"([\\w ]*)\"\\s*\\,\\s*(\\w*)\\s*.*\\)"; + //public static readonly string PropertiesPatternC = "^\\s*(\\w*)\\s*\\(\\s*\"([\\w\\(\\)\\+\\-\\\\* ]*)\"\\s*\\,\\s*(\\w*)\\s*.*\\)"; + //public static readonly string PropertiesPatternD = "(\\/\\/\\s*)*(\\w*)\\s*\\(\\s*\"([\\w\\(\\)\\+\\-\\\\* ]*)\"\\s*\\,\\s*(\\w*)\\s*.*\\)"; + //public static readonly string PropertiesPatternE = "(\\/\\/\\s*)*(\\w*)\\s*\\(\\s*\"([\\w\\(\\)\\+\\-\\\\* ]*)\"\\s*\\,\\s*(\\w*)\\s*.*\\)\\s*=\\s*[\\w,()\" {}]*"; + //public static readonly string PropertiesPatternF = "^(\\/\\/)*\\s*(\\[[\\[\\]\\w\\s\\(\\)\\_\\,]*\\])*\\s*(\\w*)\\s*\\(\\s*\"([\\w\\(\\)\\+\\-\\\\* ]*)\"\\s*\\,\\s*(\\w*)\\s*.*\\)\\s*=\\s*[\\w,()\" {}]*"; + //public static readonly string PropertiesPatternG = "^(\\s*)(\\[[\\[\\]\\w\\s\\(\\)\\_\\,]*\\])*\\s*(\\w*)\\s*\\(\\s*\"([\\w\\(\\)\\+\\-\\\\* ]*)\"\\s*\\,\\s*(\\w*)\\s*.*\\)\\s*=\\s*[\\w,()\" {}]*"; + public static readonly string PropertiesPatternG = "^(\\s*)(\\[[\\[\\]\\w\\s\\(\\)_,\\.]*\\])*\\s*(\\w*)\\s*\\(\\s*\"([\\w\\(\\)\\+\\-\\\\* ]*)\"\\s*\\,\\s*(\\w*)\\s*.*\\)\\s*=\\s*[\\w,()\" {}\\.]*"; + public static readonly string CullModePattern = @"^\s*Cull\s+(\[*\w+\]*)"; + public static readonly string ColorMaskPattern = @"^\s*ColorMask\s+([\d\w\[\]]+)(\s*\d)*"; + //public static readonly string BlendModePattern = @"\s*Blend\s+(\w+)\s+(\w+)(?:[\s,]+(\w+)\s+(\w+)|)"; + //public static readonly string BlendModePattern = @"\s*Blend\s+(\[*\w+\]*)\s+(\[*\w+\]*)(?:[\s,]+(\[*\w+\]*)\s+(\[*\w+\]*)|)"; + public static readonly string BlendModePattern = @"^\s*Blend\s+(?:(?=\d)|(\[*\w+\]*)\s+(\[*\w+\]*)(?:[\s,]+(\[*\w+\]*)\s+(\[*\w+\]*)|))"; + //public static readonly string BlendOpPattern = @"\s*BlendOp\s+(\w+)[\s,]*(?:(\w+)|)"; + //public static readonly string BlendOpPattern = @"\s*BlendOp\s+(\[*\w+\]*)[\s,]*(?:(\[*\w+\]*)|)"; + public static readonly string BlendOpPattern = @"^\s*BlendOp\s+(?:(?=\d)|(\[*\w+\]*)[\s,]*(?:(\[*\w+\]*)|))"; + + public static readonly string StencilOpGlobalPattern = @"Stencil\s*{([\w\W\s]*)}"; + public static readonly string StencilOpLinePattern = @"(\w+)\s*(\[*\w+\]*)"; + + public static readonly string ShaderGlobalsOverallPattern = "(?:\\/\\*ase_pragma\\*\\/|[\\}\\#])[\\w\\s\\;\\/\\*\\.\\\"]*\\/\\*ase_globals\\*\\/"; + public static readonly string ShaderGlobalsMultilinePattern = @"^\s*(?:uniform\s*)*(\w*)\s*(\w*);$"; + + public static readonly string TexSemantic = "float4 {0} : TEXCOORD{1};"; + public static readonly string TexFullSemantic = "float4 {0} : {1};"; + public static readonly string InterpFullSemantic = "{0} {1} : {2};"; + public static readonly string BaseInterpolatorName = "ase_texcoord"; + public static readonly string TexUVFullSemantic = "float4 ase_texcoord{0} : TEXCOORD{0};"; + public static readonly string InterpMacro = "{0}({1})"; + + public static readonly string InterpolatorDecl = Constants.VertexShaderOutputStr + ".{0} = " + Constants.VertexShaderInputStr + ".{0};"; + public static readonly string TemplateVariableDecl = "{0} = {1};"; + public static readonly string TemplateVarFormat = "{0}.{1}"; + + //public static readonly string StructsRemoval = @"struct\s+\w+\s+{[\s\w;\/\*]+};"; + public static readonly string StructsRemoval = @"struct\s+\w+\s+{[\s\w\(\).;:=,\/\*]+};"; + + public static readonly string SRPBatcherFindTag = @"CBUFFER_START\s*\(\s*UnityPerMaterial\s*\)\s*\n(\s*)"; + + public static string ReplaceAt( this string body, string oldStr, string newStr, int startIndex ) + { + return body.Remove( startIndex, oldStr.Length ).Insert( startIndex, newStr ); + } + + public static bool GetPassUniqueId( TemplateTagData tagData, TemplatePropertyContainer propertyContainer, TemplateIdManager idManager, string uniquePrefix, int offsetIdx, string subBody, ref string passUniqueID ) + { + Match match = Regex.Match( subBody, ASEPassPattern ); + if( match.Success && match.Groups.Count > 1 && match.Groups[1].Length > 0 ) + { + passUniqueID = match.Groups[ 1 ].Value; + + tagData.StartIdx = offsetIdx + match.Index; + tagData.Id = match.Value; + + idManager.RegisterId( tagData.StartIdx, uniquePrefix + tagData.Id, tagData.Id ); + propertyContainer.AddId( subBody, tagData.Id, tagData.SearchIndentation ); + return true; + } + return false; + } + + public static CustomTemplatePropertyUIEnum FetchCustomUI( string data ) + { + Match match = Regex.Match( data, TemplateCustomUI ); + if( match.Success && CustomTemplatePropertyUI.ContainsKey( match.Groups[ 1 ].Value ) ) + { + return CustomTemplatePropertyUI[ match.Groups[ 1 ].Value ]; + } + return CustomTemplatePropertyUIEnum.None; + } + + public static bool FetchInvisibleInfo( string input, ref int optionsArr, ref string id, ref int idIndex ) + { + Match match = Regex.Match( input, HidePassPattern ); + if( match.Success ) + { + id = match.Value; + idIndex = match.Index; + if( match.Groups.Count > 1 ) + { + string[] properties = match.Groups[ 1 ].Value.Split( ':' ); + for( int i = 0; i < properties.Length; i++ ) + { + if( InvisibleOptions.ContainsKey( properties[ i ] ) ) + { + optionsArr |= (int)InvisibleOptions[ properties[ i ] ]; + } + } + } + } + return match.Success; + } + + static public string GenerateTextureSemantic( ref MasterNodeDataCollector dataCollector, int uv ) + { + string texCoordName = BaseInterpolatorName; + if( uv > 0 ) + { + texCoordName += uv.ToString(); + } + + string texCoordData = string.Format( TexSemantic, texCoordName, uv ); + dataCollector.AddToVertexInput( texCoordData ); + dataCollector.AddToInterpolators( texCoordData ); + dataCollector.AddToVertexInterpolatorsDecl( string.Format( InterpolatorDecl, texCoordName ) ); + return texCoordName; + } + + public static void CreatePragmaIncludeList( string data, TemplateIncludePragmaContainter includePragmaContainer ) + { + // this finds the topmost position for including directives + int topIndex = -1; + foreach( Match match in Regex.Matches( data, GlobalTOPDirectivesPattern, RegexOptions.Singleline ) ) + { + if( match.Groups.Count == 3 ) + { + topIndex = match.Groups[ 2 ].Index; + } + } + + foreach( Match match in Regex.Matches( data, GlobalDirectivesPattern, RegexOptions.Multiline ) ) + { + if( match.Success ) + { + includePragmaContainer.AddNativeDirective( match.Groups[ 0 ].Value, topIndex ); + } + } + + foreach( Match match in Regex.Matches( data, PragmasPattern, RegexOptions.Multiline ) ) + { + if( match.Groups.Count == 2 ) + { + includePragmaContainer.AddPragma( match.Groups[ 1 ].Value ); + } + } + + foreach( Match match in Regex.Matches( data, DefinesPattern, RegexOptions.Multiline ) ) + { + if( match.Groups.Count == 2 ) + { + includePragmaContainer.AddDefine( match.Groups[ 1 ].Value ); + } + } + + foreach( Match match in Regex.Matches( data, IncludesPattern, RegexOptions.Multiline ) ) + { + if( match.Groups.Count == 2 ) + { + includePragmaContainer.AddInclude( match.Groups[ 1 ].Value ); + } + } + } + + public static void CreateShaderPropertiesList( string propertyData, ref List<TemplateShaderPropertyData> propertiesList, ref Dictionary<string, TemplateShaderPropertyData> duplicatesHelper ) + { + int identationIdx = (int)TemplateShaderPropertiesIdx.Identation; + int nameIdx = (int)TemplateShaderPropertiesIdx.Name; + int typeIdx = (int)TemplateShaderPropertiesIdx.Type; + int inspectorNameIdx = (int)TemplateShaderPropertiesIdx.InspectorName; + + foreach( Match match in Regex.Matches( propertyData, PropertiesPatternG,RegexOptions.Multiline ) ) + { + if( match.Groups.Count > 1 ) + { + if( !duplicatesHelper.ContainsKey( match.Groups[ nameIdx ].Value ) && PropertyToWireType.ContainsKey( match.Groups[ typeIdx ].Value ) ) + { + TemplateShaderPropertyData newData = new TemplateShaderPropertyData( match.Index, + match.Value, + match.Groups[ identationIdx ].Value, + match.Groups[ inspectorNameIdx ].Value, + match.Groups[ nameIdx ].Value, + PropertyToWireType[ match.Groups[ typeIdx ].Value ], + PropertyType.Property ); + propertiesList.Add( newData ); + duplicatesHelper.Add( newData.PropertyName, newData ); + } + } + } + } + + public static void CreateShaderGlobalsList( string propertyData, ref List<TemplateShaderPropertyData> propertiesList, ref Dictionary<string, TemplateShaderPropertyData> duplicatesHelper ) + { + int typeIdx = (int)TemplateShaderGlobalsIdx.Type; + int nameIdx = (int)TemplateShaderGlobalsIdx.Name; + + // removes structs + propertyData = Regex.Replace( propertyData, StructsRemoval, "" ); + MatchCollection matchCollection = Regex.Matches( propertyData, ShaderGlobalsOverallPattern ); + string value = ( matchCollection.Count > 0 ) ? matchCollection[ 0 ].Groups[ 0 ].Value : propertyData; + foreach( Match lineMatch in Regex.Matches( value, ShaderGlobalsMultilinePattern, RegexOptions.Multiline ) ) + { + if( lineMatch.Groups.Count > 1 ) + { + if( !duplicatesHelper.ContainsKey( lineMatch.Groups[ nameIdx ].Value ) && CgToWirePortType.ContainsKey( lineMatch.Groups[ typeIdx ].Value ) ) + { + TemplateShaderPropertyData newData = new TemplateShaderPropertyData( -1, + string.Empty, + string.Empty, + string.Empty, + lineMatch.Groups[ nameIdx ].Value, + CgToWirePortType[ lineMatch.Groups[ typeIdx ].Value ], + PropertyType.Global ); + duplicatesHelper.Add( newData.PropertyName, newData ); + propertiesList.Add( newData ); + } + } + } + } + + public static void CreateStencilOps( string stencilData, ref TemplateStencilData stencilDataObj ) + { + stencilDataObj.DataCheck = TemplateDataCheck.Invalid; + MatchCollection overallGlobalMatch = Regex.Matches( stencilData, StencilOpGlobalPattern ); + if( overallGlobalMatch.Count == 1 && overallGlobalMatch[ 0 ].Groups.Count == 2 ) + { + string property = string.Empty; + string value = overallGlobalMatch[ 0 ].Groups[ 1 ].Value; + foreach( Match match in Regex.Matches( value, StencilOpLinePattern ) ) + { + stencilDataObj.DataCheck = TemplateDataCheck.Valid; + if( match.Groups.Count == 3 ) + { + switch( match.Groups[ 1 ].Value ) + { + default: + { + stencilDataObj.DataCheck = TemplateDataCheck.Invalid; + return; + } + case "Ref": + { + if( match.Groups[ 2 ].Success && IsInlineProperty( match.Groups[ 2 ].Value, ref property ) ) + { + stencilDataObj.ReferenceInline = property; + } + else + { + try + { + stencilDataObj.Reference = Convert.ToInt32( match.Groups[ 2 ].Value ); + } + catch( Exception e ) + { + Debug.LogException( e ); + stencilDataObj.DataCheck = TemplateDataCheck.Invalid; + return; + } + } + } + break; + case "ReadMask": + { + if( match.Groups[ 2 ].Success && IsInlineProperty( match.Groups[ 2 ].Value, ref property ) ) + { + stencilDataObj.ReadMaskInline = property; + } + else + { + try + { + stencilDataObj.ReadMask = Convert.ToInt32( match.Groups[ 2 ].Value ); + } + catch( Exception e ) + { + Debug.LogException( e ); + stencilDataObj.DataCheck = TemplateDataCheck.Invalid; + return; + } + } + } + break; + case "WriteMask": + { + if( match.Groups[ 2 ].Success && IsInlineProperty( match.Groups[ 2 ].Value, ref property ) ) + { + stencilDataObj.WriteMaskInline = property; + } + else + { + try + { + stencilDataObj.WriteMask = Convert.ToInt32( match.Groups[ 2 ].Value ); + } + catch( Exception e ) + { + Debug.LogException( e ); + stencilDataObj.DataCheck = TemplateDataCheck.Invalid; + return; + } + } + } + break; + case "CompFront": + case "Comp": + { + if( match.Groups[ 2 ].Success && IsInlineProperty( match.Groups[ 2 ].Value, ref property ) ) + { + stencilDataObj.ComparisonFrontInline = property; + } + else + { + stencilDataObj.ComparisonFront = match.Groups[ 2 ].Value; + } + } + break; + case "PassFront": + case "Pass": + { + if( match.Groups[ 2 ].Success && IsInlineProperty( match.Groups[ 2 ].Value, ref property ) ) + { + stencilDataObj.PassFrontInline = property; + } + else + { + stencilDataObj.PassFront = match.Groups[ 2 ].Value; + } + } + break; + case "FailFront": + case "Fail": + { + if( match.Groups[ 2 ].Success && IsInlineProperty( match.Groups[ 2 ].Value, ref property ) ) + { + stencilDataObj.FailFrontInline = property; + } + else + { + stencilDataObj.FailFront = match.Groups[ 2 ].Value; + } + } + break; + case "ZFail": + case "ZFailFront": + { + if( match.Groups[ 2 ].Success && IsInlineProperty( match.Groups[ 2 ].Value, ref property ) ) + { + stencilDataObj.ZFailFrontInline = property; + } + else + { + stencilDataObj.ZFailFront = match.Groups[ 2 ].Value; + } + } + break; + case "CompBack": + { + if( match.Groups[ 2 ].Success && IsInlineProperty( match.Groups[ 2 ].Value, ref property ) ) + { + stencilDataObj.ComparisonBackInline = property; + } + else + { + stencilDataObj.ComparisonBack = match.Groups[ 2 ].Value; + } + } + break; + case "PassBack": + { + if( match.Groups[ 2 ].Success && IsInlineProperty( match.Groups[ 2 ].Value, ref property ) ) + { + stencilDataObj.PassBackInline = property; + } + else + { + stencilDataObj.PassBack = match.Groups[ 2 ].Value; + } + } + break; + case "FailBack": + { + if( match.Groups[ 2 ].Success && IsInlineProperty( match.Groups[ 2 ].Value, ref property ) ) + { + stencilDataObj.FailBackInline = property; + } + else + { + stencilDataObj.FailBack = match.Groups[ 2 ].Value; + } + } + break; + case "ZFailBack": + { + if( match.Groups[ 2 ].Success && IsInlineProperty( match.Groups[ 2 ].Value, ref property ) ) + { + stencilDataObj.ZFailBackInline = property; + } + else + { + stencilDataObj.ZFailBack = match.Groups[ 2 ].Value; + } + } + break; + } + } + } + } + } + + public static void CreateColorMask( string colorMaskData, ref TemplateColorMaskData colorMaskObj ) + { + colorMaskObj.DataCheck = TemplateDataCheck.Invalid; + Match match = Regex.Match( colorMaskData, ColorMaskPattern ); + if( match.Groups.Count == 3 && !match.Groups[ 2 ].Success ) // second group is the colormask MRT which isn't implemented yet + { + string property = string.Empty; + if( match.Groups[ 1 ].Success && IsInlineProperty( match.Groups[ 1 ].Value, ref property ) ) + { + colorMaskObj.InlineData = property; + colorMaskObj.DataCheck = TemplateDataCheck.Valid; + } + else + { + for( int i = 0; i < 4; i++ ) + { + colorMaskObj.ColorMaskData[ i ] = false; + } + + colorMaskObj.DataCheck = TemplateDataCheck.Valid; + try + { + for( int i = 0; i < match.Groups[ 1 ].Value.Length; i++ ) + { + switch( Char.ToLower( match.Groups[ 1 ].Value[ i ] ) ) + { + case 'r': colorMaskObj.ColorMaskData[ 0 ] = true; break; + case 'g': colorMaskObj.ColorMaskData[ 1 ] = true; break; + case 'b': colorMaskObj.ColorMaskData[ 2 ] = true; break; + case 'a': colorMaskObj.ColorMaskData[ 3 ] = true; break; + case '0': + { + for( int j = 0; j < 4; j++ ) + { + colorMaskObj.ColorMaskData[ j ] = false; + } + return; + } + default: + { + colorMaskObj.DataCheck = TemplateDataCheck.Invalid; + return; + } + } + } + } + catch( Exception e ) + { + Debug.LogException( e ); + colorMaskObj.DataCheck = TemplateDataCheck.Invalid; + return; + } + } + } + } + + public static void CreateCullMode( string cullModeData, ref TemplateCullModeData cullDataObj ) + { + cullDataObj.DataCheck = TemplateDataCheck.Invalid; + Match match = Regex.Match( cullModeData, CullModePattern ); + if( match.Groups.Count == 2 ) + { + string property = string.Empty; + if( match.Groups[ 1 ].Success && IsInlineProperty( match.Groups[ 1 ].Value, ref property ) ) + { + cullDataObj.InlineData = property; + cullDataObj.DataCheck = TemplateDataCheck.Valid; + } + else + { + try + { + cullDataObj.CullModeData = (CullMode)Enum.Parse( typeof( CullMode ), match.Groups[ 1 ].Value ); + cullDataObj.DataCheck = TemplateDataCheck.Valid; + } + catch( Exception e ) + { + cullDataObj.DataCheck = TemplateDataCheck.Invalid; + Debug.LogException( e ); + return; + } + } + } + } + + public static void CreateBlendMode( string blendModeData, ref TemplateBlendData blendDataObj ) + { + blendDataObj.ValidBlendMode = true; + string property = string.Empty; + bool noMatches = true; + // TODO: OPTIMIZE REGEX EXPRESSIONS TO NOT CATCH EMPTY GROUPS + foreach( Match match in Regex.Matches( blendModeData, BlendModePattern ) ) + { + + if( match.Groups.Count == 3 ) + { + if( match.Groups[ 0 ].Success && + match.Groups[ 1 ].Success ) + { + + try + { + if( IsInlineProperty( match.Groups[ 1 ].Value, ref property ) ) + { + blendDataObj.SourceFactorRGBInline = property; + } + else + { + AvailableBlendFactor sourceAll = (AvailableBlendFactor)Enum.Parse( typeof( AvailableBlendFactor ), match.Groups[ 1 ].Value ); + blendDataObj.SourceFactorRGB = sourceAll; + } + if( match.Groups[ 2 ].Success && IsInlineProperty( match.Groups[ 2 ].Value, ref property ) ) + { + blendDataObj.DestFactorRGBInline = property; + } + else + { + AvailableBlendFactor destAll = (AvailableBlendFactor)Enum.Parse( typeof( AvailableBlendFactor ), match.Groups[ 2 ].Value ); + blendDataObj.DestFactorRGB = destAll; + } + + blendDataObj.SeparateBlendFactors = false; + blendDataObj.BlendModeOff = false; + noMatches = false; + } + catch( Exception e ) + { + Debug.LogException( e ); + blendDataObj.DataCheck = TemplateDataCheck.Invalid; + blendDataObj.ValidBlendMode = false; + return; + } + break; + } + } + else if( match.Groups.Count == 5 ) + { + if( match.Groups[ 0 ].Success && + match.Groups[ 1 ].Success ) + { + try + { + if( IsInlineProperty( match.Groups[ 1 ].Value, ref property ) ) + { + blendDataObj.SourceFactorRGBInline = property; + } + else + { + AvailableBlendFactor sourceRGB = (AvailableBlendFactor)Enum.Parse( typeof( AvailableBlendFactor ), match.Groups[ 1 ].Value ); + blendDataObj.SourceFactorRGB = sourceRGB; + } + + if( match.Groups[ 2 ].Success && IsInlineProperty( match.Groups[ 2 ].Value, ref property ) ) + { + blendDataObj.DestFactorRGBInline = property; + } + else + { + AvailableBlendFactor destRGB = (AvailableBlendFactor)Enum.Parse( typeof( AvailableBlendFactor ), match.Groups[ 2 ].Value ); + blendDataObj.DestFactorRGB = destRGB; + } + + if( match.Groups[ 3 ].Success && match.Groups[ 4 ].Success ) + { + if( IsInlineProperty( match.Groups[ 3 ].Value, ref property ) ) + { + blendDataObj.SourceFactorAlphaInline = property; + } + else + { + AvailableBlendFactor sourceA = (AvailableBlendFactor)Enum.Parse( typeof( AvailableBlendFactor ), match.Groups[ 3 ].Value ); + blendDataObj.SourceFactorAlpha = sourceA; + } + + if( IsInlineProperty( match.Groups[ 4 ].Value, ref property ) ) + { + blendDataObj.DestFactorAlphaInline = property; + } + else + { + AvailableBlendFactor destA = (AvailableBlendFactor)Enum.Parse( typeof( AvailableBlendFactor ), match.Groups[ 4 ].Value ); + blendDataObj.DestFactorAlpha = destA; + } + + blendDataObj.SeparateBlendFactors = true; + } + else + { + blendDataObj.SeparateBlendFactors = false; + } + blendDataObj.BlendModeOff = false; + noMatches = false; + } + catch( Exception e ) + { + Debug.LogException( e ); + blendDataObj.DataCheck = TemplateDataCheck.Invalid; + blendDataObj.ValidBlendMode = false; + return; + } + break; + } + } + } + + if( noMatches ) + blendDataObj.ValidBlendMode = false; + } + + public static void CreateBlendOp( string blendOpData, ref TemplateBlendData blendDataObj ) + { + bool noMatches = true; + blendDataObj.ValidBlendOp = true; + string property = string.Empty; + // TODO: OPTIMIZE REGEX EXPRESSIONS TO NOT CATCH EMPTY GROUPS + foreach( Match match in Regex.Matches( blendOpData, BlendOpPattern, RegexOptions.None ) ) + { + if( match.Groups.Count == 2 ) + { + if( match.Groups[ 0 ].Success && + match.Groups[ 1 ].Success ) + { + + try + { + if( IsInlineProperty( match.Groups[ 1 ].Value, ref property ) ) + { + blendDataObj.BlendOpRGBInline = property; + } + else + { + AvailableBlendOps blendOpsAll = (AvailableBlendOps)Enum.Parse( typeof( AvailableBlendOps ), match.Groups[ 1 ].Value ); + blendDataObj.BlendOpRGB = blendOpsAll; + } + blendDataObj.SeparateBlendOps = false; + noMatches = false; + } + catch( Exception e ) + { + Debug.LogException( e ); + blendDataObj.DataCheck = TemplateDataCheck.Invalid; + blendDataObj.ValidBlendOp = false; + return; + } + break; + } + } + else if( match.Groups.Count == 3 ) + { + if( match.Groups[ 0 ].Success && + match.Groups[ 1 ].Success ) + { + try + { + if( IsInlineProperty( match.Groups[ 1 ].Value, ref property ) ) + { + blendDataObj.BlendOpRGBInline = property; + } + else + { + AvailableBlendOps blendOpsRGB = (AvailableBlendOps)Enum.Parse( typeof( AvailableBlendOps ), match.Groups[ 1 ].Value ); + blendDataObj.BlendOpRGB = blendOpsRGB; + } + + if( match.Groups[ 2 ].Success ) + { + if( IsInlineProperty( match.Groups[ 2 ].Value, ref property ) ) + { + blendDataObj.BlendOpAlphaInline = property; + } + else + { + AvailableBlendOps blendOpsA = (AvailableBlendOps)Enum.Parse( typeof( AvailableBlendOps ), match.Groups[ 2 ].Value ); + blendDataObj.BlendOpAlpha = blendOpsA; + } + blendDataObj.SeparateBlendOps = true; + } + else + { + blendDataObj.SeparateBlendOps = false; + } + noMatches = false; + } + catch( Exception e ) + { + Debug.LogException( e ); + blendDataObj.DataCheck = TemplateDataCheck.Invalid; + blendDataObj.ValidBlendOp = false; + return; + } + break; + } + } + } + + if( noMatches ) + blendDataObj.ValidBlendOp = false; + } + + public static void FetchLocalVars( string body, ref List<TemplateLocalVarData> localVarList, TemplateFunctionData vertexFunction, TemplateFunctionData fragFunction ) + { + foreach( Match match in Regex.Matches( body, LocalVarPattern ) ) + { + if( match.Groups.Count == 4 ) + { + if( CgToWirePortType.ContainsKey( match.Groups[ 2 ].Value ) ) + { + MasterNodePortCategory category; + if( fragFunction.MainBodyLocalIdx > vertexFunction.MainBodyLocalIdx ) + { + if( match.Index < fragFunction.MainBodyLocalIdx ) + { + category = MasterNodePortCategory.Vertex; + } + else + { + category = MasterNodePortCategory.Fragment; + } + } + else + { + if( match.Index < vertexFunction.MainBodyLocalIdx ) + { + category = MasterNodePortCategory.Fragment; + } + else + { + category = MasterNodePortCategory.Vertex; + } + } + + if( !string.IsNullOrEmpty( match.Groups[ 1 ].Value ) && ShortcutToInfo.ContainsKey( match.Groups[ 1 ].Value ) ) + { + string id = match.Groups[ 0 ].Value.Substring( 0, match.Groups[ 0 ].Value.IndexOf( "*/" ) + 2 ); + TemplateLocalVarData data = new TemplateLocalVarData( ShortcutToInfo[ match.Groups[ 1 ].Value ], id, CgToWirePortType[ match.Groups[ 2 ].Value ], category, match.Groups[ 3 ].Value, match.Index ); + localVarList.Add( data ); + } + else + { + TemplateLocalVarData data = new TemplateLocalVarData( CgToWirePortType[ match.Groups[ 2 ].Value ], category, match.Groups[ 3 ].Value, match.Index ); + localVarList.Add( data ); + } + + } + } + } + } + + public static void FetchInlineVars( string body, ref TemplateIdManager idManager ) + { + foreach( Match match in Regex.Matches( body, InlinePattern ) ) + { + if( match.Success && match.Groups.Count == 2 ) + { + string id = match.Groups[ 0 ].Value; + string prop = match.Groups[ 1 ].Value; + idManager.RegisterTag( id, prop ); + } + } + } + + public static TemplateSRPType CreateTags( ref TemplateTagsModuleData tagsObj, bool isSubShader ) + { + TemplateSRPType srpType = TemplateSRPType.BuiltIn; + MatchCollection matchColl = Regex.Matches( tagsObj.TagsId, TagsPattern, RegexOptions.IgnorePatternWhitespace ); + int count = matchColl.Count; + if( count > 0 ) + { + for( int i = 0; i < count; i++ ) + { + if( matchColl[ i ].Groups.Count == 3 ) + { + if( isSubShader && matchColl[ i ].Groups[ 1 ].Value.Equals( "RenderPipeline" ) ) + { + if( TagToRenderPipeline.ContainsKey( matchColl[ i ].Groups[ 2 ].Value ) ) + srpType = TagToRenderPipeline[ matchColl[ i ].Groups[ 2 ].Value ]; + } + tagsObj.Tags.Add( new TemplatesTagData( matchColl[ i ].Groups[ 1 ].Value, matchColl[ i ].Groups[ 2 ].Value ) ); + } + } + } + return srpType; + } + + public static void CreateZWriteMode( string zWriteData, ref TemplateDepthData depthDataObj ) + { + depthDataObj.DataCheck = TemplateDataCheck.Invalid; + Match match = Regex.Match( zWriteData, ZWritePattern ); + if( match.Groups.Count == 2 ) + { + string property = string.Empty; + if( match.Groups[ 1 ].Success && IsInlineProperty( match.Groups[ 1 ].Value, ref property ) ) + { + depthDataObj.ZWriteInlineValue = property; + depthDataObj.DataCheck = TemplateDataCheck.Valid; + depthDataObj.ValidZWrite = true; + } + else + { + try + { + depthDataObj.ZWriteModeValue = (ZWriteMode)Enum.Parse( typeof( ZWriteMode ), match.Groups[ 1 ].Value ); + depthDataObj.DataCheck = TemplateDataCheck.Valid; + depthDataObj.ValidZWrite = true; + } + catch + { + depthDataObj.DataCheck = TemplateDataCheck.Invalid; + } + } + } + } + + public static void CreateZTestMode( string zTestData, ref TemplateDepthData depthDataObj ) + { + depthDataObj.DataCheck = TemplateDataCheck.Invalid; + Match match = Regex.Match( zTestData, ZTestPattern ); + if( match.Groups.Count == 2 ) + { + string property = string.Empty; + if( match.Groups[ 1 ].Success && IsInlineProperty( match.Groups[ 1 ].Value, ref property ) ) + { + depthDataObj.ZTestInlineValue = property; + depthDataObj.DataCheck = TemplateDataCheck.Valid; + depthDataObj.ValidZTest = true; + } + else + { + try + { + depthDataObj.ZTestModeValue = (ZTestMode)Enum.Parse( typeof( ZTestMode ), match.Groups[ 1 ].Value ); + depthDataObj.DataCheck = TemplateDataCheck.Valid; + depthDataObj.ValidZTest = true; + } + catch + { + depthDataObj.DataCheck = TemplateDataCheck.Invalid; + } + } + } + } + + public static void CreateZOffsetMode( string zOffsetData, ref TemplateDepthData depthDataObj ) + { + depthDataObj.DataCheck = TemplateDataCheck.Invalid; + Match match = Regex.Match( zOffsetData, ZOffsetPattern ); + if( match.Groups.Count == 3 ) + { + try + { + string property = string.Empty; + + if( match.Groups[ 1 ].Success && IsInlineProperty( match.Groups[ 1 ].Value, ref property ) ) + { + depthDataObj.OffsetFactorInlineValue = property; + } + else + { + depthDataObj.OffsetFactor = Convert.ToSingle( match.Groups[ 1 ].Value ); + } + + if( match.Groups[ 2 ].Success && IsInlineProperty( match.Groups[ 2 ].Value, ref property ) ) + { + depthDataObj.OffsetUnitsInlineValue = property; + } + else + { + depthDataObj.OffsetUnits = Convert.ToSingle( match.Groups[ 2 ].Value ); + } + + depthDataObj.ValidOffset = true; + depthDataObj.DataCheck = TemplateDataCheck.Valid; + } + catch + { + depthDataObj.DataCheck = TemplateDataCheck.Invalid; + } + } + } + + public static List<TemplateVertexData> CreateVertexDataList( string vertexData, string parametersBody ) + { + List<TemplateVertexData> vertexDataList = null; + Dictionary<TemplateSemantics, TemplateVertexData> vertexDataDict = null; + + foreach( Match match in Regex.Matches( vertexData, VertexDataPattern ) ) + { + if( match.Groups.Count > 1 ) + { + if( vertexDataList == null ) + { + vertexDataList = new List<TemplateVertexData>(); + vertexDataDict = new Dictionary<TemplateSemantics, TemplateVertexData>(); + } + + WirePortDataType dataType = CgToWirePortType[ match.Groups[ 1 ].Value ]; + string varName = match.Groups[ 2 ].Value; + TemplateSemantics semantics = (TemplateSemantics)Enum.Parse( typeof( TemplateSemantics ), match.Groups[ 3 ].Value ); + TemplateVertexData templateVertexData = new TemplateVertexData( semantics, dataType, varName ); + vertexDataList.Add( templateVertexData ); + vertexDataDict.Add( semantics, templateVertexData ); + } + } + + if( vertexData.Contains( Constants.InstanceIdMacro ) ) + { + TemplateVertexData templateVertexData = new TemplateVertexData( TemplateSemantics.SV_InstanceID, WirePortDataType.UINT, Constants.InstanceIdVariable ); + templateVertexData.DataInfo = TemplateInfoOnSematics.INSTANCE_ID; + templateVertexData.Available = true; + templateVertexData.ExcludeStructPrefix = true; + + vertexDataList.Add( templateVertexData ); + vertexDataDict.Add( TemplateSemantics.SV_InstanceID, templateVertexData ); + } + + if( !string.IsNullOrEmpty( parametersBody ) ) + { + string[] paramsArray = parametersBody.Split( IOUtils.FIELD_SEPARATOR ); + if( paramsArray.Length > 0 ) + { + for( int i = 0; i < paramsArray.Length; i++ ) + { + string[] paramDataArr = paramsArray[ i ].Split( IOUtils.VALUE_SEPARATOR ); + if( paramDataArr.Length == 2 ) + { + string[] swizzleInfoArr = paramDataArr[ 1 ].Split( IOUtils.FLOAT_SEPARATOR ); + TemplateSemantics semantic = ShortcutToSemantic[ swizzleInfoArr[ 0 ] ]; + if( vertexDataDict.ContainsKey( semantic ) ) + { + TemplateVertexData templateVertexData = vertexDataDict[ semantic ]; + if( templateVertexData != null ) + { + if( swizzleInfoArr.Length > 1 ) + { + templateVertexData.DataSwizzle = "." + swizzleInfoArr[ 1 ]; + } + templateVertexData.DataInfo = ShortcutToInfo[ paramDataArr[ 0 ] ]; + templateVertexData.Available = true; + } + } + } + } + } + } + + if( vertexDataDict != null ) + { + vertexDataDict.Clear(); + vertexDataDict = null; + } + + return vertexDataList; + } + + public static TemplateInterpData CreateInterpDataList( string interpData, string fullLine, int maxInterpolators ) + { + TemplateInterpData interpDataObj = null; + List<TemplateVertexData> interpDataList = null; + Dictionary<TemplateSemantics, TemplateVertexData> interpDataDict = null; + Match rangeMatch = Regex.Match( fullLine, InterpRangePattern ); + if( rangeMatch.Groups.Count > 0 ) + { + interpDataObj = new TemplateInterpData(); + // Get range of available interpolators + int minVal = 0; + int maxVal = 0; + try + { + string[] minValArgs = rangeMatch.Groups[ 1 ].Value.Split( IOUtils.FLOAT_SEPARATOR ); + minVal = Convert.ToInt32( minValArgs[ 0 ] ); + if( string.IsNullOrEmpty( rangeMatch.Groups[ 2 ].Value ) ) + { + maxVal = maxInterpolators - 1; + interpDataObj.DynamicMax = true; + } + else + { + maxVal = Convert.ToInt32( rangeMatch.Groups[ 2 ].Value ); + } + if( minVal > maxVal ) + { + //int aux = minVal; + //minVal = maxVal; + //maxVal = aux; + maxVal = minVal; + } + + for( int i = minVal; i <= maxVal; i++ ) + { + interpDataObj.AvailableInterpolators.Add( new TemplateInterpElement( IntToSemantic[ i ] ) ); + } + if( minValArgs.Length > 1 ) + { + interpDataObj.AvailableInterpolators[ 0 ].SetAvailableChannelsFromString( minValArgs[ 1 ] ); + } + } + catch( Exception e ) + { + Debug.LogException( e ); + } + + interpDataList = new List<TemplateVertexData>(); + interpDataDict = new Dictionary<TemplateSemantics, TemplateVertexData>(); + + //Get Current interpolators + int parametersBeginIdx = fullLine.IndexOf( ":" ) + 1; + int parametersEnd = fullLine.IndexOf( TemplatesManager.TemplateEndOfLine ); + string parametersBody = fullLine.Substring( parametersBeginIdx, parametersEnd - parametersBeginIdx ); + + foreach( Match match in Regex.Matches( interpData, VertexDataPattern ) ) + { + if( match.Groups.Count > 1 ) + { + WirePortDataType dataType = CgToWirePortType[ match.Groups[ 1 ].Value ]; + string varName = match.Groups[ 2 ].Value; + TemplateSemantics semantics = (TemplateSemantics)Enum.Parse( typeof( TemplateSemantics ), match.Groups[ 3 ].Value ); + TemplateVertexData templateVertexData = new TemplateVertexData( semantics, dataType, varName ); + //interpDataList.Add( templateVertexData ); + interpDataDict.Add( semantics, templateVertexData ); + interpDataObj.RawInterpolators.Add( templateVertexData ); + //Check if they are also on the free channels list and update their names + interpDataObj.ReplaceNameOnInterpolator( semantics, varName ); + } + } + + if( interpData.Contains( Constants.InstanceIdMacro ) ) + { + TemplateVertexData templateInterpData = new TemplateVertexData( TemplateSemantics.SV_InstanceID, WirePortDataType.UINT, Constants.InstanceIdVariable ); + templateInterpData.DataInfo = TemplateInfoOnSematics.INSTANCE_ID; + templateInterpData.Available = true; + templateInterpData.ExcludeStructPrefix = true; + interpDataList.Add( templateInterpData ); + interpDataDict.Add( TemplateSemantics.SV_InstanceID, templateInterpData ); + } + + Dictionary<string, TemplateVertexData> auxDict = new Dictionary<string, TemplateVertexData>(); + // Get info for available interpolators + string[] paramsArray = parametersBody.Split( IOUtils.FIELD_SEPARATOR ); + if( paramsArray.Length > 0 ) + { + for( int i = 0; i < paramsArray.Length; i++ ) + { + string[] paramDataArr = paramsArray[ i ].Split( IOUtils.VALUE_SEPARATOR ); + if( paramDataArr.Length == 2 ) + { + string[] swizzleInfoArr = paramDataArr[ 1 ].Split( IOUtils.FLOAT_SEPARATOR ); + TemplateSemantics semantic = ShortcutToSemantic[ swizzleInfoArr[ 0 ] ]; + if( interpDataDict.ContainsKey( semantic ) ) + { + if( interpDataDict[ semantic ] != null ) + { + string[] multiComponent = paramDataArr[ 0 ].Split( IOUtils.FLOAT_SEPARATOR ); + + if( multiComponent.Length > 1 ) + { + TemplateVertexData templateInterpData = null; + if( auxDict.ContainsKey( multiComponent[ 0 ] ) ) + { + templateInterpData = auxDict[ multiComponent[ 0 ] ]; + } + else + { + templateInterpData = new TemplateVertexData( interpDataDict[ semantic ] ); + //if( swizzleInfoArr.Length > 1 ) + //{ + // templateInterpData.DataSwizzle = "." + swizzleInfoArr[ 1 ]; + //} + templateInterpData.DataInfo = ShortcutToInfo[ multiComponent[ 0 ] ]; + templateInterpData.Available = true; + interpDataList.Add( templateInterpData ); + auxDict.Add( multiComponent[ 0 ], templateInterpData ); + } + + if( swizzleInfoArr[ 1 ].Length == multiComponent[ 1 ].Length ) + { + for( int channelIdx = 0; channelIdx < swizzleInfoArr[ 1 ].Length; channelIdx++ ) + { + templateInterpData.RegisterComponent( multiComponent[ 1 ][ channelIdx ], interpDataDict[ semantic ].VarName + "." + swizzleInfoArr[ 1 ][ channelIdx ] ); + } + } + } + else + { + TemplateVertexData templateInterpData = new TemplateVertexData( interpDataDict[ semantic ] ); + if( swizzleInfoArr.Length > 1 ) + { + templateInterpData.DataSwizzle = "." + swizzleInfoArr[ 1 ]; + } + templateInterpData.DataInfo = ShortcutToInfo[ paramDataArr[ 0 ] ]; + templateInterpData.Available = true; + interpDataList.Add( templateInterpData ); + } + } + } + } + } + } + + /*TODO: + 1) Remove interpDataList.Add( templateVertexData ); from initial foreach + 2) When looping though each foreach array element, create a new TemplateVertexData + from the one containted on the interpDataDict and add it to interpDataList + */ + for( int i = 0; i < interpDataList.Count; i++ ) + { + interpDataList[ i ].BuildVar(); + } + + auxDict.Clear(); + auxDict = null; + + interpDataObj.Interpolators = interpDataList; + interpDataDict.Clear(); + interpDataDict = null; + } + return interpDataObj; + } + + public static void FetchDependencies( TemplateInfoContainer dependencies, ref string body ) + { + int index = body.IndexOf( TemplatesManager.TemplateDependenciesListTag ); + if( index > 0 ) + { + dependencies.Index = index; + dependencies.Id = TemplatesManager.TemplateDependenciesListTag; + dependencies.Data = TemplatesManager.TemplateDependenciesListTag; + } + else + { + int lastIndex = body.LastIndexOf( '}' ); + if( lastIndex > 0 ) + { + body = body.Insert( lastIndex, "\t" + TemplatesManager.TemplateDependenciesListTag + "\n" ); + FetchDependencies( dependencies, ref body ); + } + } + } + + public static void FetchCustomInspector( TemplateInfoContainer inspectorContainer, ref string body ) + { + Match match = Regex.Match( body, CustomInspectorPattern, RegexOptions.Multiline ); + if( match != null && match.Groups.Count > 1 ) + { + inspectorContainer.Index = match.Index; + inspectorContainer.Id = match.Groups[ 0 ].Value; + inspectorContainer.Data = match.Groups[ 1 ].Value; + +#if UNITY_2019_3_OR_NEWER + if( ASEPackageManagerHelper.CurrentHDVersion > ASESRPVersions.ASE_SRP_6_9_1 ) + { + if( inspectorContainer.Data.Equals( "UnityEditor.Experimental.Rendering.HDPipeline.HDLitGUI" ) ) + inspectorContainer.Data = "UnityEditor.Rendering.HighDefinition.HDLitGUI"; + } +#endif + } + else + { + int index = body.LastIndexOf( '}' ); + if( index > 0 ) + { + body = body.Insert( index, string.Format( "\tCustomEditor \"{0}\"\n", Constants.DefaultCustomInspector ) ); + FetchCustomInspector( inspectorContainer, ref body ); + } + } + } + + public static void FetchFallback( TemplateInfoContainer fallbackContainer, ref string body ) + { + Match match = Regex.Match( body, FallbackPattern, RegexOptions.Multiline | RegexOptions.IgnoreCase ); + if( match != null && match.Groups.Count > 1 ) + { + fallbackContainer.Index = match.Index; + fallbackContainer.Id = match.Groups[ 0 ].Value; + fallbackContainer.Data = match.Groups[ 1 ].Value; + } + else + { + int index = body.LastIndexOf( '}' ); + if( index > 0 ) + { + body = body.Insert( index, "\tFallback \"\"\n" ); + FetchFallback( fallbackContainer, ref body ); + } + } + } + + public static string AutoSwizzleData( string dataVar, WirePortDataType from, WirePortDataType to, bool isPosition ) + { + switch( from ) + { + case WirePortDataType.COLOR: + case WirePortDataType.FLOAT4: + { + switch( to ) + { + case WirePortDataType.FLOAT3: dataVar += ".xyz"; break; + case WirePortDataType.FLOAT2: dataVar += ".xy"; break; + case WirePortDataType.INT: + case WirePortDataType.FLOAT: dataVar += ".x"; break; + } + } + break; + case WirePortDataType.FLOAT3: + { + switch( to ) + { + case WirePortDataType.FLOAT4: dataVar = string.Format( "float4({0},{1})", dataVar,(isPosition?1:0) ); break; + case WirePortDataType.FLOAT2: dataVar += ".xy"; break; + case WirePortDataType.INT: + case WirePortDataType.FLOAT: dataVar += ".x"; break; + } + } + break; + case WirePortDataType.FLOAT2: + { + switch( to ) + { + case WirePortDataType.FLOAT4: dataVar = string.Format( "float4({0},0,{1})", dataVar , (isPosition ? 1 : 0) ); break; + case WirePortDataType.FLOAT3: dataVar = string.Format( "float3({0},0)", dataVar ); break; + case WirePortDataType.INT: + case WirePortDataType.FLOAT: dataVar += ".x"; break; + } + } + break; + case WirePortDataType.FLOAT: + { + switch( to ) + { + case WirePortDataType.FLOAT4: dataVar = string.Format( "float4({0},0,0,{1})", dataVar, ( isPosition ? 1 : 0 ) ); break; + case WirePortDataType.FLOAT3: dataVar = string.Format( "float3({0},0,0)", dataVar ); break; + case WirePortDataType.FLOAT2: dataVar = string.Format( "float2({0},0)", dataVar ); break; + } + } + break; + } + return dataVar; + } + + public static bool CheckIfTemplate( string assetPath ) + { + Type type = AssetDatabase.GetMainAssetTypeAtPath( assetPath ); + if( type == typeof( Shader ) ) + { + Shader shader = AssetDatabase.LoadAssetAtPath<Shader>( assetPath ); + if( shader != null ) + { + string body = IOUtils.LoadTextFileFromDisk( assetPath ); + return ( body.IndexOf( TemplatesManager.TemplateShaderNameBeginTag ) > -1 ); + } + } + return false; + } + + public static bool CheckIfCompatibles( WirePortDataType first, WirePortDataType second ) + { + switch( first ) + { + case WirePortDataType.OBJECT: + return true; + case WirePortDataType.FLOAT: + case WirePortDataType.FLOAT2: + case WirePortDataType.FLOAT3: + case WirePortDataType.FLOAT4: + case WirePortDataType.COLOR: + case WirePortDataType.INT: + { + switch( second ) + { + case WirePortDataType.FLOAT3x3: + case WirePortDataType.FLOAT4x4: + case WirePortDataType.SAMPLER1D: + case WirePortDataType.SAMPLER2D: + case WirePortDataType.SAMPLER3D: + case WirePortDataType.SAMPLERCUBE: + return false; + } + } + break; + case WirePortDataType.FLOAT3x3: + case WirePortDataType.FLOAT4x4: + { + switch( second ) + { + case WirePortDataType.FLOAT: + case WirePortDataType.FLOAT2: + case WirePortDataType.FLOAT3: + case WirePortDataType.FLOAT4: + case WirePortDataType.COLOR: + case WirePortDataType.INT: + case WirePortDataType.SAMPLER1D: + case WirePortDataType.SAMPLER2D: + case WirePortDataType.SAMPLER3D: + case WirePortDataType.SAMPLERCUBE: + return false; + } + } + break; + case WirePortDataType.SAMPLER1D: + case WirePortDataType.SAMPLER2D: + case WirePortDataType.SAMPLER3D: + case WirePortDataType.SAMPLERCUBE: + { + switch( second ) + { + case WirePortDataType.FLOAT: + case WirePortDataType.FLOAT2: + case WirePortDataType.FLOAT3: + case WirePortDataType.FLOAT4: + case WirePortDataType.FLOAT3x3: + case WirePortDataType.FLOAT4x4: + case WirePortDataType.COLOR: + case WirePortDataType.INT: + return false; + } + } + break; + } + return true; + } + // Lightweight <-> Default functions + public static string WorldSpaceViewDir( MasterNodeDataCollector dataCollector, string worldPosVec3, bool normalize ) + { + string value = string.Empty; + if( dataCollector.IsTemplate && dataCollector.IsSRP ) + { + value = string.Format( "_WorldSpaceCameraPos.xyz - {0}", worldPosVec3 ); + } + else + { + value = string.Format( "UnityWorldSpaceViewDir( {0} )", worldPosVec3 ); + } + + if( normalize ) + { + value = SafeNormalize( dataCollector, value ); + } + + return value; + } + + public static string SafeNormalize( MasterNodeDataCollector dataCollector, string value ) + { + if( dataCollector.IsTemplate && dataCollector.IsSRP ) + { + value = string.Format( "SafeNormalize( {0} )", value ); + } + else + { + dataCollector.AddToIncludes( -1, Constants.UnityBRDFLib ); + value = string.Format( "Unity_SafeNormalize( {0} )", value ); + } + return value; + } + + + public static string CreateUnpackNormalStr( MasterNodeDataCollector dataCollector, bool applyScale, string scale ) + { + string funcName; + if( dataCollector.IsTemplate && dataCollector.IsSRP ) + { + if( dataCollector.TemplateDataCollectorInstance.IsHDRP ) + { + funcName = "UnpackNormalmapRGorAG( {0}, " + scale + " )"; + } + else + { + funcName = "UnpackNormalScale( {0}, " + scale + " )"; + } + } + else + { + funcName = applyScale ? "UnpackScaleNormal( {0}, " + scale + " )" : "UnpackNormal( {0} )"; + } + return funcName; + } + + public static bool IsInlineProperty( string data, ref string property ) + { + if( data.Length > 0 && data[ 0 ] == '[' && data[ data.Length - 1 ] == ']' ) + { + property = data.Substring( 1, data.Length - 2 ); + return true; + } + return false; + } + + // public static readonly string FetchDefaultDepthFormat = "UNITY_SAMPLE_DEPTH(tex2Dproj(_CameraDepthTexture,UNITY_PROJ_COORD( {0} )))"; + public static readonly string FetchDefaultDepthFormat = "SAMPLE_DEPTH_TEXTURE( _CameraDepthTexture, {0}.xy )"; + public static readonly string FetchDefaultDepthFormatVertex = "SAMPLE_DEPTH_TEXTURE_LOD( _CameraDepthTexture, float4( {0}.xy, 0, 0 ) )"; + + public static readonly string FetchLWDepthFormat = "SHADERGRAPH_SAMPLE_SCENE_DEPTH( {0}.xy )"; + public static readonly string FetchLWDepthFormatVertex = "SHADERGRAPH_SAMPLE_SCENE_DEPTH_LOD( {0}.xy )"; +#if UNITY_2018_3_OR_NEWER + public static readonly string FetchHDDepthFormat = "SampleCameraDepth( {0}.xy )"; +#else + public static readonly string FetchHDDepthFormat = "SAMPLE_TEXTURE2D( _CameraDepthTexture, s_point_clamp_sampler, {0}.xy ).r"; +#endif + public static string CreateDepthFetch( MasterNodeDataCollector dataCollector, string screenPos ) + { + string screenDepthInstruction = string.Empty; + if( dataCollector.IsTemplate && dataCollector.IsSRP ) + { + if( dataCollector.TemplateDataCollectorInstance.CurrentSRPType == TemplateSRPType.Lightweight ) + { + if( dataCollector.PortCategory == MasterNodePortCategory.Vertex ) + { + string m_functionBody = string.Empty; + GenerateLW( ref m_functionBody ); + dataCollector.AddFunctions( FetchLWDepthFormatVertex, m_functionBody, "0" ); + screenDepthInstruction = string.Format( FetchLWDepthFormatVertex, screenPos ); + } + else + screenDepthInstruction = string.Format( FetchLWDepthFormat, screenPos ); + } + else if( dataCollector.TemplateDataCollectorInstance.CurrentSRPType == TemplateSRPType.HD ) + screenDepthInstruction = string.Format( FetchHDDepthFormat, screenPos ); + } + else + { + if( dataCollector.PortCategory == MasterNodePortCategory.Vertex ) + screenDepthInstruction = string.Format( FetchDefaultDepthFormatVertex, screenPos ); + else + screenDepthInstruction = string.Format( FetchDefaultDepthFormat, screenPos ); + } + return screenDepthInstruction; + } + + public static void GenerateLW( ref string body ) + { + body = string.Empty; + IOUtils.AddFunctionHeader( ref body, "float SHADERGRAPH_SAMPLE_SCENE_DEPTH_LOD(float2 uv)" ); + IOUtils.AddFunctionLine( ref body, "#if defined(REQUIRE_DEPTH_TEXTURE)" ); + IOUtils.AddFunctionLine( ref body, "#if defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED)" ); + IOUtils.AddFunctionLine( ref body, " \tfloat rawDepth = SAMPLE_TEXTURE2D_ARRAY_LOD(_CameraDepthTexture, sampler_CameraDepthTexture, uv, unity_StereoEyeIndex, 0).r;" ); + IOUtils.AddFunctionLine( ref body, "#else" ); + IOUtils.AddFunctionLine( ref body, " \tfloat rawDepth = SAMPLE_DEPTH_TEXTURE_LOD(_CameraDepthTexture, sampler_CameraDepthTexture, uv, 0);" ); + IOUtils.AddFunctionLine( ref body, "#endif" ); + IOUtils.AddFunctionLine( ref body, "return rawDepth;" ); + IOUtils.AddFunctionLine( ref body, "#endif // REQUIRE_DEPTH_TEXTURE" ); + IOUtils.AddFunctionLine( ref body, "return 0;" ); + IOUtils.CloseFunctionBody( ref body ); + } + + public static bool GetShaderModelForInterpolatorAmount( int interpAmount, ref string shaderModel ) + { + for( int i = 0; i < AvailableShaderModels.Length; i++ ) + { + if( AvailableInterpolators[ AvailableShaderModels[ i ] ] >= interpAmount ) + { + shaderModel = AvailableShaderModels[ i ]; + return true; + } + } + return false; + } + + public static string GetSubShaderFrom( string shaderBody ) + { + Match match = Regex.Match( shaderBody, FetchSubShaderBody, RegexOptions.Singleline ); + if( match.Success && match.Groups.Count > 1 ) + { + return match.Groups[ 1 ].Value; + } + + return string.Empty; + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateHelperFunctions.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateHelperFunctions.cs.meta new file mode 100644 index 00000000..8cbfe8cd --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateHelperFunctions.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 517aad6764d713946bc566f0a83cd44d +timeCreated: 1495548641 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateIdManager.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateIdManager.cs new file mode 100644 index 00000000..a9d242d0 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateIdManager.cs @@ -0,0 +1,236 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplatePassId + { + public string PassId; + public bool RemoveFromShader; + } + + + [Serializable] + public class TemplateTag + { + public string Tag = string.Empty; + public string Replacement = string.Empty; + public string Output = string.Empty; + public TemplateTag( string tag, string replacement = null ) + { + Tag = tag; + if( replacement != null ) + { + Replacement = replacement; + Output = replacement; + } + } + } + + [Serializable] + public class TemplateId + { + public int StartIdx = -1; + public string UniqueID; + public string Tag; + public string ReplacementText; + public bool IsReplaced = false; + public bool EmptyReplacer = false; + public TemplateId( int bodyIdx, string uniqueID, string tag, bool emptyReplacer = false ) + { + StartIdx = bodyIdx; + UniqueID = uniqueID; + Tag = tag; + EmptyReplacer = emptyReplacer; + ReplacementText = emptyReplacer ? string.Empty : tag; + } + + public void SetReplacementText( string replacementText ) + { + ReplacementText = replacementText; + IsReplaced = true; + } + + public void Reset() + { + ReplacementText = EmptyReplacer?string.Empty:Tag; + IsReplaced = false; + } + } + + [Serializable] + public class TemplateIdManager + { + [SerializeField] + private bool m_isSorted = false; + [SerializeField] + private string m_shaderBody; + [SerializeField] + private List<TemplateId> m_registeredIds = new List<TemplateId>(); + + [SerializeField] + private List<TemplateTag> m_registeredTags = new List<TemplateTag>(); + + [SerializeField] + private List<TemplatePassId> m_registeredPassIds = new List<TemplatePassId>(); + + private Dictionary<string, TemplateId> m_registeredIdsDict = new Dictionary<string, TemplateId>(); + + public TemplateIdManager( string shaderBody ) + { + m_shaderBody = shaderBody; + } + + public void Destroy() + { + m_registeredPassIds.Clear(); + m_registeredPassIds = null; + + m_registeredTags.Clear(); + m_registeredTags = null; + + m_registeredIds.Clear(); + m_registeredIds = null; + if( m_registeredIdsDict != null ) + { + m_registeredIdsDict.Clear(); + m_registeredIdsDict = null; + } + } + + void RefreshIds() + { + if( m_registeredIdsDict == null ) + { + m_registeredIdsDict = new Dictionary<string, TemplateId>(); + } + + if( m_registeredIdsDict.Count != m_registeredIds.Count ) + { + m_registeredIdsDict.Clear(); + int count = m_registeredIds.Count; + for( int i = 0; i < count; i++ ) + { + m_registeredIdsDict.Add( m_registeredIds[ i ].UniqueID, m_registeredIds[ i ] ); + } + } + } + + public void RegisterId( int bodyIdx, string uniqueID, string tag, bool emptyReplacer = false ) + { + if( bodyIdx < 0 ) + return; + + RefreshIds(); + + TemplateId templateId = new TemplateId( bodyIdx, uniqueID, tag, emptyReplacer ); + m_registeredIds.Add( templateId ); + m_registeredIdsDict.Add( uniqueID, templateId ); + } + + public void RegisterTag( string tag, string replacement = null ) + { + m_registeredTags.Add( new TemplateTag( tag, replacement ) ); + } + + public void RegisterPassId( string passId ) + { + m_registeredPassIds.Add( new TemplatePassId() { PassId = passId, RemoveFromShader = false } ); + } + + public void SetPassIdUsage( int idx , bool removeFromShader ) + { + m_registeredPassIds[ idx ].RemoveFromShader = removeFromShader; + } + + public void SetReplacementText( string uniqueId, string replacementText ) + { + RefreshIds(); + + if( m_registeredIdsDict.ContainsKey( uniqueId ) && m_registeredIdsDict[ uniqueId ].StartIdx >= 0 ) + m_registeredIdsDict[ uniqueId ].SetReplacementText( replacementText ); + } + + + public string BuildShader() + { + if( !m_isSorted ) + { + m_registeredIds.Sort( ( x, y ) => { return x.StartIdx.CompareTo( y.StartIdx ); } ); + } + + int idCount = m_registeredIds.Count; + int offset = 0; + string finalShaderBody = m_shaderBody; + for( int i = 0; i < idCount; i++ ) + { + if( m_registeredIds[ i ].StartIdx >= 0 && m_registeredIds[ i ].IsReplaced ) + { + finalShaderBody = finalShaderBody.ReplaceAt( m_registeredIds[ i ].Tag, m_registeredIds[ i ].ReplacementText, offset + m_registeredIds[ i ].StartIdx ); + offset += ( m_registeredIds[ i ].ReplacementText.Length - m_registeredIds[ i ].Tag.Length ); + } + } + + int count = m_registeredPassIds.Count; + for( int i = 0; i < count; i++ ) + { + if( m_registeredPassIds[ i ].RemoveFromShader ) + finalShaderBody = finalShaderBody.Replace( m_registeredPassIds[ i ].PassId, string.Empty ); + } + + for( int i = 0; i < idCount; i++ ) + { + if( !m_registeredIds[ i ].IsReplaced && !m_registeredIds[ i ].Tag.Equals( m_registeredIds[ i ].ReplacementText ) ) + { + finalShaderBody = finalShaderBody.Replace( m_registeredIds[ i ].Tag, m_registeredIds[ i ].ReplacementText ); + } + } + + count = m_registeredTags.Count; + for( int i = 0; i < count; i++ ) + { + finalShaderBody = finalShaderBody.Replace( m_registeredTags[ i ].Tag, m_registeredTags[ i ].Replacement ); + m_registeredTags[ i ].Replacement = m_registeredTags[ i ].Output; + } + + //finalShaderBody = finalShaderBody.Replace( TemplatesManager.TemplateExcludeFromGraphTag, string.Empty ); + //finalShaderBody = finalShaderBody.Replace( TemplatesManager.TemplateMainPassTag, string.Empty ); + + return finalShaderBody; + } + + public void ResetRegistersState() + { + int count = m_registeredIds.Count; + for( int i = 0; i < count; i++ ) + { + m_registeredIds[ i ].Reset(); + } + } + + public void Reset() + { + m_registeredIds.Clear(); + if( m_registeredIdsDict == null ) + { + m_registeredIdsDict = new Dictionary<string, TemplateId>(); + } + else + { + m_registeredIdsDict.Clear(); + } + } + + public string ShaderBody + { + get { return m_shaderBody; } + set { m_shaderBody = value; } + } + + public List<TemplateTag> RegisteredTags { get { return m_registeredTags; } set { m_registeredTags = value; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateIdManager.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateIdManager.cs.meta new file mode 100644 index 00000000..887ff5a8 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateIdManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b0d2e93061ffcbd45b085a61e5000daa +timeCreated: 1517315635 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateInterpData.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateInterpData.cs new file mode 100644 index 00000000..6e5da580 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateInterpData.cs @@ -0,0 +1,234 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateInterpElement + { + public TemplateSemantics Semantic; + public bool[] AvailableChannels = { true, true, true, true }; + public bool IsFull = false; + public int Usage = 0; + public string Name; + + public TemplateInterpElement( TemplateInterpElement other ) + { + Semantic = other.Semantic; + for ( int i = 0; i < AvailableChannels.Length; i++ ) + { + AvailableChannels[ i ] = other.AvailableChannels[ i ]; + } + IsFull = other.IsFull; + Usage = other.Usage; + Name = other.Name; + } + + public TemplateInterpElement( TemplateSemantics semantic ) + { + Semantic = semantic; + int semanticId = TemplateHelperFunctions.SemanticToInt[ Semantic ]; + Name = ( semanticId == 0 ) ? TemplateHelperFunctions.BaseInterpolatorName : TemplateHelperFunctions.BaseInterpolatorName + semanticId.ToString(); + } + + public void SetAvailableChannelsFromString( string channels ) + { + for ( int i = 0; i < AvailableChannels.Length; i++ ) + { + AvailableChannels[ i ] = false; + } + Usage = AvailableChannels.Length; + + for ( int i = 0; i < channels.Length; i++ ) + { + switch ( channels[ i ] ) + { + case 'x': if ( !AvailableChannels[ 0 ] ) { AvailableChannels[ 0 ] = true; Usage--; } break; + case 'y': if ( !AvailableChannels[ 1 ] ) { AvailableChannels[ 1 ] = true; Usage--; } break; + case 'z': if ( !AvailableChannels[ 2 ] ) { AvailableChannels[ 2 ] = true; Usage--; } break; + case 'w': if ( !AvailableChannels[ 3 ] ) { AvailableChannels[ 3 ] = true; Usage--; } break; + } + } + } + + public TemplateVertexData RequestChannels( WirePortDataType type, bool isColor, string customName = null ) + { + if ( IsFull ) + return null; + + int channelsRequired = TemplateHelperFunctions.DataTypeChannelUsage[ type ]; + if ( channelsRequired == 0 ) + return null; + + int firstChannel = -1; + for ( int i = 0; i < AvailableChannels.Length; i++ ) + { + if ( AvailableChannels[ i ] ) + { + if ( firstChannel < 0 ) + { + firstChannel = i; + } + channelsRequired -= 1; + if ( channelsRequired == 0 ) + break; + } + } + + //did not found enough channels to fill request + if ( channelsRequired > 0 ) + return null; + + if( Usage == 0 && customName != null ) + { + Name = customName; + } + + Usage += 1; + TemplateVertexData data = null; + + if ( type == WirePortDataType.COLOR || type == WirePortDataType.FLOAT4 ) + { + // Automatically lock all channels + for ( int i = firstChannel; i < ( firstChannel + channelsRequired ); i++ ) + { + AvailableChannels[ i ] = false; + } + IsFull = true; + data = new TemplateVertexData( Semantic, type, Name ); + } + else + { + string[] swizzleArray = ( isColor ) ? TemplateHelperFunctions.ColorSwizzle : TemplateHelperFunctions.VectorSwizzle; + string channels = "."; + int count = firstChannel + TemplateHelperFunctions.DataTypeChannelUsage[ type ]; + for ( int i = firstChannel; i < count; i++ ) + { + AvailableChannels[ i ] = false; + channels += swizzleArray[ i ]; + if ( i == ( AvailableChannels.Length - 1 ) ) + { + IsFull = true; + } + } + + data = new TemplateVertexData( Semantic, type, Name, channels ); + } + return data; + } + } + + [Serializable] + public class TemplateInterpData + { + [SerializeField] + private string m_interpDataId = string.Empty; + + [SerializeField] + private int m_interpDataStartIdx = -1; + + [SerializeField] + private bool m_dynamicMax = false; + + public List<TemplateInterpElement> AvailableInterpolators = new List<TemplateInterpElement>(); + public List<TemplateVertexData> Interpolators = new List<TemplateVertexData>(); + public List<TemplateVertexData> RawInterpolators = new List<TemplateVertexData>(); + + public TemplateInterpData() { } + + public bool HasRawInterpolatorOfName( string name ) + { + return RawInterpolators.Exists( ( x ) => x.VarName.Equals( name )); + } + + public TemplateInterpData( TemplateInterpData other ) + { + m_dynamicMax = other.DynamicMax; + + foreach ( TemplateInterpElement data in other.AvailableInterpolators ) + { + AvailableInterpolators.Add( new TemplateInterpElement( data ) ); + } + + for ( int i = 0; i < other.Interpolators.Count; i++ ) + { + Interpolators.Add( new TemplateVertexData( other.Interpolators[ i ] ) ); + } + + for( int i = 0; i < other.RawInterpolators.Count; i++ ) + { + RawInterpolators.Add( new TemplateVertexData( other.RawInterpolators[ i ] ) ); + } + } + + + public void RecalculateAvailableInterpolators( int newMax ) + { + if( m_dynamicMax ) + { + if( !TemplateHelperFunctions.IntToSemantic.ContainsKey( ( newMax - 1 ) ) ) + { + Debug.LogWarning( "Attempting to add inexisting available interpolators" ); + return; + } + + if( AvailableInterpolators.Count > 0 ) + { + int currMax = 1 + TemplateHelperFunctions.SemanticToInt[ AvailableInterpolators[ AvailableInterpolators.Count - 1 ].Semantic ]; + if( newMax > currMax ) + { + int count = newMax - currMax; + for( int i = 0; i < count; i++ ) + { + AvailableInterpolators.Add( new TemplateInterpElement( TemplateHelperFunctions.IntToSemantic[ currMax + i ] )); + } + } + else if( newMax < currMax ) + { + int min = TemplateHelperFunctions.SemanticToInt[ AvailableInterpolators[ 0 ].Semantic ]; + if( newMax > min ) + { + int count = currMax - newMax; + for( int i = 0; i < count; i++ ) + { + AvailableInterpolators.RemoveAt( AvailableInterpolators.Count - 1 ); + } + } + } + } + } + } + + public void ReplaceNameOnInterpolator( TemplateSemantics semantic, string newName ) + { + for ( int i = 0; i < AvailableInterpolators.Count; i++ ) + { + if ( AvailableInterpolators[ i ].Semantic == semantic ) + { + AvailableInterpolators[ i ].Name = newName; + break; + } + } + } + + public void Destroy() + { + AvailableInterpolators.Clear(); + AvailableInterpolators = null; + + Interpolators.Clear(); + Interpolators = null; + + RawInterpolators.Clear(); + RawInterpolators = null; + } + + public string InterpDataId { get { return m_interpDataId; } set { m_interpDataId = value; } } + public int InterpDataStartIdx { get { return m_interpDataStartIdx; } set { m_interpDataStartIdx = value; } } + public bool DynamicMax { get { return m_dynamicMax; } set { m_dynamicMax = value; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateInterpData.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateInterpData.cs.meta new file mode 100644 index 00000000..cf31bc9b --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateInterpData.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8f700ba5366bcda45beea5c0e2db9f3e +timeCreated: 1496053368 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateLocalVarData.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateLocalVarData.cs new file mode 100644 index 00000000..3cde2f03 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateLocalVarData.cs @@ -0,0 +1,59 @@ +using System; +using UnityEngine; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateLocalVarData + { + [SerializeField] + private WirePortDataType m_dataType = WirePortDataType.OBJECT; + + [SerializeField] + private string m_localVarName = string.Empty; + + [SerializeField] + private int m_position = -1; + + [SerializeField] + private bool m_isSpecialVar = false; + + [SerializeField] + private TemplateInfoOnSematics m_specialVarType; + + [SerializeField] + private MasterNodePortCategory m_category; + + [SerializeField] + private string m_id; + + public TemplateLocalVarData( WirePortDataType dataType, MasterNodePortCategory category, string localVarName, int position ) + { + m_dataType = dataType; + m_localVarName = localVarName; + m_position = position; + m_category = category; + //Debug.Log( m_localVarName + " " + m_inputData.PortCategory + " " + m_inputData.PortName ); + } + + public TemplateLocalVarData( TemplateInfoOnSematics specialVarType,string id, WirePortDataType dataType, MasterNodePortCategory category, string localVarName, int position ) + { + m_id = id; + m_dataType = dataType; + m_localVarName = localVarName; + m_position = position; + m_specialVarType = specialVarType; + m_isSpecialVar = true; + m_category = category; + //Debug.Log( m_localVarName + " " + m_inputData.PortCategory + " " + m_inputData.PortName ); + } + + public WirePortDataType DataType { get { return m_dataType; } } + public string LocalVarName { get { return m_localVarName; } } + public int Position { get { return m_position; } } + public bool IsSpecialVar { get { return m_isSpecialVar; } } + public TemplateInfoOnSematics SpecialVarType{ get { return m_specialVarType; } } + public MasterNodePortCategory Category { get { return m_category; } } + public string Id { get { return m_id; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateLocalVarData.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateLocalVarData.cs.meta new file mode 100644 index 00000000..267c3527 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateLocalVarData.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4c6ad22d8633c7142ae0237479df76ed +timeCreated: 1518017743 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateLocalVarsNode.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateLocalVarsNode.cs new file mode 100644 index 00000000..85898210 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateLocalVarsNode.cs @@ -0,0 +1,258 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> +using UnityEngine; +using UnityEditor; +using System; +using System.Collections.Generic; + +namespace AmplifyShaderEditor +{ + [Serializable] + [NodeAttributes( "Template Local Var Data", "Surface Data", "Select and use available local variable data from the template" )] + public sealed class TemplateLocalVarsNode : TemplateNodeParent + { + private List<TemplateLocalVarData> m_localVarsData = null; + + [SerializeField] + private int m_currentDataIdx = -1; + + [SerializeField] + private string m_dataName = string.Empty; + + private string[] m_dataLabels = null; + + private bool m_fetchDataId = false; + private UpperLeftWidgetHelper m_upperLeftWidgetHelper = new UpperLeftWidgetHelper(); + + void FetchDataId() + { + if( m_localVarsData != null && m_localVarsData.Count > 0 ) + { + m_currentDataIdx = 0; + int count = m_localVarsData.Count; + m_dataLabels = new string[ count ]; + for( int i = 0; i < count; i++ ) + { + m_dataLabels[ i ] = m_localVarsData[ i ].LocalVarName; + if( m_localVarsData[ i ].LocalVarName.Equals( m_dataName ) ) + { + m_currentDataIdx = i; + } + } + UpdateFromId(); + } + else + { + m_currentDataIdx = -1; + } + } + + void UpdateFromId() + { + if( m_localVarsData != null ) + { + if( m_localVarsData.Count == 0 ) + { + for( int i = 0; i < 4; i++ ) + m_containerGraph.DeleteConnection( false, UniqueId, i, false, true ); + + m_headerColor = UIUtils.GetColorFromCategory( "Default" ); + m_content.text = "None"; + m_additionalContent.text = string.Empty; + m_outputPorts[ 0 ].ChangeProperties( "None", WirePortDataType.OBJECT, false ); + ConfigurePorts(); + return; + } + + bool areCompatible = TemplateHelperFunctions.CheckIfCompatibles( m_outputPorts[ 0 ].DataType, m_localVarsData[ m_currentDataIdx ].DataType ); + string category = m_localVarsData[ m_currentDataIdx ].Category == MasterNodePortCategory.Fragment ? "Surface Data" : "Vertex Data"; + m_headerColor = UIUtils.GetColorFromCategory( category ); + switch( m_localVarsData[ m_currentDataIdx ].DataType ) + { + default: + case WirePortDataType.INT: + case WirePortDataType.FLOAT: + m_outputPorts[ 0 ].ChangeProperties( Constants.EmptyPortValue, m_localVarsData[ m_currentDataIdx ].DataType, false ); + break; + case WirePortDataType.FLOAT2: + m_outputPorts[ 0 ].ChangeProperties( "XY", m_localVarsData[ m_currentDataIdx ].DataType, false ); + break; + case WirePortDataType.FLOAT3: + m_outputPorts[ 0 ].ChangeProperties( "XYZ", m_localVarsData[ m_currentDataIdx ].DataType, false ); + break; + case WirePortDataType.FLOAT4: + m_outputPorts[ 0 ].ChangeProperties( "XYZW", m_localVarsData[ m_currentDataIdx ].DataType, false ); + break; + case WirePortDataType.COLOR: + m_outputPorts[ 0 ].ChangeProperties( "RGBA", m_localVarsData[ m_currentDataIdx ].DataType, false ); + break; + } + + ConfigurePorts(); + + if( !areCompatible ) + { + m_containerGraph.DeleteConnection( false, UniqueId, 0, false, true ); + } + + m_dataName = m_localVarsData[ m_currentDataIdx ].LocalVarName; + m_content.text = m_dataName; + m_sizeIsDirty = true; + CheckWarningState(); + } + } + + public override void DrawProperties() + { + base.DrawProperties(); + if( m_multiPassMode ) + { + DrawMultipassProperties(); + } + + if( m_currentDataIdx > -1 ) + { + EditorGUI.BeginChangeCheck(); + m_currentDataIdx = EditorGUILayoutPopup( DataLabelStr, m_currentDataIdx, m_dataLabels ); + if( EditorGUI.EndChangeCheck() ) + { + UpdateFromId(); + } + } + } + protected override void OnSubShaderChange() + { + FetchLocalVarData(); + FetchDataId(); + } + + protected override void OnPassChange() + { + base.OnPassChange(); + FetchLocalVarData(); + FetchDataId(); + } + + void DrawMultipassProperties() + { + DrawSubShaderUI(); + DrawPassUI(); + } + + public override void Draw( DrawInfo drawInfo ) + { + base.Draw( drawInfo ); + if( m_containerGraph.CurrentCanvasMode != NodeAvailability.TemplateShader ) + return; + + if( m_localVarsData == null || m_localVarsData.Count == 0 ) + { + MasterNode masterNode = m_containerGraph.CurrentMasterNode; + if( masterNode.CurrentMasterNodeCategory == AvailableShaderTypes.Template ) + { + FetchLocalVarData( masterNode ); + } + } + + if( m_fetchDataId ) + { + m_fetchDataId = false; + FetchDataId(); + } + + if( m_currentDataIdx > -1 ) + { + EditorGUI.BeginChangeCheck(); + m_currentDataIdx = m_upperLeftWidgetHelper.DrawWidget( this, m_currentDataIdx, m_dataLabels ); + if( EditorGUI.EndChangeCheck() ) + { + UpdateFromId(); + } + } + } + + public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar ) + { + if( m_localVarsData[ m_currentDataIdx ].Category != dataCollector.PortCategory ) + { + UIUtils.ShowMessage( UniqueId, string.Format( "Local Var {0} can only work on ports of type {1}", m_localVarsData[ m_currentDataIdx ].LocalVarName, m_localVarsData[ m_currentDataIdx ].Category ) ); + return m_outputPorts[ 0 ].ErrorValue; + } + + if( m_multiPassMode ) + { + if( dataCollector.TemplateDataCollectorInstance.MultipassSubshaderIdx != SubShaderIdx || + dataCollector.TemplateDataCollectorInstance.MultipassPassIdx != PassIdx + ) + { + UIUtils.ShowMessage( UniqueId, string.Format( "{0} is only intended for subshader {1} and pass {2}", m_dataLabels[ m_currentDataIdx ], SubShaderIdx, PassIdx ) ); + return m_outputPorts[ outputId ].ErrorValue; + } + } + + return GetOutputVectorItem( 0, outputId, m_dataName ); + } + + public override void ReadFromString( ref string[] nodeParams ) + { + base.ReadFromString( ref nodeParams ); + m_dataName = GetCurrentParam( ref nodeParams ); + m_fetchDataId = true; + } + + public override void WriteToString( ref string nodeInfo, ref string connectionsInfo ) + { + base.WriteToString( ref nodeInfo, ref connectionsInfo ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_dataName ); + } + + public override void OnMasterNodeReplaced( MasterNode newMasterNode ) + { + base.OnMasterNodeReplaced( newMasterNode ); + if( newMasterNode.CurrentMasterNodeCategory == AvailableShaderTypes.Template ) + { + FetchLocalVarData( newMasterNode ); + } + else + { + m_localVarsData = null; + m_currentDataIdx = -1; + } + } + + void FetchLocalVarData( MasterNode masterNode = null ) + { + FetchMultiPassTemplate( masterNode ); + if( m_multiPassMode ) + { + if( m_templateMPData != null ) + { + m_localVarsData = m_templateMPData.SubShaders[ SubShaderIdx ].Passes[ PassIdx ].LocalVarsList; + m_fetchDataId = true; + } + } + else + { + TemplateData currentTemplate = ( masterNode as TemplateMasterNode ).CurrentTemplate; + if( currentTemplate != null ) + { + m_localVarsData = currentTemplate.LocalVarsList; + m_fetchDataId = true; + } + else + { + m_localVarsData = null; + m_currentDataIdx = -1; + } + } + } + + public override void Destroy() + { + base.Destroy(); + m_dataLabels = null; + m_localVarsData = null; + m_upperLeftWidgetHelper = null; + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateLocalVarsNode.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateLocalVarsNode.cs.meta new file mode 100644 index 00000000..f7453d99 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateLocalVarsNode.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f708a5bf672ab004a9363a4a71f48f28 +timeCreated: 1518104790 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMasterNode.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMasterNode.cs new file mode 100644 index 00000000..6d6c1de9 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMasterNode.cs @@ -0,0 +1,750 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +// THIS FILE IS DEPRECATED AND SHOULD NOT BE USED + +#define SHOW_TEMPLATE_HELP_BOX + +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace AmplifyShaderEditor +{ + [Serializable] + [NodeAttributes( "Template Master Node", "Master", "Shader Generated according to template rules", null, KeyCode.None, false, true, "Template MultiPass Master Node", typeof( TemplateMultiPassMasterNode ) )] + public sealed class TemplateMasterNode : MasterNode + { + private const string WarningMessage = "Templates is a feature that is still heavily under development and users may experience some problems.\nPlease email support@amplify.pt if any issue occurs."; + private const string CurrentTemplateLabel = "Current Template"; + private const string OpenTemplateStr = "Edit Template"; + + //protected const string SnippetsFoldoutStr = " Snippets"; + //[SerializeField] + //private bool m_snippetsFoldout = true; + + [NonSerialized] + private TemplateData m_currentTemplate = null; + + private bool m_fireTemplateChange = false; + private bool m_fetchMasterNodeCategory = false; + private bool m_reRegisterTemplateData = false; + + [SerializeField] + private string m_templateGUID = string.Empty; + + [SerializeField] + private string m_templateName = string.Empty; + + [SerializeField] + private TemplatesBlendModule m_blendOpHelper = new TemplatesBlendModule(); + + [SerializeField] + private TemplateCullModeModule m_cullModeHelper = new TemplateCullModeModule(); + + [SerializeField] + private TemplateColorMaskModule m_colorMaskHelper = new TemplateColorMaskModule(); + + [SerializeField] + private TemplatesStencilBufferModule m_stencilBufferHelper = new TemplatesStencilBufferModule(); + + [SerializeField] + private TemplateDepthModule m_depthOphelper = new TemplateDepthModule(); + + [SerializeField] + private TemplateTagsModule m_tagsHelper = new TemplateTagsModule(); + + protected override void CommonInit( int uniqueId ) + { + base.CommonInit( uniqueId ); + m_masterNodeCategory = 1;// First Template + m_marginPreviewLeft = 20; + m_insideSize.y = 60; + m_customPrecision = true; + } + + public override void ReleaseResources() + { + if( m_currentTemplate != null && m_currentTemplate.AvailableShaderProperties != null ) + { + // Unregister old template properties + int oldPropertyCount = m_currentTemplate.AvailableShaderProperties.Count; + for( int i = 0; i < oldPropertyCount; i++ ) + { + UIUtils.ReleaseUniformName( UniqueId, m_currentTemplate.AvailableShaderProperties[ i ].PropertyName ); + } + } + } + + public override void OnEnable() + { + base.OnEnable(); + m_reRegisterTemplateData = true; + } + + void FetchInfoFromTemplate() + { + if( m_currentTemplate.BlendData.DataCheck == TemplateDataCheck.Valid ) + m_blendOpHelper.ConfigureFromTemplateData( m_currentTemplate.BlendData ); + + if( m_currentTemplate.CullModeData.DataCheck == TemplateDataCheck.Valid ) + m_cullModeHelper.ConfigureFromTemplateData( m_currentTemplate.CullModeData ); + + if( m_currentTemplate.ColorMaskData.DataCheck == TemplateDataCheck.Valid ) + m_colorMaskHelper.ConfigureFromTemplateData( m_currentTemplate.ColorMaskData ); + + if( m_currentTemplate.StencilData.DataCheck == TemplateDataCheck.Valid ) + m_stencilBufferHelper.ConfigureFromTemplateData( m_currentTemplate.StencilData ); + + if( m_currentTemplate.DepthData.DataCheck == TemplateDataCheck.Valid ) + m_depthOphelper.ConfigureFromTemplateData( m_currentTemplate.DepthData ); + + if( m_currentTemplate.TagData.DataCheck == TemplateDataCheck.Valid ) + m_tagsHelper.ConfigureFromTemplateData( m_currentTemplate.TagData ); + } + + void FetchCurrentTemplate() + { + m_currentTemplate = m_containerGraph.ParentWindow.TemplatesManagerInstance.GetTemplate( m_templateGUID ) as TemplateData; + if( m_currentTemplate == null ) + { + m_currentTemplate = m_containerGraph.ParentWindow.TemplatesManagerInstance.GetTemplate( m_templateName ) as TemplateData; + } + + if( m_currentTemplate != null ) + { + if( m_inputPorts.Count != m_currentTemplate.InputDataList.Count ) + { + DeleteAllInputConnections( true ); + + List<TemplateInputData> inputDataList = m_currentTemplate.InputDataList; + int count = inputDataList.Count; + for( int i = 0; i < count; i++ ) + { + AddInputPort( inputDataList[ i ].DataType, false, inputDataList[ i ].PortName, inputDataList[ i ].OrderId, inputDataList[ i ].PortCategory, inputDataList[ i ].PortUniqueId ); + } + FetchInfoFromTemplate(); + } + else + { + List<TemplateInputData> inputDataList = m_currentTemplate.InputDataList; + int count = inputDataList.Count; + for( int i = 0; i < count; i++ ) + { + m_inputPorts[ i ].ChangeProperties( inputDataList[ i ].PortName, inputDataList[ i ].DataType, false ); + } + } + } + } + + public override void RefreshAvailableCategories() + { + FetchCurrentTemplate(); + + int templateCount = m_containerGraph.ParentWindow.TemplatesManagerInstance.TemplateCount; + m_availableCategories = new MasterNodeCategoriesData[ templateCount + 1 ]; + m_availableCategoryLabels = new GUIContent[ templateCount + 1 ]; + + m_availableCategories[ 0 ] = new MasterNodeCategoriesData( AvailableShaderTypes.SurfaceShader, string.Empty ); + m_availableCategoryLabels[ 0 ] = new GUIContent( "Surface" ); + if( m_currentTemplate == null ) + { + m_masterNodeCategory = -1; + } + + for( int i = 0; i < templateCount; i++ ) + { + int idx = i + 1; + TemplateData templateData = m_containerGraph.ParentWindow.TemplatesManagerInstance.GetTemplate( i ) as TemplateData; + + if( m_currentTemplate != null && m_currentTemplate.GUID.Equals( templateData.GUID ) ) + m_masterNodeCategory = idx; + + m_availableCategories[ idx ] = new MasterNodeCategoriesData( AvailableShaderTypes.Template, templateData.GUID ); + m_availableCategoryLabels[ idx ] = new GUIContent( templateData.Name ); + } + } + + void SetCategoryIdxFromTemplate() + { + int templateCount = m_containerGraph.ParentWindow.TemplatesManagerInstance.TemplateCount; + for( int i = 0; i < templateCount; i++ ) + { + int idx = i + 1; + TemplateData templateData = m_containerGraph.ParentWindow.TemplatesManagerInstance.GetTemplate( i ) as TemplateData; + if( templateData != null && m_currentTemplate != null && m_currentTemplate.GUID.Equals( templateData.GUID ) ) + m_masterNodeCategory = idx; + } + } + + public void SetTemplate( TemplateData newTemplate, bool writeDefaultData, bool fetchMasterNodeCategory ) + { + ReleaseResources(); + + if( newTemplate == null || newTemplate.InputDataList == null ) + return; + + m_fetchMasterNodeCategory = fetchMasterNodeCategory; + + DeleteAllInputConnections( true ); + m_currentTemplate = newTemplate; + m_currentShaderData = newTemplate.Name; + + List<TemplateInputData> inputDataList = newTemplate.InputDataList; + int count = inputDataList.Count; + for( int i = 0; i < count; i++ ) + { + AddInputPort( inputDataList[ i ].DataType, false, inputDataList[ i ].PortName, inputDataList[ i ].OrderId, inputDataList[ i ].PortCategory, inputDataList[ i ].PortUniqueId ); + } + + if( writeDefaultData ) + { + ShaderName = newTemplate.DefaultShaderName; + } + + RegisterProperties(); + m_fireTemplateChange = true; + m_templateGUID = newTemplate.GUID; + m_templateName = newTemplate.DefaultShaderName; + FetchInfoFromTemplate(); + } + + void RegisterProperties() + { + if( m_currentTemplate != null ) + { + m_reRegisterTemplateData = false; + // Register old template properties + int newPropertyCount = m_currentTemplate.AvailableShaderProperties.Count; + for( int i = 0; i < newPropertyCount; i++ ) + { + int nodeId = UIUtils.CheckUniformNameOwner( m_currentTemplate.AvailableShaderProperties[ i ].PropertyName ); + if( nodeId > -1 ) + { + ParentNode node = m_containerGraph.GetNode( nodeId ); + if( node != null ) + { + UIUtils.ShowMessage( string.Format( "Template requires property name {0} which is currently being used by {1}. Please rename it and reload template.", m_currentTemplate.AvailableShaderProperties[ i ].PropertyName, node.Attributes.Name ) ); + } + else + { + UIUtils.ShowMessage( string.Format( "Template requires property name {0} which is currently being on your graph. Please rename it and reload template.", m_currentTemplate.AvailableShaderProperties[ i ].PropertyName ) ); + } + } + else + { + UIUtils.RegisterUniformName( UniqueId, m_currentTemplate.AvailableShaderProperties[ i ].PropertyName ); + } + } + } + } + + public override void DrawProperties() + { + if( m_currentTemplate == null ) + return; + + base.DrawProperties(); + + bool generalIsVisible = ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedGeneralShaderOptions; + NodeUtils.DrawPropertyGroup( ref generalIsVisible, GeneralFoldoutStr, DrawGeneralOptions ); + ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedGeneralShaderOptions = generalIsVisible; + if( m_currentTemplate.BlendData.DataCheck == TemplateDataCheck.Valid ) + m_blendOpHelper.Draw( this ); + + + if( m_currentTemplate.StencilData.DataCheck == TemplateDataCheck.Valid ) + { + CullMode cullMode = ( m_currentTemplate.CullModeData.DataCheck == TemplateDataCheck.Valid ) ? m_cullModeHelper.CurrentCullMode : CullMode.Back; + m_stencilBufferHelper.Draw( this, cullMode ); + } + + if( m_currentTemplate.DepthData.DataCheck == TemplateDataCheck.Valid ) + m_depthOphelper.Draw( this ); + + if( m_currentTemplate.TagData.DataCheck == TemplateDataCheck.Valid ) + m_tagsHelper.Draw( this ); + + DrawMaterialInputs( UIUtils.MenuItemToolbarStyle ); + + // NodeUtils.DrawPropertyGroup( ref m_snippetsFoldout, SnippetsFoldoutStr, DrawSnippetOptions ); + if( GUILayout.Button( OpenTemplateStr ) && m_currentTemplate != null ) + { + try + { + string pathname = AssetDatabase.GUIDToAssetPath( m_currentTemplate.GUID ); + if( !string.IsNullOrEmpty( pathname ) ) + { + Shader selectedTemplate = AssetDatabase.LoadAssetAtPath<Shader>( pathname ); + if( selectedTemplate != null ) + { + AssetDatabase.OpenAsset( selectedTemplate, 1 ); + } + } + } + catch( Exception e ) + { + Debug.LogException( e ); + } + } + +#if SHOW_TEMPLATE_HELP_BOX + EditorGUILayout.HelpBox( WarningMessage, MessageType.Warning ); +#endif + + } + + public void DrawGeneralOptions() + { + DrawShaderName(); + DrawCurrentShaderType(); + EditorGUI.BeginChangeCheck(); + DrawPrecisionProperty( false ); + if( EditorGUI.EndChangeCheck() ) + ContainerGraph.CurrentPrecision = m_currentPrecisionType; + + if( m_currentTemplate.CullModeData.DataCheck == TemplateDataCheck.Valid ) + m_cullModeHelper.Draw( this ); + + if( m_currentTemplate.ColorMaskData.DataCheck == TemplateDataCheck.Valid ) + m_colorMaskHelper.Draw( this ); + } + + //public void DrawSnippetOptions() + //{ + // m_currentTemplate.DrawSnippetProperties( this ); + //} + + bool CreateInstructionsForList( ref List<InputPort> ports, ref string shaderBody, ref List<string> vertexInstructions, ref List<string> fragmentInstructions ) + { + if( ports.Count == 0 ) + return true; + + bool isValid = true; + UIUtils.CurrentWindow.CurrentGraph.ResetNodesLocalVariables(); + for( int i = 0; i < ports.Count; i++ ) + { + TemplateInputData inputData = m_currentTemplate.InputDataFromId( ports[ i ].PortId ); + if( ports[ i ].IsConnected ) + { + m_currentDataCollector.ResetInstructions(); + m_currentDataCollector.ResetVertexInstructions(); + + m_currentDataCollector.PortCategory = ports[ i ].Category; + string newPortInstruction = ports[ i ].GeneratePortInstructions( ref m_currentDataCollector ); + + + if( m_currentDataCollector.DirtySpecialLocalVariables ) + { + string cleanVariables = m_currentDataCollector.SpecialLocalVariables.Replace( "\t", string.Empty ); + m_currentDataCollector.AddInstructions( cleanVariables, false ); + m_currentDataCollector.ClearSpecialLocalVariables(); + } + + if( m_currentDataCollector.DirtyVertexVariables ) + { + string cleanVariables = m_currentDataCollector.VertexLocalVariables.Replace( "\t", string.Empty ); + m_currentDataCollector.AddVertexInstruction( cleanVariables, UniqueId, false ); + m_currentDataCollector.ClearVertexLocalVariables(); + } + + // fill functions + for( int j = 0; j < m_currentDataCollector.InstructionsList.Count; j++ ) + { + fragmentInstructions.Add( m_currentDataCollector.InstructionsList[ j ].PropertyName ); + } + + for( int j = 0; j < m_currentDataCollector.VertexDataList.Count; j++ ) + { + vertexInstructions.Add( m_currentDataCollector.VertexDataList[ j ].PropertyName ); + } + + isValid = m_currentTemplate.FillTemplateBody( inputData.TagId, ref shaderBody, newPortInstruction ) && isValid; + } + else + { + isValid = m_currentTemplate.FillTemplateBody( inputData.TagId, ref shaderBody, inputData.DefaultValue ) && isValid; + } + } + return isValid; + } + + public override void Draw( DrawInfo drawInfo ) + { + base.Draw( drawInfo ); + + if( m_currentTemplate == null ) + { + FetchCurrentTemplate(); + } + + if( m_reRegisterTemplateData ) + { + RegisterProperties(); + } + + if( m_containerGraph.IsInstancedShader ) + { + DrawInstancedIcon( drawInfo ); + } + + if( m_fetchMasterNodeCategory ) + { + if( m_availableCategories != null ) + { + m_fetchMasterNodeCategory = false; + SetCategoryIdxFromTemplate(); + } + } + + if( m_fireTemplateChange ) + { + m_fireTemplateChange = false; + m_containerGraph.FireMasterNodeReplacedEvent(); + } + } + + public override void UpdateFromShader( Shader newShader ) + { + if( m_currentMaterial != null ) + { + m_currentMaterial.shader = newShader; + } + CurrentShader = newShader; + } + + public override void UpdateMasterNodeMaterial( Material material ) + { + m_currentMaterial = material; + FireMaterialChangedEvt(); + } + + public override Shader Execute( string pathname, bool isFullPath ) + { + if( m_currentTemplate == null ) + return m_currentShader; + + //Create data collector + ForceReordering(); + base.Execute( pathname, isFullPath ); + + SetupNodeCategories(); + + m_currentDataCollector.TemplateDataCollectorInstance.BuildFromTemplateData( m_currentDataCollector, m_currentTemplate ); + int shaderPropertiesAmount = m_currentTemplate.AvailableShaderProperties.Count; + for( int i = 0; i < shaderPropertiesAmount; i++ ) + { + m_currentDataCollector.SoftRegisterUniform( m_currentTemplate.AvailableShaderProperties[ i ] ); + } + m_containerGraph.CheckPropertiesAutoRegister( ref m_currentDataCollector ); + + //Sort ports by both + List<InputPort> fragmentPorts = new List<InputPort>(); + List<InputPort> vertexPorts = new List<InputPort>(); + SortInputPorts( ref vertexPorts, ref fragmentPorts ); + + string shaderBody = m_currentTemplate.TemplateBody; + + List<string> vertexInstructions = new List<string>(); + List<string> fragmentInstructions = new List<string>(); + + bool validBody = true; + + validBody = CreateInstructionsForList( ref fragmentPorts, ref shaderBody, ref vertexInstructions, ref fragmentInstructions ) && validBody; + ContainerGraph.ResetNodesLocalVariablesIfNot( MasterNodePortCategory.Vertex ); + validBody = CreateInstructionsForList( ref vertexPorts, ref shaderBody, ref vertexInstructions, ref fragmentInstructions ) && validBody; + + m_currentTemplate.ResetTemplateUsageData(); + + // Fill vertex interpolators assignment + for( int i = 0; i < m_currentDataCollector.VertexInterpDeclList.Count; i++ ) + { + vertexInstructions.Add( m_currentDataCollector.VertexInterpDeclList[ i ] ); + } + + vertexInstructions.AddRange( m_currentDataCollector.TemplateDataCollectorInstance.GetInterpUnusedChannels() ); + //Fill common local variables and operations + + validBody = m_currentTemplate.FillVertexInstructions( ref shaderBody, vertexInstructions.ToArray() ) && validBody; + validBody = m_currentTemplate.FillFragmentInstructions( ref shaderBody, fragmentInstructions.ToArray() ) && validBody; + + // Add Instanced Properties + if( m_containerGraph.IsInstancedShader ) + { + m_currentDataCollector.TabifyInstancedVars(); + m_currentDataCollector.InstancedPropertiesList.Insert( 0, new PropertyDataCollector( -1, string.Format( IOUtils.InstancedPropertiesBegin, UIUtils.RemoveInvalidCharacters( m_shaderName ) ) ) ); + m_currentDataCollector.InstancedPropertiesList.Add( new PropertyDataCollector( -1, IOUtils.InstancedPropertiesEnd ) ); + m_currentDataCollector.UniformsList.AddRange( m_currentDataCollector.InstancedPropertiesList ); + } + + //Add Functions + m_currentDataCollector.UniformsList.AddRange( m_currentDataCollector.FunctionsList ); + + // Fill common tags + m_currentDataCollector.IncludesList.AddRange( m_currentDataCollector.PragmasList ); + + validBody = m_currentTemplate.FillTemplateBody( m_currentTemplate.ShaderNameId, ref shaderBody, string.Format( TemplatesManager.NameFormatter, m_shaderName ) ) && validBody; + validBody = m_currentTemplate.FillTemplateBody( TemplatesManager.TemplatePassTag, ref shaderBody, m_currentDataCollector.GrabPassList ) && validBody; + validBody = m_currentTemplate.FillTemplateBody( TemplatesManager.TemplatePragmaTag, ref shaderBody, m_currentDataCollector.IncludesList ) && validBody; + //validBody = m_currentTemplate.FillTemplateBody( TemplatesManager.TemplateTagsTag, ref shaderBody, m_currentDataCollector.TagsList ) && validBody; + validBody = m_currentTemplate.FillTemplateBody( TemplatesManager.TemplatePropertyTag, ref shaderBody, m_currentDataCollector.BuildUnformatedPropertiesStringArr() ) && validBody; + validBody = m_currentTemplate.FillTemplateBody( TemplatesManager.TemplateGlobalsTag, ref shaderBody, m_currentDataCollector.UniformsList ) && validBody; + validBody = m_currentTemplate.FillTemplateBody( m_currentTemplate.VertexDataId, ref shaderBody, m_currentDataCollector.VertexInputList.ToArray() ) && validBody; + validBody = m_currentTemplate.FillTemplateBody( m_currentTemplate.InterpDataId, ref shaderBody, m_currentDataCollector.InterpolatorList.ToArray() ) && validBody; + + if( m_currentTemplate.BlendData.ValidBlendMode ) + { + validBody = m_currentTemplate.FillTemplateBody( m_currentTemplate.BlendData.BlendModeId, ref shaderBody, m_blendOpHelper.CurrentBlendFactor ) && validBody; + } + + if( m_currentTemplate.BlendData.ValidBlendOp ) + { + validBody = m_currentTemplate.FillTemplateBody( m_currentTemplate.BlendData.BlendOpId, ref shaderBody, m_blendOpHelper.CurrentBlendOp ) && validBody; + } + + if( m_currentTemplate.BlendData.ValidAlphaToMask ) + { + validBody = m_currentTemplate.FillTemplateBody( m_currentTemplate.BlendData.AlphaToMaskId, ref shaderBody, m_blendOpHelper.CurrentAlphaToMask ) && validBody; + } + + if( m_currentTemplate.DepthData.ValidZWrite ) + { + validBody = m_currentTemplate.FillTemplateBody( m_currentTemplate.DepthData.ZWriteModeId, ref shaderBody, m_depthOphelper.CurrentZWriteMode ) && validBody; + } + + if( m_currentTemplate.DepthData.ValidZTest ) + { + validBody = m_currentTemplate.FillTemplateBody( m_currentTemplate.DepthData.ZTestModeId, ref shaderBody, m_depthOphelper.CurrentZTestMode ) && validBody; + } + + if( m_currentTemplate.DepthData.ValidOffset ) + { + validBody = m_currentTemplate.FillTemplateBody( m_currentTemplate.DepthData.OffsetId, ref shaderBody, m_depthOphelper.CurrentOffset ) && validBody; + } + + if( m_currentTemplate.CullModeData.DataCheck == TemplateDataCheck.Valid ) + { + validBody = m_currentTemplate.FillTemplateBody( m_currentTemplate.CullModeData.CullModeId, ref shaderBody, m_cullModeHelper.GenerateShaderData(false) ) && validBody; + } + + if( m_currentTemplate.ColorMaskData.DataCheck == TemplateDataCheck.Valid ) + { + validBody = m_currentTemplate.FillTemplateBody( m_currentTemplate.ColorMaskData.ColorMaskId, ref shaderBody, m_colorMaskHelper.GenerateShaderData( false ) ) && validBody; + } + + if( m_currentTemplate.StencilData.DataCheck == TemplateDataCheck.Valid ) + { + CullMode cullMode = ( m_currentTemplate.CullModeData.DataCheck == TemplateDataCheck.Valid ) ? m_cullModeHelper.CurrentCullMode : CullMode.Back; + validBody = m_currentTemplate.FillTemplateBody( m_currentTemplate.StencilData.StencilBufferId, ref shaderBody, m_stencilBufferHelper.CreateStencilOp( cullMode ) ) && validBody; + } + + if( m_currentTemplate.TagData.DataCheck == TemplateDataCheck.Valid ) + { + validBody = m_currentTemplate.FillTemplateBody( m_currentTemplate.TagData.TagsId, ref shaderBody, m_tagsHelper.GenerateTags() ) && validBody; + } + + if( m_currentDataCollector.TemplateDataCollectorInstance.HasVertexInputParams ) + { + validBody = m_currentTemplate.FillTemplateBody( TemplatesManager.TemplateInputsVertParamsTag, ref shaderBody, m_currentDataCollector.TemplateDataCollectorInstance.VertexInputParamsStr ) && validBody; + } + + if( m_currentDataCollector.TemplateDataCollectorInstance.HasFragmentInputParams ) + { + validBody = m_currentTemplate.FillTemplateBody( TemplatesManager.TemplateInputsFragParamsTag, ref shaderBody, m_currentDataCollector.TemplateDataCollectorInstance.FragInputParamsStr ) && validBody; + } + + m_currentTemplate.FillEmptyTags( ref shaderBody ); + + //m_currentTemplate.InsertSnippets( ref shaderBody ); + + vertexInstructions.Clear(); + vertexInstructions = null; + + fragmentInstructions.Clear(); + fragmentInstructions = null; + if( validBody ) + { + UpdateShaderAsset( ref pathname, ref shaderBody, isFullPath ); + } + + return m_currentShader; + } + + public override void ReadFromString( ref string[] nodeParams ) + { + base.ReadFromString( ref nodeParams ); + try + { + ShaderName = GetCurrentParam( ref nodeParams ); + if( m_shaderName.Length > 0 ) + ShaderName = UIUtils.RemoveShaderInvalidCharacters( ShaderName ); + + string templateGUID = GetCurrentParam( ref nodeParams ); + string templateShaderName = string.Empty; + if( UIUtils.CurrentShaderVersion() > 13601 ) + { + templateShaderName = GetCurrentParam( ref nodeParams ); + } + + TemplateData template = m_containerGraph.ParentWindow.TemplatesManagerInstance.GetTemplate( templateGUID ) as TemplateData; + if( template != null ) + { + SetTemplate( template, false, true ); + } + else + { + template = m_containerGraph.ParentWindow.TemplatesManagerInstance.GetTemplateByName( templateShaderName ) as TemplateData; + if( template != null ) + { + SetTemplate( template, false, true ); + } + else + { + m_masterNodeCategory = -1; + } + } + + if( UIUtils.CurrentShaderVersion() > 13902 ) + { + //BLEND MODULE + if( m_currentTemplate.BlendData.ValidBlendMode ) + { + m_blendOpHelper.ReadBlendModeFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + if( m_currentTemplate.BlendData.ValidBlendOp ) + { + m_blendOpHelper.ReadBlendOpFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + //CULL MODE + if( m_currentTemplate.CullModeData.DataCheck == TemplateDataCheck.Valid ) + { + m_cullModeHelper.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + //COLOR MASK + if( m_currentTemplate.ColorMaskData.DataCheck == TemplateDataCheck.Valid ) + { + m_colorMaskHelper.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + //STENCIL BUFFER + if( m_currentTemplate.StencilData.DataCheck == TemplateDataCheck.Valid ) + { + m_stencilBufferHelper.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + } + + if( UIUtils.CurrentShaderVersion() > 14202 ) + { + //DEPTH OPTIONS + if( m_currentTemplate.DepthData.ValidZWrite ) + { + m_depthOphelper.ReadZWriteFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + if( m_currentTemplate.DepthData.ValidZTest ) + { + m_depthOphelper.ReadZTestFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + if( m_currentTemplate.DepthData.ValidOffset ) + { + m_depthOphelper.ReadOffsetFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + } + + //TAGS + if( UIUtils.CurrentShaderVersion() > 14301 ) + { + if( m_currentTemplate.TagData.DataCheck == TemplateDataCheck.Valid ) + m_tagsHelper.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + } + catch( Exception e ) + { + Debug.LogException( e, this ); + } + m_containerGraph.CurrentCanvasMode = NodeAvailability.TemplateShader; + m_containerGraph.CurrentPrecision = m_currentPrecisionType; + } + + public override void WriteToString( ref string nodeInfo, ref string connectionsInfo ) + { + base.WriteToString( ref nodeInfo, ref connectionsInfo ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_shaderName ); + IOUtils.AddFieldValueToString( ref nodeInfo, ( m_currentTemplate != null ) ? m_currentTemplate.GUID : string.Empty ); + IOUtils.AddFieldValueToString( ref nodeInfo, ( m_currentTemplate != null ) ? m_currentTemplate.DefaultShaderName : string.Empty ); + + //BLEND MODULE + if( m_currentTemplate.BlendData.ValidBlendMode ) + { + m_blendOpHelper.WriteBlendModeToString( ref nodeInfo ); + } + + if( m_currentTemplate.BlendData.ValidBlendOp ) + { + m_blendOpHelper.WriteBlendOpToString( ref nodeInfo ); + } + + //CULL MODULE + if( m_currentTemplate.CullModeData.DataCheck == TemplateDataCheck.Valid ) + { + m_cullModeHelper.WriteToString( ref nodeInfo ); + } + + //COLOR MASK MODULE + if( m_currentTemplate.ColorMaskData.DataCheck == TemplateDataCheck.Valid ) + { + m_colorMaskHelper.WriteToString( ref nodeInfo ); + } + + //STENCIL BUFFER MODULE + if( m_currentTemplate.StencilData.DataCheck == TemplateDataCheck.Valid ) + { + m_stencilBufferHelper.WriteToString( ref nodeInfo ); + } + + //DEPTH MODULE + if( m_currentTemplate.DepthData.ValidZWrite ) + { + m_depthOphelper.WriteZWriteToString( ref nodeInfo ); + } + + if( m_currentTemplate.DepthData.ValidZTest ) + { + m_depthOphelper.WriteZTestToString( ref nodeInfo ); + } + + if( m_currentTemplate.DepthData.ValidOffset ) + { + m_depthOphelper.WriteOffsetToString( ref nodeInfo ); + } + + //TAGS + if( m_currentTemplate.TagData.DataCheck == TemplateDataCheck.Valid ) + { + m_tagsHelper.WriteToString( ref nodeInfo ); + } + } + + public override void Destroy() + { + base.Destroy(); + m_currentTemplate = null; + m_blendOpHelper = null; + m_cullModeHelper = null; + m_colorMaskHelper.Destroy(); + m_colorMaskHelper = null; + m_stencilBufferHelper.Destroy(); + m_stencilBufferHelper = null; + m_tagsHelper.Destroy(); + m_tagsHelper = null; + + } + + public TemplateData CurrentTemplate { get { return m_currentTemplate; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMasterNode.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMasterNode.cs.meta new file mode 100644 index 00000000..b17058f3 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMasterNode.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8bbd856408a816448a2686501df37397 +timeCreated: 1493905112 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMenuItems.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMenuItems.cs new file mode 100644 index 00000000..920dc274 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMenuItems.cs @@ -0,0 +1,50 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> +using UnityEditor; + +namespace AmplifyShaderEditor +{ + public class TemplateMenuItems + { + [MenuItem( "Assets/Create/Amplify Shader/Legacy/Unlit", false, 85 )] + public static void ApplyTemplateLegacyUnlit() + { + AmplifyShaderEditorWindow.CreateConfirmationTemplateShader( "0770190933193b94aaa3065e307002fa" ); + } + [MenuItem( "Assets/Create/Amplify Shader/Legacy/Post Process", false, 85 )] + public static void ApplyTemplateLegacyPostProcess() + { + AmplifyShaderEditorWindow.CreateConfirmationTemplateShader( "c71b220b631b6344493ea3cf87110c93" ); + } + [MenuItem( "Assets/Create/Amplify Shader/Deprecated/Legacy/Default Unlit", false, 85 )] + public static void ApplyTemplateDeprecatedLegacyDefaultUnlit() + { + AmplifyShaderEditorWindow.CreateConfirmationTemplateShader( "6e114a916ca3e4b4bb51972669d463bf" ); + } + [MenuItem( "Assets/Create/Amplify Shader/Legacy/Default UI", false, 85 )] + public static void ApplyTemplateLegacyDefaultUI() + { + AmplifyShaderEditorWindow.CreateConfirmationTemplateShader( "5056123faa0c79b47ab6ad7e8bf059a4" ); + } + [MenuItem( "Assets/Create/Amplify Shader/Legacy/Unlit Lightmap", false, 85 )] + public static void ApplyTemplateLegacyUnlitLightmap() + { + AmplifyShaderEditorWindow.CreateConfirmationTemplateShader( "899e609c083c74c4ca567477c39edef0" ); + } + [MenuItem( "Assets/Create/Amplify Shader/Legacy/Default Sprites", false, 85 )] + public static void ApplyTemplateLegacyDefaultSprites() + { + AmplifyShaderEditorWindow.CreateConfirmationTemplateShader( "0f8ba0101102bb14ebf021ddadce9b49" ); + } + [MenuItem( "Assets/Create/Amplify Shader/Legacy/Particles Alpha Blended", false, 85 )] + public static void ApplyTemplateLegacyParticlesAlphaBlended() + { + AmplifyShaderEditorWindow.CreateConfirmationTemplateShader( "0b6a9f8b4f707c74ca64c0be8e590de0" ); + } + [MenuItem( "Assets/Create/Amplify Shader/Legacy/Multi Pass Unlit", false, 85 )] + public static void ApplyTemplateLegacyMultiPassUnlit() + { + AmplifyShaderEditorWindow.CreateConfirmationTemplateShader( "e1de45c0d41f68c41b2cc20c8b9c05ef" ); + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMenuItems.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMenuItems.cs.meta new file mode 100644 index 00000000..69a390bc --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMenuItems.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: da0b931bd234a1e43b65f684d4b59bfb +timeCreated: 1496736284 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModuleHelper.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModuleHelper.cs new file mode 100644 index 00000000..147fee0b --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModuleHelper.cs @@ -0,0 +1,497 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using UnityEngine; + +namespace AmplifyShaderEditor +{ + + [Serializable] + public class TemplateModulesHelper + { + [SerializeField] + internal bool Foldout = false; + + private bool m_isDirty = false; + + [SerializeField] + private TemplatesBlendModule m_blendOpHelper = new TemplatesBlendModule(); + + [SerializeField] + private TemplateCullModeModule m_cullModeHelper = new TemplateCullModeModule(); + + [SerializeField] + private TemplateColorMaskModule m_colorMaskHelper = new TemplateColorMaskModule(); + + [SerializeField] + private TemplatesStencilBufferModule m_stencilBufferHelper = new TemplatesStencilBufferModule(); + + [SerializeField] + private TemplateDepthModule m_depthOphelper = new TemplateDepthModule(); + + [SerializeField] + private TemplateTagsModule m_tagsHelper = new TemplateTagsModule(); + + [SerializeField] + private TemplateShaderModelModule m_shaderModelHelper = new TemplateShaderModelModule(); + + [SerializeField] + private TemplateAdditionalIncludesHelper m_additionalIncludes = new TemplateAdditionalIncludesHelper(); + + [SerializeField] + private TemplateAdditionalDefinesHelper m_additionalDefines = new TemplateAdditionalDefinesHelper(); + + [SerializeField] + private TemplateAdditionalPragmasHelper m_additionalPragmas = new TemplateAdditionalPragmasHelper(); + + [SerializeField] + private TemplateAdditionalDirectivesHelper m_additionalDirectives = new TemplateAdditionalDirectivesHelper(" Additional Directives"); + + [SerializeField] + private bool m_hasValidData = false; + + [SerializeField] + private bool m_allModulesMode = false; + + public void CopyFrom( TemplateModulesHelper other ) + { + m_allModulesMode = other.AllModulesMode; + + if( other.BlendOpHelper.IsDirty ) + { + m_blendOpHelper.CopyFrom( other.BlendOpHelper, true ); + } + + if( other.CullModeHelper.IsDirty ) + { + m_cullModeHelper.CopyFrom( other.CullModeHelper , true ); + } + + if( other.ColorMaskHelper.IsDirty ) + { + m_colorMaskHelper.CopyFrom( other.ColorMaskHelper , true); + } + + if( other.StencilBufferHelper.IsDirty ) + { + m_stencilBufferHelper.CopyFrom( other.StencilBufferHelper,true ); + } + + if( other.DepthOphelper.IsDirty ) + { + m_depthOphelper.CopyFrom( other.DepthOphelper,true ); + } + + if( other.TagsHelper.IsDirty ) + { + m_tagsHelper.CopyFrom( other.TagsHelper ); + } + + if( other.ShaderModelHelper.IsDirty ) + { + m_shaderModelHelper.CopyFrom( other.ShaderModelHelper, true ); + } + } + + public void SyncWith( TemplateModulesHelper other ) + { + + if( m_blendOpHelper.ValidData && other.BlendOpHelper.ValidData ) + { + m_blendOpHelper.CopyFrom( other.BlendOpHelper, false ); + } + + if( m_cullModeHelper.ValidData && other.CullModeHelper.ValidData ) + { + m_cullModeHelper.CopyFrom( other.CullModeHelper, false ); + } + + if( m_colorMaskHelper.ValidData && other.ColorMaskHelper.ValidData ) + { + m_colorMaskHelper.CopyFrom( other.ColorMaskHelper , false ); + } + + if( m_stencilBufferHelper.ValidData && other.StencilBufferHelper.ValidData ) + { + m_stencilBufferHelper.CopyFrom( other.StencilBufferHelper, false ); + } + + if( m_depthOphelper.ValidData && other.DepthOphelper.ValidData ) + { + m_depthOphelper.CopyFrom( other.DepthOphelper, false ); + } + + if( m_shaderModelHelper.ValidData && other.ShaderModelHelper.ValidData ) + { + m_shaderModelHelper.CopyFrom( other.ShaderModelHelper , false); + } + } + + public void FetchDataFromTemplate( TemplateModulesData module ) + { + m_allModulesMode = module.AllModulesMode; + + if( module.PragmaTag.IsValid ) + { + m_hasValidData = true; + //m_additionalPragmas.IsValid = true; + //m_additionalPragmas.FillNativeItems( module.IncludePragmaContainer.PragmasList ); + + //m_additionalIncludes.IsValid = true; + //m_additionalIncludes.FillNativeItems( module.IncludePragmaContainer.IncludesList ); + + //m_additionalDefines.IsValid = true; + //m_additionalDefines.FillNativeItems( module.IncludePragmaContainer.DefinesList ); + + m_additionalDirectives.FillNativeItems( module.IncludePragmaContainer.NativeDirectivesList ); + m_additionalDirectives.IsValid = true; + } + else + { + //m_additionalPragmas.IsValid = false; + //m_additionalIncludes.IsValid = false; + //m_additionalDefines.IsValid = false; + m_additionalDirectives.IsValid = false; + } + + m_blendOpHelper.ConfigureFromTemplateData( module.BlendData ); + if( module.BlendData.DataCheck == TemplateDataCheck.Valid ) + { + m_hasValidData = true; + } + + m_cullModeHelper.ConfigureFromTemplateData( module.CullModeData ); + if( module.CullModeData.DataCheck == TemplateDataCheck.Valid ) + { + m_hasValidData = true; + } + + m_colorMaskHelper.ConfigureFromTemplateData( module.ColorMaskData ); + if( module.ColorMaskData.DataCheck == TemplateDataCheck.Valid ) + { + m_hasValidData = true; + } + + m_stencilBufferHelper.ConfigureFromTemplateData( module.StencilData ); + if( module.StencilData.DataCheck == TemplateDataCheck.Valid ) + { + m_hasValidData = true; + } + + m_depthOphelper.ConfigureFromTemplateData( module.DepthData ); + if( module.DepthData.DataCheck == TemplateDataCheck.Valid ) + { + m_hasValidData = true; + } + + m_tagsHelper.ConfigureFromTemplateData( module.TagData ); + if( module.TagData.DataCheck == TemplateDataCheck.Valid ) + { + m_hasValidData = true; + } + + m_shaderModelHelper.ConfigureFromTemplateData( module.ShaderModel ); + if( module.ShaderModel.DataCheck == TemplateDataCheck.Valid ) + { + m_hasValidData = true; + } + } + + public void OnLogicUpdate( TemplateModulesData currentModule ) + { + if( currentModule.TagData.DataCheck == TemplateDataCheck.Valid ) + m_tagsHelper.OnLogicUpdate(); + } + + public void Draw( ParentNode owner, TemplateModulesData currentModule , TemplateModulesHelper parent = null ) + { + if( currentModule.ShaderModel.DataCheck == TemplateDataCheck.Valid ) + m_shaderModelHelper.Draw( owner ); + + m_isDirty = m_shaderModelHelper.IsDirty; + + if( currentModule.CullModeData.DataCheck == TemplateDataCheck.Valid ) + m_cullModeHelper.Draw( owner ); + + m_isDirty = m_isDirty || m_cullModeHelper.IsDirty; + + if( currentModule.ColorMaskData.DataCheck == TemplateDataCheck.Valid ) + m_colorMaskHelper.Draw( owner ); + + m_isDirty = m_isDirty || m_colorMaskHelper.IsDirty; + + if( currentModule.DepthData.DataCheck == TemplateDataCheck.Valid ) + m_depthOphelper.Draw( owner, false ); + + m_isDirty = m_isDirty || m_depthOphelper.IsDirty; + + if( currentModule.BlendData.DataCheck == TemplateDataCheck.Valid ) + m_blendOpHelper.Draw( owner, false ); + + m_isDirty = m_isDirty || m_blendOpHelper.IsDirty; + + + if( currentModule.StencilData.DataCheck == TemplateDataCheck.Valid ) + { + CullMode cullMode = CullMode.Back; + if( currentModule.CullModeData.DataCheck == TemplateDataCheck.Valid ) + { + cullMode = m_cullModeHelper.CurrentCullMode; + } + else if( parent != null && parent.CullModeHelper.ValidData ) + { + cullMode = parent.CullModeHelper.CurrentCullMode; + } + m_stencilBufferHelper.Draw( owner, cullMode, false ); + } + + m_isDirty = m_isDirty || m_stencilBufferHelper.IsDirty; + + if( currentModule.TagData.DataCheck == TemplateDataCheck.Valid ) + m_tagsHelper.Draw( owner, false ); + + m_isDirty = m_isDirty || m_tagsHelper.IsDirty; + + if( currentModule.PragmaTag.IsValid ) + { + //m_additionalDefines.Draw( owner ); + //m_additionalIncludes.Draw( owner ); + //m_additionalPragmas.Draw( owner ); + m_additionalDirectives.Draw( owner , false); + } + + m_isDirty = m_isDirty || + //m_additionalDefines.IsDirty || + //m_additionalIncludes.IsDirty || + //m_additionalPragmas.IsDirty || + m_additionalDirectives.IsDirty; + } + + public void Destroy() + { + m_shaderModelHelper = null; + m_blendOpHelper = null; + m_cullModeHelper = null; + m_colorMaskHelper.Destroy(); + m_colorMaskHelper = null; + m_stencilBufferHelper.Destroy(); + m_stencilBufferHelper = null; + m_tagsHelper.Destroy(); + m_tagsHelper = null; + m_additionalDefines.Destroy(); + m_additionalDefines = null; + m_additionalIncludes.Destroy(); + m_additionalIncludes = null; + m_additionalPragmas.Destroy(); + m_additionalPragmas = null; + m_additionalDirectives.Destroy(); + m_additionalDirectives = null; + } + + public string GenerateAllModulesString( bool isSubShader ) + { + string moduleBody = string.Empty; + if( !ShaderModelHelper.IndependentModule ) + { + moduleBody += ShaderModelHelper.GenerateShaderData( isSubShader ) + "\n"; + } + + if( !BlendOpHelper.IndependentModule ) + { + if( BlendOpHelper.BlendModeEnabled ) + moduleBody += BlendOpHelper.CurrentBlendFactor + "\n"; + + if( BlendOpHelper.BlendOpActive ) + moduleBody += BlendOpHelper.CurrentBlendOp + "\n"; + + } + + if( !BlendOpHelper.AlphaToMaskIndependent ) + { + if( BlendOpHelper.ValidAlphaToMask && BlendOpHelper.AlphaToMaskValue ) + moduleBody += BlendOpHelper.CurrentAlphaToMask + "\n"; + } + + if( !CullModeHelper.IndependentModule ) + moduleBody += CullModeHelper.GenerateShaderData( isSubShader ) + "\n"; + + if( !ColorMaskHelper.IndependentModule ) + moduleBody += ColorMaskHelper.GenerateShaderData( isSubShader ) + "\n"; + + if( !DepthOphelper.IndependentModule ) + { + moduleBody += DepthOphelper.CurrentZWriteMode; + moduleBody += DepthOphelper.CurrentZTestMode; + if( DepthOphelper.OffsetEnabled ) + moduleBody += DepthOphelper.CurrentOffset; + } + + if( !StencilBufferHelper.IndependentModule && StencilBufferHelper.Active ) + { + CullMode cullMode = ( CullModeHelper.ValidData ) ? CullModeHelper.CurrentCullMode : CullMode.Back; + moduleBody += StencilBufferHelper.CreateStencilOp( cullMode ); + } + + return moduleBody; + } + + public void ReadFromString( ref uint index, ref string[] nodeParams ) + { + try + { + m_blendOpHelper.ReadFromString( ref index, ref nodeParams ); + } + catch( Exception e ) + { + Debug.LogException( e ); + } + try + { + m_cullModeHelper.ReadFromString( ref index, ref nodeParams ); + } + catch( Exception e ) + { + Debug.LogException( e ); + } + try + { + m_colorMaskHelper.ReadFromString( ref index, ref nodeParams ); + } + catch( Exception e ) + { + Debug.LogException( e ); + } + try + { + m_stencilBufferHelper.ReadFromString( ref index, ref nodeParams ); + } + catch( Exception e ) + { + Debug.LogException( e ); + } + try + { + m_depthOphelper.ReadFromString( ref index, ref nodeParams ); + } + catch( Exception e ) + { + Debug.LogException( e ); + } + try + { + m_tagsHelper.ReadFromString( ref index, ref nodeParams ); + } + catch( Exception e ) + { + Debug.LogException( e ); + } + try + { + m_shaderModelHelper.ReadFromString( ref index, ref nodeParams ); + } + catch( Exception e ) + { + Debug.LogException( e ); + } + + + if( UIUtils.CurrentShaderVersion() < 15312 ) + { + try + { + m_additionalDefines.ReadFromString( ref index, ref nodeParams ); + } + catch( Exception e ) + { + Debug.LogException( e ); + } + try + { + m_additionalPragmas.ReadFromString( ref index, ref nodeParams ); + } + catch( Exception e ) + { + Debug.LogException( e ); + } + try + { + m_additionalIncludes.ReadFromString( ref index, ref nodeParams ); + } + catch( Exception e ) + { + Debug.LogException( e ); + } + + m_additionalDirectives.AddItems( AdditionalLineType.Include, m_additionalIncludes.ItemsList ); + m_additionalDirectives.AddItems( AdditionalLineType.Define, m_additionalDefines.ItemsList ); + m_additionalDirectives.AddItems( AdditionalLineType.Pragma, m_additionalPragmas.ItemsList ); + + } + else + { + try + { + m_additionalDirectives.ReadFromString( ref index, ref nodeParams ); + } + catch( Exception e ) + { + Debug.LogException( e ); + } + } + } + + public void WriteToString( ref string nodeInfo ) + { + m_blendOpHelper.WriteToString( ref nodeInfo ); + m_cullModeHelper.WriteToString( ref nodeInfo ); + m_colorMaskHelper.WriteToString( ref nodeInfo ); + m_stencilBufferHelper.WriteToString( ref nodeInfo ); + m_depthOphelper.WriteToString( ref nodeInfo ); + m_tagsHelper.WriteToString( ref nodeInfo ); + m_shaderModelHelper.WriteToString( ref nodeInfo ); + + //m_additionalDefines.WriteToString( ref nodeInfo ); + //m_additionalPragmas.WriteToString( ref nodeInfo ); + //m_additionalIncludes.WriteToString( ref nodeInfo ); + + m_additionalDirectives.WriteToString( ref nodeInfo ); + } + + public TemplatesBlendModule BlendOpHelper { get { return m_blendOpHelper; } } + public TemplateCullModeModule CullModeHelper { get { return m_cullModeHelper; } } + public TemplateColorMaskModule ColorMaskHelper { get { return m_colorMaskHelper; } } + public TemplatesStencilBufferModule StencilBufferHelper { get { return m_stencilBufferHelper; } } + public TemplateDepthModule DepthOphelper { get { return m_depthOphelper; } } + public TemplateTagsModule TagsHelper { get { return m_tagsHelper; } } + public TemplateShaderModelModule ShaderModelHelper { get { return m_shaderModelHelper; } } + //public TemplateAdditionalIncludesHelper AdditionalIncludes { get { return m_additionalIncludes; } } + //public TemplateAdditionalDefinesHelper AdditionalDefines { get { return m_additionalDefines; } } + //public TemplateAdditionalPragmasHelper AdditionalPragmas { get { return m_additionalPragmas; } } + public TemplateAdditionalDirectivesHelper AdditionalDirectives { get { return m_additionalDirectives; } } + public bool AllModulesMode { get { return m_allModulesMode; } } + public bool HasValidData { get { return m_hasValidData; } } + public bool IsDirty + { + get { return m_isDirty; } + set + { + m_isDirty = value; + if( !value ) + { + m_blendOpHelper.IsDirty = false; + m_cullModeHelper.IsDirty = false; + m_colorMaskHelper.IsDirty = false; + m_stencilBufferHelper.IsDirty = false; + m_tagsHelper.IsDirty = false; + m_shaderModelHelper.IsDirty = false; + //m_additionalDefines.IsDirty = false; + //m_additionalPragmas.IsDirty = false; + //m_additionalIncludes.IsDirty = false; + m_additionalDirectives.IsDirty = false; + } + } + } + // public bool Foldout { get { return m_foldout; } set { m_foldout = value; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModuleHelper.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModuleHelper.cs.meta new file mode 100644 index 00000000..95ebce97 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModuleHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 144af5a201bd97542bf3a483976759db +timeCreated: 1518705839 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModuleParent.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModuleParent.cs new file mode 100644 index 00000000..cb28c2f3 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModuleParent.cs @@ -0,0 +1,62 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using UnityEngine; +using UnityEditor; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateModuleParent + { + private const string UnreadableDataMessagePrefix = "Unreadable data on Module "; + protected string m_unreadableMessage; + + [SerializeField] + protected bool m_validData = false; + + [SerializeField] + protected bool m_isDirty = false; + + [SerializeField] + protected string m_moduleName = string.Empty; + + //[SerializeField] + //protected bool m_foldoutValue = false; + + [SerializeField] + protected bool m_independentModule = true; + + public TemplateModuleParent( string moduleName ) { m_moduleName = moduleName; m_unreadableMessage = UnreadableDataMessagePrefix + moduleName; } + public virtual void Draw( UndoParentNode owner , bool style = true) { } + public virtual void ReadFromString( ref uint index, ref string[] nodeParams ) { } + public virtual void WriteToString( ref string nodeInfo ) { } + public virtual string GenerateShaderData( bool isSubShader ) { return string.Empty; } + public virtual void Destroy() { } + public bool ValidData { get { return m_validData; } } + public bool ValidAndIndependent { get { return m_validData && m_independentModule; } } + + public virtual void ShowUnreadableDataMessage( ParentNode owner ) + { + ShowUnreadableDataMessage(); + } + + public virtual void ShowUnreadableDataMessage() + { + EditorGUILayout.HelpBox( m_unreadableMessage, MessageType.Info ); + } + + public bool IsDirty + { + get { return m_isDirty; } + set { m_isDirty = value; } + } + + public bool IndependentModule + { + get { return m_independentModule; } + set { m_independentModule = value; } + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModuleParent.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModuleParent.cs.meta new file mode 100644 index 00000000..a0a1d88c --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModuleParent.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3aaabf1f5cb06414a8be17a89487e10f +timeCreated: 1511185965 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModulesData.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModulesData.cs new file mode 100644 index 00000000..5cbc9a7b --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModulesData.cs @@ -0,0 +1,541 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using System.Text.RegularExpressions; +using System.Collections.Generic; +using UnityEngine; + +namespace AmplifyShaderEditor +{ + public enum TemplateModuleDataType + { + ModuleShaderModel, + ModuleBlendMode, + ModuleBlendOp, + ModuleAlphaToMask, + ModuleCullMode, + ModuleColorMask, + ModuleStencil, + ModuleZwrite, + ModuleZTest, + ModuleZOffset, + ModuleTag, + ModuleGlobals, + ModuleSRPBatcher, + ModuleFunctions, + ModulePragma, + ModulePragmaBefore, + ModulePass, + ModuleInputVert, + ModuleInputFrag, + PassVertexFunction, + PassFragmentFunction, + PassVertexData, + PassInterpolatorData, + PassNameData, + AllModules, + VControl, + ControlData, + DomainData + //EndPass + } + + public enum TemplateSRPType + { + BuiltIn, + HD, + Lightweight + } + + [Serializable] + public class TemplateModulesData + { + [SerializeField] + private TemplateBlendData m_blendData = new TemplateBlendData(); + + [SerializeField] + private TemplateCullModeData m_cullModeData = new TemplateCullModeData(); + + [SerializeField] + private TemplateColorMaskData m_colorMaskData = new TemplateColorMaskData(); + + [SerializeField] + private TemplateStencilData m_stencilData = new TemplateStencilData(); + + [SerializeField] + private TemplateDepthData m_depthData = new TemplateDepthData(); + + [SerializeField] + private TemplateTagsModuleData m_tagData = new TemplateTagsModuleData(); + + [SerializeField] + private TemplateTagData m_globalsTag = new TemplateTagData( TemplatesManager.TemplateGlobalsTag, true ); + + [SerializeField] + private TemplateTagData m_srpBatcherTag = new TemplateTagData( TemplatesManager.TemplateSRPBatcherTag, true ); + + [SerializeField] + private TemplateTagData m_allModulesTag = new TemplateTagData( TemplatesManager.TemplateAllModulesTag, true ); + + [SerializeField] + private TemplateTagData m_functionsTag = new TemplateTagData( TemplatesManager.TemplateFunctionsTag, true ); + + [SerializeField] + private TemplateTagData m_pragmaTag = new TemplateTagData( TemplatesManager.TemplatePragmaTag, true ); + + [SerializeField] + private TemplateTagData m_pragmaBeforeTag = new TemplateTagData( TemplatesManager.TemplatePragmaBeforeTag, true ); + + [SerializeField] + private TemplateTagData m_passTag = new TemplateTagData( TemplatesManager.TemplatePassTag, true ); + + [SerializeField] + private TemplateTagData m_inputsVertTag = new TemplateTagData( TemplatesManager.TemplateInputsVertParamsTag, false ); + + [SerializeField] + private TemplateTagData m_inputsFragTag = new TemplateTagData( TemplatesManager.TemplateInputsFragParamsTag, false ); + + [SerializeField] + private TemplateShaderModelData m_shaderModel = new TemplateShaderModelData(); + + [SerializeField] + private TemplateSRPType m_srpType = TemplateSRPType.BuiltIn; + + [SerializeField] + private bool m_srpIsPBR = false; + + [SerializeField] + private string m_uniquePrefix; + + [SerializeField] + private TemplateIncludePragmaContainter m_includePragmaContainer = new TemplateIncludePragmaContainter(); + + [SerializeField] + private bool m_allModulesMode = false; + + [SerializeField] + private string m_passUniqueName = string.Empty; + + public void Destroy() + { + m_blendData = null; + m_cullModeData = null; + m_colorMaskData = null; + m_stencilData = null; + m_depthData = null; + m_tagData.Destroy(); + m_tagData = null; + m_globalsTag = null; + m_srpBatcherTag = null; + m_allModulesTag = null; + m_functionsTag = null; + m_pragmaTag = null; + m_pragmaBeforeTag = null; + m_passTag = null; + m_inputsVertTag = null; + m_inputsFragTag = null; + m_includePragmaContainer.Destroy(); + m_includePragmaContainer = null; + } + + public void ConfigureCommonTag( TemplateTagData tagData, TemplatePropertyContainer propertyContainer, TemplateIdManager idManager, string uniquePrefix, int offsetIdx, string subBody ) + { + int id = subBody.IndexOf( tagData.Id ); + if ( id >= 0 ) + { + tagData.StartIdx = offsetIdx + id; + idManager.RegisterId( tagData.StartIdx, uniquePrefix + tagData.Id, tagData.Id ); + propertyContainer.AddId( subBody, tagData.Id, tagData.SearchIndentation ); + } + } + + public TemplateModulesData( TemplateOptionsContainer optionsContainer, TemplateIdManager idManager, TemplatePropertyContainer propertyContainer, string uniquePrefix, int offsetIdx, string subBody, bool isSubShader ) + { + if ( string.IsNullOrEmpty( subBody ) ) + return; + + m_uniquePrefix = uniquePrefix; + //PRAGMAS AND INCLUDES + TemplateHelperFunctions.CreatePragmaIncludeList( subBody, m_includePragmaContainer ); + + //COMMON TAGS + ConfigureCommonTag( m_globalsTag, propertyContainer, idManager, uniquePrefix, offsetIdx, subBody ); + ConfigureCommonTag( m_srpBatcherTag, propertyContainer, idManager, uniquePrefix, offsetIdx, subBody ); + ConfigureCommonTag( m_functionsTag, propertyContainer, idManager, uniquePrefix, offsetIdx, subBody ); + ConfigureCommonTag( m_pragmaTag, propertyContainer, idManager, uniquePrefix, offsetIdx, subBody ); + ConfigureCommonTag( m_pragmaBeforeTag, propertyContainer, idManager, uniquePrefix, offsetIdx, subBody ); + if( !TemplateHelperFunctions.GetPassUniqueId( m_passTag, propertyContainer, idManager, uniquePrefix, offsetIdx, subBody, ref m_passUniqueName ) ) + { + ConfigureCommonTag( m_passTag, propertyContainer, idManager, uniquePrefix, offsetIdx, subBody ); + } + ConfigureCommonTag( m_inputsVertTag, propertyContainer, idManager, uniquePrefix, offsetIdx, subBody ); + ConfigureCommonTag( m_inputsFragTag, propertyContainer, idManager, uniquePrefix, offsetIdx, subBody ); + + // If Options are enabled then remove them so they won't influence Regex matches + if( optionsContainer.Enabled && optionsContainer.EndIndex > 0 ) + { + offsetIdx += optionsContainer.EndIndex; + subBody = subBody.Substring( optionsContainer.EndIndex ); + } + //BlEND MODE + { + Match blendModeMatch = Regex.Match( subBody, TemplateHelperFunctions.BlendWholeWordPattern ); + if( blendModeMatch.Success ) + { + int blendModeIdx = blendModeMatch.Index; + + int end = subBody.IndexOf( TemplatesManager.TemplateNewLine, blendModeIdx ); + string blendParams = subBody.Substring( blendModeIdx, end - blendModeIdx ); + m_blendData.BlendModeId = blendParams; + m_blendData.BlendModeStartIndex = offsetIdx + blendModeIdx; + idManager.RegisterId( m_blendData.BlendModeStartIndex, uniquePrefix + m_blendData.BlendModeId, m_blendData.BlendModeId ); + + TemplateHelperFunctions.CreateBlendMode( blendParams, ref m_blendData ); + if( m_blendData.ValidBlendMode ) + { + propertyContainer.AddId( subBody, blendParams, false ); + } + + } + } + //BLEND OP + { + Match blendOpMatch = Regex.Match( subBody, TemplateHelperFunctions.BlendOpWholeWordPattern ); + if( blendOpMatch.Success ) + { + int blendOpIdx = blendOpMatch.Index; + int end = subBody.IndexOf( TemplatesManager.TemplateNewLine, blendOpIdx ); + string blendOpParams = subBody.Substring( blendOpIdx, end - blendOpIdx ); + m_blendData.BlendOpId = blendOpParams; + BlendData.BlendOpStartIndex = offsetIdx + blendOpIdx; + idManager.RegisterId( m_blendData.BlendOpStartIndex, uniquePrefix + m_blendData.BlendOpId, m_blendData.BlendOpId ); + TemplateHelperFunctions.CreateBlendOp( blendOpParams, ref m_blendData ); + if( m_blendData.ValidBlendOp ) + { + propertyContainer.AddId( subBody, blendOpParams, false ); + } + } + + } + + //ALPHA TO MASK + { + Match alphaToMaskMatch = Regex.Match( subBody, TemplateHelperFunctions.AlphaToMaskPattern ); + if( alphaToMaskMatch.Success ) + { + m_blendData.ValidAlphaToMask = true; + m_blendData.AlphaToMaskId = alphaToMaskMatch.Groups[ 0 ].Value; + if( alphaToMaskMatch.Groups.Count > 1 ) + m_blendData.AlphaToMaskValue = alphaToMaskMatch.Groups[ 1 ].Value.Equals( "On" ) ? true : false; + m_blendData.IndependentAlphaToMask = true; + idManager.RegisterId( offsetIdx + alphaToMaskMatch.Index, uniquePrefix + m_blendData.AlphaToMaskId, m_blendData.AlphaToMaskId ); + propertyContainer.AddId( subBody, m_blendData.AlphaToMaskId, false ); + } + + m_blendData.DataCheck = ( m_blendData.ValidBlendMode || m_blendData.ValidBlendOp || m_blendData.ValidAlphaToMask ) ? TemplateDataCheck.Valid : TemplateDataCheck.Invalid; + } + + //CULL MODE + { + Match cullMatch = Regex.Match( subBody, TemplateHelperFunctions.CullWholeWordPattern ); + if( cullMatch.Success ) + { + int cullIdx = cullMatch.Index; + int end = subBody.IndexOf( TemplatesManager.TemplateNewLine, cullIdx ); + string cullParams = subBody.Substring( cullIdx, end - cullIdx ); + m_cullModeData.CullModeId = cullParams; + m_cullModeData.StartIdx = offsetIdx + cullIdx; + idManager.RegisterId( m_cullModeData.StartIdx, uniquePrefix + m_cullModeData.CullModeId, m_cullModeData.CullModeId ); + TemplateHelperFunctions.CreateCullMode( cullParams, ref m_cullModeData ); + if( m_cullModeData.DataCheck == TemplateDataCheck.Valid ) + propertyContainer.AddId( subBody, cullParams, false, string.Empty ); + + } + } + //COLOR MASK + { + Match colorMaskMatch = Regex.Match( subBody, TemplateHelperFunctions.ColorMaskWholeWordPattern ); + if( colorMaskMatch.Success ) + { + int colorMaskIdx = colorMaskMatch.Index; + int end = subBody.IndexOf( TemplatesManager.TemplateNewLine, colorMaskIdx ); + string colorMaskParams = subBody.Substring( colorMaskIdx, end - colorMaskIdx ); + m_colorMaskData.ColorMaskId = colorMaskParams; + m_colorMaskData.StartIdx = offsetIdx + colorMaskIdx; + idManager.RegisterId( m_colorMaskData.StartIdx, uniquePrefix + m_colorMaskData.ColorMaskId, m_colorMaskData.ColorMaskId ); + TemplateHelperFunctions.CreateColorMask( colorMaskParams, ref m_colorMaskData ); + if( m_colorMaskData.DataCheck == TemplateDataCheck.Valid ) + propertyContainer.AddId( subBody, colorMaskParams, false ); + + } + } + //STENCIL + { + Match stencilMatch = Regex.Match( subBody, TemplateHelperFunctions.StencilWholeWordPattern ); + if( stencilMatch.Success ) + { + int stencilIdx = stencilMatch.Index; + int stencilEndIdx = subBody.IndexOf( "}", stencilIdx ); + if( stencilEndIdx > 0 ) + { + string stencilParams = subBody.Substring( stencilIdx, stencilEndIdx + 1 - stencilIdx ); + m_stencilData.StencilBufferId = stencilParams; + m_stencilData.StartIdx = offsetIdx + stencilIdx; + idManager.RegisterId( m_stencilData.StartIdx, uniquePrefix + m_stencilData.StencilBufferId, m_stencilData.StencilBufferId ); + TemplateHelperFunctions.CreateStencilOps( stencilParams, ref m_stencilData ); + if( m_stencilData.DataCheck == TemplateDataCheck.Valid ) + { + propertyContainer.AddId( subBody, stencilParams, true ); + } + } + } + else + { + int stencilTagIdx = subBody.IndexOf( TemplatesManager.TemplateStencilTag ); + if( stencilTagIdx > -1 ) + { + m_stencilData.SetIndependentDefault(); + m_stencilData.StencilBufferId = TemplatesManager.TemplateStencilTag; + m_stencilData.StartIdx = offsetIdx + stencilTagIdx; + idManager.RegisterId( m_stencilData.StartIdx, uniquePrefix + m_stencilData.StencilBufferId, m_stencilData.StencilBufferId ); + propertyContainer.AddId( subBody, m_stencilData.StencilBufferId, true ); + } + } + } + //ZWRITE + { + Match zWriteMatch = Regex.Match( subBody, TemplateHelperFunctions.ZWriteWholeWordPattern ); + if( zWriteMatch.Success ) + { + int zWriteOpIdx = zWriteMatch.Index; + int zWriteEndIdx = subBody.IndexOf( TemplatesManager.TemplateNewLine, zWriteOpIdx ); + if( zWriteEndIdx > 0 ) + { + m_depthData.ZWriteModeId = subBody.Substring( zWriteOpIdx, zWriteEndIdx + 1 - zWriteOpIdx ); + m_depthData.ZWriteStartIndex = offsetIdx + zWriteOpIdx; + idManager.RegisterId( m_depthData.ZWriteStartIndex, uniquePrefix + m_depthData.ZWriteModeId, m_depthData.ZWriteModeId ); + TemplateHelperFunctions.CreateZWriteMode( m_depthData.ZWriteModeId, ref m_depthData ); + if( m_depthData.DataCheck == TemplateDataCheck.Valid ) + { + propertyContainer.AddId( subBody, m_depthData.ZWriteModeId, true ); + } + } + } + } + + //ZTEST + { + Match zTestMatch = Regex.Match( subBody, TemplateHelperFunctions.ZTestWholeWordPattern ); + if( zTestMatch.Success ) + { + int zTestOpIdx = zTestMatch.Index; + int zTestEndIdx = subBody.IndexOf( TemplatesManager.TemplateNewLine, zTestOpIdx ); + if( zTestEndIdx > 0 ) + { + m_depthData.ZTestModeId = subBody.Substring( zTestOpIdx, zTestEndIdx + 1 - zTestOpIdx ); + m_depthData.ZTestStartIndex = offsetIdx + zTestOpIdx; + idManager.RegisterId( m_depthData.ZTestStartIndex, uniquePrefix + m_depthData.ZTestModeId, m_depthData.ZTestModeId ); + TemplateHelperFunctions.CreateZTestMode( m_depthData.ZTestModeId, ref m_depthData ); + if( m_depthData.DataCheck == TemplateDataCheck.Valid ) + { + propertyContainer.AddId( subBody, m_depthData.ZTestModeId, true ); + } + } + } + } + + //ZOFFSET + { + Match zOffsetMatch = Regex.Match( subBody, TemplateHelperFunctions.ZOffsetWholeWordPattern ); + if( zOffsetMatch.Success ) + { + int zOffsetIdx = zOffsetMatch.Index; + int zOffsetEndIdx = subBody.IndexOf( TemplatesManager.TemplateNewLine, zOffsetIdx ); + if( zOffsetEndIdx > 0 ) + { + m_depthData.OffsetId = subBody.Substring( zOffsetIdx, zOffsetEndIdx + 1 - zOffsetIdx ); + m_depthData.OffsetStartIndex = offsetIdx + zOffsetIdx; + idManager.RegisterId( m_depthData.OffsetStartIndex, uniquePrefix + m_depthData.OffsetId, m_depthData.OffsetId ); + TemplateHelperFunctions.CreateZOffsetMode( m_depthData.OffsetId, ref m_depthData ); + if( m_depthData.DataCheck == TemplateDataCheck.Valid ) + { + propertyContainer.AddId( subBody, m_depthData.OffsetId, true ); + } + } + } + m_depthData.SetDataCheck(); + } + //TAGS + { + Match tagsMatch = Regex.Match( subBody, TemplateHelperFunctions.TagsWholeWordPattern ); + if ( tagsMatch.Success ) + { + int tagsIdx = tagsMatch.Index; + int tagsEndIdx = subBody.IndexOf( "}", tagsIdx ); + if ( tagsEndIdx > -1 ) + { + m_tagData.Reset(); + m_tagData.TagsId = subBody.Substring( tagsIdx, tagsEndIdx + 1 - tagsIdx ); + m_tagData.StartIdx = offsetIdx + tagsIdx; + idManager.RegisterId( m_tagData.StartIdx, uniquePrefix + m_tagData.TagsId, m_tagData.TagsId ); + m_srpType = TemplateHelperFunctions.CreateTags( ref m_tagData, isSubShader ); + + propertyContainer.AddId( subBody, m_tagData.TagsId, false ); + m_tagData.DataCheck = TemplateDataCheck.Valid; + } + else + { + m_tagData.DataCheck = TemplateDataCheck.Invalid; + } + } + else + { + m_tagData.DataCheck = TemplateDataCheck.Invalid; + } + } + + //SHADER MODEL + { + Match match = Regex.Match( subBody, TemplateHelperFunctions.ShaderModelPattern ); + if ( match != null && match.Groups.Count > 1 ) + { + if ( TemplateHelperFunctions.AvailableInterpolators.ContainsKey( match.Groups[ 1 ].Value ) ) + { + m_shaderModel.Id = match.Groups[ 0 ].Value; + m_shaderModel.StartIdx = offsetIdx + match.Index; + m_shaderModel.Value = match.Groups[ 1 ].Value; + m_shaderModel.InterpolatorAmount = TemplateHelperFunctions.AvailableInterpolators[ match.Groups[ 1 ].Value ]; + m_shaderModel.DataCheck = TemplateDataCheck.Valid; + idManager.RegisterId( m_shaderModel.StartIdx, uniquePrefix + m_shaderModel.Id, m_shaderModel.Id ); + } + else + { + m_shaderModel.DataCheck = TemplateDataCheck.Invalid; + } + } + } + + // ALL MODULES + int allModulesIndex = subBody.IndexOf( TemplatesManager.TemplateAllModulesTag ); + if( allModulesIndex > 0 ) + { + //ONLY REGISTER MISSING TAGS + ConfigureCommonTag( m_allModulesTag, propertyContainer, idManager, uniquePrefix, offsetIdx, subBody ); + m_allModulesMode = true; + + m_blendData.SetAllModulesDefault(); + + if( !m_cullModeData.IsValid ) + m_cullModeData.SetAllModulesDefault(); + + if( !m_colorMaskData.IsValid ) + m_colorMaskData.SetAllModulesDefault(); + + if( !m_stencilData.IsValid ) + m_stencilData.SetAllModulesDefault(); + + if( !m_depthData.IsValid ) + m_depthData.SetAllModulesDefault(); + + if( !m_shaderModel.IsValid ) + m_shaderModel.SetAllModulesDefault(); + } + } + + public void TestPropertyInternalName( string name, ref List<TemplateShaderPropertyData> availableShaderProperties, ref Dictionary<string, TemplateShaderPropertyData> duplicatesHelper ) + { + if( !string.IsNullOrEmpty( name ) && !duplicatesHelper.ContainsKey( name )) + { + TemplateShaderPropertyData newData = new TemplateShaderPropertyData( -1, string.Empty, string.Empty, name, name, WirePortDataType.INT, PropertyType.Property ); + availableShaderProperties.Add( newData ); + duplicatesHelper.Add( newData.PropertyName , newData ); + } + } + + public void RegisterInternalUnityInlines( ref List<TemplateShaderPropertyData> availableShaderProperties, ref Dictionary<string, TemplateShaderPropertyData> duplicatesHelper ) + { + TestPropertyInternalName( m_depthData.ZWriteInlineValue, ref availableShaderProperties , ref duplicatesHelper); + TestPropertyInternalName( m_depthData.ZTestInlineValue, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_depthData.OffsetFactorInlineValue, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_depthData.OffsetUnitsInlineValue, ref availableShaderProperties, ref duplicatesHelper ); + + TestPropertyInternalName( m_blendData.SourceFactorRGBInline, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_blendData.DestFactorRGBInline, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_blendData.SourceFactorAlphaInline, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_blendData.DestFactorAlphaInline, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_blendData.BlendOpRGBInline, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_blendData.BlendOpAlphaInline, ref availableShaderProperties, ref duplicatesHelper ); + + TestPropertyInternalName( m_stencilData.ReferenceInline, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_stencilData.ReadMaskInline, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_stencilData.WriteMaskInline, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_stencilData.ComparisonFrontInline, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_stencilData.PassFrontInline, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_stencilData.FailFrontInline, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_stencilData.ZFailFrontInline, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_stencilData.ComparisonBackInline, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_stencilData.PassBackInline, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_stencilData.FailBackInline, ref availableShaderProperties, ref duplicatesHelper ); + TestPropertyInternalName( m_stencilData.ZFailBackInline, ref availableShaderProperties, ref duplicatesHelper ); + + TestPropertyInternalName( m_cullModeData.InlineData, ref availableShaderProperties, ref duplicatesHelper ); + + TestPropertyInternalName( m_colorMaskData.InlineData, ref availableShaderProperties, ref duplicatesHelper ); + } + + public void SetPassUniqueNameIfUndefined( string value ) + { + if( string.IsNullOrEmpty( m_passUniqueName ) ) + m_passUniqueName = value; + } + + public bool HasValidData + { + get + { + return m_blendData.DataCheck == TemplateDataCheck.Valid || + m_cullModeData.DataCheck == TemplateDataCheck.Valid || + m_colorMaskData.DataCheck == TemplateDataCheck.Valid || + m_stencilData.DataCheck == TemplateDataCheck.Valid || + m_depthData.DataCheck == TemplateDataCheck.Valid || + m_tagData.DataCheck == TemplateDataCheck.Valid || + m_shaderModel.DataCheck == TemplateDataCheck.Valid || + m_globalsTag.IsValid || + m_srpBatcherTag.IsValid || + m_allModulesTag.IsValid || + m_functionsTag.IsValid || + m_pragmaTag.IsValid || + m_pragmaBeforeTag.IsValid || + m_passTag.IsValid || + m_inputsVertTag.IsValid || + m_inputsFragTag.IsValid; + } + } + + public TemplateBlendData BlendData { get { return m_blendData; } } + public TemplateCullModeData CullModeData { get { return m_cullModeData; } } + public TemplateColorMaskData ColorMaskData { get { return m_colorMaskData; } } + public TemplateStencilData StencilData { get { return m_stencilData; } } + public TemplateDepthData DepthData { get { return m_depthData; } } + public TemplateTagsModuleData TagData { get { return m_tagData; } } + public TemplateTagData GlobalsTag { get { return m_globalsTag; } } + public TemplateTagData SRPBatcherTag { get { return m_srpBatcherTag; } } + public TemplateTagData AllModulesTag { get { return m_allModulesTag; } } + public TemplateTagData FunctionsTag { get { return m_functionsTag; } } + public TemplateTagData PragmaTag { get { return m_pragmaTag; } } + public TemplateTagData PragmaBeforeTag { get { return m_pragmaBeforeTag; } } + public TemplateTagData PassTag { get { return m_passTag; } } + public TemplateTagData InputsVertTag { get { return m_inputsVertTag; } } + public TemplateTagData InputsFragTag { get { return m_inputsFragTag; } } + public TemplateShaderModelData ShaderModel { get { return m_shaderModel; } } + public TemplateSRPType SRPType { get { return m_srpType; } set { m_srpType = value; } } + public bool SRPIsPBR { get { return m_srpIsPBR; } set { m_srpIsPBR = value; } } + public bool SRPIsPBRHD { get { return m_srpIsPBR && m_srpType == TemplateSRPType.HD; } } + public string UniquePrefix { get { return m_uniquePrefix; } } + public string PassUniqueName { get { return m_passUniqueName; } } + public bool HasPassUniqueName { get { return !string.IsNullOrEmpty( m_passUniqueName ); } } + public TemplateIncludePragmaContainter IncludePragmaContainer { get { return m_includePragmaContainer; } } + public bool AllModulesMode { get { return m_allModulesMode; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModulesData.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModulesData.cs.meta new file mode 100644 index 00000000..64714772 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateModulesData.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 122447ac2bc376a448a42a0f5373e63b +timeCreated: 1521718529 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPass.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPass.cs new file mode 100644 index 00000000..5086b55f --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPass.cs @@ -0,0 +1,1248 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> +using System; +using System.Text.RegularExpressions; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateUniquePassData + { + public int SubShaderIdx; + public int PassIdx; + } + + [Serializable] + public sealed class TemplateMultiPass : TemplateDataParent + { + [SerializeField] + private List<TemplateShaderPropertyData> m_availableShaderProperties = new List<TemplateShaderPropertyData>(); + + [SerializeField] + private List<TemplateSubShader> m_subShaders = new List<TemplateSubShader>(); + + [SerializeField] + private TemplateTagData m_propertyTag; + + [SerializeField] + private TemplateIdManager m_templateIdManager; + + [SerializeField] + private string m_shaderNameId = string.Empty; + + [SerializeField] + private string m_shaderBody; + + [SerializeField] + private TemplatePropertyContainer m_templateProperties = new TemplatePropertyContainer(); + + [SerializeField] + private TemplateShaderInfo m_shaderData; + + [SerializeField] + private bool m_isSinglePass = false; + + [SerializeField] + private int m_masterNodesRequired = 0; + + [SerializeField] + TemplateInfoContainer m_customInspectorContainer = new TemplateInfoContainer(); + + [SerializeField] + TemplateInfoContainer m_dependenciesContainer = new TemplateInfoContainer(); + + [SerializeField] + TemplateInfoContainer m_fallbackContainer = new TemplateInfoContainer(); + + [SerializeField] + TemplateInfoContainer m_beforePragmaContainer = new TemplateInfoContainer(); + + [SerializeField] + private CustomTemplatePropertyUIEnum m_customTemplatePropertyUI = CustomTemplatePropertyUIEnum.None; + + [SerializeField] + private int m_lodInjectorId = -1; + + [SerializeField] + TemplateShaderModelData m_globalShaderModel = new TemplateShaderModelData(); + + private Dictionary<string, TemplateUniquePassData> m_passUniqueIdData = new Dictionary<string, TemplateUniquePassData>(); + + + public TemplateMultiPass() + { + m_templateType = TemplateDataType.MultiPass; + } + + public TemplateMultiPass( string name, string guid, bool isCommunity ) + { + m_templateType = TemplateDataType.MultiPass; + Init( name, guid, isCommunity ); + } + + public override void Init( string name, string guid, bool isCommunity ) + { + base.Init( name, guid, isCommunity ); + TemplatesManager.CurrTemplateGUIDLoaded = guid; + LoadTemplateBody( guid ); + Name = string.IsNullOrEmpty( name ) ? m_defaultShaderName : name; + } + + void LoadTemplateBody( string guid ) + { + m_passUniqueIdData.Clear(); + m_guid = guid; + string datapath = AssetDatabase.GUIDToAssetPath( guid ); + string shaderBody = string.Empty; + shaderBody = IOUtils.LoadTextFileFromDisk( datapath ); + shaderBody = shaderBody.Replace( "\r\n", "\n" ); + + // Insert Before Tag + MatchCollection col = Regex.Matches( shaderBody, TemplateHelperFunctions.BeforePragmaPattern, RegexOptions.Singleline ); + for( int i = col.Count - 1; i >= 0; i-- ) + { + if( col[ i ].Groups.Count == 3 ) + { + shaderBody = shaderBody.Insert( col[ i ].Groups[ 2 ].Index, TemplatesManager.TemplatePragmaBeforeTag + "\n" + col[ i ].Groups[ 1 ].Value ); + } + } + //Detect SRP Batcher + MatchCollection srpMatch = Regex.Matches( shaderBody, TemplateHelperFunctions.SRPBatcherFindTag ); + for( int i = srpMatch.Count - 1; i >= 0; i-- ) + { + if( srpMatch[ i ].Groups.Count == 2 ) + { + shaderBody = shaderBody.Insert( srpMatch[ i ].Groups[ 0 ].Index + srpMatch[ i ].Groups[ 0 ].Length, TemplatesManager.TemplateSRPBatcherTag + srpMatch[ i ].Groups[ 1 ].Value ); + } + } + + + // Detect if template has LOD tag, if not, insert one + // It will be read and processed over the TemplateSubShader constructor + { + Match match = Regex.Match( shaderBody, TemplateHelperFunctions.SubShaderLODPattern ); + if( match == null || ( match != null && !match.Success ) ) + { + MatchCollection subShaderMatch = Regex.Matches( shaderBody, TemplatesManager.TemplateMPSubShaderTag ); + + int subShaderAmount = subShaderMatch.Count; + + for( int i = subShaderAmount - 1; i > -1; i-- ) + { + if( subShaderMatch[ i ].Success ) + { + shaderBody = shaderBody.Insert( subShaderMatch[ i ].Index + subShaderMatch[ i ].Length, "\n\t\t\tLOD 0\n" ); + } + } + } + } + m_shaderData = TemplateShaderInfoUtil.CreateShaderData( shaderBody ); + if( m_shaderData == null ) + { + m_isValid = false; + return; + } + + m_templateIdManager = new TemplateIdManager( shaderBody ); + + try + { + int nameBegin = shaderBody.IndexOf( TemplatesManager.TemplateShaderNameBeginTag ); + if( nameBegin < 0 ) + { + // Not a template + return; + } + + int nameEnd = shaderBody.IndexOf( TemplatesManager.TemplateFullEndTag, nameBegin ); + if( nameEnd < 0 ) + return; + + + m_shaderBody = shaderBody; + int defaultBegin = nameBegin + TemplatesManager.TemplateShaderNameBeginTag.Length; + int defaultLength = nameEnd - defaultBegin; + m_defaultShaderName = shaderBody.Substring( defaultBegin, defaultLength ); + int[] nameIdx = m_defaultShaderName.AllIndexesOf( "\"" ); + nameIdx[ 0 ] += 1; // Ignore the " character from the string + m_defaultShaderName = m_defaultShaderName.Substring( nameIdx[ 0 ], nameIdx[ 1 ] - nameIdx[ 0 ] ); + m_shaderNameId = shaderBody.Substring( nameBegin, nameEnd + TemplatesManager.TemplateFullEndTag.Length - nameBegin ); + m_templateProperties.AddId( shaderBody, m_shaderNameId, false ); + m_templateIdManager.RegisterId( nameBegin, m_shaderNameId, m_shaderNameId ); + shaderBody = shaderBody.Substring( nameEnd + TemplatesManager.TemplateFullEndTag.Length ); + } + catch( Exception e ) + { + Debug.LogException( e ); + m_isValid = false; + } + + m_customTemplatePropertyUI = TemplateHelperFunctions.FetchCustomUI( shaderBody ); + TemplateHelperFunctions.FetchDependencies( m_dependenciesContainer, ref m_shaderBody ); + if( m_dependenciesContainer.IsValid ) + { + int index = m_dependenciesContainer.Id.IndexOf( TemplatesManager.TemplateDependenciesListTag ); + m_templateProperties.AddId( new TemplateProperty( m_dependenciesContainer.Id, m_dependenciesContainer.Id.Substring( 0, index ), true ) ); + m_templateIdManager.RegisterId( m_dependenciesContainer.Index, m_dependenciesContainer.Id, m_dependenciesContainer.Id ); + } + + TemplateHelperFunctions.FetchCustomInspector( m_customInspectorContainer, ref m_shaderBody ); + if( m_customInspectorContainer.IsValid ) + { + int index = m_customInspectorContainer.Id.IndexOf( "CustomEditor" ); + m_templateProperties.AddId( new TemplateProperty( m_customInspectorContainer.Id, m_customInspectorContainer.Id.Substring( 0, index ), true ) ); + m_templateIdManager.RegisterId( m_customInspectorContainer.Index, m_customInspectorContainer.Id, m_customInspectorContainer.Id ); + } + + TemplateHelperFunctions.FetchFallback( m_fallbackContainer, ref m_shaderBody ); + if( m_fallbackContainer.IsValid ) + { + int index = m_fallbackContainer.Id.IndexOf( "Fallback", StringComparison.InvariantCultureIgnoreCase ); + m_templateProperties.AddId( new TemplateProperty( m_fallbackContainer.Id, m_fallbackContainer.Id.Substring( 0, index ), true ) ); + m_templateIdManager.RegisterId( m_fallbackContainer.Index, m_fallbackContainer.Id, m_fallbackContainer.Id ); + } + + m_lodInjectorId = m_shaderBody.IndexOf( TemplatesManager.TemplateLODsTag ); + + // Shader body may have been changed to inject inexisting tags like fallback + m_templateIdManager.ShaderBody = m_shaderBody; + + m_propertyTag = new TemplateTagData( m_shaderData.PropertyStartIdx, TemplatesManager.TemplatePropertyTag, true ); + m_templateIdManager.RegisterId( m_shaderData.PropertyStartIdx, TemplatesManager.TemplatePropertyTag, TemplatesManager.TemplatePropertyTag ); + m_templateProperties.AddId( shaderBody, TemplatesManager.TemplatePropertyTag, true ); + Dictionary<string, TemplateShaderPropertyData> duplicatesHelper = new Dictionary<string, TemplateShaderPropertyData>(); + TemplateHelperFunctions.CreateShaderPropertiesList( m_shaderData.Properties, ref m_availableShaderProperties, ref duplicatesHelper ); + for( int i = 0; i < m_availableShaderProperties.Count; i++ ) + { + m_templateIdManager.RegisterId( m_availableShaderProperties[ i ].Index, m_availableShaderProperties[ i ].FullValue, m_availableShaderProperties[ i ].FullValue ); + } + + int subShaderCount = m_shaderData.SubShaders.Count; + + int mainSubShaderIdx = -1; + int mainPassIdx = -1; + + int firstVisibleSubShaderId = -1; + int firstVisiblePassId = -1; + bool foundMainPass = false; + bool foundFirstVisible = false; + + m_templateIdManager.RegisterTag( TemplatesManager.TemplatePassesEndTag ); + m_templateIdManager.RegisterTag( TemplatesManager.TemplateMainPassTag ); + + //SHADER MODEL + { + Match shaderModelMatch = Regex.Match( m_shaderData.Properties, TemplateHelperFunctions.ShaderModelPattern ); + if( shaderModelMatch != null && shaderModelMatch.Success ) + { + if( TemplateHelperFunctions.AvailableInterpolators.ContainsKey( shaderModelMatch.Groups[ 1 ].Value ) ) + { + m_globalShaderModel.Id = shaderModelMatch.Groups[ 0 ].Value; + m_globalShaderModel.StartIdx = shaderModelMatch.Index; + m_globalShaderModel.Value = shaderModelMatch.Groups[ 1 ].Value; + m_globalShaderModel.InterpolatorAmount = TemplateHelperFunctions.AvailableInterpolators[ shaderModelMatch.Groups[ 1 ].Value ]; + m_globalShaderModel.DataCheck = TemplateDataCheck.Valid; + } + else + { + m_globalShaderModel.DataCheck = TemplateDataCheck.Invalid; + } + } + } + // + + + for( int i = 0; i < subShaderCount; i++ ) + { + TemplateSubShader subShader = new TemplateSubShader(this, i, m_templateIdManager, "SubShader" + i, m_shaderData.SubShaders[ i ], ref duplicatesHelper ); + + if( subShader.FoundMainPass ) + { + if( !foundMainPass ) + { + foundMainPass = true; + mainSubShaderIdx = i; + mainPassIdx = subShader.MainPass; + } + } + else if( subShader.MainPass > -1 ) + { + if( !foundFirstVisible ) + { + foundFirstVisible = true; + firstVisibleSubShaderId = i; + firstVisiblePassId = subShader.MainPass; + } + } + + m_subShaders.Add( subShader ); + m_masterNodesRequired += subShader.Passes.Count; + } + + + if( !foundMainPass && foundFirstVisible ) + { + mainSubShaderIdx = firstVisibleSubShaderId; + mainPassIdx = firstVisiblePassId; + } + + for( int subShaderIdx = 0; subShaderIdx < subShaderCount; subShaderIdx++ ) + { + m_subShaders[ subShaderIdx ].Modules.RegisterInternalUnityInlines( ref m_availableShaderProperties , ref duplicatesHelper ); + int passCount = m_subShaders[ subShaderIdx ].Passes.Count; + for( int passIdx = 0; passIdx < passCount; passIdx++ ) + { + m_subShaders[ subShaderIdx ].Passes[ passIdx ].Modules.RegisterInternalUnityInlines( ref m_availableShaderProperties, ref duplicatesHelper ); + m_subShaders[ subShaderIdx ].Passes[ passIdx ].IsMainPass = ( mainSubShaderIdx == subShaderIdx && mainPassIdx == passIdx ); + } + } + + duplicatesHelper.Clear(); + duplicatesHelper = null; + m_isSinglePass = ( m_subShaders.Count == 1 && m_subShaders[ 0 ].PassAmount == 1 ); + + } + + public void ResetState() + { + m_templateIdManager.ResetRegistersState(); + int subshaderCount = m_subShaders.Count; + for( int subShaderIdx = 0; subShaderIdx < subshaderCount; subShaderIdx++ ) + { + m_subShaders[ subShaderIdx ].TemplateProperties.ResetTemplateUsageData(); + int passCount = m_subShaders[ subShaderIdx ].Passes.Count; + for( int passIdx = 0; passIdx < passCount; passIdx++ ) + { + m_subShaders[ subShaderIdx ].Passes[ passIdx ].TemplateProperties.ResetTemplateUsageData(); + } + } + } + + public override void Destroy() + { + m_templateProperties.Destroy(); + m_templateProperties = null; + + m_availableShaderProperties.Clear(); + m_availableShaderProperties = null; + + int subShaderCount = m_subShaders.Count; + for( int i = 0; i < subShaderCount; i++ ) + { + m_subShaders[ i ].Destroy(); + } + + m_subShaders.Clear(); + m_subShaders = null; + + m_templateIdManager.Destroy(); + m_templateIdManager = null; + } + + public void SetSubShaderData( TemplateModuleDataType type, int subShaderId, string[] list ) + { + string id = GetSubShaderDataId( type, subShaderId, false ); + string body = string.Empty; + FillTemplateBody( subShaderId, -1, id, ref body, list ); + SetSubShaderData( type, subShaderId, body ); + } + + public void SetSubShaderData( TemplateModuleDataType type, int subShaderId, List<PropertyDataCollector> list ) + { + string id = GetSubShaderDataId( type, subShaderId, false ); + string body = string.Empty; + FillTemplateBody( subShaderId, -1, id, ref body, list ); + SetSubShaderData( type, subShaderId, body ); + } + + public void SetSubShaderData( TemplateModuleDataType type, int subShaderId, string text ) + { + if( subShaderId >= m_subShaders.Count ) + return; + + string prefix = m_subShaders[ subShaderId ].Modules.UniquePrefix; + switch( type ) + { + case TemplateModuleDataType.AllModules: + { + m_templateIdManager.SetReplacementText( prefix + TemplatesManager.TemplateAllModulesTag, text ); + } + break; + case TemplateModuleDataType.ModuleShaderModel: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.ShaderModel.Id, text ); + } + break; + case TemplateModuleDataType.ModuleBlendMode: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.BlendData.BlendModeId, text ); + } + break; + case TemplateModuleDataType.ModuleBlendOp: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.BlendData.BlendOpId, text ); + } + break; + case TemplateModuleDataType.ModuleAlphaToMask: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.BlendData.AlphaToMaskId, text ); + } + break; + case TemplateModuleDataType.ModuleCullMode: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.CullModeData.CullModeId, text ); + } + break; + case TemplateModuleDataType.ModuleColorMask: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.ColorMaskData.ColorMaskId, text ); + } + break; + case TemplateModuleDataType.ModuleStencil: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.StencilData.StencilBufferId, text ); + } + break; + case TemplateModuleDataType.ModuleZwrite: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.DepthData.ZWriteModeId, text ); + } + break; + case TemplateModuleDataType.ModuleZTest: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.DepthData.ZTestModeId, text ); + } + break; + case TemplateModuleDataType.ModuleZOffset: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.DepthData.OffsetId, text ); + } + break; + case TemplateModuleDataType.ModuleTag: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.TagData.TagsId, text ); + } + break; + case TemplateModuleDataType.ModuleGlobals: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.GlobalsTag.Id, text ); + } + break; + case TemplateModuleDataType.ModuleSRPBatcher: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.SRPBatcherTag.Id, text ); + } + break; + case TemplateModuleDataType.ModuleFunctions: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.FunctionsTag.Id, text ); + } + break; + case TemplateModuleDataType.ModulePragma: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.PragmaTag.Id, text ); + } + break; + case TemplateModuleDataType.ModulePragmaBefore: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.PragmaBeforeTag.Id, text ); + } + break; + case TemplateModuleDataType.ModulePass: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.PassTag.Id, text ); + } + break; + case TemplateModuleDataType.ModuleInputVert: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.InputsVertTag.Id, text ); + } + break; + case TemplateModuleDataType.ModuleInputFrag: + { + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Modules.InputsFragTag.Id, text ); + } + break; + } + } + + public void SetPropertyData( string[] properties ) + { + string body = string.Empty; + FillTemplateBody( -1, -1, TemplatesManager.TemplatePropertyTag, ref body, properties ); + SetPropertyData( body ); + } + + + public void SetPropertyData( string text ) + { + m_templateIdManager.SetReplacementText( m_propertyTag.Id, text ); + } + + public string GetSubShaderDataId( TemplateModuleDataType type, int subShaderId, bool addPrefix ) + { + if( subShaderId >= m_subShaders.Count ) + return string.Empty; + + string prefix = string.Empty; + switch( type ) + { + case TemplateModuleDataType.AllModules: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + TemplatesManager.TemplateAllModulesTag; + } + case TemplateModuleDataType.ModuleBlendMode: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.BlendData.BlendModeId; + } + case TemplateModuleDataType.ModuleBlendOp: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.BlendData.BlendOpId; + } + case TemplateModuleDataType.ModuleAlphaToMask: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.BlendData.AlphaToMaskId; + } + case TemplateModuleDataType.ModuleCullMode: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.CullModeData.CullModeId; + } + case TemplateModuleDataType.ModuleColorMask: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.ColorMaskData.ColorMaskId; + } + case TemplateModuleDataType.ModuleStencil: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.StencilData.StencilBufferId; + } + case TemplateModuleDataType.ModuleZwrite: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.DepthData.ZWriteModeId; + } + case TemplateModuleDataType.ModuleZTest: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.DepthData.ZTestModeId; + } + case TemplateModuleDataType.ModuleZOffset: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.DepthData.OffsetId; + } + case TemplateModuleDataType.ModuleTag: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.TagData.TagsId; + } + case TemplateModuleDataType.ModuleGlobals: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.GlobalsTag.Id; + } + case TemplateModuleDataType.ModuleSRPBatcher: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.SRPBatcherTag.Id; + } + case TemplateModuleDataType.ModuleFunctions: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.FunctionsTag.Id; + } + case TemplateModuleDataType.ModulePragma: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.PragmaTag.Id; + } + case TemplateModuleDataType.ModulePragmaBefore: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.PragmaBeforeTag.Id; + } + case TemplateModuleDataType.ModulePass: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.PassTag.Id; + } + case TemplateModuleDataType.ModuleInputVert: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.InputsVertTag.Id; + } + case TemplateModuleDataType.ModuleInputFrag: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Modules.InputsFragTag.Id; + } + } + return string.Empty; + + } + public string GetPassDataId( TemplateModuleDataType type, int subShaderId, int passId, bool addPrefix ) + { + if( subShaderId >= m_subShaders.Count || passId >= m_subShaders[ subShaderId ].Passes.Count ) + return string.Empty; + + string prefix = string.Empty; + switch( type ) + { + case TemplateModuleDataType.AllModules: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + TemplatesManager.TemplateAllModulesTag; + } + case TemplateModuleDataType.ModuleBlendMode: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.BlendData.BlendModeId; + } + case TemplateModuleDataType.ModuleBlendOp: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.BlendData.BlendOpId; + } + case TemplateModuleDataType.ModuleAlphaToMask: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.BlendData.AlphaToMaskId; + } + case TemplateModuleDataType.ModuleCullMode: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.CullModeData.CullModeId; + } + case TemplateModuleDataType.ModuleColorMask: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.ColorMaskData.ColorMaskId; + } + case TemplateModuleDataType.ModuleStencil: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.StencilData.StencilBufferId; + } + case TemplateModuleDataType.ModuleZwrite: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.DepthData.ZWriteModeId; + } + case TemplateModuleDataType.ModuleZTest: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.DepthData.ZTestModeId; + } + case TemplateModuleDataType.ModuleZOffset: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.DepthData.OffsetId; + } + case TemplateModuleDataType.ModuleTag: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.TagData.TagsId; + } + case TemplateModuleDataType.ModuleGlobals: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.GlobalsTag.Id; + } + case TemplateModuleDataType.ModuleSRPBatcher: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.SRPBatcherTag.Id; + } + case TemplateModuleDataType.ModuleFunctions: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.FunctionsTag.Id; + } + case TemplateModuleDataType.ModulePragma: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.PragmaTag.Id; + } + case TemplateModuleDataType.ModulePragmaBefore: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.PragmaBeforeTag.Id; + } + case TemplateModuleDataType.ModulePass: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.PassTag.Id; + } + case TemplateModuleDataType.ModuleInputVert: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.InputsVertTag.Id; + } + case TemplateModuleDataType.ModuleInputFrag: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.InputsFragTag.Id; + } + case TemplateModuleDataType.PassVertexFunction: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].VertexFunctionData.Id; + } + case TemplateModuleDataType.PassFragmentFunction: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].FragmentFunctionData.Id; + } + case TemplateModuleDataType.PassVertexData: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].VertexDataContainer.VertexDataId; + } + case TemplateModuleDataType.PassInterpolatorData: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].InterpolatorDataContainer.InterpDataId; + } + case TemplateModuleDataType.VControl: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].TessVControlTag.Id; + } + case TemplateModuleDataType.ControlData: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].TessControlData.Id; + } + case TemplateModuleDataType.DomainData: + { + prefix = addPrefix ? m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix : string.Empty; + return prefix + m_subShaders[ subShaderId ].Passes[ passId ].TessDomainData.Id; + } + } + return string.Empty; + } + + public void SetPassData( TemplateModuleDataType type, int subShaderId, int passId, string[] list ) + { + //if( list == null || list.Length == 0 ) + // return; + + string id = GetPassDataId( type, subShaderId, passId, false ); + string body = string.Empty; + FillTemplateBody( subShaderId, passId, id, ref body, list ); + SetPassData( type, subShaderId, passId, body ); + } + + public void SetPassData( TemplateModuleDataType type, int subShaderId, int passId, List<PropertyDataCollector> list ) + { + //if( list == null || list.Count == 0 ) + // return; + + string id = GetPassDataId( type, subShaderId, passId, false ); + string body = string.Empty; + FillTemplateBody( subShaderId, passId, id, ref body, list ); + SetPassData( type, subShaderId, passId, body ); + } + + public void SetPassData( TemplateModuleDataType type, int subShaderId, int passId, string text ) + { + if( subShaderId >= m_subShaders.Count || passId >= m_subShaders[ subShaderId ].Passes.Count ) + return; + + string prefix = string.Empty; + switch( type ) + { + //case TemplateModuleDataType.EndPass: + //{ + // prefix = m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix; + // m_templateIdManager.SetReplacementText( prefix + TemplatesManager.TemplateEndPassTag, text ); + //} + //break; + case TemplateModuleDataType.AllModules: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + TemplatesManager.TemplateAllModulesTag, text ); + } + break; + case TemplateModuleDataType.ModuleShaderModel: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.ShaderModel.Id, text ); + } + break; + case TemplateModuleDataType.ModuleBlendMode: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.BlendData.BlendModeId, text ); + } + break; + case TemplateModuleDataType.ModuleBlendOp: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.BlendData.BlendOpId, text ); + } + break; + case TemplateModuleDataType.ModuleAlphaToMask: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.BlendData.AlphaToMaskId, text ); + } + break; + case TemplateModuleDataType.ModuleCullMode: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.CullModeData.CullModeId, text ); + } + break; + case TemplateModuleDataType.ModuleColorMask: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.ColorMaskData.ColorMaskId, text ); + } + break; + case TemplateModuleDataType.ModuleStencil: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.StencilData.StencilBufferId, text ); + } + break; + case TemplateModuleDataType.ModuleZwrite: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.DepthData.ZWriteModeId, text ); + } + break; + case TemplateModuleDataType.ModuleZTest: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.DepthData.ZTestModeId, text ); + } + break; + case TemplateModuleDataType.ModuleZOffset: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.DepthData.OffsetId, text ); + } + break; + case TemplateModuleDataType.ModuleTag: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.TagData.TagsId, text ); + } + break; + case TemplateModuleDataType.ModuleGlobals: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.GlobalsTag.Id, text ); + } + break; + case TemplateModuleDataType.ModuleSRPBatcher: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.SRPBatcherTag.Id, text ); + } + break; + case TemplateModuleDataType.ModuleFunctions: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.FunctionsTag.Id, text ); + } + break; + case TemplateModuleDataType.ModulePragma: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.PragmaTag.Id, text ); + } + break; + case TemplateModuleDataType.ModulePragmaBefore: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.PragmaBeforeTag.Id, text ); + } + break; + case TemplateModuleDataType.ModulePass: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.PassTag.Id, text ); + } + break; + case TemplateModuleDataType.ModuleInputVert: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.InputsVertTag.Id, text ); + } + break; + case TemplateModuleDataType.ModuleInputFrag: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].Modules.UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].Modules.InputsFragTag.Id, text ); + } + break; + case TemplateModuleDataType.PassVertexFunction: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].VertexFunctionData.Id, text ); + } + break; + case TemplateModuleDataType.PassFragmentFunction: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].FragmentFunctionData.Id, text ); + } + break; + case TemplateModuleDataType.PassVertexData: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].VertexDataContainer.VertexDataId, text ); + } + break; + case TemplateModuleDataType.PassInterpolatorData: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].InterpolatorDataContainer.InterpDataId, text ); + } + break; + case TemplateModuleDataType.PassNameData: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].PassNameContainer.Id, text ); + } + break; + case TemplateModuleDataType.VControl: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].TessVControlTag.Id, text ); + } + break; + case TemplateModuleDataType.ControlData: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].TessControlData.Id, text ); + } + break; + case TemplateModuleDataType.DomainData: + { + prefix = m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].TessDomainData.Id, text ); + } + break; + } + } + + public void SetPassInputData( int subShaderId, int passId, int inputId, string text ) + { + if( subShaderId >= m_subShaders.Count || + passId >= m_subShaders[ subShaderId ].Passes.Count ) + return; + + string prefix = m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix; + TemplateInputData inputData = m_subShaders[ subShaderId ].Passes[ passId ].InputDataFromId( inputId ); + if( inputData != null ) + { + m_templateIdManager.SetReplacementText( prefix + inputData.TagId, text ); + } + else + { + Debug.LogErrorFormat( "Unable to find input data for port with id {0} on subshader {1} pass {2}", inputId, subShaderId, passId ); + } + } + + public void SetPassInputDataByArrayIdx( int subShaderId, int passId, int inputId, string text ) + { + if( subShaderId >= m_subShaders.Count || + passId >= m_subShaders[ subShaderId ].Passes.Count || + inputId >= m_subShaders[ subShaderId ].Passes[ passId ].InputDataList.Count ) + return; + + string prefix = m_subShaders[ subShaderId ].Passes[ passId ].UniquePrefix; + m_templateIdManager.SetReplacementText( prefix + m_subShaders[ subShaderId ].Passes[ passId ].InputDataList[ inputId ].TagId, text ); + } + + public TemplateData CreateTemplateData( string name, string guid, int subShaderId, int passId ) + { + if( subShaderId >= m_subShaders.Count || + passId >= m_subShaders[ subShaderId ].Passes.Count ) + return null; + + if( string.IsNullOrEmpty( name ) ) + name = m_defaultShaderName; + + TemplateData templateData = ScriptableObject.CreateInstance<TemplateData>(); + templateData.Name = name; + templateData.GUID = guid; + templateData.TemplateBody = m_shaderBody; + templateData.DefaultShaderName = m_defaultShaderName; + templateData.ShaderNameId = m_shaderNameId; + templateData.OrderId = m_orderId; + + templateData.InputDataList = SubShaders[ subShaderId ].Passes[ passId ].InputDataList; + templateData.VertexDataContainer = SubShaders[ subShaderId ].Passes[ passId ].VertexDataContainer; + templateData.InterpolatorDataContainer = SubShaders[ subShaderId ].Passes[ passId ].InterpolatorDataContainer; + templateData.AvailableShaderProperties = m_availableShaderProperties; + templateData.VertexFunctionData = SubShaders[ subShaderId ].Passes[ passId ].VertexFunctionData; + templateData.FragmentFunctionData = SubShaders[ subShaderId ].Passes[ passId ].FragmentFunctionData; + templateData.BlendData = SubShaders[ subShaderId ].Passes[ passId ].Modules.BlendData; + templateData.CullModeData = SubShaders[ subShaderId ].Passes[ passId ].Modules.CullModeData; + templateData.ColorMaskData = SubShaders[ subShaderId ].Passes[ passId ].Modules.ColorMaskData; + templateData.StencilData = SubShaders[ subShaderId ].Passes[ passId ].Modules.StencilData; + templateData.DepthData = SubShaders[ subShaderId ].Passes[ passId ].Modules.DepthData; + templateData.TagData = SubShaders[ subShaderId ].Passes[ passId ].Modules.TagData; + + //templateData.PropertyList = m_pr; + //private Dictionary<string, TemplateProperty> m_propertyDict = new Dictionary<string, TemplateProperty>(); + + return templateData; + } + + public bool FillTemplateBody( int subShaderId, int passId, string id, ref string body, List<PropertyDataCollector> values ) + { + if( values.Count == 0 ) + { + return true; + } + + string[] array = new string[ values.Count ]; + for( int i = 0; i < values.Count; i++ ) + { + array[ i ] = values[ i ].PropertyName; + } + return FillTemplateBody( subShaderId, passId, id, ref body, array ); + } + + public bool FillTemplateBody( int subShaderId, int passId, string id, ref string body, params string[] values ) + { + if( values.Length == 0 ) + { + if( id[ id.Length - 1 ] == '\n' ) + body = "\n"; + + return true; + } + + TemplatePropertyContainer propertyContainer = null; + if( subShaderId >= 0 ) + { + if( passId >= 0 ) + { + propertyContainer = SubShaders[ subShaderId ].Passes[ passId ].TemplateProperties; + } + else + { + propertyContainer = SubShaders[ subShaderId ].TemplateProperties; + } + } + else + { + propertyContainer = m_templateProperties; + } + + propertyContainer.BuildInfo(); + + if( propertyContainer.PropertyDict.ContainsKey( id ) ) + { + string finalValue = propertyContainer.PropertyDict[ id ].UseIndentationAtStart ? propertyContainer.PropertyDict[ id ].Indentation : string.Empty; + for( int i = 0; i < values.Length; i++ ) + { + + if( propertyContainer.PropertyDict[ id ].AutoLineFeed ) + { + string[] valuesArr = values[ i ].Split( '\n' ); + for( int j = 0; j < valuesArr.Length; j++ ) + { + //first value will be automatically indented by the string replace + finalValue += ( ( i == 0 && j == 0 ) ? string.Empty : propertyContainer.PropertyDict[ id ].Indentation ) + valuesArr[ j ]; + finalValue += TemplatesManager.TemplateNewLine; + } + } + else + { + //first value will be automatically indented by the string replace + finalValue += ( i == 0 ? string.Empty : propertyContainer.PropertyDict[ id ].Indentation ) + values[ i ]; + } + } + + body = finalValue; + propertyContainer.PropertyDict[ id ].Used = true; + return true; + } + + if( values.Length > 1 || !string.IsNullOrEmpty( values[ 0 ] ) ) + { + UIUtils.ShowMessage( string.Format( "Attempting to write data into inexistant tag {0}. Please review the template {1} body and consider adding the missing tag.", id, m_defaultShaderName ), MessageSeverity.Error ); + return false; + } + return true; + } + + public bool FillVertexInstructions( int subShaderId, int passId, params string[] values ) + { + TemplateFunctionData vertexFunctionData = SubShaders[ subShaderId ].Passes[ passId ].VertexFunctionData; + if( vertexFunctionData != null && !string.IsNullOrEmpty( vertexFunctionData.Id ) ) + { + string body = string.Empty; + bool isValid = FillTemplateBody( subShaderId, passId, vertexFunctionData.Id, ref body, values ); + SetPassData( TemplateModuleDataType.PassVertexFunction, subShaderId, passId, body ); + return isValid; + } + + if( values.Length > 0 ) + { + UIUtils.ShowMessage( "Attemping to add vertex instructions on a template with no assigned vertex code area", MessageSeverity.Error ); + return false; + } + return true; + } + + public bool FillFragmentInstructions( int subShaderId, int passId, params string[] values ) + { + TemplateFunctionData fragmentFunctionData = SubShaders[ subShaderId ].Passes[ passId ].FragmentFunctionData; + if( fragmentFunctionData != null && !string.IsNullOrEmpty( fragmentFunctionData.Id ) ) + { + string body = string.Empty; + bool isValid = FillTemplateBody( subShaderId, passId, fragmentFunctionData.Id, ref body, values ); + SetPassData( TemplateModuleDataType.PassFragmentFunction, subShaderId, passId, body ); + return isValid; + } + + if( values.Length > 0 ) + { + UIUtils.ShowMessage( "Attemping to add fragment instructions on a template with no assigned vertex code area", MessageSeverity.Error ); + return false; + } + return true; + } + + public void SetShaderName( string name ) + { + m_templateIdManager.SetReplacementText( m_shaderNameId, name ); + } + + public void SetCustomInspector( string customInspector ) + { + if( m_customInspectorContainer.Index > -1 ) + { + m_templateIdManager.SetReplacementText( m_customInspectorContainer.Id, m_templateProperties.PropertyDict[ m_customInspectorContainer.Id ].Indentation + customInspector ); + } + } + + public void SetFallback( string fallback ) + { + if( m_fallbackContainer.Index > -1 ) + { + m_templateIdManager.SetReplacementText( m_fallbackContainer.Id, m_templateProperties.PropertyDict[ m_fallbackContainer.Id ].Indentation + fallback ); + } + } + + public void SetDependencies( string dependencies ) + { + if( m_dependenciesContainer.Index > -1 ) + { + m_templateIdManager.SetReplacementText( m_dependenciesContainer.Id, dependencies ); + } + } + + private void OnEnable() + { + hideFlags = HideFlags.HideAndDontSave; + } + + public override bool Reload() + { + m_propertyTag = null; + m_shaderNameId = string.Empty; + m_shaderBody = string.Empty; + m_isSinglePass = false; + m_masterNodesRequired = 0; + m_beforePragmaContainer.Reset(); + m_customInspectorContainer.Reset(); + m_fallbackContainer.Reset(); + m_dependenciesContainer.Reset(); + m_availableShaderProperties.Clear(); + int count = m_subShaders.Count; + for( int i = 0; i < count; i++ ) + { + m_subShaders[ i ].Destroy(); + } + m_subShaders.Clear(); + + m_templateIdManager.Reset(); + if( m_shaderData != null ) + m_shaderData.Destroy(); + + m_templateProperties.Reset(); + + string oldName = m_defaultShaderName; + LoadTemplateBody( m_guid ); + + if( m_communityTemplate ) + Name = m_defaultShaderName; + + return !oldName.Equals( m_defaultShaderName ); + } + + public bool GetSubShaderandPassFor( string passUniqueId, ref int subShaderId, ref int passId ) + { + if( string.IsNullOrEmpty( passUniqueId ) ) + return false; + + if( m_passUniqueIdData.Count == 0 ) + { + for( int subShaderIdx = 0; subShaderIdx < m_subShaders.Count; subShaderIdx++ ) + { + for( int passIdx = 0; passIdx < m_subShaders[ subShaderIdx ].Passes.Count; passIdx++ ) + { + if( m_subShaders[ subShaderIdx ].Passes[ passIdx ].Modules.HasPassUniqueName ) + { + if( m_passUniqueIdData.ContainsKey( m_subShaders[ subShaderIdx ].Passes[ passIdx ].Modules.PassUniqueName ) ) + { + Debug.LogErrorFormat( "Found duplicate pass name '{0}' over template. Please fix template as it will result in multiple errors.", m_subShaders[ subShaderIdx ].Passes[ passIdx ].Modules.PassUniqueName ); + return false; + } + m_passUniqueIdData.Add( m_subShaders[ subShaderIdx ].Passes[ passIdx ].Modules.PassUniqueName, new TemplateUniquePassData() { PassIdx = passIdx, SubShaderIdx = subShaderIdx } ); + } + } + } + } + + if( m_passUniqueIdData.ContainsKey( passUniqueId ) ) + { + subShaderId = m_passUniqueIdData[ passUniqueId ].SubShaderIdx; + passId = m_passUniqueIdData[ passUniqueId ].PassIdx; + return true; + } + subShaderId = -1; + passId = -1; + return false; + } + + public TemplateShaderPropertyData GetShaderPropertyData( string propertyName ) + { + return m_availableShaderProperties.Find( ( x ) => ( x.PropertyName.Equals( propertyName ) ) ); + } + + public TemplateSRPType SRPtype { get { return m_subShaders[ 0 ].Modules.SRPType; } } + //public bool SRPIsPBRHD { get { return m_subShaders[0].Modules.SRPIsPBRHD ; } } + public List<TemplateSubShader> SubShaders { get { return m_subShaders; } } + public List<TemplateShaderPropertyData> AvailableShaderProperties { get { return m_availableShaderProperties; } } + public TemplateTagData PropertyTag { get { return m_propertyTag; } } + public TemplateIdManager IdManager { get { return m_templateIdManager; } } + public TemplatePropertyContainer TemplateProperties { get { return m_templateProperties; } } + public TemplateInfoContainer CustomInspectorContainer { get { return m_customInspectorContainer; } } + public TemplateInfoContainer FallbackContainer { get { return m_fallbackContainer; } } + public TemplateInfoContainer BeforePragmaContainer { get { return m_beforePragmaContainer; } } + public bool IsSinglePass { get { return m_isSinglePass; } } + public int MasterNodesRequired { get { return m_masterNodesRequired; } } + public CustomTemplatePropertyUIEnum CustomTemplatePropertyUI { get { return m_customTemplatePropertyUI; } } + public bool CanAddLODs { get { return m_lodInjectorId > -1; } } + public TemplateShaderModelData GlobalShaderModel { get { return m_globalShaderModel; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPass.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPass.cs.meta new file mode 100644 index 00000000..00e2dee2 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPass.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4214390aa7f66364bbab454dc15a04ac +timeCreated: 1516981847 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPassMasterNode.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPassMasterNode.cs new file mode 100644 index 00000000..92ce5c77 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPassMasterNode.cs @@ -0,0 +1,3113 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> +//#define SHOW_TEMPLATE_HELP_BOX + +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace AmplifyShaderEditor +{ + public enum HDSRPMaterialType + { + SubsurfaceScattering, + Standard, + Specular, + Anisotropy, + Iridescence, + Translucent + } + + public enum InvisibilityStatus + { + LockedInvisible, + Invisible, + Visible + } + + public enum SetTemplateSource + { + NewShader, + ShaderLoad, + HotCodeReload + }; + + [Serializable] + [NodeAttributes( "Template Master Node", "Master", "Shader Generated according to template rules", null, KeyCode.None, false )] + public sealed class TemplateMultiPassMasterNode : MasterNode + { + private const double MaxLODEditTimestamp = 1; + + private static int PASS_SELECTOR_VERSION = 16200; + private static int PASS_UNIQUE_ID_VERSION = 16204; + + private const string LodNameId = "LODName"; + private const string LodValueId = "LODValue"; + + private const string LodSubtitle = "LOD( {0} )"; + private const string AdditionalLODsStr = "LODs"; + + private const string SubTitleFormatterStr = "(SubShader {0} Pass {1})"; + private const string NoSubShaderPropertyStr = "No Sub-Shader properties available"; + private const string NoPassPropertyStr = "No Pass properties available"; + + private const string WarningMessage = "Templates is a feature that is still heavily under development and users may experience some problems.\nPlease email support@amplify.pt if any issue occurs."; + private const string OpenTemplateStr = "Edit Template"; + private const string ReloadTemplateStr = "Reload Template"; + private const string CommonPropertiesStr = "Common Properties "; + private const string SubShaderModuleStr = "SubShader "; + private const string PassModuleStr = "Pass "; + + private const string PassNameStr = "Name"; + private const string PassNameFormateStr = "Name \"{0}\""; + private const string SubShaderLODValueLabel = "LOD Value"; + private const string SubShaderLODNameLabel = "LOD Name"; + + + + private bool m_reRegisterTemplateData = false; + private bool m_fireTemplateChange = false; + private bool m_fetchMasterNodeCategory = false; + + [SerializeField] + private string m_templateGUID = "4e1801f860093ba4f9eb58a4b556825b"; + + [SerializeField] + private int m_passIdx = 0; + + //[SerializeField] + //private string m_passIdxStr = string.Empty; + + [SerializeField] + private bool m_passFoldout = false; + + [SerializeField] + private int m_subShaderIdx = 0; + + //[SerializeField] + //private string m_subShaderIdxStr = string.Empty; + + [SerializeField] + private bool m_subStringFoldout = false; + + [SerializeField] + private bool m_lodFoldout = false; + + + [SerializeField] + private string m_mainLODName = string.Empty; + + //[SerializeField] + //private string m_subShaderLODStr; + + //[SerializeField] + //private bool m_mainMPMasterNode = false; + + [NonSerialized] + private TemplateMultiPass m_templateMultiPass = null; + + [NonSerialized] + private TemplateMultiPassMasterNode m_mainMasterNodeRef = null; + + [SerializeField] + private TemplateModulesHelper m_subShaderModule = new TemplateModulesHelper(); + + [SerializeField] + private TemplateModulesHelper m_passModule = new TemplateModulesHelper(); + + [SerializeField] + private UsePassHelper m_usePass; + + [SerializeField] + private string m_passName = string.Empty; + + [SerializeField] + private string m_passUniqueId = string.Empty; + + [SerializeField] + private string m_originalPassName = string.Empty; + + [SerializeField] + private bool m_hasLinkPorts = false; + + [SerializeField] + private InvisibilityStatus m_isInvisible = InvisibilityStatus.Visible; + + [SerializeField] + private int m_invisibleOptions = 0; + + [SerializeField] + private bool m_invalidNode = false; + + [SerializeField] + private FallbackPickerHelper m_fallbackHelper = null; + + [SerializeField] + private DependenciesHelper m_dependenciesHelper = new DependenciesHelper(); + + [SerializeField] + private TemplateOptionsUIHelper m_subShaderOptions = new TemplateOptionsUIHelper( true ); + + [SerializeField] + private TemplateOptionsUIHelper m_passOptions = new TemplateOptionsUIHelper( false ); + + [SerializeField] + private TemplatePassSelectorHelper m_passSelector = new TemplatePassSelectorHelper(); + + [SerializeField] + private TemplateOptionsDefinesContainer m_optionsDefineContainer = new TemplateOptionsDefinesContainer(); + + [SerializeField] + private TerrainDrawInstancedHelper m_drawInstancedHelper = new TerrainDrawInstancedHelper(); + + // HATE THIS BELOW, MUST REMOVE HD SPECIFIC CODE FROM GENERIC MASTER NODE + private const string HDSRPMaterialTypeStr = "Material Type"; + private const string SRPMaterialSubsurfaceScatteringKeyword = "_MATERIAL_FEATURE_SUBSURFACE_SCATTERING 1"; + private const string SRPMaterialTransmissionKeyword = "_MATERIAL_FEATURE_TRANSMISSION 1"; + private const string SRPHDMaterialSpecularKeyword = "_MATERIAL_FEATURE_SPECULAR_COLOR 1"; + //private const string SRPLWMaterialSpecularKeyword = "_SPECULAR_SETUP 1"; + private const string SRPMaterialAnisotropyKeyword = "_MATERIAL_FEATURE_ANISOTROPY 1"; + private const string SRPMaterialIridiscenceKeyword = "_MATERIAL_FEATURE_IRIDESCENCE 1"; + //private const string SRPMaterialNormalMapKeyword = "_NORMALMAP 1"; + //private const string SRPMaterialAlphaTestKeyword = "_ALPHATEST_ON 1"; + //private const string SRPMaterialBlendModeAlphaClipThresholdKeyword = "_AlphaClip 1"; + private const string SRPMaterialTransparentKeyword = "_SURFACE_TYPE_TRANSPARENT 1"; + private const string SRPMaterialBlendModeAddKeyword = "_BLENDMODE_ADD 1"; + private const string SRPMaterialBlendModeAlphaKeyword = "_BLENDMODE_ALPHA 1"; + private const string SRPMaterialClearCoatKeyword = "_MATERIAL_FEATURE_CLEAR_COAT"; + + [NonSerialized] + private bool m_fetchPorts = true; + [NonSerialized] + private InputPort m_specularPort; + [NonSerialized] + private InputPort m_metallicPort; + [NonSerialized] + private InputPort m_coatMaskPort; + [NonSerialized] + private InputPort m_diffusionProfilePort; + [NonSerialized] + private InputPort m_subsurfaceMaskPort; + [NonSerialized] + private InputPort m_thicknessPort; + [NonSerialized] + private InputPort m_anisotropyPort; + [NonSerialized] + private InputPort m_iridescenceThicknessPort; + [NonSerialized] + private InputPort m_iridescenceMaskPort; + [NonSerialized] + private InputPort m_indexOfRefractionPort; + [NonSerialized] + private InputPort m_transmittanceColorPort; + [NonSerialized] + private InputPort m_transmittanceAbsorptionDistancePort; + [NonSerialized] + private InputPort m_transmittanceMaskPort; + + [SerializeField] + private HDSRPMaterialType m_hdSrpMaterialType = HDSRPMaterialType.Standard; + + [NonSerialized] + private bool m_refreshLODValueMasterNodes = false; + [NonSerialized] + private bool m_refocusLODValueMasterNodes = false; + [NonSerialized] + private double m_refreshLODValueMasterNodesTimestamp; + + ////////////////////////////////////////////////////////////////////////// + protected override void CommonInit( int uniqueId ) + { + base.CommonInit( uniqueId ); + m_masterNodeCategory = 1;// First Template + m_marginPreviewLeft = 20; + m_shaderNameIsTitle = true; + m_customInspectorName = string.Empty; + m_customPrecision = true; + } + + public override void ReleaseResources() + { + // Internal template resources ( for inline properties) are released by first node on the list + // As it's also registered that way + if( IsLODMainFirstPass ) + m_containerGraph.ClearInternalTemplateNodes(); + + if( !IsLODMainMasterNode ) + return; + TemplateMultiPass template = ( m_templateMultiPass == null ) ? m_containerGraph.ParentWindow.TemplatesManagerInstance.GetTemplate( m_templateGUID ) as TemplateMultiPass : m_templateMultiPass; + //Maintained the logic of being the main master node to unregister since this method is being called + //over the main master node in multiple places + //but it will unregister with unique of the first master node (pass 0) since it was the one + //to register it + int passUniqueId = ( m_passIdx == 0 ) ? UniqueId : ContainerGraph.MultiPassMasterNodes.NodesList[ 0 ].UniqueId; + + if( template != null && template.AvailableShaderProperties != null ) + { + // Unregister old template properties + int oldPropertyCount = template.AvailableShaderProperties.Count; + for( int i = 0; i < oldPropertyCount; i++ ) + { + UIUtils.ReleaseUniformName( passUniqueId, template.AvailableShaderProperties[ i ].PropertyName ); + } + } + } + + public void CopyOptionsFrom( TemplateMultiPassMasterNode origin ) + { + //Copy options + SubShaderOptions.CopyOptionsValuesFrom( origin.SubShaderOptions ); + PassOptions.CopyOptionsValuesFrom( origin.PassOptions ); + + //Copy selected passes + if( IsMainOutputNode ) + m_passSelector.CopyFrom( origin.PassSelector ); + } + + void RegisterProperties() + { + //First pass must be the one to always register properties so all modules + //can extract a valid negative Id when reading inline properties + if( /*!IsLODMainMasterNode*/!IsLODMainFirstPass ) + { + m_reRegisterTemplateData = false; + return; + } + + if( m_templateMultiPass != null ) + { + m_reRegisterTemplateData = false; + // Register old template properties + int newPropertyCount = m_templateMultiPass.AvailableShaderProperties.Count; + for( int i = 0; i < newPropertyCount; i++ ) + { + m_containerGraph.AddInternalTemplateNode( m_templateMultiPass.AvailableShaderProperties[ i ] ); + int nodeId = UIUtils.CheckUniformNameOwner( m_templateMultiPass.AvailableShaderProperties[ i ].PropertyName ); + if( nodeId > -1 ) + { + if( UniqueId != nodeId ) + { + ParentNode node = m_containerGraph.GetNode( nodeId ); + if( node != null ) + { + UIUtils.ShowMessage( string.Format( "Template requires property name {0} which is currently being used by {1}. Please rename it and reload template.", m_templateMultiPass.AvailableShaderProperties[ i ].PropertyName, node.Attributes.Name ) ); + } + else + { + UIUtils.ShowMessage( string.Format( "Template requires property name {0} which is currently being on your graph. Please rename it and reload template.", m_templateMultiPass.AvailableShaderProperties[ i ].PropertyName ) ); + } + } + } + else + { + UIUtils.RegisterUniformName( UniqueId, m_templateMultiPass.AvailableShaderProperties[ i ].PropertyName ); + } + } + } + } + + public override void OnEnable() + { + base.OnEnable(); + m_reRegisterTemplateData = true; + + if( m_usePass == null ) + { + m_usePass = ScriptableObject.CreateInstance<UsePassHelper>(); + m_usePass.Init( " Additional Use Passes" ); + } + + if( m_fallbackHelper == null ) + { + m_fallbackHelper = ScriptableObject.CreateInstance<FallbackPickerHelper>(); + m_fallbackHelper.Init(); + } + } + + protected override void OnUniqueIDAssigned() + { + base.OnUniqueIDAssigned(); + if( UniqueId >= 0 ) + { + if( m_lodIndex == -1 ) + { + m_containerGraph.MultiPassMasterNodes.AddNode( this ); + } + else + { + m_containerGraph.LodMultiPassMasternodes[ m_lodIndex ].AddNode( this ); + } + } + } + + public override void OnInputPortConnected( int portId, int otherNodeId, int otherPortId, bool activateNode = true ) + { + base.OnInputPortConnected( portId, otherNodeId, otherPortId, activateNode ); + m_passOptions.CheckImediateActionsForPort( this, portId ); + } + + public override void OnInputPortDisconnected( int portId ) + { + base.OnInputPortDisconnected( portId ); + m_passOptions.CheckImediateActionsForPort( this, portId ); + } + + public void ForceTemplateRefresh() + { + SetTemplate( null, false, true, m_subShaderIdx, m_passIdx, SetTemplateSource.HotCodeReload ); + } + + public void SetTemplate( TemplateMultiPass template, bool writeDefaultData, bool fetchMasterNodeCategory, int subShaderIdx, int passIdx , SetTemplateSource source ) + { + if( subShaderIdx > -1 ) + m_subShaderIdx = subShaderIdx; + + if( passIdx > -1 ) + m_passIdx = passIdx; + + ReleaseResources(); + bool hotCodeOrRead = ( template == null ); + m_templateMultiPass = ( hotCodeOrRead ) ? m_containerGraph.ParentWindow.TemplatesManagerInstance.GetTemplate( m_templateGUID ) as TemplateMultiPass : template; + if( m_templateMultiPass != null ) + { + + string passName = string.IsNullOrEmpty( m_passUniqueId ) ? ( m_isInvisible == InvisibilityStatus.LockedInvisible ? m_passName : m_originalPassName ) : m_passUniqueId; + int newPassIdx = m_passIdx; + int newSubShaderIdx = m_subShaderIdx; + m_templateMultiPass.GetSubShaderandPassFor( passName, ref newSubShaderIdx, ref newPassIdx ); + if( newPassIdx == -1 || newSubShaderIdx == -1 ) + { + //m_containerGraph.MarkToDelete( this ); + ContainerGraph.ParentWindow.SetOutdatedShaderFromTemplate(); + m_invalidNode = true; + UIUtils.ShowMessage( "Template changed drastically. Removing invalid passes." ); + return; + } + else + { + if( m_passIdx != newPassIdx ) + m_passIdx = newPassIdx; + + if( m_subShaderIdx != newSubShaderIdx ) + m_subShaderIdx = newSubShaderIdx; + } + + m_containerGraph.CurrentSRPType = m_templateMultiPass.SRPtype; + if( m_templateMultiPass.IsSinglePass ) + { + SetAdditonalTitleText( string.Empty ); + } + else if( m_templateMultiPass.SubShaders[ 0 ].MainPass != m_passIdx ) + { + SetAdditonalTitleText( string.Format( SubTitleFormatterStr, m_subShaderIdx, m_passIdx ) ); + } + m_invalidNode = false; + if( m_subShaderIdx >= m_templateMultiPass.SubShaders.Count || + m_passIdx >= m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes.Count ) + { + if( DebugConsoleWindow.DeveloperMode ) + Debug.LogFormat( "Inexisting pass {0}. Cancelling template fetch", m_originalPassName ); + + return; + } + + m_isMainOutputNode = m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].IsMainPass; + if( m_isMainOutputNode ) + { + // We cannot use UIUtils.MasterNodeOnTexture.height since this method can be + // called before UIUtils is initialized + m_insideSize.y = 55; + } + else + { + m_insideSize.y = 0; + } + + //IsMainOutputNode = m_mainMPMasterNode; + if( source != SetTemplateSource.HotCodeReload ) + { + //Only set this if no hotcode reload happens ( via new shader or load ) + m_isInvisible = m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].IsInvisible ? InvisibilityStatus.LockedInvisible : InvisibilityStatus.Visible; + } + else + { + // On hot code reload we only need to verify if template pass visibility data changes + // and change accordingly + if( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].IsInvisible ) + { + if( m_isInvisible != InvisibilityStatus.LockedInvisible ) + m_isInvisible = InvisibilityStatus.LockedInvisible; + } + else + { + if( m_isInvisible == InvisibilityStatus.LockedInvisible ) + { + m_isInvisible = InvisibilityStatus.Visible; + } + } + } + + m_invisibleOptions = m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].InvisibleOptions; + + m_originalPassName = m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].PassNameContainer.Data; + + if( !hotCodeOrRead ) + { + if( m_templateMultiPass.SubShaders[ m_subShaderIdx ].LODContainer.Index > -1 ) + { + //m_subShaderLODStr = m_templateMultiPass.SubShaders[ m_subShaderIdx ].LODContainer.Id; + ShaderLOD = Convert.ToInt32( m_templateMultiPass.SubShaders[ m_subShaderIdx ].LODContainer.Data ); + } + else + { + ShaderLOD = 0; + } + } + + m_shaderNameIsTitle = IsMainOutputNode; + m_fetchMasterNodeCategory = fetchMasterNodeCategory; + m_templateGUID = m_templateMultiPass.GUID; + UpdatePortInfo(); + + RegisterProperties(); + + // template is null when hot code reloading or loading from file so inspector name shouldn't be changed + if( !hotCodeOrRead ) + { + m_customInspectorName = m_templateMultiPass.CustomInspectorContainer.Data; + if( m_isMainOutputNode ) + { + m_passSelector.Clear(); + m_passSelector.Setup( m_templateMultiPass.SubShaders[ m_subShaderIdx ] ); + } + } + else + { + //Hotcode reload or ReadFromString + // Setup is only made if internal pass array is null + if( m_isMainOutputNode ) + { + m_passSelector.Setup( m_templateMultiPass.SubShaders[ m_subShaderIdx ] ); + } + } + + SetupCustomOptionsFromTemplate( template != null ); + + if( string.IsNullOrEmpty( m_fallbackHelper.RawFallbackShader ) ) + m_fallbackHelper.RawFallbackShader = m_templateMultiPass.FallbackContainer.Data; + + //bool updateInfofromTemplate = UpdatePortInfo(); + //if( updateInfofromTemplate ) + //{ + m_subShaderModule.FetchDataFromTemplate( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Modules ); + m_passModule.FetchDataFromTemplate( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules ); + //} + + //RegisterProperties(); + if( writeDefaultData ) + { + //ShaderName = m_templateMultiPass.DefaultShaderName; + ShaderName = m_shaderName; + m_passName = m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].PassNameContainer.Data; + if( !m_templateMultiPass.IsSinglePass /*&& !m_shaderNameIsTitle*/ ) + { + if( m_templateMultiPass.SubShaders[ 0 ].MainPass != m_passIdx ) + SetClippedTitle( m_passName ); + } + } + + UpdateSubShaderPassStr(); + + if( m_isMainOutputNode ) + m_fireTemplateChange = true; + } + else + { + m_invalidNode = true; + } + } + + public override void OnRefreshLinkedPortsComplete() + { + if( m_invalidNode ) + return; + + if( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules.SRPIsPBRHD ) + ConfigHDPorts(); + + SetReadOptions(); + } + + public void SetReadOptions() + { + m_passOptions.SetReadOptions(); + if( m_isMainOutputNode ) + m_subShaderOptions.SetReadOptions(); + } + + bool UpdatePortInfo() + { + List<TemplateInputData> inputDataList = m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].InputDataList; + int count = inputDataList.Count; + if( count != m_inputPorts.Count ) + { + DeleteAllInputConnections( true ); + + for( int i = 0; i < count; i++ ) + { + InputPort port = AddInputPort( inputDataList[ i ].DataType, false, inputDataList[ i ].PortName, inputDataList[ i ].OrderId, inputDataList[ i ].PortCategory, inputDataList[ i ].PortUniqueId ); + port.ExternalLinkId = inputDataList[ i ].LinkId; + m_hasLinkPorts = m_hasLinkPorts || !string.IsNullOrEmpty( inputDataList[ i ].LinkId ); + } + return true; + } + else + { + for( int i = 0; i < count; i++ ) + { + m_inputPorts[ i ].ChangeProperties( inputDataList[ i ].PortName, inputDataList[ i ].DataType, false ); + m_inputPorts[ i ].ExternalLinkId = inputDataList[ i ].LinkId; + } + return false; + } + } + + public void SetPropertyActionFromItem( TemplateModulesHelper module, TemplateActionItem item ) + { + TemplateModulesHelper subShaderModule = m_isMainOutputNode ? m_subShaderModule : m_mainMasterNodeRef.SubShaderModule; + switch( item.PropertyAction ) + { + case PropertyActionsEnum.CullMode: + { + if( item.CopyFromSubShader ) + { + module.CullModeHelper.CurrentCullMode = subShaderModule.CullModeHelper.CurrentCullMode; + } + else + { + module.CullModeHelper.CurrentCullMode = item.ActionCullMode; + } + + } + break; + case PropertyActionsEnum.ColorMask: + { + if( item.CopyFromSubShader ) + { + module.ColorMaskHelper.ColorMask = subShaderModule.ColorMaskHelper.ColorMask; + } + else + { + module.ColorMaskHelper.ColorMask = item.ColorMask; + } + } + break; + case PropertyActionsEnum.ZWrite: + { + if( item.CopyFromSubShader ) + { + module.DepthOphelper.ZWriteModeValue = subShaderModule.DepthOphelper.ZWriteModeValue; + } + else + { + module.DepthOphelper.ZWriteModeValue = item.ActionZWrite; + } + } + break; + case PropertyActionsEnum.ZTest: + { + if( item.CopyFromSubShader ) + { + module.DepthOphelper.ZTestModeValue = subShaderModule.DepthOphelper.ZTestModeValue; + } + else + { + module.DepthOphelper.ZTestModeValue = item.ActionZTest; + } + } + break; + case PropertyActionsEnum.ZOffsetFactor: + { + if( item.CopyFromSubShader ) + { + module.DepthOphelper.OffsetFactorValue = subShaderModule.DepthOphelper.OffsetFactorValue; + } + else + { + module.DepthOphelper.OffsetFactorValue = item.ActionZOffsetFactor; + } + } + break; + case PropertyActionsEnum.ZOffsetUnits: + { + if( item.CopyFromSubShader ) + { + module.DepthOphelper.OffsetUnitsValue = subShaderModule.DepthOphelper.OffsetUnitsValue; + } + else + { + module.DepthOphelper.OffsetUnitsValue = item.ActionZOffsetUnits; + } + } + break; + case PropertyActionsEnum.BlendRGB: + { + if( item.CopyFromSubShader ) + { + module.BlendOpHelper.SourceFactorRGB = subShaderModule.BlendOpHelper.SourceFactorRGB; + module.BlendOpHelper.DestFactorRGB = subShaderModule.BlendOpHelper.DestFactorRGB; + } + else + { + module.BlendOpHelper.SourceFactorRGB = item.ActionBlendRGBSource; + module.BlendOpHelper.DestFactorRGB = item.ActionBlendRGBDest; + } + } + break; + case PropertyActionsEnum.BlendAlpha: + { + if( item.CopyFromSubShader ) + { + module.BlendOpHelper.SourceFactorAlpha = subShaderModule.BlendOpHelper.SourceFactorAlpha; + module.BlendOpHelper.DestFactorAlpha = subShaderModule.BlendOpHelper.DestFactorAlpha; + } + else + { + module.BlendOpHelper.CurrentAlphaIndex = 1; + module.BlendOpHelper.SourceFactorAlpha = item.ActionBlendAlphaSource; + module.BlendOpHelper.DestFactorAlpha = item.ActionBlendAlphaDest; + } + } + break; + case PropertyActionsEnum.BlendOpRGB: + { + if( item.CopyFromSubShader ) + { + module.BlendOpHelper.BlendOpRGB = subShaderModule.BlendOpHelper.BlendOpRGB; + } + else + { + module.BlendOpHelper.BlendOpRGB = item.ActionBlendOpRGB; + } + } + break; + case PropertyActionsEnum.BlendOpAlpha: + { + if( item.CopyFromSubShader ) + { + module.BlendOpHelper.BlendOpAlpha = subShaderModule.BlendOpHelper.BlendOpAlpha; + } + else + { + module.BlendOpHelper.BlendOpAlpha = item.ActionBlendOpAlpha; + } + } + break; + case PropertyActionsEnum.StencilReference: + { + if( item.CopyFromSubShader ) + { + module.StencilBufferHelper.ReferenceValue = subShaderModule.StencilBufferHelper.ReferenceValue; + } + else + { + module.StencilBufferHelper.ReferenceValue = item.ActionStencilReference; + } + } + break; + case PropertyActionsEnum.StencilReadMask: + { + if( item.CopyFromSubShader ) + { + module.StencilBufferHelper.ReadMaskValue = subShaderModule.StencilBufferHelper.ReadMaskValue; + } + else + { + module.StencilBufferHelper.ReadMaskValue = item.ActionStencilReadMask; + } + } + break; + case PropertyActionsEnum.StencilWriteMask: + { + if( item.CopyFromSubShader ) + { + module.StencilBufferHelper.WriteMaskValue = subShaderModule.StencilBufferHelper.WriteMaskValue; + } + else + { + module.StencilBufferHelper.WriteMaskValue = item.ActionStencilWriteMask; + } + } + break; + case PropertyActionsEnum.StencilComparison: + { + if( item.CopyFromSubShader ) + { + module.StencilBufferHelper.ComparisonFunctionIdxValue = subShaderModule.StencilBufferHelper.ComparisonFunctionIdxValue; + } + else + { + module.StencilBufferHelper.ComparisonFunctionIdxValue = item.ActionStencilComparison; + } + } + break; + case PropertyActionsEnum.StencilPass: + { + if( item.CopyFromSubShader ) + { + module.StencilBufferHelper.PassStencilOpIdxValue = subShaderModule.StencilBufferHelper.PassStencilOpIdxValue; + } + else + { + module.StencilBufferHelper.PassStencilOpIdxValue = item.ActionStencilPass; + } + } + break; + case PropertyActionsEnum.StencilFail: + { + if( item.CopyFromSubShader ) + { + module.StencilBufferHelper.FailStencilOpIdxValue = subShaderModule.StencilBufferHelper.FailStencilOpIdxValue; + } + else + { + module.StencilBufferHelper.FailStencilOpIdxValue = item.ActionStencilFail; + } + } + break; + case PropertyActionsEnum.StencilZFail: + { + if( item.CopyFromSubShader ) + { + module.StencilBufferHelper.ZFailStencilOpIdxValue = subShaderModule.StencilBufferHelper.ZFailStencilOpIdxValue; + } + else + { + module.StencilBufferHelper.ZFailStencilOpIdxValue = item.ActionStencilZFail; + } + } + break; + case PropertyActionsEnum.RenderType: + { + module.TagsHelper.AddSpecialTag( TemplateSpecialTags.RenderType, item ); + } + break; + case PropertyActionsEnum.RenderQueue: + { + module.TagsHelper.AddSpecialTag( TemplateSpecialTags.Queue, item ); + } + break; + } + } + + public void OnCustomPassOptionSelected( bool isRefreshing, bool invertAction, TemplateOptionUIItem uiItem, params TemplateActionItem[] validActions ) + { + m_passOptions.OnCustomOptionSelected( isRefreshing, invertAction, this, uiItem, validActions ); + } + + public void OnCustomSubShaderOptionSelected( bool isRefreshing, bool invertAction, TemplateOptionUIItem uiItem, params TemplateActionItem[] validActions ) + { + if( m_isMainOutputNode ) + m_subShaderOptions.OnCustomOptionSelected( isRefreshing, invertAction, this, uiItem, validActions ); + } + + void SetupCustomOptionsFromTemplate( bool newTemplate ) + { + m_passOptions.SetupCustomOptionsFromTemplate( this, newTemplate ); + if( m_isMainOutputNode ) + m_subShaderOptions.SetupCustomOptionsFromTemplate( this, newTemplate ); + } + + void SetPassCustomOptionsInfo( TemplateMultiPassMasterNode masterNode ) + { + TemplateMultiPassMasterNode mainMasterNode = masterNode.IsMainOutputNode ? masterNode : ( m_containerGraph.CurrentMasterNode as TemplateMultiPassMasterNode ); + mainMasterNode.SubShaderOptions.SetSubShaderCustomOptionsPortsInfo( masterNode, ref m_currentDataCollector ); + masterNode.PassOptions.SetCustomOptionsInfo( masterNode, ref m_currentDataCollector ); + } + + void RefreshCustomOptionsDict() + { + m_passOptions.RefreshCustomOptionsDict(); + if( m_isMainOutputNode ) + m_subShaderOptions.RefreshCustomOptionsDict(); + } + + void SetCategoryIdxFromTemplate() + { + int templateCount = m_containerGraph.ParentWindow.TemplatesManagerInstance.TemplateCount; + for( int i = 0; i < templateCount; i++ ) + { + int idx = i + 1; + TemplateMultiPass templateData = m_containerGraph.ParentWindow.TemplatesManagerInstance.GetTemplate( i ) as TemplateMultiPass; + if( templateData != null && m_templateMultiPass != null && m_templateMultiPass.GUID.Equals( templateData.GUID ) ) + m_masterNodeCategory = idx; + } + } + + public void CheckTemplateChanges() + { + if( m_invalidNode ) + return; + + if( IsLODMainMasterNode ) + { + if( m_containerGraph.MultiPassMasterNodes.Count != m_templateMultiPass.MasterNodesRequired ) + { + if( m_availableCategories == null ) + RefreshAvailableCategories(); + + if( DebugConsoleWindow.DeveloperMode ) + Debug.Log( "Template Pass amount was changed. Rebuiling master nodes" ); + + m_containerGraph.ParentWindow.ReplaceMasterNode( m_availableCategories[ m_masterNodeCategory ], true ); + } + } + } + + public override void OnNodeLogicUpdate( DrawInfo drawInfo ) + { + if( m_invalidNode ) + { + return; + } + base.OnNodeLogicUpdate( drawInfo ); + + if( m_templateMultiPass == null ) + { + // Hotcode reload has happened + SetTemplate( null, false, true, m_subShaderIdx, m_passIdx , SetTemplateSource.HotCodeReload ); + CheckTemplateChanges(); + } + + if( m_reRegisterTemplateData ) + { + RegisterProperties(); + } + + if( m_fetchMasterNodeCategory ) + { + if( m_availableCategories != null ) + { + m_fetchMasterNodeCategory = false; + SetCategoryIdxFromTemplate(); + } + } + + if( m_fireTemplateChange ) + { + m_fireTemplateChange = false; + m_containerGraph.FireMasterNodeReplacedEvent(); + } + + if( m_subShaderModule.HasValidData ) + { + m_subShaderModule.OnLogicUpdate( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Modules ); + } + + if( m_passModule.HasValidData ) + { + m_passModule.OnLogicUpdate( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules ); + } + + if( !m_isMainOutputNode && m_mainMasterNodeRef == null ) + { + m_mainMasterNodeRef = m_containerGraph.CurrentMasterNode as TemplateMultiPassMasterNode; + } + + if( m_refreshLODValueMasterNodes && ( EditorApplication.timeSinceStartup - m_refreshLODValueMasterNodesTimestamp ) > MaxLODEditTimestamp ) + { + m_refreshLODValueMasterNodes = false; + m_refocusLODValueMasterNodes = true; + m_containerGraph.SortLODMasterNodes(); + } + } + + public override void Draw( DrawInfo drawInfo ) + { + if( m_isInvisible == InvisibilityStatus.Visible ) + { + base.Draw( drawInfo ); + } + } + + public override void OnNodeLayout( DrawInfo drawInfo ) + { + if( m_invalidNode ) + { + if( m_isMainOutputNode ) + { + UIUtils.ShowMessage( "Invalid current template. Switching to Standard Surface", MessageSeverity.Error ); + m_shaderModelIdx = 0; + m_masterNodeCategory = 0; + m_containerGraph.ParentWindow.ReplaceMasterNode( new MasterNodeCategoriesData( AvailableShaderTypes.SurfaceShader, m_shaderName ), false ); + } + return; + } + + if( m_isInvisible != InvisibilityStatus.Visible ) + { + return; + } + + if( !IsMainOutputNode ) + { + if( !IsInvisible && Docking ) + { + m_useSquareNodeTitle = true; + TemplateMultiPassMasterNode master = ContainerGraph.CurrentMasterNode as TemplateMultiPassMasterNode; + m_position = master.TruePosition; + m_position.height = 32; + int masterIndex = ContainerGraph.MultiPassMasterNodes.NodesList.IndexOf( master ); + int index = ContainerGraph.MultiPassMasterNodes.GetNodeRegisterIdx( UniqueId ); + if( index > masterIndex ) + { + int backTracking = 0; + for( int i = index - 1; i > masterIndex; i-- ) + { + if( !ContainerGraph.MultiPassMasterNodes.NodesList[ i ].IsInvisible && ContainerGraph.MultiPassMasterNodes.NodesList[ i ].Docking ) + backTracking++; + } + m_position.y = master.TruePosition.yMax + 1 + 33 * ( backTracking );// ContainerGraph.MultiPassMasterNodes.NodesList[ index - 1 ].TruePosition.yMax; + base.OnNodeLayout( drawInfo ); + } + else + { + int forwardTracking = 1; + for( int i = index + 1; i < masterIndex; i++ ) + { + if( !ContainerGraph.MultiPassMasterNodes.NodesList[ i ].IsInvisible && ContainerGraph.MultiPassMasterNodes.NodesList[ i ].Docking ) + forwardTracking++; + } + m_position.y = master.TruePosition.y - 33 * ( forwardTracking );// ContainerGraph.MultiPassMasterNodes.NodesList[ index - 1 ].TruePosition.yMax; + base.OnNodeLayout( drawInfo ); + } + } + else + { + m_useSquareNodeTitle = false; + base.OnNodeLayout( drawInfo ); + } + } + else + { + base.OnNodeLayout( drawInfo ); + } + } + + public override void OnNodeRepaint( DrawInfo drawInfo ) + { + base.OnNodeRepaint( drawInfo ); + if( m_invalidNode ) + return; + + if( m_isInvisible == InvisibilityStatus.Visible ) + { + if( m_containerGraph.IsInstancedShader ) + { + DrawInstancedIcon( drawInfo ); + } + } + } + + public override void UpdateFromShader( Shader newShader ) + { + if( m_currentMaterial != null && m_currentMaterial.shader != newShader ) + { + m_currentMaterial.shader = newShader; + } + CurrentShader = newShader; + } + + public override void UpdateMasterNodeMaterial( Material material ) + { + m_currentMaterial = material; + FireMaterialChangedEvt(); + } + + void DrawReloadButton() + { + if( GUILayout.Button( ReloadTemplateStr ) && m_templateMultiPass != null ) + { + m_templateMultiPass.Reload(); + } + } + + void DrawOpenTemplateButton() + { + GUILayout.BeginHorizontal(); + { + if( GUILayout.Button( OpenTemplateStr ) && m_templateMultiPass != null ) + { + try + { + string pathname = AssetDatabase.GUIDToAssetPath( m_templateMultiPass.GUID ); + if( !string.IsNullOrEmpty( pathname ) ) + { + Shader selectedTemplate = AssetDatabase.LoadAssetAtPath<Shader>( pathname ); + if( selectedTemplate != null ) + { + AssetDatabase.OpenAsset( selectedTemplate, 1 ); + } + } + } + catch( Exception e ) + { + Debug.LogException( e ); + } + } + + if( GUILayout.Button( "\u25C4", GUILayout.Width( 18 ), GUILayout.Height( 18 ) ) && m_templateMultiPass != null ) + { + try + { + string pathname = AssetDatabase.GUIDToAssetPath( m_templateMultiPass.GUID ); + if( !string.IsNullOrEmpty( pathname ) ) + { + Shader selectedTemplate = AssetDatabase.LoadAssetAtPath<Shader>( pathname ); + if( selectedTemplate != null ) + { + Event.current.Use(); + Selection.activeObject = selectedTemplate; + EditorGUIUtility.PingObject( Selection.activeObject ); + } + } + } + catch( Exception e ) + { + Debug.LogException( e ); + } + } + } + GUILayout.EndHorizontal(); + } + + public override void DrawProperties() + { + base.DrawProperties(); + if( m_invalidNode ) + return; + + NodeUtils.DrawPropertyGroup( ref m_propertiesFoldout, CommonPropertiesStr, DrawCommonProperties ); + NodeUtils.DrawPropertyGroup( ref m_subStringFoldout, SubShaderModuleStr, DrawSubShaderProperties ); + NodeUtils.DrawPropertyGroup( ref m_passFoldout, PassModuleStr, DrawPassProperties ); + + DrawMaterialInputs( UIUtils.MenuItemToolbarStyle, false ); + + if( m_propertyOrderChanged ) + { + List<TemplateMultiPassMasterNode> mpNodes = UIUtils.CurrentWindow.CurrentGraph.MultiPassMasterNodes.NodesList; + int count = mpNodes.Count; + for( int i = 0; i < count; i++ ) + { + if( mpNodes[ i ].UniqueId != UniqueId ) + { + mpNodes[ i ].CopyPropertyListFrom( this ); + } + } + } + +#if SHOW_TEMPLATE_HELP_BOX + EditorGUILayout.HelpBox( WarningMessage, MessageType.Warning ); +#endif + } + + // this will be removed later when PBR options are created + void SetExtraDefine( string define ) + { + List<TemplateMultiPassMasterNode> nodes = this.ContainerGraph.MultiPassMasterNodes.NodesList; + int count = nodes.Count; + for( int nodeIdx = 0; nodeIdx < count; nodeIdx++ ) + { + nodes[ nodeIdx ].OptionsDefineContainer.AddDefine( "#define " + define, false ); + } + } + + void AddHDKeywords() + { + if( m_templateMultiPass.CustomTemplatePropertyUI == CustomTemplatePropertyUIEnum.None ) + return; + + if( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Modules.SRPType != TemplateSRPType.HD || + !m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules.SRPIsPBR ) + return; + + switch( m_hdSrpMaterialType ) + { + case HDSRPMaterialType.SubsurfaceScattering: + { + SetExtraDefine( SRPMaterialSubsurfaceScatteringKeyword ); + //m_currentDataCollector.AddToDefines( UniqueId, SRPMaterialSubsurfaceScatteringKeyword ); + if( m_thicknessPort != null && m_thicknessPort.HasOwnOrLinkConnection ) + { + SetExtraDefine( SRPMaterialTransmissionKeyword ); + //m_currentDataCollector.AddToDefines( UniqueId, SRPMaterialTransmissionKeyword ); + } + } + break; + case HDSRPMaterialType.Standard: + break; + case HDSRPMaterialType.Specular: + { + SetExtraDefine( SRPHDMaterialSpecularKeyword ); + //m_currentDataCollector.AddToDefines( UniqueId, SRPHDMaterialSpecularKeyword ); + } + break; + case HDSRPMaterialType.Anisotropy: + { + SetExtraDefine( SRPMaterialAnisotropyKeyword ); + //m_currentDataCollector.AddToDefines( UniqueId, SRPMaterialAnisotropyKeyword ); + } + break; + case HDSRPMaterialType.Iridescence: + { + SetExtraDefine( SRPMaterialIridiscenceKeyword ); + //m_currentDataCollector.AddToDefines( UniqueId, SRPMaterialIridiscenceKeyword ); + } + break; + case HDSRPMaterialType.Translucent: + { + SetExtraDefine( SRPMaterialTransmissionKeyword ); + //m_currentDataCollector.AddToDefines( UniqueId, SRPMaterialTransmissionKeyword ); + } + break; + } + + if( m_coatMaskPort != null && m_coatMaskPort.HasOwnOrLinkConnection ) + { + SetExtraDefine( SRPMaterialClearCoatKeyword ); + //m_currentDataCollector.AddToDefines( UniqueId, SRPMaterialClearCoatKeyword ); + } + } + + void FetchHDPorts() + { + if( m_fetchPorts ) + { + m_fetchPorts = false; + if( m_inputPorts.Count > 4 ) + { + m_specularPort = GetInputPortByUniqueId( 3 ); + m_metallicPort = GetInputPortByUniqueId( 4 ); + m_coatMaskPort = GetInputPortByUniqueId( 11 ); + m_diffusionProfilePort = GetInputPortByUniqueId( 12 ); + m_subsurfaceMaskPort = GetInputPortByUniqueId( 13 ); + m_thicknessPort = GetInputPortByUniqueId( 14 ); + m_anisotropyPort = GetInputPortByUniqueId( 15 ); + m_iridescenceThicknessPort = GetInputPortByUniqueId( 16 ); + m_iridescenceMaskPort = GetInputPortByUniqueId( 17 ); + m_indexOfRefractionPort = GetInputPortByUniqueId( 18 ); + m_transmittanceColorPort = GetInputPortByUniqueId( 19 ); + m_transmittanceAbsorptionDistancePort = GetInputPortByUniqueId( 20 ); + m_transmittanceMaskPort = GetInputPortByUniqueId( 21 ); + } + } + } + + void ConfigHDPorts() + { + if( m_templateMultiPass.CustomTemplatePropertyUI == CustomTemplatePropertyUIEnum.None ) + return; + + if( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Modules.SRPType != TemplateSRPType.HD || + !m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules.SRPIsPBR ) + return; + + FetchHDPorts(); + if( m_inputPorts.Count > 4 ) + { + switch( m_hdSrpMaterialType ) + { + case HDSRPMaterialType.SubsurfaceScattering: + { + m_specularPort.Visible = false; + m_metallicPort.Visible = false; + m_coatMaskPort.Visible = true; + m_diffusionProfilePort.Visible = true; + m_subsurfaceMaskPort.Visible = true; + m_thicknessPort.Visible = true; + m_anisotropyPort.Visible = false; + m_iridescenceThicknessPort.Visible = false; + m_iridescenceMaskPort.Visible = false; + m_indexOfRefractionPort.Visible = false; + m_transmittanceColorPort.Visible = false; + m_transmittanceAbsorptionDistancePort.Visible = false; + m_transmittanceMaskPort.Visible = false; + } + break; + case HDSRPMaterialType.Standard: + { + m_specularPort.Visible = false; + m_metallicPort.Visible = true; + m_coatMaskPort.Visible = true; + m_diffusionProfilePort.Visible = false; + m_subsurfaceMaskPort.Visible = false; + m_thicknessPort.Visible = false; + m_anisotropyPort.Visible = false; + m_iridescenceThicknessPort.Visible = false; + m_iridescenceMaskPort.Visible = false; + m_indexOfRefractionPort.Visible = false; + m_transmittanceColorPort.Visible = false; + m_transmittanceAbsorptionDistancePort.Visible = false; + m_transmittanceMaskPort.Visible = false; + } + break; + case HDSRPMaterialType.Specular: + { + m_specularPort.Visible = true; + m_metallicPort.Visible = false; + m_coatMaskPort.Visible = true; + m_diffusionProfilePort.Visible = false; + m_subsurfaceMaskPort.Visible = false; + m_thicknessPort.Visible = false; + m_anisotropyPort.Visible = false; + m_iridescenceThicknessPort.Visible = false; + m_iridescenceMaskPort.Visible = false; + m_indexOfRefractionPort.Visible = false; + m_transmittanceColorPort.Visible = false; + m_transmittanceAbsorptionDistancePort.Visible = false; + m_transmittanceMaskPort.Visible = false; + } + break; + case HDSRPMaterialType.Anisotropy: + { + m_specularPort.Visible = false; + m_metallicPort.Visible = true; + m_coatMaskPort.Visible = true; + m_diffusionProfilePort.Visible = false; + m_subsurfaceMaskPort.Visible = false; + m_thicknessPort.Visible = false; + m_anisotropyPort.Visible = true; + m_iridescenceThicknessPort.Visible = false; + m_iridescenceMaskPort.Visible = false; + m_indexOfRefractionPort.Visible = false; + m_transmittanceColorPort.Visible = false; + m_transmittanceAbsorptionDistancePort.Visible = false; + m_transmittanceMaskPort.Visible = false; + } + break; + case HDSRPMaterialType.Iridescence: + { + m_specularPort.Visible = false; + m_metallicPort.Visible = true; + m_coatMaskPort.Visible = true; + m_diffusionProfilePort.Visible = false; + m_subsurfaceMaskPort.Visible = false; + m_thicknessPort.Visible = false; + m_anisotropyPort.Visible = false; + m_iridescenceThicknessPort.Visible = true; + m_iridescenceMaskPort.Visible = true; + m_indexOfRefractionPort.Visible = false; + m_transmittanceColorPort.Visible = false; + m_transmittanceAbsorptionDistancePort.Visible = false; + m_transmittanceMaskPort.Visible = false; + } + break; + case HDSRPMaterialType.Translucent: + { + m_specularPort.Visible = false; + m_metallicPort.Visible = false; + m_coatMaskPort.Visible = false; + m_diffusionProfilePort.Visible = true; + m_subsurfaceMaskPort.Visible = false; + m_thicknessPort.Visible = true; + m_anisotropyPort.Visible = false; + m_iridescenceThicknessPort.Visible = false; + m_iridescenceMaskPort.Visible = false; + m_indexOfRefractionPort.Visible = false; + m_transmittanceColorPort.Visible = false; + m_transmittanceAbsorptionDistancePort.Visible = false; + m_transmittanceMaskPort.Visible = false; + } + break; + } + } + m_sizeIsDirty = ( m_isInvisible == InvisibilityStatus.Visible ); + } + + + public void SetShaderLODValueAndLabel( int value ) + { + if( ShaderLOD != value ) + ShaderLOD = value; + + if( ContainerGraph.HasLODs ) + { + SetClippedAdditionalTitle( string.Format( LodSubtitle, ShaderLOD ) ); + } + else + { + SetAdditonalTitleText( string.Empty ); + } + } + + void DrawLODAddRemoveButtons() + { + DrawLODAddRemoveButtons( -2 , true ); + } + + void DrawLODAddRemoveButtons( int index , bool showRemove ) + { + if( GUILayoutButton( string.Empty, UIUtils.PlusStyle, GUILayout.Width( 15 ) ) ) + { + Vector2 minPos = Vec2Position; + //bool newNodePositionMode = false; + //if( newNodePositionMode ) + //{ + // for( int lod = 0; lod < ContainerGraph.LodMultiPassMasternodes.Count; lod++ ) + // { + // if( ContainerGraph.LodMultiPassMasternodes[ lod ].Count != 0 ) + // { + // Vector2 currPos = ContainerGraph.LodMultiPassMasternodes[ lod ].NodesList[ m_passIdx ].Vec2Position; + // if( currPos.y > minPos.y ) + // { + // minPos = currPos; + // } + // } + // else + // { + // if( index < 0 ) + // { + // index = lod; + // } + // break; + // } + // } + //} + //else + //{ + for( int lod = ContainerGraph.LodMultiPassMasternodes.Count - 1 ; lod >= 0; lod-- ) + { + if( ContainerGraph.LodMultiPassMasternodes[ lod ].Count != 0 ) + { + minPos = ContainerGraph.LodMultiPassMasternodes[ lod ].NodesList[ m_passIdx ].Vec2Position; + break; + } + } + //} + + minPos.y += HeightEstimate + 10; + ContainerGraph.CreateLodMasterNodes( m_templateMultiPass, index, minPos ); + } + + if( showRemove && GUILayoutButton( string.Empty, UIUtils.MinusStyle, GUILayout.Width( 15 ) ) ) + { + ContainerGraph.DestroyLodMasterNodes( index ); + } + } + + void SetupLODNodeName() + { + if( IsMainOutputNode ) + { + if( string.IsNullOrEmpty( m_mainLODName ) ) + { + m_shaderNameIsTitle = true; + m_content.text = GenerateClippedTitle( m_croppedShaderName ); + } + else + { + m_shaderNameIsTitle = false; + m_content.text = GenerateClippedTitle( m_mainLODName ); + } + } + else + { + m_shaderNameIsTitle = false; + m_content.text = GenerateClippedTitle( m_passName ); + } + } + + public void DrawLodRowItem(bool listMode) + { + float labelWidthBuffer = EditorGUIUtility.labelWidth; + EditorGUILayout.BeginHorizontal(); + if( listMode ) + { + if( GUILayout.Button( "\u25b6", GUILayout.Width( 18 ), GUILayout.Height( 18 ) ) ) + { + m_containerGraph.ParentWindow.FocusOnNode( this, 1, false, true ); + } + EditorGUI.BeginChangeCheck(); + GUI.SetNextControlName( LodValueId + m_lodIndex ); + m_shaderLOD = EditorGUILayoutIntField( string.Empty, m_shaderLOD, GUILayout.Width( 50 ) ); + } + else + { + EditorGUI.BeginChangeCheck(); + EditorGUIUtility.labelWidth = 45; + GUI.SetNextControlName( LodValueId + m_lodIndex ); + m_shaderLOD = EditorGUILayoutIntField( "LOD", ShaderLOD, GUILayout.Width(100)); + EditorGUIUtility.labelWidth = labelWidthBuffer; + } + + if( EditorGUI.EndChangeCheck() ) + { + m_refreshLODValueMasterNodes = true; + m_refreshLODValueMasterNodesTimestamp = EditorApplication.timeSinceStartup; + + if( ContainerGraph.HasLODs ) + SetClippedAdditionalTitle( string.Format( LodSubtitle, ShaderLOD ) ); + } + + EditorGUI.BeginChangeCheck(); + GUI.SetNextControlName( LodNameId + ShaderLOD ); + if( listMode ) + { + m_mainLODName = EditorGUILayoutTextField( string.Empty, m_mainLODName, GUILayout.Width( 100 ) ); + } + else + { + GUILayout.Space( -15 ); + EditorGUIUtility.labelWidth = 45; + m_mainLODName = EditorGUILayoutTextField( string.Empty, m_mainLODName ); + EditorGUIUtility.labelWidth = labelWidthBuffer; + } + if( EditorGUI.EndChangeCheck() ) + { + // If reorder is scheduled make sure it doesn't happen when editing LOD name + if( m_refreshLODValueMasterNodes ) + m_refreshLODValueMasterNodesTimestamp = EditorApplication.timeSinceStartup; + + SetupLODNodeName(); + } + + if( listMode ) + DrawLODAddRemoveButtons( m_lodIndex, ( m_lodIndex >= 0) ); + + EditorGUILayout.EndHorizontal(); + + if( m_refocusLODValueMasterNodes ) + { + m_refocusLODValueMasterNodes = false; + string focusedControl = GUI.GetNameOfFocusedControl(); + if( focusedControl.Contains( LodValueId ) ) + { + GUI.FocusControl( LodValueId + m_lodIndex ); + TextEditor te = (TextEditor)GUIUtility.GetStateObject( typeof( TextEditor ), GUIUtility.keyboardControl ); + if( te != null ) + { + te.SelectTextEnd(); + } + } + else if( focusedControl.Contains( LodNameId ) ) + { + GUI.FocusControl( LodNameId + m_lodIndex ); + TextEditor te = (TextEditor)GUIUtility.GetStateObject( typeof( TextEditor ), GUIUtility.keyboardControl ); + if( te != null ) + { + te.SelectTextEnd(); + } + } + } + } + + void DrawLOD() + { + if( m_templateMultiPass.CanAddLODs && m_lodIndex == -1 ) + { + EditorGUILayout.Space(); + + DrawLodRowItem(true); + EditorGUILayout.Space(); + + for( int i = 0; i < ContainerGraph.LodMultiPassMasternodes.Count; i++ ) + { + if( ContainerGraph.LodMultiPassMasternodes[ i ].NodesList.Count > 0 ) + { + TemplateMultiPassMasterNode masterNode = m_containerGraph.LodMultiPassMasternodes[ i ].NodesList[ m_passIdx ]; + masterNode.DrawLodRowItem( true ); + EditorGUILayout.Space(); + } + } + EditorGUILayout.Space(); + } + } + + void DrawCommonProperties() + { + if( m_isMainOutputNode ) + { + //if( m_templateMultiPass.CanAddLODs && m_lodIndex == -1 ) + //{ + // if( GUILayoutButton( string.Empty, UIUtils.PlusStyle, GUILayout.Width( 15 ) ) ) + // { + // ContainerGraph.CreateLodMasterNodes( m_templateMultiPass, Vec2Position ); + // } + + + // if( GUILayoutButton( string.Empty, UIUtils.MinusStyle, GUILayout.Width( 15 ) ) ) + // { + // ContainerGraph.DestroyLodMasterNodes(); + // } + + //} + + //EditorGUILayout.LabelField( "LOD: " + m_lodIndex ); + DrawShaderName(); + DrawCurrentShaderType(); + + if( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules.SRPIsPBRHD ) + { + if( m_templateMultiPass.CustomTemplatePropertyUI == CustomTemplatePropertyUIEnum.HDPBR ) + { + EditorGUI.BeginChangeCheck(); + CurrentHDMaterialType = (HDSRPMaterialType)EditorGUILayoutEnumPopup( HDSRPMaterialTypeStr, m_hdSrpMaterialType ); + if( EditorGUI.EndChangeCheck() ) + ConfigHDPorts(); + } + } + + EditorGUI.BeginChangeCheck(); + DrawPrecisionProperty( false ); + if( EditorGUI.EndChangeCheck() ) + ContainerGraph.CurrentPrecision = m_currentPrecisionType; + m_drawInstancedHelper.Draw( this ); + m_fallbackHelper.Draw( this ); + DrawCustomInspector( m_templateMultiPass.SRPtype != TemplateSRPType.BuiltIn ); + m_subShaderOptions.DrawCustomOptions( this ); + m_dependenciesHelper.Draw( this, true ); + } + //EditorGUILayout.LabelField( m_subShaderIdxStr ); + //EditorGUILayout.LabelField( m_passIdxStr ); + + if( IsLODMainMasterNode && m_templateMultiPass.CanAddLODs ) + { + NodeUtils.DrawNestedPropertyGroup( ref m_lodFoldout, AdditionalLODsStr, DrawLOD, DrawLODAddRemoveButtons ); + } + + DrawOpenTemplateButton(); + if( DebugConsoleWindow.DeveloperMode ) + DrawReloadButton(); + + } + + public void DrawSubShaderProperties() + { + if( !m_isMainOutputNode ) + { + m_mainMasterNodeRef.DrawSubShaderProperties(); + return; + } + + bool noValidData = true; + if( ShaderLOD > 0 ) + { + noValidData = false; + if( m_templateMultiPass.CanAddLODs && m_containerGraph.LodMultiPassMasternodes[0].Count > 0 ) + { + DrawLodRowItem( false ); + } + else + { + ShaderLOD = EditorGUILayoutIntField( SubShaderLODValueLabel, ShaderLOD ); + } + } + + if( m_subShaderModule.HasValidData ) + { + noValidData = false; + m_subShaderModule.Draw( this, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Modules ); + //if( m_subShaderModule.IsDirty ) + //{ + // List<TemplateMultiPassMasterNode> mpNodes = UIUtils.CurrentWindow.CurrentGraph.MultiPassMasterNodes.NodesList; + // int count = mpNodes.Count; + // for( int i = 0; i < count; i++ ) + // { + // if( mpNodes[ i ].SubShaderIdx == m_subShaderIdx && mpNodes[ i ].UniqueId != UniqueId ) + // { + // mpNodes[ i ].SubShaderModule.CopyFrom( m_subShaderModule ); + // } + // } + // m_subShaderModule.IsDirty = false; + //} + } + + m_passSelector.Draw( this ); + + if( noValidData ) + { + EditorGUILayout.HelpBox( NoSubShaderPropertyStr, MessageType.Info ); + } + } + + void DrawPassProperties() + { + EditorGUI.BeginChangeCheck(); + m_passName = EditorGUILayoutTextField( PassNameStr, m_passName ); + if( EditorGUI.EndChangeCheck() ) + { + if( m_passName.Length > 0 ) + { + m_passName = UIUtils.RemoveShaderInvalidCharacters( m_passName ); + } + else + { + m_passName = m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].PassNameContainer.Data; + } + //if( !m_templateMultiPass.IsSinglePass ) + // SetClippedTitle( m_passName ); + } + EditorGUILayout.LabelField( Pass.Modules.PassUniqueName ); + if( m_passModule.HasValidData ) + { + m_passModule.Draw( this, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules, m_subShaderModule ); + } + + m_usePass.Draw( this, false ); + m_passOptions.DrawCustomOptions( this ); + } + + bool CreateInstructionsForList( TemplateData templateData, ref List<InputPort> ports, ref string shaderBody, ref List<string> vertexInstructions, ref List<string> fragmentInstructions ) + { + if( ports.Count == 0 ) + return true; + AddHDKeywords(); + bool isValid = true; + //UIUtils.CurrentWindow.CurrentGraph.ResetNodesLocalVariables(); + for( int i = 0; i < ports.Count; i++ ) + { + TemplateInputData inputData = templateData.InputDataFromId( ports[ i ].PortId ); + if( ports[ i ].HasOwnOrLinkConnection ) + { + //if( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Modules.SRPType == TemplateSRPType.Lightweight ) + //{ + // if( ports[ i ].Name.Contains( "Normal" ) ) + // { + // m_currentDataCollector.AddToDirectives( SRPMaterialNormalMapKeyword, -1, AdditionalLineType.Define ); + // } + + // if( ports[ i ].Name.Contains( "Alpha Clip Threshold" ) ) + // { + // m_currentDataCollector.AddToDirectives( SRPMaterialBlendModeAlphaClipThresholdKeyword, -1, AdditionalLineType.Define ); + // } + + // if( ports[ i ].Name.Contains( "Specular" ) ) + // { + // m_currentDataCollector.AddToDirectives( SRPLWMaterialSpecularKeyword, -1, AdditionalLineType.Define ); + // } + //} + //else if( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Modules.SRPType == TemplateSRPType.HD ) + //{ + // if( ports[ i ].Name.Contains( "Normal" ) ) + // { + // //m_currentDataCollector.AddToDefines( UniqueId, SRPMaterialNormalMapKeyword ); + // } + + // if( ports[ i ].Name.Contains( "Alpha Clip Threshold" ) ) + // { + // //m_currentDataCollector.AddToDefines( UniqueId, SRPMaterialAlphaTestKeyword ); + // } + + //} + + m_currentDataCollector.ResetInstructions(); + m_currentDataCollector.ResetVertexInstructions(); + + m_currentDataCollector.PortCategory = ports[ i ].Category; + string newPortInstruction = ports[ i ].GeneratePortInstructions( ref m_currentDataCollector ); + + if( m_currentDataCollector.DirtySpecialLocalVariables ) + { + string cleanVariables = m_currentDataCollector.SpecialLocalVariables.Replace( "\t", string.Empty ); + m_currentDataCollector.AddInstructions( cleanVariables, false ); + m_currentDataCollector.ClearSpecialLocalVariables(); + } + + if( m_currentDataCollector.DirtyVertexVariables ) + { + string cleanVariables = m_currentDataCollector.VertexLocalVariables.Replace( "\t", string.Empty ); + m_currentDataCollector.AddVertexInstruction( cleanVariables, UniqueId, false ); + m_currentDataCollector.ClearVertexLocalVariables(); + } + + // fill functions + for( int j = 0; j < m_currentDataCollector.InstructionsList.Count; j++ ) + { + fragmentInstructions.Add( m_currentDataCollector.InstructionsList[ j ].PropertyName ); + } + + for( int j = 0; j < m_currentDataCollector.VertexDataList.Count; j++ ) + { + vertexInstructions.Add( m_currentDataCollector.VertexDataList[ j ].PropertyName ); + } + + m_templateMultiPass.SetPassInputData( m_subShaderIdx, m_passIdx, ports[ i ].PortId, newPortInstruction ); + isValid = m_templateMultiPass.FillTemplateBody( m_subShaderIdx, m_passIdx, inputData.TagId, ref shaderBody, newPortInstruction ) && isValid; + } + else + { + m_templateMultiPass.SetPassInputData( m_subShaderIdx, m_passIdx, ports[ i ].PortId, inputData.DefaultValue ); + isValid = m_templateMultiPass.FillTemplateBody( m_subShaderIdx, m_passIdx, inputData.TagId, ref shaderBody, inputData.DefaultValue ) && isValid; + } + } + return isValid; + } + + public string BuildShaderBody( MasterNodeDataCollector inDataCollector, ref MasterNodeDataCollector outDataCollector ) + { + List<TemplateMultiPassMasterNode> list = UIUtils.CurrentWindow.CurrentGraph.MultiPassMasterNodes.NodesList; + int currentSubshader = list[ 0 ].SubShaderIdx; + m_templateMultiPass.SetShaderName( string.Format( TemplatesManager.NameFormatter, m_shaderName ) ); + if( string.IsNullOrEmpty( m_customInspectorName ) ) + { + m_templateMultiPass.SetCustomInspector( string.Empty ); + } + else + { + m_templateMultiPass.SetCustomInspector( CustomInspectorFormatted ); + } + + m_templateMultiPass.SetFallback( m_fallbackHelper.FallbackShader ); + m_templateMultiPass.SetDependencies( m_dependenciesHelper.GenerateDependencies() ); + + if( inDataCollector != null ) + outDataCollector.CopyPropertiesFromDataCollector( inDataCollector ); + + outDataCollector.TemplateDataCollectorInstance.CurrentSRPType = m_templateMultiPass.SRPtype; + + int lastActivePass = m_passSelector.LastActivePass; + int count = list.Count; + + for( int i = 0; i < count; i++ ) + { + bool removePass = !m_passSelector.IsVisible( i ); + + list[ 0 ].CurrentTemplate.IdManager.SetPassIdUsage( i, removePass ); + if( removePass ) + continue; + + list[ i ].CollectData(); + list[ i ].FillPassData( this, outDataCollector.TemplateDataCollectorInstance ); + + if( list[ i ].SubShaderIdx == currentSubshader ) + { + outDataCollector.CopyPropertiesFromDataCollector( list[ i ].CurrentDataCollector ); + } + else + { + list[ i - 1 ].FillPropertyData( outDataCollector ); + list[ i - 1 ].FillSubShaderData(); + outDataCollector.Destroy(); + outDataCollector = new MasterNodeDataCollector(); + outDataCollector.CopyPropertiesFromDataCollector( list[ i ].CurrentDataCollector ); + + currentSubshader = list[ i ].SubShaderIdx; + } + + // Last element must the one filling subshader data + // as only there all properties are caught + //if( i == ( count - 1 ) ) + if( i == lastActivePass ) + { + list[ i ].FillPropertyData( outDataCollector ); + } + + if( list[ i ].IsMainOutputNode ) + list[ i ].FillSubShaderData(); + } + + outDataCollector.TemplateDataCollectorInstance.BuildCBuffer( -1 ); + + //Fill uniforms is set on last since we need to collect all srp batcher data ( if needed ) + //To set it into each pass + for( int i = 0; i < count; i++ ) + { + bool removePass = !m_passSelector.IsVisible( i ); + if( removePass ) + continue; + + list[ i ].FillUniforms( outDataCollector.TemplateDataCollectorInstance ); + } + + return list[ 0 ].CurrentTemplate.IdManager.BuildShader(); + } + + public string BuildLOD( MasterNodeDataCollector inDataCollector, ref MasterNodeDataCollector outDataCollector ) + { + UsageListTemplateMultiPassMasterNodes bufferNodesList = ContainerGraph.MultiPassMasterNodes; + int bufferMasterNodeId = ContainerGraph.CurrentMasterNodeId; + + ContainerGraph.MultiPassMasterNodes = ContainerGraph.LodMultiPassMasternodes[ m_lodIndex ]; + ContainerGraph.CurrentMasterNodeId = UniqueId; + + m_templateMultiPass.ResetState(); + base.Execute( string.Empty, false ); + string shaderBody = BuildShaderBody( inDataCollector, ref outDataCollector ); + + + ContainerGraph.MultiPassMasterNodes = bufferNodesList; + ContainerGraph.CurrentMasterNodeId = bufferMasterNodeId; + return shaderBody; + } + + public override Shader Execute( string pathname, bool isFullPath ) + { + ForceReordering(); + MasterNodeDataCollector overallDataCollector = new MasterNodeDataCollector(); + + //BUILD LOD + string allLodSubShaders = string.Empty; + if( ContainerGraph.HasLODs ) + { + for( int lod = 0; lod < ContainerGraph.LodMultiPassMasternodes.Count; lod++ ) + { + if( ContainerGraph.LodMultiPassMasternodes[ lod ].Count == 0 ) + break; + + TemplateMultiPassMasterNode newMasterNode = ContainerGraph.LodMultiPassMasternodes[ lod ].NodesList.Find( ( x ) => x.IsMainOutputNode ); + string lodSubShaders = newMasterNode.BuildLOD( null, ref overallDataCollector ); + lodSubShaders = TemplateHelperFunctions.GetSubShaderFrom( lodSubShaders ) + "\n"; + allLodSubShaders += lodSubShaders; + } + } + + //BUILD MAIN + m_templateMultiPass.ResetState(); + base.Execute( pathname, isFullPath ); + MasterNodeDataCollector dummy = new MasterNodeDataCollector(); + string shaderBody = BuildShaderBody( overallDataCollector, ref dummy ); + + //COMBINE LOD WITH MAIN + if( !string.IsNullOrEmpty( allLodSubShaders ) ) + shaderBody = shaderBody.Replace( TemplatesManager.TemplateLODsTag, allLodSubShaders ); + + UpdateShaderAsset( ref pathname, ref shaderBody, isFullPath ); + return m_currentShader; + } + + public void CollectData() + { + if( m_inputPorts.Count == 0 ) + return; + + ContainerGraph.ResetNodesLocalVariables(); + m_optionsDefineContainer.RemoveTemporaries(); + m_currentDataCollector = new MasterNodeDataCollector( this ); + m_currentDataCollector.TemplateDataCollectorInstance.SetMultipassInfo( m_templateMultiPass, m_subShaderIdx, m_passIdx, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Modules.SRPType ); + m_currentDataCollector.TemplateDataCollectorInstance.FillSpecialVariables( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ] ); + SetupNodeCategories(); + if( m_containerGraph.IsInstancedShader ) + { + string blockName = UIUtils.RemoveInvalidCharacters( ContainerGraph.GetMainMasterNodeOfLOD( -1 ).ShaderName ); + m_currentDataCollector.SetupInstancePropertiesBlock( blockName ); + } + TemplateData templateData = m_templateMultiPass.CreateTemplateData( m_shaderName, string.Empty, m_subShaderIdx, m_passIdx ); + m_currentDataCollector.TemplateDataCollectorInstance.BuildFromTemplateData( m_currentDataCollector, templateData ); + + if( m_currentDataCollector.TemplateDataCollectorInstance.InterpData.DynamicMax ) + { + int interpolatorAmount = -1; + if( m_passModule.ShaderModelHelper.ValidData ) + { + interpolatorAmount = m_passModule.ShaderModelHelper.InterpolatorAmount; + } + else + { + TemplateModulesHelper subShaderModule = IsMainOutputNode ? m_subShaderModule : ( m_containerGraph.CurrentMasterNode as TemplateMultiPassMasterNode ).SubShaderModule; + if( subShaderModule.ShaderModelHelper.ValidData ) + { + interpolatorAmount = subShaderModule.ShaderModelHelper.InterpolatorAmount; + } + } + + if( interpolatorAmount > -1 ) + { + m_currentDataCollector.TemplateDataCollectorInstance.InterpData.RecalculateAvailableInterpolators( interpolatorAmount ); + } + } + + //Copy Properties + { + int shaderPropertiesAmount = m_templateMultiPass.AvailableShaderProperties.Count; + for( int i = 0; i < shaderPropertiesAmount; i++ ) + { + m_currentDataCollector.SoftRegisterUniform( m_templateMultiPass.AvailableShaderProperties[ i ] ); + } + } + //Copy Globals from SubShader level + { + int subShaderGlobalAmount = m_templateMultiPass.SubShaders[ m_subShaderIdx ].AvailableShaderGlobals.Count; + for( int i = 0; i < subShaderGlobalAmount; i++ ) + { + m_currentDataCollector.SoftRegisterUniform( m_templateMultiPass.SubShaders[ m_subShaderIdx ].AvailableShaderGlobals[ i ] ); + } + } + //Copy Globals from Pass Level + { + int passGlobalAmount = m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].AvailableShaderGlobals.Count; + for( int i = 0; i < passGlobalAmount; i++ ) + { + m_currentDataCollector.SoftRegisterUniform( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].AvailableShaderGlobals[ i ] ); + } + } + // Check Current Options for property changes on subshader + if( m_isMainOutputNode ) + { + CheckPropertyChangesOnOptions( m_subShaderOptions ); + } + + // Check Current Options for property changes on pass + CheckPropertyChangesOnOptions( m_passOptions ); + + + //Set SRP info +#if UNITY_2018_3_OR_NEWER + if( m_templateMultiPass.SRPtype != TemplateSRPType.BuiltIn ) + ASEPackageManagerHelper.SetSRPInfoOnDataCollector( ref m_currentDataCollector ); +#endif + RegisterStandaloneFuntions(); + m_containerGraph.CheckPropertiesAutoRegister( ref m_currentDataCollector ); + + //Sort ports by both + List<InputPort> fragmentPorts = new List<InputPort>(); + List<InputPort> vertexPorts = new List<InputPort>(); + + SortInputPorts( ref vertexPorts, ref fragmentPorts ); + + + string shaderBody = templateData.TemplateBody; + + List<string> vertexInstructions = new List<string>(); + List<string> fragmentInstructions = new List<string>(); + + bool validBody = true; + + //validBody = CreateInstructionsForList( templateData, ref fragmentPorts, ref shaderBody, ref vertexInstructions, ref fragmentInstructions ) && validBody; + //ContainerGraph.ResetNodesLocalVariablesIfNot( MasterNodePortCategory.Vertex ); + //validBody = CreateInstructionsForList( templateData, ref vertexPorts, ref shaderBody, ref vertexInstructions, ref fragmentInstructions ) && validBody; + validBody = CreateInstructionsForList( templateData, ref vertexPorts, ref shaderBody, ref vertexInstructions, ref fragmentInstructions ) && validBody; + validBody = CreateInstructionsForList( templateData, ref fragmentPorts, ref shaderBody, ref vertexInstructions, ref fragmentInstructions ) && validBody; + + if( !m_isMainOutputNode && m_mainMasterNodeRef == null ) + { + m_mainMasterNodeRef = m_containerGraph.CurrentMasterNode as TemplateMultiPassMasterNode; + } + + TerrainDrawInstancedHelper drawInstanced = m_isMainOutputNode ? m_drawInstancedHelper : m_mainMasterNodeRef.DrawInstancedHelperInstance; + drawInstanced.UpdateDataCollectorForTemplates( ref m_currentDataCollector, ref vertexInstructions ); + + templateData.ResetTemplateUsageData(); + + // Fill vertex interpolators assignment + for( int i = 0; i < m_currentDataCollector.VertexInterpDeclList.Count; i++ ) + { + vertexInstructions.Add( m_currentDataCollector.VertexInterpDeclList[ i ] ); + } + + vertexInstructions.AddRange( m_currentDataCollector.TemplateDataCollectorInstance.GetInterpUnusedChannels() ); + + //Fill common local variables and operations + validBody = m_templateMultiPass.FillVertexInstructions( m_subShaderIdx, m_passIdx, vertexInstructions.ToArray() ) && validBody; + validBody = m_templateMultiPass.FillFragmentInstructions( m_subShaderIdx, m_passIdx, fragmentInstructions.ToArray() ) && validBody; + + vertexInstructions.Clear(); + vertexInstructions = null; + + fragmentInstructions.Clear(); + fragmentInstructions = null; + + // Add Instanced Properties + if( m_containerGraph.IsInstancedShader ) + { + m_currentDataCollector.OptimizeInstancedProperties(); + m_currentDataCollector.TabifyInstancedVars(); + + //string cbufferBegin = m_currentDataCollector.IsSRP ? + // string.Format( IOUtils.SRPInstancedPropertiesBegin, "UnityPerMaterial" ) : + // string.Format( IOUtils.InstancedPropertiesBegin, m_currentDataCollector.InstanceBlockName ); + //string cBufferEnd = m_currentDataCollector.IsSRP ? ( string.Format( IOUtils.SRPInstancedPropertiesEnd, m_currentDataCollector.InstanceBlockName ) ) : IOUtils.InstancedPropertiesEnd; + string cbufferBegin = m_currentDataCollector.IsSRP ? + string.Format( IOUtils.LWSRPInstancedPropertiesBegin, m_currentDataCollector.InstanceBlockName ) : + string.Format( IOUtils.InstancedPropertiesBegin, m_currentDataCollector.InstanceBlockName ); + string cBufferEnd = m_currentDataCollector.IsSRP ? ( string.Format( IOUtils.LWSRPInstancedPropertiesEnd, m_currentDataCollector.InstanceBlockName ) ) : IOUtils.InstancedPropertiesEnd; + + m_currentDataCollector.InstancedPropertiesList.Insert( 0, new PropertyDataCollector( -1, cbufferBegin ) ); + m_currentDataCollector.InstancedPropertiesList.Add( new PropertyDataCollector( -1, cBufferEnd ) ); + m_currentDataCollector.UniformsList.AddRange( m_currentDataCollector.InstancedPropertiesList ); + } + + if( m_currentDataCollector.DotsPropertiesList.Count > 0 ) + { + m_currentDataCollector.DotsPropertiesList.Insert( 0, new PropertyDataCollector( -1, "UNITY_DOTS_INSTANCING_START(MaterialPropertyMetadata)" ) ); + m_currentDataCollector.DotsPropertiesList.Insert( 0, new PropertyDataCollector( -1, "#ifdef UNITY_DOTS_INSTANCING_ENABLED" ) ); + m_currentDataCollector.DotsPropertiesList.Insert( 0, new PropertyDataCollector( -1, "" ) ); + m_currentDataCollector.DotsPropertiesList.Add( new PropertyDataCollector( -1, "UNITY_DOTS_INSTANCING_END(MaterialPropertyMetadata)" ) ); + m_currentDataCollector.DotsDefinesList.Add( new PropertyDataCollector( -1, "#endif" ) ); + m_currentDataCollector.UniformsList.AddRange( m_currentDataCollector.DotsPropertiesList ); + m_currentDataCollector.UniformsList.AddRange( m_currentDataCollector.DotsDefinesList ); + } + + TemplateShaderModelModule shaderModelModule = m_isMainOutputNode ? m_subShaderModule.ShaderModelHelper : m_mainMasterNodeRef.SubShaderModule.ShaderModelHelper; + string shaderModel = string.Empty; + if( m_passModule.ShaderModelHelper.ValidData ) + { + shaderModel = m_passModule.ShaderModelHelper.CurrentShaderModel; + } + else if( shaderModelModule.ValidData ) + { + shaderModel = shaderModelModule.CurrentShaderModel; + } + else if( m_templateMultiPass.GlobalShaderModel.IsValid ) + { + shaderModel = m_templateMultiPass.GlobalShaderModel.Value; + } + else + { + shaderModel = ( m_templateMultiPass.SRPtype == TemplateSRPType.HD ) ? "4.5" : "3.0"; + } + + m_currentDataCollector.TemplateDataCollectorInstance.CheckInterpolatorOverflow( shaderModel, m_passName ); + } + + public void CheckPropertyChangesOnOptions( TemplateOptionsUIHelper optionsUI ) + { + //Only Main LOD master node can change shader properties + if( !IsLODMainMasterNode ) + return; + + List<TemplateOptionUIItem> options = optionsUI.PassCustomOptionsUI; + for( int optionIdx = 0; optionIdx < options.Count; optionIdx++ ) + { + if( options[ optionIdx ].IsVisible ) + { + TemplateActionItem[] actionItems = options[ optionIdx ].CurrentOptionActions.Columns; + for( int actionIdx = 0; actionIdx < actionItems.Length; actionIdx++ ) + { + if( actionItems[ actionIdx ].ActionType == AseOptionsActionType.SetShaderProperty && !string.IsNullOrEmpty( actionItems[ actionIdx ].ActionBuffer ) ) + { + TemplateShaderPropertyData data = m_templateMultiPass.GetShaderPropertyData( actionItems[ actionIdx ].ActionData ); + if( data != null ) + { + string newPropertyValue = data.CreatePropertyForValue( actionItems[ actionIdx ].ActionBuffer ); + CurrentTemplate.IdManager.SetReplacementText( data.FullValue, newPropertyValue ); + } + } + } + + if( options[ optionIdx ].Options.Type == AseOptionsType.Field ) + { + foreach( var item in CurrentTemplate.IdManager.RegisteredTags ) + { + if( item.Output.Equals( options[ optionIdx ].Options.FieldInlineName ) ) + { + var node = options[ optionIdx ].Options.FieldValue.GetPropertyNode(); + if( node != null && ( node.IsConnected || node.AutoRegister ) && options[ optionIdx ].Options.FieldValue.Active ) + { + item.Replacement = node.PropertyName; + } + } + } + } + } + } + } + public void FillPropertyData( MasterNodeDataCollector dataCollector = null ) + { + MasterNodeDataCollector currDataCollector = ( dataCollector == null ) ? m_currentDataCollector : dataCollector; + +#if UNITY_2019_2_OR_NEWER + // Temporary hack + if( m_templateMultiPass.SRPtype != TemplateSRPType.BuiltIn && ASEPackageManagerHelper.CurrentHDVersion > ASESRPVersions.ASE_SRP_6_9_0 ) + { + if( m_templateMultiPass.AvailableShaderProperties.Find( x => x.PropertyName.Equals( "_AlphaCutoff" ) ) == null ) + { + if( !currDataCollector.ContainsProperty("_AlphaCutoff") ) + { + currDataCollector.AddToProperties( UniqueId, "[HideInInspector] _AlphaCutoff(\"Alpha Cutoff \", Range(0, 1)) = 0.5", -1 ); + } + } + + if( m_templateMultiPass.AvailableShaderProperties.Find( x => x.PropertyName.Equals( "_EmissionColor" ) ) == null ) + { + if( !currDataCollector.ContainsProperty( "_EmissionColor" ) ) + { + currDataCollector.AddToProperties( UniqueId, "[HideInInspector] _EmissionColor(\"Emission Color\", Color) = (1,1,1,1)", -1 ); + } + } + } +#endif + + m_templateMultiPass.SetPropertyData( currDataCollector.BuildUnformatedPropertiesStringArr() ); + } + + public void FillSubShaderData( /*MasterNodeDataCollector dataCollector = null */) + { + //MasterNodeDataCollector currDataCollector = ( dataCollector == null ) ? m_currentDataCollector : dataCollector; + //// SubShader Data + + //m_templateMultiPass.SetPropertyData( currDataCollector.BuildUnformatedPropertiesStringArr() ); + //templateMultiPass.SetSubShaderData( TemplateModuleDataType.ModulePass, m_subShaderIdx, currDataCollector.GrabPassList ); + if( ShaderLOD > -1 ) + { + string lodUniqueId = m_templateMultiPass.SubShaders[ m_subShaderIdx ].UniquePrefix + "Module" + m_templateMultiPass.SubShaders[ m_subShaderIdx ].LODContainer.Id; + m_templateMultiPass.IdManager.SetReplacementText( lodUniqueId, "LOD " + ShaderLOD ); + } + + SetModuleData( m_subShaderModule, true ); + } + + public void FillPassData( TemplateMultiPassMasterNode masterNode, TemplateDataCollector mainTemplateDataCollector ) + { + if( m_isInvisible != InvisibilityStatus.Visible ) + { + if( masterNode.UniqueId != UniqueId ) + { + if( ( m_invisibleOptions & (int)InvisibleOptionsEnum.SyncProperties ) > 0 ) + { + PassModule.SyncWith( masterNode.PassModule ); + } + } + + int inputCount = m_inputPorts.Count; + for( int i = 0; i < inputCount; i++ ) + { + if( m_inputPorts[ i ].HasExternalLink ) + { + TemplateMultiPassMasterNode linkedNode = m_inputPorts[ i ].ExternalLinkNode as TemplateMultiPassMasterNode; + if( linkedNode != null ) + { + SetLinkedModuleData( linkedNode.PassModule ); + } + } + } + } + + SetModuleData( m_passModule, false ); + if( m_currentDataCollector != null ) + { + if( Pass.CustomOptionsContainer.CopyOptionsFromMainPass ) + { + SetPassCustomOptionsInfo( m_containerGraph.CurrentMasterNode as TemplateMultiPassMasterNode ); + } + else + { + SetPassCustomOptionsInfo( this ); + } + + var inputArray = m_currentDataCollector.VertexInputList.ToArray(); + + m_templateMultiPass.SetPassData( TemplateModuleDataType.PassVertexData, m_subShaderIdx, m_passIdx, inputArray ); + m_templateMultiPass.SetPassData( TemplateModuleDataType.PassInterpolatorData, m_subShaderIdx, m_passIdx, m_currentDataCollector.InterpolatorList.ToArray() ); + SetHDInfoOnPass(); + List<PropertyDataCollector> afterNativesIncludePragmaDefineList = new List<PropertyDataCollector>(); + afterNativesIncludePragmaDefineList.AddRange( m_currentDataCollector.IncludesList ); + afterNativesIncludePragmaDefineList.AddRange( m_currentDataCollector.DefinesList ); + //includePragmaDefineList.AddRange( m_optionsDefineContainer.DefinesList ); + afterNativesIncludePragmaDefineList.AddRange( m_currentDataCollector.PragmasList ); + afterNativesIncludePragmaDefineList.AddRange( m_currentDataCollector.AfterNativeDirectivesList ); + + //includePragmaDefineList.AddRange( m_currentDataCollector.MiscList ); + + List<PropertyDataCollector> beforeNatives = new List<PropertyDataCollector>(); + beforeNatives.AddRange( m_optionsDefineContainer.DefinesList ); + beforeNatives.AddRange( m_currentDataCollector.BeforeNativeDirectivesList ); + + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModulePragmaBefore, m_subShaderIdx, m_passIdx, beforeNatives ); + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModulePragma, m_subShaderIdx, m_passIdx, afterNativesIncludePragmaDefineList ); + + m_currentDataCollector.TemplateDataCollectorInstance.CloseLateDirectives(); + + //Add Functions + if( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules.FunctionsTag.IsValid ) + { + m_currentDataCollector.FunctionsList.InsertRange( 0, m_currentDataCollector.TemplateDataCollectorInstance.LateDirectivesList ); + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleFunctions, m_subShaderIdx, m_passIdx, m_currentDataCollector.FunctionsList ); + } + else + { + m_currentDataCollector.UniformsList.InsertRange( 0, m_currentDataCollector.TemplateDataCollectorInstance.LateDirectivesList ); + m_currentDataCollector.UniformsList.AddRange( m_currentDataCollector.FunctionsList ); + } + + //copy srp batch if present + //if( m_currentDataCollector.IsSRP ) + //{ + // m_currentDataCollector.UniformsList.AddRange( mainTemplateDataCollector.SrpBatcherPropertiesList ); + //} + //m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleGlobals, m_subShaderIdx, m_passIdx, m_currentDataCollector.UniformsList ); + + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleInputVert, m_subShaderIdx, m_passIdx, m_currentDataCollector.TemplateDataCollectorInstance.VertexInputParamsStr ); + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleInputFrag, m_subShaderIdx, m_passIdx, m_currentDataCollector.TemplateDataCollectorInstance.FragInputParamsStr ); + + if( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].TessVControlTag != null && m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].TessVControlTag.IsValid ) + m_templateMultiPass.SetPassData( TemplateModuleDataType.VControl, m_subShaderIdx, m_passIdx, inputArray ); + + if( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].TessControlData != null && m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].TessControlData.IsValid ) + m_templateMultiPass.SetPassData( TemplateModuleDataType.ControlData, m_subShaderIdx, m_passIdx, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].TessControlData.GenerateControl( m_currentDataCollector.TemplateDataCollectorInstance.VertexDataDict, m_currentDataCollector.VertexInputList ) ); + + if( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].TessDomainData != null && m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].TessDomainData.IsValid ) + m_templateMultiPass.SetPassData( TemplateModuleDataType.DomainData, m_subShaderIdx, m_passIdx, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].TessDomainData.GenerateDomain( m_currentDataCollector.TemplateDataCollectorInstance.VertexDataDict, m_currentDataCollector.VertexInputList ) ); + + afterNativesIncludePragmaDefineList.Clear(); + afterNativesIncludePragmaDefineList = null; + + beforeNatives.Clear(); + beforeNatives = null; + } + + m_templateMultiPass.SetPassData( TemplateModuleDataType.PassNameData, m_subShaderIdx, m_passIdx, string.Format( PassNameFormateStr, m_passName ) ); + } + + public List<PropertyDataCollector> CrossCheckSoftRegisteredUniformList( List<PropertyDataCollector> uniformList ) + { + List<PropertyDataCollector> newItems = new List<PropertyDataCollector>(); + for( int i = 0; i < uniformList.Count; i++ ) + { + if( !m_currentDataCollector.CheckIfSoftRegistered( uniformList[ i ].PropertyName ) ) + { + newItems.Add( uniformList[ i ] ); + } + } + return newItems; + } + + public void FillUniforms( TemplateDataCollector mainTemplateDataCollector ) + { + if( m_currentDataCollector.IsSRP ) + { + + if( m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules.SRPBatcherTag.IsValid ) + { + List<PropertyDataCollector> finalList = CrossCheckSoftRegisteredUniformList( mainTemplateDataCollector.SrpBatcherPropertiesList ); + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleSRPBatcher, m_subShaderIdx, m_passIdx, finalList ); + finalList.Clear(); + finalList = null; + } + else + { + List<PropertyDataCollector> finalList = CrossCheckSoftRegisteredUniformList( mainTemplateDataCollector.FullSrpBatcherPropertiesList ); + m_currentDataCollector.UniformsList.AddRange( finalList ); + finalList.Clear(); + finalList = null; + } + } + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleGlobals, m_subShaderIdx, m_passIdx, m_currentDataCollector.UniformsList ); + } + + void SetHDInfoOnPass() + { +#if UNITY_2019_3_OR_NEWER + if( ASEPackageManagerHelper.CurrentHDVersion > ASESRPVersions.ASE_SRP_6_9_1 ) + return; +#endif + + if( m_currentDataCollector.TemplateDataCollectorInstance.CurrentSRPType == TemplateSRPType.HD ) + { + TemplateModulesHelper subShaderHelper = null; + TemplateModulesHelper passHelper = null; + + if( m_isMainOutputNode ) + { + subShaderHelper = m_subShaderModule; + passHelper = m_passModule; + } + else + { + TemplateMultiPassMasterNode masterNode = m_containerGraph.CurrentMasterNode as TemplateMultiPassMasterNode; + if( masterNode != null ) + { + subShaderHelper = masterNode.SubShaderModule; + passHelper = masterNode.PassModule; + } + else + { + subShaderHelper = m_subShaderModule; + passHelper = m_passModule; + } + } + + RenderQueue renderQueue = RenderQueue.Geometry; + RenderType renderType = RenderType.Opaque; + if( passHelper.TagsHelper.HasRenderInfo( ref renderType, ref renderQueue ) || + subShaderHelper.TagsHelper.HasRenderInfo( ref renderType, ref renderQueue ) ) + { + if( renderType == RenderType.Transparent && renderQueue == RenderQueue.Transparent ) + { + SetExtraDefine( SRPMaterialTransparentKeyword ); + //m_currentDataCollector.AddToDefines( UniqueId, SRPMaterialTransparentKeyword ); + TemplatesBlendModule blendOpHelper = passHelper.BlendOpHelper.ValidBlendMode ? passHelper.BlendOpHelper : subShaderHelper.BlendOpHelper; + if( blendOpHelper.IsAdditiveRGB ) + { + SetExtraDefine( SRPMaterialBlendModeAddKeyword ); + //m_currentDataCollector.AddToDefines( UniqueId, SRPMaterialBlendModeAddKeyword ); + } + else if( blendOpHelper.IsAlphaBlendRGB ) + { + SetExtraDefine( SRPMaterialBlendModeAlphaKeyword ); + //m_currentDataCollector.AddToDefines( UniqueId, SRPMaterialBlendModeAlphaKeyword ); + } + } + } + } + } + + void SetLinkedModuleData( TemplateModulesHelper linkedModule ) + { + //if( linkedModule.AdditionalPragmas.ValidData ) + //{ + // linkedModule.AdditionalPragmas.AddToDataCollector( ref m_currentDataCollector, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules.IncludePragmaContainer ); + //} + + //if( linkedModule.AdditionalIncludes.ValidData ) + //{ + // linkedModule.AdditionalIncludes.AddToDataCollector( ref m_currentDataCollector, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules.IncludePragmaContainer ); + //} + + //if( linkedModule.AdditionalDefines.ValidData ) + //{ + // linkedModule.AdditionalDefines.AddToDataCollector( ref m_currentDataCollector, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules.IncludePragmaContainer ); + //} + + if( linkedModule.AdditionalDirectives.ValidData ) + { + linkedModule.AdditionalDirectives.AddAllToDataCollector( ref m_currentDataCollector, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules.IncludePragmaContainer ); + } + } + + void SetModuleData( TemplateModulesHelper module, bool isSubShader ) + { + if( isSubShader ) + { + + //if ( module.AdditionalPragmas.ValidData ) + //{ + // module.AdditionalPragmas.AddToDataCollector( ref m_currentDataCollector, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Modules.IncludePragmaContainer ); + //} + + //if ( module.AdditionalIncludes.ValidData ) + //{ + // module.AdditionalIncludes.AddToDataCollector( ref m_currentDataCollector, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Modules.IncludePragmaContainer ); + //} + + //if ( module.AdditionalDefines.ValidData ) + //{ + // module.AdditionalDefines.AddToDataCollector( ref m_currentDataCollector, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Modules.IncludePragmaContainer ); + //} + + if( module.AdditionalDirectives.ValidData ) + { + module.AdditionalDirectives.AddAllToDataCollector( ref m_currentDataCollector, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Modules.IncludePragmaContainer ); + } + + if( module.TagsHelper.ValidData ) + { + m_templateMultiPass.SetSubShaderData( TemplateModuleDataType.ModuleTag, m_subShaderIdx, module.TagsHelper.GenerateTags() ); + } + + if( module.AllModulesMode ) + { + string body = module.GenerateAllModulesString( isSubShader ); + m_templateMultiPass.SetSubShaderData( TemplateModuleDataType.AllModules, m_subShaderIdx, body.Split( '\n' ) ); + } + + if( module.ShaderModelHelper.ValidAndIndependent ) + { + m_templateMultiPass.SetSubShaderData( TemplateModuleDataType.ModuleShaderModel, m_subShaderIdx, module.ShaderModelHelper.GenerateShaderData( isSubShader ) ); + } + + if( module.BlendOpHelper.IndependentModule && module.BlendOpHelper.ValidBlendMode ) + { + m_templateMultiPass.SetSubShaderData( TemplateModuleDataType.ModuleBlendMode, m_subShaderIdx, module.BlendOpHelper.CurrentBlendFactor ); + } + + if( module.BlendOpHelper.IndependentModule && module.BlendOpHelper.ValidBlendOp ) + { + m_templateMultiPass.SetSubShaderData( TemplateModuleDataType.ModuleBlendOp, m_subShaderIdx, module.BlendOpHelper.CurrentBlendOp ); + } + + if( module.BlendOpHelper.AlphaToMaskIndependent && module.BlendOpHelper.ValidAlphaToMask ) + { + m_templateMultiPass.SetSubShaderData( TemplateModuleDataType.ModuleAlphaToMask, m_subShaderIdx, module.BlendOpHelper.CurrentAlphaToMask ); + } + + if( module.CullModeHelper.ValidAndIndependent ) + { + m_templateMultiPass.SetSubShaderData( TemplateModuleDataType.ModuleCullMode, m_subShaderIdx, module.CullModeHelper.GenerateShaderData( isSubShader ) ); + } + + if( module.ColorMaskHelper.ValidAndIndependent ) + { + m_templateMultiPass.SetSubShaderData( TemplateModuleDataType.ModuleColorMask, m_subShaderIdx, module.ColorMaskHelper.GenerateShaderData( isSubShader ) ); + } + + if( module.DepthOphelper.IndependentModule && module.DepthOphelper.ValidZTest ) + { + m_templateMultiPass.SetSubShaderData( TemplateModuleDataType.ModuleZTest, m_subShaderIdx, module.DepthOphelper.CurrentZTestMode ); + } + + if( module.DepthOphelper.IndependentModule && module.DepthOphelper.ValidZWrite ) + { + m_templateMultiPass.SetSubShaderData( TemplateModuleDataType.ModuleZwrite, m_subShaderIdx, module.DepthOphelper.CurrentZWriteMode ); + } + + if( module.DepthOphelper.IndependentModule && module.DepthOphelper.ValidOffset ) + { + m_templateMultiPass.SetSubShaderData( TemplateModuleDataType.ModuleZOffset, m_subShaderIdx, module.DepthOphelper.CurrentOffset ); + } + + if( module.StencilBufferHelper.ValidAndIndependent ) + { + CullMode cullMode = ( module.CullModeHelper.ValidData ) ? module.CullModeHelper.CurrentCullMode : CullMode.Back; + string value = module.StencilBufferHelper.CreateStencilOp( cullMode ); + m_templateMultiPass.SetSubShaderData( TemplateModuleDataType.ModuleStencil, m_subShaderIdx, value.Split( '\n' ) ); + } + + } + else + { + //if ( module.AdditionalPragmas.ValidData ) + //{ + // module.AdditionalPragmas.AddToDataCollector( ref m_currentDataCollector, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules.IncludePragmaContainer ); + //} + + //if ( module.AdditionalIncludes.ValidData ) + //{ + // module.AdditionalIncludes.AddToDataCollector( ref m_currentDataCollector, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules.IncludePragmaContainer ); + //} + + //if ( module.AdditionalDefines.ValidData ) + //{ + // module.AdditionalDefines.AddToDataCollector( ref m_currentDataCollector, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules.IncludePragmaContainer ); + //} + List<PropertyDataCollector> aboveUsePass = new List<PropertyDataCollector>(); + List<PropertyDataCollector> belowUsePass = new List<PropertyDataCollector>(); + m_usePass.BuildUsePassInfo( m_currentDataCollector, ref aboveUsePass, ref belowUsePass ); + //TODO Must place this on the correct place + aboveUsePass.AddRange( belowUsePass ); + + //adding grab pass after use pass on purpose, so it wont be caught by them + aboveUsePass.AddRange( m_currentDataCollector.GrabPassList ); + + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModulePass, m_subShaderIdx, m_passIdx, aboveUsePass ); + //m_templateMultiPass.SetPassData( TemplateModuleDataType.EndPass, m_subShaderIdx, m_passIdx, bellowUsePass); + + if( module.AdditionalDirectives.ValidData ) + { + module.AdditionalDirectives.AddAllToDataCollector( ref m_currentDataCollector, m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules.IncludePragmaContainer ); + } + + if( module.TagsHelper.ValidData ) + { + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleTag, m_subShaderIdx, m_passIdx, module.TagsHelper.GenerateTags() ); + } + + if( module.AllModulesMode ) + { + string body = module.GenerateAllModulesString( isSubShader ); + m_templateMultiPass.SetPassData( TemplateModuleDataType.AllModules, m_subShaderIdx, m_passIdx, body.Split( '\n' ) ); + } + + if( module.ShaderModelHelper.ValidAndIndependent ) + { + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleShaderModel, m_subShaderIdx, m_passIdx, module.ShaderModelHelper.GenerateShaderData( isSubShader ) ); + } + + if( module.BlendOpHelper.IndependentModule && module.BlendOpHelper.ValidBlendMode ) + { + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleBlendMode, m_subShaderIdx, m_passIdx, module.BlendOpHelper.CurrentBlendFactor ); + } + + if( module.BlendOpHelper.IndependentModule && module.BlendOpHelper.ValidBlendOp ) + { + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleBlendOp, m_subShaderIdx, m_passIdx, module.BlendOpHelper.CurrentBlendOp ); + } + + if( module.BlendOpHelper.AlphaToMaskIndependent && module.BlendOpHelper.ValidAlphaToMask ) + { + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleAlphaToMask, m_subShaderIdx, m_passIdx, module.BlendOpHelper.CurrentAlphaToMask ); + } + + if( module.CullModeHelper.ValidAndIndependent ) + { + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleCullMode, m_subShaderIdx, m_passIdx, module.CullModeHelper.GenerateShaderData( isSubShader ) ); + } + + if( module.ColorMaskHelper.ValidAndIndependent ) + { + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleColorMask, m_subShaderIdx, m_passIdx, module.ColorMaskHelper.GenerateShaderData( isSubShader ) ); + } + + if( module.DepthOphelper.IndependentModule && module.DepthOphelper.ValidZTest ) + { + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleZTest, m_subShaderIdx, m_passIdx, module.DepthOphelper.CurrentZTestMode ); + } + + if( module.DepthOphelper.IndependentModule && module.DepthOphelper.ValidZWrite ) + { + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleZwrite, m_subShaderIdx, m_passIdx, module.DepthOphelper.CurrentZWriteMode ); + } + + if( module.DepthOphelper.IndependentModule && module.DepthOphelper.ValidOffset ) + { + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleZOffset, m_subShaderIdx, m_passIdx, module.DepthOphelper.CurrentOffset ); + } + + if( module.StencilBufferHelper.ValidAndIndependent ) + { + CullMode cullMode = ( module.CullModeHelper.ValidData ) ? module.CullModeHelper.CurrentCullMode : CullMode.Back; + string value = module.StencilBufferHelper.CreateStencilOp( cullMode ); + m_templateMultiPass.SetPassData( TemplateModuleDataType.ModuleStencil, m_subShaderIdx, m_passIdx, value.Split( '\n' ) ); + } + } + } + + public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar ) + { + return "0"; + } + + public override void Destroy() + { + base.Destroy(); + + m_drawInstancedHelper = null; + + m_optionsDefineContainer.Destroy(); + m_optionsDefineContainer = null; + + m_passSelector.Destroy(); + m_passSelector = null; + + m_subShaderOptions.Destroy(); + m_passOptions.Destroy(); + + m_fallbackHelper.Destroy(); + GameObject.DestroyImmediate( m_fallbackHelper ); + m_fallbackHelper = null; + + m_usePass.Destroy(); + GameObject.DestroyImmediate( m_usePass ); + m_usePass = null; + + m_dependenciesHelper.Destroy(); + m_dependenciesHelper = null; + + m_subShaderModule.Destroy(); + m_subShaderModule = null; + m_passModule.Destroy(); + m_passModule = null; + if( m_lodIndex == -1 ) + { + ContainerGraph.MultiPassMasterNodes.RemoveNode( this ); + } + else + { + ContainerGraph.LodMultiPassMasternodes[ m_lodIndex ].RemoveNode( this ); + } + } + + void UpdateSubShaderPassStr() + { + //m_subShaderIdxStr = SubShaderModuleStr + m_templateMultiPass.SubShaders[ m_subShaderIdx ].Idx; + //m_passIdxStr = PassModuleStr + m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Idx; + } + + public override void ReadFromString( ref string[] nodeParams ) + { + + base.ReadFromString( ref nodeParams ); + try + { + string currShaderName = GetCurrentParam( ref nodeParams ); + if( currShaderName.Length > 0 ) + currShaderName = UIUtils.RemoveShaderInvalidCharacters( currShaderName ); + + m_templateGUID = GetCurrentParam( ref nodeParams ); + bool hasUniqueName = false; + if( UIUtils.CurrentShaderVersion() > PASS_UNIQUE_ID_VERSION ) + { + hasUniqueName = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) ); + } + + if( hasUniqueName ) + m_passUniqueId = GetCurrentParam( ref nodeParams ); + + m_subShaderIdx = Convert.ToInt32( GetCurrentParam( ref nodeParams ) ); + m_passIdx = Convert.ToInt32( GetCurrentParam( ref nodeParams ) ); + if( UIUtils.CurrentShaderVersion() > LOD_SUBSHADER_VERSION ) + { + + if( m_lodIndex != -1 ) + { + m_containerGraph.MultiPassMasterNodes.RemoveNode( this ); + m_containerGraph.LodMultiPassMasternodes[ m_lodIndex ].AddNode( this ); + } + } + + m_passName = GetCurrentParam( ref nodeParams ); + SetTemplate( null, false, true, m_subShaderIdx, m_passIdx, SetTemplateSource.ShaderLoad ); + ////If value gotten from template is > -1 then it contains the LOD field + ////and we can properly write the value + //if( m_subShaderLOD > -1 ) + //{ + // m_subShaderLOD = subShaderLOD; + //} + + // only in here, after SetTemplate, we know if shader name is to be used as title or not + ShaderName = currShaderName; + m_visiblePorts = Convert.ToInt32( GetCurrentParam( ref nodeParams ) ); + m_subShaderModule.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + m_passModule.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + if( UIUtils.CurrentShaderVersion() > 15308 ) + { + m_fallbackHelper.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + m_dependenciesHelper.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + if( UIUtils.CurrentShaderVersion() > 15402 ) + { + m_usePass.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + if( UIUtils.CurrentShaderVersion() > 15409 ) + { + m_hdSrpMaterialType = (HDSRPMaterialType)Enum.Parse( typeof( HDSRPMaterialType ), GetCurrentParam( ref nodeParams ) ); + } + + if( UIUtils.CurrentShaderVersion() > 15501 ) + { + if( m_isMainOutputNode && UIUtils.CurrentShaderVersion() > PASS_SELECTOR_VERSION ) + m_subShaderOptions.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + + m_passOptions.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + if( m_isMainOutputNode && UIUtils.CurrentShaderVersion() > PASS_SELECTOR_VERSION ) + { + m_passSelector.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + if( m_isMainOutputNode && UIUtils.CurrentShaderVersion() > 16203 ) + { + m_drawInstancedHelper.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + if( m_isMainOutputNode && UIUtils.CurrentShaderVersion() > LOD_SUBSHADER_VERSION ) + { + m_mainLODName = GetCurrentParam( ref nodeParams ); + SetupLODNodeName(); + } + else + { + m_content.text = GenerateClippedTitle( m_passName ); + } + + + //if( m_templateMultiPass != null && !m_templateMultiPass.IsSinglePass ) + //{ + // SetClippedTitle( m_passName ); + //} + } + catch( Exception e ) + { + Debug.LogException( e, this ); + } + + m_containerGraph.CurrentCanvasMode = NodeAvailability.TemplateShader; + m_containerGraph.CurrentPrecision = m_currentPrecisionType; + } + + public override void WriteToString( ref string nodeInfo, ref string connectionsInfo ) + { + base.WriteToString( ref nodeInfo, ref connectionsInfo ); + IOUtils.AddFieldValueToString( ref nodeInfo, ShaderName ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_templateGUID ); + + bool hasUniquePassName = Pass.Modules.HasPassUniqueName; + IOUtils.AddFieldValueToString( ref nodeInfo, hasUniquePassName ); + if( hasUniquePassName ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, Pass.Modules.PassUniqueName ); + } + + IOUtils.AddFieldValueToString( ref nodeInfo, m_subShaderIdx ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_passIdx ); + + IOUtils.AddFieldValueToString( ref nodeInfo, m_passName ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_visiblePorts ); + m_subShaderModule.WriteToString( ref nodeInfo ); + m_passModule.WriteToString( ref nodeInfo ); + m_fallbackHelper.WriteToString( ref nodeInfo ); + m_dependenciesHelper.WriteToString( ref nodeInfo ); + m_usePass.WriteToString( ref nodeInfo ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_hdSrpMaterialType ); + if( m_isMainOutputNode ) + m_subShaderOptions.WriteToString( ref nodeInfo ); + + m_passOptions.WriteToString( ref nodeInfo ); + + if( m_isMainOutputNode ) + { + m_passSelector.WriteToString( ref nodeInfo ); + m_drawInstancedHelper.WriteToString( ref nodeInfo ); + } + + if( m_isMainOutputNode ) + IOUtils.AddFieldValueToString( ref nodeInfo, m_mainLODName ); + + } + + public override void ReadFromDeprecated( ref string[] nodeParams, Type oldType = null ) + { + base.ReadFromString( ref nodeParams ); + try + { + string currShaderName = GetCurrentParam( ref nodeParams ); + if( currShaderName.Length > 0 ) + currShaderName = UIUtils.RemoveShaderInvalidCharacters( currShaderName ); + + string templateGUID = GetCurrentParam( ref nodeParams ); + string templateShaderName = string.Empty; + if( UIUtils.CurrentShaderVersion() > 13601 ) + { + templateShaderName = GetCurrentParam( ref nodeParams ); + } + + TemplateMultiPass template = m_containerGraph.ParentWindow.TemplatesManagerInstance.GetTemplate( templateGUID ) as TemplateMultiPass; + if( template != null ) + { + m_templateGUID = templateGUID; + SetTemplate( null, false, true, 0, 0,SetTemplateSource.ShaderLoad ); + } + else + { + template = m_containerGraph.ParentWindow.TemplatesManagerInstance.GetTemplateByName( templateShaderName ) as TemplateMultiPass; + if( template != null ) + { + m_templateGUID = template.GUID; + SetTemplate( null, false, true, 0, 0, SetTemplateSource.ShaderLoad ); + } + else + { + m_masterNodeCategory = -1; + } + } + + if( m_invalidNode ) + return; + + // only in here, after SetTemplate, we know if shader name is to be used as title or not + ShaderName = currShaderName; + if( UIUtils.CurrentShaderVersion() > 13902 ) + { + + //BLEND MODULE + if( m_templateMultiPass.SubShaders[ 0 ].Modules.BlendData.ValidBlendMode ) + { + m_subShaderModule.BlendOpHelper.ReadBlendModeFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + else if( m_templateMultiPass.SubShaders[ 0 ].Passes[ 0 ].Modules.BlendData.ValidBlendMode ) + { + m_passModule.BlendOpHelper.ReadBlendModeFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + if( m_templateMultiPass.SubShaders[ 0 ].Modules.BlendData.ValidBlendOp ) + { + m_subShaderModule.BlendOpHelper.ReadBlendOpFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + else if( m_templateMultiPass.SubShaders[ 0 ].Passes[ 0 ].Modules.BlendData.ValidBlendOp ) + { + m_passModule.BlendOpHelper.ReadBlendOpFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + + //CULL MODE + if( m_templateMultiPass.SubShaders[ 0 ].Modules.CullModeData.DataCheck == TemplateDataCheck.Valid ) + { + m_subShaderModule.CullModeHelper.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + else if( m_templateMultiPass.SubShaders[ 0 ].Passes[ 0 ].Modules.CullModeData.DataCheck == TemplateDataCheck.Valid ) + { + m_passModule.CullModeHelper.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + //COLOR MASK + if( m_templateMultiPass.SubShaders[ 0 ].Modules.ColorMaskData.DataCheck == TemplateDataCheck.Valid ) + { + m_subShaderModule.ColorMaskHelper.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + else if( m_templateMultiPass.SubShaders[ 0 ].Passes[ 0 ].Modules.ColorMaskData.DataCheck == TemplateDataCheck.Valid ) + { + m_passModule.ColorMaskHelper.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + //STENCIL BUFFER + if( m_templateMultiPass.SubShaders[ 0 ].Modules.StencilData.DataCheck == TemplateDataCheck.Valid ) + { + m_subShaderModule.StencilBufferHelper.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + else if( m_templateMultiPass.SubShaders[ 0 ].Passes[ 0 ].Modules.StencilData.DataCheck == TemplateDataCheck.Valid ) + { + m_passModule.StencilBufferHelper.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + } + + if( UIUtils.CurrentShaderVersion() > 14202 ) + { + //DEPTH OPTIONS + if( m_templateMultiPass.SubShaders[ 0 ].Modules.DepthData.ValidZWrite ) + { + m_subShaderModule.DepthOphelper.ReadZWriteFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + else if( m_templateMultiPass.SubShaders[ 0 ].Passes[ 0 ].Modules.DepthData.ValidZWrite ) + { + m_passModule.DepthOphelper.ReadZWriteFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + if( m_templateMultiPass.SubShaders[ 0 ].Modules.DepthData.ValidZTest ) + { + m_subShaderModule.DepthOphelper.ReadZTestFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + else if( m_templateMultiPass.SubShaders[ 0 ].Passes[ 0 ].Modules.DepthData.ValidZTest ) + { + m_subShaderModule.DepthOphelper.ReadZTestFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + if( m_templateMultiPass.SubShaders[ 0 ].Modules.DepthData.ValidOffset ) + { + m_subShaderModule.DepthOphelper.ReadOffsetFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + else if( m_templateMultiPass.SubShaders[ 0 ].Passes[ 0 ].Modules.DepthData.ValidOffset ) + { + m_passModule.DepthOphelper.ReadOffsetFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + } + + //TAGS + if( UIUtils.CurrentShaderVersion() > 14301 ) + { + if( m_templateMultiPass.SubShaders[ 0 ].Modules.TagData.DataCheck == TemplateDataCheck.Valid ) + { + m_subShaderModule.TagsHelper.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + else if( m_templateMultiPass.SubShaders[ 0 ].Passes[ 0 ].Modules.TagData.DataCheck == TemplateDataCheck.Valid ) + { + m_passModule.TagsHelper.ReadFromString( ref m_currentReadParamIdx, ref nodeParams ); + } + + } + } + catch( Exception e ) + { + Debug.LogException( e, this ); + } + m_containerGraph.CurrentCanvasMode = NodeAvailability.TemplateShader; + } + + public void ForceOptionsRefresh() + { + m_passOptions.Refresh(); + if( m_isMainOutputNode ) + m_subShaderOptions.Refresh(); + } + + public void SetPassVisible( string passName, bool visible ) + { + TemplateMultiPassMasterNode node = m_containerGraph.GetMasterNodeOfPass( passName, m_lodIndex ); + if( node != null ) + { + m_passSelector.SetPassVisible( passName, visible ); + node.IsInvisible = !visible; + } + + } + + public override void RefreshExternalReferences() + { + if( m_invalidNode ) + return; + + base.RefreshExternalReferences(); + if( IsLODMainMasterNode ) + { + SetMasterNodeCategoryFromGUID( m_templateGUID ); + } + + CheckTemplateChanges(); + if( m_templateMultiPass != null && m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].Modules.SRPIsPBRHD && UIUtils.CurrentShaderVersion() < 15410 ) + { + FetchHDPorts(); + m_hdSrpMaterialType = ( m_specularPort != null && m_specularPort.HasOwnOrLinkConnection ) ? HDSRPMaterialType.Specular : HDSRPMaterialType.Standard; + ConfigHDPorts(); + } + + if( ContainerGraph.HasLODs ) + { + SetClippedAdditionalTitle( string.Format( LodSubtitle, ShaderLOD ) ); + } + + if( m_isMainOutputNode ) + { + List<TemplateMultiPassMasterNode> masterNodes = ( m_lodIndex == -1 ) ? m_containerGraph.MultiPassMasterNodes.NodesList : m_containerGraph.LodMultiPassMasternodes[ m_lodIndex ].NodesList; + masterNodes.Sort( ( x, y ) => ( x.PassIdx.CompareTo( y.PassIdx ) )); + int passAmount = m_templateMultiPass.SubShaders[ m_subShaderIdx ].PassAmount; + if( passAmount != masterNodes.Count ) + { + UIUtils.ShowMessage( "Template master nodes amount was modified. Could not set correctly its visibility options." ); + } + else + { + for( int i = 0; i < passAmount; i++ ) + { + if( i != m_passIdx ) + { + masterNodes[ i ].IsInvisible = !m_passSelector.IsVisible( i ); + } + } + } + } + } + + public override void ReadInputDataFromString( ref string[] nodeParams ) + { + //For a Template Master Node an input port data must be set by its template and not meta data + if( UIUtils.CurrentShaderVersion() > 17007 ) + return; + + int count = 0; + if( UIUtils.CurrentShaderVersion() > 7003 ) + { + try + { + count = Convert.ToInt32( nodeParams[ m_currentReadParamIdx++ ] ); + } + catch( Exception e ) + { + Debug.LogException( e ); + } + } + else + { + count = ( m_oldInputCount < 0 ) ? m_inputPorts.Count : m_oldInputCount; + } + + for( int i = 0; i < count && i < nodeParams.Length && m_currentReadParamIdx < nodeParams.Length; i++ ) + { + if( UIUtils.CurrentShaderVersion() < 5003 ) + { + int newId = VersionConvertInputPortId( i ); + if( UIUtils.CurrentShaderVersion() > 23 ) + { + m_currentReadParamIdx++; + } + + m_currentReadParamIdx++; + if( m_inputPorts[ newId ].IsEditable && UIUtils.CurrentShaderVersion() >= 3100 && m_currentReadParamIdx < nodeParams.Length ) + { + m_currentReadParamIdx++; + } + } + else + { + m_currentReadParamIdx++; + m_currentReadParamIdx++; + m_currentReadParamIdx++; + bool isEditable = Convert.ToBoolean( nodeParams[ m_currentReadParamIdx++ ] ); + if( isEditable && m_currentReadParamIdx < nodeParams.Length ) + { + m_currentReadParamIdx++; + } + } + } + } + + //For a Template Master Node an input port data must be set by its template and not meta data + public override void WriteInputDataToString( ref string nodeInfo ) { } + + public override float HeightEstimate + { + get + { + float heightEstimate = 0; + heightEstimate = 32 + Constants.INPUT_PORT_DELTA_Y; + if( m_templateMultiPass != null && !m_templateMultiPass.IsSinglePass ) + { + heightEstimate += 22; + } + float internalPortSize = 0; + for( int i = 0; i < InputPorts.Count; i++ ) + { + if( InputPorts[ i ].Visible ) + internalPortSize += 18 + Constants.INPUT_PORT_DELTA_Y; + } + + return heightEstimate + Mathf.Max( internalPortSize, m_insideSize.y ); + } + } + + public HDSRPMaterialType CurrentHDMaterialType + { + get { return m_hdSrpMaterialType; } + set + { + m_hdSrpMaterialType = value; + if( m_isMainOutputNode ) + { + List<TemplateMultiPassMasterNode> mpNodes = UIUtils.CurrentWindow.CurrentGraph.MultiPassMasterNodes.NodesList; + int count = mpNodes.Count; + for( int i = 0; i < count; i++ ) + { + if( mpNodes[ i ].UniqueId != UniqueId ) + { + mpNodes[ i ].CurrentHDMaterialType = value; + } + } + } + } + } + public TemplateSubShader SubShader { get { return m_templateMultiPass.SubShaders[ m_subShaderIdx ]; } } + public TemplatePass Pass { get { return m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ]; } } + public int SubShaderIdx { get { return m_subShaderIdx; } } + public int PassIdx { get { return m_passIdx; } } + public TemplateMultiPass CurrentTemplate { get { return m_templateMultiPass; } } + public TemplateModulesHelper SubShaderModule { get { return m_subShaderModule; } } + public TemplateModulesHelper PassModule { get { return m_passModule; } } + public string PassName { get { return m_templateMultiPass.SubShaders[ m_subShaderIdx ].Passes[ m_passIdx ].PassNameContainer.Data; } } + public string PassUniqueName + { + get + { + return string.IsNullOrEmpty( m_passUniqueId ) ? m_originalPassName : m_passUniqueId; + } + } + + public string OriginalPassName { get { return m_originalPassName; } } + public bool HasLinkPorts { get { return m_hasLinkPorts; } } + public bool IsInvisible + { + get + { + return m_isInvisible != InvisibilityStatus.Visible; + } + set + { + if( m_isInvisible != InvisibilityStatus.LockedInvisible && !m_isMainOutputNode ) + { + m_isInvisible = value ? InvisibilityStatus.Invisible : InvisibilityStatus.Visible; + if( value ) + { + for( int i = 0; i < m_inputPorts.Count; i++ ) + { + m_inputPorts[ i ].FullDeleteConnections(); + } + } + } + } + } + + public TemplatePassSelectorHelper PassSelector { get { return m_passSelector; } } + public TemplateOptionsUIHelper PassOptions { get { return m_passOptions; } } + public TemplateOptionsUIHelper SubShaderOptions { get { return m_subShaderOptions; } } + public TemplateOptionsDefinesContainer OptionsDefineContainer { get { return m_optionsDefineContainer; } } + public TerrainDrawInstancedHelper DrawInstancedHelperInstance { get { return m_drawInstancedHelper; } } + public bool InvalidNode { get { return m_invalidNode; } } + public override void SetName( string name ) + { + ShaderName = name; + } + public bool IsLODMainFirstPass { get { return m_passIdx == 0 && m_lodIndex == -1; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPassMasterNode.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPassMasterNode.cs.meta new file mode 100644 index 00000000..a96d88d0 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPassMasterNode.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fce684c26c654d14e927860863cd99dd +timeCreated: 1517406883 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPassSwitchNode.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPassSwitchNode.cs new file mode 100644 index 00000000..e8aeadf8 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPassSwitchNode.cs @@ -0,0 +1,328 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using UnityEngine; +using UnityEditor; +using System; +using System.Collections.Generic; + +namespace AmplifyShaderEditor +{ + + [Serializable] + public class InputSwitchMPHelper + { + public int SubShaderIdx; + public int PassIdx; + public InputSwitchMPHelper( int subShaderIdx, int passIdx ) + { + SubShaderIdx = subShaderIdx; + PassIdx = passIdx; + } + } + + [Serializable] + [NodeAttributes( "Template Multi-Pass Switch", "Logical Operators", "Relays, in compile time, the correct input port according to current analyzed sub-shader/pass." )] + public sealed class TemplateMultiPassSwitchNode : TemplateNodeParent + { + private const string InputLabelStr = "SubShader {0} Pass {1}"; + + [SerializeField] + private List<InputSwitchMPHelper> m_inputHelper = new List<InputSwitchMPHelper>(); + + [SerializeField] + private int m_inputCountHelper = -1; + + protected override void CommonInit( int uniqueId ) + { + m_createAllOutputs = false; + base.CommonInit( uniqueId ); + } + + public override void OnInputPortConnected( int portId, int otherNodeId, int otherPortId, bool activateNode = true ) + { + base.OnInputPortConnected( portId, otherNodeId, otherPortId, activateNode ); + UpdateConnections(); + } + + public override void OnConnectedOutputNodeChanges( int inputPortId, int otherNodeId, int otherPortId, string name, WirePortDataType type ) + { + base.OnConnectedOutputNodeChanges( inputPortId, otherNodeId, otherPortId, name, type ); + UpdateConnections(); + } + + public override void OnInputPortDisconnected( int portId ) + { + base.OnInputPortDisconnected( portId ); + UpdateConnections(); + } + + private void UpdateConnections() + { + WirePortDataType mainType = WirePortDataType.FLOAT; + + int highest = UIUtils.GetPriority( mainType ); + for( int i = 0; i < m_inputPorts.Count; i++ ) + { + if( m_inputPorts[ i ].IsConnected ) + { + WirePortDataType portType = m_inputPorts[ i ].GetOutputConnection().DataType; + if( UIUtils.GetPriority( portType ) > highest ) + { + mainType = portType; + highest = UIUtils.GetPriority( portType ); + } + } + } + + for( int i = 0; i < m_inputPorts.Count; i++ ) + { + m_inputPorts[ i ].ChangeType( mainType, false ); + } + + m_outputPorts[ 0 ].ChangeType( mainType, false ); + } + + public override void Draw( DrawInfo drawInfo ) + { + base.Draw( drawInfo ); + + if( m_templateMPData == null ) + { + FetchMultiPassTemplate(); + if( m_inputPorts.Count != m_inputCountHelper ) + { + CreateInputPorts(); + } + else + { + RefreshInputPorts(); + } + } + } + + + public void RefreshInputPorts() + { + if( m_multiPassMode ) + { + m_inputHelper.Clear(); + if( m_templateMPData != null ) + { + int index = 0; + int subShaderCount = m_templateMPData.SubShaders.Count; + for( int subShaderIdx = 0; subShaderIdx < subShaderCount; subShaderIdx++ ) + { + int passCount = m_templateMPData.SubShaders[ subShaderIdx ].Passes.Count; + for( int passIdx = 0; passIdx < passCount; passIdx++ ) + { + if( m_templateMPData.SubShaders[ subShaderIdx ].Passes[ passIdx ].HasValidFunctionBody ) + { + m_inputPorts[ index ].Name = string.Format( InputLabelStr, subShaderIdx, passIdx ); + m_inputHelper.Add( new InputSwitchMPHelper( subShaderIdx, passIdx ) ); + index += 1; + } + } + } + } + } + else + { + m_inputPorts[0].Name = "In"; + } + } + + public int RefreshInputCountHelper() + { + int inputCountHelper = 0; + if( m_multiPassMode ) + { + if( m_templateMPData != null ) + { + int subShaderCount = m_templateMPData.SubShaders.Count; + for( int subShaderIdx = 0; subShaderIdx < subShaderCount; subShaderIdx++ ) + { + int passCount = m_templateMPData.SubShaders[ subShaderIdx ].Passes.Count; + for( int passIdx = 0; passIdx < passCount; passIdx++ ) + { + if( m_templateMPData.SubShaders[ subShaderIdx ].Passes[passIdx].HasValidFunctionBody ) + inputCountHelper += 1; + } + } + } + } + else + { + inputCountHelper += 1; + } + return inputCountHelper; + } + + public void CreateInputPorts() + { + m_inputCountHelper = 0; + DeleteAllInputConnections( true ); + if( m_multiPassMode ) + { + m_inputHelper.Clear(); + if( m_templateMPData != null ) + { + int subShaderCount = m_templateMPData.SubShaders.Count; + for( int subShaderIdx = 0; subShaderIdx < subShaderCount; subShaderIdx++ ) + { + int passCount = m_templateMPData.SubShaders[ subShaderIdx ].Passes.Count; + for( int passIdx = 0; passIdx < passCount; passIdx++ ) + { + if( m_templateMPData.SubShaders[ subShaderIdx ].Passes[ passIdx ].HasValidFunctionBody ) + { + AddInputPort( WirePortDataType.FLOAT, false, string.Format( InputLabelStr, subShaderIdx, passIdx ) ); + m_inputHelper.Add( new InputSwitchMPHelper( subShaderIdx, passIdx ) ); + m_inputCountHelper += 1; + } + } + } + } + } + else + { + AddInputPort( WirePortDataType.FLOAT, false, "In" ); + m_inputCountHelper += 1; + } + } + + public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar ) + { + if( dataCollector.MasterNodeCategory != AvailableShaderTypes.Template ) + { + UIUtils.ShowMessage( "Template Multi-Pass Switch Data node is only intended for templates use only" ); + return m_outputPorts[ 0 ].ErrorValue; + } + + int currSubShaderIdx = dataCollector.TemplateDataCollectorInstance.MultipassSubshaderIdx; + int currPassIdx = dataCollector.TemplateDataCollectorInstance.MultipassPassIdx; + + int inputHelperCount = m_inputHelper.Count; + for( int i = 0; i< inputHelperCount; i++ ) + { + if(m_inputHelper[i].SubShaderIdx == currSubShaderIdx && m_inputHelper[ i ].PassIdx == currPassIdx ) + return m_inputPorts[ i ].GeneratePortInstructions( ref dataCollector ); + } + + UIUtils.ShowMessage( "Invalid subshader or pass on Template Multi-Pass Switch Data" ); + return m_outputPorts[ 0 ].ErrorValue; + } + + public override void OnMasterNodeReplaced( MasterNode newMasterNode ) + { + base.OnMasterNodeReplaced( newMasterNode ); + if( newMasterNode.CurrentMasterNodeCategory == AvailableShaderTypes.Template ) + { + FetchMultiPassTemplate( newMasterNode ); + m_inputCountHelper = RefreshInputCountHelper(); + if( m_inputPorts.Count != m_inputCountHelper ) + { + CreateInputPorts(); + } + else + { + RefreshInputPorts(); + } + } + else + { + DeleteAllInputConnections( true ); + } + } + + public override void ReadFromString( ref string[] nodeParams ) + { + base.ReadFromString( ref nodeParams ); + m_inputCountHelper = Convert.ToInt32( GetCurrentParam( ref nodeParams ) ); + // Need to add ports here so read internal data is correct + for( int i = 0; i < m_inputCountHelper; i++ ) + { + AddInputPort( WirePortDataType.FLOAT, false, Constants.EmptyPortValue ); + } + } + + public override void WriteToString( ref string nodeInfo, ref string connectionsInfo ) + { + base.WriteToString( ref nodeInfo, ref connectionsInfo ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_inputCountHelper ); + } + + public override void Destroy() + { + base.Destroy(); + m_inputHelper.Clear(); + m_inputHelper = null; + } + + public override void RefreshExternalReferences() + { + base.RefreshExternalReferences(); + FetchMultiPassTemplate(); + + bool create = false; + if( m_inputCountHelper == -1 ) + { + create = true; + } + else + { + int newInputCount = RefreshInputCountHelper(); + if( newInputCount != m_inputCountHelper ) + { + create = true; + } + } + + + if( m_multiPassMode ) + { + if( m_templateMPData != null ) + { + if( create ) + { + CreateInputPorts(); + } + else + { + m_inputHelper.Clear(); + int index = 0; + int subShaderCount = m_templateMPData.SubShaders.Count; + for( int subShaderIdx = 0; subShaderIdx < subShaderCount; subShaderIdx++ ) + { + int passCount = m_templateMPData.SubShaders[ subShaderIdx ].Passes.Count; + for( int passIdx = 0; passIdx < passCount; passIdx++ ) + { + if( m_templateMPData.SubShaders[ subShaderIdx ].Passes[ passIdx ].HasValidFunctionBody ) + { + m_inputPorts[ index ].Name = string.Format( InputLabelStr, subShaderIdx, passIdx ); + m_inputHelper.Add( new InputSwitchMPHelper( subShaderIdx, passIdx )); + index += 1; + } + } + } + + if( index != m_inputCountHelper ) + { + Debug.LogWarning( "Something wrong occured in reading MultiPass Switch node" ); + } + } + } + } + else + { + if( create ) + { + AddInputPort( WirePortDataType.FLOAT, false, "In" ); + } + else + { + m_inputPorts[ 0 ].Name = "In"; + } + } + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPassSwitchNode.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPassSwitchNode.cs.meta new file mode 100644 index 00000000..4aafb59d --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateMultiPassSwitchNode.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 58e4eb5fc3fed124384eef956c6c3ee1 +timeCreated: 1519319737 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateNodeParent.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateNodeParent.cs new file mode 100644 index 00000000..1bfc8aa9 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateNodeParent.cs @@ -0,0 +1,272 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateNodeParent : ParentNode + { + + + protected const string ErrorMessageStr = "This node can only be used inside a Template category!"; + protected const string DataLabelStr = "Data"; + protected const string SubShaderStr = "SubShader"; + protected const string PassStr = "Pass"; + + [SerializeField] + private int m_subShaderIdx = 0; + + [SerializeField] + private int m_passIdx = 0; + + [SerializeField] + private int m_passLocalArrayIdx = 0; + + [SerializeField] + protected bool m_multiPassMode = false; + + [SerializeField] + protected string[] m_availableSubshaders; + + [SerializeField] + protected string[] m_availablePassesLabels; + + [SerializeField] + protected int[] m_availablePassesValues; + + [NonSerialized] + protected TemplateMultiPass m_templateMPData = null; + protected bool m_createAllOutputs = true; + + protected override void CommonInit( int uniqueId ) + { + base.CommonInit( uniqueId ); + AddOutputPort( WirePortDataType.FLOAT, "Out" ); + if( m_createAllOutputs ) + { + AddOutputPort( WirePortDataType.FLOAT, "X" ); + AddOutputPort( WirePortDataType.FLOAT, "Y" ); + AddOutputPort( WirePortDataType.FLOAT, "Z" ); + AddOutputPort( WirePortDataType.FLOAT, "W" ); + } + m_textLabelWidth = 67; + m_hasLeftDropdown = true; + } + + public override void AfterCommonInit() + { + base.AfterCommonInit(); + + if( PaddingTitleLeft == 0 ) + { + PaddingTitleLeft = Constants.PropertyPickerWidth + Constants.IconsLeftRightMargin; + if( PaddingTitleRight == 0 ) + PaddingTitleRight = Constants.PropertyPickerWidth + Constants.IconsLeftRightMargin; + } + } + + protected void ConfigurePorts() + { + switch( m_outputPorts[ 0 ].DataType ) + { + default: + { + for( int i = 1; i < 5; i++ ) + { + m_outputPorts[ i ].Visible = false; + } + } + break; + case WirePortDataType.FLOAT2: + { + for( int i = 1; i < 5; i++ ) + { + m_outputPorts[ i ].Visible = ( i < 3 ); + if( m_outputPorts[ i ].Visible ) + { + m_outputPorts[ i ].Name = Constants.ChannelNamesVector[ i - 1 ]; + } + } + } + break; + case WirePortDataType.FLOAT3: + { + for( int i = 1; i < 5; i++ ) + { + m_outputPorts[ i ].Visible = ( i < 4 ); + if( m_outputPorts[ i ].Visible ) + { + m_outputPorts[ i ].Name = Constants.ChannelNamesVector[ i - 1 ]; + } + } + } + break; + case WirePortDataType.FLOAT4: + { + for( int i = 1; i < 5; i++ ) + { + m_outputPorts[ i ].Visible = true; + m_outputPorts[ i ].Name = Constants.ChannelNamesVector[ i - 1 ]; + } + } + break; + case WirePortDataType.COLOR: + { + for( int i = 1; i < 5; i++ ) + { + m_outputPorts[ i ].Visible = true; + m_outputPorts[ i ].Name = Constants.ChannelNamesColor[ i - 1 ]; + } + } + break; + } + m_sizeIsDirty = true; + } + + protected virtual void OnSubShaderChange() { } + protected virtual void OnPassChange() { } + + protected void DrawSubShaderUI() + { + EditorGUI.BeginChangeCheck(); + m_subShaderIdx = EditorGUILayoutPopup( SubShaderStr, m_subShaderIdx, m_availableSubshaders ); + if( EditorGUI.EndChangeCheck() ) + { + //UpdateSubShaderAmount(); + UpdatePassAmount(); + OnSubShaderChange(); + } + } + + protected void DrawPassUI() + { + EditorGUI.BeginChangeCheck(); + m_passLocalArrayIdx = EditorGUILayoutPopup( PassStr, m_passLocalArrayIdx, m_availablePassesLabels ); + if( EditorGUI.EndChangeCheck() ) + { + m_passIdx = m_availablePassesValues[ m_passLocalArrayIdx ]; + //UpdatePassAmount(); + OnPassChange(); + } + } + + virtual protected void CheckWarningState() + { + if( m_containerGraph.CurrentCanvasMode != NodeAvailability.TemplateShader ) + { + ShowTab( NodeMessageType.Error, ErrorMessageStr ); + } + else + { + m_showErrorMessage = false; + } + } + + protected void FetchMultiPassTemplate( MasterNode masterNode = null ) + { + m_multiPassMode = m_containerGraph.MultiPassMasterNodes.NodesList.Count > 0; + if( m_multiPassMode ) + { + m_templateMPData = ( ( ( masterNode == null ) ? m_containerGraph.CurrentMasterNode : masterNode ) as TemplateMultiPassMasterNode ).CurrentTemplate; + if( m_templateMPData != null ) + { + UpdateSubShaderAmount(); + } + } + } + + protected void UpdateSubShaderAmount() + { + if( m_templateMPData == null ) + m_templateMPData = ( m_containerGraph.CurrentMasterNode as TemplateMultiPassMasterNode ).CurrentTemplate; + + if( m_templateMPData != null ) + { + int subShaderCount = m_templateMPData.SubShaders.Count; + if( m_availableSubshaders == null || subShaderCount != m_availableSubshaders.Length ) + { + m_availableSubshaders = new string[ subShaderCount ]; + for( int i = 0; i < subShaderCount; i++ ) + { + m_availableSubshaders[ i ] = i.ToString(); + } + } + m_subShaderIdx = Mathf.Min( m_subShaderIdx, subShaderCount - 1 ); + UpdatePassAmount(); + } + } + protected virtual bool ValidatePass( int passIdx ) { return true; } + protected void UpdatePassAmount() + { + if( !m_multiPassMode ) + return; + + if( m_templateMPData == null ) + m_templateMPData = ( m_containerGraph.CurrentMasterNode as TemplateMultiPassMasterNode ).CurrentTemplate; + + List<string> passLabels = new List<string>(); + List<int> passValues = new List<int>(); + int minPassIdx = int.MaxValue; + int passCount = m_templateMPData.SubShaders[ m_subShaderIdx ].Passes.Count; + bool resetPassIdx = true; + for( int i = 0; i < passCount; i++ ) + { + if( ValidatePass( i ) ) + { + passLabels.Add( i.ToString() ); + passValues.Add( i ); + minPassIdx = Mathf.Min( minPassIdx, i ); + if( m_passIdx == i ) + resetPassIdx = false; + } + } + m_availablePassesLabels = passLabels.ToArray(); + m_availablePassesValues = passValues.ToArray(); + if( resetPassIdx ) + m_passIdx = minPassIdx; + + RefreshPassLocalArrayIdx(); + } + + void RefreshPassLocalArrayIdx( ) + { + for( int i = 0; i < m_availablePassesValues.Length; i++ ) + { + if( m_availablePassesValues[ i ] == m_passIdx ) + { + m_passLocalArrayIdx = i; + } + } + } + + public override void Destroy() + { + base.Destroy(); + m_templateMPData = null; + } + + public override void ReadFromString( ref string[] nodeParams ) + { + base.ReadFromString( ref nodeParams ); + if( UIUtils.CurrentShaderVersion() > TemplatesManager.MPShaderVersion ) + { + m_subShaderIdx = Convert.ToInt32( GetCurrentParam( ref nodeParams ) ); + m_passIdx = Convert.ToInt32( GetCurrentParam( ref nodeParams ) ); + } + } + + public override void WriteToString( ref string nodeInfo, ref string connectionsInfo ) + { + base.WriteToString( ref nodeInfo, ref connectionsInfo ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_subShaderIdx ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_passIdx ); + } + public int SubShaderIdx { get { return m_subShaderIdx; } } + public int PassIdx { get { return m_passIdx; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateNodeParent.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateNodeParent.cs.meta new file mode 100644 index 00000000..134dcd6c --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateNodeParent.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b21cb297a12ef0a4281213619e3e76bf +timeCreated: 1519235586 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsData.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsData.cs new file mode 100644 index 00000000..afebbc85 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsData.cs @@ -0,0 +1,958 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using System.Text.RegularExpressions; +using System.Collections.Generic; +using UnityEngine; + +namespace AmplifyShaderEditor +{ + /*ase_pass_options OLDEST + DefineOnConnected:portId:definevalue + DefineOnUnconnected:portId:definevalue + Options:name:defaultOption:opt0:opt1:opt2 + SetVisible:PortId:OptionName:OptionValue + */ + + /*ase_pass_options OLD + Option:Option Name:UI Type:Default:Item0,Item1,Item3...ItemN + Action:Action Type:Action Data:ConditionA && ConditionB || ConditionC: + */ + + /*ase_pass_options:UniqueId:PropagateDataToHiddenPasses + Option:Color Offset:A,B,C:A + A:ShowPort:My Port Name + B,C:HidePort:My Port Name + B:SetDefine:MY_DEFINE + C:SetDefine:MY_COLOR_DEFINE + Option:My Other Option:True,False + True:ShowOption:Color Offset + False:HideOption:Color Offset + Port:My Port Name + On:SetDefine:MY_COLOR_DEFINE + Off:UnsetDefine:MY_COLOR_DEFINE + */ + public enum AseOptionsUIWidget + { + Dropdown, + Toggle, + Float, + FloatRange, + Int, + IntRange + } + + public enum AseOptionsType + { + Option, + Port, + Field + } + + + public enum AseOptionItemSetup + { + None, + InvertActionOnDeselection + } + + public enum AseOptionsActionType + { + ShowOption, + HideOption, + SetOption, + HidePort, + ShowPort, + SetPortName, + SetDefine, + RemoveDefine, + SetUndefine, + RemoveUndefine, + ExcludePass, + IncludePass, + SetPropertyOnPass, + SetPropertyOnSubShader, + SetShaderProperty, + SetMaterialProperty + } + + public enum PropertyActionsEnum + { + CullMode, + ColorMask, + ZWrite, + ZTest, + ZOffsetFactor, + ZOffsetUnits, + BlendRGB, + BlendAlpha, + BlendOpRGB, + BlendOpAlpha, + StencilReference, + StencilReadMask, + StencilWriteMask, + StencilComparison, + StencilPass, + StencilFail, + StencilZFail, + RenderType, + RenderQueue + } + + public enum AseOptionsSetup + { + CopyOptionsFromMainPass, + Id, + Name + } + + [Serializable] + public class TemplateActionItem + { + public AseOptionsActionType ActionType; + public string ActionData = string.Empty; + public int ActionDataIdx = -1; + + public string PassName; + public bool AllPasses = false; + + public PropertyActionsEnum PropertyAction; + //CULL + public CullMode ActionCullMode; + //COLOR MASK + public bool[] ColorMask = { true, true, true, true }; + + //DEPTH + public ZWriteMode ActionZWrite; + public ZTestMode ActionZTest; + public float ActionZOffsetFactor; + public float ActionZOffsetUnits; + + //BLEND OPS + public AvailableBlendFactor ActionBlendRGBSource; + public AvailableBlendFactor ActionBlendRGBDest; + + public AvailableBlendFactor ActionBlendAlphaSource; + public AvailableBlendFactor ActionBlendAlphaDest; + + public AvailableBlendOps ActionBlendOpRGB; + public AvailableBlendOps ActionBlendOpAlpha; + + //STENCIL + public int ActionStencilReference; + public int ActionStencilReadMask; + public int ActionStencilWriteMask; + public int ActionStencilComparison; + public int ActionStencilPass; + public int ActionStencilFail; + public int ActionStencilZFail; + + public bool CopyFromSubShader = false; + + public string ActionBuffer; + public override string ToString() + { + return ActionType + " " + ActionData + " " + ActionDataIdx; + } + } + + [Serializable] + public class TemplateActionItemGrid + { + [Serializable] + public class TemplateActionItemRow + { + public TemplateActionItem[] Columns; + } + + public TemplateActionItemRow[] Rows; + + public TemplateActionItemGrid( int rowsCount ) + { + Rows = new TemplateActionItemRow[ rowsCount ]; + } + + public TemplateActionItem this[ int row, int column ] + { + get { return Rows[ row ].Columns[ column ]; } + set { Rows[ row ].Columns[ column ] = value; } + } + + public TemplateActionItem[] this[ int row ] + { + get { return Rows[ row ].Columns; } + + set + { + if( Rows[ row ] == null ) + Rows[ row ] = new TemplateActionItemRow(); + + Rows[ row ].Columns = value; + } + } + } + + [Serializable] + public class TemplateOptionsItem + { + public AseOptionsType Type; + public AseOptionsUIWidget UIWidget; + public AseOptionItemSetup Setup = AseOptionItemSetup.None; + + public string Id = string.Empty; + public string Name = string.Empty; + public string DefaultOption = string.Empty; + public string[] Options = null; + public string[] DisplayOptions = null; + public int DisableIdx = -1; + + [SerializeField] + private float m_defaultFieldValue; + + public float FieldMin; + public float FieldMax; + + public bool FieldInline; + public string FieldInlineName; + public string FieldInlineOutput = string.Empty; + + [SerializeField] + public InlineProperty FieldValue = new InlineProperty(); + + public TemplateActionItemGrid ActionsPerOption = null; + + public int Count = 0; + + [SerializeField] + private int m_defaultOptionIndex = -1; + + ~TemplateOptionsItem() + { + Options = null; + } + + public int OptionIndexFor( string option ) + { + for( int i = 0; i < Options.Length; i++ ) + { + if( Options[ i ].Equals( option ) ) + { + return i; + } + } + Debug.LogWarning( "Couldn't find index for option: " + option ); + return 0; + } + + public int DefaultOptionIndex + { + get + { + if( m_defaultOptionIndex > -1 ) + return m_defaultOptionIndex; + + for( int i = 0; i < Options.Length; i++ ) + { + if( Options[ i ].Equals( DefaultOption ) ) + { + m_defaultOptionIndex = i; + return i; + } + } + Debug.LogWarning( "Couldn't find index for default option: " + DefaultOption ); + return 0; + } + } + + public float DefaultFieldValue + { + get + { + return m_defaultFieldValue; + } + set + { + m_defaultFieldValue = value; + } + } + } + + [Serializable] + public class TemplateOptionsContainer + { + public bool Enabled = false; + public string Body = string.Empty; + public int Index = -1; + public int Id = -1; + public string Name = string.Empty; + public bool CopyOptionsFromMainPass = false; + public TemplateOptionsItem[] Options = null; + ~TemplateOptionsContainer() + { + Options = null; + } + + public void CopyPortOptionsFrom( TemplateOptionsContainer container, string passName ) + { + if( container == null || container.Options == null ) + return; + + List<TemplateOptionsItem> newItems = new List<TemplateOptionsItem>(); + for( int i = 0; i < container.Options.Length; i++ ) + { + if( container.Options[ i ].Type == AseOptionsType.Port && + container.Options[ i ].Id.Equals( passName ) ) + { + newItems.Add( container.Options[ i ] ); + } + } + + if( newItems.Count > 0 ) + { + Enabled = true; + if( Options == null ) + { + Options = newItems.ToArray(); + } + else + { + Array.Resize<TemplateOptionsItem>( ref Options, Options.Length + newItems.Count ); + Array.Copy( newItems.ToArray(), Options, newItems.Count ); + } + } + newItems.Clear(); + newItems = null; + } + + public int EndIndex { get { return Index + Body.Length; } } + } + + public class TemplateOptionsToolsHelper + { + //public const string PassOptionsMainPattern = @"\/\*ase_pass_options:([\w:= ]*)[\n]([\w: \t;\n&|,_\+-]*)\*\/"; + //public const string SubShaderOptionsMainPattern = @"\/\*ase_subshader_options:([\w:= ]*)[\n]([\w: \t;\n&|,_\+-]*)\*\/"; + public const string PassOptionsMainPattern = "\\/\\*ase_pass_options:([\\w:= ]*)[\n]([\\w: \t;\n&|,_\\+\\-\\(\\)\\[\\]\\\"\\=\\/\\.]*)\\*\\/"; + public const string SubShaderOptionsMainPattern = "\\/\\*ase_subshader_options:([\\w:= ]*)[\n]([\\w: \t;\n&|,_\\+\\-\\(\\)\\[\\]\\\"\\=\\/\\.]*)\\*\\/"; + public static readonly char OptionsDataSeparator = ','; + public static Dictionary<string, AseOptionsSetup> AseOptionsSetupDict = new Dictionary<string, AseOptionsSetup>() + { + { "CopyOptionsFromMainPass",AseOptionsSetup.CopyOptionsFromMainPass}, + { "Id",AseOptionsSetup.Id}, + { "Name",AseOptionsSetup.Name}, + }; + + public static Dictionary<string, AseOptionsUIWidget> AseOptionsUITypeDict = new Dictionary<string, AseOptionsUIWidget>() + { + { "Dropdown",AseOptionsUIWidget.Dropdown }, + { "Toggle", AseOptionsUIWidget.Toggle } + }; + + public static Dictionary<string, AseOptionsActionType> AseOptionsActionTypeDict = new Dictionary<string, AseOptionsActionType>() + { + {"ShowOption", AseOptionsActionType.ShowOption }, + {"HideOption", AseOptionsActionType.HideOption }, + {"SetOption", AseOptionsActionType.SetOption }, + {"HidePort", AseOptionsActionType.HidePort }, + {"ShowPort", AseOptionsActionType.ShowPort }, + {"SetPortName", AseOptionsActionType.SetPortName }, + {"SetDefine", AseOptionsActionType.SetDefine }, + {"RemoveDefine", AseOptionsActionType.RemoveDefine }, + {"SetUndefine", AseOptionsActionType.SetUndefine }, + {"RemoveUndefine", AseOptionsActionType.RemoveUndefine }, + {"ExcludePass", AseOptionsActionType.ExcludePass }, + {"IncludePass", AseOptionsActionType.IncludePass }, + {"SetPropertyOnPass", AseOptionsActionType.SetPropertyOnPass }, + {"SetPropertyOnSubShader", AseOptionsActionType.SetPropertyOnSubShader }, + {"SetShaderProperty", AseOptionsActionType.SetShaderProperty }, + {"SetMaterialProperty", AseOptionsActionType.SetMaterialProperty } + }; + + public static Dictionary<string, AseOptionItemSetup> AseOptionItemSetupDict = new Dictionary<string, AseOptionItemSetup> + { + {"None", AseOptionItemSetup.None }, + { "InvertActionOnDeselection", AseOptionItemSetup.InvertActionOnDeselection} + }; + + public static bool InvertAction( AseOptionsActionType original, ref AseOptionsActionType inverted ) + { + bool success = true; + switch( original ) + { + case AseOptionsActionType.ShowOption: + inverted = AseOptionsActionType.HideOption; + break; + case AseOptionsActionType.HideOption: + inverted = AseOptionsActionType.ShowOption; + break; + case AseOptionsActionType.HidePort: + inverted = AseOptionsActionType.ShowPort; + break; + case AseOptionsActionType.ShowPort: + inverted = AseOptionsActionType.HidePort; + break; + case AseOptionsActionType.SetDefine: + inverted = AseOptionsActionType.RemoveDefine; + break; + case AseOptionsActionType.RemoveDefine: + inverted = AseOptionsActionType.SetDefine; + break; + case AseOptionsActionType.SetUndefine: + inverted = AseOptionsActionType.RemoveUndefine; + break; + case AseOptionsActionType.RemoveUndefine: + inverted = AseOptionsActionType.SetUndefine; + break; + case AseOptionsActionType.ExcludePass: + inverted = AseOptionsActionType.IncludePass; + break; + case AseOptionsActionType.IncludePass: + inverted = AseOptionsActionType.ExcludePass; + break; + case AseOptionsActionType.SetPortName: + case AseOptionsActionType.SetOption: + case AseOptionsActionType.SetPropertyOnPass: + case AseOptionsActionType.SetPropertyOnSubShader: + success = false; + break; + } + return success; + } + + + public static TemplateOptionsContainer GenerateOptionsContainer( bool isSubShader, string data ) + { + TemplateOptionsContainer optionsContainer = new TemplateOptionsContainer(); + + Match match = Regex.Match( data, isSubShader ? SubShaderOptionsMainPattern : PassOptionsMainPattern ); + optionsContainer.Enabled = match.Success; + if( match.Success ) + { + try + { + optionsContainer.Body = match.Value; + optionsContainer.Index = match.Index; + + List<TemplateOptionsItem> optionItemsList = new List<TemplateOptionsItem>(); + List<List<TemplateActionItem>> actionItemsList = new List<List<TemplateActionItem>>(); + Dictionary<string, int> optionItemToIndex = new Dictionary<string, int>(); + TemplateOptionsItem currentOption = null; + + //OPTIONS OVERALL SETUP + string[] setupLines = match.Groups[ 1 ].Value.Split( ':' ); + for( int i = 0; i < setupLines.Length; i++ ) + { + if( AseOptionsSetupDict.ContainsKey( setupLines[ i ] ) ) + { + AseOptionsSetup setup = AseOptionsSetupDict[ setupLines[ i ] ]; + switch( setup ) + { + case AseOptionsSetup.CopyOptionsFromMainPass: optionsContainer.CopyOptionsFromMainPass = true; break; + } + } + else + { + string[] args = setupLines[ i ].Split( '=' ); + if( args.Length > 1 && AseOptionsSetupDict.ContainsKey( args[ 0 ] ) ) + { + AseOptionsSetup setup = AseOptionsSetupDict[ args[ 0 ] ]; + switch( setup ) + { + case AseOptionsSetup.Id: if( !int.TryParse( args[ 1 ], out optionsContainer.Id ) ) optionsContainer.Id = -1; break; + case AseOptionsSetup.Name: optionsContainer.Name = args[ 1 ]; break; + } + } + } + } + + //AVAILABLE OPTIONS + string body = match.Groups[ 2 ].Value.Replace( "\t", string.Empty ); + string[] optionLines = body.Split( '\n' ); + for( int oL = 0; oL < optionLines.Length; oL++ ) + { + string[] optionItems = optionLines[ oL ].Split( ':' ); + if( optionItems.Length > 0 ) + { + string[] itemIds = optionItems[ 0 ].Split( OptionsDataSeparator ); + switch( itemIds[ 0 ] ) + { + case "Option": + { + //Fills previous option with its actions + //actionItemsList is cleared over here + FillOptionAction( currentOption, ref actionItemsList ); + + optionItemToIndex.Clear(); + currentOption = new TemplateOptionsItem(); + currentOption.Type = AseOptionsType.Option; + string[] optionItemSetup = optionItems[ 1 ].Split( OptionsDataSeparator ); + currentOption.Name = optionItemSetup[ 0 ]; + if( optionItemSetup.Length > 1 ) + { + if( AseOptionItemSetupDict.ContainsKey( optionItemSetup[ 1 ] ) ) + currentOption.Setup = AseOptionItemSetupDict[ optionItemSetup[ 1 ] ]; + } + + currentOption.Id = itemIds.Length > 1 ? itemIds[ 1 ] : optionItems[ 1 ]; + currentOption.DisplayOptions = optionItems[ 2 ].Split( OptionsDataSeparator ); + currentOption.DisableIdx = currentOption.DisplayOptions.Length; + optionItems[ 2 ] += ",disable"; + currentOption.Options = optionItems[ 2 ].Split( OptionsDataSeparator ); + currentOption.Count = currentOption.Options.Length; + + for( int opIdx = 0; opIdx < currentOption.Options.Length; opIdx++ ) + { + optionItemToIndex.Add( currentOption.Options[ opIdx ], opIdx ); + actionItemsList.Add( new List<TemplateActionItem>() ); + } + + if( optionItems.Length > 3 ) + { + currentOption.DefaultOption = optionItems[ 3 ]; + } + else + { + currentOption.DefaultOption = currentOption.Options[ 0 ]; + } + + if( currentOption.Options.Length == 2 || ( currentOption.Options.Length == 3 && currentOption.Options[ 2 ].Equals( "disable" ) ) ) + { + if( ( currentOption.Options[ 0 ].Equals( "true" ) && currentOption.Options[ 1 ].Equals( "false" ) ) || + ( currentOption.Options[ 0 ].Equals( "false" ) && currentOption.Options[ 1 ].Equals( "true" ) ) ) + { + // Toggle 0 is false and 1 is true + currentOption.Options[ 0 ] = "false"; + currentOption.Options[ 1 ] = "true"; + currentOption.UIWidget = AseOptionsUIWidget.Toggle; + } + } + else if( currentOption.Options.Length > 2 ) + { + currentOption.UIWidget = AseOptionsUIWidget.Dropdown; + } + else + { + Debug.LogWarning( "Detected an option with less than two items:" + optionItems[ 1 ] ); + } + optionItemsList.Add( currentOption ); + } + break; + case "Port": + { + //Fills previous option with its actions + //actionItemsList is cleared over here + FillOptionAction( currentOption, ref actionItemsList ); + + optionItemToIndex.Clear(); + + currentOption = new TemplateOptionsItem(); + currentOption.Type = AseOptionsType.Port; + if( isSubShader && optionItems.Length > 2 ) + { + currentOption.Id = optionItems[ 1 ]; + currentOption.Name = optionItems[ 2 ]; + } + else + { + currentOption.Name = optionItems[ 1 ]; + } + + currentOption.Options = new string[] { "On", "Off" }; + optionItemToIndex.Add( currentOption.Options[ 0 ], 0 ); + optionItemToIndex.Add( currentOption.Options[ 1 ], 1 ); + + actionItemsList.Add( new List<TemplateActionItem>() ); + actionItemsList.Add( new List<TemplateActionItem>() ); + + optionItemsList.Add( currentOption ); + } + break; + case "Field": + { + //Fills previous option with its actions + //actionItemsList is cleared over here + FillOptionAction( currentOption, ref actionItemsList ); + + optionItemToIndex.Clear(); + currentOption = new TemplateOptionsItem(); + currentOption.Type = AseOptionsType.Field; + + currentOption.Id = optionItems[ 1 ]; + currentOption.Name = optionItems[ 1 ]; + + currentOption.UIWidget = AseOptionsUIWidget.Float; + if( optionItems[ 2 ].Equals( "Int" ) ) + currentOption.UIWidget = AseOptionsUIWidget.Int; + + if( optionItems.Length >= 3 ) + { + currentOption.DefaultFieldValue = Convert.ToSingle( optionItems[ 3 ], System.Globalization.CultureInfo.InvariantCulture ); + } + + if( optionItems.Length >= 6 ) + { + if( currentOption.UIWidget == AseOptionsUIWidget.Int ) + currentOption.UIWidget = AseOptionsUIWidget.Int; + else + currentOption.UIWidget = AseOptionsUIWidget.FloatRange; + + currentOption.FieldMin = Convert.ToSingle( optionItems[ 4 ], System.Globalization.CultureInfo.InvariantCulture ); + currentOption.FieldMax = Convert.ToSingle( optionItems[ 5 ], System.Globalization.CultureInfo.InvariantCulture ); + } + + if( optionItems.Length == 5 || optionItems.Length == 7 ) + { + currentOption.FieldInline = true; + currentOption.FieldInlineName = optionItems[ optionItems.Length - 1 ]; + } + + currentOption.Options = new string[] { "Change", "Inline", "disable" }; + + optionItemToIndex.Add( currentOption.Options[ 0 ], 0 ); + optionItemToIndex.Add( currentOption.Options[ 1 ], 1 ); + optionItemToIndex.Add( currentOption.Options[ 2 ], 2 ); + currentOption.DisableIdx = 2; + + actionItemsList.Add( new List<TemplateActionItem>() ); + actionItemsList.Add( new List<TemplateActionItem>() ); + actionItemsList.Add( new List<TemplateActionItem>() ); + + optionItemsList.Add( currentOption ); + } + break; + default: + { + if( optionItemToIndex.ContainsKey( optionItems[ 0 ] ) ) + { + int idx = 0; + if( currentOption != null && currentOption.UIWidget == AseOptionsUIWidget.Toggle ) + { + idx = ( optionItems[ 0 ].Equals( "true" ) ) ? 1 : 0; + if( optionItems[ 0 ].Equals( "disable" ) ) + idx = 2; + } + else + { + idx = optionItemToIndex[ optionItems[ 0 ] ]; + } + actionItemsList[ idx ].Add( CreateActionItem( isSubShader, optionItems ) ); + } + else + { + //string[] ids = optionItems[ 0 ].Split( ',' ); + if( itemIds.Length > 1 ) + { + for( int i = 0; i < itemIds.Length; i++ ) + { + if( optionItemToIndex.ContainsKey( itemIds[ i ] ) ) + { + int idx = optionItemToIndex[ itemIds[ i ] ]; + actionItemsList[ idx ].Add( CreateActionItem( isSubShader, optionItems ) ); + } + } + } + } + + } + break; + } + } + } + + //Fills last option with its actions + FillOptionAction( currentOption, ref actionItemsList ); + + actionItemsList.Clear(); + actionItemsList = null; + + optionsContainer.Options = optionItemsList.ToArray(); + optionItemsList.Clear(); + optionItemsList = null; + + optionItemToIndex.Clear(); + optionItemToIndex = null; + } + catch( Exception e ) + { + Debug.LogException( e ); + } + } + return optionsContainer; + } + + static void FillOptionAction( TemplateOptionsItem currentOption, ref List<List<TemplateActionItem>> actionItemsList ) + { + if( currentOption != null ) + { + int count = actionItemsList.Count; + currentOption.ActionsPerOption = new TemplateActionItemGrid( count ); + for( int i = 0; i < count; i++ ) + { + currentOption.ActionsPerOption[ i ] = actionItemsList[ i ].ToArray(); + actionItemsList[ i ].Clear(); + } + actionItemsList.Clear(); + } + } + + static TemplateActionItem CreateActionItem( bool isSubshader, string[] optionItems ) + { + TemplateActionItem actionItem = new TemplateActionItem(); + try + { + actionItem.ActionType = AseOptionsActionTypeDict[ optionItems[ 1 ] ]; + int optionsIdx = 2; + if( optionItems.Length > 3 ) + { + optionsIdx = 3; + actionItem.PassName = optionItems[ 2 ]; + } + else + { + actionItem.AllPasses = isSubshader; + } + + actionItem.ActionData = optionItems[ optionsIdx ]; + + switch( actionItem.ActionType ) + { + case AseOptionsActionType.ShowOption: + case AseOptionsActionType.HideOption: + { + string[] arr = optionItems[ optionsIdx ].Split( OptionsDataSeparator ); + if( arr.Length > 1 ) + { + actionItem.ActionData = arr[ 0 ]; + if( !int.TryParse( arr[ 1 ], out actionItem.ActionDataIdx ) ) + { + actionItem.ActionDataIdx = -1; + } + } + } + break; + case AseOptionsActionType.SetOption: + { + string[] arr = optionItems[ optionsIdx ].Split( OptionsDataSeparator ); + if( arr.Length > 1 ) + { + actionItem.ActionData = arr[ 0 ]; + if( !int.TryParse( arr[ 1 ], out actionItem.ActionDataIdx ) ) + { + Debug.LogWarning( "SetOption value must be a the selection index" ); + } + } + } + break; + case AseOptionsActionType.HidePort: + case AseOptionsActionType.ShowPort: + { + if( !int.TryParse( actionItem.ActionData, out actionItem.ActionDataIdx ) ) + actionItem.ActionDataIdx = -1; + } + break; + case AseOptionsActionType.SetPortName: + { + string[] arr = optionItems[ optionsIdx ].Split( OptionsDataSeparator ); + if( arr.Length > 1 ) + { + int.TryParse( arr[ 0 ], out actionItem.ActionDataIdx ); + actionItem.ActionData = arr[ 1 ]; + } + } + break; + case AseOptionsActionType.SetDefine: + case AseOptionsActionType.RemoveDefine: + case AseOptionsActionType.SetUndefine: + case AseOptionsActionType.RemoveUndefine: + case AseOptionsActionType.ExcludePass: + case AseOptionsActionType.IncludePass: + break; + case AseOptionsActionType.SetShaderProperty: + { + int optIndex = optionItems[ optionsIdx ].IndexOf( OptionsDataSeparator ); + if( optIndex > -1 ) + { + actionItem.ActionData = optionItems[ optionsIdx ].Substring( 0, optIndex ); + actionItem.ActionBuffer = optionItems[ optionsIdx ].Substring( optIndex + 1, optionItems[ optionsIdx ].Length - optIndex - 1); + } + }break; + case AseOptionsActionType.SetMaterialProperty: + { + int optIndex = optionItems[ optionsIdx ].IndexOf( OptionsDataSeparator ); + if( optIndex > -1 ) + { + actionItem.ActionData = optionItems[ optionsIdx ].Substring( 0, optIndex ); + } + } + break; + case AseOptionsActionType.SetPropertyOnPass: + case AseOptionsActionType.SetPropertyOnSubShader: + { + string[] arr = optionItems[ optionsIdx ].Split( OptionsDataSeparator ); + actionItem.PropertyAction = (PropertyActionsEnum)Enum.Parse( typeof( PropertyActionsEnum ), arr[ 0 ] ); + if( arr.Length == 1 && actionItem.ActionType == AseOptionsActionType.SetPropertyOnPass ) + { + actionItem.CopyFromSubShader = true; + } + else + { + switch( actionItem.PropertyAction ) + { + case PropertyActionsEnum.CullMode: + { + if( arr.Length > 1 ) + actionItem.ActionCullMode = (CullMode)Enum.Parse( typeof( CullMode ), arr[ 1 ] ); + } + break; + case PropertyActionsEnum.ColorMask: + { + if( arr.Length > 4 ) + { + actionItem.ColorMask[ 0 ] = Convert.ToBoolean( arr[ 1 ] ); + actionItem.ColorMask[ 1 ] = Convert.ToBoolean( arr[ 2 ] ); + actionItem.ColorMask[ 2 ] = Convert.ToBoolean( arr[ 3 ] ); + actionItem.ColorMask[ 3 ] = Convert.ToBoolean( arr[ 4 ] ); + } + } + break; + case PropertyActionsEnum.ZWrite: + { + if( arr.Length > 1 ) + actionItem.ActionZWrite = (ZWriteMode)Enum.Parse( typeof( ZWriteMode ), arr[ 1 ] ); + } + break; + case PropertyActionsEnum.ZTest: + { + if( arr.Length > 1 ) + actionItem.ActionZTest = (ZTestMode)Enum.Parse( typeof( ZTestMode ), arr[ 1 ] ); + } + break; + case PropertyActionsEnum.ZOffsetFactor: + { + if( arr.Length > 1 ) + actionItem.ActionZOffsetFactor = Convert.ToSingle( arr[ 1 ] ); + } + break; + case PropertyActionsEnum.ZOffsetUnits: + { + if( arr.Length > 1 ) + actionItem.ActionZOffsetUnits = Convert.ToSingle( arr[ 1 ] ); + } + break; + case PropertyActionsEnum.BlendRGB: + { + if( arr.Length > 2 ) + { + actionItem.ActionBlendRGBSource = (AvailableBlendFactor)Enum.Parse( typeof( AvailableBlendFactor ), arr[ 1 ] ); + actionItem.ActionBlendRGBDest = (AvailableBlendFactor)Enum.Parse( typeof( AvailableBlendFactor ), arr[ 2 ] ); + } + } + break; + case PropertyActionsEnum.BlendAlpha: + { + if( arr.Length > 2 ) + { + actionItem.ActionBlendAlphaSource = (AvailableBlendFactor)Enum.Parse( typeof( AvailableBlendFactor ), arr[ 1 ] ); + actionItem.ActionBlendAlphaDest = (AvailableBlendFactor)Enum.Parse( typeof( AvailableBlendFactor ), arr[ 2 ] ); + } + } + break; + case PropertyActionsEnum.BlendOpRGB: + { + if( arr.Length > 1 ) + { + actionItem.ActionBlendOpRGB = (AvailableBlendOps)Enum.Parse( typeof( AvailableBlendOps ), arr[ 1 ] ); + + } + } + break; + case PropertyActionsEnum.BlendOpAlpha: + { + if( arr.Length > 1 ) + { + actionItem.ActionBlendOpAlpha = (AvailableBlendOps)Enum.Parse( typeof( AvailableBlendOps ), arr[ 1 ] ); + } + } + break; + case PropertyActionsEnum.StencilReference: + { + if( arr.Length > 1 ) + { + int.TryParse( arr[ 1 ], out actionItem.ActionStencilReference ); + } + } + break; + case PropertyActionsEnum.StencilReadMask: + { + if( arr.Length > 1 ) + { + int.TryParse( arr[ 1 ], out actionItem.ActionStencilReadMask ); + } + } + break; + case PropertyActionsEnum.StencilWriteMask: + { + if( arr.Length > 1 ) + { + int.TryParse( arr[ 1 ], out actionItem.ActionStencilWriteMask ); + } + } + break; + case PropertyActionsEnum.StencilComparison: + { + if( arr.Length > 1 ) + actionItem.ActionStencilComparison = StencilBufferOpHelper.StencilComparisonValuesDict[ arr[ 1 ] ]; + } + break; + case PropertyActionsEnum.StencilPass: + { + if( arr.Length > 1 ) + actionItem.ActionStencilPass = StencilBufferOpHelper.StencilOpsValuesDict[ arr[ 1 ] ]; + } + break; + case PropertyActionsEnum.StencilFail: + { + if( arr.Length > 1 ) + actionItem.ActionStencilFail = StencilBufferOpHelper.StencilOpsValuesDict[ arr[ 1 ] ]; + } + break; + case PropertyActionsEnum.StencilZFail: + { + if( arr.Length > 1 ) + actionItem.ActionStencilZFail = StencilBufferOpHelper.StencilOpsValuesDict[ arr[ 1 ] ]; + } + break; + case PropertyActionsEnum.RenderType: + { + if( arr.Length > 1 ) + actionItem.ActionData = arr[ 1 ]; + } + break; + case PropertyActionsEnum.RenderQueue: + { + if( arr.Length > 1 ) + actionItem.ActionData = arr[ 1 ]; + if( arr.Length > 2 ) + { + int.TryParse( arr[ 2 ], out actionItem.ActionDataIdx ); + } + else + { + actionItem.ActionDataIdx = 0; + } + } + break; + } + } + } + break; + } + } + catch( Exception e ) + { + Debug.LogException( e ); + } + return actionItem; + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsData.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsData.cs.meta new file mode 100644 index 00000000..55c0596b --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsData.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 019dfacde4ed75a41851c7f15f69963f +timeCreated: 1533143812 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsDefinesContainer.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsDefinesContainer.cs new file mode 100644 index 00000000..affbd406 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsDefinesContainer.cs @@ -0,0 +1,69 @@ +using UnityEngine; +using System; +using System.Collections.Generic; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateOptionsDefinesContainer + { + [SerializeField] + private List<PropertyDataCollector> m_definesList = new List<PropertyDataCollector>(); + + [NonSerialized] + private Dictionary<string, PropertyDataCollector> m_definesDict = new Dictionary<string, PropertyDataCollector>(); + + void Refresh() + { + if( m_definesDict.Count != m_definesList.Count ) + { + m_definesDict.Clear(); + for( int i = 0; i < m_definesList.Count; i++ ) + { + m_definesDict.Add( m_definesList[ i ].PropertyName, m_definesList[ i ] ); + } + } + } + + public void RemoveTemporaries() + { + List<PropertyDataCollector> temporaries = m_definesList.FindAll( ( x ) => ( x.NodeId == 1 ) ); + for( int i = 0; i < temporaries.Count; i++ ) + { + m_definesList.Remove( temporaries[ i ] ); + m_definesDict.Remove( temporaries[ i ].PropertyName ); + } + } + + public void AddDefine( string define , bool temporary ) + { + Refresh(); + if( !m_definesDict.ContainsKey( define ) ) + { + int nodeId = temporary ? 1 : 0; + PropertyDataCollector data = new PropertyDataCollector( nodeId, define ); + m_definesDict.Add( define, data ); + m_definesList.Add( data ); + } + } + + public void RemoveDefine( string define ) + { + Refresh(); + if( m_definesDict.ContainsKey( define ) ) + { + m_definesList.Remove( m_definesDict[define] ); + m_definesDict.Remove( define ); + } + } + + public void Destroy() + { + m_definesDict.Clear(); + m_definesDict = null; + m_definesList.Clear(); + m_definesList = null; + } + public List<PropertyDataCollector> DefinesList { get { return m_definesList; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsDefinesContainer.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsDefinesContainer.cs.meta new file mode 100644 index 00000000..151a9abc --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsDefinesContainer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0f32755ee64bb1542ad9598810d9faf9 +timeCreated: 1543339825 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsPort.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsPort.cs new file mode 100644 index 00000000..04c11872 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsPort.cs @@ -0,0 +1,174 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace AmplifyShaderEditor +{ + // PORT CONTROLLERS + [Serializable] + public class TemplateOptionPortItem + { + [SerializeField] + private int m_portId = -1; + + [SerializeField] + private TemplateOptionsItem m_options; + + public TemplateOptionPortItem( TemplateMultiPassMasterNode owner, TemplateOptionsItem options ) + { + m_options = options; + InputPort port = owner.InputPorts.Find( x => x.Name.Equals( options.Name ) ); + if( port != null ) + { + m_portId = port.PortId; + } + } + + public void FillDataCollector( TemplateMultiPassMasterNode owner, ref MasterNodeDataCollector dataCollector ) + { + InputPort port = null; + if( m_portId > -1 ) + { + port = owner.GetInputPortByUniqueId( m_portId ); + } + else + { + port = owner.InputPorts.Find( x => x.Name.Equals( m_options.Name ) ); + } + + if( port != null ) + { + int optionId = port.HasOwnOrLinkConnection ? 0 : 1; + for( int i = 0; i < m_options.ActionsPerOption[ optionId ].Length; i++ ) + { + switch( m_options.ActionsPerOption[ optionId ][ i ].ActionType ) + { + case AseOptionsActionType.SetDefine: + { + List<TemplateMultiPassMasterNode> nodes = owner.ContainerGraph.GetMultiPassMasterNodes( owner.LODIndex ); + int count = nodes.Count; + for( int nodeIdx = 0; nodeIdx < count; nodeIdx++ ) + { + nodes[ nodeIdx ].OptionsDefineContainer.AddDefine( "#define "+m_options.ActionsPerOption[ optionId ][ i ].ActionData, false ); + } + //dataCollector.AddToDefines( -1, m_options.ActionsPerOption[ optionId ][ i ].ActionData ); + } + break; + case AseOptionsActionType.SetUndefine: + { + List<TemplateMultiPassMasterNode> nodes = owner.ContainerGraph.GetMultiPassMasterNodes( owner.LODIndex ); + int count = nodes.Count; + for( int nodeIdx = 0; nodeIdx < count; nodeIdx++ ) + { + nodes[ nodeIdx ].OptionsDefineContainer.AddDefine( "#undef " + m_options.ActionsPerOption[ optionId ][ i ].ActionData, false ); + } + //dataCollector.AddToDefines( -1, m_options.ActionsPerOption[ optionId ][ i ].ActionData, false ); + } + break; + case AseOptionsActionType.SetShaderProperty: + { + TemplateShaderPropertyData data = owner.CurrentTemplate.GetShaderPropertyData( m_options.ActionsPerOption[ optionId ][ i ].ActionData ); + if( data != null ) + { + string newPropertyValue = data.CreatePropertyForValue( m_options.ActionsPerOption[ optionId ][ i ].ActionBuffer ); + owner.CurrentTemplate.IdManager.SetReplacementText( data.FullValue, newPropertyValue ); + } + } + break; + } + } + } + } + + public void SubShaderFillDataCollector( TemplateMultiPassMasterNode owner, ref MasterNodeDataCollector dataCollector ) + { + + //TemplateMultiPassMasterNode targetNode = string.IsNullOrEmpty(m_options.Id) ? owner:owner.ContainerGraph.GetMasterNodeOfPass( m_options.Id , owner.LODIndex ); + TemplateMultiPassMasterNode targetNode = string.IsNullOrEmpty( m_options.Id ) ? + owner.ContainerGraph.GetMainMasterNodeOfLOD( owner.LODIndex ) : + owner.ContainerGraph.GetMasterNodeOfPass( m_options.Id , owner.LODIndex ); + + InputPort port = null; + if( m_portId > -1 ) + { + port = targetNode.GetInputPortByUniqueId( m_portId ); + } + else + { + port = targetNode.InputPorts.Find( x => x.Name.Equals( m_options.Name ) ); + } + + if( port != null ) + { + int optionId = port.HasOwnOrLinkConnection ? 0 : 1; + for( int i = 0; i < m_options.ActionsPerOption[ optionId ].Length; i++ ) + { + if( string.IsNullOrEmpty( m_options.ActionsPerOption[ optionId ][ i ].PassName ) || + m_options.ActionsPerOption[ optionId ][ i ].PassName.Equals( owner.PassName ) ) + { + switch( m_options.ActionsPerOption[ optionId ][ i ].ActionType ) + { + case AseOptionsActionType.SetDefine: + { + owner.OptionsDefineContainer.AddDefine( "#define " + m_options.ActionsPerOption[ optionId ][ i ].ActionData, true ); + } + break; + case AseOptionsActionType.SetUndefine: + { + owner.OptionsDefineContainer.AddDefine( "#undef " + m_options.ActionsPerOption[ optionId ][ i ].ActionData, true ); + } + break; + case AseOptionsActionType.SetShaderProperty: + { + TemplateShaderPropertyData data = owner.CurrentTemplate.GetShaderPropertyData( m_options.ActionsPerOption[ optionId ][ i ].ActionData ); + if( data != null ) + { + string newPropertyValue = data.CreatePropertyForValue( m_options.ActionsPerOption[ optionId ][ i ].ActionBuffer ); + owner.CurrentTemplate.IdManager.SetReplacementText( data.FullValue, newPropertyValue ); + } + } + break; + } + } + } + } + } + + public void CheckImediateActionsForPort( TemplateMultiPassMasterNode owner, int portId ) + { + if( portId != m_portId ) + return; + + InputPort port = null; + if( m_portId > -1 ) + { + port = owner.GetInputPortByUniqueId( m_portId ); + } + else + { + port = owner.InputPorts.Find( x => x.Name.Equals( m_options.Name ) ); + } + + if( port != null ) + { + int optionId = port.HasOwnOrLinkConnection ? 0 : 1; + for( int i = 0; i < m_options.ActionsPerOption[ optionId ].Length; i++ ) + { + switch( m_options.ActionsPerOption[ optionId ][ i ].ActionType ) + { + case AseOptionsActionType.SetPortName: + { + port.Name = m_options.ActionsPerOption[ optionId ][ i ].ActionData; + owner.SizeIsDirty = true; + } + break; + } + } + } + } + public TemplateOptionsItem Options { get { return m_options; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsPort.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsPort.cs.meta new file mode 100644 index 00000000..a9c15d28 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsPort.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fa2d25bd070cde046876bd1fa77bf116 +timeCreated: 1535044953 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsUI.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsUI.cs new file mode 100644 index 00000000..559f3a44 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsUI.cs @@ -0,0 +1,300 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace AmplifyShaderEditor +{ + // UI STRUCTURES + [Serializable] + public class TemplateOptionUIItem + { + public delegate void OnActionPerformed( bool isRefreshing, bool invertAction, TemplateOptionUIItem uiItem, params TemplateActionItem[] validActions ); + public event OnActionPerformed OnActionPerformedEvt; + + [SerializeField] + private bool m_isVisible = true; + + [SerializeField] + private bool m_wasVisible = true; + + [SerializeField] + private int m_currentOption = 0; + + [SerializeField] + private TemplateOptionsItem m_options; + + [SerializeField] + private bool m_checkOnExecute = false; + + [SerializeField] + private bool m_invertActionOnDeselection = false; + + public TemplateOptionUIItem( TemplateOptionsItem options ) + { + m_options = options; + if( m_options.Type == AseOptionsType.Field ) + { + m_options.FieldValue.FloatValue = m_options.DefaultFieldValue; + } + else + { + m_currentOption = m_options.DefaultOptionIndex; + } + m_invertActionOnDeselection = options.Setup == AseOptionItemSetup.InvertActionOnDeselection; + } + + public void CopyValuesFrom( TemplateOptionUIItem origin ) + { + m_isVisible = origin.IsVisible; + m_wasVisible = origin.WasVisible; + m_currentOption = origin.CurrentOption; + m_options.FieldValue.FloatValue = origin.CurrentFieldValue; + m_checkOnExecute = origin.CheckOnExecute; + m_invertActionOnDeselection = origin.InvertActionOnDeselection; + } + + public void Draw( UndoParentNode owner ) + { + if( m_isVisible ) + { + int lastOption = m_currentOption; + EditorGUI.BeginChangeCheck(); + switch( m_options.UIWidget ) + { + case AseOptionsUIWidget.Dropdown: + { + m_currentOption = owner.EditorGUILayoutPopup( m_options.Name, m_currentOption, m_options.DisplayOptions ); + } + break; + case AseOptionsUIWidget.Toggle: + { + m_currentOption = owner.EditorGUILayoutToggle( m_options.Name, m_currentOption == 1 ) ? 1 : 0; + } + break; + case AseOptionsUIWidget.Float: + { + if( m_options.FieldInline ) + { + m_options.FieldValue.FloatField( ref owner, m_options.Name ); + if( m_options.FieldValue.Active ) + m_currentOption = 1; + else + m_currentOption = 0; + } + else + { + m_options.FieldValue.FloatValue = owner.EditorGUILayoutFloatField( m_options.Name, m_options.FieldValue.FloatValue ); + } + } + break; + case AseOptionsUIWidget.Int: + { + if( m_options.FieldInline ) + { + m_options.FieldValue.IntField( ref owner, m_options.Name ); + if( m_options.FieldValue.Active ) + m_currentOption = 1; + else + m_currentOption = 0; + } + else + m_options.FieldValue.FloatValue = owner.EditorGUILayoutIntField( m_options.Name, (int)m_options.FieldValue.FloatValue ); + } + break; + case AseOptionsUIWidget.FloatRange: + { + if( m_options.FieldInline ) + { + m_options.FieldValue.SliderField( ref owner, m_options.Name, m_options.FieldMin, m_options.FieldMax ); + if( m_options.FieldValue.Active ) + m_currentOption = 1; + else + m_currentOption = 0; + } + else + m_options.FieldValue.FloatValue = owner.EditorGUILayoutSlider( m_options.Name, m_options.FieldValue.FloatValue, m_options.FieldMin, m_options.FieldMax ); + } + break; + case AseOptionsUIWidget.IntRange: + { + if( m_options.FieldInline ) + { + m_options.FieldValue.IntSlider( ref owner, m_options.Name, (int)m_options.FieldMin, (int)m_options.FieldMax ); + if( m_options.FieldValue.Active ) + m_currentOption = 1; + else + m_currentOption = 0; + } + else + m_options.FieldValue.FloatValue = owner.EditorGUILayoutIntSlider( m_options.Name, (int)m_options.FieldValue.FloatValue, (int)m_options.FieldMin, (int)m_options.FieldMax ); + } + break; + } + if( EditorGUI.EndChangeCheck() ) + { + if( OnActionPerformedEvt != null ) + { + if( m_invertActionOnDeselection ) + OnActionPerformedEvt( false, lastOption != m_options.DisableIdx, this, m_options.ActionsPerOption[ lastOption ] ); + + OnActionPerformedEvt( false, false, this, m_options.ActionsPerOption[ m_currentOption ] ); + } + } + } + } + + public void CheckEnDisable() + { + //string deb = string.Empty;// "-- Checked --" + m_options.Name+" "+ m_isVisible + " "+ m_wasVisible; + if( m_isVisible ) + { + if( !m_wasVisible ) + { + //deb = "-- Enable --" + m_options.Name; + //Debug.Log( deb ); + if( OnActionPerformedEvt != null ) + { + if( m_invertActionOnDeselection ) + { + for( int i = 0; i < m_options.Count; i++ ) + { + if( i != m_currentOption && i != m_options.DisableIdx ) + { + OnActionPerformedEvt( false, true, this, m_options.ActionsPerOption[ i ] ); + } + } + } + + OnActionPerformedEvt( false, false, this, m_options.ActionsPerOption[ m_currentOption ] ); + //if( !m_isVisible ) + //OnActionPerformedEvt( isRefreshing, false, this, m_options.ActionsPerOption[ m_options.DisableIdx ] ); + } + } + + m_wasVisible = true; + } + else if( m_wasVisible ) + { + //deb = "-- Disable --" + m_options.Name; + //Debug.Log( deb ); + m_wasVisible = false; + + if( OnActionPerformedEvt != null ) + { + OnActionPerformedEvt( false, false, this, m_options.ActionsPerOption[ m_options.DisableIdx ] ); + } + } + } + + public void FillDataCollector( ref MasterNodeDataCollector dataCollector ) + { + if( m_isVisible && m_checkOnExecute ) + { + for( int i = 0; i < m_options.ActionsPerOption[ m_currentOption ].Length; i++ ) + { + switch( m_options.ActionsPerOption[ m_currentOption ][ i ].ActionType ) + { + case AseOptionsActionType.SetDefine: + { + dataCollector.AddToDefines( -1, m_options.ActionsPerOption[ m_currentOption ][ i ].ActionData ); + } + break; + case AseOptionsActionType.SetUndefine: + { + dataCollector.AddToDefines( -1, m_options.ActionsPerOption[ m_currentOption ][ i ].ActionData, false ); + } + break; + } + } + } + } + + public void Refresh() + { + if( OnActionPerformedEvt != null ) + { + if( m_invertActionOnDeselection ) + { + for( int i = 0; i < m_options.Count; i++ ) + { + if( i != m_currentOption && i != m_options.DisableIdx ) + { + OnActionPerformedEvt( true, true, this, m_options.ActionsPerOption[ i ] ); + } + } + } + + OnActionPerformedEvt( true, false, this, m_options.ActionsPerOption[ m_currentOption ] ); + } + } + + public TemplateOptionsItem Options { get { return m_options; } } + + public void Destroy() + { + OnActionPerformedEvt = null; + } + + public bool IsVisible + { + get { return m_isVisible; } + set { m_isVisible = value; } + } + + public bool WasVisible + { + get { return m_wasVisible; } + set { m_wasVisible = value; } + } + + public bool CheckOnExecute + { + get { return m_checkOnExecute; } + set { m_checkOnExecute = value; } + } + + public InlineProperty FieldValue + { + get { return m_options.FieldValue; } + set { m_options.FieldValue = value; } + } + + public float CurrentFieldValue + { + get { return m_options.FieldValue.FloatValue; } + set { m_options.FieldValue.FloatValue = value; } + } + + public int CurrentOption + { + get { return m_currentOption; } + set + { + m_currentOption = Mathf.Clamp( value, 0, m_options.Options.Length - 1 ); + // why refreshing here? + //Refresh(); + } + } + + public int CurrentOptionIdx + { + set + { + m_currentOption = Mathf.Clamp( value, 0, m_options.Options.Length - 1 ); + } + } + public bool EmptyEvent { get { return OnActionPerformedEvt == null; } } + public TemplateActionItemGrid.TemplateActionItemRow CurrentOptionActions + { + get + { + return m_options.ActionsPerOption.Rows[m_currentOption]; + } + } + public bool InvertActionOnDeselection { get { return m_invertActionOnDeselection; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsUI.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsUI.cs.meta new file mode 100644 index 00000000..b3f17647 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsUI.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 081c72eb35d61c84e9a5c34522c3ff33 +timeCreated: 1534775306 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsUIHelper.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsUIHelper.cs new file mode 100644 index 00000000..06d346b3 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsUIHelper.cs @@ -0,0 +1,862 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using UnityEngine; +using UnityEditor; +using System; +using System.Collections.Generic; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateOptionsUIHelper + { + private const string CustomOptionsLabel = " Custom Options"; + + private bool m_isSubShader = false; + + [SerializeField] + private bool m_passCustomOptionsFoldout = true; + + [SerializeField] + private string m_passCustomOptionsLabel = CustomOptionsLabel; + + [SerializeField] + private int m_passCustomOptionsSizeCheck = 0; + + [SerializeField] + private List<TemplateOptionUIItem> m_passCustomOptionsUI = new List<TemplateOptionUIItem>(); + + [NonSerialized] + private Dictionary<string, TemplateOptionUIItem> m_passCustomOptionsUIDict = new Dictionary<string, TemplateOptionUIItem>(); + + [NonSerialized] + private TemplateMultiPassMasterNode m_owner; + + [NonSerialized] + private string[] m_readOptionNames; + + [NonSerialized] + private string[] m_readOptionSelections; + + [SerializeField] + private List<TemplateOptionPortItem> m_passCustomOptionsPorts = new List<TemplateOptionPortItem>(); + + public TemplateOptionsUIHelper( bool isSubShader ) + { + m_isSubShader = isSubShader; + } + + public void CopyOptionsValuesFrom( TemplateOptionsUIHelper origin ) + { + for( int i = 0; i < origin.PassCustomOptionsUI.Count; i++ ) + { + m_passCustomOptionsUI[ i ].CopyValuesFrom( origin.PassCustomOptionsUI[ i ] ); + } + } + + public void Destroy() + { + for( int i = 0; i < m_passCustomOptionsUI.Count; i++ ) + { + m_passCustomOptionsUI[ i ].Destroy(); + } + + m_passCustomOptionsUI.Clear(); + m_passCustomOptionsUI = null; + + m_passCustomOptionsUIDict.Clear(); + m_passCustomOptionsUIDict = null; + + m_passCustomOptionsPorts.Clear(); + m_passCustomOptionsPorts = null; + } + + public void DrawCustomOptions( TemplateMultiPassMasterNode owner ) + { + m_owner = owner; + + if( m_passCustomOptionsUI.Count > 0 ) + { + NodeUtils.DrawNestedPropertyGroup( ref m_passCustomOptionsFoldout, m_passCustomOptionsLabel, DrawCustomOptionsBlock ); + } + } + + public void DrawCustomOptionsBlock() + { + float currWidth = EditorGUIUtility.labelWidth; +#if UNITY_2019_3_OR_NEWER + float size = Mathf.Max( UIUtils.CurrentWindow.ParametersWindow.TransformedArea.width * 0.385f, 0 ); +#else + float size = Mathf.Max( UIUtils.CurrentWindow.ParametersWindow.TransformedArea.width * 0.34f, 0 ); +#endif + EditorGUIUtility.labelWidth = size; + for( int i = 0; i < m_passCustomOptionsUI.Count; i++ ) + { + m_passCustomOptionsUI[ i ].Draw( m_owner ); + } + EditorGUILayout.Space(); + EditorGUIUtility.labelWidth = currWidth; + } + + public void OnCustomOptionSelected( bool isRefreshing, bool invertAction, TemplateMultiPassMasterNode owner, TemplateOptionUIItem uiItem, params TemplateActionItem[] validActions ) + { + uiItem.CheckOnExecute = false; + for( int i = 0; i < validActions.Length; i++ ) + { + AseOptionsActionType actionType = validActions[ i ].ActionType; + if( invertAction ) + { + if( !TemplateOptionsToolsHelper.InvertAction( validActions[ i ].ActionType, ref actionType ) ) + { + continue; + } + } + + switch( actionType ) + { + case AseOptionsActionType.ShowOption: + { + TemplateOptionUIItem item = m_passCustomOptionsUI.Find( x => ( x.Options.Name.Equals( validActions[ i ].ActionData ) ) ); + if( item != null ) + { + if( isRefreshing ) + { + string optionId = validActions[ i ].PassName + validActions[ i ].ActionData + "Option"; + owner.ContainerGraph.ParentWindow.TemplatesManagerInstance.SetOptionsValue( optionId, true ); + } + + // this prevents options from showing up when loading by checking if they were hidden by another option + // it works on the assumption that an option that may possible hide this one is checked first + if( !isRefreshing ) + item.IsVisible = true; + else if( item.WasVisible ) + item.IsVisible = true; + + if( !invertAction && validActions[ i ].ActionDataIdx > -1 ) + item.CurrentOption = validActions[ i ].ActionDataIdx; + + item.CheckEnDisable(); + } + else + { + Debug.LogFormat( "Could not find Option {0} for action {1}", validActions[ i ].ActionData, validActions[ i ].ActionType ); + } + } + break; + case AseOptionsActionType.HideOption: + { + TemplateOptionUIItem item = m_passCustomOptionsUI.Find( x => ( x.Options.Name.Equals( validActions[ i ].ActionData ) ) ); + if( item != null ) + { + bool flag = false; + if( isRefreshing ) + { + string optionId = validActions[ i ].PassName + validActions[ i ].ActionData + "Option"; + flag = owner.ContainerGraph.ParentWindow.TemplatesManagerInstance.SetOptionsValue( optionId, false ); + } + + item.IsVisible = false || flag; + if( !invertAction && validActions[ i ].ActionDataIdx > -1 ) + item.CurrentOption = validActions[ i ].ActionDataIdx; + + item.CheckEnDisable(); + } + else + { + Debug.LogFormat( "Could not find Option {0} for action {1}", validActions[ i ].ActionData, validActions[ i ].ActionType ); + } + } + break; + case AseOptionsActionType.SetOption: + { + if( !uiItem.IsVisible ) + break; + + TemplateOptionUIItem item = m_passCustomOptionsUI.Find( x => ( x.Options.Name.Equals( validActions[ i ].ActionData ) ) ); + if( item != null ) + { + item.CurrentOption = validActions[ i ].ActionDataIdx; + item.Refresh(); + } + else + { + Debug.LogFormat( "Could not find Option {0} for action {1}", validActions[ i ].ActionData, validActions[ i ].ActionType ); + } + } + break; + case AseOptionsActionType.HidePort: + { + TemplateMultiPassMasterNode passMasterNode = owner; + if( !string.IsNullOrEmpty( validActions[ i ].PassName ) ) + { + passMasterNode = owner.ContainerGraph.GetMasterNodeOfPass( validActions[ i ].PassName,owner.LODIndex ); + } + + if( passMasterNode != null ) + { + InputPort port = validActions[ i ].ActionDataIdx > -1 ? + passMasterNode.GetInputPortByUniqueId( validActions[ i ].ActionDataIdx ) : + passMasterNode.InputPorts.Find( x => x.Name.Equals( validActions[ i ].ActionData ) ); + if( port != null ) + { + if( isRefreshing ) + { + string optionId = validActions[ i ].PassName + port.Name; + owner.ContainerGraph.ParentWindow.TemplatesManagerInstance.SetOptionsValue( optionId, port.IsConnected ); + port.Visible = port.IsConnected; + } + else + { + port.Visible = false; + } + passMasterNode.SizeIsDirty = true; + } + else + { + Debug.LogFormat( "Could not find port {0},{1} for action {2}", validActions[ i ].ActionDataIdx, validActions[ i ].ActionData, validActions[ i ].ActionType ); + } + } + else + { + Debug.LogFormat( "Could not find pass {0} for action {1} on {2}", validActions[ i ].PassName, validActions[ i ].ActionType, validActions[ i ].ActionData ); + } + } + break; + case AseOptionsActionType.ShowPort: + { + if( !uiItem.IsVisible ) + break; + + TemplateMultiPassMasterNode passMasterNode = owner; + if( !string.IsNullOrEmpty( validActions[ i ].PassName ) ) + { + passMasterNode = owner.ContainerGraph.GetMasterNodeOfPass( validActions[ i ].PassName, owner.LODIndex ); + } + + if( passMasterNode != null ) + { + InputPort port = validActions[ i ].ActionDataIdx > -1 ? + passMasterNode.GetInputPortByUniqueId( validActions[ i ].ActionDataIdx ) : + passMasterNode.InputPorts.Find( x => x.Name.Equals( validActions[ i ].ActionData ) ); + if( port != null ) + { + if( isRefreshing ) + { + string optionId = validActions[ i ].PassName + port.Name; + owner.ContainerGraph.ParentWindow.TemplatesManagerInstance.SetOptionsValue( optionId, true ); + } + + port.Visible = true; + passMasterNode.SizeIsDirty = true; + } + else + { + Debug.LogFormat( "Could not find port {0},{1} for action {2}", validActions[ i ].ActionDataIdx, validActions[ i ].ActionData, validActions[ i ].ActionType ); + } + } + else + { + Debug.LogFormat( "Could not find pass {0} for action {1} on {2}", validActions[ i ].PassName, validActions[ i ].ActionType, validActions[ i ].ActionData ); + } + } + break; + case AseOptionsActionType.SetPortName: + { + if( !uiItem.IsVisible ) + break; + + TemplateMultiPassMasterNode passMasterNode = owner; + if( !string.IsNullOrEmpty( validActions[ i ].PassName ) ) + { + passMasterNode = owner.ContainerGraph.GetMasterNodeOfPass( validActions[ i ].PassName, owner.LODIndex ); + } + + if( passMasterNode != null ) + { + InputPort port = passMasterNode.GetInputPortByUniqueId( validActions[ i ].ActionDataIdx ); + if( port != null ) + { + port.Name = validActions[ i ].ActionData; + passMasterNode.SizeIsDirty = true; + } + else + { + Debug.LogFormat( "Could not find port {0},{1} for action {2}", validActions[ i ].ActionDataIdx, validActions[ i ].ActionData, validActions[ i ].ActionType ); + } + } + else + { + Debug.LogFormat( "Could not find pass {0} for action {1} on {2}", validActions[ i ].PassName, validActions[ i ].ActionType, validActions[ i ].ActionData ); + } + } + break; + case AseOptionsActionType.SetDefine: + { + if( !uiItem.IsVisible ) + { + uiItem.CheckOnExecute = true; + break; + } + + //Debug.Log( "DEFINE " + validActions[ i ].ActionData ); + if( validActions[ i ].AllPasses ) + { + string actionData = validActions[ i ].ActionData; + string defineValue = string.Empty; + if( actionData.StartsWith( "pragma" ) ) + { + defineValue = "#" + actionData; + } + else + { + defineValue = "#define " + validActions[ i ].ActionData; + } + if( isRefreshing ) + { + owner.ContainerGraph.ParentWindow.TemplatesManagerInstance.SetOptionsValue( defineValue, true ); + } + List<TemplateMultiPassMasterNode> nodes = owner.ContainerGraph.GetMultiPassMasterNodes( owner.LODIndex ); + int count = nodes.Count; + for( int nodeIdx = 0; nodeIdx < count; nodeIdx++ ) + { + nodes[ nodeIdx ].OptionsDefineContainer.AddDefine( defineValue, false ); + } + } + else if( !string.IsNullOrEmpty( validActions[ i ].PassName ) ) + { + TemplateMultiPassMasterNode passMasterNode = owner.ContainerGraph.GetMasterNodeOfPass( validActions[ i ].PassName, owner.LODIndex ); + if( passMasterNode != null ) + { + string actionData = validActions[ i ].ActionData; + string defineValue = string.Empty; + if( actionData.StartsWith( "pragma" ) ) + { + defineValue = "#" + actionData; + } + else + { + defineValue = "#define " + validActions[ i ].ActionData; + } + if( isRefreshing ) + { + string optionsId = validActions[ i ].PassName + defineValue; + owner.ContainerGraph.ParentWindow.TemplatesManagerInstance.SetOptionsValue( optionsId, true ); + } + passMasterNode.OptionsDefineContainer.AddDefine( defineValue, false ); + } + else + { + Debug.LogFormat( "Could not find pass {0} for action {1} on {2}", validActions[ i ].PassName, validActions[ i ].ActionType, validActions[ i ].ActionData ); + } + } + else + { + uiItem.CheckOnExecute = true; + } + } + break; + case AseOptionsActionType.RemoveDefine: + { + //Debug.Log( "UNDEFINE " + validActions[ i ].ActionData ); + if( validActions[ i ].AllPasses ) + { + string actionData = validActions[ i ].ActionData; + string defineValue = string.Empty; + if( actionData.StartsWith( "pragma" ) ) + { + defineValue = "#" + actionData; + } + else + { + defineValue = "#define " + validActions[ i ].ActionData; + } + + bool flag = false; + if( isRefreshing ) + { + flag = owner.ContainerGraph.ParentWindow.TemplatesManagerInstance.SetOptionsValue( defineValue, false ); + } + + if( !flag ) + { + List<TemplateMultiPassMasterNode> nodes = owner.ContainerGraph.GetMultiPassMasterNodes( owner.LODIndex ); + int count = nodes.Count; + for( int nodeIdx = 0; nodeIdx < count; nodeIdx++ ) + { + nodes[ nodeIdx ].OptionsDefineContainer.RemoveDefine( defineValue ); + } + } + } + else if( !string.IsNullOrEmpty( validActions[ i ].PassName ) ) + { + TemplateMultiPassMasterNode passMasterNode = owner.ContainerGraph.GetMasterNodeOfPass( validActions[ i ].PassName, owner.LODIndex ); + if( passMasterNode != null ) + { + string actionData = validActions[ i ].ActionData; + string defineValue = string.Empty; + if( actionData.StartsWith( "pragma" ) ) + { + defineValue = "#" + actionData; + } + else + { + defineValue = "#define " + validActions[ i ].ActionData; + } + bool flag = false; + if( isRefreshing ) + { + string optionId = validActions[ i ].PassName + defineValue; + flag = owner.ContainerGraph.ParentWindow.TemplatesManagerInstance.SetOptionsValue( optionId, false ); + } + if( !flag ) + { + passMasterNode.OptionsDefineContainer.RemoveDefine( defineValue ); + } + } + else + { + Debug.LogFormat( "Could not find pass {0} for action {1} on {2}", validActions[ i ].PassName, validActions[ i ].ActionType, validActions[ i ].ActionData ); + } + } + else + { + uiItem.CheckOnExecute = false; + } + } + break; + case AseOptionsActionType.SetUndefine: + { + if( !uiItem.IsVisible ) + { + uiItem.CheckOnExecute = true; + break; + } + + if( validActions[ i ].AllPasses ) + { + string defineValue = "#undef " + validActions[ i ].ActionData; + if( isRefreshing ) + { + owner.ContainerGraph.ParentWindow.TemplatesManagerInstance.SetOptionsValue( defineValue, true ); + } + List<TemplateMultiPassMasterNode> nodes = owner.ContainerGraph.GetMultiPassMasterNodes(owner.LODIndex); + int count = nodes.Count; + for( int nodeIdx = 0; nodeIdx < count; nodeIdx++ ) + { + nodes[ nodeIdx ].OptionsDefineContainer.AddDefine( defineValue, false ); + } + } + else if( !string.IsNullOrEmpty( validActions[ i ].PassName ) ) + { + TemplateMultiPassMasterNode passMasterNode = owner.ContainerGraph.GetMasterNodeOfPass( validActions[ i ].PassName, owner.LODIndex ); + if( passMasterNode != null ) + { + string defineValue = "#undef " + validActions[ i ].ActionData; + if( isRefreshing ) + { + string optionsId = validActions[ i ].PassName + defineValue; + owner.ContainerGraph.ParentWindow.TemplatesManagerInstance.SetOptionsValue( optionsId, true ); + } + passMasterNode.OptionsDefineContainer.AddDefine( defineValue, false ); + } + else + { + Debug.LogFormat( "Could not find pass {0} for action {1} on {2}", validActions[ i ].PassName, validActions[ i ].ActionType, validActions[ i ].ActionData ); + } + } + else + { + uiItem.CheckOnExecute = true; + } + } + break; + case AseOptionsActionType.RemoveUndefine: + { + if( validActions[ i ].AllPasses ) + { + string defineValue = "#undef " + validActions[ i ].ActionData; + bool flag = false; + if( isRefreshing ) + { + flag = owner.ContainerGraph.ParentWindow.TemplatesManagerInstance.SetOptionsValue( defineValue, false ); + } + + if( !flag ) + { + List<TemplateMultiPassMasterNode> nodes = owner.ContainerGraph.GetMultiPassMasterNodes( owner.LODIndex ); + int count = nodes.Count; + for( int nodeIdx = 0; nodeIdx < count; nodeIdx++ ) + { + nodes[ nodeIdx ].OptionsDefineContainer.RemoveDefine( defineValue ); + } + } + } + else if( !string.IsNullOrEmpty( validActions[ i ].PassName ) ) + { + TemplateMultiPassMasterNode passMasterNode = owner.ContainerGraph.GetMasterNodeOfPass( validActions[ i ].PassName, owner.LODIndex ); + if( passMasterNode != null ) + { + bool flag = false; + string defineValue = "#undef " + validActions[ i ].ActionData; + if( isRefreshing ) + { + string optionId = validActions[ i ].PassName + defineValue; + flag = owner.ContainerGraph.ParentWindow.TemplatesManagerInstance.SetOptionsValue( optionId, false ); + } + + if( !flag ) + { + passMasterNode.OptionsDefineContainer.RemoveDefine( defineValue ); + } + } + else + { + Debug.LogFormat( "Could not find pass {0} for action {1} on {2}", validActions[ i ].PassName, validActions[ i ].ActionType, validActions[ i ].ActionData ); + } + } + else + { + uiItem.CheckOnExecute = false; + } + } + break; + case AseOptionsActionType.ExcludePass: + { + string optionId = validActions[ i ].ActionData + "Pass"; + bool flag = isRefreshing ? owner.ContainerGraph.ParentWindow.TemplatesManagerInstance.SetOptionsValue( optionId, false ) : false; + if( !flag ) + owner.SetPassVisible( validActions[ i ].ActionData, false ); + } + break; + case AseOptionsActionType.IncludePass: + { + if( !uiItem.IsVisible ) + break; + + string optionId = validActions[ i ].ActionData + "Pass"; + owner.ContainerGraph.ParentWindow.TemplatesManagerInstance.SetOptionsValue( optionId, true ); + owner.SetPassVisible( validActions[ i ].ActionData, true ); + } + break; + case AseOptionsActionType.SetPropertyOnPass: + { + //Debug.Log( "PASSPROP " + validActions[ i ].ActionData ); + //Refresh happens on hotcode reload and shader load and in those situation + // The property own serialization handles its setup + if( isRefreshing ) + continue; + + if( !string.IsNullOrEmpty( validActions[ i ].PassName ) ) + { + TemplateMultiPassMasterNode passMasterNode = owner.ContainerGraph.GetMasterNodeOfPass( validActions[ i ].PassName, owner.LODIndex ); + if( passMasterNode != null ) + { + passMasterNode.SetPropertyActionFromItem( passMasterNode.PassModule, validActions[ i ] ); + } + else + { + Debug.LogFormat( "Could not find pass {0} for action {1} on {2}", validActions[ i ].PassName, validActions[ i ].ActionType, validActions[ i ].ActionData ); + } + } + else + { + owner.SetPropertyActionFromItem( owner.PassModule, validActions[ i ] ); + } + } + break; + case AseOptionsActionType.SetPropertyOnSubShader: + { + //Refresh happens on hotcode reload and shader load and in those situation + // The property own serialization handles its setup + if( isRefreshing ) + continue; + + owner.SetPropertyActionFromItem( owner.SubShaderModule, validActions[ i ] ); + } + break; + case AseOptionsActionType.SetShaderProperty: + { + //This action is only check when shader is compiled over + //the TemplateMultiPassMasterNode via the on CheckPropertyChangesOnOptions() method + } + break; + case AseOptionsActionType.SetMaterialProperty: + { + if( isRefreshing ) + continue; + + if( !uiItem.IsVisible ) + break; + + if( owner.ContainerGraph.CurrentMaterial != null ) + { + string prop = validActions[ i ].ActionData; + if( owner.ContainerGraph.CurrentMaterial.HasProperty( prop ) ) + { + if( uiItem.Options.UIWidget == AseOptionsUIWidget.Float || uiItem.Options.UIWidget == AseOptionsUIWidget.FloatRange ) + owner.ContainerGraph.CurrentMaterial.SetFloat( prop, uiItem.CurrentFieldValue ); + else + owner.ContainerGraph.CurrentMaterial.SetInt( prop, (int)uiItem.CurrentFieldValue ); + + if( ASEMaterialInspector.Instance != null ) + ASEMaterialInspector.Instance.Repaint(); + } + } + } + break; + } + } + } + + public void SetupCustomOptionsFromTemplate( TemplateMultiPassMasterNode owner, bool newTemplate ) + { + TemplateOptionsContainer customOptionsContainer = m_isSubShader ? owner.SubShader.CustomOptionsContainer : owner.Pass.CustomOptionsContainer; + + if( !newTemplate && customOptionsContainer.Body.Length == m_passCustomOptionsSizeCheck ) + { + for( int i = 0; i < m_passCustomOptionsUI.Count; i++ ) + { + if( m_passCustomOptionsUI[ i ].EmptyEvent ) + { + if( m_isSubShader ) + { + m_passCustomOptionsUI[ i ].OnActionPerformedEvt += owner.OnCustomSubShaderOptionSelected; + } + else + { + m_passCustomOptionsUI[ i ].OnActionPerformedEvt += owner.OnCustomPassOptionSelected; + } + } + } + return; + } + + m_passCustomOptionsLabel = string.IsNullOrEmpty( customOptionsContainer.Name ) ? CustomOptionsLabel : " " + customOptionsContainer.Name; + + for( int i = 0; i < m_passCustomOptionsUI.Count; i++ ) + { + m_passCustomOptionsUI[ i ].Destroy(); + } + + m_passCustomOptionsUI.Clear(); + m_passCustomOptionsUIDict.Clear(); + m_passCustomOptionsPorts.Clear(); + + if( customOptionsContainer.Enabled ) + { + m_passCustomOptionsSizeCheck = customOptionsContainer.Body.Length; + for( int i = 0; i < customOptionsContainer.Options.Length; i++ ) + { + switch( customOptionsContainer.Options[ i ].Type ) + { + case AseOptionsType.Option: + { + TemplateOptionUIItem item = new TemplateOptionUIItem( customOptionsContainer.Options[ i ] ); + if( m_isSubShader ) + { + item.OnActionPerformedEvt += owner.OnCustomSubShaderOptionSelected; + } + else + { + item.OnActionPerformedEvt += owner.OnCustomPassOptionSelected; + } + + m_passCustomOptionsUI.Add( item ); + m_passCustomOptionsUIDict.Add( customOptionsContainer.Options[ i ].Id, item ); + } + break; + case AseOptionsType.Port: + { + TemplateOptionPortItem item = new TemplateOptionPortItem( owner, customOptionsContainer.Options[ i ] ); + m_passCustomOptionsPorts.Add( item ); + //if( m_isSubShader ) + //{ + // if( string.IsNullOrEmpty( customOptionsContainer.Options[ i ].Id ) ) + // { + // //No pass name selected. inject on all passes + // TemplateOptionPortItem item = new TemplateOptionPortItem( owner, customOptionsContainer.Options[ i ] ); + // m_passCustomOptionsPorts.Add( item ); + // } + // else if( customOptionsContainer.Options[ i ].Id.Equals( owner.PassName ) ) + // { + // TemplateOptionPortItem item = new TemplateOptionPortItem( owner, customOptionsContainer.Options[ i ] ); + // m_passCustomOptionsPorts.Add( item ); + // } + //} + //else + //{ + // TemplateOptionPortItem item = new TemplateOptionPortItem( owner, customOptionsContainer.Options[ i ] ); + // m_passCustomOptionsPorts.Add( item ); + //} + } + break; + case AseOptionsType.Field: + { + TemplateOptionUIItem item = new TemplateOptionUIItem( customOptionsContainer.Options[ i ] ); + if( m_isSubShader ) + { + item.OnActionPerformedEvt += owner.OnCustomSubShaderOptionSelected; + } + else + { + item.OnActionPerformedEvt += owner.OnCustomPassOptionSelected; + } + + m_passCustomOptionsUI.Add( item ); + m_passCustomOptionsUIDict.Add( customOptionsContainer.Options[ i ].Id, item ); + } + break; + } + } + } + else + { + m_passCustomOptionsSizeCheck = 0; + } + } + + public void SetCustomOptionsInfo( TemplateMultiPassMasterNode masterNode, ref MasterNodeDataCollector dataCollector ) + { + if( masterNode == null ) + return; + + for( int i = 0; i < m_passCustomOptionsUI.Count; i++ ) + { + m_passCustomOptionsUI[ i ].FillDataCollector( ref dataCollector ); + } + + for( int i = 0; i < m_passCustomOptionsPorts.Count; i++ ) + { + m_passCustomOptionsPorts[ i ].FillDataCollector( masterNode, ref dataCollector ); + } + } + + public void CheckImediateActionsForPort( TemplateMultiPassMasterNode masterNode , int portId ) + { + for( int i = 0; i < m_passCustomOptionsPorts.Count; i++ ) + { + m_passCustomOptionsPorts[ i ].CheckImediateActionsForPort( masterNode, portId ); + } + } + + public void SetSubShaderCustomOptionsPortsInfo( TemplateMultiPassMasterNode masterNode, ref MasterNodeDataCollector dataCollector ) + { + if( masterNode == null ) + return; + + + //for( int i = 0; i < m_passCustomOptionsPorts.Count; i++ ) + //{ + // if( string.IsNullOrEmpty( m_passCustomOptionsPorts[ i ].Options.Id ) || + // masterNode.PassUniqueName.Equals( m_passCustomOptionsPorts[ i ].Options.Id ) ) + // { + // m_passCustomOptionsPorts[ i ].FillDataCollector( masterNode, ref dataCollector ); + // } + //} + + for( int i = 0; i < m_passCustomOptionsPorts.Count; i++ ) + { + m_passCustomOptionsPorts[ i ].SubShaderFillDataCollector( masterNode, ref dataCollector ); + } + } + + public void RefreshCustomOptionsDict() + { + if( m_passCustomOptionsUIDict.Count != m_passCustomOptionsUI.Count ) + { + m_passCustomOptionsUIDict.Clear(); + int count = m_passCustomOptionsUI.Count; + for( int i = 0; i < count; i++ ) + { + m_passCustomOptionsUIDict.Add( m_passCustomOptionsUI[ i ].Options.Id, m_passCustomOptionsUI[ i ] ); + } + } + } + + public void ReadFromString( ref uint index, ref string[] nodeParams ) + { + RefreshCustomOptionsDict(); + int savedOptions = Convert.ToInt32( nodeParams[ index++ ] ); + + m_readOptionNames = new string[ savedOptions ]; + m_readOptionSelections = new string[ savedOptions ]; + + for( int i = 0; i < savedOptions; i++ ) + { + string optionName = nodeParams[ index++ ]; + string optionSelection = nodeParams[ index++ ]; + m_readOptionNames[ i ] = optionName; + m_readOptionSelections[ i ] = optionSelection; + + } + } + + public void SetReadOptions() + { + if( m_readOptionNames != null && m_readOptionSelections != null ) + { + for( int i = 0; i < m_readOptionNames.Length; i++ ) + { + if( m_passCustomOptionsUIDict.ContainsKey( m_readOptionNames[ i ] ) ) + { + if( m_passCustomOptionsUIDict[ m_readOptionNames[ i ] ].Options.Type == AseOptionsType.Field ) + { + m_passCustomOptionsUIDict[ m_readOptionNames[ i ] ].FieldValue.ReadFromSingle( m_readOptionSelections[ i ] ); + foreach( var item in m_passCustomOptionsUIDict[ m_readOptionNames[ i ] ].Options.ActionsPerOption.Rows ) + { + if( item.Columns.Length>0 && item.Columns[ 0 ].ActionType == AseOptionsActionType.SetMaterialProperty ) + { + if( UIUtils.CurrentWindow.CurrentGraph.CurrentMaterial != null ) + { + if( UIUtils.CurrentWindow.CurrentGraph.CurrentMaterial.HasProperty( item.Columns[ 0 ].ActionData ) ) + { + m_passCustomOptionsUIDict[ m_readOptionNames[ i ] ].CurrentFieldValue = UIUtils.CurrentWindow.CurrentGraph.CurrentMaterial.GetFloat( item.Columns[ 0 ].ActionData ); + } + } + } + } + } + else + m_passCustomOptionsUIDict[ m_readOptionNames[ i ] ].CurrentOptionIdx = Convert.ToInt32( m_readOptionSelections[ i ] ); + } + } + } + } + + public void Refresh() + { + int count = m_passCustomOptionsUI.Count; + for( int i = 0; i < count; i++ ) + { + m_passCustomOptionsUI[ i ].Refresh(); + } + } + + public void CheckDisable() + { + int count = m_passCustomOptionsUI.Count; + for( int i = 0; i < count; i++ ) + { + m_passCustomOptionsUI[ i ].CheckEnDisable(); + } + } + + public void WriteToString( ref string nodeInfo ) + { + int optionsCount = m_passCustomOptionsUI.Count; + IOUtils.AddFieldValueToString( ref nodeInfo, optionsCount ); + for( int i = 0; i < optionsCount; i++ ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_passCustomOptionsUI[ i ].Options.Id ); + if( m_passCustomOptionsUI[ i ].Options.Type == AseOptionsType.Field ) + IOUtils.AddFieldValueToString( ref nodeInfo, m_passCustomOptionsUI[ i ].FieldValue.WriteToSingle() ); + else + IOUtils.AddFieldValueToString( ref nodeInfo, m_passCustomOptionsUI[ i ].CurrentOption ); + } + } + + public List<TemplateOptionUIItem> PassCustomOptionsUI { get { return m_passCustomOptionsUI; } } + + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsUIHelper.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsUIHelper.cs.meta new file mode 100644 index 00000000..077260b0 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateOptionsUIHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 389dcf32e61ce9d47b9a92ab691365d3 +timeCreated: 1544089703 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePass.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePass.cs new file mode 100644 index 00000000..22ea92f4 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePass.cs @@ -0,0 +1,631 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> +#define CUSTOM_OPTIONS_AVAILABLE +using UnityEngine; +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace AmplifyShaderEditor +{ + + [Serializable] + public class TemplatePass + { + private const string DefaultPassNameStr = "SubShader {0} Pass {1}"; + + [SerializeField] + private int m_idx = -1; + + [SerializeField] + private bool m_isInvisible = false; + + [SerializeField] + private int m_invisibleOptions = 0; + + [SerializeField] + private bool m_isMainPass = false; + + [SerializeField] + private TemplateModulesData m_modules; + + [SerializeField] + private List<TemplateInputData> m_inputDataList = new List<TemplateInputData>(); + private Dictionary<int, TemplateInputData> m_inputDataDict = new Dictionary<int, TemplateInputData>(); + + [SerializeField] + private TemplateFunctionData m_vertexFunctionData; + + [SerializeField] + private TemplateFunctionData m_fragmentFunctionData; + + [SerializeField] + private VertexDataContainer m_vertexDataContainer; + + [SerializeField] + private TemplateInterpData m_interpolatorDataContainer; + + [SerializeField] + private TemplateTessVControlTag m_tessVControlTag; + + [SerializeField] + private TemplateTessControlData m_tessControlData; + + [SerializeField] + private TemplateTessDomainData m_tessDomainData; + + [SerializeField] + private List<TemplateLocalVarData> m_localVarsList = new List<TemplateLocalVarData>(); + + [SerializeField] + private string m_uniquePrefix; + + [SerializeField] + private TemplatePropertyContainer m_templateProperties = new TemplatePropertyContainer(); + + [SerializeField] + private List<TemplateShaderPropertyData> m_availableShaderGlobals = new List<TemplateShaderPropertyData>(); + + [SerializeField] + TemplateInfoContainer m_passNameContainer = new TemplateInfoContainer(); +#if CUSTOM_OPTIONS_AVAILABLE + [SerializeField] + TemplateOptionsContainer m_customOptionsContainer = new TemplateOptionsContainer(); +#endif + public TemplatePass( TemplateMultiPass template, TemplateSubShader subShader, int subshaderIdx, int passIdx, TemplateIdManager idManager, string uniquePrefix, int offsetIdx, TemplatePassInfo passInfo, ref Dictionary<string, TemplateShaderPropertyData> duplicatesHelper ) + { + m_idx = passIdx; + + m_uniquePrefix = uniquePrefix; + idManager.RegisterPassId( passInfo.Data ); + m_isMainPass = passInfo.Data.Contains( TemplatesManager.TemplateMainPassTag ); + if( !m_isMainPass ) + { + string id = string.Empty; + int idIndex = 0; + m_isInvisible = TemplateHelperFunctions.FetchInvisibleInfo( passInfo.Data, ref m_invisibleOptions, ref id, ref idIndex ); + if( m_isInvisible ) + { + idManager.RegisterId( idIndex, uniquePrefix + id, id, true ); + } + } + + FetchPassName( offsetIdx, passInfo.Data ); + if( m_passNameContainer.Index > -1 ) + { + idManager.RegisterId( m_passNameContainer.Index, uniquePrefix + m_passNameContainer.Id, m_passNameContainer.Id ); + } + else + { + m_passNameContainer.Data = string.Format( DefaultPassNameStr, subshaderIdx, passIdx ); + } + +#if CUSTOM_OPTIONS_AVAILABLE + m_customOptionsContainer = TemplateOptionsToolsHelper.GenerateOptionsContainer( false, passInfo.Data ); + if( m_customOptionsContainer.Enabled ) + { + idManager.RegisterId( m_customOptionsContainer.Index, uniquePrefix + m_customOptionsContainer.Body, m_customOptionsContainer.Body, true ); + } + //m_customOptionsContainer.CopyPortOptionsFrom( subShader.CustomOptionsContainer, m_passNameContainer.Data ); +#endif + m_modules = new TemplateModulesData( m_customOptionsContainer,idManager, m_templateProperties, uniquePrefix + "Module", offsetIdx, passInfo.Data, false ); + + if( !m_modules.PassTag.IsValid ) + { + m_modules.PassTag.StartIdx = passInfo.GlobalStartIdx; + m_templateProperties.AddId( passInfo.Data, m_modules.PassTag.Id, passInfo.LocalStartIdx, false ); + //m_modules.PassTag.StartIdx -= m_templateProperties.PropertyDict[ m_modules.PassTag.Id ].Indentation.Length; + //m_templateProperties.PropertyDict[ m_modules.PassTag.Id ].UseIndentationAtStart = false; + idManager.RegisterId( m_modules.PassTag.StartIdx, m_modules.UniquePrefix + m_modules.PassTag.Id, string.Empty ); + } + m_modules.SetPassUniqueNameIfUndefined( m_passNameContainer.Data ); + + m_modules.SRPType = subShader.Modules.SRPType; + if( m_modules.SRPType == TemplateSRPType.HD ) + { + m_modules.SRPIsPBR = passInfo.Data.Contains( TemplateHelperFunctions.HDPBRTag ); + + } + + Dictionary<string, TemplateShaderPropertyData> ownDuplicatesDict = new Dictionary<string, TemplateShaderPropertyData>( duplicatesHelper ); + TemplateHelperFunctions.CreateShaderGlobalsList( passInfo.Data, ref m_availableShaderGlobals, ref ownDuplicatesDict ); + + // Vertex and Interpolator data + FetchVertexAndInterpData( template, subShader.Modules, offsetIdx, passInfo.Data ); + if( m_vertexDataContainer != null ) + idManager.RegisterId( m_vertexDataContainer.VertexDataStartIdx, uniquePrefix + m_vertexDataContainer.VertexDataId, m_vertexDataContainer.VertexDataId ); + + if( m_interpolatorDataContainer != null ) + idManager.RegisterId( m_interpolatorDataContainer.InterpDataStartIdx, uniquePrefix + m_interpolatorDataContainer.InterpDataId, m_interpolatorDataContainer.InterpDataId ); + + //Fetch function code areas + FetchCodeAreas( offsetIdx, TemplatesManager.TemplateVertexCodeBeginArea, MasterNodePortCategory.Vertex, passInfo.Data ); + if( m_vertexFunctionData != null ) + idManager.RegisterId( m_vertexFunctionData.Position, uniquePrefix + m_vertexFunctionData.Id, m_vertexFunctionData.Id ); + + FetchCodeAreas( offsetIdx, TemplatesManager.TemplateFragmentCodeBeginArea, MasterNodePortCategory.Fragment, passInfo.Data ); + if( m_fragmentFunctionData != null ) + idManager.RegisterId( m_fragmentFunctionData.Position, uniquePrefix + m_fragmentFunctionData.Id, m_fragmentFunctionData.Id ); + + //Fetching inputs, must be do + if( m_fragmentFunctionData != null ) + FetchInputs( offsetIdx, MasterNodePortCategory.Fragment, passInfo.Data ); + + if( m_vertexFunctionData != null ) + FetchInputs( offsetIdx, MasterNodePortCategory.Vertex, passInfo.Data ); + + FetchTessellationData( template, subShader.Modules, offsetIdx, passInfo.Data ); + if( m_tessVControlTag != null ) + idManager.RegisterId( m_tessVControlTag.StartIdx, uniquePrefix + m_tessVControlTag.Id, m_tessVControlTag.Id ); + + if( m_tessControlData != null ) + idManager.RegisterId( m_tessControlData.StartIdx, uniquePrefix + m_tessControlData.Id, m_tessControlData.Id ); + + if( m_tessDomainData != null ) + idManager.RegisterId( m_tessDomainData.StartIdx, uniquePrefix + m_tessDomainData.Id, m_tessDomainData.Id ); + + TemplateHelperFunctions.FetchInlineVars( passInfo.Data, ref idManager ); + + //Fetch local variables must be done after fetching code areas as it needs them to see is variable is on vertex or fragment + TemplateHelperFunctions.FetchLocalVars( passInfo.Data, ref m_localVarsList, m_vertexFunctionData, m_fragmentFunctionData ); + + int localVarCount = m_localVarsList.Count; + if( localVarCount > 0 ) + { + idManager.RegisterTag( TemplatesManager.TemplateLocalVarTag ); + for( int i = 0; i < localVarCount; i++ ) + { + if( m_localVarsList[ i ].IsSpecialVar ) + { + idManager.RegisterTag( m_localVarsList[ i ].Id ); + } + } + } + + int inputsCount = m_inputDataList.Count; + for( int i = 0; i < inputsCount; i++ ) + { + if( m_inputDataList[ i ] != null ) + idManager.RegisterId( m_inputDataList[ i ].TagGlobalStartIdx, uniquePrefix + m_inputDataList[ i ].TagId, m_inputDataList[ i ].TagId ); + } + + //int passEndIndex = passInfo.Data.LastIndexOf( "}" ); + //if( passEndIndex > 0 ) + //{ + // int identationIndex = -1; + // for( int i = passEndIndex; i >= 0; i-- ) + // { + // if( passInfo.Data[ i ] == TemplatesManager.TemplateNewLine ) + // { + // identationIndex = i + 1; + // break; + // } + + // if( i == 0 ) + // { + // identationIndex = 0; + // } + // } + + // if( identationIndex > -1 ) + // { + // int length = passEndIndex - identationIndex; + // string indentation = ( length > 0 ) ? passInfo.Data.Substring( identationIndex, length ) : string.Empty; + // TemplateProperty templateProperty = new TemplateProperty( TemplatesManager.TemplateEndPassTag, indentation, false ); + // m_templateProperties.AddId( templateProperty ); + // idManager.RegisterId( offsetIdx + passEndIndex, uniquePrefix + TemplatesManager.TemplateEndPassTag, string.Empty ); + // } + //} + + ownDuplicatesDict.Clear(); + ownDuplicatesDict = null; + } + + public void Destroy() + { + m_passNameContainer = null; +#if CUSTOM_OPTIONS_AVAILABLE + m_customOptionsContainer = null; +#endif + if( m_templateProperties != null ) + m_templateProperties.Destroy(); + + m_templateProperties = null; + + if( m_modules != null ) + m_modules.Destroy(); + + m_modules = null; + + if( m_inputDataList != null ) + m_inputDataList.Clear(); + + m_inputDataList = null; + + if( m_inputDataDict != null ) + m_inputDataDict.Clear(); + + m_inputDataDict = null; + + m_vertexFunctionData = null; + m_fragmentFunctionData = null; + + if( m_vertexDataContainer != null ) + m_vertexDataContainer.Destroy(); + + m_vertexDataContainer = null; + + m_tessVControlTag = null; + + m_tessControlData = null; + + m_tessDomainData = null; + + if( m_interpolatorDataContainer != null ) + m_interpolatorDataContainer.Destroy(); + + if( m_localVarsList != null ) + { + m_localVarsList.Clear(); + m_localVarsList = null; + } + + m_interpolatorDataContainer = null; + + if( m_availableShaderGlobals != null ) + m_availableShaderGlobals.Clear(); + + m_availableShaderGlobals = null; + } + + public TemplateInputData InputDataFromId( int id ) + { + if( m_inputDataDict == null ) + m_inputDataDict = new Dictionary<int, TemplateInputData>(); + + if( m_inputDataDict.Count != m_inputDataList.Count ) + { + m_inputDataDict.Clear(); + for( int i = 0; i < m_inputDataList.Count; i++ ) + { + m_inputDataDict.Add( m_inputDataList[ i ].PortUniqueId, m_inputDataList[ i ] ); + } + } + + if( m_inputDataDict.ContainsKey( id ) ) + return m_inputDataDict[ id ]; + + return null; + } + + void FetchPassName( int offsetIdx, string body ) + { + Match match = Regex.Match( body, TemplateHelperFunctions.PassNamePattern ); + if( match != null && match.Groups.Count > 1 ) + { + m_passNameContainer.Id = match.Groups[ 0 ].Value; + m_passNameContainer.Data = match.Groups[ 1 ].Value; + m_passNameContainer.Index = offsetIdx + match.Index; + } + } + + void FetchTessellationData( TemplateMultiPass template, TemplateModulesData subShaderModule, int offsetIdx, string body ) + { + // Tessellation VControl Tag + try + { + int vcontrolcodeBegin = body.IndexOf( TemplatesManager.TemplateTessVControlTag ); + if( vcontrolcodeBegin > -1 ) + { + m_tessVControlTag = new TemplateTessVControlTag(); + m_tessVControlTag.Id = TemplatesManager.TemplateTessVControlTag; + m_tessVControlTag.StartIdx = offsetIdx + vcontrolcodeBegin; + + m_templateProperties.AddId( body, m_tessVControlTag.Id ); + } + } + catch( Exception e ) + { + Debug.LogException( e ); + } + + // Tessellation Control Data + try + { + int controlCodeBegin = body.IndexOf( TemplatesManager.TemplateTessControlCodeArea ); + if( controlCodeBegin > -1 ) + { + int beginIdx = controlCodeBegin + TemplatesManager.TemplateTessControlCodeArea.Length; + int endIdx = body.IndexOf( TemplatesManager.TemplateEndOfLine, beginIdx ); + int length = endIdx - beginIdx; + + string parameters = body.Substring( beginIdx, length ); + + string[] parametersArr = parameters.Split( IOUtils.FIELD_SEPARATOR ); + + string id = body.Substring( controlCodeBegin, endIdx + TemplatesManager.TemplateEndOfLine.Length - controlCodeBegin ); + string inParameters = parametersArr[ 0 ]; + string outParameters = ( parametersArr.Length > 1 ) ? parametersArr[ 1 ] : string.Empty; + + m_tessControlData = new TemplateTessControlData( offsetIdx + controlCodeBegin, id, inParameters, outParameters ); + + m_templateProperties.AddId( body, id ); + } + } + catch( Exception e ) + { + Debug.LogException( e ); + } + + // Tessellation Domain Data + try + { + int domainCodeBegin = body.IndexOf( TemplatesManager.TemplateTessDomainCodeArea ); + if( domainCodeBegin > -1 ) + { + int beginIdx = domainCodeBegin + TemplatesManager.TemplateTessDomainCodeArea.Length; + int endIdx = body.IndexOf( TemplatesManager.TemplateEndOfLine, beginIdx ); + int length = endIdx - beginIdx; + + string parameters = body.Substring( beginIdx, length ); + + string[] parametersArr = parameters.Split( IOUtils.FIELD_SEPARATOR ); + + string id = body.Substring( domainCodeBegin, endIdx + TemplatesManager.TemplateEndOfLine.Length - domainCodeBegin ); + string inParameters = ( parametersArr.Length > 0 ) ? parametersArr[ 0 ] : string.Empty; + string outParameters = ( parametersArr.Length > 1 ) ? parametersArr[ 1 ] : string.Empty; + string baryParameters = ( parametersArr.Length > 2 ) ? parametersArr[ 2 ] : string.Empty; + + m_tessDomainData = new TemplateTessDomainData( offsetIdx + domainCodeBegin, id, inParameters, outParameters, baryParameters ); + + m_templateProperties.AddId( body, id ); + } + } + catch( Exception e ) + { + Debug.LogException( e ); + } + } + + void FetchVertexAndInterpData(TemplateMultiPass template, TemplateModulesData subShaderModule, int offsetIdx, string body ) + { + // Vertex Data + try + { + int vertexDataTagBegin = body.IndexOf( TemplatesManager.TemplateVertexDataTag ); + if( vertexDataTagBegin > -1 ) + { + m_vertexDataContainer = new VertexDataContainer(); + m_vertexDataContainer.VertexDataStartIdx = offsetIdx + vertexDataTagBegin; + int vertexDataTagEnd = body.IndexOf( TemplatesManager.TemplateEndOfLine, vertexDataTagBegin ); + m_vertexDataContainer.VertexDataId = body.Substring( vertexDataTagBegin, vertexDataTagEnd + TemplatesManager.TemplateEndOfLine.Length - vertexDataTagBegin ); + int dataBeginIdx = body.LastIndexOf( '{', vertexDataTagBegin, vertexDataTagBegin ); + string vertexData = body.Substring( dataBeginIdx + 1, vertexDataTagBegin - dataBeginIdx ); + + int parametersBegin = vertexDataTagBegin + TemplatesManager.TemplateVertexDataTag.Length; + string parameters = body.Substring( parametersBegin, vertexDataTagEnd - parametersBegin ); + m_vertexDataContainer.VertexData = TemplateHelperFunctions.CreateVertexDataList( vertexData, parameters ); + m_templateProperties.AddId( body, m_vertexDataContainer.VertexDataId ); + } + } + catch( Exception e ) + { + Debug.LogException( e ); + } + + // Available interpolators + try + { + int interpDataBegin = body.IndexOf( TemplatesManager.TemplateInterpolatorBeginTag ); + if( interpDataBegin > -1 ) + { + int interpDataEnd = body.IndexOf( TemplatesManager.TemplateEndOfLine, interpDataBegin ); + string interpDataId = body.Substring( interpDataBegin, interpDataEnd + TemplatesManager.TemplateEndOfLine.Length - interpDataBegin ); + + int dataBeginIdx = body.LastIndexOf( '{', interpDataBegin, interpDataBegin ); + string interpData = body.Substring( dataBeginIdx + 1, interpDataBegin - dataBeginIdx ); + + int interpolatorAmount = TemplateHelperFunctions.AvailableInterpolators[ "2.5" ]; + + if( m_modules.ShaderModel.IsValid ) + { + interpolatorAmount = m_modules.ShaderModel.InterpolatorAmount; + } + else if( subShaderModule.ShaderModel.IsValid ) + { + interpolatorAmount = subShaderModule.ShaderModel.InterpolatorAmount; + } + else if( template.GlobalShaderModel.IsValid ) + { + interpolatorAmount = template.GlobalShaderModel.InterpolatorAmount; + } + + m_interpolatorDataContainer = TemplateHelperFunctions.CreateInterpDataList( interpData, interpDataId, interpolatorAmount ); + m_interpolatorDataContainer.InterpDataId = interpDataId; + m_interpolatorDataContainer.InterpDataStartIdx = offsetIdx + interpDataBegin; + m_templateProperties.AddId( body, interpDataId ); + + } + } + catch( Exception e ) + { + Debug.LogException( e ); + } + } + + void FetchCodeAreas( int offsetIdx, string begin, MasterNodePortCategory category, string body ) + { + int areaBeginIndexes = body.IndexOf( begin ); + if( areaBeginIndexes > -1 ) + { + int beginIdx = areaBeginIndexes + begin.Length; + int endIdx = body.IndexOf( TemplatesManager.TemplateEndOfLine, beginIdx ); + int length = endIdx - beginIdx; + + string parameters = body.Substring( beginIdx, length ); + + string[] parametersArr = parameters.Split( IOUtils.FIELD_SEPARATOR ); + + string id = body.Substring( areaBeginIndexes, endIdx + TemplatesManager.TemplateEndOfLine.Length - areaBeginIndexes ); + string inParameters = parametersArr[ 0 ]; + string outParameters = ( parametersArr.Length > 1 ) ? parametersArr[ 1 ] : string.Empty; + if( category == MasterNodePortCategory.Fragment ) + { + string mainBodyName = string.Empty; + int mainBodyLocalIndex = -1; + + Match mainBodyNameMatch = Regex.Match( body, TemplateHelperFunctions.FragmentPragmaPattern ); + if( mainBodyNameMatch != null && mainBodyNameMatch.Groups.Count == 2 ) + { + mainBodyName = mainBodyNameMatch.Groups[ 1 ].Value; + string pattern = string.Format( TemplateHelperFunctions.FunctionBodyStartPattern, mainBodyName ); + Match mainBodyIdMatch = Regex.Match( body, pattern ); + if( mainBodyIdMatch != null && mainBodyIdMatch.Groups.Count > 0 ) + { + mainBodyLocalIndex = mainBodyIdMatch.Index; + } + + } + + m_fragmentFunctionData = new TemplateFunctionData( mainBodyLocalIndex, mainBodyName, id, offsetIdx + areaBeginIndexes, inParameters, outParameters, category ); + } + else + { + string mainBodyName = string.Empty; + int mainBodyLocalIndex = -1; + + Match mainBodyNameMatch = Regex.Match( body, TemplateHelperFunctions.VertexPragmaPattern ); + if( mainBodyNameMatch != null && mainBodyNameMatch.Groups.Count == 2 ) + { + mainBodyName = mainBodyNameMatch.Groups[ 1 ].Value; + string pattern = string.Format( TemplateHelperFunctions.FunctionBodyStartPattern, mainBodyName ); + Match mainBodyIdMatch = Regex.Match( body, pattern ); + if( mainBodyIdMatch != null && mainBodyIdMatch.Groups.Count > 0 ) + { + mainBodyLocalIndex = mainBodyIdMatch.Index; + } + } + + m_vertexFunctionData = new TemplateFunctionData( mainBodyLocalIndex, mainBodyName, id, offsetIdx + areaBeginIndexes, inParameters, outParameters, category ); + } + m_templateProperties.AddId( body, id, true ); + } + } + + void FetchInputs( int offset, MasterNodePortCategory portCategory, string body ) + { + string beginTag = ( portCategory == MasterNodePortCategory.Fragment ) ? TemplatesManager.TemplateInputsFragBeginTag : TemplatesManager.TemplateInputsVertBeginTag; + int[] inputBeginIndexes = body.AllIndexesOf( beginTag ); + if( inputBeginIndexes != null && inputBeginIndexes.Length > 0 ) + { + for( int i = 0; i < inputBeginIndexes.Length; i++ ) + { + int inputEndIdx = body.IndexOf( TemplatesManager.TemplateEndSectionTag, inputBeginIndexes[ i ] ); + int defaultValueBeginIdx = inputEndIdx + TemplatesManager.TemplateEndSectionTag.Length; + int endLineIdx = body.IndexOf( TemplatesManager.TemplateFullEndTag, defaultValueBeginIdx ); + + string defaultValue = body.Substring( defaultValueBeginIdx, endLineIdx - defaultValueBeginIdx ); + string tagId = body.Substring( inputBeginIndexes[ i ], endLineIdx + TemplatesManager.TemplateFullEndTag.Length - inputBeginIndexes[ i ] ); + + int beginIndex = inputBeginIndexes[ i ] + beginTag.Length; + int length = inputEndIdx - beginIndex; + string inputData = body.Substring( beginIndex, length ); + string[] inputDataArray = inputData.Split( IOUtils.FIELD_SEPARATOR ); + + if( inputDataArray != null && inputDataArray.Length > 0 ) + { + try + { + string portName = inputDataArray[ (int)TemplatePortIds.Name ]; + WirePortDataType dataType = (WirePortDataType)Enum.Parse( typeof( WirePortDataType ), inputDataArray[ (int)TemplatePortIds.DataType ].ToUpper() ); + if( inputDataArray.Length == 3 ) + { + int portOrderId = m_inputDataList.Count; + int portUniqueId = -1; + bool isInt = int.TryParse( inputDataArray[ 2 ], out portUniqueId ); + if( isInt ) + { + if( portUniqueId < 0 ) + portUniqueId = m_inputDataList.Count; + + m_inputDataList.Add( new TemplateInputData( inputBeginIndexes[ i ], offset + inputBeginIndexes[ i ], tagId, portName, defaultValue, dataType, portCategory, portUniqueId, portOrderId, string.Empty ) ); + m_templateProperties.AddId( body, tagId, false ); + } + else + { + portUniqueId = m_inputDataList.Count; + m_inputDataList.Add( new TemplateInputData( inputBeginIndexes[ i ], offset + inputBeginIndexes[ i ], tagId, portName, defaultValue, dataType, portCategory, portUniqueId, portOrderId, inputDataArray[ 2 ] ) ); + m_templateProperties.AddId( body, tagId, false ); + } + } + else + { + int portUniqueIDArrIdx = (int)TemplatePortIds.UniqueId; + int portUniqueId = ( portUniqueIDArrIdx < inputDataArray.Length ) ? Convert.ToInt32( inputDataArray[ portUniqueIDArrIdx ] ) : -1; + if( portUniqueId < 0 ) + portUniqueId = m_inputDataList.Count; + + int portOrderArrayIdx = (int)TemplatePortIds.OrderId; + int portOrderId = ( portOrderArrayIdx < inputDataArray.Length ) ? Convert.ToInt32( inputDataArray[ portOrderArrayIdx ] ) : -1; + if( portOrderId < 0 ) + portOrderId = m_inputDataList.Count; + + int portLinkIdx = (int)TemplatePortIds.Link; + string linkId = ( portLinkIdx < inputDataArray.Length ) ? inputDataArray[ portLinkIdx ] : string.Empty; + m_inputDataList.Add( new TemplateInputData( inputBeginIndexes[ i ], offset + inputBeginIndexes[ i ], tagId, portName, defaultValue, dataType, portCategory, portUniqueId, portOrderId, linkId ) ); + m_templateProperties.AddId( body, tagId, false ); + } + } + catch( Exception e ) + { + Debug.LogException( e ); + } + } + } + } + } + +#if CUSTOM_OPTIONS_AVAILABLE + public TemplateOptionsContainer CustomOptionsContainer { get { return m_customOptionsContainer; } } +#endif + public TemplateModulesData Modules { get { return m_modules; } } + public List<TemplateInputData> InputDataList { get { return m_inputDataList; } } + public TemplateFunctionData VertexFunctionData { get { return m_vertexFunctionData; } } + public TemplateFunctionData FragmentFunctionData { get { return m_fragmentFunctionData; } } + public VertexDataContainer VertexDataContainer { get { return m_vertexDataContainer; } } + public TemplateInterpData InterpolatorDataContainer { get { return m_interpolatorDataContainer; } } + public TemplateTessVControlTag TessVControlTag { get { return m_tessVControlTag; } } + public TemplateTessControlData TessControlData { get { return m_tessControlData; } } + public TemplateTessDomainData TessDomainData { get { return m_tessDomainData; } } + public string UniquePrefix { get { return m_uniquePrefix; } } + public TemplatePropertyContainer TemplateProperties { get { return m_templateProperties; } } + public List<TemplateShaderPropertyData> AvailableShaderGlobals { get { return m_availableShaderGlobals; } } + public List<TemplateLocalVarData> LocalVarsList { get { return m_localVarsList; } } + public TemplateInfoContainer PassNameContainer { get { return m_passNameContainer; } } + public bool IsMainPass { get { return m_isMainPass; } set { m_isMainPass = value; } } + public bool IsInvisible { get { return m_isInvisible; } } + public int InvisibleOptions { get { return m_invisibleOptions; } } + public int Idx { get { return m_idx; } } + public bool AddToList + { + get + { + if( m_isInvisible ) + { + return ( m_inputDataList.Count > 0 ); + } + + return true; + } + } + public bool HasValidFunctionBody + { + get + { + if( m_fragmentFunctionData != null || m_vertexFunctionData != null ) + return true; + return false; + } + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePass.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePass.cs.meta new file mode 100644 index 00000000..e36dee49 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePass.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1e6749bf88e2d0f4ab5812f084973f4c +timeCreated: 1517831575 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePassSelectorHelper.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePassSelectorHelper.cs new file mode 100644 index 00000000..e85a92d3 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePassSelectorHelper.cs @@ -0,0 +1,167 @@ +using UnityEditor; +using UnityEngine; +using System; +using System.Collections.Generic; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class PassVisibleOptionsItems + { + public bool Visible; + public string Name; + public int Idx = -1; + } + + [Serializable] + public class TemplatePassSelectorHelper + { + private const string Label = " Available Passes"; + + [SerializeField] + private bool m_foldout; + + [SerializeField] + private PassVisibleOptionsItems[] m_currentPasses; + + [NonSerialized] + private Dictionary<string, PassVisibleOptionsItems> m_currentPassesDict; + + [SerializeField] + private int m_mainPassId; + + public void CopyFrom( TemplatePassSelectorHelper from ) + { + for( int i = 0; i < from.AvailablePasses.Length; i++ ) + { + SetPassVisible( from.AvailablePasses[ i ].Name, from.AvailablePasses[ i ].Visible ); + } + } + + public void Setup( TemplateSubShader subShader ) + { + if( m_currentPasses == null ) + { + m_currentPassesDict = new Dictionary<string, PassVisibleOptionsItems>(); + m_currentPasses = new PassVisibleOptionsItems[ subShader.Passes.Count ]; + for( int i = 0; i < m_currentPasses.Length; i++ ) + { + if( subShader.Passes[ i ].IsMainPass ) + m_mainPassId = i; + + m_currentPasses[ i ] = new PassVisibleOptionsItems() { Name = subShader.Passes[ i ].PassNameContainer.Data, Visible = true, Idx = i }; + m_currentPassesDict.Add( m_currentPasses[ i ].Name, m_currentPasses[ i ] ); + } + } + } + + public void Clear() + { + m_currentPasses = null; + + if( m_currentPassesDict != null ) + m_currentPassesDict.Clear(); + + m_currentPassesDict = null; + } + + public void Destroy() + { + m_currentPasses = null; + + if( m_currentPassesDict != null ) + m_currentPassesDict.Clear(); + + m_currentPassesDict = null; + } + + public void Draw( TemplateMultiPassMasterNode owner ) + { + if( m_currentPasses.Length < 2 ) + return; + + NodeUtils.DrawNestedPropertyGroup( ref m_foldout, Label, () => + { + for( int i = 0; i < m_currentPasses.Length; i++ ) + { + EditorGUI.BeginChangeCheck(); + m_currentPasses[ i ].Visible = owner.EditorGUILayoutToggleLeft( m_currentPasses[ i ].Name, m_currentPasses[ i ].Visible ); + if( EditorGUI.EndChangeCheck() ) + { + owner.ContainerGraph.GetMultiPassMasterNodes( owner.LODIndex)[ m_currentPasses[ i ].Idx ].IsInvisible = !m_currentPasses[ i ].Visible; + } + + } + EditorGUILayout.Space(); + } ); + } + + public void ReadFromString( ref uint index, ref string[] nodeParams ) + { + int passAmount = Convert.ToInt32( nodeParams[ index++ ] ); + for( int i = 0; i < passAmount; i++ ) + { + bool value = Convert.ToBoolean( nodeParams[ index++ ] ); + if( i < m_currentPasses.Length ) + { + m_currentPasses[ i ].Visible = value; + } + } + } + + public void WriteToString( ref string nodeInfo ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_currentPasses.Length ); + for( int i = 0; i < m_currentPasses.Length; i++ ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_currentPasses[ i ].Visible ); + } + } + + public void SetPassVisible( string passName, bool visible ) + { + bool refresh = false; + if( m_currentPassesDict == null ) + { + m_currentPassesDict = new Dictionary<string, PassVisibleOptionsItems>(); + refresh = true; + } + else if( m_currentPassesDict.Count != m_currentPasses.Length ) + { + refresh = true; + } + + if( refresh ) + { + for( int i = 0; i < m_currentPasses.Length; i++ ) + { + m_currentPassesDict.Add( m_currentPasses[ i ].Name, m_currentPasses[ i ] ); + } + } + + if( m_currentPassesDict.ContainsKey( passName ) ) + { + m_currentPassesDict[ passName ].Visible = visible; + } + } + + public int LastActivePass + { + get + { + if( m_currentPasses != null ) + { + for( int i = m_currentPasses.Length - 1; i > -1; i-- ) + { + if( m_currentPasses[ i ].Visible ) + return i; + } + } + m_currentPasses[ m_mainPassId ].Visible = true; + return m_mainPassId; + } + } + public bool IsVisible( int passId ) { return m_currentPasses[ passId ].Visible; } + private PassVisibleOptionsItems[] AvailablePasses { get { return m_currentPasses; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePassSelectorHelper.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePassSelectorHelper.cs.meta new file mode 100644 index 00000000..2f45a9d5 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePassSelectorHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1340693b71fe44846bb72eb1035f138d +timeCreated: 1542731803 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePostProcessor.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePostProcessor.cs new file mode 100644 index 00000000..e9ee8c71 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePostProcessor.cs @@ -0,0 +1,157 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using UnityEditor; +using UnityEngine; +using System.IO; +using System.Security.AccessControl; +using System.Security.Principal; +using System.Text.RegularExpressions; +using Debug = UnityEngine.Debug; + +namespace AmplifyShaderEditor +{ + public sealed class TemplatePostProcessor : AssetPostprocessor + { + public static TemplatesManager DummyManager; + public static void Destroy() + { + if( DummyManager != null ) + { + DummyManager.Destroy(); + ScriptableObject.DestroyImmediate( DummyManager ); + DummyManager = null; + } + } + + static void OnPostprocessAllAssets( string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths ) + { + TemplatesManager templatesManager; + bool firstTimeDummyFlag = false; + if( UIUtils.CurrentWindow == null ) + { + if( DummyManager == null ) + { + DummyManager = ScriptableObject.CreateInstance<TemplatesManager>(); + DummyManager.hideFlags = HideFlags.HideAndDontSave; + firstTimeDummyFlag = true; + } + templatesManager = DummyManager; + } + else + { + Destroy(); + templatesManager = UIUtils.CurrentWindow.TemplatesManagerInstance; + } + + if( templatesManager == null ) + { + return; + } + + if( !templatesManager.Initialized ) + { + templatesManager.Init(); + } + + bool refreshMenuItems = false; + for( int i = 0; i < importedAssets.Length; i++ ) + { + if( TemplateHelperFunctions.CheckIfTemplate( importedAssets[ i ] ) ) + { + string guid = AssetDatabase.AssetPathToGUID( importedAssets[ i ] ); + TemplateDataParent templateData = templatesManager.GetTemplate( guid ); + if( templateData != null ) + { + refreshMenuItems = templateData.Reload() || refreshMenuItems || firstTimeDummyFlag; + int windowCount = IOUtils.AllOpenedWindows.Count; + AmplifyShaderEditorWindow currWindow = UIUtils.CurrentWindow; + for( int windowIdx = 0; windowIdx < windowCount; windowIdx++ ) + { + if( IOUtils.AllOpenedWindows[ windowIdx ].OutsideGraph.CurrentCanvasMode == NodeAvailability.TemplateShader ) + { + if( IOUtils.AllOpenedWindows[ windowIdx ].OutsideGraph.MultiPassMasterNodes.NodesList[ 0 ].CurrentTemplate == templateData ) + { + UIUtils.CurrentWindow = IOUtils.AllOpenedWindows[ windowIdx ]; + IOUtils.AllOpenedWindows[ windowIdx ].OutsideGraph.ForceMultiPassMasterNodesRefresh(); + } + } + } + UIUtils.CurrentWindow = currWindow; + } + else + { + refreshMenuItems = true; + string name = TemplatesManager.OfficialTemplates.ContainsKey( guid ) ? TemplatesManager.OfficialTemplates[ guid ] : string.Empty; + TemplateMultiPass mp = TemplateMultiPass.CreateInstance<TemplateMultiPass>(); + mp.Init( name, guid, true ); + templatesManager.AddTemplate( mp ); + } + } + } + + if( deletedAssets.Length > 0 ) + { + if( deletedAssets[ 0 ].IndexOf( Constants.InvalidPostProcessDatapath ) < 0 ) + { + for( int i = 0; i < deletedAssets.Length; i++ ) + { + string guid = AssetDatabase.AssetPathToGUID( deletedAssets[ i ] ); + TemplateDataParent templateData = templatesManager.GetTemplate( guid ); + if( templateData != null ) + { + // Close any window using that template + int windowCount = IOUtils.AllOpenedWindows.Count; + for( int windowIdx = 0; windowIdx < windowCount; windowIdx++ ) + { + TemplateMasterNode masterNode = IOUtils.AllOpenedWindows[ windowIdx ].CurrentGraph.CurrentMasterNode as TemplateMasterNode; + if( masterNode != null && masterNode.CurrentTemplate.GUID.Equals( templateData.GUID ) ) + { + IOUtils.AllOpenedWindows[ windowIdx ].Close(); + } + } + + templatesManager.RemoveTemplate( templateData ); + refreshMenuItems = true; + } + } + } + } + + //for ( int i = 0; i < movedAssets.Length; i++ ) + //{ + // if ( TemplateHelperFunctions.CheckIfTemplate( movedAssets[ i ] ) ) + // { + // refreshMenuItems = true; + // break; + // } + //} + + //for ( int i = 0; i < movedFromAssetPaths.Length; i++ ) + //{ + // if ( TemplateHelperFunctions.CheckIfTemplate( movedFromAssetPaths[ i ] ) ) + // { + // refreshMenuItems = true; + // break; + // } + //} + + if( refreshMenuItems ) + { + //UnityEngine.Debug.Log( "Refresh Menu Items" ); + refreshMenuItems = false; + templatesManager.CreateTemplateMenuItems(); + + AmplifyShaderEditorWindow currWindow = UIUtils.CurrentWindow; + + int windowCount = IOUtils.AllOpenedWindows.Count; + for( int windowIdx = 0; windowIdx < windowCount; windowIdx++ ) + { + UIUtils.CurrentWindow = IOUtils.AllOpenedWindows[ windowIdx ]; + IOUtils.AllOpenedWindows[ windowIdx ].CurrentGraph.ForceCategoryRefresh(); + } + UIUtils.CurrentWindow = currWindow; + } + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePostProcessor.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePostProcessor.cs.meta new file mode 100644 index 00000000..3598b89a --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatePostProcessor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d5f63490d6402e9488add7cbdfdd6872 +timeCreated: 1496739732 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderData.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderData.cs new file mode 100644 index 00000000..6f42c6f9 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderData.cs @@ -0,0 +1,121 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplatePassInfo + { + public string Modules; + public string Data; + public int GlobalStartIdx = -1; + public int LocalStartIdx = -1; + } + + [Serializable] + public class TemplateSubShaderInfo + { + public string Data; + public string Modules; + public int StartIdx = -1; + public List<TemplatePassInfo> Passes = new List<TemplatePassInfo>(); + public void Destroy() + { + Passes.Clear(); + Passes = null; + } + } + + [Serializable] + public class TemplateShaderInfo + { + public string Body; + public string Properties; + public int PropertyStartIdx = -1; + public List<TemplateSubShaderInfo> SubShaders = new List<TemplateSubShaderInfo>(); + public void Destroy() + { + int count = SubShaders.Count; + for( int i = 0; i < count; i++ ) + { + SubShaders[ i ].Destroy(); + } + SubShaders.Clear(); + SubShaders = null; + } + } + + public class TemplateShaderInfoUtil + { + public static TemplateShaderInfo CreateShaderData( string body ) + { + int nameBegin = body.IndexOf( TemplatesManager.TemplateShaderNameBeginTag ); + if( nameBegin < 0 ) + { + // Not a template + return null; + } + + TemplateShaderInfo shaderData = null; + //SHADER + MatchCollection shaderMatch = Regex.Matches( body, "\\bShader\\b" ); + if( shaderMatch.Count > 0 ) + { + //SUBSHADER + MatchCollection subShaderMatch = Regex.Matches( body, TemplatesManager.TemplateMPSubShaderTag ); + int subShaderAmount = subShaderMatch.Count; + if( subShaderAmount > 0 ) + { + shaderData = new TemplateShaderInfo(); + shaderData.Body = body; + int length = subShaderMatch[ 0 ].Index - shaderMatch[ 0 ].Groups[ 0 ].Index; + shaderData.Properties = body.Substring( shaderMatch[ 0 ].Index, length ); + shaderData.PropertyStartIdx = body.IndexOf( TemplatesManager.TemplatePropertyTag ); + + for( int subShaderIdx = 0; subShaderIdx < subShaderAmount; subShaderIdx++ ) + { + TemplateSubShaderInfo subShaderData = new TemplateSubShaderInfo(); + int subshaderBeginIndex = subShaderMatch[ subShaderIdx ].Index; + int subShaderEndIndex = ( subShaderIdx == ( subShaderAmount - 1 ) ) ? body.Length - 1 : subShaderMatch[ subShaderIdx + 1 ].Index; + subShaderData.Data = body.Substring( subshaderBeginIndex, subShaderEndIndex - subshaderBeginIndex ); + subShaderData.StartIdx = subshaderBeginIndex; + + //PASS + MatchCollection passMatch = Regex.Matches( subShaderData.Data, TemplatesManager.TemplatePassTagPattern ); + if( passMatch.Count == 0 ) + { + passMatch = Regex.Matches( subShaderData.Data, TemplatesManager.TemplateMPPassTag ); + } + + int passCount = passMatch.Count; + if( passCount > 0 ) + { + int lastPassIndex = subShaderData.Data.LastIndexOf( TemplatesManager.TemplatePassesEndTag ); + if( lastPassIndex < 0 ) + { + lastPassIndex = subShaderData.Data.Length - 1; + } + + subShaderData.Modules = subShaderData.Data.Substring( 0, passMatch[ 0 ].Index ); + for( int passIdx = 0; passIdx < passCount; passIdx++ ) + { + int passBeginIndex = passMatch[ passIdx ].Index; + int passEndIdx = ( passIdx == ( passCount - 1 ) ) ? lastPassIndex : passMatch[ passIdx + 1 ].Index; + TemplatePassInfo passData = new TemplatePassInfo(); + passData.Data = subShaderData.Data.Substring( passBeginIndex, passEndIdx - passBeginIndex ); + passData.GlobalStartIdx = subshaderBeginIndex + passBeginIndex; + passData.LocalStartIdx = passBeginIndex; + subShaderData.Passes.Add( passData ); + } + shaderData.SubShaders.Add( subShaderData ); + } + } + } + } + return shaderData; + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderData.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderData.cs.meta new file mode 100644 index 00000000..8ae726ee --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderData.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 33fdd6a5fbc437a489acf58f5d82885c +timeCreated: 1516879445 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderModelModule.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderModelModule.cs new file mode 100644 index 00000000..e1de14b2 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderModelModule.cs @@ -0,0 +1,107 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using UnityEngine; +using UnityEditor; + +namespace AmplifyShaderEditor +{ + [Serializable] + public sealed class TemplateShaderModelModule : TemplateModuleParent + { + private const string ShaderModelStr = "Shader Model"; + private const string ShaderModelFormatStr = "#pragma target "; + private const string ShaderModelEncapsulateFormatStr = "CGINCLUDE\n#pragma target {0}\nENDCG"; + + [SerializeField] + private int m_shaderModelIdx = 2; + + [SerializeField] + private bool m_encapsulateOnCGInlude = false; + + public TemplateShaderModelModule() : base("Shader Model"){ } + + public override void Draw( UndoParentNode owner, bool style = true ) + { + EditorGUI.BeginChangeCheck(); + m_shaderModelIdx = owner.EditorGUILayoutPopup( ShaderModelStr, m_shaderModelIdx, TemplateHelperFunctions.AvailableShaderModels ); + if( EditorGUI.EndChangeCheck() ) + { + m_isDirty = true; + } + } + + public void CopyFrom( TemplateShaderModelModule other , bool allData ) + { + if( allData ) + { + m_independentModule = other.IndependentModule; + m_encapsulateOnCGInlude = other.EncapsulateOnCGInlude; + } + + m_shaderModelIdx = other.CurrentShaderModelIdx; + } + + public override void ReadFromString( ref uint index, ref string[] nodeParams ) + { + bool validDataOnMeta = m_validData; + if( UIUtils.CurrentShaderVersion() > TemplatesManager.MPShaderVersion ) + { + validDataOnMeta = Convert.ToBoolean( nodeParams[ index++ ] ); + } + + if( validDataOnMeta ) + m_shaderModelIdx = Convert.ToInt32( nodeParams[ index++ ] ); + } + + public override void WriteToString( ref string nodeInfo ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_validData ); + if( m_validData ) + IOUtils.AddFieldValueToString( ref nodeInfo, m_shaderModelIdx ); + } + + public override string GenerateShaderData( bool isSubShader ) + { + if( m_encapsulateOnCGInlude ) + { + return string.Format( ShaderModelEncapsulateFormatStr, TemplateHelperFunctions.AvailableShaderModels[ m_shaderModelIdx ] ); + } + else + { + return ShaderModelFormatStr + TemplateHelperFunctions.AvailableShaderModels[ m_shaderModelIdx ]; + } + } + + public void ConfigureFromTemplateData( TemplateShaderModelData data ) + { + bool newValidData = ( data.DataCheck == TemplateDataCheck.Valid ); + + if( newValidData && m_validData != newValidData ) + { + m_independentModule = data.IndependentModule; + + if( TemplateHelperFunctions.ShaderModelToArrayIdx.ContainsKey( data.Value ) ) + { + m_shaderModelIdx = TemplateHelperFunctions.ShaderModelToArrayIdx[ data.Value ]; + } + m_encapsulateOnCGInlude = data.Encapsulate; + } + + m_validData = newValidData; + } + + public int CurrentShaderModelIdx { get { return m_shaderModelIdx; } } + public string CurrentShaderModel { get { return TemplateHelperFunctions.AvailableShaderModels[ m_shaderModelIdx ]; } } + public bool EncapsulateOnCGInlude { get { return m_encapsulateOnCGInlude; } } + public int InterpolatorAmount + { + get + { + return TemplateHelperFunctions.AvailableInterpolators[ TemplateHelperFunctions.AvailableShaderModels[ m_shaderModelIdx ] ]; + } + } + + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderModelModule.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderModelModule.cs.meta new file mode 100644 index 00000000..9afc9c9f --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderModelModule.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 33c15b597b8db18499c1b4a76035a552 +timeCreated: 1519899350 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderPropertyData.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderPropertyData.cs new file mode 100644 index 00000000..2b67f816 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderPropertyData.cs @@ -0,0 +1,44 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateShaderPropertyData + { + public string PropertyInspectorName; + public string PropertyName; + public WirePortDataType PropertyDataType; + public PropertyType PropertyType; + + public int Index; + public string FullValue; + public string ReplacementValueHelper; + public string Identation; + + public TemplateShaderPropertyData( int index, string fullValue,string identation, string propertyInspectorName, string propertyName, WirePortDataType propertyDataType , PropertyType propertyType ) + { + Index = index; + FullValue = fullValue; + Identation = identation; + PropertyInspectorName = string.IsNullOrEmpty( propertyInspectorName )?propertyName: propertyInspectorName; + PropertyName = propertyName; + PropertyDataType = propertyDataType; + PropertyType = propertyType; + int idx = FullValue.LastIndexOf( "=" ); + ReplacementValueHelper = ( idx >= 0 ) ? FullValue.Substring( 0, idx + 1 ) +" ": FullValue + " = "; + } + + public string CreatePropertyForValue( string value ) + { + return value.Contains( PropertyName ) ? Identation + value : ReplacementValueHelper + value; + } + + public override string ToString() + { + return string.Format( "{0}(\"{1}\", {2})", PropertyName, PropertyInspectorName,UIUtils.WirePortToCgType( PropertyDataType ) ); + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderPropertyData.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderPropertyData.cs.meta new file mode 100644 index 00000000..411f0535 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderPropertyData.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7d16f1d82f69ac945ac524dd877ce7fe +timeCreated: 1496341538 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderPropertyNode.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderPropertyNode.cs new file mode 100644 index 00000000..40266c37 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderPropertyNode.cs @@ -0,0 +1,650 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace AmplifyShaderEditor +{ + public enum ShaderPropertyScope + { + Shader, + SubShader, + Pass + } + + [Serializable] + [NodeAttributes( "Template Parameter", "Constants And Properties", "Select and use one of the pre-existing properties given by the template" )] + public sealed class TemplateShaderPropertyNode : TemplateNodeParent + { + private const string CurrentScopeStr = "Scope"; + private const string WarningStr = "Preview doesn't work with global variables"; + private const string PropertyLabelStr = "Parameter"; + private const string TypeLabelStr = "Type: "; + private const string PropertyNameStr = "Property Name: "; + + private int IntPropertyId; + private int FloatPropertyId; + private int VectorPropertyId; + private int Sampler2DPropertyId; + private int Sampler3DPropertyId; + private int SamplerCubePropertyId; + + [SerializeField] + private int m_currentPropertyIdx = -1; + + [SerializeField] + private string m_propertyName = string.Empty; + + [SerializeField] + private int m_propertyNameId = 0; + + [SerializeField] + private string m_typeName = string.Empty; + + [SerializeField] + private string m_propertyNameLabel = string.Empty; + + private bool m_fetchPropertyId = false; + private bool m_fetchScopeFromProperty = false; + + private List<TemplateShaderPropertyData> m_shaderProperties = null; + private string[] m_propertyLabels = null; + + private UpperLeftWidgetHelper m_upperLeftWidgetHelper = new UpperLeftWidgetHelper(); + + //Multi-Pass only properties + [SerializeField] + private ShaderPropertyScope m_currentScope = ShaderPropertyScope.Shader; + + protected override void CommonInit( int uniqueId ) + { + base.CommonInit( uniqueId ); + m_previewShaderGUID = "4feb2016be0ece148b8bf234508f6aa4"; + } + + void FetchScope() + { + int shaderScopeCount = m_templateMPData.AvailableShaderProperties.Count; + for( int i = 0; i < shaderScopeCount; i++ ) + { + if( m_templateMPData.AvailableShaderProperties[ i ].PropertyName.Equals( m_propertyName ) ) + { + m_currentScope = ShaderPropertyScope.Shader; + } + } + + int subShaderScopeCount = m_templateMPData.SubShaders[ SubShaderIdx ].AvailableShaderGlobals.Count; + for( int i = 0; i < subShaderScopeCount; i++ ) + { + if( m_templateMPData.SubShaders[ SubShaderIdx ].AvailableShaderGlobals[ i ].PropertyName.Equals( m_propertyName ) ) + { + m_currentScope = ShaderPropertyScope.SubShader; + } + } + + int passScopeCount = m_templateMPData.SubShaders[ SubShaderIdx ].Passes[ PassIdx ].AvailableShaderGlobals.Count; + for( int i = 0; i < passScopeCount; i++ ) + { + if( m_templateMPData.SubShaders[ SubShaderIdx ].Passes[ PassIdx ].AvailableShaderGlobals[ i ].PropertyName.Equals( m_propertyName ) ) + { + m_currentScope = ShaderPropertyScope.Pass; + } + } + } + + void FetchShaderProperties() + { + if( m_templateMPData == null ) + m_templateMPData = ( m_containerGraph.CurrentMasterNode as TemplateMultiPassMasterNode ).CurrentTemplate; + + if( m_templateMPData != null ) + { + switch( m_currentScope ) + { + case ShaderPropertyScope.Shader: + m_shaderProperties = m_templateMPData.AvailableShaderProperties; + break; + case ShaderPropertyScope.SubShader: + m_shaderProperties = m_templateMPData.SubShaders[ SubShaderIdx ].AvailableShaderGlobals; + break; + case ShaderPropertyScope.Pass: + m_shaderProperties = m_templateMPData.SubShaders[ SubShaderIdx ].Passes[ PassIdx ].AvailableShaderGlobals; + break; + } + } + } + + public override void OnEnable() + { + base.OnEnable(); + IntPropertyId = Shader.PropertyToID( "_IntData" ); + FloatPropertyId = Shader.PropertyToID( "_FloatData" ); + VectorPropertyId = Shader.PropertyToID( "_VectorData" ); + Sampler2DPropertyId = Shader.PropertyToID( "_Sampler2DData" ); + Sampler3DPropertyId = Shader.PropertyToID( "_Sampler3DData" ); + SamplerCubePropertyId = Shader.PropertyToID( "_SamplerCubeData" ); + } + + public override void DrawProperties() + { + base.DrawProperties(); + if( m_multiPassMode ) + { + DrawMultipassProperties(); + } + + if( m_currentPropertyIdx > -1 ) + { + + bool hasProperties = ( m_shaderProperties != null && m_shaderProperties.Count > 0 ); + if( hasProperties ) + { + EditorGUI.BeginChangeCheck(); + m_currentPropertyIdx = EditorGUILayoutPopup( PropertyLabelStr, m_currentPropertyIdx, m_propertyLabels ); + if( EditorGUI.EndChangeCheck() ) + { + UpdateFromId(); + } + EditorGUILayout.LabelField( m_typeName ); + if( m_shaderProperties[ m_currentPropertyIdx ].PropertyType != PropertyType.Global ) + { + EditorGUILayout.LabelField( m_propertyNameLabel ); + } + } + } + } + + void DrawMultipassProperties() + { + EditorGUI.BeginChangeCheck(); + m_currentScope = (ShaderPropertyScope)EditorGUILayoutEnumPopup( CurrentScopeStr, m_currentScope ); + if( EditorGUI.EndChangeCheck() ) + { + FetchShaderProperties(); + FetchPropertyId(); + } + + bool showSubShader = false; + bool showPass = false; + switch( m_currentScope ) + { + case ShaderPropertyScope.SubShader: + { + showSubShader = true; + } + break; + case ShaderPropertyScope.Pass: + { + showSubShader = true; + showPass = true; + } + break; + } + + if( showSubShader ) + { + DrawSubShaderUI(); + } + + if( showPass ) + { + DrawPassUI(); + } + } + + protected override void OnSubShaderChange() + { + FetchShaderProperties(); + FetchPropertyId(); + } + + protected override void OnPassChange() + { + FetchShaderProperties(); + FetchPropertyId(); + } + + override protected void CheckWarningState() + { + if( m_containerGraph.CurrentCanvasMode != NodeAvailability.TemplateShader ) + { + ShowTab( NodeMessageType.Error, ErrorMessageStr ); + } + else + { + if( m_shaderProperties != null && + m_shaderProperties.Count > 0 && + m_shaderProperties.Count > m_currentPropertyIdx && + m_shaderProperties[ m_currentPropertyIdx ].PropertyType == PropertyType.Global && + m_showPreview ) + { + ShowTab( NodeMessageType.Info, WarningStr ); + } + else + { + m_showErrorMessage = false; + } + } + } + + public override void SetPreviewInputs() + { + if( m_containerGraph.CurrentCanvasMode != NodeAvailability.TemplateShader ) + return; + + if( m_shaderProperties == null || m_currentPropertyIdx >= m_shaderProperties.Count ) + return; + + if( m_shaderProperties[ m_currentPropertyIdx ].PropertyType == PropertyType.Global ) + { + m_additionalContent.text = string.Empty; + PreviewMaterial.SetInt( IntPropertyId, 0 ); + return; + } + + Material currMat = m_containerGraph.CurrentMaterial; + if( currMat != null && currMat.HasProperty( m_propertyNameId ) ) + { + switch( m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType ) + { + case WirePortDataType.INT: + { + int value = currMat.GetInt( m_propertyNameId ); + SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr, GenerateTitle( value ) ) ); + PreviewMaterial.SetInt( IntPropertyId, value ); + } + break; + case WirePortDataType.FLOAT: + { + float value = currMat.GetFloat( m_propertyNameId ); + SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr, GenerateTitle( value ) ) ); + PreviewMaterial.SetFloat( FloatPropertyId, value ); + } + break; + case WirePortDataType.FLOAT4: + { + Vector4 value = currMat.GetVector( m_propertyNameId ); + SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr, GenerateTitle( value.x, value.y, value.z, value.w ) ) ); + PreviewMaterial.SetVector( VectorPropertyId, value ); + } + break; + case WirePortDataType.COLOR: + { + Color value = currMat.GetColor( m_propertyNameId ); + SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr, GenerateTitle( value.r, value.g, value.b, value.a ) ) ); + PreviewMaterial.SetColor( VectorPropertyId, value ); + } + break; + case WirePortDataType.SAMPLER2D: + { + Texture value = currMat.GetTexture( m_propertyNameId ); + if( value ) + SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr, value.name ) ); + else + SetAdditonalTitleText( string.Empty ); + PreviewMaterial.SetTexture( Sampler2DPropertyId, value ); + } + break; + case WirePortDataType.SAMPLER3D: + { + Texture value = currMat.GetTexture( m_propertyNameId ); + if( value ) + SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr, value.name ) ); + else + SetAdditonalTitleText( string.Empty ); + PreviewMaterial.SetTexture( Sampler3DPropertyId, value ); + } + break; + case WirePortDataType.SAMPLERCUBE: + { + Texture value = currMat.GetTexture( m_propertyNameId ); + if( value ) + SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr, value.name ) ); + else + SetAdditonalTitleText( string.Empty ); + PreviewMaterial.SetTexture( SamplerCubePropertyId, value ); + } + break; + } + } + else + { + SetAdditonalTitleText( string.Empty ); + } + } + + public override void Draw( DrawInfo drawInfo ) + { + if( m_containerGraph.CurrentCanvasMode != NodeAvailability.TemplateShader ) + { + if( !m_showErrorMessage || m_errorMessageTypeIsError == NodeMessageType.Info ) + { + ShowTab( NodeMessageType.Error, ErrorMessageStr ); + } + } + else if( m_showErrorMessage ) + { + if( m_errorMessageTypeIsError == NodeMessageType.Error ) + HideTab(); + } + + base.Draw( drawInfo ); + if( m_containerGraph.CurrentCanvasMode != NodeAvailability.TemplateShader ) + return; + + if( m_shaderProperties == null ) + { + MasterNode masterNode = m_containerGraph.CurrentMasterNode; + if( masterNode.CurrentMasterNodeCategory == AvailableShaderTypes.Template ) + { + if( SetTemplate( masterNode ) ) + { + m_fetchPropertyId = true; + } + } + } + + if( m_fetchScopeFromProperty ) + { + m_fetchScopeFromProperty = false; + FetchScope(); + FetchShaderProperties(); + } + + if( m_fetchPropertyId ) + { + m_fetchPropertyId = false; + FetchPropertyId(); + } + + if( m_currentPropertyIdx > -1 ) + { + EditorGUI.BeginChangeCheck(); + m_currentPropertyIdx = m_upperLeftWidgetHelper.DrawWidget( this, m_currentPropertyIdx, m_propertyLabels ); + if( EditorGUI.EndChangeCheck() ) + { + UpdateFromId(); + } + } + } + + void FetchPropertyId() + { + if( m_shaderProperties != null ) + { + m_currentPropertyIdx = 0; + m_propertyLabels = new string[ m_shaderProperties.Count ]; + for( int i = 0; i < m_shaderProperties.Count; i++ ) + { + if( m_shaderProperties[ i ].PropertyName.Equals( m_propertyName ) ) + { + m_currentPropertyIdx = i; + } + m_propertyLabels[ i ] = m_shaderProperties[ i ].PropertyInspectorName; + } + UpdateFromId(); + } + else + { + m_currentPropertyIdx = -1; + } + } + + void UpdateFromId() + { + + if( m_shaderProperties != null ) + { + if( m_shaderProperties.Count == 0 ) + { + for( int i = 0; i < 4; i++ ) + m_containerGraph.DeleteConnection( false, UniqueId, i, false, true ); + + m_headerColor = UIUtils.GetColorFromCategory( "Default" ); + m_content.text = "None"; + m_additionalContent.text = string.Empty; + m_previewMaterialPassId = 1; + PreviewMaterial.SetFloat( FloatPropertyId, 0 ); + m_showPreview = false; + m_drawPreviewExpander = false; + m_outputPorts[ 0 ].ChangeProperties( "None", WirePortDataType.FLOAT, false ); + ConfigurePorts(); + return; + } + + m_drawPreviewExpander = true; + bool areCompatible = TemplateHelperFunctions.CheckIfCompatibles( m_outputPorts[ 0 ].DataType, m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType ); + switch( m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType ) + { + case WirePortDataType.SAMPLER1D: + case WirePortDataType.SAMPLER2D: + case WirePortDataType.SAMPLER3D: + case WirePortDataType.SAMPLERCUBE: + m_outputPorts[ 0 ].ChangeProperties( "Tex", m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType, false ); + m_headerColor = UIUtils.GetColorFromCategory( "Textures" ); + break; + case WirePortDataType.INT: + case WirePortDataType.FLOAT: + m_outputPorts[ 0 ].ChangeProperties( Constants.EmptyPortValue, m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType, false ); + m_headerColor = UIUtils.GetColorFromCategory( "Constants And Properties" ); + break; + case WirePortDataType.FLOAT4: + m_outputPorts[ 0 ].ChangeProperties( "XYZW", m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType, false ); + m_headerColor = UIUtils.GetColorFromCategory( "Constants And Properties" ); + break; + case WirePortDataType.COLOR: + m_outputPorts[ 0 ].ChangeProperties( "RGBA", m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType, false ); + m_headerColor = UIUtils.GetColorFromCategory( "Constants And Properties" ); + break; + default: + case WirePortDataType.OBJECT: + case WirePortDataType.FLOAT3x3: + case WirePortDataType.FLOAT4x4: + m_outputPorts[ 0 ].ChangeProperties( "Out", m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType, false ); + m_headerColor = UIUtils.GetColorFromCategory( "Constants And Properties" ); + break; + } + + if( !areCompatible ) + { + for( int i = 0; i < 4; i++ ) + m_containerGraph.DeleteConnection( false, UniqueId, i, false, true ); + } + + ConfigurePorts(); + + m_propertyName = m_shaderProperties[ m_currentPropertyIdx ].PropertyName; + m_content.text = m_shaderProperties[ m_currentPropertyIdx ].PropertyInspectorName; + m_propertyNameId = Shader.PropertyToID( m_propertyName ); + m_typeName = TypeLabelStr + m_shaderProperties[ m_currentPropertyIdx ].PropertyType.ToString(); + if( m_shaderProperties[ m_currentPropertyIdx ].PropertyType != PropertyType.Global ) + { + m_propertyNameLabel = PropertyNameStr + m_shaderProperties[ m_currentPropertyIdx ].PropertyName; + } + + m_sizeIsDirty = true; + Material currMat = m_containerGraph.CurrentMaterial; + if( currMat != null ) + { + if( m_shaderProperties[ m_currentPropertyIdx ].PropertyType == PropertyType.Global ) + { + m_previewMaterialPassId = 0; + if( !m_showErrorMessage && m_showPreview ) + { + ShowTab( NodeMessageType.Info, WarningStr ); + } + } + else + { + if( m_showErrorMessage && m_errorMessageTypeIsError != NodeMessageType.Error ) + { + HideTab(); + } + switch( m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType ) + { + case WirePortDataType.INT: m_previewMaterialPassId = 0; break; + case WirePortDataType.FLOAT: m_previewMaterialPassId = 1; break; + case WirePortDataType.FLOAT4: + case WirePortDataType.COLOR: m_previewMaterialPassId = 2; break; + case WirePortDataType.SAMPLER2D: m_previewMaterialPassId = 3; break; + case WirePortDataType.SAMPLER3D: m_previewMaterialPassId = 4; break; + case WirePortDataType.SAMPLERCUBE: m_previewMaterialPassId = 5; break; + default: PreviewMaterial.SetPass( 0 ); break; + } + } + } + + CheckWarningState(); + } + } + + string GenerateTitle( params float[] values ) + { + //string finalResult = "( "; + string finalResult = string.Empty; + if( values.Length == 1 ) + { + finalResult += values[ 0 ].ToString( Mathf.Abs( values[ 0 ] ) > 1000 ? Constants.PropertyBigFloatFormatLabel : Constants.PropertyFloatFormatLabel ); + } + else + { + for( int i = 0; i < values.Length; i++ ) + { + finalResult += values[ i ].ToString( Mathf.Abs( values[ i ] ) > 1000 ? Constants.PropertyBigVectorFormatLabel : Constants.PropertyVectorFormatLabel ); + if( i < ( values.Length - 1 ) ) + finalResult += ","; + } + } + //finalResult += " )"; + return finalResult; + } + + public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar ) + { + if( dataCollector.MasterNodeCategory != AvailableShaderTypes.Template ) + { + UIUtils.ShowMessage( UniqueId, "Template Parameter node is only intended for templates use only" ); + return m_outputPorts[ outputId ].ErrorValue; + } + + if( m_shaderProperties == null || m_shaderProperties.Count ==0 ) + { + UIUtils.ShowMessage( UniqueId, "Attempting to fetch inexistant parameter on " + m_nodeAttribs.Name +" node"); + return m_outputPorts[ outputId ].ErrorValue; + } + + if( m_multiPassMode ) + { + switch( m_currentScope ) + { + case ShaderPropertyScope.SubShader: + { + if( dataCollector.TemplateDataCollectorInstance.MultipassSubshaderIdx != SubShaderIdx ) + { + UIUtils.ShowMessage( UniqueId, string.Format( "{0} is only intended for subshader {1}", m_propertyLabels[ m_currentPropertyIdx ], SubShaderIdx ) ); + return m_outputPorts[ outputId ].ErrorValue; + } + } + break; + case ShaderPropertyScope.Pass: + { + if( dataCollector.TemplateDataCollectorInstance.MultipassSubshaderIdx != SubShaderIdx || + dataCollector.TemplateDataCollectorInstance.MultipassPassIdx != PassIdx + ) + { + UIUtils.ShowMessage( UniqueId, string.Format( "{0} is only intended for subshader {1} and pass {2}", m_propertyLabels[ m_currentPropertyIdx ], SubShaderIdx, PassIdx ) ); + return m_outputPorts[ outputId ].ErrorValue; + } + } + break; + } + } + + return GetOutputVectorItem( 0, outputId, m_propertyName ); + } + + public override void ReadFromString( ref string[] nodeParams ) + { + base.ReadFromString( ref nodeParams ); + m_propertyName = GetCurrentParam( ref nodeParams ); + m_propertyNameId = Shader.PropertyToID( m_propertyName ); + if( UIUtils.CurrentShaderVersion() > TemplatesManager.MPShaderVersion ) + { + m_currentScope = (ShaderPropertyScope)Enum.Parse( typeof( ShaderPropertyScope ), GetCurrentParam( ref nodeParams ) ); + } + else + { + m_fetchScopeFromProperty = true; + } + m_fetchPropertyId = true; + } + + public override void WriteToString( ref string nodeInfo, ref string connectionsInfo ) + { + base.WriteToString( ref nodeInfo, ref connectionsInfo ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_propertyName ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_currentScope ); + } + + public override void OnMasterNodeReplaced( MasterNode newMasterNode ) + { + base.OnMasterNodeReplaced( newMasterNode ); + if( newMasterNode.CurrentMasterNodeCategory == AvailableShaderTypes.Template ) + { + SetTemplate( newMasterNode ); + if( m_fetchScopeFromProperty ) + { + m_fetchScopeFromProperty = false; + FetchScope(); + } + FetchShaderProperties(); + FetchPropertyId(); + //m_containerGraph.DeleteConnection( false, UniqueId, 0, false, true ); + } + } + + bool SetTemplate( MasterNode newMasterNode ) + { + if( m_containerGraph.MultiPassMasterNodes.NodesList.Count > 0 ) + { + m_multiPassMode = true; + TemplateMultiPassMasterNode templateMasterNode = ( newMasterNode as TemplateMultiPassMasterNode ); + if( templateMasterNode != null ) + { + m_templateMPData = templateMasterNode.CurrentTemplate; + UpdateSubShaderAmount(); + FetchShaderProperties(); + return true; + } + } + else + { + m_multiPassMode = false; + TemplateMasterNode templateMasterNode = ( newMasterNode as TemplateMasterNode ); + if( templateMasterNode != null ) + { + m_shaderProperties = templateMasterNode.CurrentTemplate.AvailableShaderProperties; + return true; + } + } + return false; + } + + public override void RefreshExternalReferences() + { + base.RefreshExternalReferences(); + CheckWarningState(); + } + + public override void Destroy() + { + base.Destroy(); + m_propertyLabels = null; + m_shaderProperties = null; + m_upperLeftWidgetHelper = null; + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderPropertyNode.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderPropertyNode.cs.meta new file mode 100644 index 00000000..825090da --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateShaderPropertyNode.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1579d32d6529f33418f210a5bd730436 +timeCreated: 1496398185 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateSubShader.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateSubShader.cs new file mode 100644 index 00000000..6dc3f834 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateSubShader.cs @@ -0,0 +1,168 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using UnityEngine; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateSubShader + { + [SerializeField] + private int m_idx = -1; + + [SerializeField] + private List<TemplatePass> m_passes = new List<TemplatePass>(); + + [SerializeField] + private TemplateModulesData m_modules; + + [SerializeField] + private string m_uniquePrefix; + + [SerializeField] + private TemplatePropertyContainer m_templateProperties = new TemplatePropertyContainer(); + + [SerializeField] + private List<TemplateShaderPropertyData> m_availableShaderGlobals = new List<TemplateShaderPropertyData>(); + + [SerializeField] + private TemplateInfoContainer m_LODContainer = new TemplateInfoContainer(); + + [SerializeField] + private int m_passAmount = 0; + + [SerializeField] + private int m_mainPass = -1; + + [SerializeField] + private bool m_foundMainPassTag = false; + + [SerializeField] + TemplateOptionsContainer m_customOptionsContainer = new TemplateOptionsContainer(); + + public TemplateSubShader(TemplateMultiPass template, int subShaderIx, TemplateIdManager idManager, string uniquePrefix, TemplateSubShaderInfo subShaderInfo, ref Dictionary<string, TemplateShaderPropertyData> duplicatesHelper ) + { + m_idx = subShaderIx; + + m_uniquePrefix = uniquePrefix; + + FetchLOD( subShaderInfo.StartIdx, subShaderInfo.Modules ); + if( m_LODContainer.Index > -1 ) + { + idManager.RegisterId( m_LODContainer.Index, uniquePrefix + "Module" + m_LODContainer.Id, m_LODContainer.Id ); + } + + m_customOptionsContainer = TemplateOptionsToolsHelper.GenerateOptionsContainer( true, subShaderInfo.Data ); + if( m_customOptionsContainer.Enabled ) + { + idManager.RegisterId( m_customOptionsContainer.Index, uniquePrefix + m_customOptionsContainer.Body, m_customOptionsContainer.Body, true ); + } + + m_modules = new TemplateModulesData( m_customOptionsContainer, idManager, m_templateProperties, uniquePrefix + "Module", subShaderInfo.StartIdx, subShaderInfo.Modules, true ); + if( m_modules.SRPType == TemplateSRPType.HD ) + { + m_modules.SRPIsPBR = subShaderInfo.Data.Contains( TemplateHelperFunctions.HDPBRTag ); + } + + Dictionary<string, TemplateShaderPropertyData> ownDuplicatesDict = new Dictionary<string, TemplateShaderPropertyData>( duplicatesHelper ); + + TemplateHelperFunctions.CreateShaderGlobalsList( subShaderInfo.Modules, ref m_availableShaderGlobals, ref ownDuplicatesDict ); + + m_passAmount = subShaderInfo.Passes.Count; + + //if( !m_modules.PassTag.IsValid ) + //{ + // m_modules.PassTag.StartIdx = subShaderData.Passes[ 0 ].GlobalStartIdx; + // m_templateProperties.AddId( subShaderData.Data, m_modules.PassTag.Id, subShaderData.Passes[ 0 ].LocalStartIdx, m_modules.PassTag.SearchIndentation ); + // m_modules.PassTag.StartIdx -= m_templateProperties.PropertyDict[ m_modules.PassTag.Id ].Indentation.Length; + // m_templateProperties.PropertyDict[ m_modules.PassTag.Id ].UseIndentationAtStart = true; + // idManager.RegisterId( m_modules.PassTag.StartIdx, m_modules.UniquePrefix + m_modules.PassTag.Id, string.Empty ); + //} + + int firstVisible = -1; + int currAddedPassIdx = 0; + for( int passIdx = 0; passIdx < m_passAmount; passIdx++ ) + { + TemplatePass newPass = new TemplatePass( template, this,subShaderIx, passIdx, idManager, uniquePrefix + "Pass" + passIdx, subShaderInfo.Passes[ passIdx ].GlobalStartIdx, subShaderInfo.Passes[ passIdx ], ref ownDuplicatesDict ); + if( newPass.AddToList ) + { + if( newPass.IsMainPass && m_mainPass < 0 ) + { + m_mainPass = currAddedPassIdx; + m_foundMainPassTag = true; + } + else if(!newPass.IsInvisible && firstVisible < 0 ) + { + firstVisible = currAddedPassIdx; + } + + m_passes.Add( newPass ); + currAddedPassIdx++; + } + else + { + newPass.Destroy(); + newPass = null; + } + + } + + if( m_mainPass < 0 ) + { + // If no main pass was set then choose the first visible one + m_mainPass = ( firstVisible < 0 ) ? 0 : firstVisible; + m_passes[ m_mainPass ].IsMainPass = true; + } + + ownDuplicatesDict.Clear(); + ownDuplicatesDict = null; + } + + public void Destroy() + { + m_LODContainer = null; + + m_customOptionsContainer = null; + + m_templateProperties.Destroy(); + m_templateProperties = null; + + m_passes.Clear(); + m_passes = null; + + m_modules.Destroy(); + m_modules = null; + + m_availableShaderGlobals.Clear(); + m_availableShaderGlobals = null; + + } + + void FetchLOD( int offsetIdx, string body ) + { + Match match = Regex.Match( body, TemplateHelperFunctions.SubShaderLODPattern ); + if( match != null && match.Groups.Count > 1 ) + { + m_LODContainer.Id = match.Groups[ 0 ].Value; + m_LODContainer.Data = match.Groups[ 1 ].Value; + m_LODContainer.Index = offsetIdx + match.Index; + } + } + + public List<TemplatePass> Passes { get { return m_passes; } } + public TemplateModulesData Modules { get { return m_modules; } } + public string UniquePrefix { get { return m_uniquePrefix; } } + public TemplatePropertyContainer TemplateProperties { get { return m_templateProperties; } } + public List<TemplateShaderPropertyData> AvailableShaderGlobals { get { return m_availableShaderGlobals; } } + public TemplateInfoContainer LODContainer { get { return m_LODContainer; } } + public int PassAmount { get { return m_passAmount; } } + public bool FoundMainPass { get { return m_foundMainPassTag; } } + public int MainPass { get { return m_mainPass; } } + public int Idx { get { return m_idx; } } + public TemplateOptionsContainer CustomOptionsContainer { get { return m_customOptionsContainer; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateSubShader.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateSubShader.cs.meta new file mode 100644 index 00000000..41a78861 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateSubShader.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f4ff24a5a4c92f745a159f247574c07a +timeCreated: 1517854017 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateTagsModule.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateTagsModule.cs new file mode 100644 index 00000000..fcf38910 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateTagsModule.cs @@ -0,0 +1,440 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateTagsModule : TemplateModuleParent + { + private const string CustomTagsStr = "Tags"; + private const string TagNameStr = "Name"; + private const string TagValueStr = "Value"; + private const string QueueIndexStr = "Index"; + private const string QueueLabelStr = "Queue"; + private const string RenderTypeLabelStr = "Type"; + private const string CustomRenderTypeLabelStr = "Custom"; + + private const float ShaderKeywordButtonLayoutWidth = 15; + private UndoParentNode m_currentOwner; + + private double m_tagNameCheckTimestamp = 0; + private bool m_tagNameCheckFlag = true; + private int m_tagNameCheckItemId = 0; + private const double TagNameCheckMaxInterval = 1.5; + + [SerializeField] + private List<CustomTagData> m_availableTags = new List<CustomTagData>(); + + private Dictionary<string, CustomTagData> m_availableTagsDict = new Dictionary<string, CustomTagData>(); + + public TemplateTagsModule() : base( "Tags" ) { } + + public void CopyFrom( TemplateTagsModule other ) + { + m_availableTags.Clear(); + m_availableTagsDict.Clear(); + + int count = other.AvailableTags.Count; + for( int i = 0; i < count; i++ ) + { + CustomTagData newData = new CustomTagData( other.AvailableTags[ i ] ); + m_availableTags.Add( newData ); + m_availableTagsDict.Add( newData.TagName, newData ); + } + } + + public void ConfigureFromTemplateData( TemplateTagsModuleData tagsData ) + { + bool newValidData = tagsData.DataCheck == TemplateDataCheck.Valid; + if( newValidData && newValidData != m_validData ) + { + m_availableTags.Clear(); + m_availableTagsDict.Clear(); + int count = tagsData.Tags.Count; + for( int i = 0; i < count; i++ ) + { + CustomTagData tagData = new CustomTagData( tagsData.Tags[ i ].Name, tagsData.Tags[ i ].Value, i ); + m_availableTags.Add( tagData ); + m_availableTagsDict.Add( tagsData.Tags[ i ].Name, tagData ); + } + } + m_validData = newValidData; + } + + public override void ShowUnreadableDataMessage( ParentNode owner ) + { + bool foldout = owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedCustomTags; + NodeUtils.DrawPropertyGroup( ref foldout, CustomTagsStr, base.ShowUnreadableDataMessage ); + owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedCustomTags = foldout; + } + + public void OnLogicUpdate() + { + if( m_tagNameCheckFlag && ( EditorApplication.timeSinceStartup - m_tagNameCheckTimestamp ) > TagNameCheckMaxInterval ) + { + m_tagNameCheckFlag = false; + if( m_tagNameCheckItemId < m_availableTags.Count ) + { + if( m_availableTags[ m_tagNameCheckItemId ].TagName.Equals( Constants.RenderQueueHelperStr ) ) + { + m_availableTags[ m_tagNameCheckItemId ].SpecialTag = TemplateSpecialTags.Queue; + } + else if( m_availableTags[ m_tagNameCheckItemId ].TagName.Equals( Constants.RenderTypeHelperStr ) ) + { + m_availableTags[ m_tagNameCheckItemId ].SpecialTag = TemplateSpecialTags.RenderType; + } + else + { + m_availableTags[ m_tagNameCheckItemId ].SpecialTag = TemplateSpecialTags.None; + } + } + } + } + + public override void Draw( UndoParentNode owner, bool style = true ) + { + m_currentOwner = owner; + bool foldout = owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedCustomTags; + if( style ) + { + NodeUtils.DrawPropertyGroup( ref foldout, CustomTagsStr, DrawMainBody, DrawButtons ); + } + else + { + NodeUtils.DrawNestedPropertyGroup( ref foldout, CustomTagsStr, DrawMainBody, DrawButtons ); + } + owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedCustomTags = foldout; + } + + void DrawButtons() + { + EditorGUILayout.Separator(); + + // Add tag + if( GUILayout.Button( string.Empty, UIUtils.PlusStyle, GUILayout.Width( ShaderKeywordButtonLayoutWidth ) ) ) + { + m_availableTags.Add( new CustomTagData() ); + EditorGUI.FocusTextInControl( null ); + } + + //Remove tag + if( GUILayout.Button( string.Empty, UIUtils.MinusStyle, GUILayout.Width( ShaderKeywordButtonLayoutWidth ) ) ) + { + if( m_availableTags.Count > 0 ) + { + m_availableTags.RemoveAt( m_availableTags.Count - 1 ); + EditorGUI.FocusTextInControl( null ); + } + } + } + + void DrawMainBody() + { + EditorGUI.BeginChangeCheck(); + { + EditorGUILayout.Separator(); + int itemCount = m_availableTags.Count; + + if( itemCount == 0 ) + { + EditorGUILayout.HelpBox( "Your list is Empty!\nUse the plus button to add one.", MessageType.Info ); + } + + int markedToDelete = -1; + float originalLabelWidth = EditorGUIUtility.labelWidth; + for( int i = 0; i < itemCount; i++ ) + { + m_availableTags[ i ].TagFoldout = m_currentOwner.EditorGUILayoutFoldout( m_availableTags[ i ].TagFoldout, string.Format( "[{0}] - {1}", i, m_availableTags[ i ].TagName ) ); + if( m_availableTags[ i ].TagFoldout ) + { + EditorGUI.indentLevel += 1; + EditorGUIUtility.labelWidth = 70; + //Tag Name + EditorGUI.BeginChangeCheck(); + m_availableTags[ i ].TagName = m_currentOwner.EditorGUILayoutTextField( TagNameStr, m_availableTags[ i ].TagName ); + if( EditorGUI.EndChangeCheck() ) + { + m_availableTags[ i ].TagName = UIUtils.RemoveShaderInvalidCharacters( m_availableTags[ i ].TagName ); + m_tagNameCheckFlag = true; + m_tagNameCheckItemId = i; + m_tagNameCheckTimestamp = EditorApplication.timeSinceStartup; + } + + //Tag Value + switch( m_availableTags[ i ].SpecialTag ) + { + case TemplateSpecialTags.RenderType: + { + m_availableTags[ i ].RenderType = (RenderType)m_currentOwner.EditorGUILayoutEnumPopup( RenderTypeLabelStr, m_availableTags[ i ].RenderType ); + if( m_availableTags[ i ].RenderType == RenderType.Custom ) + { + m_availableTags[ i ].TagValue = m_currentOwner.EditorGUILayoutTextField( CustomRenderTypeLabelStr, m_availableTags[ i ].TagValue ); + } + } + break; + case TemplateSpecialTags.Queue: + { + + EditorGUI.BeginChangeCheck(); + m_availableTags[ i ].RenderQueue = (RenderQueue)m_currentOwner.EditorGUILayoutEnumPopup( QueueLabelStr, m_availableTags[ i ].RenderQueue, GUILayout.MinWidth( 150 ) ); + m_availableTags[ i ].RenderQueueOffset = m_currentOwner.EditorGUILayoutIntField( QueueIndexStr, m_availableTags[ i ].RenderQueueOffset ); + if( EditorGUI.EndChangeCheck() ) + { + m_availableTags[ i ].BuildQueueTagValue(); + } + + } + break; + case TemplateSpecialTags.None: + { + EditorGUI.BeginChangeCheck(); + m_availableTags[ i ].TagValue = m_currentOwner.EditorGUILayoutTextField( TagValueStr, m_availableTags[ i ].TagValue ); + if( EditorGUI.EndChangeCheck() ) + { + m_availableTags[ i ].TagValue = UIUtils.RemoveShaderInvalidCharacters( m_availableTags[ i ].TagValue ); + } + } + break; + + } + + EditorGUIUtility.labelWidth = originalLabelWidth; + + EditorGUILayout.BeginHorizontal(); + { + GUILayout.Label( " " ); + // Add new port + if( m_currentOwner.GUILayoutButton( string.Empty, UIUtils.PlusStyle, GUILayout.Width( ShaderKeywordButtonLayoutWidth ) ) ) + { + m_availableTags.Insert( i + 1, new CustomTagData() ); + EditorGUI.FocusTextInControl( null ); + } + + //Remove port + if( m_currentOwner.GUILayoutButton( string.Empty, UIUtils.MinusStyle, GUILayout.Width( ShaderKeywordButtonLayoutWidth ) ) ) + { + markedToDelete = i; + } + } + EditorGUILayout.EndHorizontal(); + + EditorGUI.indentLevel -= 1; + } + + } + if( markedToDelete > -1 ) + { + if( m_availableTags.Count > markedToDelete ) + { + m_availableTags.RemoveAt( markedToDelete ); + EditorGUI.FocusTextInControl( null ); + } + } + EditorGUILayout.Separator(); + } + if( EditorGUI.EndChangeCheck() ) + { + m_isDirty = true; + } + } + + //Method used by template options + // As such. Render Queue will have value and offset separated by , + public void AddSpecialTag( TemplateSpecialTags tag, TemplateActionItem item ) + { + if( tag == TemplateSpecialTags.None ) + return; + + int count = m_availableTags.Count; + for( int i = 0; i < count; i++ ) + { + if( m_availableTags[ i ].SpecialTag == tag ) + { + switch( tag ) + { + case TemplateSpecialTags.RenderType: + { + m_availableTags[ i ].RenderType = TemplateHelperFunctions.StringToRenderType[ item.ActionData ]; + return; + } + case TemplateSpecialTags.Queue: + { + + m_availableTags[ i ].RenderQueue = TemplateHelperFunctions.StringToRenderQueue[ item.ActionData ]; + m_availableTags[ i ].RenderQueueOffset = item.ActionDataIdx; + m_availableTags[ i ].BuildQueueTagValue(); + return; + } + } + } + } + + CustomTagData data = new CustomTagData(); + switch( tag ) + { + case TemplateSpecialTags.RenderType: + { + data.SpecialTag = TemplateSpecialTags.RenderType; + data.TagName = "RenderType"; + data.RenderType = TemplateHelperFunctions.StringToRenderType[ item.ActionData ]; + } + break; + case TemplateSpecialTags.Queue: + { + data.SpecialTag = TemplateSpecialTags.Queue; + data.TagName = "Queue"; + data.RenderQueue = TemplateHelperFunctions.StringToRenderQueue[ item.ActionData ]; + data.RenderQueueOffset = item.ActionDataIdx; + data.BuildQueueTagValue(); + } + break; + } + m_availableTags.Add( data ); + } + + void AddTagFromRead( string data ) + { + string[] arr = data.Split( IOUtils.VALUE_SEPARATOR ); + if( arr.Length > 1 ) + { + string name = arr[ 0 ]; + string value = arr[ 1 ]; + + if( !m_availableTagsDict.ContainsKey( name ) ) + { + CustomTagData tagData = new CustomTagData( data, m_availableTags.Count - 1 ); + m_availableTags.Add( tagData ); + m_availableTagsDict.Add( name, tagData ); + } + else + { + if( m_availableTagsDict[ name ].TagId > -1 && + m_availableTagsDict[ name ].TagId < m_availableTags.Count ) + { + if( arr.Length == 4 ) + { + m_availableTags[ m_availableTagsDict[ name ].TagId ].SetTagValue( value, arr[ 3 ] ); + } + else + { + m_availableTags[ m_availableTagsDict[ name ].TagId ].SetTagValue( value ); + } + + } + else + { + int count = m_availableTags.Count; + for( int i = 0; i < count; i++ ) + { + if( m_availableTags[ i ].TagName.Equals( name ) ) + { + m_availableTags[ i ].SetTagValue( value ); + } + } + } + } + } + } + + public override void ReadFromString( ref uint index, ref string[] nodeParams ) + { + bool validDataOnMeta = m_validData; + if( UIUtils.CurrentShaderVersion() > TemplatesManager.MPShaderVersion ) + { + validDataOnMeta = Convert.ToBoolean( nodeParams[ index++ ] ); + } + + if( validDataOnMeta ) + { + int count = Convert.ToInt32( nodeParams[ index++ ] ); + for( int i = 0; i < count; i++ ) + { + AddTagFromRead( nodeParams[ index++ ] ); + } + } + } + + public override void WriteToString( ref string nodeInfo ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_validData ); + if( m_validData ) + { + int tagsCount = m_availableTags.Count; + IOUtils.AddFieldValueToString( ref nodeInfo, tagsCount ); + for( int i = 0; i < tagsCount; i++ ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_availableTags[ i ].ToString() ); + } + } + } + + public string GenerateTags() + { + int tagsCount = m_availableTags.Count; + if( tagsCount == 0 ) + return string.Empty; + + string result = "Tags { "; + + for( int i = 0; i < tagsCount; i++ ) + { + if( m_availableTags[ i ].IsValid ) + { + result += m_availableTags[ i ].GenerateTag(); + if( i < tagsCount - 1 ) + { + result += " "; + } + } + } + + result += " }"; + + return result; + } + + public override void Destroy() + { + m_availableTags.Clear(); + m_availableTags = null; + m_currentOwner = null; + m_availableTagsDict.Clear(); + m_availableTagsDict = null; + } + + public List<CustomTagData> AvailableTags { get { return m_availableTags; } } + + public bool HasRenderInfo( ref RenderType renderType, ref RenderQueue renderQueue ) + { + if( !m_validData ) + return false; + + bool foundRenderType = false; + bool foundRenderQueue = false; + int count = m_availableTags.Count; + for( int i = 0; i < count; i++ ) + { + if( m_availableTags[ i ].TagName.Equals( Constants.RenderTypeHelperStr ) ) + { + if( TemplateHelperFunctions.StringToRenderType.ContainsKey( m_availableTags[ i ].TagValue ) ) + { + renderType = TemplateHelperFunctions.StringToRenderType[ m_availableTags[ i ].TagValue ]; + foundRenderType = true; + } + } + else if( m_availableTags[ i ].TagName.Equals( Constants.RenderQueueHelperStr ) ) + { + string value = m_availableTags[ i ].TagValue.Split( '+' )[ 0 ].Split( '-' )[ 0 ]; + if( TemplateHelperFunctions.StringToRenderQueue.ContainsKey( value ) ) + { + renderQueue = TemplateHelperFunctions.StringToRenderQueue[ value ]; + foundRenderQueue = true; + } + } + } + return foundRenderType && foundRenderQueue; + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateTagsModule.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateTagsModule.cs.meta new file mode 100644 index 00000000..b5888f75 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateTagsModule.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 905b4a4de4a974a489d7a8aac14e4fcb +timeCreated: 1516719540 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateVertexData.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateVertexData.cs new file mode 100644 index 00000000..3b82e046 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateVertexData.cs @@ -0,0 +1,190 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using UnityEngine; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateVertexData + { + [SerializeField] + private TemplateSemantics m_semantics = TemplateSemantics.NONE; + [SerializeField] + private WirePortDataType m_dataType = WirePortDataType.OBJECT; + [SerializeField] + private string m_varName = string.Empty; + [SerializeField] + private TemplateInfoOnSematics m_dataInfo = TemplateInfoOnSematics.NONE; + [SerializeField] + private string m_dataSwizzle = string.Empty; + [SerializeField] + private bool m_available = false; + [SerializeField] + private string m_varNameWithSwizzle = string.Empty; + [SerializeField] + private bool m_isSingleComponent = true; + [SerializeField] + private bool m_excludeStructPrefix = false; + [SerializeField] + private string[] m_components = { "0", "0", "0", "0" }; + [SerializeField] + private bool[] m_componentUsage = { false, false,false,false }; + + public TemplateVertexData( TemplateSemantics semantics, WirePortDataType dataType, string varName ) + { + m_semantics = semantics; + m_dataType = dataType; + m_varName = varName; + m_varNameWithSwizzle = varName; + } + + public TemplateVertexData( TemplateSemantics semantics, WirePortDataType dataType, string varName, string dataSwizzle ) + { + m_semantics = semantics; + m_dataType = dataType; + m_varName = varName; + m_dataSwizzle = dataSwizzle; + m_varNameWithSwizzle = varName + dataSwizzle; + } + + public TemplateVertexData( TemplateVertexData other ) + { + m_semantics = other.m_semantics; + m_dataType = other.m_dataType; + m_varName = other.m_varName; + m_dataInfo = other.m_dataInfo; + m_dataSwizzle = other.m_dataSwizzle; + m_available = other.m_available; + m_varNameWithSwizzle = other.m_varNameWithSwizzle; + m_isSingleComponent = other.IsSingleComponent; + m_excludeStructPrefix = other.ExcludeStructPrefix; + for( int i = 0; i < 4; i++ ) + { + m_components[ i ] = other.Components[ i ]; + } + } + + public void RegisterComponent( char channelId, string value ) + { + int channelIdInt = -1; + switch( channelId ) + { + case 'r': + case 'x': channelIdInt = 0; break; + case 'g': + case 'y': channelIdInt = 1; break; + case 'b': + case 'z': channelIdInt = 2; break; + case 'a': + case 'w': channelIdInt = 3; break; + } + + if( channelId < 0 ) + { + Debug.LogWarning( "Attempting to create interpolated data from invalid channel " + channelId ); + return; + } + + RegisterComponent( channelIdInt, value ); + } + + public void RegisterComponent( int channelId, string value ) + { + channelId = Mathf.Clamp( channelId, 0, 3 ); + m_components[ channelId ] = value; + m_componentUsage[ channelId ] = true; + m_isSingleComponent = false; + } + + public void BuildVar( PrecisionType precisionType = PrecisionType.Float ) + { + if( m_isSingleComponent ) + return; + WirePortDataType dataType = WirePortDataType.FLOAT; + if( m_componentUsage[ 3 ] ) + { + dataType = WirePortDataType.FLOAT4; + } + else if( m_componentUsage[ 2 ] ) + { + dataType = WirePortDataType.FLOAT3; + } + else if( m_componentUsage[ 1 ] ) + { + dataType = WirePortDataType.FLOAT2; + } + + string newVar = UIUtils.PrecisionWirePortToCgType( precisionType, dataType ); + newVar += "( "; + switch( dataType ) + { + default: newVar += "0"; break; + case WirePortDataType.INT: + case WirePortDataType.FLOAT: + { + newVar += "{0}."+Components[ 0 ]; + } + break; + case WirePortDataType.FLOAT2: + { + newVar += "{0}." + Components[ 0 ] + ", " + + "{0}." + Components[ 1 ]; + } + break; + case WirePortDataType.FLOAT3: + { + newVar += "{0}." + Components[ 0 ] + ", " + + "{0}." + Components[ 1 ] + ", " + + "{0}." + Components[ 2 ]; + } + break; + case WirePortDataType.FLOAT4: + case WirePortDataType.COLOR: + { + newVar += "{0}." + Components[ 0 ] + ", " + + "{0}." + Components[ 1 ] + ", " + + "{0}." + Components[ 2 ] + ", " + + "{0}." + Components[ 3 ]; + } + break; + + } + newVar += " )"; + m_varName = newVar; + m_varNameWithSwizzle = newVar; + } + + public bool ExcludeStructPrefix { get { return m_excludeStructPrefix; } set { m_excludeStructPrefix = value; } } + public bool IsSingleComponent { get { return m_isSingleComponent; } } + public string[] Components { get { return m_components; } } + public TemplateSemantics Semantics { get { return m_semantics; } } + public WirePortDataType DataType { get { return m_dataType; } } + public string VarName { get { return m_varName; } set { m_varName = value; m_varNameWithSwizzle = value + m_dataSwizzle; } } + public string DataSwizzle { get { return m_dataSwizzle; } set { m_dataSwizzle = value; m_varNameWithSwizzle = m_varName + value; } } + public TemplateInfoOnSematics DataInfo { get { return m_dataInfo; } set { m_dataInfo = value; } } + public bool Available { get { return m_available; } set { m_available = value; } } + public string VarNameWithSwizzle { get { return m_varNameWithSwizzle; } } + public WirePortDataType SwizzleType + { + get + { + if ( string.IsNullOrEmpty( m_dataSwizzle ) ) + return m_dataType; + + WirePortDataType newType = m_dataType; + switch ( m_dataSwizzle.Length ) + { + case 2: newType = WirePortDataType.FLOAT;break; + case 3: newType = WirePortDataType.FLOAT2; break; + case 4: newType = WirePortDataType.FLOAT3; break; + case 5: newType = WirePortDataType.FLOAT4; break; + } + + return newType; + } + } + + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateVertexData.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateVertexData.cs.meta new file mode 100644 index 00000000..d4575340 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateVertexData.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d11e7a9026804bd46962c527fe30d933 +timeCreated: 1496053368 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateVertexDataNode.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateVertexDataNode.cs new file mode 100644 index 00000000..65645cc3 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateVertexDataNode.cs @@ -0,0 +1,272 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using UnityEngine; +using UnityEditor; +using System; +using System.Collections.Generic; + +namespace AmplifyShaderEditor +{ + [Serializable] + [NodeAttributes( "Template Vertex Data", "Vertex Data", "Select and use available vertex data from the template" )] + public class TemplateVertexDataNode : TemplateNodeParent + { + private List<TemplateVertexData> m_interpolatorData = null; + + [SerializeField] + private int m_currentDataIdx = -1; + + [SerializeField] + private string m_dataName = string.Empty; + [SerializeField] + private string m_inVarName = string.Empty; + + private string[] m_dataLabels = null; + + private bool m_fetchDataId = false; + private UpperLeftWidgetHelper m_upperLeftWidgetHelper = new UpperLeftWidgetHelper(); + + void FetchDataId() + { + if( m_interpolatorData != null ) + { + m_currentDataIdx = 0; + int count = m_interpolatorData.Count; + m_dataLabels = new string[ count ]; + for( int i = 0; i < count; i++ ) + { + m_dataLabels[ i ] = m_interpolatorData[ i ].VarName; + if( m_interpolatorData[ i ].VarName.Equals( m_dataName ) ) + { + m_currentDataIdx = i; + } + } + UpdateFromId(); + } + else + { + m_currentDataIdx = -1; + } + } + + void UpdateFromId() + { + if( m_interpolatorData != null ) + { + if( m_interpolatorData.Count == 0 ) + { + for( int i = 0; i < 4; i++ ) + m_containerGraph.DeleteConnection( false, UniqueId, i, false, true ); + + m_headerColor = UIUtils.GetColorFromCategory( "Default" ); + m_content.text = "None"; + m_additionalContent.text = string.Empty; + m_outputPorts[ 0 ].ChangeProperties( "None", WirePortDataType.OBJECT, false ); + ConfigurePorts(); + return; + } + + bool areCompatible = TemplateHelperFunctions.CheckIfCompatibles( m_outputPorts[ 0 ].DataType, m_interpolatorData[ m_currentDataIdx ].DataType ); + switch( m_interpolatorData[ m_currentDataIdx ].DataType ) + { + default: + case WirePortDataType.INT: + case WirePortDataType.FLOAT: + m_outputPorts[ 0 ].ChangeProperties( Constants.EmptyPortValue, m_interpolatorData[ m_currentDataIdx ].DataType, false ); + break; + case WirePortDataType.FLOAT2: + m_outputPorts[ 0 ].ChangeProperties( "XY", m_interpolatorData[ m_currentDataIdx ].DataType, false ); + break; + case WirePortDataType.FLOAT3: + m_outputPorts[ 0 ].ChangeProperties( "XYZ", m_interpolatorData[ m_currentDataIdx ].DataType, false ); + break; + case WirePortDataType.FLOAT4: + m_outputPorts[ 0 ].ChangeProperties( "XYZW", m_interpolatorData[ m_currentDataIdx ].DataType, false ); + break; + case WirePortDataType.COLOR: + m_outputPorts[ 0 ].ChangeProperties( "RGBA", m_interpolatorData[ m_currentDataIdx ].DataType, false ); + break; + } + + ConfigurePorts(); + + if( !areCompatible ) + { + m_containerGraph.DeleteConnection( false, UniqueId, 0, false, true ); + } + + m_dataName = m_interpolatorData[ m_currentDataIdx ].VarName; + m_content.text = m_dataName; + m_sizeIsDirty = true; + CheckWarningState(); + } + } + + public override void DrawProperties() + { + base.DrawProperties(); + if( m_multiPassMode ) + { + DrawMultipassProperties(); + } + + if( m_currentDataIdx > -1 ) + { + EditorGUI.BeginChangeCheck(); + m_currentDataIdx = EditorGUILayoutPopup( DataLabelStr, m_currentDataIdx, m_dataLabels ); + if( EditorGUI.EndChangeCheck() ) + { + UpdateFromId(); + } + } + } + protected override void OnSubShaderChange() + { + FetchInterpolator(); + FetchDataId(); + } + + protected override void OnPassChange() + { + FetchInterpolator(); + FetchDataId(); + } + + void DrawMultipassProperties() + { + DrawSubShaderUI(); + DrawPassUI(); + } + + public override void Draw( DrawInfo drawInfo ) + { + base.Draw( drawInfo ); + if( m_containerGraph.CurrentCanvasMode != NodeAvailability.TemplateShader ) + return; + + if( m_interpolatorData == null || m_interpolatorData.Count == 0 ) + { + MasterNode masterNode = m_containerGraph.CurrentMasterNode; + FetchInterpolator( masterNode ); + } + + if( m_fetchDataId ) + { + m_fetchDataId = false; + FetchDataId(); + } + + if( m_currentDataIdx > -1 ) + { + EditorGUI.BeginChangeCheck(); + m_currentDataIdx = m_upperLeftWidgetHelper.DrawWidget( this, m_currentDataIdx, m_dataLabels ); + if( EditorGUI.EndChangeCheck() ) + { + UpdateFromId(); + } + } + } + + public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar ) + { + if( dataCollector.MasterNodeCategory != AvailableShaderTypes.Template ) + { + UIUtils.ShowMessage( UniqueId, "Template Vertex Data node is only intended for templates use only" ); + return m_outputPorts[ 0 ].ErrorValue; + } + + if( dataCollector.IsFragmentCategory ) + { + UIUtils.ShowMessage( UniqueId, "Template Vertex Data node node is only intended for vertex use use only" ); + return m_outputPorts[ 0 ].ErrorValue; + } + + if( m_multiPassMode ) + { + if( dataCollector.TemplateDataCollectorInstance.MultipassSubshaderIdx != SubShaderIdx || + dataCollector.TemplateDataCollectorInstance.MultipassPassIdx != PassIdx + ) + { + UIUtils.ShowMessage( UniqueId, string.Format( "{0} is only intended for subshader {1} and pass {2}", m_dataLabels[ m_currentDataIdx ], SubShaderIdx, PassIdx ) ); + return m_outputPorts[ outputId ].ErrorValue; + } + } + + return GetOutputVectorItem( 0, outputId, m_inVarName + m_dataName ); + } + + public override void ReadFromString( ref string[] nodeParams ) + { + base.ReadFromString( ref nodeParams ); + m_dataName = GetCurrentParam( ref nodeParams ); + m_fetchDataId = true; + } + + public override void WriteToString( ref string nodeInfo, ref string connectionsInfo ) + { + base.WriteToString( ref nodeInfo, ref connectionsInfo ); + IOUtils.AddFieldValueToString( ref nodeInfo, m_dataName ); + } + + protected override bool ValidatePass( int passIdx ) + { + return ( m_templateMPData.SubShaders[ SubShaderIdx ].Passes[ passIdx ].VertexFunctionData != null && + m_templateMPData.SubShaders[ SubShaderIdx ].Passes[ passIdx ].VertexDataContainer != null ); + } + + void FetchInterpolator( MasterNode masterNode = null ) + { + FetchMultiPassTemplate( masterNode ); + if( m_multiPassMode ) + { + if( m_templateMPData != null ) + { + m_inVarName = m_templateMPData.SubShaders[ SubShaderIdx ].Passes[ PassIdx ].VertexFunctionData.InVarName + "."; + m_interpolatorData = m_templateMPData.SubShaders[ SubShaderIdx ].Passes[ PassIdx ].VertexDataContainer.VertexData; + m_fetchDataId = true; + } + } + else + { + if( masterNode == null ) + masterNode = m_containerGraph.CurrentMasterNode; + + TemplateData currentTemplate = ( masterNode as TemplateMasterNode ).CurrentTemplate; + if( currentTemplate != null ) + { + m_inVarName = currentTemplate.VertexFunctionData.InVarName + "."; + m_interpolatorData = currentTemplate.VertexDataList; + m_fetchDataId = true; + } + else + { + m_interpolatorData = null; + m_currentDataIdx = -1; + } + } + } + + public override void OnMasterNodeReplaced( MasterNode newMasterNode ) + { + base.OnMasterNodeReplaced( newMasterNode ); + if( newMasterNode.CurrentMasterNodeCategory == AvailableShaderTypes.Template ) + { + FetchInterpolator( newMasterNode ); + } + else + { + m_interpolatorData = null; + m_currentDataIdx = -1; + } + } + + public override void Destroy() + { + base.Destroy(); + m_dataLabels = null; + m_interpolatorData = null; + m_upperLeftWidgetHelper = null; + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateVertexDataNode.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateVertexDataNode.cs.meta new file mode 100644 index 00000000..e697d689 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplateVertexDataNode.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5eb32f2452052fb43b6b93c9baa8f02f +timeCreated: 1506610215 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesBlendModule.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesBlendModule.cs new file mode 100644 index 00000000..93af8a36 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesBlendModule.cs @@ -0,0 +1,782 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using UnityEngine; +using UnityEditor; +using System.Collections.Generic; + +namespace AmplifyShaderEditor +{ + [Serializable] + public sealed class TemplatesBlendModule : TemplateModuleParent + { + private const string AlphaToMaskStr = "Alpha To Coverage"; + private const string BlendModeStr = " Blend Mode"; + + private const string BlendModesRGBStr = "Blend RGB"; + private const string BlendModesAlphaStr = "Blend Alpha"; + + private const string BlendOpsRGBStr = "Blend Op RGB"; + private const string BlendOpsAlphaStr = "Blend Op Alpha"; + + private const string SourceFactorStr = "Src"; + private const string DstFactorStr = "Dst"; + + private const string AlphaToMaskFormat = "AlphaToMask {0}"; + private const string BlendFactorOff = "Blend Off"; + private const string SingleBlendFactorStr = "Blend {0} {1}"; + private const string SeparateBlendFactorStr = "Blend {0} {1} , {2} {3}"; + + private const string SingleBlendOpStr = "BlendOp {0}"; + private const string SeparateBlendOpStr = "BlendOp {0} , {1}"; + private const string BlendOpOffStr = "BlendOp Off"; + + + private string[] m_commonBlendTypesArr; + private List<CommonBlendTypes> m_commonBlendTypes = new List<CommonBlendTypes> + { + new CommonBlendTypes("<OFF>", AvailableBlendFactor.Zero, AvailableBlendFactor.Zero ), + new CommonBlendTypes("Custom", AvailableBlendFactor.Zero, AvailableBlendFactor.Zero ) , + new CommonBlendTypes("Alpha Blend", AvailableBlendFactor.SrcAlpha, AvailableBlendFactor.OneMinusSrcAlpha ) , + new CommonBlendTypes("Premultiplied", AvailableBlendFactor.One, AvailableBlendFactor.OneMinusSrcAlpha ), + new CommonBlendTypes("Additive", AvailableBlendFactor.One, AvailableBlendFactor.One ), + new CommonBlendTypes("Soft Additive", AvailableBlendFactor.OneMinusDstColor, AvailableBlendFactor.One ), + new CommonBlendTypes("Multiplicative", AvailableBlendFactor.DstColor, AvailableBlendFactor.Zero ), + new CommonBlendTypes("2x Multiplicative", AvailableBlendFactor.DstColor, AvailableBlendFactor.SrcColor ), + new CommonBlendTypes("Particle Additive", AvailableBlendFactor.SrcAlpha, AvailableBlendFactor.One ) + }; + + [SerializeField] + private bool m_validBlendMode = false; + + [SerializeField] + private bool m_validBlendOp = false; + + [SerializeField] + private bool m_blendModeEnabled = false; + + [SerializeField] + private bool m_validAlphaToMask = false; + + [SerializeField] + private bool m_alphaToMaskValue = false; + + [SerializeField] + private bool m_alphaToMaskIndependent = false; + + // Blend Factor + // RGB + [SerializeField] + private int m_currentRGBIndex = 0; + + [SerializeField] + private AvailableBlendFactor m_sourceFactorRGB = AvailableBlendFactor.Zero; + [SerializeField] + private InlineProperty m_sourceFactorRGBInline = new InlineProperty(); + + [SerializeField] + private AvailableBlendFactor m_destFactorRGB = AvailableBlendFactor.Zero; + [SerializeField] + private InlineProperty m_destFactorRGBInline = new InlineProperty(); + + //Alpha + [SerializeField] + private int m_currentAlphaIndex = 0; + + [SerializeField] + private AvailableBlendFactor m_sourceFactorAlpha = AvailableBlendFactor.Zero; + [SerializeField] + private InlineProperty m_sourceFactorAlphaInline = new InlineProperty(); + + [SerializeField] + private AvailableBlendFactor m_destFactorAlpha = AvailableBlendFactor.Zero; + [SerializeField] + private InlineProperty m_destFactorAlphaInline = new InlineProperty(); + + //Blend Ops + [SerializeField] + private bool m_blendOpEnabled = false; + + [SerializeField] + private AvailableBlendOps m_blendOpRGB = AvailableBlendOps.OFF; + + [SerializeField] + private InlineProperty m_blendOpRGBInline = new InlineProperty(); + + [SerializeField] + private AvailableBlendOps m_blendOpAlpha = AvailableBlendOps.OFF; + + [SerializeField] + private InlineProperty m_blendOpAlphaInline = new InlineProperty(); + + public TemplatesBlendModule() : base( "Blend Mode and Ops" ) + { + m_commonBlendTypesArr = new string[ m_commonBlendTypes.Count ]; + for( int i = 0; i < m_commonBlendTypesArr.Length; i++ ) + { + m_commonBlendTypesArr[ i ] = m_commonBlendTypes[ i ].Name; + } + } + + public void CopyFrom( TemplatesBlendModule other, bool allData ) + { + if( allData ) + { + m_independentModule = other.IndependentModule; + m_alphaToMaskIndependent = other.AlphaToMaskIndependent; + m_validBlendMode = other.ValidBlendMode; + m_validBlendOp = other.ValidBlendOp; + m_validAlphaToMask = other.ValidAlphaToMask; + } + m_alphaToMaskValue = other.AlphaToMaskValue; + m_blendModeEnabled = other.BlendModeEnabled; + m_currentRGBIndex = other.CurrentRGBIndex; + m_sourceFactorRGB = other.SourceFactorRGB; + m_destFactorRGB = other.DestFactorRGB; + m_currentAlphaIndex = other.CurrentAlphaIndex; + m_sourceFactorAlpha = other.SourceFactorAlpha; + m_destFactorAlpha = other.DestFactorAlpha; + m_blendOpEnabled = other.BlendOpEnabled; + m_blendOpRGB = other.BlendOpRGB; + m_blendOpAlpha = other.BlendOpAlpha; + m_sourceFactorRGBInline = other.SourceFactorRGBInline; + m_destFactorRGBInline = other.DestFactorRGBInline; + m_sourceFactorAlphaInline = other.SourceFactorAlphaInline; + m_destFactorAlphaInline = other.DestFactorAlphaInline; + m_blendOpRGBInline = other.BlendOpRGBInline; + m_blendOpAlphaInline = other.BlendOpAlphaInline; + } + + public void ConfigureFromTemplateData( TemplateBlendData blendData ) + { + if( blendData.ValidAlphaToMask ) + { + if( m_validAlphaToMask != blendData.ValidAlphaToMask ) + { + m_alphaToMaskValue = blendData.AlphaToMaskValue; + m_validAlphaToMask = blendData.ValidAlphaToMask; + m_alphaToMaskIndependent = blendData.IndependentAlphaToMask; + } + } + + if( blendData.ValidBlendMode ) + { + if( m_validBlendMode != blendData.ValidBlendMode ) + { + m_blendModeEnabled = true; + m_independentModule = blendData.IndependentModule; + if( string.IsNullOrEmpty( blendData.SourceFactorRGBInline ) ) + { + m_sourceFactorRGB = blendData.SourceFactorRGB; + m_sourceFactorRGBInline.ResetProperty(); + } + else + { + m_sourceFactorRGBInline.SetInlineByName( blendData.SourceFactorRGBInline ); + } + + if( string.IsNullOrEmpty( blendData.DestFactorRGBInline ) ) + { + m_destFactorRGB = blendData.DestFactorRGB; + m_destFactorRGBInline.ResetProperty(); + } + else + { + m_destFactorRGBInline.SetInlineByName( blendData.DestFactorRGBInline ); + } + + if( string.IsNullOrEmpty( blendData.SourceFactorAlphaInline ) ) + { + m_sourceFactorAlpha = blendData.SourceFactorAlpha; + m_sourceFactorAlphaInline.ResetProperty(); + } + else + { + m_sourceFactorAlphaInline.SetInlineByName( blendData.SourceFactorAlphaInline ); + } + if( string.IsNullOrEmpty( blendData.DestFactorAlphaInline ) ) + { + m_destFactorAlpha = blendData.DestFactorAlpha; + m_destFactorAlphaInline.ResetProperty(); + } + else + { + m_destFactorAlphaInline.SetInlineByName( blendData.DestFactorAlphaInline ); + } + + if( blendData.SeparateBlendFactors ) + { + if( blendData.BlendModeOff ) + { + m_currentRGBIndex = 0; + } + else + { + CheckRGBIndex(); + } + CheckAlphaIndex(); + } + else + { + if( blendData.BlendModeOff ) + { + m_currentRGBIndex = 0; + } + else + { + CheckRGBIndex(); + } + m_currentAlphaIndex = 0; + } + } + } + else + { + m_blendModeEnabled = false; + } + + if( blendData.ValidBlendOp ) + { + if( m_validBlendOp != blendData.ValidBlendOp ) + { + m_blendOpEnabled = true; + if( string.IsNullOrEmpty( blendData.BlendOpRGBInline ) ) + { + m_blendOpRGB = blendData.BlendOpRGB; + m_blendOpRGBInline.ResetProperty(); + } + else + { + m_blendOpRGBInline.SetInlineByName( blendData.BlendOpRGBInline ); + } + + if( string.IsNullOrEmpty( blendData.BlendOpAlphaInline ) ) + { + m_blendOpAlpha = blendData.BlendOpAlpha; + m_blendOpAlphaInline.ResetProperty(); + } + else + { + m_blendOpAlphaInline.SetInlineByName( blendData.BlendOpAlphaInline ); + } + } + } + else + { + m_blendOpEnabled = false; + } + + m_validBlendMode = blendData.ValidBlendMode; + m_validBlendOp = blendData.ValidBlendOp; + m_validData = m_validBlendMode || m_validBlendOp; + } + + public override void ShowUnreadableDataMessage( ParentNode owner ) + { + bool foldout = owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedBlendModeModule; + NodeUtils.DrawPropertyGroup( ref foldout, BlendModeStr, base.ShowUnreadableDataMessage ); + owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedBlendModeModule = foldout; + } + + public override void Draw( UndoParentNode owner, bool style = true ) + { + bool foldout = owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedBlendModeModule; + if( style ) + { + NodeUtils.DrawPropertyGroup( ref foldout, BlendModeStr, () => + { + DrawBlock( owner, style ); + } ); + } + else + { + NodeUtils.DrawNestedPropertyGroup( ref foldout, BlendModeStr, () => + { + DrawBlock( owner, style ); + } ); + } + owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedBlendModeModule = foldout; + } + + void DrawBlock( UndoParentNode owner, bool style ) + { + EditorGUI.BeginChangeCheck(); + { + if( m_blendModeEnabled ) + { + // RGB + EditorGUI.BeginChangeCheck(); + m_currentRGBIndex = owner.EditorGUILayoutPopup( BlendModesRGBStr, m_currentRGBIndex, m_commonBlendTypesArr ); + if( EditorGUI.EndChangeCheck() ) + { + if( m_currentRGBIndex > 1 ) + { + m_sourceFactorRGB = m_commonBlendTypes[ m_currentRGBIndex ].SourceFactor; + m_sourceFactorRGBInline.IntValue = (int)m_sourceFactorRGB; + m_sourceFactorRGBInline.SetInlineNodeValue(); + + m_destFactorRGB = m_commonBlendTypes[ m_currentRGBIndex ].DestFactor; + m_destFactorRGBInline.IntValue = (int)m_destFactorRGB; + m_destFactorRGBInline.SetInlineNodeValue(); + } + } + EditorGUI.BeginDisabledGroup( m_currentRGBIndex == 0 ); + + EditorGUI.BeginChangeCheck(); + float cached = EditorGUIUtility.labelWidth; + if( style ) + { + EditorGUIUtility.labelWidth = 40; + } + else + { + EditorGUIUtility.labelWidth = 25; + } + + EditorGUILayout.BeginHorizontal(); + //m_sourceFactorRGB = (AvailableBlendFactor)owner.EditorGUILayoutEnumPopup( SourceFactorStr, m_sourceFactorRGB ); + m_sourceFactorRGBInline.CustomDrawer( ref owner, ( x ) => { m_sourceFactorRGB = (AvailableBlendFactor)x.EditorGUILayoutEnumPopup( SourceFactorStr, m_sourceFactorRGB ); }, SourceFactorStr ); + if( style ) + { + EditorGUI.indentLevel--; + EditorGUIUtility.labelWidth = 25; + } + //m_destFactorRGB = (AvailableBlendFactor)owner.EditorGUILayoutEnumPopup( DstFactorStr, m_destFactorRGB ); + m_destFactorRGBInline.CustomDrawer( ref owner, ( x ) => { m_destFactorRGB = (AvailableBlendFactor)x.EditorGUILayoutEnumPopup( DstFactorStr, m_destFactorRGB ); }, DstFactorStr ); + if( style ) + EditorGUI.indentLevel++; + + EditorGUILayout.EndHorizontal(); + + EditorGUIUtility.labelWidth = cached; + if( EditorGUI.EndChangeCheck() ) + { + CheckRGBIndex(); + } + + EditorGUI.EndDisabledGroup(); + // Alpha + EditorGUILayout.Separator(); + + EditorGUI.BeginChangeCheck(); + m_currentAlphaIndex = owner.EditorGUILayoutPopup( BlendModesAlphaStr, m_currentAlphaIndex, m_commonBlendTypesArr ); + if( EditorGUI.EndChangeCheck() ) + { + if( m_currentAlphaIndex > 0 ) + { + m_sourceFactorAlpha = m_commonBlendTypes[ m_currentAlphaIndex ].SourceFactor; + m_sourceFactorAlphaInline.IntValue = (int)m_sourceFactorAlpha; + m_sourceFactorAlphaInline.SetInlineNodeValue(); + + m_destFactorAlpha = m_commonBlendTypes[ m_currentAlphaIndex ].DestFactor; + m_destFactorAlphaInline.IntValue = (int)m_destFactorAlpha; + m_destFactorAlphaInline.SetInlineNodeValue(); + } + } + EditorGUI.BeginDisabledGroup( m_currentAlphaIndex == 0 ); + + EditorGUI.BeginChangeCheck(); + cached = EditorGUIUtility.labelWidth; + if( style ) + { + EditorGUIUtility.labelWidth = 40; + } + else + { + EditorGUIUtility.labelWidth = 25; + } + EditorGUILayout.BeginHorizontal(); + //m_sourceFactorAlpha = (AvailableBlendFactor)owner.EditorGUILayoutEnumPopup( SourceFactorStr, m_sourceFactorAlpha ); + m_sourceFactorAlphaInline.CustomDrawer( ref owner, ( x ) => { m_sourceFactorAlpha = (AvailableBlendFactor)x.EditorGUILayoutEnumPopup( SourceFactorStr, m_sourceFactorAlpha ); }, SourceFactorStr ); + if( style ) + { + EditorGUI.indentLevel--; + EditorGUIUtility.labelWidth = 25; + } + //m_destFactorAlpha = (AvailableBlendFactor)owner.EditorGUILayoutEnumPopup( DstFactorStr, m_destFactorAlpha ); + m_destFactorAlphaInline.CustomDrawer( ref owner, ( x ) => { m_destFactorAlpha = (AvailableBlendFactor)x.EditorGUILayoutEnumPopup( DstFactorStr, m_destFactorAlpha ); }, DstFactorStr ); + if( style ) + EditorGUI.indentLevel++; + EditorGUILayout.EndHorizontal(); + EditorGUIUtility.labelWidth = cached; + + if( EditorGUI.EndChangeCheck() ) + { + CheckAlphaIndex(); + } + + EditorGUI.EndDisabledGroup(); + EditorGUILayout.Separator(); + } + + if( m_blendOpEnabled ) + { + // Both these tests should be removed on a later stage + // ASE v154dev004 changed AvailableBlendOps.OFF value from -1 to 0 + // If importing the new package into an already opened ASE window makes + // hotcode to preserve the -1 value on these variables + if( (int)m_blendOpRGB == -1 ) + m_blendOpRGB = AvailableBlendOps.OFF; + + if( (int)m_blendOpAlpha == -1 ) + m_blendOpAlpha = AvailableBlendOps.OFF; + + //m_blendOpRGB = (AvailableBlendOps)owner.EditorGUILayoutEnumPopup( BlendOpsRGBStr, m_blendOpRGB ); + m_blendOpRGBInline.CustomDrawer( ref owner, ( x ) => { m_blendOpRGB = (AvailableBlendOps)x.EditorGUILayoutPopup( BlendOpsRGBStr, (int)m_blendOpRGB, BlendOpsHelper.BlendOpsLabels ); }, BlendOpsRGBStr ); + EditorGUILayout.Separator(); + //m_blendOpAlpha = (AvailableBlendOps)owner.EditorGUILayoutEnumPopup( BlendOpsAlphaStr, m_blendOpAlpha ); + m_blendOpAlphaInline.CustomDrawer( ref owner, ( x ) => { m_blendOpAlpha = (AvailableBlendOps)x.EditorGUILayoutPopup( BlendOpsAlphaStr, (int)m_blendOpAlpha, BlendOpsHelper.BlendOpsLabels ); }, BlendOpsAlphaStr ); + } + + if( m_validAlphaToMask ) + { + EditorGUILayout.Space(); + m_alphaToMaskValue = owner.EditorGUILayoutToggle( AlphaToMaskStr, m_alphaToMaskValue ); + } + } + + if( EditorGUI.EndChangeCheck() ) + { + m_isDirty = true; + } + } + + void CheckRGBIndex() + { + int count = m_commonBlendTypes.Count; + m_currentRGBIndex = 1; + for( int i = 1; i < count; i++ ) + { + if( m_commonBlendTypes[ i ].SourceFactor == m_sourceFactorRGB && m_commonBlendTypes[ i ].DestFactor == m_destFactorRGB ) + { + m_currentRGBIndex = i; + return; + } + } + + } + + void CheckAlphaIndex() + { + int count = m_commonBlendTypes.Count; + m_currentAlphaIndex = 1; + for( int i = 1; i < count; i++ ) + { + if( m_commonBlendTypes[ i ].SourceFactor == m_sourceFactorAlpha && m_commonBlendTypes[ i ].DestFactor == m_destFactorAlpha ) + { + m_currentAlphaIndex = i; + if( m_currentAlphaIndex > 0 && m_currentRGBIndex == 0 ) + m_currentRGBIndex = 1; + return; + } + } + + if( m_currentAlphaIndex > 0 && m_currentRGBIndex == 0 ) + m_currentRGBIndex = 1; + } + + public void ReadAlphaToMaskFromString( ref uint index, ref string[] nodeParams ) + { + if( UIUtils.CurrentShaderVersion() > 16102 ) + { + m_validAlphaToMask = Convert.ToBoolean( nodeParams[ index++ ] ); + if( m_validAlphaToMask ) + { + m_alphaToMaskValue = Convert.ToBoolean( nodeParams[ index++ ] ); + } + } + } + + public void ReadBlendModeFromString( ref uint index, ref string[] nodeParams ) + { + bool validDataOnMeta = m_validBlendMode; + if( UIUtils.CurrentShaderVersion() > TemplatesManager.MPShaderVersion ) + { + validDataOnMeta = Convert.ToBoolean( nodeParams[ index++ ] ); + } + + if( validDataOnMeta ) + { + if( UIUtils.CurrentShaderVersion() < 15304 ) + { + m_currentRGBIndex = Convert.ToInt32( nodeParams[ index++ ] ); + m_sourceFactorRGB = (AvailableBlendFactor)Enum.Parse( typeof( AvailableBlendFactor ), nodeParams[ index++ ] ); + m_destFactorRGB = (AvailableBlendFactor)Enum.Parse( typeof( AvailableBlendFactor ), nodeParams[ index++ ] ); + + m_currentAlphaIndex = Convert.ToInt32( nodeParams[ index++ ] ); + m_sourceFactorAlpha = (AvailableBlendFactor)Enum.Parse( typeof( AvailableBlendFactor ), nodeParams[ index++ ] ); + m_destFactorAlpha = (AvailableBlendFactor)Enum.Parse( typeof( AvailableBlendFactor ), nodeParams[ index++ ] ); + } + else + { + m_currentRGBIndex = Convert.ToInt32( nodeParams[ index++ ] ); + m_sourceFactorRGBInline.ReadFromString( ref index, ref nodeParams ); + m_sourceFactorRGB = (AvailableBlendFactor)m_sourceFactorRGBInline.IntValue; + m_destFactorRGBInline.ReadFromString( ref index, ref nodeParams ); + m_destFactorRGB = (AvailableBlendFactor)m_destFactorRGBInline.IntValue; + + m_currentAlphaIndex = Convert.ToInt32( nodeParams[ index++ ] ); + m_sourceFactorAlphaInline.ReadFromString( ref index, ref nodeParams ); + m_sourceFactorAlpha = (AvailableBlendFactor)m_sourceFactorAlphaInline.IntValue; + m_destFactorAlphaInline.ReadFromString( ref index, ref nodeParams ); + m_destFactorAlpha = (AvailableBlendFactor)m_destFactorAlphaInline.IntValue; + } + } + } + + public void ReadBlendOpFromString( ref uint index, ref string[] nodeParams ) + { + bool validDataOnMeta = m_validBlendOp; + if( UIUtils.CurrentShaderVersion() > TemplatesManager.MPShaderVersion ) + { + validDataOnMeta = Convert.ToBoolean( nodeParams[ index++ ] ); + } + + if( validDataOnMeta ) + { + if( UIUtils.CurrentShaderVersion() < 15304 ) + { + m_blendOpRGB = (AvailableBlendOps)Enum.Parse( typeof( AvailableBlendOps ), nodeParams[ index++ ] ); + m_blendOpAlpha = (AvailableBlendOps)Enum.Parse( typeof( AvailableBlendOps ), nodeParams[ index++ ] ); + } + else + { + m_blendOpRGBInline.ReadFromString( ref index, ref nodeParams ); + m_blendOpAlphaInline.ReadFromString( ref index, ref nodeParams ); + + if( UIUtils.CurrentShaderVersion() < 15404 ) + { + // Now BlendOps enum starts at 0 and not -1 + m_blendOpRGBInline.FloatValue += 1; + m_blendOpAlphaInline.FloatValue += 1; + } + + m_blendOpRGB = (AvailableBlendOps)m_blendOpRGBInline.IntValue; + m_blendOpAlpha = (AvailableBlendOps)m_blendOpAlphaInline.IntValue; + } + //m_blendOpEnabled = ( m_blendOpRGB != AvailableBlendOps.OFF ); + } + } + public void WriteAlphaToMaskToString( ref string nodeInfo ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_validAlphaToMask ); + if( m_validAlphaToMask ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_alphaToMaskValue ); + } + } + + public void WriteBlendModeToString( ref string nodeInfo ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_validBlendMode ); + if( m_validBlendMode ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_currentRGBIndex ); + if( !m_sourceFactorRGBInline.IsValid ) m_sourceFactorRGBInline.IntValue = (int)m_sourceFactorRGB; + m_sourceFactorRGBInline.WriteToString( ref nodeInfo ); + + if( !m_destFactorRGBInline.IsValid ) m_destFactorRGBInline.IntValue = (int)m_destFactorRGB; + m_destFactorRGBInline.WriteToString( ref nodeInfo ); + + IOUtils.AddFieldValueToString( ref nodeInfo, m_currentAlphaIndex ); + if( !m_sourceFactorAlphaInline.IsValid ) m_sourceFactorAlphaInline.IntValue = (int)m_sourceFactorAlpha; + m_sourceFactorAlphaInline.WriteToString( ref nodeInfo ); + + if( !m_destFactorAlphaInline.IsValid ) m_destFactorAlphaInline.IntValue = (int)m_destFactorAlpha; + m_destFactorAlphaInline.WriteToString( ref nodeInfo ); + } + } + + public void WriteBlendOpToString( ref string nodeInfo ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_validBlendOp ); + if( m_validBlendOp ) + { + if( !m_blendOpRGBInline.IsValid ) m_blendOpRGBInline.IntValue = (int)m_blendOpRGB; + m_blendOpRGBInline.WriteToString( ref nodeInfo ); + + if( !m_blendOpAlphaInline.IsValid ) m_blendOpAlphaInline.IntValue = (int)m_blendOpAlpha; + m_blendOpAlphaInline.WriteToString( ref nodeInfo ); + } + } + + public override void ReadFromString( ref uint index, ref string[] nodeParams ) + { + ReadBlendModeFromString( ref index, ref nodeParams ); + ReadBlendOpFromString( ref index, ref nodeParams ); + ReadAlphaToMaskFromString( ref index, ref nodeParams ); + } + + public override void WriteToString( ref string nodeInfo ) + { + WriteBlendModeToString( ref nodeInfo ); + WriteBlendOpToString( ref nodeInfo ); + WriteAlphaToMaskToString( ref nodeInfo ); + } + + public override void Destroy() + { + base.Destroy(); + m_sourceFactorRGBInline = null; + m_destFactorRGBInline = null; + m_sourceFactorAlphaInline = null; + m_destFactorAlphaInline = null; + m_blendOpRGBInline = null; + m_blendOpAlphaInline = null; + } + + public string CurrentAlphaToMask + { + get + { + return string.Format( AlphaToMaskFormat, m_alphaToMaskValue ? "On" : "Off" ); + } + } + public string CurrentBlendFactorSingle + { + get + { + return ( m_currentRGBIndex > 0 ) ? string.Format( SingleBlendFactorStr, m_sourceFactorRGBInline.GetValueOrProperty( m_sourceFactorRGB.ToString() ), m_destFactorRGBInline.GetValueOrProperty( m_destFactorRGB.ToString() ) ) : BlendFactorOff; + } + } + + public string CurrentBlendFactorSeparate + { + get + { + return string.Format( SeparateBlendFactorStr, + m_sourceFactorRGBInline.GetValueOrProperty( ( m_currentRGBIndex > 0 ? m_sourceFactorRGB.ToString() : AvailableBlendFactor.One.ToString() ) ), + m_destFactorRGBInline.GetValueOrProperty( m_currentRGBIndex > 0 ? m_destFactorRGB.ToString() : AvailableBlendFactor.Zero.ToString() ), + m_sourceFactorAlphaInline.GetValueOrProperty( m_sourceFactorAlpha.ToString() ), + m_destFactorAlphaInline.GetValueOrProperty( m_destFactorAlpha.ToString() ) ); + } + } + + public string CurrentBlendFactor + { + get + { + return ( ( m_currentAlphaIndex > 0 ) ? CurrentBlendFactorSeparate : CurrentBlendFactorSingle ); + } + } + + + public string CurrentBlendOpSingle + { + get + { + return ( m_blendOpRGB != AvailableBlendOps.OFF || m_blendOpRGBInline.IsValid ) ? string.Format( SingleBlendOpStr, m_blendOpRGBInline.GetValueOrProperty( m_blendOpRGB.ToString() ) ) : string.Empty; + } + } + + public string CurrentBlendOpSeparate + { + get + { + return string.Format( SeparateBlendOpStr, m_blendOpRGBInline.GetValueOrProperty( ( m_currentRGBIndex > 0 && m_blendOpRGB != AvailableBlendOps.OFF ) ? m_blendOpRGB.ToString() : AvailableBlendOps.Add.ToString() ), m_blendOpAlphaInline.GetValueOrProperty( m_blendOpAlpha.ToString() ) ); + } + } + + public string CurrentBlendOp { get { return ( ( m_blendOpAlpha != AvailableBlendOps.OFF || m_blendOpAlphaInline.IsValid ) ? CurrentBlendOpSeparate : CurrentBlendOpSingle ); } } + public bool Active { get { return m_blendModeEnabled && ( m_currentRGBIndex > 0 || m_currentAlphaIndex > 0 ); } } + public bool BlendOpActive + { + get + { + return m_blendOpEnabled && + ( + m_blendOpRGBInline.Active || + m_blendOpAlphaInline.Active || + ( !m_blendOpRGBInline.Active && m_blendOpRGB != AvailableBlendOps.OFF ) || + ( !m_blendOpAlphaInline.Active && m_blendOpAlpha != AvailableBlendOps.OFF ) ); + } + } + + public bool ValidBlendMode { get { return m_validBlendMode; } } + public bool ValidBlendOp { get { return m_validBlendOp; } } + public int CurrentRGBIndex { get { return m_currentRGBIndex; } } + + public AvailableBlendFactor SourceFactorRGB + { + get { return m_sourceFactorRGB; } + set + { + m_sourceFactorRGB = value; + m_sourceFactorRGBInline.IntValue = (int)m_sourceFactorRGB; + m_sourceFactorRGBInline.Active = false; + } + + } + public AvailableBlendFactor DestFactorRGB + { + get { return m_destFactorRGB; } + set + { + m_destFactorRGB = value; + m_destFactorRGBInline.IntValue = (int)value; + } + } + + public int CurrentAlphaIndex { get { return m_currentAlphaIndex; } set { m_currentAlphaIndex = value; } } + + public AvailableBlendFactor SourceFactorAlpha + { + get { return m_sourceFactorAlpha; } + set + { + m_sourceFactorAlpha = value; + m_sourceFactorAlphaInline.IntValue = (int)value; + m_sourceFactorAlphaInline.Active = false; + } + } + + public AvailableBlendFactor DestFactorAlpha + { + get { return m_destFactorAlpha; } + set + { + m_destFactorAlpha = value; + m_destFactorAlphaInline.IntValue = (int)value; + m_destFactorAlphaInline.Active = false; + + } + } + + public bool BlendModeEnabled { get { return m_blendModeEnabled; } } + public bool BlendOpEnabled { get { return m_blendOpEnabled; } } + public AvailableBlendOps BlendOpRGB + { + get { return m_blendOpRGB; } + set + { + m_blendOpRGB = value; + m_blendOpRGBInline.IntValue = (int)value; + m_blendOpRGBInline.Active = false; + } + } + + public AvailableBlendOps BlendOpAlpha + { + get { return m_blendOpAlpha; } + set + { + m_blendOpAlpha = value; + m_blendOpAlphaInline.IntValue = (int)value; + m_blendOpAlphaInline.Active = false; + } + } + + public InlineProperty SourceFactorRGBInline { get { return m_sourceFactorRGBInline; } } + public InlineProperty DestFactorRGBInline { get { return m_destFactorRGBInline; } } + public InlineProperty SourceFactorAlphaInline { get { return m_sourceFactorAlphaInline; } } + public InlineProperty DestFactorAlphaInline { get { return m_destFactorAlphaInline; } } + public InlineProperty BlendOpRGBInline { get { return m_blendOpRGBInline; } } + public InlineProperty BlendOpAlphaInline { get { return m_blendOpAlphaInline; } } + public bool IsAdditiveRGB { get { return m_validBlendMode && m_blendModeEnabled && ( m_currentRGBIndex > 0 ) && ( m_sourceFactorRGB == AvailableBlendFactor.One ) && ( m_destFactorRGB == AvailableBlendFactor.One ); } } + public bool IsAlphaBlendRGB { get { return m_validBlendMode && m_blendModeEnabled && ( m_currentRGBIndex > 0 ) && ( m_sourceFactorRGB == AvailableBlendFactor.SrcAlpha ) && ( m_destFactorRGB == AvailableBlendFactor.OneMinusSrcAlpha ); } } + public bool ValidAlphaToMask { get { return m_validAlphaToMask; } } + public bool AlphaToMaskValue { get { return m_alphaToMaskValue; } } + public bool AlphaToMaskIndependent { get { return m_alphaToMaskIndependent; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesBlendModule.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesBlendModule.cs.meta new file mode 100644 index 00000000..b4eeb76e --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesBlendModule.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 7c88941c5badfb7428059cc3ff0c0df9 +timeCreated: 1510933946 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesManager.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesManager.cs new file mode 100644 index 00000000..456cc4df --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesManager.cs @@ -0,0 +1,904 @@ +// Amplify Shader Editor - Visual Shader Editing Tool +// Copyright (c) Amplify Creations, Lda <info@amplify.pt> + +using System; +using UnityEditor; +using System.Collections.Generic; +using UnityEngine; +using System.Text.RegularExpressions; + +namespace AmplifyShaderEditor +{ + [Serializable] + public class TemplateInputData + { + public string PortName; + public WirePortDataType DataType; + public MasterNodePortCategory PortCategory; + public int PortUniqueId; + public int OrderId; + public int TagGlobalStartIdx; + public int TagLocalStartIdx; + public string TagId; + public string DefaultValue; + public string LinkId; + + public TemplateInputData( int tagLocalStartIdx, int tagGlobalStartIdx, string tagId, string portName, string defaultValue, WirePortDataType dataType, MasterNodePortCategory portCategory, int portUniqueId, int orderId, string linkId ) + { + DefaultValue = defaultValue; + PortName = portName; + DataType = dataType; + PortCategory = portCategory; + PortUniqueId = portUniqueId; + OrderId = orderId; + TagId = tagId; + TagGlobalStartIdx = tagGlobalStartIdx; + TagLocalStartIdx = tagLocalStartIdx; + LinkId = linkId; + } + + public TemplateInputData( TemplateInputData other ) + { + DefaultValue = other.DefaultValue; + PortName = other.PortName; + DataType = other.DataType; + PortCategory = other.PortCategory; + PortUniqueId = other.PortUniqueId; + OrderId = other.OrderId; + TagId = other.TagId; + TagGlobalStartIdx = other.TagGlobalStartIdx; + LinkId = other.LinkId; + } + } + + + + [Serializable] + public class TemplatePropertyContainer + { + [SerializeField] + private List<TemplateProperty> m_propertyList = new List<TemplateProperty>(); + private Dictionary<string, TemplateProperty> m_propertyDict = new Dictionary<string, TemplateProperty>(); + + + public void AddId( TemplateProperty templateProperty ) + { + BuildInfo(); + m_propertyList.Add( templateProperty ); + m_propertyDict.Add( templateProperty.Id, templateProperty ); + } + + public void AddId( string body, string ID, bool searchIndentation = true ) + { + AddId( body, ID, searchIndentation, string.Empty ); + } + + public void AddId( string body, string ID, bool searchIndentation, string customIndentation ) + { + BuildInfo(); + + int propertyIndex = body.IndexOf( ID ); + if( propertyIndex > -1 ) + { + if( searchIndentation ) + { + int identationIndex = -1; + for( int i = propertyIndex; i >= 0; i-- ) + { + if( body[ i ] == TemplatesManager.TemplateNewLine ) + { + identationIndex = i + 1; + break; + } + + if( i == 0 ) + { + identationIndex = 0; + } + } + if( identationIndex > -1 ) + { + int length = propertyIndex - identationIndex; + string indentation = ( length > 0 ) ? body.Substring( identationIndex, length ) : string.Empty; + TemplateProperty templateProperty = new TemplateProperty( ID, indentation, false ); + m_propertyList.Add( templateProperty ); + m_propertyDict.Add( templateProperty.Id, templateProperty ); + } + else + { + TemplateProperty templateProperty = new TemplateProperty( ID, string.Empty, false ); + m_propertyList.Add( templateProperty ); + m_propertyDict.Add( templateProperty.Id, templateProperty ); + } + } + else + { + TemplateProperty templateProperty = new TemplateProperty( ID, customIndentation, true ); + m_propertyList.Add( templateProperty ); + m_propertyDict.Add( templateProperty.Id, templateProperty ); + } + } + } + + + public void AddId( string body, string ID, int propertyIndex, bool searchIndentation ) + { + AddId( body, ID, propertyIndex, searchIndentation, string.Empty ); + } + + public void AddId( string body, string ID, int propertyIndex, bool searchIndentation, string customIndentation ) + { + if( body == null || string.IsNullOrEmpty( body ) ) + return; + + BuildInfo(); + if( searchIndentation && propertyIndex > -1 && propertyIndex < body.Length ) + { + int indentationIndex = -1; + for( int i = propertyIndex; i > 0; i-- ) + { + if( body[ i ] == TemplatesManager.TemplateNewLine ) + { + indentationIndex = i + 1; + break; + } + } + + if( indentationIndex > -1 ) + { + int length = propertyIndex - indentationIndex; + string indentation = ( length > 0 ) ? body.Substring( indentationIndex, length ) : string.Empty; + TemplateProperty templateProperty = new TemplateProperty( ID, indentation, false ); + m_propertyList.Add( templateProperty ); + m_propertyDict.Add( templateProperty.Id, templateProperty ); + } + } + else + { + TemplateProperty templateProperty = new TemplateProperty( ID, customIndentation, true ); + m_propertyList.Add( templateProperty ); + m_propertyDict.Add( templateProperty.Id, templateProperty ); + } + + } + public void BuildInfo() + { + if( m_propertyDict == null ) + { + m_propertyDict = new Dictionary<string, TemplateProperty>(); + } + + if( m_propertyList.Count != m_propertyDict.Count ) + { + m_propertyDict.Clear(); + for( int i = 0; i < m_propertyList.Count; i++ ) + { + m_propertyDict.Add( m_propertyList[ i ].Id, m_propertyList[ i ] ); + } + } + } + + public void ResetTemplateUsageData() + { + BuildInfo(); + for( int i = 0; i < m_propertyList.Count; i++ ) + { + m_propertyList[ i ].Used = false; + } + } + + public void Reset() + { + m_propertyList.Clear(); + m_propertyDict.Clear(); + } + + public void Destroy() + { + m_propertyList.Clear(); + m_propertyList = null; + m_propertyDict.Clear(); + m_propertyDict = null; + } + + + public Dictionary<string, TemplateProperty> PropertyDict + { + get + { + BuildInfo(); + return m_propertyDict; + } + } + public List<TemplateProperty> PropertyList { get { return m_propertyList; } } + } + + [Serializable] + public class TemplateProperty + { + public bool UseIndentationAtStart = false; + public string Indentation; + public bool UseCustomIndentation; + public string Id; + public bool AutoLineFeed; + public bool Used; + + public TemplateProperty( string id, string indentation, bool useCustomIndentation ) + { + Id = id; + Indentation = indentation; + UseCustomIndentation = useCustomIndentation; + AutoLineFeed = !string.IsNullOrEmpty( indentation ); + Used = false; + } + } + + [Serializable] + public class TemplateTessVControlTag + { + public string Id; + public int StartIdx; + + public TemplateTessVControlTag() + { + StartIdx = -1; + } + + public bool IsValid { get { return StartIdx >= 0; } } + } + + [Serializable] + public class TemplateTessControlData + { + public string Id; + public int StartIdx; + public string InVarType; + public string InVarName; + public string OutVarType; + public string OutVarName; + + public bool IsValid { get { return StartIdx >= 0; } } + + public TemplateTessControlData() + { + StartIdx = -1; + } + + public TemplateTessControlData( int startIdx, string id, string inVarInfo, string outVarInfo ) + { + StartIdx = startIdx; + Id = id; + string[] inVarInfoArr = inVarInfo.Split( IOUtils.VALUE_SEPARATOR ); + if( inVarInfoArr.Length > 1 ) + { + InVarType = inVarInfoArr[ 1 ]; + InVarName = inVarInfoArr[ 0 ]; + } + + string[] outVarInfoArr = outVarInfo.Split( IOUtils.VALUE_SEPARATOR ); + if( outVarInfoArr.Length > 1 ) + { + OutVarType = outVarInfoArr[ 1 ]; + OutVarName = outVarInfoArr[ 0 ]; + } + } + + public string[] GenerateControl( Dictionary<TemplateSemantics, TemplateVertexData> vertexData, List<string> inputList ) + { + List<string> value = new List<string>(); + if( vertexData != null && vertexData.Count > 0 ) + { + foreach( var item in vertexData ) + { + if( inputList.FindIndex( x => { return x.Contains( item.Value.VarName ); } ) > -1 ) + value.Add( string.Format( "{0}.{1} = {2}.{1};", OutVarName, item.Value.VarName, InVarName ) ); + } + } + return value.ToArray(); + } + } + + [Serializable] + public class TemplateTessDomainData + { + public string Id; + public int StartIdx; + public string InVarType; + public string InVarName; + public string OutVarType; + public string OutVarName; + public string BaryVarType; + public string BaryVarName; + + public bool IsValid { get { return StartIdx >= 0; } } + + public TemplateTessDomainData() + { + StartIdx = -1; + } + + public TemplateTessDomainData( int startIdx, string id, string inVarInfo, string outVarInfo, string baryVarInfo ) + { + StartIdx = startIdx; + Id = id; + string[] inVarInfoArr = inVarInfo.Split( IOUtils.VALUE_SEPARATOR ); + if( inVarInfoArr.Length > 1 ) + { + InVarType = inVarInfoArr[ 1 ]; + InVarName = inVarInfoArr[ 0 ]; + } + + string[] outVarInfoArr = outVarInfo.Split( IOUtils.VALUE_SEPARATOR ); + if( outVarInfoArr.Length > 1 ) + { + OutVarType = outVarInfoArr[ 1 ]; + OutVarName = outVarInfoArr[ 0 ]; + } + + string[] baryVarInfoArr = baryVarInfo.Split( IOUtils.VALUE_SEPARATOR ); + if( baryVarInfoArr.Length > 1 ) + { + BaryVarType = baryVarInfoArr[ 1 ]; + BaryVarName = baryVarInfoArr[ 0 ]; + } + } + + public string[] GenerateDomain( Dictionary<TemplateSemantics, TemplateVertexData> vertexData, List<string> inputList ) + { + List<string> value = new List<string>(); + if( vertexData != null && vertexData.Count > 0 ) + { + foreach( var item in vertexData ) + { + //o.ase_normal = patch[0].ase_normal * bary.x + patch[1].ase_normal * bary.y + patch[2].ase_normal * bary.z; + if( inputList.FindIndex( x => { return x.Contains( item.Value.VarName ); } ) > -1 ) + value.Add( string.Format( "{0}.{1} = {2}[0].{1} * {3}.x + {2}[1].{1} * {3}.y + {2}[2].{1} * {3}.z;", OutVarName, item.Value.VarName, InVarName, BaryVarName ) ); + } + } + return value.ToArray(); + } + } + + [Serializable] + public class TemplateFunctionData + { + public int MainBodyLocalIdx; + public string MainBodyName; + + public string Id; + public int Position; + public string InVarType; + public string InVarName; + public string OutVarType; + public string OutVarName; + public MasterNodePortCategory Category; + public TemplateFunctionData( int mainBodyLocalIdx, string mainBodyName, string id, int position, string inVarInfo, string outVarInfo, MasterNodePortCategory category ) + { + MainBodyLocalIdx = mainBodyLocalIdx; + MainBodyName = mainBodyName; + Id = id; + Position = position; + { + string[] inVarInfoArr = inVarInfo.Split( IOUtils.VALUE_SEPARATOR ); + if( inVarInfoArr.Length > 1 ) + { + InVarType = inVarInfoArr[ 1 ]; + InVarName = inVarInfoArr[ 0 ]; + } + } + { + string[] outVarInfoArr = outVarInfo.Split( IOUtils.VALUE_SEPARATOR ); + if( outVarInfoArr.Length > 1 ) + { + OutVarType = outVarInfoArr[ 1 ]; + OutVarName = outVarInfoArr[ 0 ]; + } + } + Category = category; + } + } + + [Serializable] + public class TemplateTagData + { + public int StartIdx = -1; + public string Id; + public bool SearchIndentation; + public string CustomIndentation; + + + public TemplateTagData( int startIdx, string id, bool searchIndentation ) + { + StartIdx = startIdx; + Id = id; + SearchIndentation = searchIndentation; + CustomIndentation = string.Empty; + } + + public TemplateTagData( string id, bool searchIndentation ) + { + Id = id; + SearchIndentation = searchIndentation; + CustomIndentation = string.Empty; + } + + public TemplateTagData( string id, bool searchIndentation, string customIndentation ) + { + Id = id; + SearchIndentation = searchIndentation; + CustomIndentation = customIndentation; + } + + public bool IsValid { get { return StartIdx >= 0; } } + } + + public enum TemplatePortIds + { + Name = 0, + DataType, + UniqueId, + OrderId, + Link + } + + public enum TemplateCommonTagId + { + Property = 0, + Global = 1, + Function = 2, + Tag = 3, + Pragmas = 4, + Pass = 5, + Params_Vert = 6, + Params_Frag = 7 + //CullMode = 8, + //BlendMode = 9, + //BlendOp = 10, + //ColorMask = 11, + //StencilOp = 12 + } + + [Serializable] + public class TemplatesManager : ScriptableObject + { + public static int MPShaderVersion = 14503; + + public static readonly string TemplateShaderNameBeginTag = "/*ase_name*/"; + public static readonly string TemplateStencilTag = "/*ase_stencil*/\n"; + public static readonly string TemplateAllModulesTag = "/*ase_all_modules*/\n"; + public static readonly string TemplateMPSubShaderTag = "\\bSubShader\\b\\s*{"; + //public static readonly string TemplateMPPassTag = "^\\s*Pass\b\\s*{";//"\\bPass\\b\\s*{"; + public static readonly string TemplateMPPassTag = "\\bPass\\b\\s*{"; + public static readonly string TemplateLocalVarTag = "/*ase_local_var*/"; + public static readonly string TemplateDependenciesListTag = "/*ase_dependencies_list*/"; + public static readonly string TemplatePragmaBeforeTag = "/*ase_pragma_before*/"; + public static readonly string TemplatePragmaTag = "/*ase_pragma*/"; + public static readonly string TemplatePassTag = "/*ase_pass*/"; + public static readonly string TemplatePassesEndTag = "/*ase_pass_end*/"; + public static readonly string TemplateLODsTag = "/*ase_lod*/"; + //public static readonly string TemplatePassTagPattern = @"\s\/\*ase_pass\*\/"; + public static readonly string TemplatePassTagPattern = @"\s\/\*ase_pass[:\*]+"; + public static readonly string TemplatePropertyTag = "/*ase_props*/"; + public static readonly string TemplateGlobalsTag = "/*ase_globals*/"; + public static readonly string TemplateSRPBatcherTag = "/*ase_srp_batcher*/\n"; + public static readonly string TemplateInterpolatorBeginTag = "/*ase_interp("; + public static readonly string TemplateVertexDataTag = "/*ase_vdata:"; + + public static readonly string TemplateTessVControlTag = "/*ase_vcontrol*/"; + public static readonly string TemplateTessControlCodeArea = "/*ase_control_code:"; + public static readonly string TemplateTessDomainCodeArea = "/*ase_domain_code:"; + + //public static readonly string TemplateExcludeFromGraphTag = "/*ase_hide_pass*/"; + public static readonly string TemplateMainPassTag = "/*ase_main_pass*/"; + + public static readonly string TemplateFunctionsTag = "/*ase_funcs*/\n"; + //public static readonly string TemplateTagsTag = "/*ase_tags*/"; + + //public static readonly string TemplateCullModeTag = "/*ase_cull_mode*/"; + //public static readonly string TemplateBlendModeTag = "/*ase_blend_mode*/"; + //public static readonly string TemplateBlendOpTag = "/*ase_blend_op*/"; + //public static readonly string TemplateColorMaskTag = "/*ase_color_mask*/"; + //public static readonly string TemplateStencilOpTag = "/*ase_stencil*/"; + + public static readonly string TemplateCodeSnippetAttribBegin = "#CODE_SNIPPET_ATTRIBS_BEGIN#"; + public static readonly string TemplateCodeSnippetAttribEnd = "#CODE_SNIPPET_ATTRIBS_END#\n"; + public static readonly string TemplateCodeSnippetEnd = "#CODE_SNIPPET_END#\n"; + + public static readonly char TemplateNewLine = '\n'; + + // INPUTS AREA + public static readonly string TemplateInputsVertBeginTag = "/*ase_vert_out:"; + public static readonly string TemplateInputsFragBeginTag = "/*ase_frag_out:"; + public static readonly string TemplateInputsVertParamsTag = "/*ase_vert_input*/"; + public static readonly string TemplateInputsFragParamsTag = "/*ase_frag_input*/"; + + + // CODE AREA + public static readonly string TemplateVertexCodeBeginArea = "/*ase_vert_code:"; + public static readonly string TemplateFragmentCodeBeginArea = "/*ase_frag_code:"; + + + public static readonly string TemplateEndOfLine = "*/\n"; + public static readonly string TemplateEndSectionTag = "*/"; + public static readonly string TemplateFullEndTag = "/*end*/"; + + public static readonly string NameFormatter = "\"{0}\""; + + public static readonly TemplateTagData[] CommonTags = { new TemplateTagData( TemplatePropertyTag,true), + new TemplateTagData( TemplateGlobalsTag,true), + new TemplateTagData( TemplateSRPBatcherTag,true), + new TemplateTagData( TemplateFunctionsTag,true), + //new TemplateTagData( TemplateTagsTag,false," "), + new TemplateTagData( TemplatePragmaBeforeTag,true), + new TemplateTagData( TemplatePragmaTag,true), + new TemplateTagData( TemplatePassTag,true), + new TemplateTagData( TemplateInputsVertParamsTag,false), + new TemplateTagData( TemplateInputsFragParamsTag,false), + new TemplateTagData( TemplateLODsTag,true) + //new TemplateTagData( TemplateCullModeTag,false), + //new TemplateTagData( TemplateBlendModeTag,false), + //new TemplateTagData( TemplateBlendOpTag,false), + //new TemplateTagData( TemplateColorMaskTag,false), + //new TemplateTagData( TemplateStencilOpTag,true), + }; + public static string LightweigthPBRGUID = "1976390536c6c564abb90fe41f6ee334"; + public static string LightweigthUnlitGUID = "e2514bdcf5e5399499a9eb24d175b9db"; + public static string UniversalPBRGUID = "94348b07e5e8bab40bd6c8a1e3df54cd"; + public static string UniversalUnlitGUID = "2992e84f91cbeb14eab234972e07ea9d"; + + public static string HDNewLitGUID = "53b46d85872c5b24c8f4f0a1c3fe4c87"; + public static string HDNewPBRGUID = "41e04be03f2c20941bc749271be1c937"; + public static string HDNewUnlitGUID = "7f5cb9c3ea6481f469fdd856555439ef"; + public static string HDLitGUID = "091c43ba8bd92c9459798d59b089ce4e"; + public static string HDPBRGUID = "bb308bce79762c34e823049efce65141"; + public static string HDUnlitGUID = "dfe2f27ac20b08c469b2f95c236be0c3"; + + public static Dictionary<string, string> OfficialTemplates = new Dictionary<string, string>() + { + { "0770190933193b94aaa3065e307002fa","Legacy/Unlit"}, + { "32139be9c1eb75640a847f011acf3bcf","Legacy/Post-Processing Stack"}, + { "6ce779933eb99f049b78d6163735e06f","Legacy/Custom RT Init"}, + { "32120270d1b3a8746af2aca8bc749736","Legacy/Custom RT Update"}, + { LightweigthPBRGUID,"LW/PBR"}, + { LightweigthUnlitGUID,"LW/Unlit"}, + { UniversalPBRGUID,"Universal/PBR"}, + { UniversalUnlitGUID,"Universal/Unlit"}, + { "53b46d85872c5b24c8f4f0a1c3fe4c87","HD/Lit"}, + { HDLitGUID,"Deprecated/HD/Lit"}, + { HDPBRGUID,"Deprecated/HD/PBR"}, + { HDUnlitGUID,"Deprecated/HD/Unlit"}, + { "c71b220b631b6344493ea3cf87110c93","Legacy/Post Process" }, + { "6e114a916ca3e4b4bb51972669d463bf","Deprecated/Legacy/Default Unlit" }, + { "5056123faa0c79b47ab6ad7e8bf059a4","Legacy/Default UI" }, + { "899e609c083c74c4ca567477c39edef0","Legacy/Unlit Lightmap" }, + { "0f8ba0101102bb14ebf021ddadce9b49","Legacy/Default Sprites" }, + { "0b6a9f8b4f707c74ca64c0be8e590de0","Legacy/Particles Alpha Blended" }, + { "e1de45c0d41f68c41b2cc20c8b9c05ef","Legacy/Multi Pass Unlit" } + }; + + public static readonly string TemplateMenuItemsFileGUID = "da0b931bd234a1e43b65f684d4b59bfb"; + + private Dictionary<string, TemplateDataParent> m_availableTemplates = new Dictionary<string, TemplateDataParent>(); + + [SerializeField] + private List<TemplateDataParent> m_sortedTemplates = new List<TemplateDataParent>(); + + [SerializeField] + public string[] AvailableTemplateNames; + + [SerializeField] + public bool Initialized = false; + + private Dictionary<string, bool> m_optionsInitialSetup = new Dictionary<string, bool>(); + + public static string CurrTemplateGUIDLoaded = string.Empty; + + public static bool IsTestTemplate { get { return CurrTemplateGUIDLoaded.Equals( "a95a019bbc760714bb8228af04c291d1" ); } } + public static bool ShowDebugMessages = false; + public void RefreshAvailableTemplates() + { + if( m_availableTemplates.Count != m_sortedTemplates.Count ) + { + m_availableTemplates.Clear(); + int count = m_sortedTemplates.Count; + for( int i = 0; i < count; i++ ) + { + m_availableTemplates.Add( m_sortedTemplates[ i ].GUID, m_sortedTemplates[ i ] ); + } + } + } + + public void Init() + { + if( !Initialized ) + { + if( ShowDebugMessages ) + Debug.Log( "Initialize" ); + + string templateMenuItems = IOUtils.LoadTextFileFromDisk( AssetDatabase.GUIDToAssetPath( TemplateMenuItemsFileGUID ) ); + bool refreshTemplateMenuItems = false; + + foreach( KeyValuePair<string, string> kvp in OfficialTemplates ) + { + if( !string.IsNullOrEmpty( AssetDatabase.GUIDToAssetPath( kvp.Key ) ) ) + { + TemplateMultiPass template = ScriptableObject.CreateInstance<TemplateMultiPass>(); + template.Init( kvp.Value, kvp.Key, false ); + AddTemplate( template ); + if( !refreshTemplateMenuItems && templateMenuItems.IndexOf( kvp.Value ) < 0 ) + refreshTemplateMenuItems = true; + } + } + + // Search for other possible templates on the project + string[] allShaders = AssetDatabase.FindAssets( "t:shader" ); + for( int i = 0; i < allShaders.Length; i++ ) + { + if( !m_availableTemplates.ContainsKey( allShaders[ i ] ) ) + { + CheckAndLoadTemplate( allShaders[ i ] ); + } + } + + // TODO: Sort list alphabeticaly + AvailableTemplateNames = new string[ m_sortedTemplates.Count + 1 ]; + AvailableTemplateNames[ 0 ] = "Custom"; + for( int i = 0; i < m_sortedTemplates.Count; i++ ) + { + m_sortedTemplates[ i ].OrderId = i; + AvailableTemplateNames[ i + 1 ] = m_sortedTemplates[ i ].Name; + } + + if( refreshTemplateMenuItems ) + CreateTemplateMenuItems(); + + Initialized = true; + } + } + + //[MenuItem( "Window/Amplify Shader Editor/Create Menu Items", false, 1000 )] + //public static void ForceCreateTemplateMenuItems() + //{ + // UIUtils.CurrentWindow.TemplatesManagerInstance.CreateTemplateMenuItems(); + //} + + public void CreateTemplateMenuItems() + { + if( m_sortedTemplates == null || m_sortedTemplates.Count == 0 ) + return; + + // change names for duplicates + for( int i = 0; i < m_sortedTemplates.Count; i++ ) + { + for( int j = 0; j < i; j++ ) + { + if( m_sortedTemplates[ i ].Name == m_sortedTemplates[ j ].Name ) + { + var match = Regex.Match( m_sortedTemplates[ i ].Name, @".+(\d+)" ); + if( match.Success ) + { + string strNumber = match.Groups[ 1 ].Value; + int number = int.Parse( strNumber ) + 1; + string firstPart = m_sortedTemplates[ i ].Name.Substring( 0, match.Groups[ 1 ].Index ); + string secondPart = m_sortedTemplates[ i ].Name.Substring( match.Groups[ 1 ].Index + strNumber.Length ); + m_sortedTemplates[ i ].Name = firstPart + number + secondPart; + } + else + { + m_sortedTemplates[ i ].Name += " 1"; + } + } + } + } + + System.Text.StringBuilder fileContents = new System.Text.StringBuilder(); + fileContents.Append( "// Amplify Shader Editor - Visual Shader Editing Tool\n" ); + fileContents.Append( "// Copyright (c) Amplify Creations, Lda <info@amplify.pt>\n" ); + fileContents.Append( "using UnityEditor;\n" ); + fileContents.Append( "\n" ); + fileContents.Append( "namespace AmplifyShaderEditor\n" ); + fileContents.Append( "{\n" ); + fileContents.Append( "\tpublic class TemplateMenuItems\n" ); + fileContents.Append( "\t{\n" ); + int fixedPriority = 85; + for( int i = 0; i < m_sortedTemplates.Count; i++ ) + { + fileContents.AppendFormat( "\t\t[MenuItem( \"Assets/Create/Amplify Shader/{0}\", false, {1} )]\n", m_sortedTemplates[ i ].Name, fixedPriority ); + string itemName = UIUtils.RemoveInvalidCharacters( m_sortedTemplates[ i ].Name ); + fileContents.AppendFormat( "\t\tpublic static void ApplyTemplate{0}()\n", itemName/*i*/ ); + fileContents.Append( "\t\t{\n" ); + //fileContents.AppendFormat( "\t\t\tAmplifyShaderEditorWindow.CreateNewTemplateShader( \"{0}\" );\n", m_sortedTemplates[ i ].GUID ); + fileContents.AppendFormat( "\t\t\tAmplifyShaderEditorWindow.CreateConfirmationTemplateShader( \"{0}\" );\n", m_sortedTemplates[ i ].GUID ); + fileContents.Append( "\t\t}\n" ); + } + fileContents.Append( "\t}\n" ); + fileContents.Append( "}\n" ); + string filePath = AssetDatabase.GUIDToAssetPath( TemplateMenuItemsFileGUID ); + IOUtils.SaveTextfileToDisk( fileContents.ToString(), filePath, false ); + AssetDatabase.ImportAsset( filePath ); + } + + public int GetIdForTemplate( TemplateData templateData ) + { + if( templateData == null ) + return -1; + + for( int i = 0; i < m_sortedTemplates.Count; i++ ) + { + if( m_sortedTemplates[ i ].GUID.Equals( templateData.GUID ) ) + return m_sortedTemplates[ i ].OrderId; + } + return -1; + } + + + + public void AddTemplate( TemplateDataParent templateData ) + { + if( templateData == null || !templateData.IsValid ) + return; + RefreshAvailableTemplates(); + if( !m_availableTemplates.ContainsKey( templateData.GUID ) ) + { + m_sortedTemplates.Add( templateData ); + m_availableTemplates.Add( templateData.GUID, templateData ); + } + } + + public void RemoveTemplate( string guid ) + { + TemplateDataParent templateData = GetTemplate( guid ); + if( templateData != null ) + { + RemoveTemplate( templateData ); + } + } + + public void RemoveTemplate( TemplateDataParent templateData ) + { + RefreshAvailableTemplates(); + + if( m_availableTemplates != null ) + m_availableTemplates.Remove( templateData.GUID ); + + m_sortedTemplates.Remove( templateData ); + templateData.Destroy(); + } + + public void Destroy() + { + if( TemplatesManager.ShowDebugMessages ) + Debug.Log( "Destroy Manager" ); + if( m_availableTemplates != null ) + { + foreach( KeyValuePair<string, TemplateDataParent> kvp in m_availableTemplates ) + { + kvp.Value.Destroy(); + } + m_availableTemplates.Clear(); + m_availableTemplates = null; + } + int count = m_sortedTemplates.Count; + + for( int i = 0; i < count; i++ ) + { + ScriptableObject.DestroyImmediate( m_sortedTemplates[ i ] ); + } + + m_sortedTemplates.Clear(); + m_sortedTemplates = null; + + AvailableTemplateNames = null; + Initialized = false; + } + + public TemplateDataParent GetTemplate( int id ) + { + if( id < m_sortedTemplates.Count ) + return m_sortedTemplates[ id ]; + + return null; + } + + public TemplateDataParent GetTemplate( string guid ) + { + RefreshAvailableTemplates(); + if( m_availableTemplates == null && m_sortedTemplates != null ) + { + m_availableTemplates = new Dictionary<string, TemplateDataParent>(); + for( int i = 0; i < m_sortedTemplates.Count; i++ ) + { + m_availableTemplates.Add( m_sortedTemplates[ i ].GUID, m_sortedTemplates[ i ] ); + } + } + + if( m_availableTemplates.ContainsKey( guid ) ) + return m_availableTemplates[ guid ]; + + return null; + } + + + public TemplateDataParent GetTemplateByName( string name ) + { + RefreshAvailableTemplates(); + if( m_availableTemplates == null && m_sortedTemplates != null ) + { + m_availableTemplates = new Dictionary<string, TemplateDataParent>(); + for( int i = 0; i < m_sortedTemplates.Count; i++ ) + { + m_availableTemplates.Add( m_sortedTemplates[ i ].GUID, m_sortedTemplates[ i ] ); + } + } + + foreach( KeyValuePair<string, TemplateDataParent> kvp in m_availableTemplates ) + { + if( kvp.Value.DefaultShaderName.Equals( name ) ) + { + return kvp.Value; + } + } + return null; + } + + public TemplateDataParent CheckAndLoadTemplate( string guid ) + { + TemplateDataParent templateData = GetTemplate( guid ); + if( templateData == null ) + { + string datapath = AssetDatabase.GUIDToAssetPath( guid ); + string body = IOUtils.LoadTextFileFromDisk( datapath ); + + if( body.IndexOf( TemplatesManager.TemplateShaderNameBeginTag ) > -1 ) + { + templateData = ScriptableObject.CreateInstance<TemplateMultiPass>(); + templateData.Init( string.Empty, guid, true ); + if( templateData.IsValid ) + { + AddTemplate( templateData ); + return templateData; + } + } + } + + return null; + } + + private void OnEnable() + { + if( !Initialized ) + { + Init(); + } + else + { + RefreshAvailableTemplates(); + } + hideFlags = HideFlags.HideAndDontSave; + if( ShowDebugMessages ) + Debug.Log( "On Enable Manager: " + this.GetInstanceID() ); + } + + public void ResetOptionsSetupData() + { + if( ShowDebugMessages ) + Debug.Log( "Reseting options setup data" ); + m_optionsInitialSetup.Clear(); + } + + public bool SetOptionsValue( string optionId, bool value ) + { + if( m_optionsInitialSetup.ContainsKey( optionId ) ) + { + m_optionsInitialSetup[ optionId ] = m_optionsInitialSetup[ optionId ] || value; + } + else + { + m_optionsInitialSetup.Add( optionId, value ); + } + return m_optionsInitialSetup[ optionId ]; + } + + public int TemplateCount { get { return m_sortedTemplates.Count; } } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesManager.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesManager.cs.meta new file mode 100644 index 00000000..b49d0694 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9f0aacdb47cf3b94ebbe9e72af9d3cf1 +timeCreated: 1481126958 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesStencilBufferModule.cs b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesStencilBufferModule.cs new file mode 100644 index 00000000..6be80ea4 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesStencilBufferModule.cs @@ -0,0 +1,662 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace AmplifyShaderEditor +{ + + [Serializable] + public sealed class TemplatesStencilBufferModule : TemplateModuleParent + { + private const string FoldoutLabelStr = " Stencil Buffer"; + private GUIContent ReferenceValueContent = new GUIContent( "Reference", "The value to be compared against (if Comparison is anything else than always) and/or the value to be written to the buffer (if either Pass, Fail or ZFail is set to replace)" ); + private GUIContent ReadMaskContent = new GUIContent( "Read Mask", "An 8 bit mask as an 0-255 integer, used when comparing the reference value with the contents of the buffer (referenceValue & readMask) comparisonFunction (stencilBufferValue & readMask)" ); + private GUIContent WriteMaskContent = new GUIContent( "Write Mask", "An 8 bit mask as an 0-255 integer, used when writing to the buffer" ); + private const string ComparisonStr = "Comparison"; + private const string PassStr = "Pass"; + private const string FailStr = "Fail"; + private const string ZFailStr = "ZFail"; + + private const string ComparisonFrontStr = "Comp. Front"; + private const string PassFrontStr = "Pass Front"; + private const string FailFrontStr = "Fail Front"; + private const string ZFailFrontStr = "ZFail Front"; + + private const string ComparisonBackStr = "Comp. Back"; + private const string PassBackStr = "Pass Back"; + private const string FailBackStr = "Fail Back"; + private const string ZFailBackStr = "ZFail Back"; + + private Dictionary<string, int> m_comparisonDict = new Dictionary<string, int>(); + private Dictionary<string, int> m_stencilOpsDict = new Dictionary<string, int>(); + + [SerializeField] + private bool m_active = true; + + [SerializeField] + private InlineProperty m_reference = new InlineProperty(); + + // Read Mask + private const int ReadMaskDefaultValue = 255; + [SerializeField] + private InlineProperty m_readMask = new InlineProperty( ReadMaskDefaultValue ); + + //Write Mask + private const int WriteMaskDefaultValue = 255; + [SerializeField] + private InlineProperty m_writeMask = new InlineProperty( WriteMaskDefaultValue ); + + //Comparison Function + private const int ComparisonDefaultValue = 0; + [SerializeField] + private InlineProperty m_comparisonFunctionFrontIdx = new InlineProperty( ComparisonDefaultValue ); + + [SerializeField] + private InlineProperty m_comparisonFunctionBackIdx = new InlineProperty( ComparisonDefaultValue ); + + //Pass Stencil Op + private const int PassStencilOpDefaultValue = 0; + [SerializeField] + private InlineProperty m_passStencilOpFrontIdx = new InlineProperty( PassStencilOpDefaultValue ); + + [SerializeField] + private InlineProperty m_passStencilOpBackIdx = new InlineProperty( PassStencilOpDefaultValue ); + + //Fail Stencil Op + private const int FailStencilOpDefaultValue = 0; + + [SerializeField] + private InlineProperty m_failStencilOpFrontIdx = new InlineProperty( FailStencilOpDefaultValue ); + + [SerializeField] + private InlineProperty m_failStencilOpBackIdx = new InlineProperty( FailStencilOpDefaultValue ); + + //ZFail Stencil Op + private const int ZFailStencilOpDefaultValue = 0; + [SerializeField] + private InlineProperty m_zFailStencilOpFrontIdx = new InlineProperty( ZFailStencilOpDefaultValue ); + + [SerializeField] + private InlineProperty m_zFailStencilOpBackIdx = new InlineProperty( ZFailStencilOpDefaultValue ); + + public TemplatesStencilBufferModule() : base("Stencil Buffer") + { + for( int i = 0; i < StencilBufferOpHelper.StencilComparisonValues.Length; i++ ) + { + m_comparisonDict.Add( StencilBufferOpHelper.StencilComparisonValues[ i ].ToLower(), i ); + } + + for( int i = 0; i < StencilBufferOpHelper.StencilOpsValues.Length; i++ ) + { + m_stencilOpsDict.Add( StencilBufferOpHelper.StencilOpsValues[ i ].ToLower(), i ); + } + } + + public void CopyFrom( TemplatesStencilBufferModule other , bool allData ) + { + if( allData ) + m_independentModule = other.IndependentModule; + + m_active = other.Active; + m_reference.CopyFrom( other.Reference ); + m_readMask.CopyFrom( other.ReadMask ); + m_writeMask.CopyFrom( other.WriteMask ); + m_comparisonFunctionFrontIdx.CopyFrom( other.ComparisonFunctionIdx ); + m_comparisonFunctionBackIdx.CopyFrom( other.ComparisonFunctionBackIdx ); + m_passStencilOpFrontIdx.CopyFrom( other.PassStencilOpIdx ); + m_passStencilOpBackIdx.CopyFrom( other.PassStencilOpBackIdx ); + m_failStencilOpFrontIdx.CopyFrom( other.FailStencilOpIdx ); + m_failStencilOpBackIdx.CopyFrom( other.FailStencilOpBackIdx ); + m_zFailStencilOpFrontIdx.CopyFrom( other.ZFailStencilOpIdx ); + m_zFailStencilOpBackIdx.CopyFrom( other.ZFailStencilOpBackIdx ); + } + + public void ConfigureFromTemplateData( TemplateStencilData stencilData ) + { + bool newValidData = ( stencilData.DataCheck == TemplateDataCheck.Valid ); + if( newValidData && m_validData != newValidData ) + { + m_active = stencilData.Active; + m_independentModule = stencilData.IndependentModule; + if( string.IsNullOrEmpty( stencilData.ReferenceInline ) ) + { + m_reference.IntValue = stencilData.Reference; + m_reference.ResetProperty(); + } + else + { + m_reference.SetInlineByName( stencilData.ReferenceInline ); + } + + if( string.IsNullOrEmpty( stencilData.ReadMaskInline ) ) + { + m_readMask.IntValue = stencilData.ReadMask; + m_readMask.ResetProperty(); + } + else + { + m_readMask.SetInlineByName( stencilData.ReadMaskInline ); + } + + if( string.IsNullOrEmpty( stencilData.WriteMaskInline ) ) + { + m_writeMask.IntValue = stencilData.WriteMask; + m_writeMask.ResetProperty(); + } + else + { + m_writeMask.SetInlineByName( stencilData.WriteMaskInline ); + } + + if( string.IsNullOrEmpty( stencilData.ComparisonFrontInline ) ) + { + if( !string.IsNullOrEmpty( stencilData.ComparisonFront ) ) + { + m_comparisonFunctionFrontIdx.IntValue = m_comparisonDict[ stencilData.ComparisonFront.ToLower() ]; + } + else + { + m_comparisonFunctionFrontIdx.IntValue = m_comparisonDict[ "always" ]; + } + m_comparisonFunctionFrontIdx.ResetProperty(); + } + else + { + m_comparisonFunctionFrontIdx.SetInlineByName( stencilData.ComparisonFrontInline ); + } + + if( string.IsNullOrEmpty( stencilData.PassFrontInline ) ) + { + if( !string.IsNullOrEmpty( stencilData.PassFront ) ) + { + m_passStencilOpFrontIdx.IntValue = m_stencilOpsDict[ stencilData.PassFront.ToLower() ]; + } + else + { + m_passStencilOpFrontIdx.IntValue = m_stencilOpsDict[ "keep" ]; + } + m_passStencilOpFrontIdx.ResetProperty(); + } + else + { + m_passStencilOpFrontIdx.SetInlineByName( stencilData.PassFrontInline ); + } + + if( string.IsNullOrEmpty( stencilData.FailFrontInline ) ) + { + if( !string.IsNullOrEmpty( stencilData.FailFront ) ) + { + m_failStencilOpFrontIdx.IntValue = m_stencilOpsDict[ stencilData.FailFront.ToLower() ]; + } + else + { + m_failStencilOpFrontIdx.IntValue = m_stencilOpsDict[ "keep" ]; + } + m_failStencilOpFrontIdx.ResetProperty(); + } + else + { + m_failStencilOpFrontIdx.SetInlineByName( stencilData.FailFrontInline ); + } + + if( string.IsNullOrEmpty( stencilData.ZFailFrontInline ) ) + { + if( !string.IsNullOrEmpty( stencilData.ZFailFront ) ) + { + m_zFailStencilOpFrontIdx.IntValue = m_stencilOpsDict[ stencilData.ZFailFront.ToLower() ]; + } + else + { + m_zFailStencilOpFrontIdx.IntValue = m_stencilOpsDict[ "keep" ]; + } + m_zFailStencilOpFrontIdx.ResetProperty(); + } + else + { + m_zFailStencilOpFrontIdx.SetInlineByName( stencilData.ZFailFrontInline ); + } + + if( string.IsNullOrEmpty( stencilData.ComparisonBackInline ) ) + { + if( !string.IsNullOrEmpty( stencilData.ComparisonBack ) ) + { + m_comparisonFunctionBackIdx.IntValue = m_comparisonDict[ stencilData.ComparisonBack.ToLower() ]; + } + else + { + m_comparisonFunctionBackIdx.IntValue = m_comparisonDict[ "always" ]; + } + m_comparisonFunctionBackIdx.ResetProperty(); + } + else + { + m_comparisonFunctionBackIdx.SetInlineByName( stencilData.ComparisonBackInline ); + } + + if( string.IsNullOrEmpty( stencilData.PassBackInline ) ) + { + + if( !string.IsNullOrEmpty( stencilData.PassBack ) ) + { + m_passStencilOpBackIdx.IntValue = m_stencilOpsDict[ stencilData.PassBack.ToLower() ]; + } + else + { + m_passStencilOpBackIdx.IntValue = m_stencilOpsDict[ "keep" ]; + } + m_passStencilOpBackIdx.ResetProperty(); + } + else + { + m_passStencilOpBackIdx.SetInlineByName( stencilData.PassBackInline ); + } + + if( string.IsNullOrEmpty( stencilData.FailBackInline ) ) + { + if( !string.IsNullOrEmpty( stencilData.FailBack ) ) + { + m_failStencilOpBackIdx.IntValue = m_stencilOpsDict[ stencilData.FailBack.ToLower() ]; + } + else + { + m_failStencilOpBackIdx.IntValue = m_stencilOpsDict[ "keep" ]; + } + m_failStencilOpBackIdx.ResetProperty(); + } + else + { + m_failStencilOpBackIdx.SetInlineByName( stencilData.FailBackInline ); + } + + + if( string.IsNullOrEmpty( stencilData.ZFailBackInline ) ) + { + if( !string.IsNullOrEmpty( stencilData.ZFailBack ) ) + { + m_zFailStencilOpBackIdx.IntValue = m_stencilOpsDict[ stencilData.ZFailBack.ToLower() ]; + } + else + { + m_zFailStencilOpBackIdx.IntValue = m_stencilOpsDict[ "keep" ]; + } + m_zFailStencilOpBackIdx.ResetProperty(); + } + else + { + m_zFailStencilOpBackIdx.SetInlineByName( stencilData.ZFailBackInline ); + } + } + m_validData = newValidData; + } + + public string CreateStencilOp( CullMode cullMode ) + { + if( !m_active ) + return string.Empty; + + string result = "Stencil\n{\n"; + result += string.Format( "\tRef {0}\n", m_reference.GetValueOrProperty() ); + if( m_readMask.IsValid || m_readMask.IntValue != ReadMaskDefaultValue ) + { + result += string.Format( "\tReadMask {0}\n", m_readMask.GetValueOrProperty() ); + } + + if( m_writeMask.IsValid || m_writeMask.IntValue != WriteMaskDefaultValue ) + { + result += string.Format( "\tWriteMask {0}\n", m_writeMask.GetValueOrProperty() ); + } + + if( cullMode == CullMode.Off && + ( m_comparisonFunctionBackIdx.IsValid || m_comparisonFunctionBackIdx.IntValue != ComparisonDefaultValue || + m_passStencilOpBackIdx.IsValid || m_passStencilOpBackIdx.IntValue != PassStencilOpDefaultValue || + m_failStencilOpBackIdx.IsValid || m_failStencilOpBackIdx.IntValue != FailStencilOpDefaultValue || + m_zFailStencilOpBackIdx.IsValid || m_zFailStencilOpBackIdx.IntValue != ZFailStencilOpDefaultValue ) ) + { + if( m_comparisonFunctionFrontIdx.IsValid || m_comparisonFunctionFrontIdx.IntValue != ComparisonDefaultValue ) + result += string.Format( "\tCompFront {0}\n", m_comparisonFunctionFrontIdx.GetValueOrProperty( StencilBufferOpHelper.StencilComparisonValues[ m_comparisonFunctionFrontIdx.IntValue ] ) ); + + if( m_passStencilOpFrontIdx.IsValid || m_passStencilOpFrontIdx.IntValue != PassStencilOpDefaultValue ) + result += string.Format( "\tPassFront {0}\n", m_passStencilOpFrontIdx.GetValueOrProperty( StencilBufferOpHelper.StencilOpsValues[ m_passStencilOpFrontIdx.IntValue ] ) ); + + if( m_failStencilOpFrontIdx.IsValid || m_failStencilOpFrontIdx.IntValue != FailStencilOpDefaultValue ) + result += string.Format( "\tFailFront {0}\n", m_failStencilOpFrontIdx.GetValueOrProperty( StencilBufferOpHelper.StencilOpsValues[ m_failStencilOpFrontIdx.IntValue ] ) ); + + if( m_zFailStencilOpFrontIdx.IsValid || m_zFailStencilOpFrontIdx.IntValue != ZFailStencilOpDefaultValue ) + result += string.Format( "\tZFailFront {0}\n", m_zFailStencilOpFrontIdx.GetValueOrProperty( StencilBufferOpHelper.StencilOpsValues[ m_zFailStencilOpFrontIdx.IntValue ] ) ); + + if( m_comparisonFunctionBackIdx.IsValid || m_comparisonFunctionBackIdx.IntValue != ComparisonDefaultValue ) + result += string.Format( "\tCompBack {0}\n", m_comparisonFunctionBackIdx.GetValueOrProperty( StencilBufferOpHelper.StencilComparisonValues[ m_comparisonFunctionBackIdx.IntValue ] ) ); + + if( m_passStencilOpBackIdx.IsValid || m_passStencilOpBackIdx.IntValue != PassStencilOpDefaultValue ) + result += string.Format( "\tPassBack {0}\n", m_passStencilOpBackIdx.GetValueOrProperty( StencilBufferOpHelper.StencilOpsValues[ m_passStencilOpBackIdx.IntValue ] ) ); + + if( m_failStencilOpBackIdx.IsValid || m_failStencilOpBackIdx.IntValue != FailStencilOpDefaultValue ) + result += string.Format( "\tFailBack {0}\n", m_failStencilOpBackIdx.GetValueOrProperty( StencilBufferOpHelper.StencilOpsValues[ m_failStencilOpBackIdx.IntValue ] )); + + if( m_zFailStencilOpBackIdx.IsValid || m_zFailStencilOpBackIdx.IntValue != ZFailStencilOpDefaultValue ) + result += string.Format( "\tZFailBack {0}\n", m_zFailStencilOpBackIdx.GetValueOrProperty( StencilBufferOpHelper.StencilOpsValues[ m_zFailStencilOpBackIdx.IntValue ] )); + } + else + { + if( m_comparisonFunctionFrontIdx.IsValid || m_comparisonFunctionFrontIdx.IntValue != ComparisonDefaultValue ) + result += string.Format( "\tComp {0}\n", m_comparisonFunctionFrontIdx.GetValueOrProperty(StencilBufferOpHelper.StencilComparisonValues[ m_comparisonFunctionFrontIdx.IntValue ] )); + if( m_passStencilOpFrontIdx.IsValid || m_passStencilOpFrontIdx.IntValue != PassStencilOpDefaultValue ) + result += string.Format( "\tPass {0}\n", m_passStencilOpFrontIdx.GetValueOrProperty( StencilBufferOpHelper.StencilOpsValues[ m_passStencilOpFrontIdx.IntValue ] )); + if( m_failStencilOpFrontIdx.IsValid || m_failStencilOpFrontIdx.IntValue != FailStencilOpDefaultValue ) + result += string.Format( "\tFail {0}\n", m_failStencilOpFrontIdx.GetValueOrProperty( StencilBufferOpHelper.StencilOpsValues[ m_failStencilOpFrontIdx.IntValue ] )); + if( m_zFailStencilOpFrontIdx.IsValid || m_zFailStencilOpFrontIdx.IntValue != ZFailStencilOpDefaultValue ) + result += string.Format( "\tZFail {0}\n", m_zFailStencilOpFrontIdx.GetValueOrProperty(StencilBufferOpHelper.StencilOpsValues[ m_zFailStencilOpFrontIdx.IntValue ] )); + } + + result += "}"; + return result; + } + + public override void ShowUnreadableDataMessage( ParentNode owner ) + { + bool foldout = owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedStencilOptions; + NodeUtils.DrawPropertyGroup( ref foldout, FoldoutLabelStr, base.ShowUnreadableDataMessage ); + owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedStencilOptions = foldout; + } + + public void Draw( UndoParentNode owner, CullMode cullMode , bool style = true ) + { + bool foldout = owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedStencilOptions; + if( style ) + { + NodeUtils.DrawPropertyGroup( ref foldout, FoldoutLabelStr, () => + { + DrawBlock( owner, cullMode ); + } ); + } + else + { + NodeUtils.DrawNestedPropertyGroup( owner, ref foldout, ref m_active, FoldoutLabelStr, () => + { + DrawBlock( owner, cullMode ); + } ); + } + owner.ContainerGraph.ParentWindow.InnerWindowVariables.ExpandedStencilOptions = foldout; + } + + void DrawBlock( UndoParentNode owner, CullMode cullMode ) + { + bool guiEnabled = GUI.enabled; + GUI.enabled = m_active; + EditorGUI.BeginChangeCheck(); + { + m_reference.IntSlider( ref owner, ReferenceValueContent, 0, 255 ); + m_readMask.IntSlider( ref owner, ReadMaskContent, 0, 255 ); + m_writeMask.IntSlider( ref owner, WriteMaskContent, 0, 255 ); + if( cullMode == CullMode.Off ) + { + m_comparisonFunctionFrontIdx.EnumTypePopup( ref owner, ComparisonFrontStr, StencilBufferOpHelper.StencilComparisonLabels ); + m_passStencilOpFrontIdx.EnumTypePopup( ref owner, PassFrontStr, StencilBufferOpHelper.StencilOpsLabels ); + m_failStencilOpFrontIdx.EnumTypePopup( ref owner, FailFrontStr, StencilBufferOpHelper.StencilOpsLabels ); + m_zFailStencilOpFrontIdx.EnumTypePopup( ref owner, ZFailFrontStr, StencilBufferOpHelper.StencilOpsLabels ); + EditorGUILayout.Separator(); + m_comparisonFunctionBackIdx.EnumTypePopup( ref owner, ComparisonBackStr, StencilBufferOpHelper.StencilComparisonLabels ); + m_passStencilOpBackIdx.EnumTypePopup( ref owner, PassBackStr, StencilBufferOpHelper.StencilOpsLabels ); + m_failStencilOpBackIdx.EnumTypePopup( ref owner, FailBackStr, StencilBufferOpHelper.StencilOpsLabels ); + m_zFailStencilOpBackIdx.EnumTypePopup( ref owner, ZFailBackStr, StencilBufferOpHelper.StencilOpsLabels ); + } + else + { + m_comparisonFunctionFrontIdx.EnumTypePopup( ref owner, ComparisonStr, StencilBufferOpHelper.StencilComparisonLabels ); + m_passStencilOpFrontIdx.EnumTypePopup( ref owner, PassFrontStr, StencilBufferOpHelper.StencilOpsLabels ); + m_failStencilOpFrontIdx.EnumTypePopup( ref owner, FailFrontStr, StencilBufferOpHelper.StencilOpsLabels ); + m_zFailStencilOpFrontIdx.EnumTypePopup( ref owner, ZFailFrontStr, StencilBufferOpHelper.StencilOpsLabels ); + } + } + if( EditorGUI.EndChangeCheck() ) + { + m_isDirty = true; + } + GUI.enabled = guiEnabled; + } + + public override void ReadFromString( ref uint index, ref string[] nodeParams ) + { + bool validDataOnMeta = m_validData; + if( UIUtils.CurrentShaderVersion() > TemplatesManager.MPShaderVersion ) + { + validDataOnMeta = Convert.ToBoolean( nodeParams[ index++ ] ); + } + + if( validDataOnMeta ) + { + if( UIUtils.CurrentShaderVersion() > 15307 ) + { + m_active = Convert.ToBoolean( nodeParams[ index++ ] ); + } + + if( UIUtils.CurrentShaderVersion() < 15304 ) + { + m_reference.IntValue = Convert.ToInt32( nodeParams[ index++ ] ); + m_readMask.IntValue = Convert.ToInt32( nodeParams[ index++ ] ); + m_writeMask.IntValue = Convert.ToInt32( nodeParams[ index++ ] ); + m_comparisonFunctionFrontIdx.IntValue = Convert.ToInt32( nodeParams[ index++ ] ); + m_passStencilOpFrontIdx.IntValue = Convert.ToInt32( nodeParams[ index++ ] ); + m_failStencilOpFrontIdx.IntValue = Convert.ToInt32( nodeParams[ index++ ] ); + m_zFailStencilOpFrontIdx.IntValue = Convert.ToInt32( nodeParams[ index++ ] ); + m_comparisonFunctionBackIdx.IntValue = Convert.ToInt32( nodeParams[ index++ ] ); + m_passStencilOpBackIdx.IntValue = Convert.ToInt32( nodeParams[ index++ ] ); + m_failStencilOpBackIdx.IntValue = Convert.ToInt32( nodeParams[ index++ ] ); + m_zFailStencilOpBackIdx.IntValue = Convert.ToInt32( nodeParams[ index++ ] ); + } + else + { + m_reference.ReadFromString( ref index, ref nodeParams ); + m_readMask.ReadFromString( ref index, ref nodeParams ); + m_writeMask.ReadFromString( ref index, ref nodeParams ); + m_comparisonFunctionFrontIdx.ReadFromString( ref index, ref nodeParams ); + m_passStencilOpFrontIdx.ReadFromString( ref index, ref nodeParams ); + m_failStencilOpFrontIdx.ReadFromString( ref index, ref nodeParams ); + m_zFailStencilOpFrontIdx.ReadFromString( ref index, ref nodeParams ); + m_comparisonFunctionBackIdx.ReadFromString( ref index, ref nodeParams ); + m_passStencilOpBackIdx.ReadFromString( ref index, ref nodeParams ); + m_failStencilOpBackIdx.ReadFromString( ref index, ref nodeParams ); + m_zFailStencilOpBackIdx.ReadFromString( ref index, ref nodeParams ); + } + + } + } + + public override void WriteToString( ref string nodeInfo ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_validData ); + if( m_validData ) + { + IOUtils.AddFieldValueToString( ref nodeInfo, m_active ); + m_reference.WriteToString( ref nodeInfo ); + m_readMask.WriteToString( ref nodeInfo ); + m_writeMask.WriteToString( ref nodeInfo ); + m_comparisonFunctionFrontIdx.WriteToString( ref nodeInfo ); + m_passStencilOpFrontIdx.WriteToString( ref nodeInfo ); + m_failStencilOpFrontIdx.WriteToString( ref nodeInfo ); + m_zFailStencilOpFrontIdx.WriteToString( ref nodeInfo ); + m_comparisonFunctionBackIdx.WriteToString( ref nodeInfo ); + m_passStencilOpBackIdx.WriteToString( ref nodeInfo ); + m_failStencilOpBackIdx.WriteToString( ref nodeInfo ); + m_zFailStencilOpBackIdx.WriteToString( ref nodeInfo ); + } + } + + public override void Destroy() + { + m_comparisonDict.Clear(); + m_comparisonDict = null; + + m_stencilOpsDict.Clear(); + m_stencilOpsDict = null; + + m_reference = null; + m_readMask = null; + m_writeMask = null; + m_comparisonFunctionFrontIdx = null; + m_passStencilOpFrontIdx = null; + m_failStencilOpFrontIdx = null; + m_zFailStencilOpFrontIdx = null; + m_comparisonFunctionBackIdx = null; + m_passStencilOpBackIdx = null; + m_failStencilOpBackIdx = null; + m_zFailStencilOpBackIdx = null; + } + public bool Active { get { return m_active; } } + public InlineProperty Reference { get { return m_reference; } } + public InlineProperty ReadMask { get { return m_readMask; } } + public InlineProperty WriteMask { get { return m_writeMask; } } + public InlineProperty ComparisonFunctionIdx { get { return m_comparisonFunctionFrontIdx; } } + public InlineProperty ComparisonFunctionBackIdx { get { return m_comparisonFunctionBackIdx; } } + public InlineProperty PassStencilOpIdx { get { return m_passStencilOpFrontIdx; } } + public InlineProperty PassStencilOpBackIdx { get { return m_passStencilOpBackIdx; } } + public InlineProperty FailStencilOpIdx { get { return m_failStencilOpFrontIdx; } } + public InlineProperty FailStencilOpBackIdx { get { return m_failStencilOpBackIdx; } } + public InlineProperty ZFailStencilOpIdx { get { return m_zFailStencilOpFrontIdx; } } + public InlineProperty ZFailStencilOpBackIdx { get { return m_zFailStencilOpBackIdx; } } + + + public int ReferenceValue + { + set + { + m_reference.IntValue = value; + m_reference.Active = false; + } + get + { + return m_reference.IntValue; + } + } + + public int ReadMaskValue + { + set + { + m_readMask.IntValue = value; + m_reference.Active = false; + } + get + { + return m_readMask.IntValue; + } + } + + public int WriteMaskValue + { + set + { + m_writeMask.IntValue = value; + m_writeMask.Active = false; + } + get + { + return m_writeMask.IntValue; + } + } + + public int ComparisonFunctionIdxValue + { + set + { + m_comparisonFunctionFrontIdx.IntValue = value; + m_comparisonFunctionFrontIdx.Active = false; + } + get + { + return m_comparisonFunctionFrontIdx.IntValue; + } + } + + public int ComparisonFunctionBackIdxValue + { + set + { + m_comparisonFunctionBackIdx.IntValue = value; + m_comparisonFunctionBackIdx.Active = false; + } + get + { + return m_comparisonFunctionBackIdx.IntValue; + } + } + + public int PassStencilOpIdxValue + { + set + { + m_passStencilOpFrontIdx.IntValue = value; + m_passStencilOpFrontIdx.Active = false; + } + get + { + return m_passStencilOpFrontIdx.IntValue; + } + } + + public int PassStencilOpBackIdxValue + { + set + { + m_passStencilOpBackIdx.IntValue = value; + m_passStencilOpBackIdx.Active = false; + } + get + { + return m_passStencilOpBackIdx.IntValue; + } + } + + public int FailStencilOpIdxValue + { + set + { + m_failStencilOpFrontIdx.IntValue = value; + m_failStencilOpFrontIdx.Active = false; + } + get + { + return m_failStencilOpFrontIdx.IntValue; + } + } + public int FailStencilOpBackIdxValue + { + set + { + m_failStencilOpBackIdx.IntValue = value; + m_failStencilOpBackIdx.Active = false; + } + get + { + return m_failStencilOpBackIdx.IntValue; + } + } + + public int ZFailStencilOpIdxValue + { + set + { + m_zFailStencilOpFrontIdx.IntValue = value; + m_zFailStencilOpFrontIdx.Active = false; + } + get + { + return m_zFailStencilOpFrontIdx.IntValue; + } + } + + public int ZFailStencilOpBackIdxValue + { + set + { + m_zFailStencilOpBackIdx.IntValue = value; + m_zFailStencilOpBackIdx.Active = false; + } + get + { + return m_zFailStencilOpBackIdx.IntValue; + } + } + } +} diff --git a/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesStencilBufferModule.cs.meta b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesStencilBufferModule.cs.meta new file mode 100644 index 00000000..552dbaf7 --- /dev/null +++ b/Assets/AmplifyShaderEditor/Plugins/Editor/Templates/TemplatesStencilBufferModule.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fa41b984209fa624aa1fdea5949d9d59 +timeCreated: 1511548974 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: |