예제 #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>
        /// 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);
        }