Example #1
0
        private static string[] LoadFractalSource(IFractalType[] fractalTypes)
        {
            // load fractal templates
            List <string> fractalSource = new List <string>();

            foreach (IFractalType fractal in fractalTypes)
            {
                FractalTypeDescriptor desc = fractal.GetDescription();
                string path   = desc.templatePath;
                string source = null;

                if (!File.Exists(path))
                {
                    Debug.LogError("NoiseLib: Fractal Template File at \"" + path + "\" could not be found! Skipping generation of: " + desc.name);
                }
                else
                {
                    using (StreamReader sr = new StreamReader(path))
                    {
                        source = sr.ReadToEnd();
                    }
                }

                fractalSource.Add(source);
            }

            return(fractalSource.ToArray());
        }
Example #2
0
        private static string GetShaderName(ShaderGeneratorDescriptor generatorDesc, FractalTypeDescriptor fractalDesc)
        {
            string shaderStr = string.Format("{0}/{1}{2}", generatorDesc.shaderCategory,
                                             generatorDesc.name,
                                             fractalDesc.name);

            return(shaderStr);
        }
Example #3
0
        private static void GatherFractalTypes()
        {
            List <IFractalType> instances = new List <IFractalType>();
            List <string>       names     = new List <string>();

            List <Type> types = new List <Type>();

            foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
            {
                Type[] assemblyTypes = null;

                try
                {
                    assemblyTypes = asm.GetTypes();
                }
                catch (Exception)
                {
                    Debug.Log("NoiseLib::GatherFractalTypes: Failed to get types from assembly: " + asm);
                    assemblyTypes = null;
                }

                if (assemblyTypes != null)
                {
                    types.AddRange(GetSubclassesOfGenericType(assemblyTypes, typeof(FractalType <>)));
                }
            }

            foreach (Type t in types)
            {
                PropertyInfo          propertyInfo = t.GetProperty("instance", s_bindingFlags);
                MethodInfo            methodInfo   = propertyInfo.GetGetMethod();
                IFractalType          instance     = (IFractalType)methodInfo.Invoke(null, null);
                FractalTypeDescriptor desc         = instance.GetDescription();

                if (string.IsNullOrEmpty(desc.name))
                {
                    Debug.LogError("FractalType name cannot be null or empty! Skipping fractal type: " + desc.name);
                    continue;
                }

                instances.Add(instance);
                names.Add(desc.name);
            }

            s_fractalTypes = instances.ToArray();
            s_fractalNames = names.ToArray();
        }
        public GeneratedShaderInfo(IFractalType fractalType, INoiseType noiseType)
        {
            this.fractalDesc = fractalType.GetDescription();
            this.noiseDesc   = noiseType.GetDescription();

            this.noiseIncludeStr = string.Format("#include \"{0}\"", noiseDesc.sourcePath);

            if (!string.IsNullOrEmpty(fractalDesc.name))
            {
                this.variantName = string.Format("{0}{1}", fractalDesc.name, noiseDesc.name);
            }
            else
            {
                this.variantName = noiseDesc.name;
            }

            // set the path of the generated file. this will be used when writing the file
            // to disk and when adding the include in any generated shaders that use this
            // fractal and noise type variant
            this.generatedIncludePath = string.Format("{0}/{1}/{2}.hlsl", noiseDesc.outputDir,
                                                      fractalDesc.name,
                                                      noiseDesc.name);
            this.outputDir = string.Format("{0}/{1}", noiseDesc.outputDir, fractalDesc.name);

            fractalStructName = string.Format("{0}FractalInput", fractalDesc.name);
            noiseStructName   = string.Format("{0}NoiseInput", noiseDesc.name);
            numFractalInputs  = fractalDesc.inputStructDefinition == null ? 0 : fractalDesc.inputStructDefinition.Count;
            numNoiseInputs    = noiseDesc.inputStructDefinition == null ? 0 : noiseDesc.inputStructDefinition.Count;
            fractalParamStr   = null;
            noiseParamStr     = null;
            functionInputStr  = "";

            // construct include paths string
            additionalIncludePaths = "\n";

            for (int i = 0; i < fractalDesc.additionalIncludePaths.Count; ++i)
            {
                additionalIncludePaths += $"#include \"{ fractalDesc.additionalIncludePaths[ i ] }\"\n";
            }

            additionalIncludePaths += "\n";

            // generate the string for the fractal type structure as it would appear as a parameter
            // in an HLSL function declaration
            if (numFractalInputs > 0)
            {
                fractalParamStr = string.Format("{0} {1}", fractalStructName, "fractalInput");
            }

            // generate the string for the noise type structure as it would appear as a parameter
            // in an HLSL function declaration
            if (numNoiseInputs > 0)
            {
                noiseParamStr = string.Format("{0} {1}", noiseStructName, "noiseInput");
            }

            // generate the argument string for an HLSL function declaration that would be
            // using this combination of noise and fractal type structure definitions
            functionParamStr = "";

            if (fractalParamStr != null)
            {
                functionParamStr += fractalParamStr;
                functionInputStr += "fractalInput";
            }

            if (fractalParamStr != null && noiseParamStr != null)
            {
                functionParamStr += ", ";
                functionInputStr += ", ";
            }

            if (noiseParamStr != null)
            {
                functionParamStr += noiseParamStr;
                functionInputStr += "noiseInput";
            }

            fractalStructDef = "";

            if (numFractalInputs > 0)
            {
                fractalStructDef = NoiseLib.BuildStructString(fractalStructName, fractalDesc.inputStructDefinition);

                string getDefaultFuncStr = NoiseLib.GetDefaultFunctionString(fractalStructName, fractalDesc.inputStructDefinition);
                fractalStructDef += $"\n\n{ getDefaultFuncStr }\n\n";
            }

            noiseStructDef = "";

            if (numNoiseInputs > 0)
            {
                noiseStructDef = NoiseLib.BuildStructString(noiseStructName, noiseDesc.inputStructDefinition);
            }

            // get input str construction
            getInputsStr       = "";
            getFractalInputStr = NoiseLib.GetInputFunctionCallString(fractalStructName);
            getNoiseInputStr   = NoiseLib.GetInputFunctionCallString(fractalStructName);

            if (numFractalInputs > 0)
            {
                getInputsStr += getFractalInputStr;
            }

            if (numFractalInputs > 0 && numNoiseInputs > 0)
            {
                getInputsStr += ", ";
            }

            if (numNoiseInputs > 0)
            {
                getInputsStr += getNoiseInputStr;
            }

            // get default input str construction
            getDefaultInputsStr       = "";
            getDefaultFractalInputStr = NoiseLib.GetDefaultInputFunctionCallString(fractalStructName);
            getDefaultNoiseInputStr   = NoiseLib.GetDefaultInputFunctionCallString(noiseStructName);

            if (numFractalInputs > 0)
            {
                getDefaultInputsStr += getDefaultFractalInputStr;
            }

            if (numFractalInputs > 0 && numNoiseInputs > 0)
            {
                getDefaultInputsStr += ", ";
            }

            if (numNoiseInputs > 0)
            {
                getDefaultInputsStr += getDefaultNoiseInputStr;
            }

            fractalPropertyDefStr = "";

            if (fractalDesc.inputStructDefinition != null &&
                fractalDesc.inputStructDefinition.Count > 0)
            {
                fractalPropertyDefStr  = NoiseLib.GetPropertyDefinitionStr(fractalDesc.name, fractalDesc.inputStructDefinition);
                fractalPropertyDefStr += "\n" + NoiseLib.GetPropertyFunctionStr(fractalStructName, fractalDesc.name, fractalDesc.inputStructDefinition);
            }
        }
Example #5
0
        /// <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();
        }