public IGeometryModel ReadGeometry(int lod) { if (lod < 0 || lod >= ((IRenderGeometry)this).LodCount) { throw new ArgumentOutOfRangeException(nameof(lod)); } var model = new GeometryModel(item.FileName()) { CoordinateSystem = CoordinateSystem.Default }; model.Nodes.AddRange(Nodes); model.MarkerGroups.AddRange(MarkerGroups); model.Bounds.AddRange(BoundingBoxes); model.Materials.AddRange(Halo2Common.GetMaterials(Shaders)); foreach (var region in Regions) { var gRegion = new GeometryRegion { SourceIndex = Regions.IndexOf(region), Name = region.Name }; gRegion.Permutations.AddRange(region.Permutations.Select(p => new GeometryPermutation { SourceIndex = region.Permutations.IndexOf(p), Name = p.Name, MeshIndex = p.LodArray[lod], MeshCount = 1 })); model.Regions.Add(gRegion); } foreach (var section in Sections) { var data = section.DataPointer.ReadData(section.DataSize); var baseAddress = section.DataSize - section.HeaderSize - 4; using (var ms = new MemoryStream(data)) using (var reader = new EndianReader(ms, ByteOrder.LittleEndian)) { var sectionInfo = reader.ReadObject <MeshResourceDetailsBlock>(); var submeshResource = section.Resources[0]; var indexResource = section.Resources.FirstOrDefault(r => r.Type0 == 32); var vertexResource = section.Resources.FirstOrDefault(r => r.Type0 == 56 && r.Type1 == 0); var uvResource = section.Resources.FirstOrDefault(r => r.Type0 == 56 && r.Type1 == 1); var normalsResource = section.Resources.FirstOrDefault(r => r.Type0 == 56 && r.Type1 == 2); var nodeMapResource = section.Resources.FirstOrDefault(r => r.Type0 == 100); reader.Seek(baseAddress + submeshResource.Offset, SeekOrigin.Begin); var submeshes = reader.ReadEnumerable <SubmeshDataBlock>(submeshResource.Size / 72).ToList(); var mesh = new GeometryMesh { BoundsIndex = 0, }; foreach (var submesh in submeshes) { mesh.Submeshes.Add(new GeometrySubmesh { MaterialIndex = submesh.ShaderIndex, IndexStart = submesh.IndexStart, IndexLength = submesh.IndexLength }); } if (section.FaceCount * 3 == sectionInfo.IndexCount) { mesh.IndexFormat = IndexFormat.TriangleList; } else { mesh.IndexFormat = IndexFormat.TriangleStrip; } reader.Seek(baseAddress + indexResource.Offset, SeekOrigin.Begin); mesh.Indicies = reader.ReadEnumerable <ushort>(sectionInfo.IndexCount).Select(i => (int)i).ToArray(); var nodeMap = new byte[0]; if (nodeMapResource != null) { reader.Seek(baseAddress + nodeMapResource.Offset, SeekOrigin.Begin); nodeMap = reader.ReadBytes(sectionInfo.NodeMapCount); } #region Vertices mesh.Vertices = new IVertex[section.VertexCount]; var vertexSize = vertexResource.Size / section.VertexCount; for (int i = 0; i < section.VertexCount; i++) { var vert = new Vertex(); reader.Seek(baseAddress + vertexResource.Offset + i * vertexSize, SeekOrigin.Begin); vert.Position = new UInt16N4((ushort)(reader.ReadInt16() - short.MinValue), (ushort)(reader.ReadInt16() - short.MinValue), (ushort)(reader.ReadInt16() - short.MinValue), 0); ReadBlendData(reader, section, mesh, vert, nodeMap); mesh.Vertices[i] = vert; } for (int i = 0; i < section.VertexCount; i++) { var vert = (Vertex)mesh.Vertices[i]; reader.Seek(baseAddress + uvResource.Offset + i * 4, SeekOrigin.Begin); vert.TexCoords = new UInt16N2((ushort)(reader.ReadInt16() - short.MinValue), (ushort)(reader.ReadInt16() - short.MinValue)); } for (int i = 0; i < section.VertexCount; i++) { var vert = (Vertex)mesh.Vertices[i]; reader.Seek(baseAddress + normalsResource.Offset + i * 12, SeekOrigin.Begin); vert.Normal = new HenDN3(reader.ReadUInt32()); } #endregion model.Meshes.Add(mesh); } } return(model); }
public IGeometryModel ReadGeometry(int lod) { if (lod < 0 || lod >= ((IRenderGeometry)this).LodCount) { throw new ArgumentOutOfRangeException(nameof(lod)); } var model = new GeometryModel(item.FileName()) { CoordinateSystem = CoordinateSystem.Default }; model.Materials.AddRange(Halo2Common.GetMaterials(Shaders)); #region Clusters var clusterRegion = new GeometryRegion { Name = "Clusters" }; foreach (var section in Clusters.Where(s => s.VertexCount > 0)) { var sectionIndex = Clusters.IndexOf(section); var data = section.DataPointer.ReadData(section.DataSize); var baseAddress = section.HeaderSize + 8; using (var ms = new MemoryStream(data)) using (var reader = new EndianReader(ms, ByteOrder.LittleEndian)) { var sectionInfo = reader.ReadObject <MeshResourceDetailsBlock>(); var submeshResource = section.Resources[0]; var indexResource = section.Resources.FirstOrDefault(r => r.Type0 == 32); var vertexResource = section.Resources.FirstOrDefault(r => r.Type0 == 56 && r.Type1 == 0); var uvResource = section.Resources.FirstOrDefault(r => r.Type0 == 56 && r.Type1 == 1); var normalsResource = section.Resources.FirstOrDefault(r => r.Type0 == 56 && r.Type1 == 2); reader.Seek(baseAddress + submeshResource.Offset, SeekOrigin.Begin); var submeshes = reader.ReadEnumerable <SubmeshDataBlock>(submeshResource.Size / 72).ToList(); var mesh = new GeometryMesh(); if (section.FaceCount * 3 == sectionInfo.IndexCount) { mesh.IndexFormat = IndexFormat.TriangleList; } else { mesh.IndexFormat = IndexFormat.TriangleStrip; } reader.Seek(baseAddress + indexResource.Offset, SeekOrigin.Begin); mesh.Indicies = reader.ReadEnumerable <ushort>(sectionInfo.IndexCount).Select(i => (int)i).ToArray(); #region Vertices mesh.Vertices = new IVertex[section.VertexCount]; var vertexSize = vertexResource.Size / section.VertexCount; for (int i = 0; i < section.VertexCount; i++) { var vert = new WorldVertex(); reader.Seek(baseAddress + vertexResource.Offset + i * vertexSize, SeekOrigin.Begin); vert.Position = new RealVector3D(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); mesh.Vertices[i] = vert; } for (int i = 0; i < section.VertexCount; i++) { var vert = (WorldVertex)mesh.Vertices[i]; reader.Seek(baseAddress + uvResource.Offset + i * 8, SeekOrigin.Begin); vert.TexCoords = new RealVector2D(reader.ReadSingle(), reader.ReadSingle()); } for (int i = 0; i < section.VertexCount; i++) { var vert = (WorldVertex)mesh.Vertices[i]; reader.Seek(baseAddress + normalsResource.Offset + i * 12, SeekOrigin.Begin); vert.Normal = new HenDN3(reader.ReadUInt32()); } #endregion var perm = new GeometryPermutation { SourceIndex = Clusters.IndexOf(section), Name = sectionIndex.ToString("D3", CultureInfo.CurrentCulture), MeshIndex = model.Meshes.Count, MeshCount = 1 }; foreach (var submesh in submeshes) { mesh.Submeshes.Add(new GeometrySubmesh { MaterialIndex = submesh.ShaderIndex, IndexStart = submesh.IndexStart, IndexLength = submesh.IndexLength }); } clusterRegion.Permutations.Add(perm); model.Meshes.Add(mesh); } } model.Regions.Add(clusterRegion); #endregion #region Instances foreach (var section in Sections.Where(s => s.VertexCount > 0)) { var sectionIndex = Sections.IndexOf(section); var sectionRegion = new GeometryRegion { Name = Utils.CurrentCulture($"Instances {sectionIndex:D3}") }; var data = section.DataPointer.ReadData(section.DataSize); var baseAddress = section.HeaderSize + 8; using (var ms = new MemoryStream(data)) using (var reader = new EndianReader(ms, ByteOrder.LittleEndian)) { var sectionInfo = reader.ReadObject <MeshResourceDetailsBlock>(); var submeshResource = section.Resources[0]; var indexResource = section.Resources.FirstOrDefault(r => r.Type0 == 32); var vertexResource = section.Resources.FirstOrDefault(r => r.Type0 == 56 && r.Type1 == 0); var uvResource = section.Resources.FirstOrDefault(r => r.Type0 == 56 && r.Type1 == 1); var normalsResource = section.Resources.FirstOrDefault(r => r.Type0 == 56 && r.Type1 == 2); reader.Seek(baseAddress + submeshResource.Offset, SeekOrigin.Begin); var submeshes = reader.ReadEnumerable <SubmeshDataBlock>(submeshResource.Size / 72).ToList(); var mesh = new GeometryMesh { IsInstancing = true }; if (section.FaceCount * 3 == sectionInfo.IndexCount) { mesh.IndexFormat = IndexFormat.TriangleList; } else { mesh.IndexFormat = IndexFormat.TriangleStrip; } reader.Seek(baseAddress + indexResource.Offset, SeekOrigin.Begin); mesh.Indicies = reader.ReadEnumerable <ushort>(sectionInfo.IndexCount).Select(i => (int)i).ToArray(); #region Vertices mesh.Vertices = new IVertex[section.VertexCount]; var vertexSize = vertexResource.Size / section.VertexCount; for (int i = 0; i < section.VertexCount; i++) { var vert = new WorldVertex(); reader.Seek(baseAddress + vertexResource.Offset + i * vertexSize, SeekOrigin.Begin); vert.Position = new RealVector3D(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); mesh.Vertices[i] = vert; } for (int i = 0; i < section.VertexCount; i++) { var vert = (WorldVertex)mesh.Vertices[i]; reader.Seek(baseAddress + uvResource.Offset + i * 8, SeekOrigin.Begin); vert.TexCoords = new RealVector2D(reader.ReadSingle(), reader.ReadSingle()); } for (int i = 0; i < section.VertexCount; i++) { var vert = (WorldVertex)mesh.Vertices[i]; reader.Seek(baseAddress + normalsResource.Offset + i * 12, SeekOrigin.Begin); vert.Normal = new HenDN3(reader.ReadUInt32()); } #endregion var perms = GeometryInstances .Where(i => i.SectionIndex == sectionIndex) .Select(i => new GeometryPermutation { SourceIndex = GeometryInstances.IndexOf(i), Name = i.Name, Transform = i.Transform, TransformScale = i.TransformScale, MeshIndex = model.Meshes.Count, MeshCount = 1 }).ToList(); mesh.Submeshes.AddRange( submeshes.Select(s => new GeometrySubmesh { MaterialIndex = s.ShaderIndex, IndexStart = s.IndexStart, IndexLength = s.IndexLength }) ); sectionRegion.Permutations.AddRange(perms); model.Meshes.Add(mesh); } model.Regions.Add(sectionRegion); } #endregion return(model); }