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);
        }
示例#2
0
        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);
            }
        }