public GameSound ReadData() { var resourceGestalt = cache.TagIndex.GetGlobalTag("ugh!").ReadMetadata <sound_cache_file_gestalt>(); var playback = resourceGestalt.Playbacks[PlaybackIndex]; var codec = resourceGestalt.Codecs[CodecIndex]; var sourceData = ResourceIdentifier.ReadSoundData(); var result = new GameSound { Name = item.FileName(), FormatHeader = new XmaHeader(codec.SampleRateInt, codec.ChannelCounts), DefaultExtension = "xma" }; for (int i = 0; i < playback.PermutationCount; i++) { var perm = resourceGestalt.SoundPermutations[playback.FirstPermutationIndex + i]; var name = resourceGestalt.SoundNames[perm.NameIndex].Name; byte[] permData; if (playback.PermutationCount == 1) { //skip the array copy permData = sourceData; } else { var blocks = Enumerable.Range(perm.BlockIndex, perm.BlockCount) .Select(x => resourceGestalt.DataBlocks[x]) .ToList(); permData = new byte[blocks.Sum(b => b.Size)]; var offset = 0; foreach (var block in blocks) { Array.Copy(sourceData, block.FileOffset, permData, offset, block.Size); offset += block.Size; } } result.Permutations.Add(new GameSoundPermutation { Name = name, SoundData = permData }); } return(result); }
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 }; model.Nodes.AddRange(Nodes); model.MarkerGroups.AddRange(MarkerGroups); var shaderRefs = Shaders.Select(s => s.ShaderReference); model.Materials.AddRange(Halo1Common.GetMaterials(shaderRefs, reader)); 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.LodIndex(lod), MeshCount = 1 })); model.Regions.Add(gRegion); } if (cache.CacheType == CacheType.Halo1Xbox) { model.Meshes.AddRange(ReadXboxMeshes(reader)); } else { model.Meshes.AddRange(ReadPCMeshes(reader)); } 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.Nodes.AddRange(Nodes); model.MarkerGroups.AddRange(MarkerGroups); model.Bounds.AddRange(BoundingBoxes); model.Materials.AddRange(Halo2.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.HeaderSize + 8; using (var ms = new MemoryStream(data)) using (var reader = new EndianReader(ms, ByteOrder.LittleEndian)) { reader.ReadInt32(); //hklb var sectionInfo = reader.ReadObject <MeshResourceDetailsBlock>(); var submeshResource = section.Resources[0]; var indexResource = section.Resources.FirstOrDefault(r => r.Type0 == 48); var vertexResource = section.Resources.FirstOrDefault(r => r.Type0 == 92 && r.Type1 == 0); var uvResource = section.Resources.FirstOrDefault(r => r.Type0 == 92 && r.Type1 == 1); var normalsResource = section.Resources.FirstOrDefault(r => r.Type0 == 92 && r.Type1 == 2); var nodeMapResource = section.Resources.FirstOrDefault(r => r.Type0 == 164); reader.Seek(baseAddress + submeshResource.Offset, SeekOrigin.Begin); var submeshes = reader.ReadEnumerable <Halo2.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 Halo2.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 = (Halo2.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 = (Halo2.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 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); }
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); } }
public GameSound ReadData() { if (CompressionCodec != CompressionCodec.WMA && CompressionCodec != CompressionCodec.XboxAdpcm) { throw new NotSupportedException("Unsupported Codec/Encoding"); } var resourceGestalt = cache.TagIndex.GetGlobalTag("ugh!").ReadMetadata <sound_cache_file_gestalt>(); var pitchRange = resourceGestalt.PitchRanges[PitchRangeIndex]; var result = new GameSound { Name = item.FileName() }; if (CompressionCodec == CompressionCodec.XboxAdpcm) { if (Encoding != Encoding.Codec) { result.FormatHeader = new XboxAdpcmHeader(SampleRateInt, (byte)(Encoding + 1)); } result.DefaultExtension = "wav"; } else if (CompressionCodec == CompressionCodec.WMA) { result.DefaultExtension = "wma"; } for (int i = 0; i < pitchRange.PermutationCount; i++) { var perm = resourceGestalt.SoundPermutations[pitchRange.FirstPermutationIndex + i]; var name = resourceGestalt.SoundNames[perm.NameIndex].Name; byte[] permData; if (perm.BlockCount == 1) { //skip the array copy var block = resourceGestalt.SoundPermutationChunks[perm.BlockIndex]; permData = block.DataPointer.ReadData(block.DataSize); } else { var blocks = Enumerable.Range(perm.BlockIndex, perm.BlockCount) .Select(x => resourceGestalt.SoundPermutationChunks[x]) .ToList(); permData = new byte[blocks.Sum(b => b.DataSize)]; var offset = 0; foreach (var block in blocks) { var sourceData = block.DataPointer.ReadData(block.DataSize); Array.Copy(sourceData, 0, permData, offset, sourceData.Length); offset += sourceData.Length; } } result.Permutations.Add(new GameSoundPermutation { Name = name, SoundData = permData }); } return(result); }
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 = cache.CacheType < CacheType.MccHalo3U4 ? lightmap.LightmapData.First(sldt => sldt.BspIndex == bspIndex) : lightmap.LightmapRefs.Select(sldt => sldt.Tag.ReadMetadata <scenario_lightmap_bsp_data>()).First(sldt => sldt.BspIndex == bspIndex); model.Bounds.AddRange(BoundingBoxes); model.Materials.AddRange(Halo3Common.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); 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(Halo3Common.GetMeshes(cache, lightmapData.ResourcePointer, lightmapData.Sections, (s, m) => { var index = (short)lightmapData.Sections.IndexOf(s); m.BoundsIndex = index >= BoundingBoxes.Count ? (short?)null : index; m.IsInstancing = index < BoundingBoxes.Count; })); return(model); }