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); }