private void EditVfslTag(HaloTag tag) { VFilesList vfsl; using (var stream = _fileInfo.OpenRead()) vfsl = TagDeserializer.Deserialize <VFilesList>(new TagSerializationContext(stream, _cache, tag)); var context = VfslContextFactory.Create(_stack.Context, _fileInfo, _cache, tag, vfsl); _stack.Push(context); }
private void EditBitmTag(HaloTag tag) { Bitmap bitmap; using (var stream = _fileInfo.OpenRead()) bitmap = TagDeserializer.Deserialize <Bitmap>(new TagSerializationContext(stream, _cache, tag)); var context = BitmContextFactory.Create(_stack.Context, _fileInfo, _cache, tag, bitmap); _stack.Push(context); }
private void EditHlmtTag(HaloTag tag) { Model model; using (var stream = _fileInfo.OpenRead()) model = TagDeserializer.Deserialize <Model>(new TagSerializationContext(stream, _cache, tag)); var context = HlmtContextFactory.Create(_stack.Context, _fileInfo, _cache, _stringIds, tag, model); _stack.Push(context); }
private void ReadMetadataSection(EndianReader reader, DataSerializationContext context, TagDeserializer deserializer) { var section = GetSectionHeader(reader, ModPackageSection.Metadata); if (!GoToSectionHeaderOffset(reader, section)) { return; } Metadata = deserializer.Deserialize <ModPackageMetadata>(context); }
public void InjectDds(TagSerializer serializer, TagDeserializer deserializer, Bitmap bitmap, int imageIndex, Stream ddsStream) { // Deserialize the old definition var resourceContext = new ResourceSerializationContext(bitmap.Resources[imageIndex].Resource); var definition = deserializer.Deserialize<BitmapTextureResourceDefinition>(resourceContext); if (definition.Texture == null || definition.Texture.Definition == null) throw new ArgumentException("Invalid bitmap definition"); var texture = definition.Texture.Definition; // Read the DDS header and modify the definition to match var dds = DdsHeader.Read(ddsStream); var dataSize = (int)(ddsStream.Length - ddsStream.Position); texture.Data = new ResourceDataReference(dataSize, new ResourceAddress(ResourceAddressType.Resource, 0)); texture.Width = (short)dds.Width; texture.Height = (short)dds.Height; texture.Depth = (sbyte)Math.Max(1, dds.Depth); texture.Levels = (sbyte)Math.Max(1, dds.MipMapCount); texture.Type = BitmapDdsFormatDetection.DetectType(dds); texture.D3DFormatUnused = (int)((dds.D3D10Format != DxgiFormat.Bc5UNorm) ? dds.FourCc : DdsFourCc.FromString("ATI2")); texture.Format = BitmapDdsFormatDetection.DetectFormat(dds); // Set flags based on the format switch (definition.Texture.Definition.Format) { case BitmapFormat.Dxt1: case BitmapFormat.Dxt3: case BitmapFormat.Dxt5: case BitmapFormat.Dxn: definition.Texture.Definition.Flags = BitmapFlags.Compressed; break; default: definition.Texture.Definition.Flags = BitmapFlags.None; break; } // Inject the resource data _resourceManager.Replace(bitmap.Resources[imageIndex].Resource, ddsStream); // Serialize the new resource definition serializer.Serialize(resourceContext, definition); // Modify the image data in the bitmap tag to match the definition var imageData = bitmap.Images[imageIndex]; imageData.Width = texture.Width; imageData.Height = texture.Height; imageData.Depth = texture.Depth; imageData.Type = texture.Type; imageData.Format = texture.Format; imageData.Flags = texture.Flags; imageData.MipmapCount = (sbyte)(texture.Levels - 1); imageData.DataOffset = texture.Data.Address.Offset; imageData.DataSize = texture.Data.Size; }
public TagCacheGen1(EndianReader reader, MapFile mapFile) { var tagDataSectionOffset = mapFile.Header.TagsHeaderAddress32; reader.SeekTo(tagDataSectionOffset); var dataContext = new DataSerializationContext(reader); var deserializer = new TagDeserializer(mapFile.Version); Header = deserializer.Deserialize <TagCacheGen1Header>(dataContext); if (mapFile.Version == CacheVersion.HaloXbox) { BaseTagAddress = 0x803A6000; } else { BaseTagAddress = 0x40440000; } // // Read all tags offsets are all broken, need some proper look // reader.SeekTo(Header.CachedTagArrayAddress - BaseTagAddress + tagDataSectionOffset); for (int i = 0; i < Header.TagCount; i++) { var group = new TagGroup() { Tag = new Tag(reader.ReadInt32()), ParentTag = new Tag(reader.ReadInt32()), GrandparentTag = new Tag(reader.ReadInt32()) }; var tagID = reader.ReadUInt32(); var tagPathNameAddress = reader.ReadUInt32(); var currentPos = reader.Position; string name = ""; if (tagPathNameAddress != 0) { reader.SeekTo(tagPathNameAddress - BaseTagAddress + tagDataSectionOffset); name = reader.ReadNullTerminatedString(); reader.SeekTo(currentPos); } var tagDataAddress = reader.ReadUInt32(); var weird2 = reader.ReadUInt32(); var unused = reader.ReadUInt32(); Tags.Add(new CachedTagGen1((int)(tagID & 0xFFFF), tagID, group, tagDataAddress, name)); } }
private void ReadTagNamesSection(EndianReader reader, DataSerializationContext context, TagDeserializer deserializer) { var section = GetSectionHeader(reader, ModPackageSection.TagNames); if (!GoToSectionHeaderOffset(reader, section)) { return; } var tagNamesHeader = new GenericSectionEntry(reader); reader.BaseStream.Position = tagNamesHeader.TableOffset; for (int i = 0; i < tagNamesHeader.Count; i++) { var tagNamesEntry = deserializer.Deserialize <ModPackageTagNamesEntry>(context); TagNames.Add(tagNamesEntry.TagIndex, tagNamesEntry.Name); } }
public override bool Execute(List <string> args) { if (args.Count != 1 && args.Count != 2) { return(false); } GameLanguage language; if (!ArgumentParser.ParseLanguage(args[0], out language)) { return(false); } var filter = (args.Count == 2) ? args[1] : null; var found = false; using (var stream = _fileInfo.OpenRead()) { foreach (var unicTag in _cache.Tags.FindAllByClass("unic")) { var unic = TagDeserializer.Deserialize <MultilingualUnicodeStringList>(new TagSerializationContext(stream, _cache, unicTag)); var strings = LocalizedStringPrinter.PrepareForDisplay(unic, _stringIds, unic.Strings, language, filter); if (strings.Count == 0) { continue; } if (found) { Console.WriteLine(); } Console.WriteLine("Strings found in {0:X8}.unic:", unicTag.Index); LocalizedStringPrinter.PrintStrings(strings); found = true; } } if (!found) { Console.Error.WriteLine("No strings found."); } return(true); }
public static byte[] ConvertHkpMoppData(CacheVersion sourceVersion, CacheVersion destVersion, byte[] data) { if (data == null || data.Length == 0) { return(data); } byte[] result; using (var inputReader = new EndianReader(new MemoryStream(data), CacheVersionDetection.IsLittleEndian(sourceVersion) ? EndianFormat.LittleEndian : EndianFormat.BigEndian)) using (var outputStream = new MemoryStream()) using (var outputWriter = new EndianWriter(outputStream, CacheVersionDetection.IsLittleEndian(destVersion) ? EndianFormat.LittleEndian : EndianFormat.BigEndian)) { var dataContext = new DataSerializationContext(inputReader, outputWriter); var deserializer = new TagDeserializer(sourceVersion); var serializer = new TagSerializer(destVersion); while (!inputReader.EOF) { var header = deserializer.Deserialize <HkpMoppCode>(dataContext); var dataSize = header.ArrayBase.GetCapacity(); var alignedSize = dataSize + 0xf & ~0xf; var nextOffset = inputReader.Position + alignedSize; List <byte> moppCodes = new List <byte>(); for (int j = 0; j < header.ArrayBase.GetCapacity(); j++) { moppCodes.Add(inputReader.ReadByte()); } inputReader.SeekTo(nextOffset); moppCodes = ConvertMoppCodes(sourceVersion, destVersion, moppCodes); serializer.Serialize(dataContext, header); for (int j = 0; j < moppCodes.Count; j++) { outputWriter.Write(moppCodes[j]); } StreamUtil.Align(outputStream, 0x10); } result = outputStream.ToArray(); } return(result); }
public void Load(FileInfo file) { if (!file.Exists) { throw new FileNotFoundException(file.FullName); } if (file.Length < typeof(ModPackageHeader).GetSize()) { throw new FormatException(file.FullName); } using (var stream = file.OpenRead()) using (var reader = new EndianReader(stream, leaveOpen: true)) { var dataContext = new DataSerializationContext(reader); var deserializer = new TagDeserializer(CacheVersion.HaloOnline106708); Header = deserializer.Deserialize <ModPackageHeader>(dataContext); ReadMetadataSection(reader, dataContext, deserializer); ReadTagsSection(reader, dataContext, deserializer); ReadTagNamesSection(reader, dataContext, deserializer); ReadResourcesSection(reader); ReadMapFilesSection(reader); ReadCampaignFileSection(reader); ReadStringIdSection(reader); ReadFontSection(reader); ReadFileEntries(reader, dataContext, deserializer); int tagCacheCount = TagCachesStreams.Count; TagCaches = new List <TagCacheHaloOnline>(); for (int i = 0; i < tagCacheCount; i++) { TagCaches.Add(new TagCacheHaloOnline(TagCachesStreams[i], TagCacheNames[i])); } Resources = new ResourceCacheHaloOnline(CacheVersion.HaloOnline106708, ResourcesStream); } }
public void ExtractDds(TagDeserializer deserializer, Bitmap bitmap, int imageIndex, Stream outStream) { // TODO: Make sure 3D textures and cube maps work // Deserialize the resource definition and verify it var resource = bitmap.Resources[imageIndex]; var resourceContext = new ResourceSerializationContext(resource.Resource); var definition = deserializer.Deserialize<BitmapTextureResourceDefinition>(resourceContext); if (definition.Texture == null || definition.Texture.Definition == null) throw new ArgumentException("Invalid bitmap definition"); var dataReference = definition.Texture.Definition.Data; if (dataReference.Address.Type != ResourceAddressType.Resource) throw new InvalidOperationException("Invalid resource data address"); var header = CreateDdsHeader(definition); var resourceDataStream = new MemoryStream(); _resourceManager.Extract(resource.Resource, resourceDataStream); header.WriteTo(outStream); resourceDataStream.Position = dataReference.Address.Offset; StreamUtil.Copy(resourceDataStream, outStream, dataReference.Size); }
private void ReadTagNamesSection(EndianReader reader, DataSerializationContext context, TagDeserializer deserializer) { var section = GetSectionHeader(reader, ModPackageSection.TagNames); if (!GoToSectionHeaderOffset(reader, section)) { return; } var entry = new GenericSectionEntry(reader); var cacheCount = entry.Count; TagCacheNames = new List <Dictionary <int, string> >(); for (int i = 0; i < cacheCount; i++) { var nameDict = new Dictionary <int, string>(); reader.BaseStream.Position = entry.TableOffset + 0x8 * i + section.Offset; var tagNamesTableEntry = new GenericTableEntry(reader); if (tagNamesTableEntry.Size == 0) { throw new Exception("invalid tag name table entry size!"); } reader.BaseStream.Position = tagNamesTableEntry.Offset + section.Offset; var tagNamesHeader = new GenericSectionEntry(reader); reader.BaseStream.Position = tagNamesHeader.TableOffset + section.Offset; for (int j = 0; j < tagNamesHeader.Count; j++) { var tagNamesEntry = deserializer.Deserialize <ModPackageTagNamesEntry>(context); nameDict.Add(tagNamesEntry.TagIndex, tagNamesEntry.Name); } TagCacheNames.Add(nameDict); } }
private void ReadTagsSection(EndianReader reader, DataSerializationContext context, TagDeserializer deserializer) { var section = GetSectionHeader(reader, ModPackageSection.Tags); if (!GoToSectionHeaderOffset(reader, section)) { return; } var entry = new GenericSectionEntry(reader); var cacheCount = entry.Count; TagCachesStreams = new List <Stream>(); CacheNames = new List <string>(); for (int i = 0; i < cacheCount; i++) { var tagStream = new MemoryStream(); reader.BaseStream.Position = entry.TableOffset + 0x28 * i + section.Offset; var tableEntry = deserializer.Deserialize <CacheTableEntry>(context); CacheNames.Add(tableEntry.CacheName); reader.BaseStream.Position = tableEntry.Offset + section.Offset; if (section.Size > int.MaxValue) { throw new Exception("Tag cache size not supported"); } int size = (int)section.Size; byte[] data = new byte[size]; reader.Read(data, 0, size); tagStream.Write(data, 0, size); tagStream.Position = 0; TagCachesStreams.Add(tagStream); } }
private void ReadFileEntries(EndianReader reader, ISerializationContext context, TagDeserializer deserializer) { Files = new Dictionary <string, Stream>(); var section = GetSectionHeader(reader, ModPackageSection.Files); if (!GoToSectionHeaderOffset(reader, section)) { return; } var fileTable = new GenericSectionEntry(reader); reader.BaseStream.Position = fileTable.TableOffset + section.Offset; for (int i = 0; i < fileTable.Count; i++) { var tableEntry = deserializer.Deserialize <FileTableEntry>(context); var stream = new MemoryStream(); StreamUtil.Copy(reader.BaseStream, stream, tableEntry.Size); Files.Add(tableEntry.Path, stream); } }
private CachedTag ConvertCachedTagInstance(ModPackage modPack, CachedTag modTag) { Console.WriteLine($"Converting {modTag.Name}.{modTag.Group}..."); // tag has already been converted if (TagMapping.ContainsKey(modTag.Index)) { return(CacheContext.TagCache.GetTag(TagMapping[modTag.Index])); // get the matching tag in the destination package } // Determine if tag requires conversion if (modTag.DefinitionOffset == ((CachedTagHaloOnline)modTag).TotalSize) { //modtag references a base tag, figure out which one is it and add it to the mapping CachedTag baseTag = null; if (modTag.Index < CacheContext.TagCache.Count) { baseTag = CacheContext.TagCache.GetTag(modTag.Index); } // mod tag has a name, first check if baseTag name is null, else if the names don't match or group don't match if (baseTag != null && baseTag.Group == modTag.Group && baseTag.Name != null && baseTag.Name == modTag.Name) { TagMapping[modTag.Index] = baseTag.Index; return(baseTag); } else { // tag name/group doesn't match base tag, try to look for it CachedTag cacheTag; if (CacheTagsByName.TryGetValue($"{modTag.Name}.{modTag.Group}", out cacheTag)) { TagMapping[modTag.Index] = cacheTag.Index; return(cacheTag); } // Failed to find tag in base cache Console.Error.WriteLine($"Failed to find {modTag.Name}.{modTag.Group.ToString()} in the base cache, returning null tag reference."); //return null; throw new Exception("Failed to find tag when applying."); } } else { CachedTag newTag; if (!CacheTagsByName.TryGetValue($"{modTag.Name}.{modTag.Group}", out newTag)) { newTag = CacheContext.TagCache.AllocateTag(modTag.Group); newTag.Name = modTag.Name; } TagMapping.Add(modTag.Index, newTag.Index); var definitionType = TagDefinition.Find(modTag.Group.Tag); var deserializer = new TagDeserializer(CacheVersion.HaloOnline106708); var tagDefinition = deserializer.Deserialize(new ModPackageTagSerializationContext(modPack.TagCachesStreams[0], CacheContext, modPack, (CachedTagHaloOnline)modTag), definitionType); tagDefinition = ConvertData(modPack, tagDefinition); if (definitionType == typeof(ForgeGlobalsDefinition)) { tagDefinition = ConvertForgeGlobals((ForgeGlobalsDefinition)tagDefinition); } else if (definitionType == typeof(Scenario)) { tagDefinition = ConvertScenario(modPack, (Scenario)tagDefinition); } CacheContext.Serialize(CacheStream, newTag, tagDefinition); foreach (var resourcePointer in ((CachedTagHaloOnline)modTag).ResourcePointerOffsets) { var newTagHo = newTag as CachedTagHaloOnline; newTagHo.AddResourceOffset(resourcePointer); } return(newTag); } }
public override bool Execute(List <string> args) { if (args.Count != 3) { return(false); } var variantName = args[0]; var fileType = args[1]; var fileName = args[2]; if (fileType != "obj") { return(false); } // Find the variant to extract if (_model.RenderModel == null) { Console.Error.WriteLine("The model does not have a render model associated with it."); return(true); } var variant = _model.Variants.FirstOrDefault(v => (_stringIds.GetString(v.Name) ?? v.Name.ToString()) == variantName); if (variant == null && _model.Variants.Count > 0) { Console.Error.WriteLine("Unable to find variant \"{0}\"", variantName); Console.Error.WriteLine("Use \"listvariants\" to list available variants."); return(true); } // Load resource caches Console.WriteLine("Loading resource caches..."); var resourceManager = new ResourceDataManager(); try { resourceManager.LoadCachesFromDirectory(_fileInfo.DirectoryName); } catch { Console.WriteLine("Unable to load the resource .dat files."); Console.WriteLine("Make sure that they all exist and are valid."); return(true); } // Deserialize the render model tag Console.WriteLine("Reading model data..."); RenderModel renderModel; using (var cacheStream = _fileInfo.OpenRead()) { var renderModelContext = new TagSerializationContext(cacheStream, _cache, _model.RenderModel); renderModel = TagDeserializer.Deserialize <RenderModel>(renderModelContext); } if (renderModel.Resource == null) { Console.Error.WriteLine("Render model does not have a resource associated with it"); return(true); } // Deserialize the resource definition var resourceContext = new ResourceSerializationContext(renderModel.Resource); var definition = TagDeserializer.Deserialize <RenderGeometryResourceDefinition>(resourceContext); using (var resourceStream = new MemoryStream()) { // Extract the resource data resourceManager.Extract(renderModel.Resource, resourceStream); using (var objFile = new StreamWriter(File.Open(fileName, FileMode.Create, FileAccess.Write))) { var objExtractor = new ObjExtractor(objFile); var vertexCompressor = new VertexCompressor(renderModel.Compression[0]); // Create a (de)compressor from the first compression block if (variant != null) { // Extract each region in the variant foreach (var region in variant.Regions) { // Get the corresonding region in the render model tag if (region.RenderModelRegionIndex >= renderModel.Regions.Count) { continue; } var renderModelRegion = renderModel.Regions[region.RenderModelRegionIndex]; // Get the corresponding permutation in the render model tag // (Just extract the first permutation for now) if (region.Permutations.Count == 0) { continue; } var permutation = region.Permutations[0]; if (permutation.RenderModelPermutationIndex >= renderModelRegion.Permutations.Count) { continue; } var renderModelPermutation = renderModelRegion.Permutations[permutation.RenderModelPermutationIndex]; // Extract each mesh in the permutation var meshIndex = renderModelPermutation.MeshIndex; var meshCount = renderModelPermutation.MeshCount; var regionName = _stringIds.GetString(region.Name) ?? region.Name.ToString(); var permutationName = _stringIds.GetString(permutation.Name) ?? permutation.Name.ToString(); Console.WriteLine("Extracting {0} mesh(es) for {1}:{2}...", meshCount, regionName, permutationName); for (var i = 0; i < meshCount; i++) { // Create a MeshReader for the mesh and pass it to the obj extractor var meshReader = new MeshReader(renderModel.Meshes[meshIndex + i], definition); objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream); } } } else { // No variant - just extract every mesh Console.WriteLine("Extracting {0} mesh(es)...", renderModel.Meshes.Count); foreach (var mesh in renderModel.Meshes) { // Create a MeshReader for the mesh and pass it to the obj extractor var meshReader = new MeshReader(mesh, definition); objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream); } } objExtractor.Finish(); } } Console.WriteLine("Done!"); return(true); }
public bool Read(EndianReader reader) { if (!IsValid(reader)) { return(false); } var deserializer = new TagDeserializer(Version); while (!reader.EOF) { var dataContext = new DataSerializationContext(reader); var chunkHeaderPosition = reader.Position; var header = (BlfChunkHeader)deserializer.Deserialize(dataContext, typeof(BlfChunkHeader)); reader.SeekTo(chunkHeaderPosition); switch (header.Signature.ToString()) { case "_blf": ContentFlags |= BlfFileContentFlags.StartOfFile; StartOfFile = (BlfChunkStartOfFile)deserializer.Deserialize(dataContext, typeof(BlfChunkStartOfFile)); break; case "_eof": ContentFlags |= BlfFileContentFlags.EndOfFile; var position = reader.Position; EndOfFile = (BlfChunkEndOfFile)deserializer.Deserialize(dataContext, typeof(BlfChunkEndOfFile)); AuthenticationType = EndOfFile.AuthenticationType; switch (AuthenticationType) { case BlfAuthenticationType.None: break; case BlfAuthenticationType.CRC: reader.SeekTo(position); EndOfFileCRC = (BlfEndOfFileCRC)deserializer.Deserialize(dataContext, typeof(BlfEndOfFileCRC)); break; case BlfAuthenticationType.RSA: reader.SeekTo(position); EndOfFileRSA = (BlfEndOfFileRSA)deserializer.Deserialize(dataContext, typeof(BlfEndOfFileRSA)); break; case BlfAuthenticationType.SHA1: reader.SeekTo(position); EndOfFileSHA1 = (BlfEndOfFileSHA1)deserializer.Deserialize(dataContext, typeof(BlfEndOfFileSHA1)); break; } return(true); case "cmpn": ContentFlags |= BlfFileContentFlags.Campaign; Campaign = (BlfCampaign)deserializer.Deserialize(dataContext, typeof(BlfCampaign)); break; case "levl": ContentFlags |= BlfFileContentFlags.Scenario; Scenario = (BlfScenario)deserializer.Deserialize(dataContext, typeof(BlfScenario)); break; case "modp": ContentFlags |= BlfFileContentFlags.ModReference; ModReference = (BlfModPackageReference)deserializer.Deserialize(dataContext, typeof(BlfModPackageReference)); break; case "mapv": ContentFlags |= BlfFileContentFlags.MapVariant; MapVariant = (BlfMapVariant)deserializer.Deserialize(dataContext, typeof(BlfMapVariant)); break; case "tagn": ContentFlags |= BlfFileContentFlags.MapVariantTagNames; MapVariantTagNames = (BlfMapVariantTagNames)deserializer.Deserialize(dataContext, typeof(BlfMapVariantTagNames)); break; case "mpvr": ContentFlags |= BlfFileContentFlags.GameVariant; GameVariant = (BlfGameVariant)deserializer.Deserialize(dataContext, typeof(BlfGameVariant)); break; case "chdr": ContentFlags |= BlfFileContentFlags.ContentHeader; ContentHeader = (BlfContentHeader)deserializer.Deserialize(dataContext, typeof(BlfContentHeader)); break; case "scnd": case "scnc": case "mapi": case "flmh": case "flmd": case "athr": case "ssig": case "mps2": case "chrt": default: throw new NotImplementedException($"BLF chunk type {header.Signature.ToString()} not implemented!"); } } return(true); }
public void InjectDds(TagSerializer serializer, TagDeserializer deserializer, Bitmap bitmap, int imageIndex, Stream ddsStream, ResourceLocation location = ResourceLocation.Textures) { var resource = bitmap.Resources[imageIndex].Resource; var newResource = (resource == null); ResourceSerializationContext resourceContext; BitmapTextureInteropResource definition; if (newResource) { // Create a new resource reference resource = new PageableResource { Page = new RawPage(), Resource = new TagResourceGen3 { ResourceFixups = new List <TagResourceGen3.ResourceFixup>(), ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(), ResourceType = TagResourceTypeGen3.Bitmap, Unknown2 = 1 } }; bitmap.Resources[imageIndex].Resource = resource; resourceContext = new ResourceSerializationContext(CacheContext, resource); definition = new BitmapTextureInteropResource { Texture = new TagStructureReference <BitmapTextureInteropResource.BitmapDefinition> { Definition = new BitmapTextureInteropResource.BitmapDefinition { Data = new TagData(), UnknownData = new TagData(), } } }; } else { // Deserialize the old definition resourceContext = new ResourceSerializationContext(CacheContext, resource); definition = deserializer.Deserialize <BitmapTextureInteropResource>(resourceContext); } if (definition.Texture == null || definition.Texture.Definition == null) { throw new ArgumentException("Invalid bitmap definition"); } var texture = definition.Texture.Definition; var imageData = bitmap.Images[imageIndex]; // Read the DDS header and modify the definition to match var dds = DdsHeader.Read(ddsStream); var dataSize = (int)(ddsStream.Length - ddsStream.Position); texture.Data = new TagData(dataSize, new CacheResourceAddress(CacheResourceAddressType.Resource, 0)); texture.Width = (short)dds.Width; texture.Height = (short)dds.Height; texture.Depth = (sbyte)Math.Max(1, dds.Depth); texture.MipmapCount = (sbyte)Math.Max(1, dds.MipMapCount); texture.Type = BitmapDdsFormatDetection.DetectType(dds); texture.D3DFormat = (int)((dds.D3D10Format != DxgiFormat.Bc5UNorm) ? dds.FourCc : DdsFourCc.FromString("ATI2")); texture.Format = BitmapDdsFormatDetection.DetectFormat(dds); // Set flags based on the format switch (texture.Format) { case BitmapFormat.Dxt1: case BitmapFormat.Dxt3: case BitmapFormat.Dxt5: case BitmapFormat.Dxn: texture.Flags = BitmapFlags.Compressed; break; default: texture.Flags = BitmapFlags.None; break; } if ((texture.Width & (texture.Width - 1)) == 0 && (texture.Height & (texture.Height - 1)) == 0) { texture.Flags |= BitmapFlags.PowerOfTwoDimensions; } // If creating a new image, then add a new resource, otherwise replace the existing one if (newResource) { resource.ChangeLocation(location); CacheContext.AddResource(resource, ddsStream); } else { CacheContext.ReplaceResource(resource, ddsStream); } // Serialize the new resource definition serializer.Serialize(resourceContext, definition); // Modify the image data in the bitmap tag to match the definition imageData.Width = texture.Width; imageData.Height = texture.Height; imageData.Depth = texture.Depth; imageData.Type = texture.Type; imageData.Format = texture.Format; imageData.Flags = texture.Flags; imageData.MipmapCount = (sbyte)(texture.MipmapCount - 1); imageData.DataOffset = texture.Data.Address.Offset; imageData.DataSize = texture.Data.Size; imageData.Curve = (BitmapImageCurve)texture.Curve; }
public TagCacheGen2(EndianReader reader, MapFile mapFile) { Version = mapFile.Version; var tagDataSectionOffset = mapFile.Header.TagsHeaderAddress32; reader.SeekTo(tagDataSectionOffset); var dataContext = new DataSerializationContext(reader); var deserializer = new TagDeserializer(mapFile.Version); Header = deserializer.Deserialize <TagCacheGen2Header>(dataContext); BaseTagAddress = (Header.TagGroupsOffset - 0x20); // // Read tag groups // //seek to the tag groups offset, seems to be contiguous to the header reader.SeekTo(tagDataSectionOffset + Header.TagGroupsOffset - BaseTagAddress); // TODO: check how halo 2 xbox uses this for (int i = 0; i < Header.TagGroupCount; i++) { var tag = new Tag(reader.ReadInt32()); var group = new TagGroup() { Tag = tag, ParentTag = new Tag(reader.ReadInt32()), GrandparentTag = new Tag(reader.ReadInt32()), Name = StringId.Invalid // has no stringids in tag groups }; TagGroups[tag] = group; } // // Read cached tags // reader.SeekTo(tagDataSectionOffset + Header.TagsOffset - BaseTagAddress); for (int i = 0; i < Header.TagCount; i++) { var tag = new Tag(reader.ReadInt32()); uint ID = reader.ReadUInt32(); uint address = reader.ReadUInt32(); int size = reader.ReadInt32(); if (tag.Value == -1 || tag.Value == 0 || size == -1 || address == 0xFFFFFFFF || ID == 0 || ID == 0xFFFFFFFF) { Tags.Add(null); } else { Tags.Add(new CachedTagGen2((int)(ID & 0xFFFF), ID, TagGroups[tag], address, size, null)); } } reader.SeekTo(mapFile.Header.TagNameIndicesOffset); var tagNamesOffset = new int[Header.TagCount]; for (int i = 0; i < Header.TagCount; i++) { tagNamesOffset[i] = reader.ReadInt32(); } // // Read tag names // reader.SeekTo(mapFile.Header.TagNamesBufferOffset); for (int i = 0; i < tagNamesOffset.Length; i++) { if (Tags[i] == null) { continue; } if (tagNamesOffset[i] == -1) { continue; } reader.SeekTo(tagNamesOffset[i] + mapFile.Header.TagNamesBufferOffset); Tags[i].Name = reader.ReadNullTerminatedString(); } // // Set hardcoded tags from the header // var scnrTag = GetTag(Header.ScenarioID); HardcodedTags[scnrTag.Group.Tag] = (CachedTagGen2)scnrTag; var globalTag = GetTag(Header.GlobalsID); HardcodedTags[globalTag.Group.Tag] = (CachedTagGen2)globalTag; }
public void InjectDds(TagSerializer serializer, TagDeserializer deserializer, Bitmap bitmap, int imageIndex, Stream ddsStream) { var resource = bitmap.Resources[imageIndex].Resource; var newResource = (resource == null); ResourceSerializationContext resourceContext; BitmapTextureResourceDefinition definition; if (newResource) { // Create a new resource reference resource = new ResourceReference { DefinitionFixups = new List<ResourceDefinitionFixup>(), D3DObjectFixups = new List<D3DObjectFixup>(), Type = 1, // TODO: Map out this type enum instead of using numbers Unknown68 = 1 }; bitmap.Resources[imageIndex].Resource = resource; resourceContext = new ResourceSerializationContext(resource); definition = new BitmapTextureResourceDefinition { Texture = new D3DPointer<BitmapTextureResourceDefinition.BitmapDefinition> { Definition = new BitmapTextureResourceDefinition.BitmapDefinition() } }; } else { // Deserialize the old definition resourceContext = new ResourceSerializationContext(resource); definition = deserializer.Deserialize<BitmapTextureResourceDefinition>(resourceContext); } if (definition.Texture == null || definition.Texture.Definition == null) throw new ArgumentException("Invalid bitmap definition"); var texture = definition.Texture.Definition; var imageData = bitmap.Images[imageIndex]; // Read the DDS header and modify the definition to match var dds = DdsHeader.Read(ddsStream); var dataSize = (int)(ddsStream.Length - ddsStream.Position); texture.Data = new ResourceDataReference(dataSize, new ResourceAddress(ResourceAddressType.Resource, 0)); texture.Width = (short)dds.Width; texture.Height = (short)dds.Height; texture.Depth = (sbyte)Math.Max(1, dds.Depth); texture.Levels = (sbyte)Math.Max(1, dds.MipMapCount); texture.Type = BitmapDdsFormatDetection.DetectType(dds); texture.D3DFormatUnused = (int)((dds.D3D10Format != DxgiFormat.Bc5UNorm) ? dds.FourCc : DdsFourCc.FromString("ATI2")); texture.Format = BitmapDdsFormatDetection.DetectFormat(dds); // Set flags based on the format switch (texture.Format) { case BitmapFormat.Dxt1: case BitmapFormat.Dxt3: case BitmapFormat.Dxt5: case BitmapFormat.Dxn: texture.Flags = BitmapFlags.Compressed; break; default: texture.Flags = BitmapFlags.None; break; } if ((texture.Width & (texture.Width - 1)) == 0 && (texture.Height & (texture.Height - 1)) == 0) texture.Flags |= BitmapFlags.PowerOfTwoDimensions; // If creating a new image, then add a new resource, otherwise replace the existing one if (newResource) _resourceManager.Add(resource, ResourceLocation.Textures, ddsStream); else _resourceManager.Replace(resource, ddsStream); // Serialize the new resource definition serializer.Serialize(resourceContext, definition); // Modify the image data in the bitmap tag to match the definition imageData.Width = texture.Width; imageData.Height = texture.Height; imageData.Depth = texture.Depth; imageData.Type = texture.Type; imageData.Format = texture.Format; imageData.Flags = texture.Flags; imageData.MipmapCount = (sbyte)(texture.Levels - 1); imageData.DataOffset = texture.Data.Address.Offset; imageData.DataSize = texture.Data.Size; imageData.Unknown15 = texture.Unknown35; }
public override bool Execute(List <string> args) { if (args.Count != 1) { return(false); } var outDir = args[0]; Directory.CreateDirectory(outDir); Console.WriteLine("Loading resource caches..."); var resourceManager = new ResourceDataManager(); try { resourceManager.LoadCachesFromDirectory(_fileInfo.DirectoryName); } catch { Console.WriteLine("Unable to load the resource .dat files."); Console.WriteLine("Make sure that they all exist and are valid."); return(true); } var extractor = new BitmapDdsExtractor(resourceManager); var count = 0; using (var tagsStream = _fileInfo.OpenRead()) { foreach (var tag in _cache.Tags.FindAllByClass("bitm")) { Console.Write("Extracting "); TagPrinter.PrintTagShort(tag); try { var tagContext = new TagSerializationContext(tagsStream, _cache, tag); var bitmap = TagDeserializer.Deserialize <Bitmap>(tagContext); var ddsOutDir = outDir; if (bitmap.Images.Count > 1) { ddsOutDir = Path.Combine(outDir, tag.Index.ToString("X8")); Directory.CreateDirectory(ddsOutDir); } for (var i = 0; i < bitmap.Images.Count; i++) { var outPath = Path.Combine(ddsOutDir, ((bitmap.Images.Count > 1) ? i.ToString() : tag.Index.ToString("X8")) + ".dds"); using (var outStream = File.Open(outPath, FileMode.Create, FileAccess.Write)) { extractor.ExtractDds(bitmap, i, outStream); } } count++; } catch (Exception ex) { Console.WriteLine("ERROR: Failed to extract bitmap: " + ex.Message); } } } Console.WriteLine("Extracted {0} bitmaps.", count); return(true); }
public void InjectDds(TagSerializer serializer, TagDeserializer deserializer, Bitmap bitmap, int imageIndex, Stream ddsStream) { var resource = bitmap.Resources[imageIndex].Resource; var newResource = (resource == null); ResourceSerializationContext resourceContext; BitmapTextureResourceDefinition definition; if (newResource) { // Create a new resource reference resource = new ResourceReference { DefinitionFixups = new List <ResourceDefinitionFixup>(), D3DObjectFixups = new List <D3DObjectFixup>(), Type = 1, // TODO: Map out this type enum instead of using numbers Unknown68 = 1 }; bitmap.Resources[imageIndex].Resource = resource; resourceContext = new ResourceSerializationContext(resource); definition = new BitmapTextureResourceDefinition { Texture = new D3DPointer <BitmapTextureResourceDefinition.BitmapDefinition> { Definition = new BitmapTextureResourceDefinition.BitmapDefinition() } }; } else { // Deserialize the old definition resourceContext = new ResourceSerializationContext(resource); definition = deserializer.Deserialize <BitmapTextureResourceDefinition>(resourceContext); } if (definition.Texture == null || definition.Texture.Definition == null) { throw new ArgumentException("Invalid bitmap definition"); } var texture = definition.Texture.Definition; var imageData = bitmap.Images[imageIndex]; // Read the DDS header and modify the definition to match var dds = DdsHeader.Read(ddsStream); var dataSize = (int)(ddsStream.Length - ddsStream.Position); texture.Data = new ResourceDataReference(dataSize, new ResourceAddress(ResourceAddressType.Resource, 0)); texture.Width = (short)dds.Width; texture.Height = (short)dds.Height; texture.Depth = (sbyte)Math.Max(1, dds.Depth); texture.Levels = (sbyte)Math.Max(1, dds.MipMapCount); texture.Type = BitmapDdsFormatDetection.DetectType(dds); texture.D3DFormatUnused = (int)((dds.D3D10Format != DxgiFormat.Bc5UNorm) ? dds.FourCc : DdsFourCc.FromString("ATI2")); texture.Format = BitmapDdsFormatDetection.DetectFormat(dds); // Set flags based on the format switch (texture.Format) { case BitmapFormat.Dxt1: case BitmapFormat.Dxt3: case BitmapFormat.Dxt5: case BitmapFormat.Dxn: texture.Flags = BitmapFlags.Compressed; break; default: texture.Flags = BitmapFlags.None; break; } if ((texture.Width & (texture.Width - 1)) == 0 && (texture.Height & (texture.Height - 1)) == 0) { texture.Flags |= BitmapFlags.PowerOfTwoDimensions; } // If creating a new image, then add a new resource, otherwise replace the existing one if (newResource) { _resourceManager.Add(resource, ResourceLocation.Textures, ddsStream); } else { _resourceManager.Replace(resource, ddsStream); } // Serialize the new resource definition serializer.Serialize(resourceContext, definition); // Modify the image data in the bitmap tag to match the definition imageData.Width = texture.Width; imageData.Height = texture.Height; imageData.Depth = texture.Depth; imageData.Type = texture.Type; imageData.Format = texture.Format; imageData.Flags = texture.Flags; imageData.MipmapCount = (sbyte)(texture.Levels - 1); imageData.DataOffset = texture.Data.Address.Offset; imageData.DataSize = texture.Data.Size; imageData.Unknown15 = texture.Unknown35; }
public override bool Execute(List<string> args) { if (args.Count != 2) return false; // // Verify the xbox scenario_structure_bsp tag // var bspName = args[0]; var newTagIndex = ArgumentParser.ParseTagIndex(Info, args[1]); CacheFile.IndexItem item = null; Console.WriteLine("Verifying xbox tag..."); foreach (var tag in BlamCache.IndexItems) { if (tag.ClassCode == "sbsp" && tag.Filename == bspName) { item = tag; break; } } if (item == null) { Console.WriteLine("Xbox tag does not exist: " + args[0]); return false; } // // Load the xbox scenario_structure_bsp tag // var xboxContext = new XboxSerializationContext(item); var deserializer = new TagDeserializer(BlamCache.Version); var sbsp = deserializer.Deserialize<ScenarioStructureBsp>(xboxContext); // blank resources that will be generated/converted from ODST automatically later var Resource1 = new ResourceReference() { Index = 1337, Owner = newTagIndex }; // render geo 1 var Resource2 = new ResourceReference() { Index = 1337, Owner = newTagIndex }; // render geo 2 var Resource3 = new ResourceReference() { Index = 1337, Owner = newTagIndex }; // collision BSP tag data var Resource4 = new ResourceReference() { Index = 1337, Owner = newTagIndex }; // other tag data and shit (unknown raw 3rd in halo 3, etc.) // Set the resource refs in the tag to the blank ones we just made sbsp.Geometry.Resource = Resource1; sbsp.Geometry2.Resource = Resource2; sbsp.CollisionBSPResource = Resource3; sbsp.Resource4 = Resource4; using (var cacheStream = Info.CacheFile.Open(FileMode.Open, FileAccess.ReadWrite)) { Console.WriteLine("Writing ElDewrito tag to tag " + newTagIndex+"..."); var context = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIDs, Info.Cache.Tags[newTagIndex.Index]); Info.Serializer.Serialize(context, sbsp); } return true; }