コード例 #1
0
        private byte[] Deswizzle(uint width, uint height, uint numMipmaps, byte[] image)
        {
            uint bpp           = 8;
            uint blkWidth      = 4;
            uint blkHeight     = 4;
            uint dataAlignment = 512;

            uint blockHeight         = SwitchSwizzler.GetBlockHeight(SwitchSwizzler.DivRoundUp(height, blkHeight));
            uint blockHeightLog2     = (uint)System.Convert.ToString(blockHeight, 2).Length - 1;
            int  linesPerBlockHeight = (1 << (int)blockHeightLog2) * 8;

            uint totalSize = 0;

            for (var i = 0; i < numMipmaps; i++)
            {
                uint mipmapWidth  = Math.Max(1, width >> i);
                uint mipmapHeight = Math.Max(1, height >> i);
                uint mipmapSize   = SwitchSwizzler.DivRoundUp(mipmapWidth, blkWidth) *
                                    SwitchSwizzler.DivRoundUp(mipmapHeight, blkHeight) *
                                    bpp;

                totalSize += mipmapSize;
            }

            var result = new byte[totalSize];

            uint surfaceSize      = 0;
            var  blockHeightShift = 0;

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

            uint resultOffset = 0;

            for (var i = 0; i < numMipmaps; i++)
            {
                uint mipmapWidth  = Math.Max(1, width >> i);
                uint mipmapHeight = Math.Max(1, height >> i);
                uint mipmapSize   = SwitchSwizzler.DivRoundUp(mipmapWidth, blkWidth) *
                                    SwitchSwizzler.DivRoundUp(mipmapHeight, blkHeight) *
                                    bpp;

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

                uint roundWidth  = SwitchSwizzler.DivRoundUp(mipmapWidth, blkWidth);
                uint roundHeight = SwitchSwizzler.DivRoundUp(mipmapHeight, blkHeight);

                surfaceSize += SwitchSwizzler.RoundUp(surfaceSize, dataAlignment) - surfaceSize;
                mipOffsets.Add(surfaceSize);

                var msize = (int)(mipOffsets[0] + image.Length - mipOffsets[i]);

                var mipmap = new byte[msize];
                Array.Copy(image, mipOffsets[i], mipmap, 0, msize);

                var info = new SwizzleInfo
                {
                    Width           = mipmapWidth,
                    Height          = mipmapHeight,
                    Depth           = 1,
                    BlkWidth        = blkWidth,
                    BlkHeight       = blkHeight,
                    BlkDepth        = 1,
                    RoundPitch      = 1,
                    Bpp             = bpp,
                    TileMode        = 0,
                    BlockHeightLog2 = (int)Math.Max(0, blockHeightLog2 - blockHeightShift),
                };

                uint pitch = SwitchSwizzler.RoundUp(roundWidth * bpp, 64);
                surfaceSize += pitch *
                               SwitchSwizzler.RoundUp(roundHeight, Math.Max(1, blockHeight >> blockHeightShift) * 8);
                byte[] deswizzled = SwitchSwizzler.Deswizzle(info, mipmap);
                Array.Copy(deswizzled, 0, result, resultOffset, mipmapSize);
                resultOffset += mipmapSize;
            }

            return(result);
        }
コード例 #2
0
 /// <summary>
 /// Swizzles an image.
 /// </summary>
 /// <param name="info">Image and swizzle information.</param>
 /// <param name="data">Image data.</param>
 /// <returns>The swizzled image data.</returns>
 public static byte[] Swizzle(SwizzleInfo info, byte[] data)
 {
     return(info != null?Swizzle(info, data, 1) : data);
 }
コード例 #3
0
        private static byte[] Swizzle(SwizzleInfo info, byte[] data, int toSwizzle)
        {
            var blockHeight = (uint)(1 << info.BlockHeightLog2);

            uint width  = DivRoundUp(info.Width, info.BlkWidth);
            uint height = DivRoundUp(info.Height, info.BlkHeight);

            uint pitch;
            uint surfaceSize;

            if (info.TileMode == 1)
            {
                pitch = width * info.Bpp;

                if (info.RoundPitch == 1)
                {
                    pitch = RoundUp(pitch, 32);
                }

                surfaceSize = pitch * height;
            }
            else
            {
                pitch       = RoundUp(width * info.Bpp, 64);
                surfaceSize = pitch * RoundUp(height, blockHeight * 8);
            }

            var result = new byte[surfaceSize];

            for (uint y = 0; y < height; y++)
            {
                for (uint x = 0; x < width; x++)
                {
                    uint swizzledPosition;

                    if (info.TileMode == 1)
                    {
                        swizzledPosition = (y * pitch) + (x * info.Bpp);
                    }
                    else
                    {
                        swizzledPosition = GetAddrBlockLinear(x, y, width, info.Bpp, 0, blockHeight);
                    }

                    uint originalPosition = ((y * width) + x) * info.Bpp;

                    if (swizzledPosition + info.Bpp > surfaceSize)
                    {
                        continue;
                    }

                    if (toSwizzle == 0)
                    {
                        Array.Copy(data, swizzledPosition, result, originalPosition, info.Bpp);
                    }
                    else
                    {
                        Array.Copy(data, originalPosition, result, swizzledPosition, info.Bpp);
                    }
                }
            }

            return(result);
        }
コード例 #4
0
        /// <summary>
        /// Write the swizzled mipmaps to a DataStream.
        /// </summary>
        /// <param name="height">Image height (in pixels).</param>
        /// <param name="width">Image width (in pixels).</param>
        /// <param name="mipmaps">The list of mipmaps.</param>
        /// <returns>The DataStream.</returns>
        protected override DataStream Write(uint height, uint width, List <byte[]> mipmaps)
        {
            if (mipmaps == null)
            {
                throw new ArgumentNullException(nameof(mipmaps));
            }

            DataStream outputDataStream = DataStreamFactory.FromMemory();
            var        writer           = new DataWriter(outputDataStream)
            {
                DefaultEncoding = Encoding.ASCII,
                Endianness      = EndiannessMode.LittleEndian,
            };

            writer.Write(0x20L);
            writer.Write(0x10L);
            writer.Write(0x20L);
            writer.Write(0x00L); // Size
            writer.Write(0x00L);
            writer.Write(0x00L);

            writer.Write(0x20L);
            writer.Write(0x18L);
            writer.Write(0x28L);
            writer.Write(0x00L); // Size - 0x38

            writer.Write(width);
            writer.Write(height);
            writer.Write(0x01);
            writer.Write(0x01);

            writer.Write(0x49);
            writer.Write(mipmaps.Count);

            var blockHeightShift = 0;

            const uint blkWidth  = 4;
            const uint blkHeight = 4;
            const uint bpp       = 8;

            uint blockHeight     = SwitchSwizzler.GetBlockHeight(SwitchSwizzler.DivRoundUp(height, blkHeight));
            uint blockHeightLog2 = (uint)System.Convert.ToString(blockHeight, 2).Length - 1;

            uint linesPerBlockHeight = blockHeight * 8;

            for (var mipLevel = 0; mipLevel < mipmaps.Count; mipLevel++)
            {
                byte[] mipmap = mipmaps[mipLevel];

                uint mipmapWidth  = Math.Max(1, width >> mipLevel);
                uint mipmapHeight = Math.Max(1, height >> mipLevel);

                uint roundedHeight = SwitchSwizzler.DivRoundUp(mipmapHeight, blkHeight);

                if (SwitchSwizzler.Pow2RoundUp(roundedHeight) < linesPerBlockHeight)
                {
                    blockHeightShift += 1;
                }

                var info = new SwizzleInfo
                {
                    Width           = mipmapWidth,
                    Height          = mipmapHeight,
                    Depth           = 1,
                    BlkWidth        = blkWidth,
                    BlkHeight       = blkHeight,
                    BlkDepth        = 1,
                    RoundPitch      = 1,
                    Bpp             = bpp,
                    TileMode        = 0,
                    BlockHeightLog2 = (int)Math.Max(0, blockHeightLog2 - blockHeightShift),
                };

                byte[] swizzled = SwitchSwizzler.Swizzle(info, mipmap);
                writer.Write(swizzled);
            }

            writer.Stream.Seek(0x18, System.IO.SeekOrigin.Begin);
            writer.Write(outputDataStream.Length - 0x30);

            writer.Stream.Seek(0x48, System.IO.SeekOrigin.Begin);
            writer.Write(outputDataStream.Length - 0x68);

            return(outputDataStream);
        }