protected void GenOutputs(StringBuilder Output, ShaderOutputReg[] Regs, string Prefix = "") { for (int i = 0; i < Regs.Length; i++) { ShaderOutputReg Reg = Regs[i]; if (Reg.Mask != 0) { if (Reg.Name == ShaderOutputRegName.TexCoord0W) { Reg.Name = ShaderOutputRegName.TexCoord0; } OutputNames[i] = $"{Prefix}{Reg.Name}"; //Shaders can have more than one generic output. //In this case we need to add a suffix to avoid name clashes. if (Reg.Name == ShaderOutputRegName.Generic) { OutputNames[i] += "_" + i; } Output.AppendLine($"out vec4 {OutputNames[i]};"); } } }
public GFShader(BinaryReader Reader) : this() { uint MagicNumber = Reader.ReadUInt32(); uint ShaderCount = Reader.ReadUInt32(); GFSection.SkipPadding(Reader.BaseStream); GFSection ShaderSection = new GFSection(Reader); Name = Reader.ReadPaddedString(0x40); uint Hash = Reader.ReadUInt32(); uint Count = Reader.ReadUInt32(); GFSection.SkipPadding(Reader.BaseStream); uint CommandsLength = Reader.ReadUInt32(); uint CommandsCount = Reader.ReadUInt32(); uint CommandsHash = Reader.ReadUInt32(); uint Padding = Reader.ReadUInt32(); string FileName = Reader.ReadPaddedString(0x40); uint[] Commands = new uint[CommandsLength >> 2]; for (int Index = 0; Index < Commands.Length; Index++) { Commands[Index] = Reader.ReadUInt32(); } uint[] OutMap = new uint[7]; List <uint> ShaderExecutable = new List <uint>(); List <ulong> ShaderSwizzles = new List <ulong>(); PICACommandReader CmdReader = new PICACommandReader(Commands); while (CmdReader.HasCommand) { PICACommand Cmd = CmdReader.GetCommand(); uint Param = Cmd.Parameters[0]; int Stage = ((int)Cmd.Register >> 3) & 7; if (Stage >= 6) { Stage -= 2; } switch (Cmd.Register) { /* Shader */ case PICARegister.GPUREG_SH_OUTMAP_O0: OutMap[0] = Param; break; case PICARegister.GPUREG_SH_OUTMAP_O1: OutMap[1] = Param; break; case PICARegister.GPUREG_SH_OUTMAP_O2: OutMap[2] = Param; break; case PICARegister.GPUREG_SH_OUTMAP_O3: OutMap[3] = Param; break; case PICARegister.GPUREG_SH_OUTMAP_O4: OutMap[4] = Param; break; case PICARegister.GPUREG_SH_OUTMAP_O5: OutMap[5] = Param; break; case PICARegister.GPUREG_SH_OUTMAP_O6: OutMap[6] = Param; break; /* Fragment Shader */ case PICARegister.GPUREG_TEXENV0_SOURCE: case PICARegister.GPUREG_TEXENV1_SOURCE: case PICARegister.GPUREG_TEXENV2_SOURCE: case PICARegister.GPUREG_TEXENV3_SOURCE: case PICARegister.GPUREG_TEXENV4_SOURCE: case PICARegister.GPUREG_TEXENV5_SOURCE: TexEnvStages[Stage].Source = new PICATexEnvSource(Param); break; case PICARegister.GPUREG_TEXENV0_OPERAND: case PICARegister.GPUREG_TEXENV1_OPERAND: case PICARegister.GPUREG_TEXENV2_OPERAND: case PICARegister.GPUREG_TEXENV3_OPERAND: case PICARegister.GPUREG_TEXENV4_OPERAND: case PICARegister.GPUREG_TEXENV5_OPERAND: TexEnvStages[Stage].Operand = new PICATexEnvOperand(Param); break; case PICARegister.GPUREG_TEXENV0_COMBINER: case PICARegister.GPUREG_TEXENV1_COMBINER: case PICARegister.GPUREG_TEXENV2_COMBINER: case PICARegister.GPUREG_TEXENV3_COMBINER: case PICARegister.GPUREG_TEXENV4_COMBINER: case PICARegister.GPUREG_TEXENV5_COMBINER: TexEnvStages[Stage].Combiner = new PICATexEnvCombiner(Param); break; case PICARegister.GPUREG_TEXENV0_COLOR: case PICARegister.GPUREG_TEXENV1_COLOR: case PICARegister.GPUREG_TEXENV2_COLOR: case PICARegister.GPUREG_TEXENV3_COLOR: case PICARegister.GPUREG_TEXENV4_COLOR: case PICARegister.GPUREG_TEXENV5_COLOR: TexEnvStages[Stage].Color = new RGBA(Param); break; case PICARegister.GPUREG_TEXENV0_SCALE: case PICARegister.GPUREG_TEXENV1_SCALE: case PICARegister.GPUREG_TEXENV2_SCALE: case PICARegister.GPUREG_TEXENV3_SCALE: case PICARegister.GPUREG_TEXENV4_SCALE: case PICARegister.GPUREG_TEXENV5_SCALE: TexEnvStages[Stage].Scale = new PICATexEnvScale(Param); break; case PICARegister.GPUREG_TEXENV_UPDATE_BUFFER: PICATexEnvStage.SetUpdateBuffer(TexEnvStages, Param); break; case PICARegister.GPUREG_TEXENV_BUFFER_COLOR: TexEnvBufferColor = new RGBA(Param); break; /* Geometry Shader */ case PICARegister.GPUREG_GSH_ENTRYPOINT: if (GeoShader == null) { GeoShader = new ShaderProgram(); } GeoShader.MainOffset = Param & 0xffff; break; /* Vertex Shader */ case PICARegister.GPUREG_VSH_CODETRANSFER_DATA0: case PICARegister.GPUREG_VSH_CODETRANSFER_DATA1: case PICARegister.GPUREG_VSH_CODETRANSFER_DATA2: case PICARegister.GPUREG_VSH_CODETRANSFER_DATA3: case PICARegister.GPUREG_VSH_CODETRANSFER_DATA4: case PICARegister.GPUREG_VSH_CODETRANSFER_DATA5: case PICARegister.GPUREG_VSH_CODETRANSFER_DATA6: case PICARegister.GPUREG_VSH_CODETRANSFER_DATA7: ShaderExecutable.AddRange(Cmd.Parameters); break; case PICARegister.GPUREG_VSH_OPDESCS_DATA0: case PICARegister.GPUREG_VSH_OPDESCS_DATA1: case PICARegister.GPUREG_VSH_OPDESCS_DATA2: case PICARegister.GPUREG_VSH_OPDESCS_DATA3: case PICARegister.GPUREG_VSH_OPDESCS_DATA4: case PICARegister.GPUREG_VSH_OPDESCS_DATA5: case PICARegister.GPUREG_VSH_OPDESCS_DATA6: case PICARegister.GPUREG_VSH_OPDESCS_DATA7: for (int i = 0; i < Cmd.Parameters.Length; i++) { ShaderSwizzles.Add(Cmd.Parameters[i]); } break; case PICARegister.GPUREG_VSH_ENTRYPOINT: if (VtxShader == null) { VtxShader = new ShaderProgram(); } VtxShader.MainOffset = Param & 0xffff; break; } } Executable = ShaderExecutable.ToArray(); Swizzles = ShaderSwizzles.ToArray(); for (int i = 0; i < OutMap.Length; i++) { if (OutMap[i] == 0) { continue; } ShaderOutputReg Reg = new ShaderOutputReg(); for (int j = 0; j < 4; j++) { uint Value = (OutMap[i] >> j * 8) & 0x1f; if (Value != 0x1f) { Reg.Mask |= 1u << j; if (Value < 0x4) { Reg.Name = ShaderOutputRegName.Position; } else if (Value < 0x8) { Reg.Name = ShaderOutputRegName.QuatNormal; } else if (Value < 0xc) { Reg.Name = ShaderOutputRegName.Color; } else if (Value < 0xe) { Reg.Name = ShaderOutputRegName.TexCoord0; } else if (Value < 0x10) { Reg.Name = ShaderOutputRegName.TexCoord1; } else if (Value < 0x11) { Reg.Name = ShaderOutputRegName.TexCoord0W; } else if (Value < 0x12) { Reg.Name = ShaderOutputRegName.Generic; } else if (Value < 0x16) { Reg.Name = ShaderOutputRegName.View; } else if (Value < 0x18) { Reg.Name = ShaderOutputRegName.TexCoord2; } else { Reg.Name = ShaderOutputRegName.Generic; } } } if (VtxShader != null) { VtxShader.OutputRegs[i] = Reg; } if (GeoShader != null) { GeoShader.OutputRegs[i] = Reg; } } HashSet <uint> Dsts = new HashSet <uint>(); uint LblId = 0; for (uint i = 0; i < Executable.Length; i++) { ShaderOpCode OpCode = (ShaderOpCode)(Executable[i] >> 26); if (OpCode == ShaderOpCode.Call || OpCode == ShaderOpCode.CallC || OpCode == ShaderOpCode.CallU || OpCode == ShaderOpCode.JmpC || OpCode == ShaderOpCode.JmpU) { uint Dst = (Executable[i] >> 10) & 0xfff; if (!Dsts.Contains(Dst)) { Dsts.Add(Dst); string Name = "label_" + Dst.ToString("x4"); ShaderLabel Label = new ShaderLabel() { Id = LblId++, Offset = Dst, Length = 0, Name = Name }; if (VtxShader != null) { VtxShader.Labels.Add(Label); } if (GeoShader != null) { GeoShader.Labels.Add(Label); } } } } MakeArray(VtxShader?.Vec4Uniforms, "v_c"); MakeArray(GeoShader?.Vec4Uniforms, "g_c"); FindProgramEnd(VtxShader, Executable); FindProgramEnd(GeoShader, Executable); VtxShaderUniforms = CmdReader.GetAllVertexShaderUniforms(); GeoShaderUniforms = CmdReader.GetAllGeometryShaderUniforms(); }