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}