private Bitmap ETCBytesToBitmap(byte[] etc, int width, int height) { var etcsize = ETC1.GetEncodedDataSize(width, height); var inBfr = Java.Nio.ByteBuffer.AllocateDirect(etcsize + 16).Order(Java.Nio.ByteOrder.NativeOrder()); var outBfr = Java.Nio.ByteBuffer.AllocateDirect(width * height * 3).Order(Java.Nio.ByteOrder.NativeOrder()); WriteETCHeader(inBfr, width, height); inBfr.Put(etc, 0, etcsize); inBfr.Position(0); ETC1.DecodeImage(inBfr, outBfr, width, height, 3, width * 3); outBfr.Position(0); byte[] outBytes = new byte[width * height * 3]; outBfr.Get(outBytes); return(RGBBytesToBitmap(outBytes, width, height, false)); }
public static Bitmap GetBitmapETC(BXLIM bxlim, bool crop = true) { bool etc1a4 = bxlim.Footer.Format == XLIMEncoding.ETC1A4; byte[] data = bxlim.PixelData; ETC1.CheckETC1Lib(); try { var width = Math.Max(NextLargestPow2(bxlim.Width), 16); var height = Math.Max(NextLargestPow2(bxlim.Height), 16); Bitmap img = new Bitmap(width, height); img = DecodeETC(bxlim, img, data, etc1a4); return(crop ? CropBMP(bxlim, img) : img); } catch { return(null); } }
private static Bitmap DecodeETC(IXLIMHeader bclim, Bitmap img, byte[] textureData, bool etc1A4) { /* http://jul.rustedlogic.net/thread.php?id=17312 * Much of this code is taken/modified from Tharsis. Thank you to Tharsis's creator, xdaniel. * https://github.com/xdanieldzd/Tharsis */ /* Get compressed data & handle to it */ //textureData = switchEndianness(textureData, 0x10); ushort[] input = new ushort[textureData.Length / sizeof(ushort)]; Buffer.BlockCopy(textureData, 0, input, 0, textureData.Length); GCHandle pInput = GCHandle.Alloc(input, GCHandleType.Pinned); /* Marshal data around, invoke ETC1.dll for conversion, etc */ uint size1 = 0; var w = (ushort)img.Width; var h = (ushort)img.Height; ETC1.ConvertETC1(IntPtr.Zero, ref size1, IntPtr.Zero, w, h, etc1A4); // true = etc1a4, false = etc1 uint[] output = new uint[size1]; GCHandle pOutput = GCHandle.Alloc(output, GCHandleType.Pinned); ETC1.ConvertETC1(pOutput.AddrOfPinnedObject(), ref size1, pInput.AddrOfPinnedObject(), w, h, etc1A4); pOutput.Free(); pInput.Free(); /* Unscramble if needed // could probably be done in ETC1Lib.dll, it's probably pretty ugly, but whatever... */ /* Non-square code blocks could need some cleanup, verification, etc. as well... */ uint[] finalized = new uint[output.Length]; // Act if it's square because BCLIM swizzling is stupid Buffer.BlockCopy(output, 0, finalized, 0, finalized.Length); byte[] tmp = new byte[finalized.Length]; Buffer.BlockCopy(finalized, 0, tmp, 0, tmp.Length); byte[] imgData = tmp; for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { int k = (j + (i * img.Height)) * 4; img.SetPixel(i, j, Color.FromArgb(imgData[k + 3], imgData[k], imgData[k + 1], imgData[k + 2])); } } if (bclim is BFLIM) { return(img); } // Image is 13 instead of 12 // 24 34 img.RotateFlip(RotateFlipType.Rotate90FlipX); if (w > h) { // Image is now in appropriate order, but the shifting is messed up. Let's fix that. Bitmap img2 = new Bitmap(Math.Max(NextLargestPow2(bclim.Width), 16), Math.Max(NextLargestPow2(bclim.Height), 16)); for (int y = 0; y < Math.Max(NextLargestPow2(bclim.Width), 16); y += 8) { for (int x = 0; x < Math.Max(NextLargestPow2(bclim.Height), 16); x++) { for (int j = 0; j < 8; j++) // Treat every 8 vertical pixels as 1 pixel for purposes of calculation, add to offset later. { int x1 = (x + (y / 8 * h)) % img2.Width; // Reshift x int y1 = (x + (y / 8 * h)) / img2.Width * 8; // Reshift y img2.SetPixel(x1, y1 + j, img.GetPixel(x, y + j)); // Reswizzle } } } return(img2); } if (h > w) { Bitmap img2 = new Bitmap(Math.Max(NextLargestPow2(bclim.Width), 16), Math.Max(NextLargestPow2(bclim.Height), 16)); for (int y = 0; y < Math.Max(NextLargestPow2(bclim.Width), 16); y += 8) { for (int x = 0; x < Math.Max(NextLargestPow2(bclim.Height), 16); x++) { for (int j = 0; j < 8; j++) // Treat every 8 vertical pixels as 1 pixel for purposes of calculation, add to offset later. { int x1 = x % img2.Width; // Reshift x int y1 = (x + (y / 8 * h)) / img2.Width * 8; // Reshift y img2.SetPixel(x1, y1 + j, img.GetPixel(x, y + j)); // Reswizzle } } } return(img2); } return(img); }
public static unsafe byte[] FromBitmap(Bitmap Picture, ImageFormat Format, bool ExactSize = false) { if (ExactSize && ((Picture.Width % 8) != 0 || (Picture.Height % 8) != 0)) { return(null); } int physicalwidth = Picture.Width; int physicalheight = Picture.Height; int ConvWidth = Picture.Width; int ConvHeight = Picture.Height; if (!ExactSize) { ConvWidth = 1 << (int)Math.Ceiling(Math.Log(Picture.Width, 2)); ConvHeight = 1 << (int)Math.Ceiling(Math.Log(Picture.Height, 2)); } BitmapData d = Picture.LockBits(new Rectangle(0, 0, Picture.Width, Picture.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); uint * res = (uint *)d.Scan0; byte[] result = new byte[ConvWidth * ConvHeight * GetBpp(Format) / 8]; int offs = 0; switch (Format) { case ImageFormat.RGBA8: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvWidth; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); Color c = Color.FromArgb((int)res[(y + y2) * d.Stride / 4 + x + x2]); result[offs + pos * 4 + 0] = c.A; result[offs + pos * 4 + 1] = c.B; result[offs + pos * 4 + 2] = c.G; result[offs + pos * 4 + 3] = c.R; } offs += 64 * 4; } } break; case ImageFormat.RGB8: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvWidth; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); Color c = Color.FromArgb((int)res[(y + y2) * d.Stride / 4 + x + x2]); result[offs + pos * 3 + 0] = c.B; result[offs + pos * 3 + 1] = c.G; result[offs + pos * 3 + 2] = c.R; } offs += 64 * 3; } } break; case ImageFormat.RGBA5551: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvHeight; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); IOUtil.WriteU16LE(result, offs + pos * 2, (ushort)GFXUtil.ConvertColorFormat(res[(y + y2) * d.Stride / 4 + x + x2], ColorFormat.ARGB8888, ColorFormat.RGBA5551)); } offs += 64 * 2; } } break; case ImageFormat.RGB565: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvWidth; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); IOUtil.WriteU16LE(result, offs + pos * 2, (ushort)GFXUtil.ConvertColorFormat(res[(y + y2) * d.Stride / 4 + x + x2], ColorFormat.ARGB8888, ColorFormat.RGB565)); //GFXUtil.ArgbToRGB565(res[(y + y2) * d.Stride / 4 + x + x2])); } offs += 64 * 2; } } break; case ImageFormat.RGBA4: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvWidth; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); IOUtil.WriteU16LE(result, offs + pos * 2, (ushort)GFXUtil.ConvertColorFormat(res[(y + y2) * d.Stride / 4 + x + x2], ColorFormat.ARGB8888, ColorFormat.RGBA4444)); } offs += 64 * 2; } } break; case ImageFormat.LA8: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvWidth; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); Color c = Color.FromArgb((int)res[(y + y2) * d.Stride / 4 + x + x2]); result[offs + pos * 2] = c.A; result[offs + pos * 2 + 1] = c.B; result[offs + pos * 2 + 1] = c.G; result[offs + pos * 2 + 1] = c.R; } offs += 64 * 2; } } break; //case ImageFormat.HILO8: // for (int y = 0; y < ConvHeight; y += 8) // { // for (int x = 0; x < ConvWidth; x += 8) // { // for (int i = 0; i < 64; i++) // { // int x2 = i % 8; // if (x + x2 >= physicalwidth) continue; // int y2 = i / 8; // if (y + y2 >= physicalheight) continue; // int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); // Color c = Color.FromArgb((int)res[(y + y2) * d.Stride / 4 + x + x2]); // result[offs + pos * 2] = c.A; // result[offs + pos * 2 + 1] = c.B; // result[offs + pos * 2 + 1] = c.G; // result[offs + pos * 2 + 1] = c.R; // } // offs += 64 * 2; // } // } // break; //case ImageFormat.L8: // for (int y = 0; y < ConvHeight; y += 8) // { // for (int x = 0; x < ConvWidth; x += 8) // { // for (int i = 0; i < 64; i++) // { // int x2 = i % 8; // if (x + x2 >= physicalwidth) continue; // int y2 = i / 8; // if (y + y2 >= physicalheight) continue; // int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); // Color c = Color.FromArgb((int)res[(y + y2) * d.Stride / 4 + x + x2]); // result[offs + pos] = c.B; // result[offs + pos] = c.G; // result[offs + pos] = c.R; // } // offs += 64; // } // } // break; //case ImageFormat.A8: // for (int y = 0; y < ConvHeight; y += 8) // { // for (int x = 0; x < ConvWidth; x += 8) // { // for (int i = 0; i < 64; i++) // { // int x2 = i % 8; // if (x + x2 >= physicalwidth) continue; // int y2 = i / 8; // if (y + y2 >= physicalheight) continue; // int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); // Color c = Color.FromArgb((int)res[(y + y2) * d.Stride / 4 + x + x2]); // result[offs + pos] = c.A; // } // offs += 64; // } // } // break; //case ImageFormat.LA4: // for (int y = 0; y < ConvHeight; y += 8) // { // for (int x = 0; x < ConvWidth; x += 8) // { // for (int i = 0; i < 64; i++) // { // int x2 = i % 8; // if (x + x2 >= physicalwidth) continue; // int y2 = i / 8; // if (y + y2 >= physicalheight) continue; // int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); // Color c = Color.FromArgb((int)res[(y + y2) * d.Stride / 4 + x + x2]); // } // offs += 64; // } // } // break; //case ImageFormat.L4: // for (int y = 0; y < ConvHeight; y += 8) // { // for (int x = 0; x < ConvWidth; x += 8) // { // for (int i = 0; i < 64; i++) // { // int x2 = i % 8; // if (x + x2 >= physicalwidth) continue; // int y2 = i / 8; // if (y + y2 >= physicalheight) continue; // int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); // Color c = Color.FromArgb((int)res[(y + y2) * d.Stride / 4 + x + x2]); // } // offs += 64 / 2; // } // } // break; //case ImageFormat.A4: // for (int y = 0; y < ConvHeight; y += 8) // { // for (int x = 0; x < ConvWidth; x += 8) // { // for (int i = 0; i < 64; i++) // { // int x2 = i % 8; // if (x + x2 >= physicalwidth) continue; // int y2 = i / 8; // if (y + y2 >= physicalheight) continue; // int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); // Color c = Color.FromArgb((int)res[(y + y2) * d.Stride / 4 + x + x2]); // } // offs += 64 / 2; // } // } // break; case ImageFormat.ETC1: case ImageFormat.ETC1A4: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvWidth; x += 8) { for (int i = 0; i < 8; i += 4) { for (int j = 0; j < 8; j += 4) { if (Format == ImageFormat.ETC1A4) { ulong alpha = 0; int iiii = 0; for (int xx = 0; xx < 4; xx++) { for (int yy = 0; yy < 4; yy++) { uint color; if (x + j + xx >= physicalwidth) { color = 0x00FFFFFF; } else if (y + i + yy >= physicalheight) { color = 0x00FFFFFF; } else { color = res[((y + i + yy) * (d.Stride / 4)) + x + j + xx]; } uint a = color >> 24; a >>= 4; alpha |= (ulong)a << (iiii * 4); iiii++; } } IOUtil.WriteU64LE(result, offs, alpha); offs += 8; } Color[] pixels = new Color[4 * 4]; for (int yy = 0; yy < 4; yy++) { for (int xx = 0; xx < 4; xx++) { if (x + j + xx >= physicalwidth) { pixels[yy * 4 + xx] = Color.Transparent; } else if (y + i + yy >= physicalheight) { pixels[yy * 4 + xx] = Color.Transparent; } else { pixels[yy * 4 + xx] = Color.FromArgb((int)res[((y + i + yy) * (d.Stride / 4)) + x + j + xx]); } } } IOUtil.WriteU64LE(result, offs, ETC1.GenETC1(pixels)); offs += 8; } } } } break; default: throw new NotImplementedException("This format is not implemented yet."); } return(result); }
public Bitmap GetBitmap(int ArrayLevel = 0, int MipLevel = 0, int DepthLevel = 0) { uint width = Math.Max(1, Width >> MipLevel); uint height = Math.Max(1, Height >> MipLevel); byte[] data = GetImageData(ArrayLevel, MipLevel, DepthLevel); byte[] paletteData = GetPaletteData(); if (Format == TEX_FORMAT.R8G8B8A8_UNORM) { return(BitmapExtension.GetBitmap(ConvertBgraToRgba(data), (int)width, (int)height)); } try { if (data == null) { throw new Exception("Data is null!"); } if (PlatformSwizzle == PlatformSwizzle.Platform_3DS) { var Image = BitmapExtension.GetBitmap(ConvertBgraToRgba(CTR_3DS.DecodeBlock(data, (int)width, (int)height, Format)), (int)width, (int)height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); Image.RotateFlip(RotateFlipType.RotateNoneFlipY); //It's upside down for some reason so flip it return(Image); } if (PlatformSwizzle == PlatformSwizzle.Platform_Gamecube) { return(BitmapExtension.GetBitmap(Decode_Gamecube.DecodeData(data, paletteData, width, height, Format, PaletteFormat), (int)width, (int)height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)); } switch (Format) { case TEX_FORMAT.R4G4_UNORM: return(BitmapExtension.GetBitmap(R4G4.Decompress(data, (int)width, (int)height, false), (int)width, (int)height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)); case TEX_FORMAT.BC5_SNORM: return(DDSCompressor.DecompressBC5(data, (int)width, (int)height, true)); case TEX_FORMAT.ETC1_UNORM: return(BitmapExtension.GetBitmap(ETC1.ETC1Decompress(data, (int)width, (int)height, false), (int)width, (int)height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)); case TEX_FORMAT.ETC1_A4: return(BitmapExtension.GetBitmap(ETC1.ETC1Decompress(data, (int)width, (int)height, true), (int)width, (int)height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)); case TEX_FORMAT.R5G5B5A1_UNORM: case TEX_FORMAT.LA8: case TEX_FORMAT.L8: return(BitmapExtension.GetBitmap(RGBAPixelDecoder.Decode(data, (int)width, (int)height, Format), (int)width, (int)height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)); } if (Runtime.UseDirectXTexDecoder) { return(BitmapExtension.GetBitmap(DecodeBlock(data, width, height, Format, new byte[0], Parameters), (int)width, (int)height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)); } else { return(DecodeNotDirectXTex(data, width, height, Format)); } } catch (Exception ex) { /* Forms.STErrorDialog.Show($"Texture failed to load!", "Texture [GetBitmap({MipLevel},{ArrayLevel})]", DebugInfo() + " \n" + ex); * * try * { * return DecodeNotDirectXTex(data, width, height, Format); * } * catch * { * Forms.STErrorDialog.Show($"Texture failed to load!", "Texture [GetBitmap({MipLevel},{ArrayLevel})]", DebugInfo() + " \n" + ex); * }*/ return(null); } }
public static unsafe byte[] FromBitmap(Bitmap Picture, TextureFormat Format, bool ExactSize = false) { if (ExactSize && ((Picture.Width % 8) != 0 || (Picture.Height % 8) != 0)) { return(null); } int physicalwidth = Picture.Width; int physicalheight = Picture.Height; int ConvWidth = Picture.Width; int ConvHeight = Picture.Height; if (!ExactSize) { ConvWidth = 1 << (int)Math.Ceiling(Math.Log(Picture.Width, 2)); ConvHeight = 1 << (int)Math.Ceiling(Math.Log(Picture.Height, 2)); } BitmapData d = Picture.LockBits(new Rectangle(0, 0, Picture.Width, Picture.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); uint * res = (uint *)d.Scan0; byte[] result = new byte[ConvWidth * ConvHeight * GetBpp(Format) / 8]; int offs = 0; switch (Format) { case TextureFormat.Rgba8: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvWidth; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[(x2 % 4) + (y2 % 4) * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); if ((y + y2) * d.Stride / 4 + x + x2 > d.Height * d.Stride) { Console.WriteLine("{0} > {1} overflow", (y + y2) * d.Stride / 4 + x + x2, d.Height * d.Stride); Environment.Exit(1); } Color c = Color.FromArgb((int)res[(y + y2) * d.Stride / 4 + x + x2]); // magic line. removing this causes the white boxes to go away, but every texture gets a black outline if (c == Color.FromArgb(0, 0, 0, 0)) { c = Color.FromArgb(0, 0xff, 0xff, 0xff); } result[offs + pos * 4 + 0] = c.A; result[offs + pos * 4 + 1] = c.B; result[offs + pos * 4 + 2] = c.G; result[offs + pos * 4 + 3] = c.R; } offs += 64 * 4; } } break; case TextureFormat.Rgb8: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvWidth; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); Color c = Color.FromArgb((int)res[(y + y2) * d.Stride / 4 + x + x2]); result[offs + pos * 3 + 0] = c.B; result[offs + pos * 3 + 1] = c.G; result[offs + pos * 3 + 2] = c.R; } offs += 64 * 3; } } break; case TextureFormat.Rgb565: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvWidth; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); IOUtil.WriteU16LE(result, offs + pos * 2, (ushort)GFXUtil.ConvertColorFormat(res[(y + y2) * d.Stride / 4 + x + x2], ColorFormat.ARGB8888, ColorFormat.RGB565)); //GFXUtil.ArgbToRGB565(res[(y + y2) * d.Stride / 4 + x + x2])); } offs += 64 * 2; } } break; case TextureFormat.Rgba4: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvWidth; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[(x2 % 4) + (y2 % 4) * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); IOUtil.WriteU16LE(result, offs + pos * 2, (ushort)GFXUtil.ConvertColorFormat(res[(y + y2) * d.Stride / 4 + x + x2], ColorFormat.ARGB8888, ColorFormat.RGBA4444)); } offs += 64 * 2; } } break; case TextureFormat.La8: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvWidth; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); Color c = Color.FromArgb((int)res[(y + y2) * d.Stride / 4 + x + x2]); result[offs + pos * 2 + 0] = c.A; result[offs + pos * 2 + 1] = c.R; } offs += 64 * 2; } } break; case TextureFormat.Hilo8: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvWidth; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); Color c = Color.FromArgb((int)res[(y + y2) * d.Stride / 4 + x + x2]); result[offs + pos * 2 + 0] = c.R; result[offs + pos * 2 + 1] = c.G; } offs += 64 * 2; } } break; case TextureFormat.L8: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvWidth; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); Color c = Color.FromArgb((int)res[(y + y2) * d.Stride / 4 + x + x2]); result[offs + pos * 1 + 0] = c.R; } offs += 64 * 1; } } break; case TextureFormat.A8: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvWidth; x += 8) { for (int i = 0; i < 64; i++) { int x2 = i % 8; if (x + x2 >= physicalwidth) { continue; } int y2 = i / 8; if (y + y2 >= physicalheight) { continue; } int pos = TileOrder[x2 % 4 + y2 % 4 * 4] + 16 * (x2 / 4) + 32 * (y2 / 4); Color c = Color.FromArgb((int)res[(y + y2) * d.Stride / 4 + x + x2]); result[offs + pos * 1 + 0] = c.A; } offs += 64 * 1; } } break; case TextureFormat.Etc1: case TextureFormat.Etc1A4: for (int y = 0; y < ConvHeight; y += 8) { for (int x = 0; x < ConvWidth; x += 8) { for (int i = 0; i < 8; i += 4) { for (int j = 0; j < 8; j += 4) { if (Format == TextureFormat.Etc1A4) { ulong alpha = 0; int iiii = 0; for (int xx = 0; xx < 4; xx++) { for (int yy = 0; yy < 4; yy++) { uint color; if (x + j + xx >= physicalwidth) { color = 0x00FFFFFF; } else if (y + i + yy >= physicalheight) { color = 0x00FFFFFF; } else { color = res[((y + i + yy) * (d.Stride / 4)) + x + j + xx]; } uint a = color >> 24; a >>= 4; alpha |= (ulong)a << (iiii * 4); iiii++; } } IOUtil.WriteU64LE(result, offs, alpha); offs += 8; } Color[] pixels = new Color[4 * 4]; for (int yy = 0; yy < 4; yy++) { for (int xx = 0; xx < 4; xx++) { if (x + j + xx >= physicalwidth) { pixels[yy * 4 + xx] = Color.Transparent; } else if (y + i + yy >= physicalheight) { pixels[yy * 4 + xx] = Color.Transparent; } else { pixels[yy * 4 + xx] = Color.FromArgb((int)res[((y + i + yy) * (d.Stride / 4)) + x + j + xx]); } } } IOUtil.WriteU64LE(result, offs, ETC1.GenETC1(pixels)); offs += 8; } } } } break; default: throw new NotImplementedException("This format is not implemented yet."); } return(result); }