A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Text;
4using JetBrains.Annotations;
5using UnityEditor.Graphing;
6using System.Globalization;
7using UnityEngine.Profiling;
8
9namespace UnityEditor.ShaderGraph
10{
11 struct ShaderStringMapping
12 {
13 public AbstractMaterialNode node { get; set; }
14 // public List<AbstractMaterialNode> nodes { get; set; }
15 public int startIndex { get; set; }
16 public int count { get; set; }
17 }
18
19 class ShaderStringBuilder : IDisposable
20 {
21 enum ScopeType
22 {
23 Indent,
24 Block,
25 BlockSemicolon
26 }
27
28 StringBuilder m_StringBuilder;
29 Stack<ScopeType> m_ScopeStack;
30 int m_IndentationLevel;
31 ShaderStringMapping m_CurrentMapping;
32 List<ShaderStringMapping> m_Mappings;
33 bool m_HumanReadable;
34
35 const string k_IndentationString = " ";
36 const string k_NewLineString = "\n";
37
38 internal AbstractMaterialNode currentNode
39 {
40 get { return m_CurrentMapping.node; }
41 set
42 {
43 m_CurrentMapping.count = m_StringBuilder.Length - m_CurrentMapping.startIndex;
44 if (m_CurrentMapping.count > 0)
45 m_Mappings.Add(m_CurrentMapping);
46 m_CurrentMapping.node = value;
47 m_CurrentMapping.startIndex = m_StringBuilder.Length;
48 m_CurrentMapping.count = 0;
49 }
50 }
51
52 internal List<ShaderStringMapping> mappings
53 {
54 get { return m_Mappings; }
55 }
56
57 public ShaderStringBuilder(int indentationLevel = 0, int stringBuilderSize = 8192, bool humanReadable = false)
58 {
59 IncreaseIndent(indentationLevel);
60 m_StringBuilder = new StringBuilder(stringBuilderSize);
61 m_ScopeStack = new Stack<ScopeType>();
62 m_Mappings = new List<ShaderStringMapping>();
63 m_CurrentMapping = new ShaderStringMapping();
64 m_HumanReadable = humanReadable;
65 }
66
67 public void AppendNewLine()
68 {
69 m_StringBuilder.Append(k_NewLineString);
70 }
71
72 private void AppendLine(string value, int startIndex, int count)
73 {
74 if (value.Length > 0)
75 {
76 TryAppendIndentation();
77 m_StringBuilder.Append(value, startIndex, count);
78 }
79 AppendNewLine();
80 }
81
82 public void AppendLine(string value)
83 {
84 if (!string.IsNullOrEmpty(value))
85 {
86 TryAppendIndentation();
87 m_StringBuilder.Append(value);
88 }
89 AppendNewLine();
90 }
91
92 public void AddLine(string v0) { TryAppendIndentation(); Append(v0); AppendNewLine(); }
93 public void AddLine(string v0, string v1) { TryAppendIndentation(); Append(v0); Append(v1); AppendNewLine(); }
94 public void AddLine(string v0, string v1, string v2) { TryAppendIndentation(); Append(v0); Append(v1); Append(v2); AppendNewLine(); }
95 public void AddLine(string v0, string v1, string v2, string v3) { TryAppendIndentation(); Append(v0); Append(v1); Append(v2); Append(v3); AppendNewLine(); }
96 public void AddLine(string v0, string v1, string v2, string v3, string v4) { TryAppendIndentation(); Append(v0); Append(v1); Append(v2); Append(v3); Append(v4); AppendNewLine(); }
97 public void AddLine(string v0, string v1, string v2, string v3, string v4, string v5) { TryAppendIndentation(); Append(v0); Append(v1); Append(v2); Append(v3); Append(v4); Append(v5); AppendNewLine(); }
98 public void AddLine(string v0, string v1, string v2, string v3, string v4, string v5, string v6) { TryAppendIndentation(); Append(v0); Append(v1); Append(v2); Append(v3); Append(v4); Append(v5); Append(v6); AppendNewLine(); }
99 public void AddLine(string v0, string v1, string v2, string v3, string v4, string v5, string v6, string v7) { TryAppendIndentation(); Append(v0); Append(v1); Append(v2); Append(v3); Append(v4); Append(v5); Append(v6); Append(v7); AppendNewLine(); }
100
101 [StringFormatMethod("formatString")]
102 public void AppendLine(string formatString, params object[] args)
103 {
104 TryAppendIndentation();
105 m_StringBuilder.AppendFormat(CultureInfo.InvariantCulture, formatString, args);
106 AppendNewLine();
107 }
108
109 static readonly char[] LineSeparators = new[] { '\n', '\r'};
110 public void AppendLines(string lines)
111 {
112 if (string.IsNullOrEmpty(lines))
113 return;
114
115 int startSearchIndex = 0;
116 int indexOfNextBreak = lines.IndexOfAny(LineSeparators);
117 while (indexOfNextBreak >= 0)
118 {
119 AppendLine(lines, startSearchIndex, indexOfNextBreak - startSearchIndex);
120 startSearchIndex = indexOfNextBreak + 1;
121 indexOfNextBreak = lines.IndexOfAny(LineSeparators, startSearchIndex);
122 }
123
124 if (startSearchIndex < lines.Length)
125 {
126 AppendLine(lines, startSearchIndex, lines.Length - startSearchIndex);
127 }
128 }
129
130 public void Append(string value)
131 {
132 m_StringBuilder.Append(value);
133 }
134
135 public void Append(string value, int start, int count)
136 {
137 m_StringBuilder.Append(value, start, count);
138 }
139
140 [StringFormatMethod("formatString")]
141 public void Append(string formatString, params object[] args)
142 {
143 m_StringBuilder.AppendFormat(formatString, args);
144 }
145
146 public void AppendSpaces(int count)
147 {
148 m_StringBuilder.Append(' ', count);
149 }
150
151 public void TryAppendIndentation()
152 {
153 if (m_HumanReadable)
154 {
155 for (var i = 0; i < m_IndentationLevel; i++)
156 m_StringBuilder.Append(k_IndentationString);
157 }
158 }
159
160 public IDisposable IndentScope()
161 {
162 m_ScopeStack.Push(ScopeType.Indent);
163 IncreaseIndent();
164 return this;
165 }
166
167 public IDisposable BlockScope()
168 {
169 AppendLine("{");
170 IncreaseIndent();
171 m_ScopeStack.Push(ScopeType.Block);
172 return this;
173 }
174
175 public IDisposable BlockSemicolonScope()
176 {
177 AppendLine("{");
178 IncreaseIndent();
179 m_ScopeStack.Push(ScopeType.BlockSemicolon);
180 return this;
181 }
182
183 public void IncreaseIndent()
184 {
185 m_IndentationLevel++;
186 }
187
188 public void IncreaseIndent(int level)
189 {
190 for (var i = 0; i < level; i++)
191 IncreaseIndent();
192 }
193
194 public void DecreaseIndent()
195 {
196 m_IndentationLevel--;
197 }
198
199 public void DecreaseIndent(int level)
200 {
201 for (var i = 0; i < level; i++)
202 DecreaseIndent();
203 }
204
205 public void Dispose()
206 {
207 if (m_ScopeStack.Count == 0)
208 return;
209
210 switch (m_ScopeStack.Pop())
211 {
212 case ScopeType.Indent:
213 DecreaseIndent();
214 break;
215 case ScopeType.Block:
216 DecreaseIndent();
217 AppendLine("}");
218 break;
219 case ScopeType.BlockSemicolon:
220 DecreaseIndent();
221 AppendLine("};");
222 break;
223 }
224 }
225
226 public void Concat(ShaderStringBuilder other)
227 {
228 // First re-add all the mappings from `other`, such that their mappings are transformed.
229 foreach (var mapping in other.m_Mappings)
230 {
231 currentNode = mapping.node;
232
233 // Use `AppendLines` to indent according to the current indentation.
234 if (m_HumanReadable)
235 {
236 AppendLines(other.ToString(mapping.startIndex, mapping.count));
237 }
238 else
239 {
240 Append(other.ToString(mapping.startIndex, mapping.count));
241 }
242 }
243 currentNode = other.currentNode;
244 if (m_HumanReadable)
245 {
246 AppendLines(other.ToString(other.m_CurrentMapping.startIndex, other.length - other.m_CurrentMapping.startIndex));
247 }
248 else
249 {
250 Append(other.ToString(other.m_CurrentMapping.startIndex, other.length - other.m_CurrentMapping.startIndex));
251 }
252 }
253
254 public void ReplaceInCurrentMapping(string oldValue, string newValue)
255 {
256 Profiler.BeginSample("ReplaceInCurrentMapping");
257 int start = m_CurrentMapping.startIndex;
258 int end = m_StringBuilder.Length - start;
259 m_StringBuilder.Replace(oldValue, newValue, start, end);
260 Profiler.EndSample();
261 }
262
263 public void Replace(string oldValue, string newValue, int start, int end)
264 {
265 m_StringBuilder.Replace(oldValue, newValue, start, end);
266 }
267
268 public string ToCodeBlock()
269 {
270 // Remove new line
271 if (m_StringBuilder.Length > 0)
272 m_StringBuilder.Length = m_StringBuilder.Length - 1;
273
274 if (m_HumanReadable)
275 {
276 // Set indentations
277 m_StringBuilder.Replace(Environment.NewLine, Environment.NewLine + k_IndentationString);
278 }
279
280 return m_StringBuilder.ToString();
281 }
282
283 public override string ToString()
284 {
285 return m_StringBuilder.ToString();
286 }
287
288 public string ToString(int startIndex, int length)
289 {
290 return m_StringBuilder.ToString(startIndex, length);
291 }
292
293 internal void Clear()
294 {
295 m_StringBuilder.Length = 0;
296 }
297
298 internal int length
299 {
300 get { return m_StringBuilder.Length; }
301 set { m_StringBuilder.Length = value; }
302 }
303 }
304}