Beispiel #1
0
        public override void Open()
        {
            using (BinaryReader reader = new BinaryReader(new FileStream(AbsolutePath, FileMode.Open)))
            {
                Mipmaps = new List <byte[]>();
                // TODO: Why are there empty streams?
                if (reader.BaseStream.Length == 0)
                {
                    return;
                }

                reader.BaseStream.Position = reader.BaseStream.Length - 0xB0;


                int[] mipmapSizes = new int[16];
                for (int i = 0; i < mipmapSizes.Length; i++)
                {
                    mipmapSizes[i] = reader.ReadInt32();
                }

                reader.ReadChars(4); // TNX magic

                TexName = ReadTexName(reader);

                Width  = reader.ReadInt32();
                Height = reader.ReadInt32();
                Depth  = reader.ReadInt32();

                Format = (NUTEX_FORMAT)reader.ReadByte();

                reader.ReadByte();

                ushort Padding = reader.ReadUInt16();
                reader.ReadUInt32();

                int    MipCount     = reader.ReadInt32();
                int    Alignment    = reader.ReadInt32();
                int    ArrayCount   = reader.ReadInt32();
                int    ImageSize    = reader.ReadInt32();
                char[] Magic        = reader.ReadChars(4);
                int    MajorVersion = reader.ReadInt16();
                int    MinorVersion = reader.ReadInt16();

                uint blkWidth  = (uint)blkDims[Format].X;
                uint blkHeight = (uint)blkDims[Format].Y;

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

                uint bpp = GetBpps(Format);

                reader.BaseStream.Position = 0;
                int blockHeightShift = 0;
                for (int i = 0; i < 1; i++)
                {
                    int size = mipmapSizes[i];

                    if (i == 0 && size % Alignment != 0)
                    {
                        size += Alignment - (size % Alignment);
                    }

                    byte[] deswiz  = SwitchSwizzler.Deswizzle((uint)Width, (uint)Height, blkWidth, blkHeight, 0, bpp, tileMode, (int)Math.Max(0, BlockHeightLog2 - blockHeightShift), reader.ReadBytes(ImageSize));
                    byte[] trimmed = new byte[mipmapSizes[0]];
                    Array.Copy(deswiz, 0, trimmed, 0, trimmed.Length);

                    Mipmaps.Add(trimmed);
                }
            }
        }
Beispiel #2
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);
        }
Beispiel #3
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);
        }