Example #1
0
        /**
         * Ported from https://github.com/KillzXGaming/Switch-Toolbox
         */
        public static byte[] GetImageData(SBSurface surface, byte[] ImageData, int ArrayLevel, int MipLevel, int MipCount, int target = 1)
        {
            uint bpp       = TextureFormatInfo.GetBPP(surface.InternalFormat);
            uint blkWidth  = TextureFormatInfo.GetBlockWidth(surface.InternalFormat);
            uint blkHeight = TextureFormatInfo.GetBlockHeight(surface.InternalFormat);
            uint blkDepth  = TextureFormatInfo.GetBlockDepth(surface.InternalFormat);

            uint blockHeight     = GetBlockHeight(DivRoundUp((uint)surface.Height, blkHeight));
            int  BlockHeightLog2 = Convert.ToString(blockHeight, 2).Length - 1;

            uint Pitch         = 0;
            uint DataAlignment = 512;
            uint TileMode      = 0;

            int linesPerBlockHeight = (1 << BlockHeightLog2) * 8;

            uint ArrayOffset = 0;

            for (int arrayLevel = 0; arrayLevel < surface.ArrayCount; arrayLevel++)
            {
                uint SurfaceSize      = 0;
                int  blockHeightShift = 0;

                List <uint> MipOffsets = new List <uint>();

                for (int mipLevel = 0; mipLevel < MipCount; mipLevel++)
                {
                    uint width  = (uint)Math.Max(1, surface.Width >> mipLevel);
                    uint height = (uint)Math.Max(1, surface.Height >> mipLevel);
                    uint depth  = (uint)Math.Max(1, surface.Depth >> mipLevel);

                    uint size = DivRoundUp(width, blkWidth) * DivRoundUp(height, blkHeight) * bpp;

                    if (Pow2RoundUp(DivRoundUp(height, blkWidth)) < linesPerBlockHeight)
                    {
                        blockHeightShift += 1;
                    }

                    //SBConsole.WriteLine(height + " " + blkWidth + " " + Pow2RoundUp(DivRoundUp(height, blkWidth)) + " " + blockHeight + " " + blockHeightShift + " " + linesPerBlockHeight + " " + BlockHeightLog2 + " " + (int)Math.Max(0, BlockHeightLog2 - blockHeightShift));

                    uint width__  = DivRoundUp(width, blkWidth);
                    uint height__ = DivRoundUp(height, blkHeight);

                    //Calculate the mip size instead
                    byte[] AlignedData = new byte[(RoundUp(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]) / surface.ArrayCount);

                    if (msize > ImageData.Length - (ArrayOffset + MipOffsets[mipLevel]))
                    {
                        msize = (int)(ImageData.Length - (ArrayOffset + MipOffsets[mipLevel]));
                    }

                    byte[] data_ = new byte[msize];
                    if (ArrayLevel == arrayLevel && MipLevel == mipLevel)
                    {
                        Array.Copy(ImageData, ArrayOffset + MipOffsets[mipLevel], data_, 0, msize);
                    }
                    try
                    {
                        Pitch        = RoundUp(width__ * bpp, 64);
                        SurfaceSize += Pitch * RoundUp(height__, Math.Max(1, blockHeight >> blockHeightShift) * 8);

                        if (ArrayLevel == arrayLevel && MipLevel == mipLevel)
                        {
                            //SBConsole.WriteLine($"{width} {height} {blkWidth} {blkHeight} {target} {bpp} {TileMode} {(int)Math.Max(0, BlockHeightLog2 - blockHeightShift)} {data_.Length}");
                            byte[] result = 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;

                            return(result_);
                        }
                    }
                    catch (Exception e)
                    {
                        System.Windows.Forms.MessageBox.Show($"Failed to swizzle texture {surface.Name}!");
                        Console.WriteLine(e);

                        return(new byte[0]);
                    }
                }

                ArrayOffset += (uint)(ImageData.Length / surface.ArrayCount);
            }
            return(new byte[0]);
        }
Example #2
0
        public static byte[] CreateBuffer(SBSurface surface, int target = 1)
        {
            List <byte> ImageData = new List <byte>();

            if (surface.Arrays.Count == 0)
            {
                return(ImageData.ToArray());
            }

            var  MipCount  = surface.Arrays[0].Mipmaps.Count;
            uint bpp       = TextureFormatInfo.GetBPP(surface.InternalFormat);
            uint blkWidth  = TextureFormatInfo.GetBlockWidth(surface.InternalFormat);
            uint blkHeight = TextureFormatInfo.GetBlockHeight(surface.InternalFormat);
            uint blkDepth  = TextureFormatInfo.GetBlockDepth(surface.InternalFormat);

            uint blockHeight     = GetBlockHeight(DivRoundUp((uint)surface.Height, blkHeight));
            uint BlockHeightLog2 = (uint)Convert.ToString(blockHeight, 2).Length - 1;

            uint Pitch         = 0;
            uint DataAlignment = 512;
            uint TileMode      = 0;

            int linesPerBlockHeight = (1 << (int)BlockHeightLog2) * 8;

            //uint ArrayOffset = 0;
            for (int arrayLevel = 0; arrayLevel < surface.Arrays.Count; arrayLevel++)
            {
                uint SurfaceSize      = 0;
                int  blockHeightShift = 0;

                List <uint> MipOffsets = new List <uint>();

                for (int mipLevel = 0; mipLevel < MipCount; mipLevel++)
                {
                    uint width  = (uint)Math.Max(1, surface.Width >> mipLevel);
                    uint height = (uint)Math.Max(1, surface.Height >> mipLevel);
                    uint depth  = (uint)Math.Max(1, surface.Depth >> mipLevel);

                    uint size = DivRoundUp(width, blkWidth) * DivRoundUp(height, blkHeight) * bpp;

                    if (Pow2RoundUp(DivRoundUp(height, blkWidth)) < linesPerBlockHeight)
                    {
                        blockHeightShift += 1;
                    }


                    uint width__  = DivRoundUp(width, blkWidth);
                    uint height__ = DivRoundUp(height, blkHeight);

                    //Calculate the mip size instead
                    byte[] AlignedData = new byte[(RoundUp(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] + surface.Arrays[arrayLevel].Mipmaps[mipLevel].Length - MipOffsets[mipLevel]) / surface.ArrayCount);

                    //try
                    {
                        Pitch        = RoundUp(width__ * bpp, 64);
                        SurfaceSize += Pitch * RoundUp(height__, Math.Max(1, blockHeight >> blockHeightShift) * 8);

                        //Console.WriteLine($"{width} {height} {blkWidth} {blkHeight} {target} {bpp} {TileMode} {(int)Math.Max(0, BlockHeightLog2 - blockHeightShift)}");
                        var mipData = surface.Arrays[arrayLevel].Mipmaps[mipLevel];

                        /*byte[] padded = new byte[mipData.Length * 2];
                         * Array.Copy(mipData, 0, padded, 0, mipData.Length);
                         * mipData = padded;*/
                        byte[] result = Swizzle(width, height, depth, blkWidth, blkHeight, blkDepth, target, bpp, TileMode, (int)Math.Max(0, BlockHeightLog2 - blockHeightShift), mipData);
                        //Console.WriteLine(result.Length + " " + surface.Mipmaps[mipLevel].Length);
                        ImageData.AddRange(result);
                    }

                    /*catch (Exception e)
                     * {
                     *  System.Windows.Forms.MessageBox.Show($"Failed to swizzle texture {surface.Name}!");
                     *  Console.WriteLine(e);
                     *
                     *  return new byte[0];
                     * }*/
                }

                // alignment
                if (arrayLevel != surface.Arrays.Count - 1)
                {
                    ImageData.AddRange(new byte[0x1000 - (ImageData.Count % 0x1000)]);
                }
            }
            return(ImageData.ToArray());
        }