Пример #1
0
        static public ShaderResult FromString(string effectSource, string filePath, Options options, IEffectCompilerOutput output)
        {
            var macros = new Dictionary <string, string>();

            macros.Add("MGFX", "1");

            options.Profile.AddMacros(macros);

            // If we're building shaders for debug set that flag too.
            if (options.Debug)
            {
                macros.Add("DEBUG", "1");
            }

            if (!string.IsNullOrEmpty(options.Defines))
            {
                var defines = options.Defines.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var define in defines)
                {
                    var name  = define;
                    var value = "1";
                    if (define.Contains("="))
                    {
                        var parts = define.Split('=');

                        if (parts.Length > 0)
                        {
                            name = parts[0].Trim();
                        }

                        if (parts.Length > 1)
                        {
                            value = parts[1].Trim();
                        }
                    }

                    macros.Add(name, value);
                }
            }

            // Use the D3DCompiler to pre-process the file resolving
            // all #includes and macros.... this even works for GLSL.
            string newFile;
            var    fullPath     = Path.GetFullPath(filePath);
            var    dependencies = new List <string>();

            newFile = Preprocessor.Preprocess(effectSource, fullPath, macros, dependencies, output);

            // Parse the resulting file for techniques and passes.
            var tree = new Parser(new Scanner()).Parse(newFile, fullPath);

            if (tree.Errors.Count > 0)
            {
                var errors = String.Empty;
                foreach (var error in tree.Errors)
                {
                    errors += string.Format("{0}({1},{2}) : {3}\r\n", error.File, error.Line, error.Column, error.Message);
                }

                throw new Exception(errors);
            }

            // Evaluate the results of the parse tree.
            var shaderInfo = tree.Eval() as ShaderInfo;

            // Remove the samplers and techniques so that the shader compiler
            // gets a clean file without any FX file syntax in it.
            var cleanFile = newFile;

            ParseTreeTools.WhitespaceNodes(TokenType.Technique_Declaration, tree.Nodes, ref cleanFile);
            ParseTreeTools.WhitespaceNodes(TokenType.Sampler_Declaration_States, tree.Nodes, ref cleanFile);

            // Setup the rest of the shader info.
            ShaderResult result = new ShaderResult();

            result.ShaderInfo   = shaderInfo;
            result.Dependencies = dependencies;
            result.FilePath     = fullPath;
            result.FileContent  = cleanFile;
            if (!string.IsNullOrEmpty(options.OutputFile))
            {
                result.OutputFilePath = Path.GetFullPath(options.OutputFile);
            }
            result.AdditionalOutputFiles = new List <string>();

            // Remove empty techniques.
            for (var i = 0; i < shaderInfo.Techniques.Count; i++)
            {
                var tech = shaderInfo.Techniques[i];
                if (tech.Passes.Count <= 0)
                {
                    shaderInfo.Techniques.RemoveAt(i);
                    i--;
                }
            }

            // We must have at least one technique.
            if (shaderInfo.Techniques.Count <= 0)
            {
                throw new Exception("The effect must contain at least one technique and pass!");
            }

            result.Profile = options.Profile;
            result.Debug   = options.Debug;

            return(result);
        }
Пример #2
0
        static public ShaderInfo FromString(string effectSource, string filePath, Options options, IEffectCompilerOutput output)
        {
            var macros = new Dictionary <string, string>();

            macros.Add("MGFX", "1");

            // Under the DX11 profile we pass a few more macros.
            if (options.Profile == ShaderProfile.DirectX_11)
            {
                macros.Add("HLSL", "1");
                macros.Add("SM4", "1");
            }
            else if (options.Profile == ShaderProfile.OpenGL)
            {
                macros.Add("GLSL", "1");
                macros.Add("OPENGL", "1");
            }
            else if (options.Profile == ShaderProfile.PlayStation4)
            {
                throw new NotSupportedException("PlayStation 4 support isn't available in this build.");
            }

            // If we're building shaders for debug set that flag too.
            if (options.Debug)
            {
                macros.Add("DEBUG", "1");
            }

            if (!string.IsNullOrEmpty(options.Defines))
            {
                var defines = options.Defines.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var define in defines)
                {
                    macros.Add(define, "1");
                }
            }

            // Use the D3DCompiler to pre-process the file resolving
            // all #includes and macros.... this even works for GLSL.
            string newFile;
            var    fullPath     = Path.GetFullPath(filePath);
            var    dependencies = new List <string>();

            newFile = Preprocessor.Preprocess(effectSource, fullPath, macros, dependencies, output);

            // Parse the resulting file for techniques and passes.
            var tree = new Parser(new Scanner()).Parse(newFile, fullPath);

            if (tree.Errors.Count > 0)
            {
                var errors = String.Empty;
                foreach (var error in tree.Errors)
                {
                    errors += string.Format("{0}({1},{2}) : {3}\r\n", error.File, error.Line, error.Column, error.Message);
                }

                throw new Exception(errors);
            }

            // Evaluate the results of the parse tree.
            var result = tree.Eval() as ShaderInfo;

            result.Dependencies = dependencies;
            result.FilePath     = fullPath;
            result.FileContent  = newFile;
            if (!string.IsNullOrEmpty(options.OutputFile))
            {
                result.OutputFilePath = Path.GetFullPath(options.OutputFile);
            }
            result.AdditionalOutputFiles = new List <string>();

            // Remove empty techniques.
            for (var i = 0; i < result.Techniques.Count; i++)
            {
                var tech = result.Techniques[i];
                if (tech.Passes.Count <= 0)
                {
                    result.Techniques.RemoveAt(i);
                    i--;
                }
            }

            // We must have at least one technique.
            if (result.Techniques.Count <= 0)
            {
                throw new Exception("The effect must contain at least one technique and pass!");
            }

            // Finally remove the techniques from the file.
            //
            // TODO: Do we really need to do this, or will the HLSL
            // compiler just ignore it as we compile shaders?
            //

            /*
             * var extra = 2;
             * var offset = 0;
             * foreach (var tech in result.Techniques)
             * {
             *      // Remove the technique from the file.
             *      newFile = newFile.Remove(tech.startPos + offset, tech.length + extra);
             *      offset -= tech.length + extra;
             *
             *      techniques.Add(tech);
             * }
             */

            result.Profile = options.Profile;
            result.Debug   = options.Debug;

            return(result);
        }