/// <summary> /// Forces the generation of any shaders that make use of generated noise header files. Gathers all /// the NoiseShaderGenerators and generates shaders based on the ".noisehlsltemplate" file /// provided by that particular NoiseShaderGenerator implementation /// </summary> public static void GenerateShaders() { System.Globalization.CultureInfo prevCultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture; System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture; GatherGenerators(); IFractalType[] fractalTypes = s_fractalTypes; INoiseType[] noiseTypes = s_noiseTypes; Dictionary <Type, INoiseShaderGenerator> generators = s_generators; StringBuilder shaderSB = new StringBuilder(); StringBuilder passesSB = new StringBuilder(); foreach (KeyValuePair <Type, INoiseShaderGenerator> pair in generators) { shaderSB.Clear(); passesSB.Clear(); string shaderTemplateStr = null; INoiseShaderGenerator generator = pair.Value; ShaderGeneratorDescriptor generatorDesc = generator.GetDescription(); if (!File.Exists(generatorDesc.templatePath)) { Debug.LogError("Could not find specified template file for noise shader generator: " + generator); continue; } // load contents of shader template using (StreamReader sr = new StreamReader(generatorDesc.templatePath)) { shaderTemplateStr = sr.ReadToEnd(); } // find the pass template using regex matching Match passTemplateMatch = Regex.Match(shaderTemplateStr, Strings.k_regexPassTemplate1); if (!passTemplateMatch.Success) { Debug.LogError($"Could not find pass template in {generatorDesc.templatePath}. Skipping noise shader generation for this generator type!!"); continue; } string passTemplateStr = passTemplateMatch.Value; // generate shaders for each fractal type foreach (IFractalType fractal in fractalTypes) { FractalTypeDescriptor fractalDesc = fractal.GetDescription(); string fullShaderCategory = GetShaderName(generatorDesc, fractalDesc); shaderSB.Append(NoiseLib.Strings.k_warningHeader); shaderSB.Append(shaderTemplateStr); shaderSB.Replace(NoiseLib.Strings.k_tagShaderCategory, $"\"{fullShaderCategory}\""); // add passes for each noise type foreach (INoiseType noise in noiseTypes) { GeneratedShaderInfo info = new GeneratedShaderInfo(fractal, noise); // add to passes string builer passesSB.Append(passTemplateStr); passesSB.AppendLine(); passesSB.Replace(NoiseLib.Strings.k_tagIncludes, string.Format("#include \"{0}\"", info.generatedIncludePath)); info.ReplaceTags(passesSB); } // replace template with generated passes string newContents = Regex.Replace(shaderSB.ToString(), Strings.k_regexPassTemplate2, passesSB.ToString()); newContents = newContents.Replace(NoiseLib.Strings.k_tagFractalName, fractalDesc.name); // load shader contents from disk if it exists string fileName = string.Format("{0}{1}.shader", generatorDesc.name, fractalDesc.name); string filePath = string.Format("{0}/{1}", generatorDesc.outputDir, fileName); if (!Directory.Exists(generatorDesc.outputDir)) { Directory.CreateDirectory(generatorDesc.outputDir); } string currentContents = null; FileInfo fi = new FileInfo(filePath); if (File.Exists(filePath)) { using (StreamReader sr = new StreamReader(filePath)) { currentContents = sr.ReadToEnd(); currentContents = NormalizeLineEndings(currentContents); } } // do some code cleanup newContents = Regex.Replace(newContents, NoiseLib.Strings.k_regexDupCommas, ", "); newContents = Regex.Replace(newContents, NoiseLib.Strings.k_emptyArgsRight, " )"); newContents = Regex.Replace(newContents, NoiseLib.Strings.k_emptyArgsLeft, "( "); newContents = NormalizeLineEndings(newContents); // only write to file if it is not read-only, ie. if it is one of the generated // shader files that we ship with the TerrainTools package if (!fi.IsReadOnly) { if (currentContents == null || currentContents.CompareTo(newContents) != 0) { try { using (StreamWriter sw = new StreamWriter(filePath)) { sw.Write(newContents); } } catch (Exception) { // restore previous cultureinfo System.Threading.Thread.CurrentThread.CurrentCulture = prevCultureInfo; } } } shaderSB.Clear(); passesSB.Clear(); } } // restore previous cultureinfo System.Threading.Thread.CurrentThread.CurrentCulture = prevCultureInfo; UnityEditor.AssetDatabase.Refresh(); }
/*========================================================================================== * * Generate HLSL * * ==========================================================================================*/ /// <summary> /// Forces generation of the NoiseType and FractalType variant HLSL header files /// </summary> public static void GenerateHeaderFiles() { System.Globalization.CultureInfo prevCultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture; System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture; GatherNoiseTypes(); GatherFractalTypes(); INoiseType[] noiseTypes = s_noiseTypes; IFractalType[] fractalTypes = s_fractalTypes; string[] fractalContents = LoadFractalSource(fractalTypes); string[] noiseContents = LoadNoiseSource(noiseTypes); for (int f = 0; f < fractalTypes.Length; ++f) { string fractalStr = fractalContents[f]; // dont generate for this fractal type if the source could not be found if (fractalStr == null) { continue; } IFractalType fractal = fractalTypes[f]; for (int n = 0; n < noiseTypes.Length; ++n) { string noiseStr = noiseContents[n]; // dont generate for this noise type if the source could not be found if (noiseStr == null) { continue; } INoiseType noise = noiseTypes[n]; GeneratedShaderInfo info = new GeneratedShaderInfo(fractal, noise); StringBuilder sb = new StringBuilder(); sb.Append(Strings.k_warningHeader); // add the DO NOT EDIT warning sb.Append(fractalStr); // add the fractal template info.ReplaceTags(sb); string newContents = sb.ToString(); // do some code cleanup newContents = Regex.Replace(newContents, Strings.k_regexDupCommas, ", "); newContents = Regex.Replace(newContents, Strings.k_emptyArgsRight, " )"); newContents = Regex.Replace(newContents, Strings.k_emptyArgsLeft, "( "); newContents = NormalizeLineEndings(newContents); string outputDir = info.outputDir; // TODO(wyatt): need to verify this is actually a directory and not a file if (!Directory.Exists(outputDir)) { Directory.CreateDirectory(outputDir); } string oldContents = null; FileInfo fi = new FileInfo(info.generatedIncludePath); if (File.Exists(info.generatedIncludePath)) { using (StreamReader sr = new StreamReader(info.generatedIncludePath)) { oldContents = sr.ReadToEnd(); oldContents = NormalizeLineEndings(oldContents); } } if (!fi.IsReadOnly) { if (oldContents == null || newContents.CompareTo(oldContents) != 0) { try { using (StreamWriter sw = new StreamWriter(info.generatedIncludePath)) { sw.Write(newContents); } } catch (Exception) { // restore previous cultureinfo System.Threading.Thread.CurrentThread.CurrentCulture = prevCultureInfo; } } } } } // restore previous cultureinfo System.Threading.Thread.CurrentThread.CurrentCulture = prevCultureInfo; UnityEditor.AssetDatabase.Refresh(); }