예제 #1
0
        public static string Decompile(byte[] shader_data)
        {
            var instructions = Disassembler.Disassemble(shader_data);

            Constants  = "";
            Parameters = "";
            Inputs     = "";
            Outputs    = "";
            Functions  = "";
            Main       = "";

            // Constants that are commonly used by instructions.
            Constants +=
                "#define MAX_FLOAT 3.402823466e+38F		\n"+
                "#define INFINITY (1 / 0)				\n"+
                "#define NaN (0 / 0)					\n"+
                "#define ZERO 0							\n";

            // declaring these as arrays lets us not even worry about parameters on the HLSL side
            // and they will point to the correct register index that the game stores values in.
            // Example: if we disassemble an instruction 'adds r0, c19.xy', we can replace that in HLSL with
            // r0 = c[19].x + c[19].y - VERY SIMPLE!
            Parameters +=
                "float4 c[224];\n" +
                "int i[16];	   \n" +
                "bool b[16];   \n" +
                "sampler s[16];\n";

            // Much more work is needed here.
            // TODO: handle all ControlFlowInstruction types.
            // Distinguish between ALU and Fetch instructions.
            foreach (var instr in instructions)
            {
                foreach (var cf_instr in instr.cf_instrs)
                {
                    Main += $"{INDENT}// {cf_instr.opcode}\n";

                    // Handle CF instructions which execute ALU/Fetch instructions
                    if (cf_instr.Executes)
                    {
                        var executes = instructions.Skip((int)cf_instr.exec.address).Take((int)cf_instr.exec.count).ToArray();

                        for (var i = 0; i < executes.Length; i++)
                        {
                            var execute = executes[i];

                            // Use 'i' with bit operations on 'cf_instr.exec.serialize' to determine ALU/Fetch.
                            // TODO: work on fetch-type output.
                            if ((cf_instr.exec.serialize & (1 << (i * 2))) != 0)
                            {
                                Main += Fetch.Get(execute);
                            }
                            else
                            {
                                ALU.Get(execute);
                            }
                        }
                    }

                    if (cf_instr.EndsShader)
                    {
                        goto EndOfShader;
                    }
                }
            }
EndOfShader:

            string hlsl =
                "// Decompiled with Jabukufo's ucode Decompiler \n" +
                "\n" +
                " // Constants:								\n"+
                $"{Constants}								\n"+
                "\n" +
                " // Parameters:							\n"+
                $"{Parameters}								\n"+
                "\n" +
                " // Inputs:								\n"+
                "struct INPUT								\n"+
                "{											\n"+
                $"{Inputs}									\n"+
                "};											\n"+
                "\n" +
                " // Outputs:								\n"+
                "struct OUTPUT								\n"+
                "{											\n"+
                $"{Outputs}									\n"+
                "};											\n"+
                "\n" +
                " // Variables:								\n"+
                "bool   p0 = false; // predicate 'register'.\n" +
                "int    a0 = 0; // address 'register'.		\n"+
                "float4 aL = 0; // loop 'register'.			\n"+
                "float4 lc = 0; // loop count.				\n"+
                "float4 ps = 0; // previous scalar result,	\n"+
                "float4 pv = 0; // previous vector result.	\n"+
                "\n" +
                " // Functions:								\n"+
                $"{Functions}								\n"+
                "\n" +
                " // Main:									\n"+
                "OUTPUT main ( INPUT In )					\n"+
                "{											\n"+
                "	OUTPUT Out;								\n"+
                "											\n"+
                $"{Main}									\n"+
                "	return Out;								\n"+
                "}											";

            return(PostFixups.Apply(hlsl));
        }