private void WriteHashTable(BinaryWriter Writer, List <string> Elems) { Elems = Elems.Where(x => x != null).Distinct().ToList(); Writer.Write((uint)Elems.Count); foreach (string Elem in Elems) { GFNV1 FNV = new GFNV1(); byte[] Buffer = Encoding.ASCII.GetBytes(Elem); Array.Resize(ref Buffer, 0x40); foreach (byte b in Buffer) { if (b == 0) { break; } FNV.Hash(b); } Writer.Write(FNV.HashCode); Writer.Write(Buffer); } }
public GFHashName(string Name) { GFNV1 FNV = new GFNV1(); FNV.Hash(Name); Hash = FNV.HashCode; this.Name = Name; }
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) { long StartPosition = Writer.BaseStream.Position; new GFSection(MagicStr).Write(Writer); GFNV1 FNV = new GFNV1(); FNV.Hash(Name); Writer.Write(FNV.HashCode); Writer.WritePaddedString(Name, 0x40); Writer.Write(0u); Writer.Write(BBoxMinVector); Writer.Write(BBoxMaxVector); Writer.Write((uint)SubMeshes.Count); Writer.Write(BoneIndicesPerVertex); Writer.Write(0xfffffffffffffffful); Writer.Write(0xfffffffffffffffful); for (int Index = 0; Index < SubMeshes.Count; Index++) { GFSubMesh SM = SubMeshes[Index]; PICACommandWriter CmdWriter; /* Enable commands */ CmdWriter = new PICACommandWriter(); ulong BufferFormats = 0; ulong BufferAttributes = 0; ulong BufferPermutation = 0; int AttributesTotal = 0; //Normal Attributes for (int Attr = 0; Attr < SM.Attributes.Count; Attr++) { PICAAttribute Attrib = SM.Attributes[Attr]; int Shift = AttributesTotal++ *4; ulong AttribFmt; AttribFmt = (ulong)Attrib.Format; AttribFmt |= (ulong)((Attrib.Elements - 1) & 3) << 2; BufferFormats |= AttribFmt << Shift; BufferPermutation |= (ulong)Attrib.Name << Shift; BufferAttributes |= (ulong)Attr << Shift; } BufferAttributes |= (ulong)(SM.VertexStride & 0xff) << 48; BufferAttributes |= (ulong)SM.Attributes.Count << 60; //Fixed Attributes foreach (PICAFixedAttribute Attrib in SM.FixedAttributes) { BufferFormats |= 1ul << (48 + AttributesTotal); BufferPermutation |= (ulong)Attrib.Name << AttributesTotal++ *4; } BufferFormats |= (ulong)(AttributesTotal - 1) << 60; CmdWriter.SetCommand(PICARegister.GPUREG_VSH_INPUTBUFFER_CONFIG, 0xa0000000u | (uint)(AttributesTotal - 1), 0xb); CmdWriter.SetCommand(PICARegister.GPUREG_VSH_NUM_ATTR, (uint)(AttributesTotal - 1), 1); CmdWriter.SetCommand(PICARegister.GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW, (uint)(BufferPermutation >> 0)); CmdWriter.SetCommand(PICARegister.GPUREG_VSH_ATTRIBUTES_PERMUTATION_HIGH, (uint)(BufferPermutation >> 32)); CmdWriter.SetCommand(PICARegister.GPUREG_ATTRIBBUFFERS_LOC, true, 0x03000000u, //Base Address (Place holder) (uint)(BufferFormats >> 0), (uint)(BufferFormats >> 32), 0x99999999u, //Attributes Buffer Address (Place holder) (uint)(BufferAttributes >> 0), (uint)(BufferAttributes >> 32)); for (int Attr = 0; Attr < SM.FixedAttributes.Count; Attr++) { PICAFixedAttribute Attrib = SM.FixedAttributes[Attr]; float Scale = Attrib.Name == PICAAttributeName.Color || Attrib.Name == PICAAttributeName.BoneWeight ? GFMesh.Scales[1] : 1; PICAFixedAttribute ScaledAttribute = new PICAFixedAttribute() { Name = Attrib.Name, Value = new PICAVectorFloat24(Attrib.Value.X, Attrib.Value.Y, Attrib.Value.Z, Attrib.Value.W) / Scale }; CmdWriter.SetCommand(PICARegister.GPUREG_FIXEDATTRIB_INDEX, true, (uint)(SM.Attributes.Count + Attr), ScaledAttribute.Value.Word0, ScaledAttribute.Value.Word1, ScaledAttribute.Value.Word2); } CmdWriter.WriteEnd(); WriteCmdsBuff(Writer, CmdWriter.GetBuffer(), Index * 3); /* Disable commands */ CmdWriter = new PICACommandWriter(); //Assuming that the Position isn't used as Fixed Attribute since this doesn't make sense. CmdWriter.SetCommand(PICARegister.GPUREG_ATTRIBBUFFER0_OFFSET, true, 0, 0, 0); for (int Attr = 1; Attr < 12; Attr++) { CmdWriter.SetCommand(PICARegister.GPUREG_ATTRIBBUFFER0_CONFIG2 + Attr * 3, 0); if (SM.FixedAttributes?.Any(x => (int)x.Name == Attr) ?? false) { CmdWriter.SetCommand(PICARegister.GPUREG_FIXEDATTRIB_INDEX, true, (uint)Attr, 0, 0, 0); } } CmdWriter.WriteEnd(); WriteCmdsBuff(Writer, CmdWriter.GetBuffer(), Index * 3 + 1); /* Index commands */ CmdWriter = new PICACommandWriter(); uint IdxFmtAddr = SM.IsIdx8Bits ? 0x01999999u : 0x81999999u; CmdWriter.SetCommand(PICARegister.GPUREG_RESTART_PRIMITIVE, true); CmdWriter.SetCommand(PICARegister.GPUREG_INDEXBUFFER_CONFIG, IdxFmtAddr); CmdWriter.SetCommand(PICARegister.GPUREG_NUMVERTICES, (uint)SM.Indices.Length); CmdWriter.SetCommand(PICARegister.GPUREG_START_DRAW_FUNC0, false, 1); CmdWriter.SetCommand(PICARegister.GPUREG_DRAWELEMENTS, true); CmdWriter.SetCommand(PICARegister.GPUREG_START_DRAW_FUNC0, true, 1); CmdWriter.SetCommand(PICARegister.GPUREG_VTX_FUNC, true); CmdWriter.SetCommand(PICARegister.GPUREG_PRIMITIVE_CONFIG, (uint)SM.PrimitiveMode << 8, 8); CmdWriter.SetCommand(PICARegister.GPUREG_PRIMITIVE_CONFIG, (uint)SM.PrimitiveMode << 8, 8); CmdWriter.WriteEnd(); WriteCmdsBuff(Writer, CmdWriter.GetBuffer(), Index * 3 + 2); } foreach (GFSubMesh SM in SubMeshes) { FNV = new GFNV1(); FNV.Hash(SM.Name); Writer.Write(FNV.HashCode); Writer.Write(GetPaddedLen4(SM.Name.Length)); Writer.WritePaddedString(SM.Name, GetPaddedLen4(SM.Name.Length)); Writer.Write(SM.BoneIndicesCount); byte[] BoneIndices = new byte[0x1f]; SM.BoneIndices.CopyTo(BoneIndices, 0); Writer.Write(BoneIndices); int VerticesCount = 0; if (SM.VertexStride != 0) { VerticesCount = SM.RawBuffer.Length / SM.VertexStride; } int VtxBuffLen = SM.RawBuffer.Length; int IdxBuffLen = SM.Indices.Length * (SM.IsIdx8Bits ? 1 : 2); Writer.Write(VerticesCount); Writer.Write(SM.Indices.Length); Writer.Write(GetPaddedLen16(VtxBuffLen)); Writer.Write(GetPaddedLen16(IdxBuffLen)); } foreach (GFSubMesh SM in SubMeshes) { long Position = Writer.BaseStream.Position; Writer.Write(SM.RawBuffer); int VertexBufferPaddingLength = GetPaddedLen16(SM.RawBuffer.Length) - SM.RawBuffer.Length; Writer.Write(new byte[VertexBufferPaddingLength]); /*while (((Writer.BaseStream.Position - Position) & 3) != 0) * { * Writer.Write((byte)0); * }*/ Position = Writer.BaseStream.Position; foreach (ushort Idx in SM.Indices) { if (SM.IsIdx8Bits) { Writer.Write((byte)Idx); } else { Writer.Write(Idx); } } /*while (((Writer.BaseStream.Position - Position) & 0xf) != 0) * { * Writer.Write((byte)0); * }*/ int IndexBufferLength = SM.Indices.Length * (SM.IsIdx8Bits ? 1 : 2); int IndexBufferPaddingLength = GetPaddedLen16(IndexBufferLength) - IndexBufferLength; Writer.Write(new byte[IndexBufferPaddingLength]); } Writer.Align(0x10, 0); Writer.Write(0ul); Writer.Write(0ul); long EndPosition = Writer.BaseStream.Position; Writer.BaseStream.Seek(StartPosition + 8, SeekOrigin.Begin); Writer.Write((uint)(EndPosition - StartPosition - 0x10)); Writer.BaseStream.Seek(EndPosition, SeekOrigin.Begin); }