public byte[] DecodeImage(STGenericTexture texture, byte[] data, uint width, uint height, int array, int mip) { uint bpp = TextureFormatHelper.GetBytesPerPixel(OutputFormat); GX2.GX2Surface surf = new GX2.GX2Surface(); surf.bpp = bpp; surf.height = texture.Height; surf.width = texture.Width; surf.depth = texture.ArrayCount; surf.alignment = Alignment; surf.aa = (uint)AAMode; surf.dim = (uint)SurfaceDimension; surf.format = (uint)Format; surf.use = (uint)SurfaceUse; surf.pitch = Pitch; surf.data = data; surf.mipData = MipData != null ? MipData : data; surf.mipOffset = MipOffsets != null ? MipOffsets : new uint[0]; surf.numMips = texture.MipCount; surf.numArray = texture.ArrayCount; surf.tileMode = (uint)TileMode; surf.swizzle = Swizzle; Console.WriteLine("WII U DECODE"); return(GX2.Decode(surf, array, mip)); }
//Method from https://github.com/aboood40091/BNTX-Editor/blob/master/formConv.py public bool Decode(TexFormat format, byte[] input, int width, int height, out byte[] output) { if (!IsSupported(format)) { output = null; return(false); } uint bpp = TextureFormatHelper.GetBytesPerPixel(format); int size = width * height * 4; bpp = (uint)(input.Length / (width * height)); output = new byte[size]; int inPos = 0; int outPos = 0; byte[] comp = new byte[] { 0, 0, 0, 0xFF, 0, 0xFF }; byte[] compSel = new byte[4] { 0, 1, 2, 3 }; if (format == TexFormat.LA8) { compSel = new byte[4] { 0, 0, 0, 1 }; bpp = 2; } else if (format == TexFormat.L8) { compSel = new byte[4] { 0, 0, 0, 5 } } ; for (int Y = 0; Y < height; Y++) { for (int X = 0; X < width; X++) { inPos = (Y * width + X) * (int)bpp; outPos = (Y * width + X) * 4; int pixel = 0; for (int i = 0; i < bpp; i++) { pixel |= input[inPos + i] << (8 * i); } comp = GetComponentsFromPixel(format, pixel, comp); output[outPos + 3] = comp[compSel[3]]; output[outPos + 2] = comp[compSel[2]]; output[outPos + 1] = comp[compSel[1]]; output[outPos + 0] = comp[compSel[0]]; } } return(output != null); }
public static byte[] GetImageData(STGenericTexture texture, byte[] ImageData, int ArrayLevel, int MipLevel, int DepthLevel, uint BlockHeightLog2, int target = 1, bool LinearTileMode = false) { var format = texture.Platform.OutputFormat; uint bpp = TextureFormatHelper.GetBytesPerPixel(format); uint blkWidth = texture.GetBlockWidth(); uint blkHeight = texture.GetBlockHeight(); uint blkDepth = texture.GetBlockDepth(); uint blockHeight = TegraX1Swizzle.GetBlockHeight(TegraX1Swizzle.DIV_ROUND_UP(texture.Height, blkHeight)); Console.WriteLine($"format {format} {bpp} {blkWidth} {blkHeight} {blockHeight}"); Console.WriteLine($"ArrayLevel {ArrayLevel} {MipLevel} {DepthLevel} {BlockHeightLog2}"); uint Pitch = 0; uint DataAlignment = 512; uint TileMode = 0; if (LinearTileMode) { TileMode = 1; } uint numDepth = 1; if (texture.Depth > 1) { numDepth = texture.Depth; } int linesPerBlockHeight = (1 << (int)BlockHeightLog2) * 8; uint ArrayOffset = 0; for (int depthLevel = 0; depthLevel < numDepth; depthLevel++) { for (int arrayLevel = 0; arrayLevel < texture.ArrayCount; arrayLevel++) { uint SurfaceSize = 0; int blockHeightShift = 0; List <uint> MipOffsets = new List <uint>(); for (int mipLevel = 0; mipLevel < texture.MipCount; mipLevel++) { uint width = (uint)Math.Max(1, texture.Width >> mipLevel); uint height = (uint)Math.Max(1, texture.Height >> mipLevel); uint depth = (uint)Math.Max(1, texture.Depth >> mipLevel); uint size = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth) * TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight) * bpp; Console.WriteLine($"size " + size); if (TegraX1Swizzle.pow2_round_up(TegraX1Swizzle.DIV_ROUND_UP(height, blkWidth)) < linesPerBlockHeight) { blockHeightShift += 1; } uint width__ = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth); uint height__ = TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight); //Calculate the mip size instead byte[] AlignedData = new byte[(TegraX1Swizzle.round_up(SurfaceSize, DataAlignment) - SurfaceSize)]; SurfaceSize += (uint)AlignedData.Length; MipOffsets.Add(SurfaceSize); //Get the first mip offset and current one and the total image size int msize = (int)((MipOffsets[0] + ImageData.Length - MipOffsets[mipLevel]) / texture.ArrayCount); byte[] data_ = ByteUtils.SubArray(ImageData, ArrayOffset + MipOffsets[mipLevel], (uint)msize); try { Pitch = TegraX1Swizzle.round_up(width__ * bpp, 64); SurfaceSize += Pitch * TegraX1Swizzle.round_up(height__, Math.Max(1, blockHeight >> blockHeightShift) * 8); byte[] result = TegraX1Swizzle.deswizzle(width, height, depth, blkWidth, blkHeight, blkDepth, target, bpp, TileMode, (int)Math.Max(0, BlockHeightLog2 - blockHeightShift), data_); //Create a copy and use that to remove uneeded data byte[] result_ = new byte[size]; Array.Copy(result, 0, result_, 0, size); result = null; if (ArrayLevel == arrayLevel && MipLevel == mipLevel && DepthLevel == depthLevel) { return(result_); } } catch (Exception e) { Console.WriteLine($"Failed to swizzle texture {texture.Name}!"); Console.WriteLine(e); return(new byte[0]); } } ArrayOffset += (uint)(ImageData.Length / texture.ArrayCount); } } return(new byte[0]); }
public static List <uint[]> GenerateMipSizes(TexFormat Format, uint Width, uint Height, uint Depth, uint SurfaceCount, uint MipCount, uint ImageSize) { List <uint[]> MipMapSizes = new List <uint[]>(); uint bpp = TextureFormatHelper.GetBytesPerPixel(Format); uint blkWidth = TextureFormatHelper.GetBlockWidth(Format); uint blkHeight = TextureFormatHelper.GetBlockHeight(Format); uint blkDepth = TextureFormatHelper.GetBlockDepth(Format); uint blockHeight = TegraX1Swizzle.GetBlockHeight(TegraX1Swizzle.DIV_ROUND_UP(Height, blkHeight)); uint BlockHeightLog2 = (uint)Convert.ToString(blockHeight, 2).Length - 1; uint Pitch = 0; uint DataAlignment = 512; int linesPerBlockHeight = (1 << (int)BlockHeightLog2) * 8; uint ArrayCount = SurfaceCount; uint ArrayOffset = 0; for (int arrayLevel = 0; arrayLevel < ArrayCount; arrayLevel++) { uint SurfaceSize = 0; int blockHeightShift = 0; uint[] MipOffsets = new uint[MipCount]; for (int mipLevel = 0; mipLevel < MipCount; mipLevel++) { uint width = (uint)Math.Max(1, Width >> mipLevel); uint height = (uint)Math.Max(1, Height >> mipLevel); uint depth = (uint)Math.Max(1, Depth >> mipLevel); uint size = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth) * TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight) * bpp; if (TegraX1Swizzle.pow2_round_up(TegraX1Swizzle.DIV_ROUND_UP(height, blkWidth)) < linesPerBlockHeight) { blockHeightShift += 1; } uint width__ = TegraX1Swizzle.DIV_ROUND_UP(width, blkWidth); uint height__ = TegraX1Swizzle.DIV_ROUND_UP(height, blkHeight); //Calculate the mip size instead byte[] AlignedData = new byte[(TegraX1Swizzle.round_up(SurfaceSize, DataAlignment) - SurfaceSize)]; SurfaceSize += (uint)AlignedData.Length; MipOffsets[mipLevel] = (SurfaceSize); //Get the first mip offset and current one and the total image size int msize = (int)((MipOffsets[0] + ImageSize - MipOffsets[mipLevel]) / ArrayCount); Pitch = TegraX1Swizzle.round_up(width__ * bpp, 64); SurfaceSize += Pitch * TegraX1Swizzle.round_up(height__, Math.Max(1, blockHeight >> blockHeightShift) * 8); } ArrayOffset += (uint)(ImageSize / ArrayCount); MipMapSizes.Add(MipOffsets); } return(MipMapSizes); }