public BitmapDdsExtractor(ResourceDataManager resourceManager) { _resourceManager = resourceManager; }
/// <summary> /// Creates a CollisionModel bsp from a Scenario StructureBsp. /// This does not work for sbsps with > 65536 planes, which use a /// larger encoding for their bsp related structs differing from the /// struct used in common with collision model bsps. /// </summary> /// <returns></returns> public static BSP fromSbsp(ScenarioStructureBsp sbsp, OpenTagCache info) { // Need to work out how to do that class attribute enumeration thing // so all of this folds down to < 10 lines BSP bsp = fromSbspInit(sbsp); var resource = sbsp.Resource3; var resourceManager = new ResourceDataManager(); try { resourceManager.LoadCachesFromDirectory(info.CacheFile.DirectoryName); } catch { Console.WriteLine("Unable to load the resource .dat files."); Console.WriteLine("Make sure that they all exist and are valid."); } //Create a binary reader for the resource Stream stream = new MemoryStream(); resourceManager.Extract(sbsp.Resource3, stream); BinaryReader reader = new BinaryReader(stream); reader.BaseStream.Position = 0; Console.WriteLine("Stream position: {0:X8}", reader.BaseStream.Position); for (int i = 0; i < bsp.Bsp3dNodes.Count; ++i) { BSP.Bsp3dNode node = new BSP.Bsp3dNode(); node.Plane = reader.ReadInt16(); node.BackChildLower = reader.ReadByte(); node.BackChildMid = reader.ReadByte(); node.BackChildUpper = reader.ReadByte(); node.FrontChildLower = reader.ReadByte(); node.FrontChildMid = reader.ReadByte(); node.FrontChildUpper = reader.ReadByte(); bsp.Bsp3dNodes[i] = node; } //Align to the next multiple of 16 reader.BaseStream.Position = -((-reader.BaseStream.Position) & ~0xf); Console.WriteLine("Stream position: {0:X8}", reader.BaseStream.Position); for (int i = 0; i < bsp.Planes.Count; ++i) { BSP.Plane plane = new BSP.Plane(); plane.PlaneI = reader.ReadSingle(); plane.PlaneJ = reader.ReadSingle(); plane.PlaneK = reader.ReadSingle(); plane.PlaneD = reader.ReadSingle(); bsp.Planes[i] = plane; } //Put here for consistency reader.BaseStream.Position = -((-reader.BaseStream.Position) & ~0xf); Console.WriteLine("Stream position: {0:X8}", reader.BaseStream.Position); for (int i = 0; i < bsp.Leaves.Count; ++i) { BSP.Leaf leaf = new BSP.Leaf(); leaf.Flags = reader.ReadInt16(); leaf.Bsp2dReferenceCount = reader.ReadInt16(); leaf.Unknown = reader.ReadInt16(); leaf.FirstBsp2dReference = reader.ReadInt16(); bsp.Leaves[i] = leaf; } //Align to the next multiple of 16 reader.BaseStream.Position = -((-reader.BaseStream.Position) & ~0xf); Console.WriteLine("Stream position: {0:X8}", reader.BaseStream.Position); for (int i = 0; i < bsp.Bsp2dReferences.Count; ++i) { BSP.Bsp2dReference bsp2dref = new BSP.Bsp2dReference(); bsp2dref.Plane = reader.ReadInt16(); bsp2dref.Bsp2dNode = reader.ReadInt16(); bsp.Bsp2dReferences[i] = bsp2dref; } //Align to the next multiple of 16 reader.BaseStream.Position = -((-reader.BaseStream.Position) & ~0xf); Console.WriteLine("Stream position: {0:X8}", reader.BaseStream.Position); for (int i = 0; i < bsp.Bsp2dNodes.Count; ++i) { BSP.Bsp2dNode node = new BSP.Bsp2dNode(); node.PlaneI = reader.ReadSingle(); node.PlaneJ = reader.ReadSingle(); node.PlaneD = reader.ReadSingle(); node.LeftChild = reader.ReadInt16(); node.RightChild = reader.ReadInt16(); bsp.Bsp2dNodes[i] = node; } //Put here for consistency reader.BaseStream.Position = -((-reader.BaseStream.Position) & ~0xf); Console.WriteLine("Stream position: {0:X8}", reader.BaseStream.Position); for (int i = 0; i < bsp.Surfaces.Count; ++i) { BSP.Surface surface = new BSP.Surface(); surface.Plane = reader.ReadUInt16(); surface.FirstEdge = reader.ReadUInt16(); surface.Material = reader.ReadInt16(); surface.Unknown = reader.ReadInt16(); surface.BreakableSurface = reader.ReadInt16(); surface.Unknown2 = reader.ReadInt16(); bsp.Surfaces[i] = surface; } //Align to the next multiple of 16 reader.BaseStream.Position = -((-reader.BaseStream.Position) & ~0xf); Console.WriteLine("Stream position: {0:X8}", reader.BaseStream.Position); for (int i = 0; i < bsp.Edges.Count; ++i) { BSP.Edge edge = new BSP.Edge(); edge.StartVertex = reader.ReadUInt16(); edge.EndVertex = reader.ReadUInt16(); edge.ForwardEdge = reader.ReadUInt16(); edge.ReverseEdge = reader.ReadUInt16(); edge.LeftSurface = reader.ReadUInt16(); edge.RightSurface = reader.ReadUInt16(); bsp.Edges[i] = edge; } //Align to the next multiple of 16 reader.BaseStream.Position = -((-reader.BaseStream.Position) & ~0xf); Console.WriteLine("Stream position: {0:X8}", reader.BaseStream.Position); for (int i = 0; i < bsp.Vertices.Count; ++i) { BSP.Vertex vert = new BSP.Vertex(); vert.PointX = reader.ReadSingle(); vert.PointY = reader.ReadSingle(); vert.PointZ = reader.ReadSingle(); vert.FirstEdge = reader.ReadInt16(); vert.Unknown = reader.ReadInt16(); bsp.Vertices[i] = vert; } return bsp; }
public BitmapDdsInjector(ResourceDataManager resourceManager) { _resourceManager = resourceManager; }
private object ConvertStructure(object data, Type type, OpenTagCache srcInfo, Stream srcStream, ResourceDataManager srcResources, OpenTagCache destInfo, Stream destStream, ResourceDataManager destResources, TagVersionMap tagMap) { // Convert each field var enumerator = new TagFieldEnumerator(new TagStructureInfo(type, destInfo.Version)); while (enumerator.Next()) { var oldValue = enumerator.Field.GetValue(data); var newValue = Convert(oldValue, srcInfo, srcStream, srcResources, destInfo, destStream, destResources, tagMap); enumerator.Field.SetValue(data, newValue); } // Perform fixups FixObjectTypes(data, type, srcInfo); FixShaders(data); var scenario = data as Scenario; if (scenario != null) { FixScenario(scenario); } return(data); }
private ResourceReference ConvertResource(ResourceReference resource, OpenTagCache srcInfo, ResourceDataManager srcResources, OpenTagCache destInfo, ResourceDataManager destResources) { if (resource == null) { return(null); } Console.WriteLine("- Copying resource {0} in {1}...", resource.Index, resource.GetLocation()); var data = srcResources.ExtractRaw(resource); var newLocation = FixResourceLocation(resource.GetLocation(), srcInfo.Version, destInfo.Version); destResources.AddRaw(resource, newLocation, data); return(resource); }
private Array ConvertArray(Array array, OpenTagCache srcInfo, Stream srcStream, ResourceDataManager srcResources, OpenTagCache destInfo, Stream destStream, ResourceDataManager destResources, TagVersionMap tagMap) { if (array.GetType().GetElementType().IsPrimitive) { return(array); } for (var i = 0; i < array.Length; i++) { var oldValue = array.GetValue(i); var newValue = Convert(oldValue, srcInfo, srcStream, srcResources, destInfo, destStream, destResources, tagMap); array.SetValue(newValue, i); } return(array); }
private object ConvertList(object list, Type type, OpenTagCache srcInfo, Stream srcStream, ResourceDataManager srcResources, OpenTagCache destInfo, Stream destStream, ResourceDataManager destResources, TagVersionMap tagMap) { if (type.GenericTypeArguments[0].IsPrimitive) { return(list); } var count = (int)type.GetProperty("Count").GetValue(list); var getItem = type.GetMethod("get_Item"); var setItem = type.GetMethod("set_Item"); for (var i = 0; i < count; i++) { var oldValue = getItem.Invoke(list, new object[] { i }); var newValue = Convert(oldValue, srcInfo, srcStream, srcResources, destInfo, destStream, destResources, tagMap); setItem.Invoke(list, new object[] { i, newValue }); } return(list); }
private object Convert(object data, OpenTagCache srcInfo, Stream srcStream, ResourceDataManager srcResources, OpenTagCache destInfo, Stream destStream, ResourceDataManager destResources, TagVersionMap tagMap) { if (data == null) { return(null); } var type = data.GetType(); if (type.IsPrimitive) { return(data); } if (type == typeof(StringId)) { return(ConvertStringId((StringId)data, srcInfo, destInfo)); } if (type == typeof(TagInstance)) { return(ConvertTag((TagInstance)data, srcInfo, srcStream, srcResources, destInfo, destStream, destResources, tagMap)); } if (type == typeof(ResourceReference)) { return(ConvertResource((ResourceReference)data, srcInfo, srcResources, destInfo, destResources)); } if (type == typeof(GeometryReference)) { return(ConvertGeometry((GeometryReference)data, srcInfo, srcResources, destInfo, destResources)); } if (type.IsArray) { return(ConvertArray((Array)data, srcInfo, srcStream, srcResources, destInfo, destStream, destResources, tagMap)); } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List <>)) { return(ConvertList(data, type, srcInfo, srcStream, srcResources, destInfo, destStream, destResources, tagMap)); } if (type.GetCustomAttributes(typeof(TagStructureAttribute), false).Length > 0) { return(ConvertStructure(data, type, srcInfo, srcStream, srcResources, destInfo, destStream, destResources, tagMap)); } return(data); }
private TagInstance ConvertTag(TagInstance srcTag, OpenTagCache srcInfo, Stream srcStream, ResourceDataManager srcResources, OpenTagCache destInfo, Stream destStream, ResourceDataManager destResources, TagVersionMap tagMap) { TagPrinter.PrintTagShort(srcTag); // Uncomment this to use 0x101F for all shaders /*if (srcTag.IsClass("rm ")) * return destInfo.Cache.Tags[0x101F];*/ // Check if the tag is in the map, and just return the translated tag if so var destIndex = tagMap.Translate(srcInfo.Version, srcTag.Index, destInfo.Version); if (destIndex >= 0) { Console.WriteLine("- Using already-known index {0:X4}", destIndex); return(destInfo.Cache.Tags[destIndex]); } // Deserialize the tag from the source cache var structureType = TagStructureTypes.FindByGroupTag(srcTag.Group.Tag); var srcContext = new TagSerializationContext(srcStream, srcInfo.Cache, srcInfo.StringIds, srcTag); var tagData = srcInfo.Deserializer.Deserialize(srcContext, structureType); // Uncomment this to use 0x101F in place of shaders that need conversion /*if (tagData is RenderMethod) * { * var rm = (RenderMethod)tagData; * foreach (var prop in rm.ShaderProperties) * { * if (tagMap.Translate(srcInfo.Version, prop.Template.Index, destInfo.Version) < 0) * return destInfo.Cache.Tags[0x101F]; * } * }*/ // Allocate a new tag and create a mapping for it var newTag = destInfo.Cache.AllocateTag(srcTag.Group); tagMap.Add(srcInfo.Version, srcTag.Index, destInfo.Version, newTag.Index); if (srcTag.IsInGroup("decs") || srcTag.IsInGroup("rmd ")) { _isDecalShader = true; } // Convert it tagData = Convert(tagData, srcInfo, srcStream, srcResources, destInfo, destStream, destResources, tagMap); if (srcTag.IsInGroup("decs") || srcTag.IsInGroup("rmd ")) { _isDecalShader = false; } // Re-serialize into the destination cache var destContext = new TagSerializationContext(destStream, destInfo.Cache, destInfo.StringIds, newTag); destInfo.Serializer.Serialize(destContext, tagData); return(newTag); }
private bool ExtractAMF(Model.Variant variant, string fileName) { // Load resource caches Console.WriteLine("Loading resource caches..."); var resourceManager = new ResourceDataManager(); try { resourceManager.LoadCachesFromDirectory(Info.CacheFile.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 = Info.CacheFile.OpenRead()) { var renderModelContext = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIDs, Definition.RenderModel); renderModel = Info.Deserializer.Deserialize <RenderModel>(renderModelContext); } if (renderModel.Geometry.Resource == null) { Console.WriteLine("Render model does not have a resource associated with it"); return(true); } // Deserialize the resource definition var resourceContext = new ResourceSerializationContext(renderModel.Geometry.Resource); var definition = Info.Deserializer.Deserialize <RenderGeometryResourceDefinition>(resourceContext); using (var resourceStream = new MemoryStream()) { // Extract the resource data resourceManager.Extract(renderModel.Geometry.Resource, resourceStream); var regionMeshes = new Dictionary <string, Mesh>(); foreach (var region in variant.Regions) { regionMeshes[Info.StringIDs.GetString(region.Name)] = renderModel.Geometry.Meshes[region.RenderModelRegionIndex]; } var headerAddressList = new List <int>(); var headerValueList = new List <int>(); var markerAddressList = new List <int>(); var markerValueList = new List <int>(); var permAddressList = new List <int>(); var permValueList = new List <int>(); var vertAddressList = new List <int>(); var indxAddressList = new List <int>(); var meshAddressList = new List <int>(); using (var bw = new BinaryWriter(File.Create(fileName))) { #region Header bw.Write("AMF!".ToCharArray()); bw.Write(2.0f); //format version bw.Write((Info.StringIDs.GetString(renderModel.Name) + "\0").ToCharArray()); bw.Write(renderModel.Nodes.Count); headerAddressList.Add((int)bw.BaseStream.Position); bw.Write(0); bw.Write(renderModel.MarkerGroups.Count); headerAddressList.Add((int)bw.BaseStream.Position); bw.Write(0); bw.Write(regionMeshes.Count); headerAddressList.Add((int)bw.BaseStream.Position); bw.Write(0); bw.Write(renderModel.Materials.Count); headerAddressList.Add((int)bw.BaseStream.Position); bw.Write(0); #endregion #region Nodes headerValueList.Add((int)bw.BaseStream.Position); foreach (var node in renderModel.Nodes) { bw.Write((Info.StringIDs.GetString(node.Name) + "\0").ToCharArray()); bw.Write((short)node.ParentNode); bw.Write((short)node.FirstChildNode); bw.Write((short)node.NextSiblingNode); bw.Write(node.DefaultTranslation.X * 100); bw.Write(node.DefaultTranslation.Y * 100); bw.Write(node.DefaultTranslation.Z * 100); bw.Write(node.DefaultRotation.X); bw.Write(node.DefaultRotation.Y); bw.Write(node.DefaultRotation.Z); bw.Write(node.DefaultRotation.W); } #endregion #region Marker Groups headerValueList.Add((int)bw.BaseStream.Position); foreach (var group in renderModel.MarkerGroups) { bw.Write((Info.StringIDs.GetString(group.Name) + "\0").ToCharArray()); bw.Write(group.Markers.Count); markerAddressList.Add((int)bw.BaseStream.Position); bw.Write(0); } #endregion #region Markers foreach (var group in renderModel.MarkerGroups) { markerValueList.Add((int)bw.BaseStream.Position); foreach (var marker in group.Markers) { bw.Write((byte)marker.RegionIndex); bw.Write((byte)marker.PermutationIndex); bw.Write((short)marker.NodeIndex); bw.Write(marker.Translation.X * 100); bw.Write(marker.Translation.Y * 100); bw.Write(marker.Translation.Z * 100); bw.Write(marker.Rotation.X); bw.Write(marker.Rotation.Y); bw.Write(marker.Rotation.Z); bw.Write(marker.Rotation.W); } } #endregion #region Regions headerValueList.Add((int)bw.BaseStream.Position); foreach (var region in renderModel.Regions) { bw.Write((Info.StringIDs.GetString(region.Name) + "\0").ToCharArray()); bw.Write(regionMeshes.Count); permAddressList.Add((int)bw.BaseStream.Position); bw.Write(0); } #endregion #region Permutations foreach (var part in regionMeshes) { permValueList.Add((int)bw.BaseStream.Position); bw.Write((Info.StringIDs.GetString(variant.Name) + "\0").ToCharArray()); if (part.Value.Type == VertexType.Rigid) { bw.Write((byte)1); } else if (part.Value.Type == VertexType.Skinned) { bw.Write((byte)2); } else { throw new NotImplementedException(); } bw.Write((byte)part.Value.RigidNodeIndex); bw.Write(definition.VertexBuffers[part.Value.VertexBuffers[0]].Definition.Count); vertAddressList.Add((int)bw.BaseStream.Position); bw.Write(0); int count = 0; foreach (var submesh in part.Value.SubParts) { count += submesh.IndexCount; } bw.Write(count); indxAddressList.Add((int)bw.BaseStream.Position); bw.Write(0); bw.Write(part.Value.SubParts.Count); meshAddressList.Add((int)bw.BaseStream.Position); bw.Write(0); bw.Write(float.NaN); //no transforms (render_models are pre-transformed) } #endregion } } return(true); }
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" && fileType != "amf") { return(false); } // Find the variant to extract if (Definition.RenderModel == null) { Console.WriteLine("The model does not have a render model associated with it."); return(true); } var variant = Definition.Variants.FirstOrDefault(v => (Info.StringIDs.GetString(v.Name) ?? v.Name.ToString()) == variantName); if (variant == null && Definition.Variants.Count > 0) { Console.WriteLine("Unable to find variant \"{0}\"", variantName); Console.WriteLine("Use \"listvariants\" to list available variants."); return(true); } if (fileType == "amf") { return(ExtractAMF(variant, fileName)); } // Load resource caches Console.WriteLine("Loading resource caches..."); var resourceManager = new ResourceDataManager(); try { resourceManager.LoadCachesFromDirectory(Info.CacheFile.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 = Info.CacheFile.OpenRead()) { var renderModelContext = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIDs, Definition.RenderModel); renderModel = Info.Deserializer.Deserialize <RenderModel>(renderModelContext); } if (renderModel.Geometry.Resource == null) { Console.WriteLine("Render model does not have a resource associated with it"); return(true); } // Deserialize the resource definition var resourceContext = new ResourceSerializationContext(renderModel.Geometry.Resource); var definition = Info.Deserializer.Deserialize <RenderGeometryResourceDefinition>(resourceContext); using (var resourceStream = new MemoryStream()) { // Extract the resource data resourceManager.Extract(renderModel.Geometry.Resource, resourceStream); Directory.CreateDirectory(Path.GetDirectoryName(fileName)); using (var objFile = new StreamWriter(File.Open(fileName, FileMode.Create, FileAccess.Write))) { var objExtractor = new ObjExtractor(objFile); var vertexCompressor = new VertexCompressor(renderModel.Geometry.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 < 0 || 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 = Info.StringIDs.GetString(region.Name) ?? region.Name.ToString(); var permutationName = Info.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(Info.Version, renderModel.Geometry.Meshes[meshIndex + i], definition); objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream); } } } else { // No variant - just extract every mesh Console.WriteLine("Extracting {0} mesh(es)...", renderModel.Geometry.Meshes.Count); foreach (var mesh in renderModel.Geometry.Meshes) { // Create a MeshReader for the mesh and pass it to the obj extractor var meshReader = new MeshReader(Info.Version, mesh, definition); objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream); } } objExtractor.Finish(); } } Console.WriteLine("Done!"); return(true); }
public override bool Execute(List <string> args) { if (args.Count != 1) { return(false); } // // Verify and load the blam shader // var shaderName = args[0]; CacheBase.IndexItem item = null; Console.WriteLine("Verifying blam shader tag..."); foreach (var tag in BlamCache.IndexItems) { if ((tag.ParentClass == "rm") && tag.Filename == shaderName) { item = tag; break; } } if (item == null) { Console.WriteLine("Blam shader tag does not exist: " + shaderName); return(false); } var renderMethod = DefinitionsManager.rmsh(BlamCache, item); var templateItem = BlamCache.IndexItems.Find(i => i.ID == renderMethod.Properties[0].TemplateTagID); var template = DefinitionsManager.rmt2(BlamCache, templateItem); // // Determine the blam shader's base bitmap // var bitmapIndex = -1; var bitmapArgName = ""; for (var i = 0; i < template.UsageBlocks.Count; i++) { var entry = template.UsageBlocks[i]; if (entry.Usage.StartsWith("base_map") || entry.Usage.StartsWith("diffuse_map") || entry.Usage == "foam_texture") { bitmapIndex = i; bitmapArgName = entry.Usage; break; } } // // Load and decode the blam shader's base bitmap // var bitmItem = BlamCache.IndexItems.Find(i => i.ID == renderMethod.Properties[0].ShaderMaps[bitmapIndex].BitmapTagID); var bitm = DefinitionsManager.bitm(BlamCache, bitmItem); var submap = bitm.Bitmaps[0]; byte[] raw; if (BlamCache.Version <= DefinitionSet.Halo2Vista) { raw = BlamCache.GetRawFromID(submap.PixelsOffset, submap.RawSize); } else { if (bitm.RawChunkBs.Count > 0) { int rawID = bitm.RawChunkBs[submap.InterleavedIndex].RawID; byte[] buffer = BlamCache.GetRawFromID(rawID); raw = new byte[submap.RawSize]; Array.Copy(buffer, submap.Index2 * submap.RawSize, raw, 0, submap.RawSize); } else { int rawID = bitm.RawChunkAs[0].RawID; raw = BlamCache.GetRawFromID(rawID, submap.RawSize); } } var vHeight = submap.VirtualHeight; var vWidth = submap.VirtualWidth; var ms = new MemoryStream(); var bw = new BinaryWriter(ms); if (submap.Flags.Values[3]) { raw = DXTDecoder.ConvertToLinearTexture(raw, vWidth, vHeight, submap.Format); } if (submap.Format != BitmapFormat.A8R8G8B8) { for (int i = 0; i < raw.Length; i += 2) { Array.Reverse(raw, i, 2); } } else { for (int i = 0; i < (raw.Length); i += 4) { Array.Reverse(raw, i, 4); } } new DDS(submap).Write(bw); bw.Write(raw); raw = ms.ToArray(); bw.Close(); bw.Dispose(); // // ElDorado Serialization // using (var cacheStream = Info.CacheFile.Open(FileMode.Open, FileAccess.ReadWrite)) { // // Create the new eldorado bitmap // var resourceManager = new ResourceDataManager(); resourceManager.LoadCachesFromDirectory(Info.CacheFile.DirectoryName); var newBitm = Info.Cache.DuplicateTag(cacheStream, Info.Cache.Tags[0x101F]); var bitmap = new TagDefinitions.Bitmap { Flags = TagDefinitions.Bitmap.RuntimeFlags.UseResource, Sequences = new List <TagDefinitions.Bitmap.Sequence> { new TagDefinitions.Bitmap.Sequence { Name = "", FirstBitmapIndex = 0, BitmapCount = 1 } }, Images = new List <TagDefinitions.Bitmap.Image> { new TagDefinitions.Bitmap.Image { Signature = new Tag("bitm").Value, Unknown28 = -1 } }, Resources = new List <TagDefinitions.Bitmap.BitmapResource> { new TagDefinitions.Bitmap.BitmapResource() } }; using (var imageStream = new MemoryStream(raw)) { var injector = new BitmapDdsInjector(resourceManager); imageStream.Seek(0, SeekOrigin.Begin); injector.InjectDds(Info.Serializer, Info.Deserializer, bitmap, 0, imageStream); } var context = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIDs, newBitm); Info.Serializer.Serialize(context, bitmap); // // Create the new eldorado shader // var newRmsh = Info.Cache.DuplicateTag(cacheStream, Info.Cache.Tags[0x331A]); context = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIDs, newRmsh); var shader = Info.Deserializer.Deserialize <TagDefinitions.Shader>(context); shader.ShaderProperties[0].ShaderMaps[0].Bitmap = newBitm; Info.Serializer.Serialize(context, shader); Console.WriteLine("Done! New shader tag is 0x" + newRmsh.Index.ToString("X8")); } return(true); }