public static byte[] DecodeBlock(byte[] Input, int Width, int Height, TEX_FORMAT Format) { if (Format == TEX_FORMAT.ETC1 || Format == TEX_FORMAT.ETC1_A4) { return(ETC1.ETC1Decompress(Input, Width, Height, Format == TEX_FORMAT.ETC1_A4)); } byte[] Output = new byte[Width * Height * 4]; int Increment = FmtBPP[(int)ConvertToPICAFormat(Format)] / 8; if (Increment == 0) { Increment = 1; } int IOffset = 0; for (int TY = 0; TY < Height; TY += 8) { for (int TX = 0; TX < Width; TX += 8) { for (int Px = 0; Px < 64; Px++) { int X = SwizzleLUT[Px] & 7; int Y = (SwizzleLUT[Px] - X) >> 3; int OOffet = (TX + X + ((Height - 1 - (TY + Y)) * Width)) * 4; switch (Format) { case TEX_FORMAT.R8G8_UNORM: Output[OOffet + 0] = Input[IOffset + 3]; Output[OOffet + 1] = Input[IOffset + 2]; Output[OOffet + 2] = Input[IOffset + 1]; Output[OOffet + 3] = Input[IOffset + 0]; break; case TEX_FORMAT.R8G8B8A8_UNORM: Output[OOffet + 0] = Input[IOffset + 2]; Output[OOffet + 1] = Input[IOffset + 1]; Output[OOffet + 2] = Input[IOffset + 0]; Output[OOffet + 3] = 0xff; break; case TEX_FORMAT.B5G5R5A1_UNORM: DecodeRGBA5551(Output, OOffet, GetUShort(Input, IOffset)); break; case TEX_FORMAT.B5G6R5_UNORM: DecodeRGB565(Output, OOffet, GetUShort(Input, IOffset)); break; case TEX_FORMAT.B4G4R4A4_UNORM: DecodeRGBA4(Output, OOffet, GetUShort(Input, IOffset)); break; case TEX_FORMAT.LA8: Output[OOffet + 0] = Input[IOffset + 1]; Output[OOffet + 1] = Input[IOffset + 1]; Output[OOffet + 2] = Input[IOffset + 1]; Output[OOffet + 3] = Input[IOffset + 0]; break; case TEX_FORMAT.HIL08: Output[OOffet + 0] = Input[IOffset + 1]; Output[OOffet + 1] = Input[IOffset + 0]; Output[OOffet + 2] = 0; Output[OOffet + 3] = 0xff; break; case TEX_FORMAT.L8: Output[OOffet + 0] = Input[IOffset]; Output[OOffet + 1] = Input[IOffset]; Output[OOffet + 2] = Input[IOffset]; Output[OOffet + 3] = 0xff; break; case TEX_FORMAT.A8_UNORM: Output[OOffet + 0] = 0xff; Output[OOffet + 1] = 0xff; Output[OOffet + 2] = 0xff; Output[OOffet + 3] = Input[IOffset]; break; case TEX_FORMAT.LA4: Output[OOffet + 0] = (byte)((Input[IOffset] >> 4) | (Input[IOffset] & 0xf0)); Output[OOffet + 1] = (byte)((Input[IOffset] >> 4) | (Input[IOffset] & 0xf0)); Output[OOffet + 2] = (byte)((Input[IOffset] >> 4) | (Input[IOffset] & 0xf0)); Output[OOffet + 3] = (byte)((Input[IOffset] << 4) | (Input[IOffset] & 0x0f)); break; case TEX_FORMAT.L4: int L = (Input[IOffset >> 1] >> ((IOffset & 1) << 2)) & 0xf; Output[OOffet + 0] = (byte)((L << 4) | L); Output[OOffet + 1] = (byte)((L << 4) | L); Output[OOffet + 2] = (byte)((L << 4) | L); Output[OOffet + 3] = 0xff; break; case TEX_FORMAT.A4: int A = (Input[IOffset >> 1] >> ((IOffset & 1) << 2)) & 0xf; Output[OOffet + 0] = 0xff; Output[OOffet + 1] = 0xff; Output[OOffet + 2] = 0xff; Output[OOffet + 3] = (byte)((A << 4) | A); break; } Output[OOffet + 0] = 0xff; Output[OOffet + 1] = 0xff; Output[OOffet + 2] = 0xff; Output[OOffet + 3] = Input[IOffset]; IOffset += Increment; } } } return(Output); }
/// <summary> /// Gets a <see cref="Bitmap"/> given an array and mip index. /// </summary> /// <param name="ArrayIndex">The index of the surface/array. Cubemaps will have 6</param> /// <param name="MipLevel">The index of the mip level.</param> /// <returns></returns> public Bitmap GetBitmap(int ArrayLevel = 0, int MipLevel = 0) { uint width = Math.Max(1, Width >> MipLevel); uint height = Math.Max(1, Height >> MipLevel); byte[] data = GetImageData(ArrayLevel, MipLevel); try { if (data == null) { throw new Exception("Data is null!"); } if (PlatformSwizzle == PlatformSwizzle.Platform_3DS && !IsCompressed(Format)) { 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); } 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: 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)); default: return(BitmapExtension.GetBitmap(DecodeBlock(data, width, height, Format), (int)width, (int)height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)); } } catch (Exception ex) { Forms.STErrorDialog.Show($"Texture failed to load!", "Texture [GetBitmap({MipLevel},{ArrayLevel})]", DebugInfo() + " \n" + ex); try { if (Format == TEX_FORMAT.BC1_UNORM) { return(DDSCompressor.DecompressBC1(data, (int)Width, (int)Height, false)); } else if (Format == TEX_FORMAT.BC1_UNORM_SRGB) { return(DDSCompressor.DecompressBC1(data, (int)Width, (int)Height, true)); } else if (Format == TEX_FORMAT.BC3_UNORM_SRGB) { return(DDSCompressor.DecompressBC3(data, (int)Width, (int)Height, false)); } else if (Format == TEX_FORMAT.BC3_UNORM) { return(DDSCompressor.DecompressBC3(data, (int)Width, (int)Height, true)); } else if (Format == TEX_FORMAT.BC4_UNORM) { return(DDSCompressor.DecompressBC4(data, (int)Width, (int)Height, false)); } else if (Format == TEX_FORMAT.BC4_SNORM) { return(DDSCompressor.DecompressBC4(data, (int)Width, (int)Height, true)); } else if (Format == TEX_FORMAT.BC5_UNORM) { return(DDSCompressor.DecompressBC5(data, (int)Width, (int)Height, false)); } else { if (Runtime.UseOpenGL) { Runtime.OpenTKInitialized = true; LoadOpenGLTexture(); return(RenderableTex.GLTextureToBitmap(RenderableTex)); } } } catch { Forms.STErrorDialog.Show($"Texture failed to load!", "Texture [GetBitmap({MipLevel},{ArrayLevel})]", DebugInfo() + " \n" + ex); } return(null); } }