public static void DecompileShader(string InputFile, string OutputFile, string MetadataFile = null)
        {
            // Create a copy of the file since it will be trashed
            if (!InputFile.Equals(OutputFile))
            {
                File.Copy(InputFile, OutputFile, true);
            }

            var p = new System.Diagnostics.Process();

            p.StartInfo.WorkingDirectory       = "C:\\Users\\Administrator\\Desktop\\cmd_Decompiler-1.3.2\\";
            p.StartInfo.FileName               = "C:\\Users\\Administrator\\Desktop\\cmd_Decompiler-1.3.2\\cmd_Decompiler.exe";
            p.StartInfo.Arguments              = "-D " + OutputFile;
            p.StartInfo.RedirectStandardOutput = false;
            p.StartInfo.UseShellExecute        = false;
            p.StartInfo.CreateNoWindow         = true;
            p.Start();

            // Gather metadata while it's being decompiled
            ShaderMetadata         metadata  = null;
            ShaderVariableMetadata variables = null;

            if (!string.IsNullOrEmpty(MetadataFile))
            {
                metadata  = new ShaderMetadata(MetadataFile);
                variables = new ShaderVariableMetadata(MetadataFile);
            }

            p.WaitForExit();

            // Fix stupid naming quirk with 3dm (swap the files)
            string ext = Path.GetExtension(OutputFile);

            if (!ext.ToLower().Equals(".hlsl"))
            {
                string target = OutputFile.Replace(Path.GetExtension(OutputFile), ".hlsl");
                File.Delete(OutputFile);
                File.Move(target, OutputFile);
            }

            if (metadata != null)
            {
                // Rip out 3dmigoto's header - it ends right before the "void main()" line
                List <string> fileLines = System.IO.File.ReadAllLines(OutputFile).ToList();

                for (int i = 0; i < fileLines.Count; i++)
                {
                    if (fileLines[i].ToLower().Contains("void main"))
                    {
                        break;
                    }

                    fileLines.Remove(fileLines[i]);
                    i--;
                }

                // Now paste our header back into it
                List <string> replacedLines = new List <string>(metadata.GetTextData());

                // Regenerate samplers and texture slots
                foreach (Tuple <int, string> sampler in metadata.GetSamplers())
                {
                    ReplaceInAllLines(fileLines, $"s{sampler.Item1}_s", $"{sampler.Item2}");
                    ReplaceInAllLines(fileLines, $"t{sampler.Item1}.", $"Tex{sampler.Item2}.");

                    replacedLines.Add($"SamplerState {sampler.Item2} : register(s{sampler.Item1});");
                    replacedLines.Add($"Texture2D<float4> Tex{sampler.Item2} : register(t{sampler.Item1});");
                }

                // Regenerate constant buffer variable accesses (TODO: inefficient as hell)
                for (int i = 0; i < fileLines.Count; i++)
                {
                }

                // Add back HLSL instructions
                replacedLines.Add(Environment.NewLine);
                replacedLines.AddRange(fileLines);

                // Done. Dump it back to disk.
                File.WriteAllLines(OutputFile, replacedLines);
            }
        }
        public static bool ValidateShaderOfType(string Type, string HlslType, string OriginalFile, string SourcePath)
        {
            var metadata = new ShaderMetadata(OriginalFile.Replace(".bin", ".txt"));

            // Grab the technique along with each #define used
            var techniqueId = metadata.GetTechnique();
            var macros      = GetCompilationMacros(Type, HlslType, metadata.GetDefines().ToList());

            //Program.LogLine("Validating shader [Technique: {0:X8}]: {1}...", techniqueId, OriginalFile);

            // Read from disk, compile, then disassemble to text
            ShaderBytecode originalBytecode = null;
            ShaderBytecode newBytecode      = null;

            try
            {
                originalBytecode = RecompileShader3DMigoto(OriginalFile, HlslType).Strip(m_StripFlags);

                //originalBytecode = ShaderBytecode.FromFile(OriginalFile).Strip(m_StripFlags);
                newBytecode = CompileShaderOfType(SourcePath, HlslType, macros).Strip(m_StripFlags);
            }
            catch (InvalidProgramException e)
            {
                Program.Log($"{OriginalFile}\n{e.Message}");
                return(false);
            }

            string[] originalDisasm = originalBytecode.Disassemble(DisassemblyFlags.None).Split('\n');
            string[] newDisasm      = newBytecode.Disassemble(DisassemblyFlags.None).Split('\n');

            // Sometimes the newly generated output will be shorter than the original code. Add some padding
            // to prevent out-of-bounds array access.
            if (originalDisasm.Length > newDisasm.Length)
            {
                string[] newArray = new string[originalDisasm.Length];

                for (int i = 0; i < newArray.Length; i++)
                {
                    newArray[i] = "\n";
                }

                newDisasm.CopyTo(newArray, 0);
                newDisasm = newArray;
            }

            try
            {
                ValidateShaderHeader(originalDisasm, newDisasm);
                ValidateShaderCode(originalDisasm, newDisasm);
            }
            catch (Exception)
            {
                //Program.LogLine("Validation failed.");

                // Dump raw disassembly to file
                File.WriteAllLines($"{Program.ShaderDiffDirectory}\\{Type}-{techniqueId:X}-{HlslType}-old.txt", originalDisasm);
                File.WriteAllLines($"{Program.ShaderDiffDirectory}\\{Type}-{techniqueId:X}-{HlslType}-new.txt", newDisasm);

                //
                // Generate the "symbolic" diff by:
                //
                // - Replacing all temporary registers with rX.xxxx
                // - Sorting all lines
                // - Eliminating all empty lines
                //
                var tempRegisterExpr = new Regex(@"r\d\.[xXyYzZwW]{1,4}", RegexOptions.Compiled);

                for (int i = 0; i < originalDisasm.Length; i++)
                {
                    originalDisasm[i] = tempRegisterExpr.Replace(originalDisasm[i], "rX.xxxx");
                    newDisasm[i]      = tempRegisterExpr.Replace(newDisasm[i], "rX.xxxx");
                }

                File.WriteAllLines($"{Program.ShaderDiffDirectory}\\{Type}-{techniqueId:X}-{HlslType}-symbolic-old.txt", originalDisasm.Where(x => !string.IsNullOrWhiteSpace(x)).OrderBy(x => x));
                File.WriteAllLines($"{Program.ShaderDiffDirectory}\\{Type}-{techniqueId:X}-{HlslType}-symbolic-new.txt", newDisasm.Where(x => !string.IsNullOrWhiteSpace(x)).OrderBy(x => x));
                return(false);
            }

            return(true);
        }