/// <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 Bitmap GetBitmapByTag(PakFile Pak, Texture pict, PixelFormat PF) { try { byte[] raw; Pak.Reader.SeekTo(pict.DataAddress); raw = Pak.Reader.ReadBytes(pict.RawSize); //change to BigEndian if (pict.isLittleEndian) { int block = 2; if (pict.Format == TextureFormat.A8R8G8B8 || pict.Format == TextureFormat.X8R8G8B8) { block = 4; } for (int i = 0; i < raw.Length; i += block) { Array.Reverse(raw, i, block); } } if (pict.Type == TextureType.CubeMap) { return(DXTDecoder.DecodeCubeMap(raw, pict, PF)); } raw = DXTDecoder.DecodeBitmap(raw, pict); //PixelFormat PF = (Alpha) ? PixelFormat.Format32bppArgb : PixelFormat.Format32bppRgb; Bitmap bitmap2 = new Bitmap(pict.Width, pict.Height, PF); Rectangle rect = new Rectangle(0, 0, pict.Width, pict.Height); BitmapData bitmapdata = bitmap2.LockBits(rect, ImageLockMode.WriteOnly, PF); byte[] destinationArray = new byte[(pict.Width * pict.Height) * 4]; for (int j = 0; j < pict.Height; j++) { Array.Copy(raw, j * pict.VirtualWidth * 4, destinationArray, j * pict.Width * 4, pict.Width * 4); } Marshal.Copy(destinationArray, 0, bitmapdata.Scan0, destinationArray.Length); bitmap2.UnlockBits(bitmapdata); return(bitmap2); } catch { return(null); } }
public static SKImage DecodeImage(byte[] sequence, int width, int height, int depth, EPixelFormat format) { byte[] data; SKColorType colorType; switch (format) { case EPixelFormat.PF_DXT5: data = DXTDecoder.DecodeDXT5(sequence, width, height, depth); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_DXT1: data = DXTDecoder.DecodeDXT1(sequence, width, height, depth); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_ASTC_8x8: var x = (int)TextureFormatHelper.GetBlockWidth(format); var y = (int)TextureFormatHelper.GetBlockHeight(format); var z = (int)TextureFormatHelper.GetBlockDepth(format); data = ASTCDecoder.DecodeToRGBA8888(sequence, x, y, z, width, height, 1); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_B8G8R8A8: data = sequence; colorType = SKColorType.Bgra8888; break; case EPixelFormat.PF_BC5: data = BCDecoder.DecodeBC5(sequence, width, height); colorType = SKColorType.Rgb888x; break; case EPixelFormat.PF_BC4: data = BCDecoder.DecodeBC4(sequence, width, height); colorType = SKColorType.Rgb888x; break; case EPixelFormat.PF_G8: data = sequence; colorType = SKColorType.Gray8; break; case EPixelFormat.PF_FloatRGBA: data = sequence; colorType = SKColorType.RgbaF16; break; case EPixelFormat.PF_BC7: data = Detex.DecodeDetexLinear(sequence, width, height, isFloat: false, inputFormat: DetexTextureFormat.DETEX_TEXTURE_FORMAT_BPTC, outputPixelFormat: DetexPixelFormat.DETEX_PIXEL_FORMAT_RGBA8); colorType = SKColorType.Rgb888x; break; case EPixelFormat.PF_BC6H: data = Detex.DecodeDetexLinear(sequence, width, height, isFloat: true, inputFormat: DetexTextureFormat.DETEX_TEXTURE_FORMAT_BPTC_FLOAT, outputPixelFormat: DetexPixelFormat.DETEX_PIXEL_FORMAT_RGBX8); // Not sure whether that works, would actually be DETEX_PIXEL_FORMAT_FLOAT_RGBX32 data = Detex.DecodeBC6H(sequence, width, height); colorType = SKColorType.Rgb888x; break; case EPixelFormat.PF_ETC1: data = Detex.DecodeDetexLinear(sequence, width, height, isFloat: false, inputFormat: DetexTextureFormat.DETEX_TEXTURE_FORMAT_ETC1, outputPixelFormat: DetexPixelFormat.DETEX_PIXEL_FORMAT_RGBA8); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_ETC2_RGB: data = Detex.DecodeDetexLinear(sequence, width, height, isFloat: false, inputFormat: DetexTextureFormat.DETEX_TEXTURE_FORMAT_ETC2, outputPixelFormat: DetexPixelFormat.DETEX_PIXEL_FORMAT_RGBA8); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_ETC2_RGBA: data = Detex.DecodeDetexLinear(sequence, width, height, isFloat: false, inputFormat: DetexTextureFormat.DETEX_TEXTURE_FORMAT_ETC2_EAC, outputPixelFormat: DetexPixelFormat.DETEX_PIXEL_FORMAT_RGBA8); colorType = SKColorType.Rgba8888; break; default: throw new NotImplementedException($"Cannot decode {format} format"); } using var bitmap = new SKBitmap(new SKImageInfo(width, height, colorType, SKAlphaType.Unpremul)); unsafe { fixed(byte *p = data) { bitmap.SetPixels(new IntPtr(p)); } } return(SKImage.FromBitmap(bitmap)); }
public static void DecodeTexture(FTexture2DMipMap mip, EPixelFormat format, bool isNormalMap, out byte[] data, out SKColorType colorType) { switch (format) { case EPixelFormat.PF_DXT1: data = DXTDecoder.DXT1(mip.Data.Data, mip.SizeX, mip.SizeY, mip.SizeZ); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_DXT5: data = DXTDecoder.DXT5(mip.Data.Data, mip.SizeX, mip.SizeY, mip.SizeZ); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_ASTC_4x4: case EPixelFormat.PF_ASTC_6x6: case EPixelFormat.PF_ASTC_8x8: case EPixelFormat.PF_ASTC_10x10: case EPixelFormat.PF_ASTC_12x12: data = ASTCDecoder.RGBA8888( mip.Data.Data, FormatHelper.GetBlockWidth(format), FormatHelper.GetBlockHeight(format), FormatHelper.GetBlockDepth(format), mip.SizeX, mip.SizeY, mip.SizeZ); colorType = SKColorType.Rgba8888; if (isNormalMap) { // UE4 drops blue channel for normal maps before encoding, restore it unsafe { var offset = 0; fixed(byte *d = data) { for (var i = 0; i < mip.SizeX * mip.SizeY; i++) { d[offset + 2] = BCDecoder.GetZNormal(d[offset], d[offset + 1]); offset += 4; } } } } break; case EPixelFormat.PF_BC4: data = BCDecoder.BC4(mip.Data.Data, mip.SizeX, mip.SizeY); colorType = SKColorType.Rgb888x; break; case EPixelFormat.PF_BC5: data = BCDecoder.BC5(mip.Data.Data, mip.SizeX, mip.SizeY); colorType = SKColorType.Rgb888x; break; case EPixelFormat.PF_BC6H: // BC6H doesn't work no matter the pixel format, the closest we can get is either // Rgb565 DETEX_PIXEL_FORMAT_FLOAT_RGBX16 or Rgb565 DETEX_PIXEL_FORMAT_FLOAT_BGRX16 data = Detex.DecodeDetexLinear(mip.Data.Data, mip.SizeX, mip.SizeY, true, DetexTextureFormat.DETEX_TEXTURE_FORMAT_BPTC_FLOAT, DetexPixelFormat.DETEX_PIXEL_FORMAT_FLOAT_RGBX16); colorType = SKColorType.Rgb565; break; case EPixelFormat.PF_BC7: data = Detex.DecodeDetexLinear(mip.Data.Data, mip.SizeX, mip.SizeY, false, DetexTextureFormat.DETEX_TEXTURE_FORMAT_BPTC, DetexPixelFormat.DETEX_PIXEL_FORMAT_RGBA8); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_ETC1: data = Detex.DecodeDetexLinear(mip.Data.Data, mip.SizeX, mip.SizeY, false, DetexTextureFormat.DETEX_TEXTURE_FORMAT_ETC1, DetexPixelFormat.DETEX_PIXEL_FORMAT_RGBA8); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_ETC2_RGB: data = Detex.DecodeDetexLinear(mip.Data.Data, mip.SizeX, mip.SizeY, false, DetexTextureFormat.DETEX_TEXTURE_FORMAT_ETC2, DetexPixelFormat.DETEX_PIXEL_FORMAT_RGBA8); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_ETC2_RGBA: data = Detex.DecodeDetexLinear(mip.Data.Data, mip.SizeX, mip.SizeY, false, DetexTextureFormat.DETEX_TEXTURE_FORMAT_ETC2_EAC, DetexPixelFormat.DETEX_PIXEL_FORMAT_RGBA8); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_R16F: case EPixelFormat.PF_R16F_FILTER: unsafe { fixed(byte *d = mip.Data.Data) { data = ConvertRawR16DataToRGB888X(mip.SizeX, mip.SizeY, d, mip.SizeX * 2); // 2 BPP } } colorType = SKColorType.Rgb888x; break; case EPixelFormat.PF_B8G8R8A8: data = mip.Data.Data; colorType = SKColorType.Bgra8888; break; case EPixelFormat.PF_G8: data = mip.Data.Data; colorType = SKColorType.Gray8; break; case EPixelFormat.PF_FloatRGBA: unsafe { fixed(byte *d = mip.Data.Data) { data = ConvertRawR16G16B16A16FDataToRGBA8888(mip.SizeX, mip.SizeY, d, mip.SizeX * 8, false); // 8 BPP } } colorType = SKColorType.Rgba8888; break; default: throw new NotImplementedException($"Unknown pixel format: {format}"); } }
/// <summary> /// Sending texture to video card<para/> /// Отправка текстуры на видеокарту /// </summary> public void Send() { if (State != ReadyState.NotSent) { return; } bool texEnabled = GL.IsEnabled(EnableCap.Texture2D); if (!texEnabled) { GL.Enable(EnableCap.Texture2D); } // Searching in parent // Поиск в родителе TextureFile.Entry e = Parent.File.Textures[name.ToLower()]; // Generating texture // Генерация текстуры gltex = GL.GenTexture(); GL.BindTexture(TextureTarget.Texture2D, gltex); GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)All.Modulate); // Sending scans // Отправка сканов int mipLevel = 0; byte[] texData; bool useCompression = false; PixelInternalFormat internalFormat = PixelInternalFormat.Four; PixelFormat pixelFormat = PixelFormat.Rgba; PixelType pixelType = PixelType.UnsignedByte; // Check for compression // Проверка на сжатие по DXT if (e.ScanCompression != TextureFile.Compression.Uncompressed) { // Decoding if compression is not supported // Раскодирование, если сжатие аппаратно не поддерживается if (!Managers.TextureManager.CompressionSupported) { useCompression = false; } else { // Compression is supported, so we can send it directlty to GPU // Сжатие аппаратно поддерживается, можно отсылать на видеокарту useCompression = true; internalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt1Ext; if (e.ScanCompression == TextureFile.Compression.DXT3) { internalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt3Ext; } } } else { // Common texture, determine type by texture mode // Обычная текстура, разбор типа по режиму if ((e.Flags & (int)TextureFile.RasterFlags.Format1555) != 0) { pixelType = PixelType.UnsignedShort5551; } else if ((e.Flags & (int)TextureFile.RasterFlags.Format565) != 0) { pixelType = PixelType.UnsignedShort565; } else if ((e.Flags & (int)TextureFile.RasterFlags.Format4444) != 0) { pixelType = PixelType.UnsignedShort565; } else if ((e.Flags & (int)TextureFile.RasterFlags.FormatLum8) != 0) { pixelType = PixelType.UnsignedByte; internalFormat = PixelInternalFormat.Luminance8; pixelFormat = PixelFormat.Luminance; } else if ((e.Flags & (int)TextureFile.RasterFlags.Format888) != 0) { pixelType = PixelType.UnsignedByte; internalFormat = PixelInternalFormat.Three; pixelFormat = PixelFormat.Rgb; } } // Sending scans // Отправка сканов foreach (TextureFile.Scan scan in e.Scans) { // Decode scans if needed // Раскодирование скана если требуется if (e.ScanCompression != TextureFile.Compression.Uncompressed && !useCompression) { texData = DXTDecoder.Decode((int)scan.Size.X, (int)scan.Size.Y, scan.Data, (e.ScanCompression == TextureFile.Compression.DXT3) ? DXTDecoder.CompressionType.DXT3 : DXTDecoder.CompressionType.DXT1); } else { texData = scan.Data; } // Determine compression while sending // Выборка сжатия при отправке if (useCompression) { GL.CompressedTexImage2D(TextureTarget.Texture2D, mipLevel, internalFormat, (int)scan.Size.X, (int)scan.Size.Y, 0, texData.Length, texData); } else { GL.TexImage2D(TextureTarget.Texture2D, mipLevel, internalFormat, (int)scan.Size.X, (int)scan.Size.Y, 0, pixelFormat, pixelType, texData); } mipLevel++; } Mipmapped = e.Scans.Length > 1; if (!texEnabled) { GL.Disable(EnableCap.Texture2D); } State = ReadyState.Complete; }
public override void Read(ArchiveReader reader) { // dont care if (reader.ReadByte() != 0) { throw new Exception("Expected 0 is not zero"); } if (reader.ReadByte() != 0) { // Initialize prop base.Read(reader); if (Get("origin") is WzVector2D origin) { CenterX = origin.X; CenterY = origin.Y; } } else { base._objects = new Dictionary <string, object>(); } Width = reader.ReadCompressedInt(); if (Width >= 0x10000) { throw new Exception($"Invalid Width: {Width}"); } Height = reader.ReadCompressedInt(); if (Height >= 0x10000) { throw new Exception($"Invalid Height: {Height}"); } PixFormat = (WzPixFormat)reader.ReadCompressedInt(); if (!( PixFormat == WzPixFormat.A4R4G4B4 || PixFormat == WzPixFormat.A8R8G8B8 || PixFormat == WzPixFormat.R5G6B5 || PixFormat == WzPixFormat.DXT3 || PixFormat == WzPixFormat.DXT5 )) { throw new Exception($"Invalid PixFormat: {PixFormat:D}"); } MagLevel = reader.ReadCompressedInt(); if (MagLevel < 0) { throw new Exception("MagLevel is < 0"); } // Zeroes for (var i = 0; i < 4; i++) { if (reader.ReadCompressedInt() != 0) { throw new Exception("Expected 0 is not zero"); } } var dataSize = reader.ReadInt32(); if (reader.ReadByte() != 0) { throw new Exception("Expected 0 is not zero"); } Create(Width, Height, MagLevel, (WzPixFormat)0); using (var outputStream = new MemoryStream(ExpectedDataSize)) using (var inputStream = new MemoryStream(dataSize)) { var isPlainZlibStream = reader.ReadByte() == 0x78; reader.BaseStream.Position -= 1; var blob = new byte[Math.Min(0x20000, dataSize)]; if (reader.HasCurrentCrypto && !isPlainZlibStream) { // Need to skip 1 for (var i = 1; i < dataSize;) { var blobSize = reader.ReadInt32(); i += 4; Array.Resize(ref blob, blobSize); reader.Read(blob, 0, blobSize); reader.TryDecryptImage(blob); inputStream.Write(blob, 0, blobSize); i += blobSize; } } else { for (var i = 0; i < dataSize;) { var blobSize = Math.Min(blob.Length, dataSize - i); reader.Read(blob, 0, blobSize); inputStream.Write(blob, 0, blobSize); i += blobSize; } } inputStream.Position = 2; using (var deflate = new DeflateStream(inputStream, CompressionMode.Decompress)) { deflate.CopyTo(outputStream); } var uncompressedSize = outputStream.Length; outputStream.Position = 0; Bitmap output = null; byte[] arr; switch (PixFormat) { case WzPixFormat.A4R4G4B4: arr = ARGB16toARGB32(outputStream, uncompressedSize); break; case WzPixFormat.DXT5: case WzPixFormat.DXT3: arr = DXTDecoder.Decode( TileWidth, TileHeight, outputStream.ToArray(), PixFormat == WzPixFormat.DXT3 ? DXTDecoder.CompressionType.DXT3 : DXTDecoder.CompressionType.DXT5 ); break; default: arr = outputStream.ToArray(); break; } PixelFormat format; switch (PixFormat) { case WzPixFormat.R5G6B5: format = PixelFormat.Format16bppRgb565; break; case WzPixFormat.A4R4G4B4: case WzPixFormat.A8R8G8B8: default: format = PixelFormat.Format32bppArgb; break; } output = new Bitmap(TileWidth, TileHeight, format); var rect = new Rectangle(0, 0, output.Width, output.Height); var bmpData = output.LockBits(rect, ImageLockMode.ReadWrite, output.PixelFormat); var arrRowLength = rect.Width * (Image.GetPixelFormatSize(output.PixelFormat) / 8); var ptr = bmpData.Scan0; for (var i = 0; i < rect.Height; i++) { Marshal.Copy(arr, i * arrRowLength, ptr, arrRowLength); ptr += bmpData.Stride; } output.UnlockBits(bmpData); SetCanvas(0, 0, new WzRawCanvas { Bitmap = output, MagLevel = MagLevel, }); } }
public static void SaveImage(string Filename, PakFile Pak, Texture pict, BitmapFormat Format, bool Alpha) { byte[] raw; Pak.Reader.SeekTo(pict.DataAddress); raw = Pak.Reader.ReadBytes(pict.RawSize); //change to BigEndian if (pict.isLittleEndian) { int block = 2; if (pict.Format == TextureFormat.A8R8G8B8 || pict.Format == TextureFormat.X8R8G8B8) { block = 4; } for (int i = 0; i < raw.Length; i += block) { Array.Reverse(raw, i, block); } } 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; PixelFormat PF = (Alpha) ? PixelFormat.Format32bppArgb : PixelFormat.Format32bppRgb; if (!Filename.EndsWith(ext)) { Filename += ext; } if (pict.Type == TextureType.CubeMap) { var img = DXTDecoder.DecodeCubeMap(raw, pict, PF); if (!Directory.GetParent(Filename).Exists) { Directory.GetParent(Filename).Create(); } img.Save(Filename, ImageFormat.Tiff); return; } raw = DXTDecoder.DecodeBitmap(raw, pict); Bitmap bitmap2 = new Bitmap(pict.Width, pict.Height, PF); Rectangle rect = new Rectangle(0, 0, pict.Width, pict.Height); BitmapData bitmapdata = bitmap2.LockBits(rect, ImageLockMode.WriteOnly, PF); byte[] destinationArray = new byte[(pict.Width * pict.Height) * pLength]; for (int j = 0; j < pict.Height; j++) { Array.Copy(raw, j * pict.VirtualWidth * pLength, destinationArray, j * pict.Width * pLength, pict.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 (pict.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); } } 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."); } }
/// <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 override void Read(BinaryReader reader) { // dont care Debug.Assert(reader.ReadByte() == 0); // just zero if (reader.ReadByte() != 0) { // Initialize prop base.Read(reader); } else { base._objects = new Dictionary <string, object>(); } Width = reader.ReadCompressedInt(); Debug.Assert(Width < 0x10000); Height = reader.ReadCompressedInt(); Debug.Assert(Height < 0x10000); PixFormat = (WzPixFormat)reader.ReadCompressedInt(); Debug.Assert( PixFormat == WzPixFormat.A4R4G4B4 || PixFormat == WzPixFormat.A8R8G8B8 || PixFormat == WzPixFormat.R5G6B5 || PixFormat == WzPixFormat.DXT3 || PixFormat == WzPixFormat.DXT5 ); MagLevel = reader.ReadCompressedInt(); Debug.Assert(MagLevel >= 0); // Zeroes for (var i = 0; i < 4; i++) { Debug.Assert(reader.ReadCompressedInt() == 0); } var dataSize = reader.ReadInt32(); Debug.Assert(reader.ReadByte() == 0); // just zero using (var outputStream = new MemoryStream(ExpectedDataSize)) using (var inputStream = new MemoryStream(dataSize)) { var isPlainZlibStream = reader.ReadByte() == 0x78; reader.BaseStream.Position -= 1; var blob = new byte[Math.Min(0x2000, dataSize)]; if (WzEncryption.HasCurrentCrypto && !isPlainZlibStream) { // Need to skip 1 for (var i = 1; i < dataSize;) { var blobSize = reader.ReadInt32(); i += 4; Array.Resize(ref blob, blobSize); reader.Read(blob, 0, blobSize); WzEncryption.TryDecryptImage(blob); inputStream.Write(blob, 0, blobSize); i += blobSize; } } else { for (var i = 0; i < dataSize;) { var blobSize = Math.Min(blob.Length, dataSize - i); reader.Read(blob, 0, blobSize); inputStream.Write(blob, 0, blobSize); i += blobSize; } } inputStream.Position = 2; using (var deflate = new DeflateStream(inputStream, CompressionMode.Decompress)) { deflate.CopyTo(outputStream); } var uncompressedSize = outputStream.Length; outputStream.Position = 0; Bitmap output = null; byte[] arr; switch (PixFormat) { case WzPixFormat.A4R4G4B4: arr = ARGB16toARGB32(outputStream, uncompressedSize); break; case WzPixFormat.DXT5: case WzPixFormat.DXT3: arr = DXTDecoder.Decode( TileWidth, TileHeight, outputStream.ToArray(), PixFormat == WzPixFormat.DXT3 ? DXTDecoder.CompressionType.DXT3 : DXTDecoder.CompressionType.DXT5 ); break; default: arr = outputStream.ToArray(); break; } PixelFormat format; switch (PixFormat) { case WzPixFormat.R5G6B5: format = PixelFormat.Format16bppRgb565; break; case WzPixFormat.A4R4G4B4: case WzPixFormat.A8R8G8B8: default: format = PixelFormat.Format32bppArgb; break; } output = new Bitmap(TileWidth, TileHeight, format); var rect = new Rectangle(0, 0, output.Width, output.Height); var bmpData = output.LockBits(rect, ImageLockMode.ReadWrite, output.PixelFormat); // Apply MipMap stuff var arrRowLength = rect.Width * Image.GetPixelFormatSize(output.PixelFormat) / 8; var ptr = bmpData.Scan0; for (var i = 0; i < rect.Height; i++) { Marshal.Copy(arr, i * arrRowLength, ptr, arrRowLength); ptr += bmpData.Stride; } output.UnlockBits(bmpData); Tile = output; } }
private static void DecodeTexture(FTexture2DMipMap mip, EPixelFormat format, out byte[] data, out SKColorType colorType) { switch (format) { case EPixelFormat.PF_DXT1: data = DXTDecoder.DXT1(mip.Data.Data, mip.SizeX, mip.SizeY, mip.SizeZ); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_DXT5: data = DXTDecoder.DXT5(mip.Data.Data, mip.SizeX, mip.SizeY, mip.SizeZ); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_ASTC_8x8: data = ASTCDecoder.RGBA8888( mip.Data.Data, FormatHelper.GetBlockWidth(format), FormatHelper.GetBlockHeight(format), FormatHelper.GetBlockDepth(format), mip.SizeX, mip.SizeY, mip.SizeZ); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_BC4: data = BCDecoder.BC4(mip.Data.Data, mip.SizeX, mip.SizeY); colorType = SKColorType.Rgb888x; break; case EPixelFormat.PF_BC5: data = BCDecoder.BC5(mip.Data.Data, mip.SizeX, mip.SizeY); colorType = SKColorType.Rgb888x; break; case EPixelFormat.PF_BC6H: // BC6H doesn't work no matter the pixel format, the closest we can get is either // Rgb565 DETEX_PIXEL_FORMAT_FLOAT_RGBX16 or Rgb565 DETEX_PIXEL_FORMAT_FLOAT_BGRX16 data = Detex.DecodeDetexLinear(mip.Data.Data, mip.SizeX, mip.SizeY, true, inputFormat: DetexTextureFormat.DETEX_TEXTURE_FORMAT_BPTC_FLOAT, outputPixelFormat: DetexPixelFormat.DETEX_PIXEL_FORMAT_FLOAT_RGBX16); colorType = SKColorType.Rgb565; break; case EPixelFormat.PF_BC7: data = Detex.DecodeDetexLinear(mip.Data.Data, mip.SizeX, mip.SizeY, false, inputFormat: DetexTextureFormat.DETEX_TEXTURE_FORMAT_BPTC, outputPixelFormat: DetexPixelFormat.DETEX_PIXEL_FORMAT_RGBA8); colorType = SKColorType.Rgb888x; break; case EPixelFormat.PF_ETC1: data = Detex.DecodeDetexLinear(mip.Data.Data, mip.SizeX, mip.SizeY, false, inputFormat: DetexTextureFormat.DETEX_TEXTURE_FORMAT_ETC1, outputPixelFormat: DetexPixelFormat.DETEX_PIXEL_FORMAT_RGBA8); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_ETC2_RGB: data = Detex.DecodeDetexLinear(mip.Data.Data, mip.SizeX, mip.SizeY, false, inputFormat: DetexTextureFormat.DETEX_TEXTURE_FORMAT_ETC2, outputPixelFormat: DetexPixelFormat.DETEX_PIXEL_FORMAT_RGBA8); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_ETC2_RGBA: data = Detex.DecodeDetexLinear(mip.Data.Data, mip.SizeX, mip.SizeY, false, inputFormat: DetexTextureFormat.DETEX_TEXTURE_FORMAT_ETC2_EAC, outputPixelFormat: DetexPixelFormat.DETEX_PIXEL_FORMAT_RGBA8); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_B8G8R8A8: data = mip.Data.Data; colorType = SKColorType.Bgra8888; break; case EPixelFormat.PF_G8: data = mip.Data.Data; colorType = SKColorType.Gray8; break; case EPixelFormat.PF_FloatRGBA: data = mip.Data.Data; colorType = SKColorType.RgbaF16; break; default: throw new NotImplementedException($"Unknown pixel format: {format}"); } }
public async Task LoadFromStream(Stream stream, bool lzma = false) { var br = new ExtendedBinaryReader(stream); // DTX Header iResType = br.ReadUInt32(); iVersion = br.ReadInt32(); width = br.ReadUInt16(); height = br.ReadUInt16(); nMipmap = br.ReadUInt16(); nSection = br.ReadUInt16(); flags = br.ReadInt32(); userFlags = br.ReadInt32(); extra = br.ReadBytes(12); cmdStr = br.ReadBytes(128); if (iResType != 0 || iVersion != -5 || nMipmap == 0) { if (lzma) { throw new Exception("Unsupported DTX Type"); } else { stream.Position = 0; var lzmaStream = new LzmaDecodeStream(stream); var ms = new MemoryStream(); lzmaStream.CopyTo(ms); await LoadFromStream(ms, true); return; } } DXTDecoder decoder = null; if (storeType == 4) { decoder = new DXT1Decoder(); } else if (storeType == 5) { decoder = new DXT3Decoder(); } else if (storeType == 6) { decoder = new DXT5Decoder(); } if (decoder != null) { rawBuffer = await decoder.DecodeFrame(stream, width, height); } else { rawBuffer = br.ReadBytes(width * height * 4); } br.Close(); }
public static SKImage DecodeImage(byte[] sequence, int width, int height, int depth, EPixelFormat format) { byte[] data; SKColorType colorType; switch (format) { case EPixelFormat.PF_DXT5: data = DXTDecoder.DecodeDXT5(sequence, width, height, depth); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_DXT1: data = DXTDecoder.DecodeDXT1(sequence, width, height, depth); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_ASTC_8x8: var x = (int)TextureFormatHelper.GetBlockWidth(format); var y = (int)TextureFormatHelper.GetBlockHeight(format); var z = (int)TextureFormatHelper.GetBlockDepth(format); data = ASTCDecoder.DecodeToRGBA8888(sequence, x, y, z, width, height, 1); colorType = SKColorType.Rgba8888; break; case EPixelFormat.PF_B8G8R8A8: data = sequence; colorType = SKColorType.Bgra8888; break; case EPixelFormat.PF_BC5: data = BCDecoder.DecodeBC5(sequence, width, height); colorType = SKColorType.Bgra8888; break; case EPixelFormat.PF_BC4: data = BCDecoder.DecodeBC4(sequence, width, height); colorType = SKColorType.Bgra8888; break; case EPixelFormat.PF_G8: data = sequence; colorType = SKColorType.Gray8; break; case EPixelFormat.PF_FloatRGBA: data = sequence; colorType = SKColorType.RgbaF16; break; default: throw new NotImplementedException($"Cannot decode {format} format"); } using var bitmap = new SKBitmap(new SKImageInfo(width, height, colorType, SKAlphaType.Unpremul)); unsafe { fixed(byte *p = data) { bitmap.SetPixels(new IntPtr(p)); } } return(SKImage.FromBitmap(bitmap)); }
public static void DecodeTextureNSW(FTexture2DMipMap mip, EPixelFormat format, bool isNormalMap, out byte[] data, out SKColorType colorType) { switch (format) { case EPixelFormat.PF_DXT5: { var uBlockSize = mip.SizeX / 4; var vBlockSize = mip.SizeY / 4; var totalBlocks = mip.Data.Data.Length / 16; if (uBlockSize * vBlockSize > totalBlocks) { throw new ParserException($"Texture unable to be untiled: {format}"); } var d = PlatformDeswizzlers.DesizzleNSW(mip.Data.Data, mip.SizeX, mip.SizeY, 4, 4, 16); data = DXTDecoder.DXT5(d, mip.SizeX, mip.SizeY, mip.SizeZ); colorType = SKColorType.Rgba8888; break; } case EPixelFormat.PF_DXT1: { var uBlockSize = mip.SizeX / 4; var vBlockSize = mip.SizeY / 4; var totalBlocks = mip.Data.Data.Length / 8; if (uBlockSize * vBlockSize > totalBlocks) { throw new ParserException($"Texture unable to be untiled: {format}"); } var d = PlatformDeswizzlers.DesizzleNSW(mip.Data.Data, mip.SizeX, mip.SizeY, 4, 4, 8); data = DXTDecoder.DXT1(d, mip.SizeX, mip.SizeY, mip.SizeZ); colorType = SKColorType.Rgba8888; break; } case EPixelFormat.PF_B8G8R8A8: { var uBlockSize = mip.SizeX / 4; var vBlockSize = mip.SizeY / 4; var totalBlocks = mip.Data.Data.Length / 4; if (uBlockSize * vBlockSize > totalBlocks) { throw new ParserException($"Texture unable to be untiled: {format}"); } data = PlatformDeswizzlers.DesizzleNSW(mip.Data.Data, mip.SizeX, mip.SizeY, 1, 1, 4); colorType = SKColorType.Bgra8888; break; } default: { TextureDecoder.DecodeTexture(mip, format, isNormalMap, out data, out colorType); break; } } }
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); }