public static Bitmap DecodeByteArray(byte[] imagedata, ushort Width, ushort Height, TextureFormat Format) { CTRTexture tex = new CTRTexture { Format = Format, Size = new Size(Width, Height), ImageData = (byte[])imagedata.Clone() }; return(DecodeTexture(tex)); }
public static Bitmap DecodeTexture(CTRTexture tex) { tex.BytesPerPixel = GetBytesPerPixel(tex.Format); if (tex.IsEtc1) { return(GetEtcBitmap(tex)); } tex.RedBitSize = GetRedBitSize(tex.Format); tex.GreenBitSize = GetGreenBitSize(tex.Format); tex.BlueBitSize = GetBlueBitSize(tex.Format); tex.AlphaBitSize = GetAlphaBitSize(tex.Format); tex.LuminanceBitSize = GetLuminanceBitSize(tex.Format); tex.PostProcess = getPostProcessingDelegate(tex.Format); tex.ChannelOrder = GetChannelOrder(tex.Format); return(GetGenericBitmap(tex)); }
/* private static readonly int[] etcScramble = new int[4] { 2, 3, 1, 0 }; */ public static Bitmap DecodeBCLIM(string filename) { CTRTexture bclim = new CTRTexture(); using (FileStream fs = File.OpenRead(filename)) { using (BinaryReader br = new BinaryReader(fs)) { br.BaseStream.Seek(fs.Length - 0x28 + 0x1C, SeekOrigin.Begin); bclim.Size = new Size { Width = br.ReadUInt16(), Height = br.ReadUInt16() }; bclim.Format = (TextureFormat)br.ReadUInt32(); int imageDataLen = br.ReadInt32(); br.BaseStream.Seek(0, SeekOrigin.Begin); bclim.ImageData = br.ReadBytes(imageDataLen); } } return(DecodeTexture(bclim)); }
private static Bitmap GetEtcBitmap(CTRTexture tex) { Bitmap bmp = new Bitmap(tex.Size.Width, tex.Size.Height); BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat); IntPtr ptr = bmpData.Scan0; int bytes = Math.Abs(bmpData.Stride) * bmp.Height; byte[] rgbaValues = new byte[bytes]; bool hasAlpha = tex.HasAlpha; int offset = 0; for (int y = 0; y < tex.Size.Height; y += 4) { for (int x = 0; x < tex.Size.Width; x += 4) { offset = GetEtc1BlockOffset(tex.Size, x, y, hasAlpha); ulong alphaValue = hasAlpha ? BitConverter.ToUInt64(tex.ImageData, offset) : ulong.MaxValue; ulong rgbValue = BitConverter.ToUInt64(tex.ImageData, hasAlpha ? offset + 8 : offset); bool flip = (rgbValue & 0x100000000L) != 0; bool dif = (rgbValue & 0x200000000L) != 0; uint r1, g1, b1; uint r2, g2, b2; if (dif) { uint mult = 0xFF / 0x1F; sbyte rt, gt, bt; rt = (sbyte)((long)(rgbValue >> 56) & 7); gt = (sbyte)((long)(rgbValue >> 48) & 7); bt = (sbyte)((long)(rgbValue >> 40) & 7); rt = (sbyte)((int)rt << 5); rt = (sbyte)((int)rt >> 5); gt = (sbyte)((int)gt << 5); gt = (sbyte)((int)gt >> 5); bt = (sbyte)((int)bt << 5); bt = (sbyte)((int)bt >> 5); r1 = (uint)(rgbValue >> 59) & 31; g1 = (uint)(rgbValue >> 51) & 31; b1 = (uint)(rgbValue >> 43) & 31; r2 = (uint)(r1 + (int)rt) * mult; g2 = (uint)(g1 + (int)gt) * mult; b2 = (uint)(b1 + (int)bt) * mult; r1 *= mult; g1 *= mult; b1 *= mult; } else { uint mult = 0xFF / 0xF; r1 = (uint)((rgbValue >> 60) & 0xF) * mult; g1 = (uint)((rgbValue >> 52) & 0xF) * mult; b1 = (uint)((rgbValue >> 44) & 0xF) * mult; r2 = (uint)((rgbValue >> 56) & 0xF) * mult; g2 = (uint)((rgbValue >> 48) & 0xF) * mult; b2 = (uint)((rgbValue >> 40) & 0xF) * mult; } uint cmpOne = (uint)((rgbValue >> 37) & 7); uint cmpTwo = (uint)((rgbValue >> 34) & 7); byte[] block = new byte[0x40]; if (flip) { for (int bY = 0; bY < 2; bY++) { for (int bX = 0; bX < 4; bX++) { GetEtc1Pixel(r1, g1, b1, bX, bY, rgbValue, alphaValue, cmpOne).CopyTo(rgbaValues, ((x + bX) * 4 + ((y + bY) * 4 * tex.Size.Width))); GetEtc1Pixel(r2, g2, b2, bX, bY + 2, rgbValue, alphaValue, cmpTwo).CopyTo(rgbaValues, ((x + bX) * 4 + (((y + 2) + bY) * 4 * tex.Size.Width))); } } } else { for (int bY = 0; bY < 4; bY++) { for (int bX = 0; bX < 2; bX++) { GetEtc1Pixel(r1, g1, b1, bX, bY, rgbValue, alphaValue, cmpOne).CopyTo(rgbaValues, ((x + bX) * 4 + ((y + bY) * 4 * tex.Size.Width))); GetEtc1Pixel(r2, g2, b2, bX + 2, bY, rgbValue, alphaValue, cmpTwo).CopyTo(rgbaValues, ((x + bX + 2) * 4 + ((y + bY) * 4 * tex.Size.Width))); } } } } } Marshal.Copy(rgbaValues, 0, ptr, bytes); bmp.UnlockBits(bmpData); return(bmp); }
private static Bitmap GetGenericBitmap(CTRTexture tex) { uint redBitMask = (uint)((1 << tex.RedBitSize) - 1); uint blueBitMask = (uint)((1 << tex.BlueBitSize) - 1); uint greenBitMask = (uint)((1 << tex.GreenBitSize) - 1); uint alphaBitMask = (uint)((1 << tex.AlphaBitSize) - 1); uint luminanceBitMask = (uint)((1 << tex.LuminanceBitSize) - 1); bool crop = false; Size size = new Size { Width = tex.Size.Width, Height = tex.Size.Height }; if ((int)(tex.ImageData.Length / tex.BytesPerPixel) > (tex.Size.Width * tex.Size.Height)) { size = new Size { Width = Nlpo2(tex.Size.Width), Height = Nlpo2(tex.Size.Height) }; crop = true; } Bitmap bmp = new Bitmap(size.Width, size.Height); BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat); IntPtr ptr = bmpData.Scan0; int bytes = Math.Abs(bmpData.Stride) * bmp.Height; byte[] rgbaValues = new byte[bytes]; int bitsPerPixel = (int)tex.BytesPerPixel * 8; int Offset = 0; for (int y = 0; y < size.Height; y++) { for (int x = 0; x < size.Width; x++) { int xInd = x & 7, yInd = y & 7; int pixelOffset = GetPixelDataOffset(size, x, y, tex.BytesPerPixel) + (int)(tex.BytesPerPixel * (double)TileTable[yInd, xInd]); uint Value; switch (bitsPerPixel) { case 4: Value = (uint)(tex.ImageData[pixelOffset] >> (4 * (x & 1))) & 0xF; break; case 8: Value = (uint)(tex.ImageData[pixelOffset]); break; case 16: Value = BitConverter.ToUInt16(tex.ImageData, pixelOffset); break; case 24: Value = (uint)(BitConverter.ToUInt32(tex.ImageData, pixelOffset)); break; case 32: Value = BitConverter.ToUInt32(tex.ImageData, pixelOffset); break; default: Value = 0; break; } uint Red, Green, Blue, Alpha, Luminance; Red = Green = Blue = Alpha = Luminance = 0xFF; if (tex.LuminanceBitSize > 0) { Luminance = (Value & luminanceBitMask) * (0xFF / luminanceBitMask); Value >>= tex.LuminanceBitSize; } switch (tex.ChannelOrder) { case ChannelOrder.Rgba: if (tex.RedBitSize > 0) { Red = (Value & redBitMask) * (0xFF / redBitMask); Value >>= tex.RedBitSize; } if (tex.GreenBitSize > 0) { Green = (Value & greenBitMask) * (0xFF / greenBitMask); Value >>= tex.GreenBitSize; } if (tex.BlueBitSize > 0) { Blue = (Value & blueBitMask) * (0xFF / blueBitMask); Value >>= tex.BlueBitSize; } if (tex.AlphaBitSize > 0) { Alpha = (Value & alphaBitMask) * (0xFF / alphaBitMask); Value >>= tex.AlphaBitSize; } break; case ChannelOrder.Abgr: if (tex.AlphaBitSize > 0) { Alpha = (Value & alphaBitMask) * (0xFF / alphaBitMask); Value >>= tex.AlphaBitSize; } if (tex.BlueBitSize > 0) { Blue = (Value & blueBitMask) * (0xFF / blueBitMask); Value >>= tex.BlueBitSize; } if (tex.GreenBitSize > 0) { Green = (Value & greenBitMask) * (0xFF / greenBitMask); Value >>= tex.GreenBitSize; } if (tex.RedBitSize > 0) { Red = (Value & redBitMask) * (0xFF / redBitMask); Value >>= tex.RedBitSize; } break; } if (tex.LuminanceBitSize > 0) { rgbaValues[Offset + 0] = (byte)Luminance; rgbaValues[Offset + 1] = (byte)Luminance; rgbaValues[Offset + 2] = (byte)Luminance; rgbaValues[Offset + 3] = (byte)Alpha; } else { rgbaValues[Offset + 0] = (byte)Blue; rgbaValues[Offset + 1] = (byte)Green; rgbaValues[Offset + 2] = (byte)Red; rgbaValues[Offset + 3] = (byte)Alpha; } Offset += 4; } } tex.PostProcess(size, rgbaValues); Marshal.Copy(rgbaValues, 0, ptr, bytes); bmp.UnlockBits(bmpData); if (crop) { Bitmap bmp2 = new Bitmap(tex.Size.Width, tex.Size.Height); using (Graphics g = Graphics.FromImage(bmp2)) g.DrawImage(bmp, new Point(0, 0)); return(bmp2); } return(bmp); }