@@ -20,7 +20,9 @@ public static class ShaderGenerator
2020 private const string COMMON_PROPERTIES_PATH = "Packages/com.unity.toonshader/Runtime/Shaders/Common/Parts~/CommonPropertiesPart.shader" ;
2121 private const string TESSELATION_PROPERTIES_PATH = "Packages/com.unity.toonshader/Runtime/Shaders/Common/Parts~/TessellationPropertiesPart.shader" ;
2222 private const string UNITY_TOON_SHADER_PATH = "Packages/com.unity.toonshader/Runtime/Integrated/Shaders/UnityToon.shader" ;
23+ private const string UNITY_TOON_SHADER_TEMPLATE_PATH = "Packages/com.unity.toonshader/Runtime/Shaders/Common/Parts~/UnityToon.shader.template" ;
2324 private const string UNITY_TOON_TESSELATION_SHADER_PATH = "Packages/com.unity.toonshader/Runtime/Integrated/Shaders/UnityToonTessellation.shader" ;
25+ private const string UNITY_TOON_TESSELATION_SHADER_TEMPLATE_PATH = "Packages/com.unity.toonshader/Runtime/Shaders/Common/Parts~/UnityToonTessellation.shader.template" ;
2426
2527 [ MenuItem ( "Toon Shader/Generate Shader Files" ) ]
2628 public static void GenerateShaderFilesMenu ( )
@@ -87,158 +89,41 @@ private static void GenerateShaderFilesInternal()
8789
8890 private static void GenerateUnityToonShader ( string commonProperties , string autoCommentLine )
8991 {
90- // Read the original shader file to preserve the rest of the content
91- string originalContent = ReadFile ( UNITY_TOON_SHADER_PATH ) ;
92- if ( string . IsNullOrEmpty ( originalContent ) )
93- {
94- originalContent = ReadFile ( UNITY_TOON_SHADER_PATH + ".template" ) ;
95- if ( string . IsNullOrEmpty ( originalContent ) )
96- {
97- Debug . LogError ( $ "Failed to read original shader from { UNITY_TOON_SHADER_PATH } ") ;
98- return ;
99- }
100- }
101- // Replace the Properties block
102- string newContent = ReplacePropertiesBlock ( originalContent , commonProperties , string . Empty , autoCommentLine ) ;
103- WriteFile ( UNITY_TOON_SHADER_PATH , newContent ) ;
92+ GenerateShaderFromTemplate ( UNITY_TOON_SHADER_TEMPLATE_PATH , UNITY_TOON_SHADER_PATH , commonProperties , string . Empty , autoCommentLine ) ;
10493 }
105-
94+
10695 private static void GenerateUnityToonTessellationShader ( string commonProperties , string tessellationProperties , string autoCommentLine )
10796 {
108- // Read the original shader file to preserve the rest of the content
109- string originalContent = ReadFile ( UNITY_TOON_TESSELATION_SHADER_PATH ) ;
110- if ( string . IsNullOrEmpty ( originalContent ) )
111- {
112- originalContent = ReadFile ( UNITY_TOON_TESSELATION_SHADER_PATH + ".template" ) ;
113- if ( string . IsNullOrEmpty ( originalContent ) )
114- {
115- Debug . LogError ( $ "Failed to read original tessellation shader from { UNITY_TOON_TESSELATION_SHADER_PATH } ") ;
116- return ;
117- }
118- }
119- // Replace the Properties block
120- string newContent = ReplacePropertiesBlock ( originalContent , commonProperties , tessellationProperties , autoCommentLine ) ;
121- WriteFile ( UNITY_TOON_TESSELATION_SHADER_PATH , newContent ) ;
97+ GenerateShaderFromTemplate ( UNITY_TOON_TESSELATION_SHADER_TEMPLATE_PATH , UNITY_TOON_TESSELATION_SHADER_PATH , commonProperties , tessellationProperties , autoCommentLine ) ;
12298 }
123-
124- private static string ReplacePropertiesBlock ( string originalContent , string commonProperties , string tessellationProperties , string autoCommentLine )
125- {
126- // Find the Properties block using a more robust regex that handles nested braces
127- string propertiesPattern = @"Properties\s*\{" ;
128- Match startMatch = Regex . Match ( originalContent , propertiesPattern ) ;
129-
130- if ( ! startMatch . Success )
131- {
132- Debug . LogError ( "Could not find Properties block start in shader file" ) ;
133- return originalContent ;
134- }
135-
136- // Find the matching closing brace
137- int startIndex = startMatch . Index ;
138- int braceCount = 0 ;
139- int endIndex = startIndex ;
140- bool foundStart = false ;
141-
142- for ( int i = startIndex ; i < originalContent . Length ; i ++ )
143- {
144- if ( originalContent [ i ] == '{' )
145- {
146- braceCount ++ ;
147- foundStart = true ;
148- }
149- else if ( originalContent [ i ] == '}' )
150- {
151- braceCount -- ;
152- if ( foundStart && braceCount == 0 )
153- {
154- endIndex = i ;
155- break ;
156- }
157- }
158- }
159-
160- if ( braceCount != 0 )
161- {
162- Debug . LogError ( "Could not find matching closing brace for Properties block" ) ;
163- return originalContent ;
164- }
165-
166- int lineStartIndex = originalContent . LastIndexOf ( '\n ' , startIndex - 1 ) ;
167- int baseIndentStart = lineStartIndex == - 1 ? 0 : lineStartIndex + 1 ;
168- string baseIndent = " " ;
169- string blockIndent = baseIndent + " " ;
170-
171- // Build new Properties block
172- List < string > newProperties = new List < string > ( ) ;
173- Dictionary < string , int > propertyLineIndices = new Dictionary < string , int > ( StringComparer . Ordinal ) ;
174- int propertyCount = 0 ;
175-
176- newProperties . Add ( $ "{ baseIndent } Properties {{") ;
17799
178- void AppendPropertyLine ( string trimmedLine , bool allowOverride )
100+ private static void GenerateShaderFromTemplate ( string templatePath , string outputPath , string commonProperties , string tessellationProperties , string autoCommentLine )
101+ {
102+ string templateContent = ReadFile ( templatePath ) ;
103+ if ( string . IsNullOrEmpty ( templateContent ) )
179104 {
180- if ( string . IsNullOrEmpty ( trimmedLine ) )
181- {
182- newProperties . Add ( string . Empty ) ;
183- return ;
184- }
185-
186- string propertyLine = $ "{ blockIndent } { trimmedLine } ";
187- string propertyName = GetPropertyName ( trimmedLine ) ;
188-
189- if ( propertyName == null )
105+ templateContent = ReadFile ( outputPath ) ;
106+ if ( string . IsNullOrEmpty ( templateContent ) )
190107 {
191- newProperties . Add ( propertyLine ) ;
108+ Debug . LogError ( $ "Failed to read template or existing shader for { outputPath } " ) ;
192109 return ;
193110 }
194-
195- if ( propertyLineIndices . TryGetValue ( propertyName , out int existingIndex ) )
196- {
197- if ( allowOverride )
198- {
199- newProperties [ existingIndex ] = propertyLine ;
200- return ;
201- }
202-
203- string existingLine = newProperties [ existingIndex ] ;
204- bool existingHidden = existingLine . Trim ( ) . StartsWith ( "[HideInInspector]" , StringComparison . Ordinal ) ;
205- bool newHidden = trimmedLine . StartsWith ( "[HideInInspector]" , StringComparison . Ordinal ) ;
206-
207- if ( existingHidden && ! newHidden )
208- {
209- newProperties [ existingIndex ] = propertyLine ;
210- }
211- return ;
212- }
213-
214- propertyLineIndices [ propertyName ] = newProperties . Count ;
215- propertyCount ++ ;
216- newProperties . Add ( propertyLine ) ;
217111 }
218112
219- foreach ( string line in commonProperties . Split ( '\n ' ) )
220- {
221- AppendPropertyLine ( line . Trim ( ) , allowOverride : false ) ;
222- }
113+ templateContent = templateContent . TrimStart ( '\uFEFF ' ) ;
223114
224- if ( ! string . IsNullOrEmpty ( tessellationProperties ) )
225- {
226- newProperties . Add ( string . Empty ) ;
227- newProperties . Add ( $ "{ blockIndent } // Tessellation-specific properties") ;
228- foreach ( string line in tessellationProperties . Split ( '\n ' ) )
229- {
230- AppendPropertyLine ( line . Trim ( ) , allowOverride : true ) ;
231- }
232- }
115+ PropertySections sections = BuildPropertySections ( commonProperties , tessellationProperties , " " ) ;
233116
234- newProperties . Add ( baseIndent + "}" ) ;
117+ templateContent = ReplacePlaceholder ( templateContent , " [COMMON_PROPERTIES]" , sections . Common ) ;
118+ templateContent = ReplacePlaceholder ( templateContent , "[COMMON_PROPERTIES]" , sections . Common ) ;
235119
236- Debug . Log ( $ "Generated Properties block with { propertyCount } properties") ;
120+ templateContent = ReplacePlaceholder ( templateContent , " [TESSELLATION_PROPERTIES]" , sections . Tess ) ;
121+ templateContent = ReplacePlaceholder ( templateContent , "[TESSELLATION_PROPERTIES]" , sections . Tess ) ;
237122
238- string newPropertiesText = string . Join ( " \n " , newProperties ) ;
123+ Debug . Log ( $ "Generated properties with { sections . Count } entries for { outputPath } " ) ;
239124
240- string updatedContent = originalContent . Substring ( 0 , baseIndentStart ) + newPropertiesText + originalContent . Substring ( endIndex + 1 ) ;
241- return ApplyAutoGeneratedComment ( updatedContent , autoCommentLine ) ;
125+ templateContent = ApplyAutoGeneratedComment ( templateContent , autoCommentLine ) ;
126+ WriteFile ( outputPath , templateContent ) ;
242127 }
243128
244129 private static string ExtractPropertiesBlockContent ( string shaderContent )
@@ -395,5 +280,136 @@ private static string ApplyAutoGeneratedComment(string content, string commentLi
395280
396281 return result ;
397282 }
283+
284+ private static string ReplacePlaceholder ( string content , string placeholder , string replacement )
285+ {
286+ if ( content . Contains ( placeholder ) )
287+ {
288+ return content . Replace ( placeholder , replacement ?? string . Empty ) ;
289+ }
290+
291+ return content ;
292+ }
293+
294+ private static PropertySections BuildPropertySections ( string commonProperties , string tessellationProperties , string indent )
295+ {
296+ var entries = new List < PropertyEntry > ( ) ;
297+ var nameToIndex = new Dictionary < string , int > ( StringComparer . Ordinal ) ;
298+
299+ void AddLines ( string rawText , string source )
300+ {
301+ if ( string . IsNullOrEmpty ( rawText ) )
302+ {
303+ return ;
304+ }
305+
306+ var lines = rawText . Split ( new [ ] { '\n ' , '\r ' } , StringSplitOptions . None ) ;
307+ foreach ( var rawLine in lines )
308+ {
309+ var trimmed = rawLine . Trim ( ) ;
310+ var entry = new PropertyEntry
311+ {
312+ Line = trimmed ,
313+ Source = source ,
314+ Name = GetPropertyName ( trimmed )
315+ } ;
316+
317+ if ( trimmed . Length == 0 )
318+ {
319+ entries . Add ( entry ) ;
320+ continue ;
321+ }
322+
323+ if ( ! string . IsNullOrEmpty ( entry . Name ) && nameToIndex . TryGetValue ( entry . Name , out int existingIndex ) )
324+ {
325+ entries [ existingIndex ] = entry ;
326+ }
327+ else
328+ {
329+ entries . Add ( entry ) ;
330+ if ( ! string . IsNullOrEmpty ( entry . Name ) )
331+ {
332+ nameToIndex [ entry . Name ] = entries . Count - 1 ;
333+ }
334+ }
335+ }
336+ }
337+
338+ AddLines ( commonProperties , "common" ) ;
339+ AddLines ( tessellationProperties , "tess" ) ;
340+
341+ int propertyCount = 0 ;
342+ var commonLines = new List < string > ( ) ;
343+ var tessLines = new List < string > ( ) ;
344+
345+ foreach ( var entry in entries )
346+ {
347+ if ( ! string . IsNullOrEmpty ( entry . Name ) )
348+ {
349+ propertyCount ++ ;
350+ }
351+
352+ var target = entry . Source == "tess" ? tessLines : commonLines ;
353+ if ( string . IsNullOrEmpty ( entry . Line ) )
354+ {
355+ target . Add ( string . Empty ) ;
356+ }
357+ else
358+ {
359+ target . Add ( indent + entry . Line ) ;
360+ }
361+ }
362+
363+ commonLines = CleanupLines ( commonLines ) ;
364+ tessLines = CleanupLines ( tessLines ) ;
365+
366+ return new PropertySections
367+ {
368+ Common = string . Join ( "\n " , commonLines ) ,
369+ Tess = string . Join ( "\n " , tessLines ) ,
370+ Count = propertyCount
371+ } ;
372+ }
373+
374+ private static List < string > CleanupLines ( List < string > lines )
375+ {
376+ var result = new List < string > ( lines ) ;
377+
378+ while ( result . Count > 0 && result [ 0 ] . Length == 0 )
379+ {
380+ result . RemoveAt ( 0 ) ;
381+ }
382+
383+ while ( result . Count > 0 && result [ result . Count - 1 ] . Length == 0 )
384+ {
385+ result . RemoveAt ( result . Count - 1 ) ;
386+ }
387+
388+ var cleaned = new List < string > ( ) ;
389+ foreach ( var line in result )
390+ {
391+ if ( line . Length == 0 && cleaned . Count > 0 && cleaned [ cleaned . Count - 1 ] . Length == 0 )
392+ {
393+ continue ;
394+ }
395+ cleaned . Add ( line ) ;
396+ }
397+
398+ return cleaned ;
399+ }
400+
401+ private struct PropertySections
402+ {
403+ public string Common ;
404+ public string Tess ;
405+ public int Count ;
406+ }
407+
408+ private class PropertyEntry
409+ {
410+ public string Line ;
411+ public string Source ;
412+ public string Name ;
413+ }
398414 }
399415}
0 commit comments