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); }
public IGeometryModel ReadGeometry(int lod) { if (lod < 0 || lod >= ((IRenderGeometry)this).LodCount) { throw new ArgumentOutOfRangeException(nameof(lod)); } using (var reader = cache.CreateReader(cache.DefaultAddressTranslator)) { var model = new GeometryModel(item.FileName()) { CoordinateSystem = CoordinateSystem.Default }; var shaderRefs = Lightmaps.SelectMany(m => m.Materials) .Where(m => m.ShaderReference.TagId >= 0) .GroupBy(m => m.ShaderReference.TagId) .Select(g => g.First().ShaderReference) .ToList(); var shaderIds = shaderRefs.Select(r => r.TagId).ToList(); model.Materials.AddRange(Halo1Common.GetMaterials(shaderRefs, reader)); reader.Seek(SurfacePointer.Address, SeekOrigin.Begin); var indices = reader.ReadEnumerable <ushort>(SurfaceCount * 3).ToArray(); var gRegion = new GeometryRegion { Name = "Clusters" }; int sectionIndex = 0; foreach (var section in Lightmaps) { if (section.Materials.Count == 0) { continue; } var localIndices = new List <int>(); var vertices = new List <WorldVertex>(); var submeshes = new List <IGeometrySubmesh>(); var gPermutation = new GeometryPermutation { SourceIndex = Lightmaps.IndexOf(section), Name = sectionIndex.ToString("D3", CultureInfo.CurrentCulture), MeshIndex = sectionIndex, MeshCount = 1 }; foreach (var submesh in section.Materials) { reader.Seek(submesh.VertexPointer.Address, SeekOrigin.Begin); submeshes.Add(new GeometrySubmesh { MaterialIndex = (short)shaderIds.IndexOf(submesh.ShaderReference.TagId), IndexStart = localIndices.Count, IndexLength = submesh.SurfaceCount * 3 }); localIndices.AddRange( indices.Skip(submesh.SurfaceIndex * 3) .Take(submesh.SurfaceCount * 3) .Select(i => i + vertices.Count) ); var vertsTemp = reader.ReadEnumerable <WorldVertex>(submesh.VertexCount).ToList(); vertices.AddRange(vertsTemp); } gRegion.Permutations.Add(gPermutation); model.Meshes.Add(new GeometryMesh { IndexFormat = IndexFormat.TriangleList, VertexWeights = VertexWeights.None, Indicies = localIndices.ToArray(), Vertices = vertices.ToArray(), Submeshes = submeshes }); sectionIndex++; } model.Regions.Add(gRegion); return(model); } }