public GFTexture(BinaryReader Reader) { uint MagicNumber = Reader.ReadUInt32(); uint TextureCount = Reader.ReadUInt32(); GFSection TextureSection = new GFSection(Reader); uint TextureLength = Reader.ReadUInt32(); Reader.BaseStream.Seek(0xc, SeekOrigin.Current); //Padding? Always zero it seems Name = Reader.ReadPaddedString(0x40); Width = Reader.ReadUInt16(); Height = Reader.ReadUInt16(); Format = (GFTextureFormat)Reader.ReadUInt16(); MipmapSize = Reader.ReadUInt16(); Reader.BaseStream.Seek(0x10, SeekOrigin.Current); //Padding RawBuffer = Reader.ReadBytes((int)TextureLength); }
public GFModel(BinaryReader Reader, string ModelName) : this() { Name = ModelName; uint MagicNumber = Reader.ReadUInt32(); uint SectionsCount = Reader.ReadUInt32(); GFSection.SkipPadding(Reader.BaseStream); GFSection ModelSection = new GFSection(Reader); GFHashName[] ShaderNames = ReadHashTable(Reader); GFHashName[] TextureNames = ReadHashTable(Reader); GFHashName[] MaterialNames = ReadHashTable(Reader); GFHashName[] MeshNames = ReadHashTable(Reader); BBoxMinVector = Reader.ReadVector4(); BBoxMaxVector = Reader.ReadVector4(); Transform = Reader.ReadMatrix4x4(); //TODO: Investigate what is this (maybe Tile permissions?) uint UnknownDataLength = Reader.ReadUInt32(); uint UnknownDataOffset = Reader.ReadUInt32(); ulong Padding = Reader.ReadUInt64(); Reader.BaseStream.Seek(UnknownDataOffset + UnknownDataLength, SeekOrigin.Current); int BonesCount = Reader.ReadInt32(); Reader.BaseStream.Seek(0xc, SeekOrigin.Current); for (int Index = 0; Index < BonesCount; Index++) { Skeleton.Add(new GFBone(Reader)); } GFSection.SkipPadding(Reader.BaseStream); int LUTsCount = Reader.ReadInt32(); int LUTLength = Reader.ReadInt32(); GFSection.SkipPadding(Reader.BaseStream); for (int Index = 0; Index < LUTsCount; Index++) { LUTs.Add(new GFLUT(Reader, LUTLength)); } for (int Index = 0; Index < MaterialNames.Length; Index++) { Materials.Add(new GFMaterial(Reader)); } for (int Index = 0; Index < MeshNames.Length; Index++) { Meshes.Add(new GFMesh(Reader)); } foreach (GFLUT LUT in LUTs) { foreach (GFHashName HN in TextureNames) { GFNV1 FNV = new GFNV1(); FNV.Hash(HN.Name); if (LUT.HashId == FNV.HashCode) { LUT.Name = HN.Name; break; } } } }
public void Write(BinaryWriter Writer) { uint SectionsCount = (uint)(Materials.Count + Meshes.Count + 1); Writer.Write(MagicNum); Writer.Write(SectionsCount); GFSection.SkipPadding(Writer.BaseStream); long StartPosition = Writer.BaseStream.Position; new GFSection(MagicStr).Write(Writer); List <string> ShaderNames = new List <string>(); List <string> TextureNames = new List <string>(); List <string> MaterialNames = new List <string>(); List <string> MeshNames = new List <string>(); foreach (GFMaterial Mat in Materials) { ShaderNames.Add(Mat.ShaderName); TextureNames.Add(Mat.TextureCoords[0].Name); TextureNames.Add(Mat.TextureCoords[1].Name); TextureNames.Add(Mat.TextureCoords[2].Name); TextureNames.Add(GetLUTName(Mat.LUT0HashId)); TextureNames.Add(GetLUTName(Mat.LUT1HashId)); TextureNames.Add(GetLUTName(Mat.LUT2HashId)); MaterialNames.Add(Mat.MaterialName); } foreach (GFMesh Mesh in Meshes) { MeshNames.Add(Mesh.Name); } WriteHashTable(Writer, ShaderNames); WriteHashTable(Writer, TextureNames); WriteHashTable(Writer, MaterialNames); WriteHashTable(Writer, MeshNames); Writer.Write(BBoxMinVector); Writer.Write(BBoxMaxVector); Writer.Write(Transform); //TODO: Figure out what is this. Writer.Write(0); Writer.Write(0x10); Writer.Write(0ul); Writer.Write(0ul); Writer.Write(0ul); Writer.Write((uint)Skeleton.Count); Writer.BaseStream.Seek(0xc, SeekOrigin.Current); foreach (GFBone Bone in Skeleton) { Bone.Write(Writer); } GFSection.SkipPadding(Writer.BaseStream); Writer.Write(LUTs.Count); Writer.Write(0x420); GFSection.SkipPadding(Writer.BaseStream); foreach (GFLUT LUT in LUTs) { LUT.Write(Writer); } long EndPosition = Writer.BaseStream.Position; Writer.BaseStream.Seek(StartPosition + 8, SeekOrigin.Begin); Writer.Write((uint)(EndPosition - StartPosition - 0x10)); Writer.BaseStream.Seek(EndPosition, SeekOrigin.Begin); foreach (GFMaterial Mat in Materials) { Mat.Write(Writer); } foreach (GFMesh Mesh in Meshes) { Mesh.Write(Writer); } }
public GFMesh(BinaryReader Reader) : this() { GFSection MeshSection = new GFSection(Reader); long Position = Reader.BaseStream.Position; uint NameHash = Reader.ReadUInt32(); string NameStr = Reader.ReadPaddedString(0x40); Name = NameStr; Reader.ReadUInt32(); BBoxMinVector = Reader.ReadVector4(); //Is it right? seems to be 0, 0, 0, 1 BBoxMaxVector = Reader.ReadVector4(); //Is it right? seems to be 0, 0, 0, 1 uint SubMeshesCount = Reader.ReadUInt32(); BoneIndicesPerVertex = Reader.ReadInt32(); Reader.BaseStream.Seek(0x10, SeekOrigin.Current); //Padding List <uint[]> CmdList = new List <uint[]>(); uint CommandsLength; uint CommandIndex; uint CommandsCount; uint Padding; do { CommandsLength = Reader.ReadUInt32(); CommandIndex = Reader.ReadUInt32(); CommandsCount = Reader.ReadUInt32(); Padding = Reader.ReadUInt32(); uint[] Commands = new uint[CommandsLength >> 2]; for (int Index = 0; Index < Commands.Length; Index++) { Commands[Index] = Reader.ReadUInt32(); } CmdList.Add(Commands); }while (CommandIndex < CommandsCount - 1); SubMeshSize[] SMSizes = new SubMeshSize[SubMeshesCount]; //Add SubMesh with Hash, Name and Bone Indices. //The rest is added latter (because the data is split inside the file). for (int MeshIndex = 0; MeshIndex < SubMeshesCount; MeshIndex++) { GFSubMesh SM = new GFSubMesh(); uint SMNameHash = Reader.ReadUInt32(); SM.Name = Reader.ReadIntLengthString(); SM.BoneIndicesCount = Reader.ReadByte(); for (int Bone = 0; Bone < 0x1f; Bone++) { SM.BoneIndices[Bone] = Reader.ReadByte(); } SMSizes[MeshIndex] = new SubMeshSize() { VerticesCount = Reader.ReadInt32(), IndicesCount = Reader.ReadInt32(), VerticesLength = Reader.ReadInt32(), IndicesLength = Reader.ReadInt32() }; SubMeshes.Add(SM); } for (int MeshIndex = 0; MeshIndex < SubMeshesCount; MeshIndex++) { GFSubMesh SM = SubMeshes[MeshIndex]; uint[] EnableCommands = CmdList[MeshIndex * 3 + 0]; uint[] DisableCommands = CmdList[MeshIndex * 3 + 1]; uint[] IndexCommands = CmdList[MeshIndex * 3 + 2]; PICACommandReader CmdReader; CmdReader = new PICACommandReader(EnableCommands); PICAVectorFloat24[] Fixed = new PICAVectorFloat24[12]; ulong BufferFormats = 0; ulong BufferAttributes = 0; ulong BufferPermutation = 0; int AttributesCount = 0; int AttributesTotal = 0; int FixedIndex = 0; while (CmdReader.HasCommand) { PICACommand Cmd = CmdReader.GetCommand(); uint Param = Cmd.Parameters[0]; switch (Cmd.Register) { case PICARegister.GPUREG_ATTRIBBUFFERS_FORMAT_LOW: BufferFormats |= (ulong)Param << 0; break; case PICARegister.GPUREG_ATTRIBBUFFERS_FORMAT_HIGH: BufferFormats |= (ulong)Param << 32; break; case PICARegister.GPUREG_ATTRIBBUFFER0_CONFIG1: BufferAttributes |= Param; break; case PICARegister.GPUREG_ATTRIBBUFFER0_CONFIG2: BufferAttributes |= (ulong)(Param & 0xffff) << 32; SM.VertexStride = (byte)(Param >> 16); AttributesCount = (int)(Param >> 28); break; case PICARegister.GPUREG_FIXEDATTRIB_INDEX: FixedIndex = (int)Param; break; case PICARegister.GPUREG_FIXEDATTRIB_DATA0: Fixed[FixedIndex].Word0 = Param; break; case PICARegister.GPUREG_FIXEDATTRIB_DATA1: Fixed[FixedIndex].Word1 = Param; break; case PICARegister.GPUREG_FIXEDATTRIB_DATA2: Fixed[FixedIndex].Word2 = Param; break; case PICARegister.GPUREG_VSH_NUM_ATTR: AttributesTotal = (int)(Param + 1); break; case PICARegister.GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW: BufferPermutation |= (ulong)Param << 0; break; case PICARegister.GPUREG_VSH_ATTRIBUTES_PERMUTATION_HIGH: BufferPermutation |= (ulong)Param << 32; break; } } for (int Index = 0; Index < AttributesTotal; Index++) { if (((BufferFormats >> (48 + Index)) & 1) != 0) { PICAAttributeName Name = (PICAAttributeName)((BufferPermutation >> Index * 4) & 0xf); float Scale = Name == PICAAttributeName.Color || Name == PICAAttributeName.BoneWeight ? Scales[1] : 1; SM.FixedAttributes.Add(new PICAFixedAttribute() { Name = Name, Value = Fixed[Index] * Scale }); } else { int PermutationIdx = (int)((BufferAttributes >> Index * 4) & 0xf); int AttributeName = (int)((BufferPermutation >> PermutationIdx * 4) & 0xf); int AttributeFmt = (int)((BufferFormats >> PermutationIdx * 4) & 0xf); PICAAttribute Attrib = new PICAAttribute() { Name = (PICAAttributeName)AttributeName, Format = (PICAAttributeFormat)(AttributeFmt & 3), Elements = (AttributeFmt >> 2) + 1, Scale = Scales[AttributeFmt & 3] }; if (Attrib.Name == PICAAttributeName.BoneIndex) { Attrib.Scale = 1; } SM.Attributes.Add(Attrib); } } CmdReader = new PICACommandReader(IndexCommands); uint BufferAddress = 0; uint BufferCount = 0; while (CmdReader.HasCommand) { PICACommand Cmd = CmdReader.GetCommand(); uint Param = Cmd.Parameters[0]; switch (Cmd.Register) { case PICARegister.GPUREG_INDEXBUFFER_CONFIG: BufferAddress = Param; break; case PICARegister.GPUREG_NUMVERTICES: BufferCount = Param; break; case PICARegister.GPUREG_PRIMITIVE_CONFIG: SM.PrimitiveMode = (PICAPrimitiveMode)(Param >> 8); break; } } SM.RawBuffer = Reader.ReadBytes(SMSizes[MeshIndex].VerticesLength); SM.Indices = new ushort[BufferCount]; long IndexAddress = Reader.BaseStream.Position; for (int Index = 0; Index < BufferCount; Index++) { if ((BufferAddress >> 31) != 0) { SM.Indices[Index] = Reader.ReadUInt16(); } else { SM.Indices[Index] = Reader.ReadByte(); } } Reader.BaseStream.Seek(IndexAddress + SMSizes[MeshIndex].IndicesLength, SeekOrigin.Begin); } Reader.BaseStream.Seek(Position + MeshSection.Length, SeekOrigin.Begin); }
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(); }