Ejemplo n.º 1
0
        public IGeometryModel ReadGeometry(int lod)
        {
            if (lod < 0 || lod >= ((IRenderGeometry)this).LodCount)
            {
                throw new ArgumentOutOfRangeException(nameof(lod));
            }

            var model = new GeometryModel(Name)
            {
                CoordinateSystem = CoordinateSystem.Default
            };

            model.Nodes.AddRange(Nodes);
            model.MarkerGroups.AddRange(MarkerGroups);
            model.Bounds.AddRange(BoundingBoxes);
            model.Materials.AddRange(Halo4Common.GetMaterials(Shaders));

            foreach (var region in Regions)
            {
                var gRegion = new GeometryRegion {
                    SourceIndex = Regions.IndexOf(region), Name = region.Name
                };
                gRegion.Permutations.AddRange(region.Permutations.Where(p => p.SectionIndex >= 0).Select(p =>
                                                                                                         new GeometryPermutation
                {
                    SourceIndex = region.Permutations.IndexOf(p),
                    Name        = p.Name,
                    MeshIndex   = p.SectionIndex,
                    MeshCount   = p.SectionCount
                }));

                if (gRegion.Permutations.Any())
                {
                    model.Regions.Add(gRegion);
                }
            }

            Func <int, int, int> mapNodeFunc = null;

            if (Flags.HasFlag(ModelFlags.UseLocalNodes))
            {
                mapNodeFunc = (si, i) => NodeMaps[si].Indices[i];
            }

            model.Meshes.AddRange(Halo4Common.GetMeshes(cache, ResourcePointer, Sections, (s, m) => m.BoundsIndex = 0, mapNodeFunc));

            CreateInstanceMeshes(model);

            return(model);
        }
        public IGeometryModel ReadGeometry(int lod)
        {
            if (lod < 0 || lod >= ((IRenderGeometry)this).LodCount)
            {
                throw new ArgumentOutOfRangeException(nameof(lod));
            }

            var scenario = cache.TagIndex.GetGlobalTag("scnr").ReadMetadata <scenario>();
            var model    = new GeometryModel(item.FileName())
            {
                CoordinateSystem = CoordinateSystem.Default
            };

            var bspBlock = scenario.StructureBsps.First(s => s.BspReference.TagId == item.Id);
            var bspIndex = scenario.StructureBsps.IndexOf(bspBlock);

            var lightmap     = scenario.ScenarioLightmapReference.Tag.ReadMetadata <scenario_lightmap>();
            var lightmapData = lightmap.LightmapRefs[bspIndex].LightmapDataReference.Tag.ReadMetadata <scenario_lightmap_bsp_data>();

            model.Bounds.AddRange(lightmapData.BoundingBoxes);
            model.Materials.AddRange(Halo4Common.GetMaterials(Shaders));

            var clusterRegion = new GeometryRegion {
                Name = "Clusters"
            };

            clusterRegion.Permutations.AddRange(
                Clusters.Select((c, i) => new GeometryPermutation
            {
                SourceIndex = i,
                Name        = Clusters.IndexOf(c).ToString("D3", CultureInfo.CurrentCulture),
                MeshIndex   = c.SectionIndex,
                MeshCount   = 1
            })
                );
            model.Regions.Add(clusterRegion);

            if (!loadedInstances)
            {
                var resourceGestalt = cache.TagIndex.GetGlobalTag("zone").ReadMetadata <cache_file_resource_gestalt>();
                var entry           = resourceGestalt.ResourceEntries[InstancesResourcePointer.ResourceIndex];
                var address         = entry.ResourceFixups[entry.ResourceFixups.Count - 10].Offset & 0x0FFFFFFF;

                using (var ms = new MemoryStream(InstancesResourcePointer.ReadData(PageType.Auto)))
                    using (var reader = new EndianReader(ms, cache.ByteOrder))
                    {
                        var blockSize = cache.CacheType == CacheType.Halo4Beta ? 164 : 148;
                        for (int i = 0; i < GeometryInstances.Count; i++)
                        {
                            reader.Seek(address + blockSize * i, SeekOrigin.Begin);
                            GeometryInstances[i].TransformScale = reader.ReadSingle();
                            GeometryInstances[i].Transform      = new Matrix4x4
                            {
                                M11 = reader.ReadSingle(),
                                M12 = reader.ReadSingle(),
                                M13 = reader.ReadSingle(),

                                M21 = reader.ReadSingle(),
                                M22 = reader.ReadSingle(),
                                M23 = reader.ReadSingle(),

                                M31 = reader.ReadSingle(),
                                M32 = reader.ReadSingle(),
                                M33 = reader.ReadSingle(),

                                M41 = reader.ReadSingle(),
                                M42 = reader.ReadSingle(),
                                M43 = reader.ReadSingle(),
                            };
                            reader.Seek(10, SeekOrigin.Current);
                            GeometryInstances[i].SectionIndex = reader.ReadInt16();
                        }
                    }

                loadedInstances = true;
            }

            foreach (var instanceGroup in GeometryInstances.GroupBy(i => i.SectionIndex))
            {
                var section       = lightmapData.Sections[instanceGroup.Key];
                var sectionRegion = new GeometryRegion {
                    Name = Utils.CurrentCulture($"Instances {instanceGroup.Key:D3}")
                };
                sectionRegion.Permutations.AddRange(
                    instanceGroup.Select(i => new GeometryPermutation
                {
                    SourceIndex    = GeometryInstances.IndexOf(i),
                    Name           = i.Name,
                    Transform      = i.Transform,
                    TransformScale = i.TransformScale,
                    MeshIndex      = i.SectionIndex,
                    MeshCount      = 1
                })
                    );
                model.Regions.Add(sectionRegion);
            }

            model.Meshes.AddRange(Halo4Common.GetMeshes(cache, lightmapData.ResourcePointer, lightmapData.Sections, (s, m) =>
            {
                var index      = (short)lightmapData.Sections.IndexOf(s);
                m.BoundsIndex  = index >= lightmapData.BoundingBoxes.Count ? (short?)null : index;
                m.IsInstancing = index < lightmapData.BoundingBoxes.Count;
            }));

            return(model);
        }