You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

516 lines
19 KiB

  1. // Amplify Shader Editor - Visual Shader Editing Tool
  2. // Copyright (c) Amplify Creations, Lda <info@amplify.pt>
  3. #define CUSTOM_OPTIONS_AVAILABLE
  4. using UnityEngine;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Text.RegularExpressions;
  8. namespace AmplifyShaderEditor
  9. {
  10. [Serializable]
  11. public class TemplatePass
  12. {
  13. private const string DefaultPassNameStr = "SubShader {0} Pass {1}";
  14. [SerializeField]
  15. private int m_idx = -1;
  16. [SerializeField]
  17. private bool m_isInvisible = false;
  18. [SerializeField]
  19. private int m_invisibleOptions = 0;
  20. [SerializeField]
  21. private bool m_isMainPass = false;
  22. [SerializeField]
  23. private TemplateModulesData m_modules;
  24. [SerializeField]
  25. private List<TemplateInputData> m_inputDataList = new List<TemplateInputData>();
  26. private Dictionary<int, TemplateInputData> m_inputDataDict = new Dictionary<int, TemplateInputData>();
  27. [SerializeField]
  28. private TemplateFunctionData m_vertexFunctionData;
  29. [SerializeField]
  30. private TemplateFunctionData m_fragmentFunctionData;
  31. [SerializeField]
  32. private VertexDataContainer m_vertexDataContainer;
  33. [SerializeField]
  34. private TemplateInterpData m_interpolatorDataContainer;
  35. [SerializeField]
  36. private List<TemplateLocalVarData> m_localVarsList = new List<TemplateLocalVarData>();
  37. [SerializeField]
  38. private string m_uniquePrefix;
  39. [SerializeField]
  40. private TemplatePropertyContainer m_templateProperties = new TemplatePropertyContainer();
  41. [SerializeField]
  42. private List<TemplateShaderPropertyData> m_availableShaderGlobals = new List<TemplateShaderPropertyData>();
  43. [SerializeField]
  44. TemplateInfoContainer m_passNameContainer = new TemplateInfoContainer();
  45. #if CUSTOM_OPTIONS_AVAILABLE
  46. [SerializeField]
  47. TemplateOptionsContainer m_customOptionsContainer = new TemplateOptionsContainer();
  48. #endif
  49. public TemplatePass( TemplateModulesData subShaderModule, int subshaderIdx, int passIdx, TemplateIdManager idManager, string uniquePrefix, int offsetIdx, TemplatePassInfo passInfo, ref Dictionary<string, TemplateShaderPropertyData> duplicatesHelper )
  50. {
  51. m_idx = passIdx;
  52. m_uniquePrefix = uniquePrefix;
  53. m_isMainPass = passInfo.Data.Contains( TemplatesManager.TemplateMainPassTag );
  54. if( !m_isMainPass )
  55. {
  56. string id = string.Empty;
  57. int idIndex = 0;
  58. m_isInvisible = TemplateHelperFunctions.FetchInvisibleInfo( passInfo.Data, ref m_invisibleOptions, ref id, ref idIndex );
  59. if( m_isInvisible )
  60. {
  61. idManager.RegisterId( idIndex, uniquePrefix + id, id, true );
  62. }
  63. }
  64. #if CUSTOM_OPTIONS_AVAILABLE
  65. m_customOptionsContainer = TemplateOptionsToolsHelper.GenerateOptionsContainer( passInfo.Data );
  66. if( m_customOptionsContainer.Enabled )
  67. {
  68. idManager.RegisterId( m_customOptionsContainer.Index, uniquePrefix + m_customOptionsContainer.Body, m_customOptionsContainer.Body, true );
  69. }
  70. #endif
  71. FetchPassName( offsetIdx, passInfo.Data );
  72. if( m_passNameContainer.Index > -1 )
  73. {
  74. idManager.RegisterId( m_passNameContainer.Index, uniquePrefix + m_passNameContainer.Id, m_passNameContainer.Id );
  75. }
  76. else
  77. {
  78. m_passNameContainer.Data = string.Format( DefaultPassNameStr, subshaderIdx, passIdx );
  79. }
  80. m_modules = new TemplateModulesData( idManager, m_templateProperties, uniquePrefix + "Module", offsetIdx, passInfo.Data, false );
  81. if( !m_modules.PassTag.IsValid )
  82. {
  83. m_modules.PassTag.StartIdx = passInfo.GlobalStartIdx;
  84. m_templateProperties.AddId( passInfo.Data, m_modules.PassTag.Id, passInfo.LocalStartIdx, false );
  85. //m_modules.PassTag.StartIdx -= m_templateProperties.PropertyDict[ m_modules.PassTag.Id ].Indentation.Length;
  86. //m_templateProperties.PropertyDict[ m_modules.PassTag.Id ].UseIndentationAtStart = false;
  87. idManager.RegisterId( m_modules.PassTag.StartIdx, m_modules.UniquePrefix + m_modules.PassTag.Id, string.Empty );
  88. }
  89. m_modules.SRPType = subShaderModule.SRPType;
  90. if( m_modules.SRPType == TemplateSRPType.HD )
  91. {
  92. m_modules.SRPIsPBR = passInfo.Data.Contains( TemplateHelperFunctions.HDPBRTag );
  93. }
  94. Dictionary<string, TemplateShaderPropertyData> ownDuplicatesDict = new Dictionary<string, TemplateShaderPropertyData>( duplicatesHelper );
  95. TemplateHelperFunctions.CreateShaderGlobalsList( passInfo.Data, ref m_availableShaderGlobals, ref ownDuplicatesDict );
  96. // Vertex and Interpolator data
  97. FetchVertexAndInterpData( subShaderModule, offsetIdx, passInfo.Data );
  98. if( m_vertexDataContainer != null )
  99. idManager.RegisterId( m_vertexDataContainer.VertexDataStartIdx, uniquePrefix + m_vertexDataContainer.VertexDataId, m_vertexDataContainer.VertexDataId );
  100. if( m_interpolatorDataContainer != null )
  101. idManager.RegisterId( m_interpolatorDataContainer.InterpDataStartIdx, uniquePrefix + m_interpolatorDataContainer.InterpDataId, m_interpolatorDataContainer.InterpDataId );
  102. //Fetch function code areas
  103. FetchCodeAreas( offsetIdx, TemplatesManager.TemplateVertexCodeBeginArea, MasterNodePortCategory.Vertex, passInfo.Data );
  104. if( m_vertexFunctionData != null )
  105. idManager.RegisterId( m_vertexFunctionData.Position, uniquePrefix + m_vertexFunctionData.Id, m_vertexFunctionData.Id );
  106. FetchCodeAreas( offsetIdx, TemplatesManager.TemplateFragmentCodeBeginArea, MasterNodePortCategory.Fragment, passInfo.Data );
  107. if( m_fragmentFunctionData != null )
  108. idManager.RegisterId( m_fragmentFunctionData.Position, uniquePrefix + m_fragmentFunctionData.Id, m_fragmentFunctionData.Id );
  109. //Fetching inputs, must be do
  110. if( m_fragmentFunctionData != null )
  111. FetchInputs( offsetIdx, MasterNodePortCategory.Fragment, passInfo.Data );
  112. if( m_vertexFunctionData != null )
  113. FetchInputs( offsetIdx, MasterNodePortCategory.Vertex, passInfo.Data );
  114. //Fetch local variables must be done after fetching code areas as it needs them to see is variable is on vertex or fragment
  115. TemplateHelperFunctions.FetchLocalVars( passInfo.Data, ref m_localVarsList, m_vertexFunctionData, m_fragmentFunctionData );
  116. int localVarCount = m_localVarsList.Count;
  117. if( localVarCount > 0 )
  118. {
  119. idManager.RegisterTag( TemplatesManager.TemplateLocalVarTag );
  120. for( int i = 0; i < localVarCount; i++ )
  121. {
  122. if( m_localVarsList[ i ].IsSpecialVar )
  123. {
  124. idManager.RegisterTag( m_localVarsList[ i ].Id );
  125. }
  126. }
  127. }
  128. int inputsCount = m_inputDataList.Count;
  129. for( int i = 0; i < inputsCount; i++ )
  130. {
  131. if( m_inputDataList[ i ] != null )
  132. idManager.RegisterId( m_inputDataList[ i ].TagGlobalStartIdx, uniquePrefix + m_inputDataList[ i ].TagId, m_inputDataList[ i ].TagId );
  133. }
  134. //int passEndIndex = passInfo.Data.LastIndexOf( "}" );
  135. //if( passEndIndex > 0 )
  136. //{
  137. // int identationIndex = -1;
  138. // for( int i = passEndIndex; i >= 0; i-- )
  139. // {
  140. // if( passInfo.Data[ i ] == TemplatesManager.TemplateNewLine )
  141. // {
  142. // identationIndex = i + 1;
  143. // break;
  144. // }
  145. // if( i == 0 )
  146. // {
  147. // identationIndex = 0;
  148. // }
  149. // }
  150. // if( identationIndex > -1 )
  151. // {
  152. // int length = passEndIndex - identationIndex;
  153. // string indentation = ( length > 0 ) ? passInfo.Data.Substring( identationIndex, length ) : string.Empty;
  154. // TemplateProperty templateProperty = new TemplateProperty( TemplatesManager.TemplateEndPassTag, indentation, false );
  155. // m_templateProperties.AddId( templateProperty );
  156. // idManager.RegisterId( offsetIdx + passEndIndex, uniquePrefix + TemplatesManager.TemplateEndPassTag, string.Empty );
  157. // }
  158. //}
  159. ownDuplicatesDict.Clear();
  160. ownDuplicatesDict = null;
  161. }
  162. public void Destroy()
  163. {
  164. m_passNameContainer = null;
  165. #if CUSTOM_OPTIONS_AVAILABLE
  166. m_customOptionsContainer = null;
  167. #endif
  168. if( m_templateProperties != null )
  169. m_templateProperties.Destroy();
  170. m_templateProperties = null;
  171. if( m_modules != null )
  172. m_modules.Destroy();
  173. m_modules = null;
  174. if( m_inputDataList != null )
  175. m_inputDataList.Clear();
  176. m_inputDataList = null;
  177. if( m_inputDataDict != null )
  178. m_inputDataDict.Clear();
  179. m_inputDataDict = null;
  180. m_vertexFunctionData = null;
  181. m_fragmentFunctionData = null;
  182. if( m_vertexDataContainer != null )
  183. m_vertexDataContainer.Destroy();
  184. m_vertexDataContainer = null;
  185. if( m_interpolatorDataContainer != null )
  186. m_interpolatorDataContainer.Destroy();
  187. if( m_localVarsList != null )
  188. {
  189. m_localVarsList.Clear();
  190. m_localVarsList = null;
  191. }
  192. m_interpolatorDataContainer = null;
  193. if( m_availableShaderGlobals != null )
  194. m_availableShaderGlobals.Clear();
  195. m_availableShaderGlobals = null;
  196. }
  197. public TemplateInputData InputDataFromId( int id )
  198. {
  199. if( m_inputDataDict == null )
  200. m_inputDataDict = new Dictionary<int, TemplateInputData>();
  201. if( m_inputDataDict.Count != m_inputDataList.Count )
  202. {
  203. m_inputDataDict.Clear();
  204. for( int i = 0; i < m_inputDataList.Count; i++ )
  205. {
  206. m_inputDataDict.Add( m_inputDataList[ i ].PortUniqueId, m_inputDataList[ i ] );
  207. }
  208. }
  209. if( m_inputDataDict.ContainsKey( id ) )
  210. return m_inputDataDict[ id ];
  211. return null;
  212. }
  213. void FetchPassName( int offsetIdx, string body )
  214. {
  215. Match match = Regex.Match( body, TemplateHelperFunctions.PassNamePattern );
  216. if( match != null && match.Groups.Count > 1 )
  217. {
  218. m_passNameContainer.Id = match.Groups[ 0 ].Value;
  219. m_passNameContainer.Data = match.Groups[ 1 ].Value;
  220. m_passNameContainer.Index = offsetIdx + match.Index;
  221. }
  222. }
  223. void FetchVertexAndInterpData( TemplateModulesData subShaderModule, int offsetIdx, string body )
  224. {
  225. // Vertex Data
  226. try
  227. {
  228. int vertexDataTagBegin = body.IndexOf( TemplatesManager.TemplateVertexDataTag );
  229. if( vertexDataTagBegin > -1 )
  230. {
  231. m_vertexDataContainer = new VertexDataContainer();
  232. m_vertexDataContainer.VertexDataStartIdx = offsetIdx + vertexDataTagBegin;
  233. int vertexDataTagEnd = body.IndexOf( TemplatesManager.TemplateEndOfLine, vertexDataTagBegin );
  234. m_vertexDataContainer.VertexDataId = body.Substring( vertexDataTagBegin, vertexDataTagEnd + TemplatesManager.TemplateEndOfLine.Length - vertexDataTagBegin );
  235. int dataBeginIdx = body.LastIndexOf( '{', vertexDataTagBegin, vertexDataTagBegin );
  236. string vertexData = body.Substring( dataBeginIdx + 1, vertexDataTagBegin - dataBeginIdx );
  237. int parametersBegin = vertexDataTagBegin + TemplatesManager.TemplateVertexDataTag.Length;
  238. string parameters = body.Substring( parametersBegin, vertexDataTagEnd - parametersBegin );
  239. m_vertexDataContainer.VertexData = TemplateHelperFunctions.CreateVertexDataList( vertexData, parameters );
  240. m_templateProperties.AddId( body, m_vertexDataContainer.VertexDataId );
  241. }
  242. }
  243. catch( Exception e )
  244. {
  245. Debug.LogException( e );
  246. }
  247. // Available interpolators
  248. try
  249. {
  250. int interpDataBegin = body.IndexOf( TemplatesManager.TemplateInterpolatorBeginTag );
  251. if( interpDataBegin > -1 )
  252. {
  253. int interpDataEnd = body.IndexOf( TemplatesManager.TemplateEndOfLine, interpDataBegin );
  254. string interpDataId = body.Substring( interpDataBegin, interpDataEnd + TemplatesManager.TemplateEndOfLine.Length - interpDataBegin );
  255. int dataBeginIdx = body.LastIndexOf( '{', interpDataBegin, interpDataBegin );
  256. string interpData = body.Substring( dataBeginIdx + 1, interpDataBegin - dataBeginIdx );
  257. int interpolatorAmount = TemplateHelperFunctions.AvailableInterpolators[ "2.5" ];
  258. if( m_modules.ShaderModel.IsValid )
  259. {
  260. interpolatorAmount = m_modules.ShaderModel.InterpolatorAmount;
  261. }
  262. else if( subShaderModule.ShaderModel.IsValid )
  263. {
  264. interpolatorAmount = subShaderModule.ShaderModel.InterpolatorAmount;
  265. }
  266. m_interpolatorDataContainer = TemplateHelperFunctions.CreateInterpDataList( interpData, interpDataId, interpolatorAmount );
  267. m_interpolatorDataContainer.InterpDataId = interpDataId;
  268. m_interpolatorDataContainer.InterpDataStartIdx = offsetIdx + interpDataBegin;
  269. m_templateProperties.AddId( body, interpDataId );
  270. }
  271. }
  272. catch( Exception e )
  273. {
  274. Debug.LogException( e );
  275. }
  276. }
  277. void FetchCodeAreas( int offsetIdx, string begin, MasterNodePortCategory category, string body )
  278. {
  279. int areaBeginIndexes = body.IndexOf( begin );
  280. if( areaBeginIndexes > -1 )
  281. {
  282. int beginIdx = areaBeginIndexes + begin.Length;
  283. int endIdx = body.IndexOf( TemplatesManager.TemplateEndOfLine, beginIdx );
  284. int length = endIdx - beginIdx;
  285. string parameters = body.Substring( beginIdx, length );
  286. string[] parametersArr = parameters.Split( IOUtils.FIELD_SEPARATOR );
  287. string id = body.Substring( areaBeginIndexes, endIdx + TemplatesManager.TemplateEndOfLine.Length - areaBeginIndexes );
  288. string inParameters = parametersArr[ 0 ];
  289. string outParameters = ( parametersArr.Length > 1 ) ? parametersArr[ 1 ] : string.Empty;
  290. if( category == MasterNodePortCategory.Fragment )
  291. {
  292. string mainBodyName = string.Empty;
  293. int mainBodyLocalIndex = -1;
  294. Match mainBodyNameMatch = Regex.Match( body, TemplateHelperFunctions.FragmentPragmaPattern );
  295. if( mainBodyNameMatch != null && mainBodyNameMatch.Groups.Count == 2 )
  296. {
  297. mainBodyName = mainBodyNameMatch.Groups[ 1 ].Value;
  298. string pattern = string.Format( TemplateHelperFunctions.FunctionBodyStartPattern, mainBodyName );
  299. Match mainBodyIdMatch = Regex.Match( body, pattern );
  300. if( mainBodyIdMatch != null && mainBodyIdMatch.Groups.Count > 0 )
  301. {
  302. mainBodyLocalIndex = mainBodyIdMatch.Index;
  303. }
  304. }
  305. m_fragmentFunctionData = new TemplateFunctionData( mainBodyLocalIndex, mainBodyName, id, offsetIdx + areaBeginIndexes, inParameters, outParameters, category );
  306. }
  307. else
  308. {
  309. string mainBodyName = string.Empty;
  310. int mainBodyLocalIndex = -1;
  311. Match mainBodyNameMatch = Regex.Match( body, TemplateHelperFunctions.VertexPragmaPattern );
  312. if( mainBodyNameMatch != null && mainBodyNameMatch.Groups.Count == 2 )
  313. {
  314. mainBodyName = mainBodyNameMatch.Groups[ 1 ].Value;
  315. string pattern = string.Format( TemplateHelperFunctions.FunctionBodyStartPattern, mainBodyName );
  316. Match mainBodyIdMatch = Regex.Match( body, pattern );
  317. if( mainBodyIdMatch != null && mainBodyIdMatch.Groups.Count > 0 )
  318. {
  319. mainBodyLocalIndex = mainBodyIdMatch.Index;
  320. }
  321. }
  322. m_vertexFunctionData = new TemplateFunctionData( mainBodyLocalIndex, mainBodyName, id, offsetIdx + areaBeginIndexes, inParameters, outParameters, category );
  323. }
  324. m_templateProperties.AddId( body, id, true );
  325. }
  326. }
  327. void FetchInputs( int offset, MasterNodePortCategory portCategory, string body )
  328. {
  329. string beginTag = ( portCategory == MasterNodePortCategory.Fragment ) ? TemplatesManager.TemplateInputsFragBeginTag : TemplatesManager.TemplateInputsVertBeginTag;
  330. int[] inputBeginIndexes = body.AllIndexesOf( beginTag );
  331. if( inputBeginIndexes != null && inputBeginIndexes.Length > 0 )
  332. {
  333. for( int i = 0; i < inputBeginIndexes.Length; i++ )
  334. {
  335. int inputEndIdx = body.IndexOf( TemplatesManager.TemplateEndSectionTag, inputBeginIndexes[ i ] );
  336. int defaultValueBeginIdx = inputEndIdx + TemplatesManager.TemplateEndSectionTag.Length;
  337. int endLineIdx = body.IndexOf( TemplatesManager.TemplateFullEndTag, defaultValueBeginIdx );
  338. string defaultValue = body.Substring( defaultValueBeginIdx, endLineIdx - defaultValueBeginIdx );
  339. string tagId = body.Substring( inputBeginIndexes[ i ], endLineIdx + TemplatesManager.TemplateFullEndTag.Length - inputBeginIndexes[ i ] );
  340. int beginIndex = inputBeginIndexes[ i ] + beginTag.Length;
  341. int length = inputEndIdx - beginIndex;
  342. string inputData = body.Substring( beginIndex, length );
  343. string[] inputDataArray = inputData.Split( IOUtils.FIELD_SEPARATOR );
  344. if( inputDataArray != null && inputDataArray.Length > 0 )
  345. {
  346. try
  347. {
  348. string portName = inputDataArray[ (int)TemplatePortIds.Name ];
  349. WirePortDataType dataType = (WirePortDataType)Enum.Parse( typeof( WirePortDataType ), inputDataArray[ (int)TemplatePortIds.DataType ].ToUpper() );
  350. if( inputDataArray.Length == 3 )
  351. {
  352. int portOrderId = m_inputDataList.Count;
  353. int portUniqueId = -1;
  354. bool isInt = int.TryParse( inputDataArray[ 2 ], out portUniqueId );
  355. if( isInt )
  356. {
  357. if( portUniqueId < 0 )
  358. portUniqueId = m_inputDataList.Count;
  359. m_inputDataList.Add( new TemplateInputData( inputBeginIndexes[ i ], offset + inputBeginIndexes[ i ], tagId, portName, defaultValue, dataType, portCategory, portUniqueId, portOrderId, string.Empty ) );
  360. m_templateProperties.AddId( body, tagId, false );
  361. }
  362. else
  363. {
  364. portUniqueId = m_inputDataList.Count;
  365. m_inputDataList.Add( new TemplateInputData( inputBeginIndexes[ i ], offset + inputBeginIndexes[ i ], tagId, portName, defaultValue, dataType, portCategory, portUniqueId, portOrderId, inputDataArray[ 2 ] ) );
  366. m_templateProperties.AddId( body, tagId, false );
  367. }
  368. }
  369. else
  370. {
  371. int portUniqueIDArrIdx = (int)TemplatePortIds.UniqueId;
  372. int portUniqueId = ( portUniqueIDArrIdx < inputDataArray.Length ) ? Convert.ToInt32( inputDataArray[ portUniqueIDArrIdx ] ) : -1;
  373. if( portUniqueId < 0 )
  374. portUniqueId = m_inputDataList.Count;
  375. int portOrderArrayIdx = (int)TemplatePortIds.OrderId;
  376. int portOrderId = ( portOrderArrayIdx < inputDataArray.Length ) ? Convert.ToInt32( inputDataArray[ portOrderArrayIdx ] ) : -1;
  377. if( portOrderId < 0 )
  378. portOrderId = m_inputDataList.Count;
  379. int portLinkIdx = (int)TemplatePortIds.Link;
  380. string linkId = ( portLinkIdx < inputDataArray.Length ) ? inputDataArray[ portLinkIdx ] : string.Empty;
  381. m_inputDataList.Add( new TemplateInputData( inputBeginIndexes[ i ], offset + inputBeginIndexes[ i ], tagId, portName, defaultValue, dataType, portCategory, portUniqueId, portOrderId, linkId ) );
  382. m_templateProperties.AddId( body, tagId, false );
  383. }
  384. }
  385. catch( Exception e )
  386. {
  387. Debug.LogException( e );
  388. }
  389. }
  390. }
  391. }
  392. }
  393. #if CUSTOM_OPTIONS_AVAILABLE
  394. public TemplateOptionsContainer CustomOptionsContainer { get { return m_customOptionsContainer; } }
  395. #endif
  396. public TemplateModulesData Modules { get { return m_modules; } }
  397. public List<TemplateInputData> InputDataList { get { return m_inputDataList; } }
  398. public TemplateFunctionData VertexFunctionData { get { return m_vertexFunctionData; } }
  399. public TemplateFunctionData FragmentFunctionData { get { return m_fragmentFunctionData; } }
  400. public VertexDataContainer VertexDataContainer { get { return m_vertexDataContainer; } }
  401. public TemplateInterpData InterpolatorDataContainer { get { return m_interpolatorDataContainer; } }
  402. public string UniquePrefix { get { return m_uniquePrefix; } }
  403. public TemplatePropertyContainer TemplateProperties { get { return m_templateProperties; } }
  404. public List<TemplateShaderPropertyData> AvailableShaderGlobals { get { return m_availableShaderGlobals; } }
  405. public List<TemplateLocalVarData> LocalVarsList { get { return m_localVarsList; } }
  406. public TemplateInfoContainer PassNameContainer { get { return m_passNameContainer; } }
  407. public bool IsMainPass { get { return m_isMainPass; } set { m_isMainPass = value; } }
  408. public bool IsInvisible { get { return m_isInvisible; } }
  409. public int InvisibleOptions { get { return m_invisibleOptions; } }
  410. public int Idx { get { return m_idx; } }
  411. public bool AddToList
  412. {
  413. get
  414. {
  415. if( m_isInvisible )
  416. {
  417. return ( m_inputDataList.Count > 0 );
  418. }
  419. return true;
  420. }
  421. }
  422. public bool HasValidFunctionBody
  423. {
  424. get
  425. {
  426. if( m_fragmentFunctionData != null || m_vertexFunctionData != null )
  427. return true;
  428. return false;
  429. }
  430. }
  431. }
  432. }