void WriteInstruction(Instruction instruction) { switch (instruction.Opcode) { case Opcode.Abs: WriteLine("{0} = abs({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Add: WriteLine("{0} = {1} + {2};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Cmp: // TODO: should be per-component WriteLine("{0} = ({1} >= 0) ? {2} : {3};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.Def: var c = new Constant( instruction.GetParamRegisterNumber(0), instruction.GetParamSingle(1), instruction.GetParamSingle(2), instruction.GetParamSingle(3), instruction.GetParamSingle(4)); ConstantDefinitions.Add(c); break; case Opcode.DefI: var ci = new ConstantInt(instruction.GetParamRegisterNumber(0), instruction.Params[1], instruction.Params[2], instruction.Params[3], instruction.Params[4]); ConstantIntDefinitions.Add(ci); break; case Opcode.DP2Add: WriteLine("{0} = dot({1}, {2}) + {3};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.Dp3: WriteLine("{0} = dot({1}, {2});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Dp4: WriteLine("{0} = dot({1}, {2});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Else: indent = indent.Substring(0, indent.Length - 1); WriteLine("} else {"); indent += "\t"; break; case Opcode.Endif: indent = indent.Substring(0, indent.Length - 1); WriteLine("}"); break; case Opcode.Exp: WriteLine("{0} = exp2({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Frc: WriteLine("{0} = frac({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.If: WriteLine("if ({0}) {{", GetSourceName(instruction, 0)); indent += "\t"; break; case Opcode.IfC: if ((IfComparison)instruction.Modifier == IfComparison.GE && instruction.GetSourceModifier(0) == SourceModifier.AbsAndNegate && instruction.GetSourceModifier(1) == SourceModifier.Abs && instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0) == instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1)) { WriteLine("if ({0} == 0) {{", instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0)); } else if ((IfComparison)instruction.Modifier == IfComparison.LT && instruction.GetSourceModifier(0) == SourceModifier.AbsAndNegate && instruction.GetSourceModifier(1) == SourceModifier.Abs && instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0) == instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1)) { WriteLine("if ({0} != 0) {{", instruction.GetParamRegisterName(0) + instruction.GetSourceSwizzleName(0)); } else { string ifComparison; switch ((IfComparison)instruction.Modifier) { case IfComparison.GT: ifComparison = ">"; break; case IfComparison.EQ: ifComparison = "=="; break; case IfComparison.GE: ifComparison = ">="; break; case IfComparison.LE: ifComparison = "<="; break; case IfComparison.NE: ifComparison = "!="; break; case IfComparison.LT: ifComparison = "<"; break; default: throw new InvalidOperationException(); } WriteLine("if ({0} {2} {1}) {{", GetSourceName(instruction, 0), GetSourceName(instruction, 1), ifComparison); } indent += "\t"; break; case Opcode.Log: WriteLine("{0} = log2({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Lrp: WriteLine("{0} = lerp({2}, {3}, {1});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.Mad: WriteLine("{0} = {1} * {2} + {3};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2), GetSourceName(instruction, 3)); break; case Opcode.Max: WriteLine("{0} = max({1}, {2});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Min: WriteLine("{0} = min({1}, {2});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Mov: WriteLine("{0} = {1};", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.MovA: WriteLine("{0} = {1};", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Mul: WriteLine("{0} = {1} * {2};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Nrm: WriteLine("{0} = normalize({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Pow: WriteLine("{0} = pow({1}, {2});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Rcp: WriteLine("{0} = 1 / {1};", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Rsq: WriteLine("{0} = 1 / sqrt({1});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Sge: if (instruction.GetSourceModifier(1) == SourceModifier.AbsAndNegate && instruction.GetSourceModifier(2) == SourceModifier.Abs && instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1) == instruction.GetParamRegisterName(2) + instruction.GetSourceSwizzleName(2)) { WriteLine("{0} = ({1} == 0) ? 1 : 0;", GetDestinationName(instruction), instruction.GetParamRegisterName(1) + instruction.GetSourceSwizzleName(1)); } else { WriteLine("{0} = ({1} >= {2}) ? 1 : 0;", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); } break; case Opcode.Slt: WriteLine("{0} = ({1} < {2}) ? 1 : 0;", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.SinCos: WriteLine("sincos({1}, {0}, {0});", GetDestinationName(instruction), GetSourceName(instruction, 1)); break; case Opcode.Sub: WriteLine("{0} = {1} - {2};", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Tex: if ((shader.MajorVersion == 1 && shader.MinorVersion >= 4) || (shader.MajorVersion > 1)) { WriteLine("{0} = tex2D({2}, {1});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); } else { WriteLine("{0} = tex2D();", GetDestinationName(instruction)); } break; case Opcode.TexLDL: WriteLine("{0} = tex2Dlod({2}, {1});", GetDestinationName(instruction), GetSourceName(instruction, 1), GetSourceName(instruction, 2)); break; case Opcode.Comment: case Opcode.End: break; } }
string GetSourceConstantName(Instruction instruction, int srcIndex) { var registerType = instruction.GetParamRegisterType(srcIndex); int registerNumber = instruction.GetParamRegisterNumber(srcIndex); switch (registerType) { case RegisterType.ConstBool: //throw new NotImplementedException(); return(null); case RegisterType.ConstInt: { var constantInt = ConstantIntDefinitions.FirstOrDefault(x => x.RegisterIndex == registerNumber); if (constantInt == null) { return(null); } byte[] swizzle = instruction.GetSourceSwizzleComponents(srcIndex); uint[] constant = { constantInt[swizzle[0]], constantInt[swizzle[1]], constantInt[swizzle[2]], constantInt[swizzle[3]] }; switch (instruction.GetSourceModifier(srcIndex)) { case SourceModifier.None: break; case SourceModifier.Negate: throw new NotImplementedException(); /* * for (int i = 0; i < 4; i++) * { * constant[i] = -constant[i]; * }*/ break; default: throw new NotImplementedException(); } int destLength = instruction.GetDestinationMaskLength(); switch (destLength) { case 1: return(constant[0].ToString()); case 2: if (constant[0] == constant[1]) { return(constant[0].ToString()); } return($"int2({constant[0]}, {constant[1]})"); case 3: if (constant[0] == constant[1] && constant[0] == constant[2]) { return(constant[0].ToString()); } return($"int3({constant[0]}, {constant[1]}, {constant[2]})"); case 4: if (constant[0] == constant[1] && constant[0] == constant[2] && constant[0] == constant[3]) { return(constant[0].ToString()); } return($"int4({constant[0]}, {constant[1]}, {constant[2]}, {constant[3]})"); default: throw new InvalidOperationException(); } } case RegisterType.Const: case RegisterType.Const2: case RegisterType.Const3: case RegisterType.Const4: { var constantRegister = ConstantDefinitions.FirstOrDefault(x => x.RegisterIndex == registerNumber); if (constantRegister == null) { return(null); } byte[] swizzle = instruction.GetSourceSwizzleComponents(srcIndex); float[] constant = { constantRegister[swizzle[0]], constantRegister[swizzle[1]], constantRegister[swizzle[2]], constantRegister[swizzle[3]] }; switch (instruction.GetSourceModifier(srcIndex)) { case SourceModifier.None: break; case SourceModifier.Negate: for (int i = 0; i < 4; i++) { constant[i] = -constant[i]; } break; default: throw new NotImplementedException(); } int destLength; if (instruction.HasDestination) { destLength = instruction.GetDestinationMaskLength(); } else { if (instruction.Opcode == Opcode.If || instruction.Opcode == Opcode.IfC) { // TODO } destLength = 4; } switch (destLength) { case 1: return(constant[0].ToString(CultureInfo.InvariantCulture)); case 2: if (constant[0] == constant[1]) { return(constant[0].ToString(CultureInfo.InvariantCulture)); } return(string.Format("float2({0}, {1})", constant[0].ToString(CultureInfo.InvariantCulture), constant[1].ToString(CultureInfo.InvariantCulture))); case 3: if (constant[0] == constant[1] && constant[0] == constant[2]) { return(constant[0].ToString(CultureInfo.InvariantCulture)); } return(string.Format("float3({0}, {1}, {2})", constant[0].ToString(CultureInfo.InvariantCulture), constant[1].ToString(CultureInfo.InvariantCulture), constant[2].ToString(CultureInfo.InvariantCulture))); case 4: if (constant[0] == constant[1] && constant[0] == constant[2] && constant[0] == constant[3]) { return(constant[0].ToString(CultureInfo.InvariantCulture)); } return(string.Format("float4({0}, {1}, {2}, {3})", constant[0].ToString(CultureInfo.InvariantCulture), constant[1].ToString(CultureInfo.InvariantCulture), constant[2].ToString(CultureInfo.InvariantCulture), constant[3].ToString(CultureInfo.InvariantCulture))); default: throw new InvalidOperationException(); } } default: return(null); } }