protected override SolidMeshVertex GetVertex(BinaryReader reader, SolidObjectMaterial material, int stride) { MostWantedMaterial mwm = (MostWantedMaterial)material; SolidMeshVertex vertex = new SolidMeshVertex(); InternalEffectID id = (InternalEffectID)mwm.EffectId; switch (id) { case InternalEffectID.WorldNormalMap: case InternalEffectID.WorldReflectShader: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Normal = BinaryUtil.ReadVector3(reader); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadVector2(reader); reader.BaseStream.Position += 8; // TODO: What's this additional D3DDECLUSAGE_TEXCOORD element? vertex.Tangent = BinaryUtil.ReadVector3(reader); reader.BaseStream.Position += 4; // skip W component of tangent vector break; case InternalEffectID.skyshader: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Normal = BinaryUtil.ReadVector3(reader); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadVector2(reader); reader.BaseStream.Position += 8; // TODO: What's this additional D3DDECLUSAGE_TEXCOORD element? break; case InternalEffectID.WorldShader: case InternalEffectID.GlossyWindow: case InternalEffectID.billboardshader: case InternalEffectID.CarShader: vertex.Position = BinaryUtil.ReadVector3(reader); vertex.Normal = BinaryUtil.ReadVector3(reader); vertex.Color = reader.ReadUInt32(); vertex.TexCoords = BinaryUtil.ReadVector2(reader); break; default: throw new Exception($"Unsupported effect in object {Name}: {id}"); } return(vertex); }
private SolidObject ReadObject(BinaryReader br, long size, SolidObject solidObject) { if (solidObject == null) { solidObject = new MostWantedObject(); } var endPos = br.BaseStream.Position + size; while (br.BaseStream.Position < endPos) { var chunkId = br.ReadUInt32(); var chunkSize = br.ReadUInt32(); var chunkEndPos = br.BaseStream.Position + chunkSize; if ((chunkId & 0x80000000) == 0x80000000) { solidObject = ReadObject(br, chunkSize, solidObject); } else { var padding = 0u; while (br.ReadUInt32() == 0x11111111) { padding += 4; if (br.BaseStream.Position >= chunkEndPos) { break; } } br.BaseStream.Position -= 4; chunkSize -= padding; switch (chunkId) { case SolidListObjHeadChunk: { _namedMaterials = 0; var header = BinaryUtil.ReadStruct <SolidObjectHeader>(br); var name = BinaryUtil.ReadNullTerminatedString(br); solidObject.Name = name; solidObject.Hash = header.Hash; solidObject.MinPoint = header.BoundsMin; solidObject.MaxPoint = header.BoundsMax; solidObject.Transform = header.Transform; break; } // 12 40 13 00 case 0x00134012: { for (var j = 0; j < chunkSize / 8; j++) { solidObject.TextureHashes.Add(br.ReadUInt32()); br.BaseStream.Position += 4; } break; } case 0x134900: { var descriptor = BinaryUtil.ReadUnmanagedStruct <SolidObjectDescriptor>(br); solidObject.MeshDescriptor = new SolidMeshDescriptor { Flags = descriptor.Flags, HasNormals = true, NumIndices = descriptor.NumIndices, NumMats = descriptor.NumMats, NumVertexStreams = descriptor.NumVertexStreams }; break; } case 0x00134b02: { var shadingGroupSize = Marshal.SizeOf <SolidObjectShadingGroup>(); Debug.Assert(chunkSize % shadingGroupSize == 0); var numMats = chunkSize / shadingGroupSize; var streamIndex = 0; var lastEffectID = 0u; for (var j = 0; j < numMats; j++) { var shadingGroup = BinaryUtil.ReadStruct <SolidObjectShadingGroup>(br); if (j > 0 && shadingGroup.EffectId != lastEffectID) { streamIndex++; } var solidObjectMaterial = new MostWantedMaterial { Flags = shadingGroup.Flags, NumIndices = shadingGroup.NumTris * 3, MinPoint = shadingGroup.BoundsMin, MaxPoint = shadingGroup.BoundsMax, NumVerts = shadingGroup.NumVerts, TextureHash = solidObject.TextureHashes[shadingGroup.TextureNumber[0]], EffectId = shadingGroup.EffectId, VertexStreamIndex = streamIndex }; solidObject.Materials.Add(solidObjectMaterial); solidObject.MeshDescriptor.NumVerts += shadingGroup.NumVerts; lastEffectID = shadingGroup.EffectId; } break; } case 0x134b01: { if (chunkSize > 0) { var vb = new byte[chunkSize]; var readSize = br.Read(vb, 0, vb.Length); Debug.Assert(readSize == chunkSize); solidObject.VertexBuffers.Add(vb); } break; } case 0x134b03: { foreach (var material in solidObject.Materials) { material.Indices = new ushort[material.NumIndices]; for (var j = 0; j < material.NumIndices; j++) { material.Indices[j] = br.ReadUInt16(); } } break; } case 0x00134c02: { if (chunkSize > 0) { solidObject.Materials[_namedMaterials++].Name = BinaryUtil.ReadNullTerminatedString(br); } break; } default: //Console.WriteLine($"0x{chunkId:X8} [{chunkSize}] @{br.BaseStream.Position}"); break; } } br.BaseStream.Position = chunkEndPos; } return(solidObject); }