/// <summary> /// Gets an image from a bitmap tag. /// </summary> /// <param name="Cache">The CacheFile containing the bitmap tag.</param> /// <param name="bitm">The bitmap tag.</param> /// <param name="Index">The index of the BitmapData chunk to use.</param> /// <param name="Alpha">Whether to include the alpha channel in the image.</param> /// <returns>The image from the bitmap tag as a Bitmap.</returns> public static Bitmap GetBitmapByTag(CacheBase Cache, bitmap bitm, int Index, PixelFormat PF) { try { var submap = bitm.Bitmaps[Index]; byte[] raw; if (Cache.Version <= DefinitionSet.Halo2Vista) { raw = Cache.GetRawFromID(submap.PixelsOffset, submap.RawSize); } else { if (bitm.RawChunkBs.Count > 0) { int rawID = bitm.RawChunkBs[submap.InterleavedIndex].RawID; byte[] buffer = Cache.GetRawFromID(rawID); raw = new byte[submap.RawSize]; Array.Copy(buffer, submap.Index2 * submap.RawSize, raw, 0, submap.RawSize); } else { int rawID = bitm.RawChunkAs[Index].RawID; raw = Cache.GetRawFromID(rawID, submap.RawSize); } } int vHeight = submap.VirtualHeight; int vWidth = submap.VirtualWidth; if (submap.Type == TextureType.CubeMap) { return(DXTDecoder.DecodeCubeMap(raw, submap, PF, Cache.Version)); } raw = DXTDecoder.DecodeBitmap(raw, submap, Cache.Version); Bitmap bitmap2 = new Bitmap(submap.Width, submap.Height, PF); Rectangle rect = new Rectangle(0, 0, submap.Width, submap.Height); BitmapData bitmapdata = bitmap2.LockBits(rect, ImageLockMode.WriteOnly, PF); byte[] destinationArray = new byte[(submap.Width * submap.Height) * 4]; for (int j = 0; j < submap.Height; j++) { Array.Copy(raw, j * vWidth * 4, destinationArray, j * submap.Width * 4, submap.Width * 4); } Marshal.Copy(destinationArray, 0, bitmapdata.Scan0, destinationArray.Length); bitmap2.UnlockBits(bitmapdata); return(bitmap2); } catch { return(null); } }
public static void SaveBink(string Filename, CacheBase Cache, CacheBase.IndexItem Tag) { var bik = DefinitionsManager.bink(Cache, Tag); var raw = Cache.GetRawFromID(bik.RawID); if (!Filename.EndsWith(".bik")) { Filename += ".bik"; } if (!Directory.GetParent(Filename).Exists) { Directory.GetParent(Filename).Create(); } var fs = new FileStream(Filename, FileMode.Create, FileAccess.Write); var bw = new BinaryWriter(fs); for (int i = 0; i < (raw.Length); i += 4) { Array.Reverse(raw, i, 4); } bw.Write(raw); bw.Close(); bw.Dispose(); }
public scenario_structure_bsp(CacheBase Cache, int Address) { cache = Cache; EndianReader Reader = Cache.Reader; Reader.SeekTo(Address); #region sldt/lbsp ID //lbsp's sections address will be used instead of the one in sbsp int sectCount = 0, sectionAddress = 0, bbCount = 0, bbAddr = 0; foreach (var item in Cache.IndexItems) { if (item.ClassCode == "scnr") { Reader.SeekTo(item.Offset + 160); int cnt = Reader.ReadInt32(); int ptr = Reader.ReadInt32() - Cache.Magic; int bspIndex = 0; for (int i = 0; i < cnt; i++) { Reader.SeekTo(ptr + 336 * i + 12); if (Cache.IndexItems.GetItemByID(Reader.ReadInt32()).Offset == Address) { bspIndex = i; break; } } Reader.SeekTo(item.Offset + 1896 + 12); int sldtID = Reader.ReadInt32(); int sldtAddress = Cache.IndexItems.GetItemByID(sldtID).Offset; Reader.SeekTo(sldtAddress + 4); cnt = Reader.ReadInt32(); ptr = Reader.ReadInt32() - Cache.Magic; Reader.SeekTo(ptr + 32 * bspIndex + 12); int lbspID = Reader.ReadInt32(); int lbspAddress = Cache.IndexItems.GetItemByID(lbspID).Offset; Reader.SeekTo(lbspAddress + 320); //320, 512, 692 sectCount = Reader.ReadInt32(); sectionAddress = Reader.ReadInt32() - Cache.Magic; Reader.SeekTo(lbspAddress + 344); //344, 536, 716 bbCount = Reader.ReadInt32(); bbAddr = Reader.ReadInt32() - Cache.Magic; Reader.SeekTo(lbspAddress + 464); //464, 656, 836 geomRawID = Reader.ReadInt32(); break; } } #endregion Reader.SeekTo(Address + 268); XBounds = new RealBounds(Reader.ReadSingle(), Reader.ReadSingle()); YBounds = new RealBounds(Reader.ReadSingle(), Reader.ReadSingle()); ZBounds = new RealBounds(Reader.ReadSingle(), Reader.ReadSingle()); #region Clusters Block Reader.SeekTo(Address + 340); int iCount = Reader.ReadInt32(); int iOffset = Reader.ReadInt32() - Cache.Magic; for (int i = 0; i < 1; i++) { Clusters.Add(new Cluster(Cache, iOffset + 140 * i)); } #endregion #region Shaders Block Reader.SeekTo(Address + 352); iCount = Reader.ReadInt32(); iOffset = Reader.ReadInt32() - Cache.Magic; for (int i = 0; i < iCount; i++) { Shaders.Add(new Halo4Retail.render_model.Shader(Cache, iOffset + 44 * i)); } #endregion #region GeometryInstances Block Reader.SeekTo(Address + 640); iCount = Reader.ReadInt32(); iOffset = Reader.ReadInt32() - Cache.Magic; for (int i = 0; i < iCount; i++) { GeomInstances.Add(new InstancedGeometry(Cache, iOffset + 4 * i)); } #region Load Fixup Data Reader.SeekTo(Address + 1364); int id = Reader.ReadInt32(); var entry = Cache.zone.RawEntries[id & 0xFFFF]; var er = new EndianReader(new MemoryStream(Cache.GetRawFromID(id)), EndianFormat.BigEndian); int addr = entry.Fixups[entry.Fixups.Count - 10].Offset; for (int i = 0; i < GeomInstances.Count; i++) { er.SeekTo(addr + 148 * i); var geom = GeomInstances[i]; geom.TransformScale = er.ReadSingle(); geom.TransformMatrix.m11 = er.ReadSingle(); geom.TransformMatrix.m12 = er.ReadSingle(); geom.TransformMatrix.m13 = er.ReadSingle(); geom.TransformMatrix.m21 = er.ReadSingle(); geom.TransformMatrix.m22 = er.ReadSingle(); geom.TransformMatrix.m23 = er.ReadSingle(); geom.TransformMatrix.m31 = er.ReadSingle(); geom.TransformMatrix.m32 = er.ReadSingle(); geom.TransformMatrix.m33 = er.ReadSingle(); geom.TransformMatrix.m41 = er.ReadSingle(); geom.TransformMatrix.m42 = er.ReadSingle(); geom.TransformMatrix.m43 = er.ReadSingle(); er.ReadUInt16(); er.ReadUInt16(); er.ReadInt32(); er.ReadUInt16(); geom.SectionIndex = er.ReadUInt16(); } er.Close(); er.Dispose(); #endregion #endregion Reader.SeekTo(Address + 844); RawID1 = Reader.ReadInt32(); Reader.SeekTo(Address + 1048); RawID2 = Reader.ReadInt32(); #region ModelSections Block Reader.SeekTo(Address + 1144); iCount = Reader.ReadInt32(); iOffset = Reader.ReadInt32() - Cache.Magic; if (sectionAddress == -Cache.Magic) { sectionAddress = iOffset; //null address in lbsp } for (int i = 0; i < sectCount; i++) { ModelSections.Add(new Halo4Retail.render_model.ModelSection(Cache, sectionAddress + 112 * i)); } #endregion #region Bounding Boxes Block Reader.SeekTo(Address + 1168); iCount = Reader.ReadInt32(); iOffset = Reader.ReadInt32() - Cache.Magic; for (int i = 0; i < bbCount; i++) { BoundingBoxes.Add(new Halo4Retail.render_model.BoundingBox(Cache, bbAddr + 52 * i)); } #endregion Reader.SeekTo(Address + 1288); RawID3 = Reader.ReadInt32(); }
/// <summary> /// Saves an image from a bitmap tag to disk. /// </summary> /// <param name="Filename">The full path and filename to save to.</param> /// <param name="Cache">The CacheFile containing the bitmap tag.</param> /// <param name="Tag">The bitmap tag.</param> /// <param name="Index">The index of the BitmapData chunk to use.</param> /// <param name="Format">The format to save the image in.</param> /// <param name="Alpha">Whether to include the alpha channel in the image. Only applies when saving in TIF format.</param> public static void SaveImage(string Filename, CacheBase Cache, bitmap bitm, int Index, BitmapFormat Format, bool Alpha) { var submap = bitm.Bitmaps[Index]; byte[] raw; if (Cache.Version <= DefinitionSet.Halo2Vista) { raw = Cache.GetRawFromID(submap.PixelsOffset, submap.RawSize); } else { if (bitm.RawChunkBs.Count > 0) { int rawID = bitm.RawChunkBs[submap.InterleavedIndex].RawID; byte[] buffer = Cache.GetRawFromID(rawID); raw = new byte[submap.RawSize]; Array.Copy(buffer, submap.Index2 * submap.RawSize, raw, 0, submap.RawSize); } else { int rawID = bitm.RawChunkAs[Index].RawID; raw = Cache.GetRawFromID(rawID, submap.RawSize); } } int vHeight = submap.VirtualHeight; int vWidth = submap.VirtualWidth; if (Format == BitmapFormat.TIF || Format == BitmapFormat.PNG) { string ext = (Format == BitmapFormat.TIF) ? ".tif" : ".png"; int pLength = (Format == BitmapFormat.TIF) ? 4 : 4; ImageFormat IF = (Format == BitmapFormat.TIF) ? ImageFormat.Tiff : ImageFormat.Png; if (!Filename.EndsWith(ext)) { Filename += ext; } if (submap.Type == TextureType.CubeMap) { var img = DXTDecoder.DecodeCubeMap(raw, submap, Alpha ? PixelFormat.Format32bppArgb : PixelFormat.Format32bppRgb, Cache.Version); if (!Directory.GetParent(Filename).Exists) { Directory.GetParent(Filename).Create(); } img.Save(Filename, ImageFormat.Tiff); return; } raw = DXTDecoder.DecodeBitmap(raw, submap, Cache.Version); PixelFormat PF = (Alpha) ? PixelFormat.Format32bppArgb : PixelFormat.Format32bppRgb; Bitmap bitmap2 = new Bitmap(submap.Width, submap.Height, PF); Rectangle rect = new Rectangle(0, 0, submap.Width, submap.Height); BitmapData bitmapdata = bitmap2.LockBits(rect, ImageLockMode.WriteOnly, PF); byte[] destinationArray = new byte[(submap.Width * submap.Height) * pLength]; for (int j = 0; j < submap.Height; j++) { Array.Copy(raw, j * vWidth * pLength, destinationArray, j * submap.Width * pLength, submap.Width * pLength); } Marshal.Copy(destinationArray, 0, bitmapdata.Scan0, destinationArray.Length); bitmap2.UnlockBits(bitmapdata); if (!Directory.GetParent(Filename).Exists) { Directory.GetParent(Filename).Create(); } bitmap2.Save(Filename, IF); } else if (Format == BitmapFormat.DDS) { if (!Filename.EndsWith(".dds")) { Filename += ".dds"; } if (!Directory.GetParent(Filename).Exists) { Directory.GetParent(Filename).Create(); } var fs = new FileStream(Filename, FileMode.Create, FileAccess.Write); var bw = new BinaryWriter(fs); if (submap.Flags.Values[3]) { raw = DXTDecoder.ConvertToLinearTexture(raw, vWidth, vHeight, submap.Format); } if (submap.Format != TextureFormat.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); bw.Close(); bw.Dispose(); } else if (Format == BitmapFormat.RAW) { if (!Filename.EndsWith(".bin")) { Filename += ".bin"; } if (!Directory.GetParent(Filename).Exists) { Directory.GetParent(Filename).Create(); } File.WriteAllBytes(Filename, raw); } else { throw new InvalidOperationException("Invalid BitmapFormat received."); } }
public scenario_structure_bsp(CacheBase Cache, int Address) { cache = Cache; EndianReader Reader = Cache.Reader; Reader.SeekTo(Address); #region sldt/lbsp ID //lbsp's sections address will be used instead of the one in sbsp int sectCount = 0, sectionAddress = 0, bbCount = 0, bbAddr = 0; foreach (var item in Cache.IndexItems) { if (item.ClassCode == "scnr") { Reader.SeekTo(item.Offset + 160); int cnt = Reader.ReadInt32(); int ptr = Reader.ReadInt32() - Cache.Magic; int bspIndex = 0; for (int i = 0; i < cnt; i++) { Reader.SeekTo(ptr + 336 * i + 12); if (Cache.IndexItems.GetItemByID(Reader.ReadInt32()).Offset == Address) { bspIndex = i; break; } } Reader.SeekTo(item.Offset + 1896 + 12); int sldtID = Reader.ReadInt32(); int sldtAddress = Cache.IndexItems.GetItemByID(sldtID).Offset; Reader.SeekTo(sldtAddress + 4); cnt = Reader.ReadInt32(); ptr = Reader.ReadInt32() - Cache.Magic; Reader.SeekTo(ptr + 32 * bspIndex + 12); int lbspID = Reader.ReadInt32(); int lbspAddress = Cache.IndexItems.GetItemByID(lbspID).Offset; Reader.SeekTo(lbspAddress + 320); //320, 512, 692 sectCount = Reader.ReadInt32(); sectionAddress = Reader.ReadInt32() - Cache.Magic; Reader.SeekTo(lbspAddress + 344); //344, 536, 716 bbCount = Reader.ReadInt32(); bbAddr = Reader.ReadInt32() - Cache.Magic; Reader.SeekTo(lbspAddress + 464); //464, 656, 836 geomRawID = Reader.ReadInt32(); break; } } #endregion Reader.SeekTo(Address + 268); XBounds = new Range<float>(Reader.ReadSingle(), Reader.ReadSingle()); YBounds = new Range<float>(Reader.ReadSingle(), Reader.ReadSingle()); ZBounds = new Range<float>(Reader.ReadSingle(), Reader.ReadSingle()); #region Clusters Block Reader.SeekTo(Address + 340); int iCount = Reader.ReadInt32(); int iOffset = Reader.ReadInt32() - Cache.Magic; for (int i = 0; i < 1; i++) Clusters.Add(new Cluster(Cache, iOffset + 140 * i)); #endregion #region Shaders Block Reader.SeekTo(Address + 352); iCount = Reader.ReadInt32(); iOffset = Reader.ReadInt32() - Cache.Magic; for (int i = 0; i < iCount; i++) Shaders.Add(new Halo4Retail.render_model.Shader(Cache, iOffset + 44 * i)); #endregion #region GeometryInstances Block Reader.SeekTo(Address + 640); iCount = Reader.ReadInt32(); iOffset = Reader.ReadInt32() - Cache.Magic; for (int i = 0; i < iCount; i++) GeomInstances.Add(new InstancedGeometry(Cache, iOffset + 4 * i)); #region Load Fixup Data Reader.SeekTo(Address + 1364); int id = Reader.ReadInt32(); var entry = Cache.zone.RawEntries[id & 0xFFFF]; var er = new EndianReader(new MemoryStream(Cache.GetRawFromID(id)), EndianFormat.Big); int addr = entry.Fixups[entry.Fixups.Count - 10].Offset; for (int i = 0; i < GeomInstances.Count; i++) { er.SeekTo(addr + 148 * i); var geom = GeomInstances[i]; geom.TransformScale = er.ReadSingle(); geom.TransformMatrix = Matrix4x3.Read(er); er.ReadUInt16(); er.ReadUInt16(); er.ReadInt32(); er.ReadUInt16(); geom.SectionIndex = er.ReadUInt16(); } er.Close(); er.Dispose(); #endregion #endregion Reader.SeekTo(Address + 844); RawID1 = Reader.ReadInt32(); Reader.SeekTo(Address + 1048); RawID2 = Reader.ReadInt32(); #region ModelSections Block Reader.SeekTo(Address + 1144); iCount = Reader.ReadInt32(); iOffset = Reader.ReadInt32() - Cache.Magic; if (sectionAddress == -Cache.Magic) sectionAddress = iOffset; //null address in lbsp for (int i = 0; i < sectCount; i++) ModelSections.Add(new Halo4Retail.render_model.ModelSection(Cache, sectionAddress + 112 * i)); #endregion #region Bounding Boxes Block Reader.SeekTo(Address + 1168); iCount = Reader.ReadInt32(); iOffset = Reader.ReadInt32() - Cache.Magic; for (int i = 0; i < bbCount; i++) BoundingBoxes.Add(new Halo4Retail.render_model.BoundingBox(Cache, bbAddr + 52 * i)); #endregion Reader.SeekTo(Address + 1288); RawID3 = Reader.ReadInt32(); }