Exemple #1
0
        public byte[] Rebuild()
        {
            FileOutput o    = new FileOutput();
            FileOutput data = new FileOutput();

            //We always want BE for the first six bytes
            o.Endian    = Endianness.Big;
            data.Endian = Endianness.Big;

            if (Endian == Endianness.Big)
            {
                o.writeUInt(0x4E545033); //NTP3
            }
            else if (Endian == Endianness.Little)
            {
                o.writeUInt(0x4E545744); //NTWD
            }

            //Most NTWU NUTs are 0x020E, which isn't valid for NTP3/NTWD
            if (Version > 0x0200)
            {
                Version = 0x0200;
            }
            o.writeUShort(Version);

            //After that, endian is used appropriately
            o.Endian    = Endian;
            data.Endian = Endian;

            o.writeUShort((ushort)Textures.Count);
            o.writeInt(0);
            o.writeInt(0);

            //calculate total header size
            uint headerLength = 0;

            foreach (NutTexture texture in Textures)
            {
                byte surfaceCount = (byte)texture.surfaces.Count;
                bool isCubemap    = surfaceCount == 6;
                if (surfaceCount < 1 || surfaceCount > 6)
                {
                    throw new NotImplementedException($"Unsupported surface amount {surfaceCount} for texture with hash 0x{texture.HashId:X}. 1 to 6 faces are required.");
                }
                else if (surfaceCount > 1 && surfaceCount < 6)
                {
                    throw new NotImplementedException($"Unsupported cubemap face amount for texture with hash 0x{texture.HashId:X}. Six faces are required.");
                }
                byte mipmapCount = (byte)texture.surfaces[0].mipmaps.Count;

                ushort headerSize = 0x50;
                if (isCubemap)
                {
                    headerSize += 0x10;
                }
                if (mipmapCount > 1)
                {
                    headerSize += (ushort)(mipmapCount * 4);
                    while (headerSize % 0x10 != 0)
                    {
                        headerSize += 1;
                    }
                }

                headerLength += headerSize;
            }

            // write headers+data
            foreach (NutTexture texture in Textures)
            {
                byte surfaceCount = (byte)texture.surfaces.Count;
                bool isCubemap    = surfaceCount == 6;
                byte mipmapCount  = (byte)texture.surfaces[0].mipmaps.Count;

                uint dataSize = 0;

                foreach (var mip in texture.GetAllMipmaps())
                {
                    dataSize += (uint)mip.Length;
                    while (dataSize % 0x10 != 0)
                    {
                        dataSize += 1;
                    }
                }

                ushort headerSize = 0x50;
                if (isCubemap)
                {
                    headerSize += 0x10;
                }
                if (mipmapCount > 1)
                {
                    headerSize += (ushort)(mipmapCount * 4);
                    while (headerSize % 0x10 != 0)
                    {
                        headerSize += 1;
                    }
                }

                o.writeUInt(dataSize + headerSize);
                o.writeUInt(0);
                o.writeUInt(dataSize);
                o.writeUShort(headerSize);
                o.writeUShort(0);

                o.writeByte(0);
                o.writeByte(mipmapCount);
                o.writeByte(0);
                o.writeByte(texture.getNutFormat());
                o.writeShort(texture.Width);
                o.writeShort(texture.Height);
                o.writeInt(0);
                o.writeUInt(texture.DdsCaps2);

                if (Version < 0x0200)
                {
                    o.writeUInt(0);
                }
                else if (Version >= 0x0200)
                {
                    o.writeUInt((uint)(headerLength + data.size()));
                }
                headerLength -= headerSize;
                o.writeInt(0);
                o.writeInt(0);
                o.writeInt(0);

                if (isCubemap)
                {
                    o.writeInt(texture.surfaces[0].mipmaps[0].Length);
                    o.writeInt(texture.surfaces[0].mipmaps[0].Length);
                    o.writeInt(0);
                    o.writeInt(0);
                }

                if (texture.getNutFormat() == 14 || texture.getNutFormat() == 17)
                {
                    texture.SwapChannelOrderDown();
                }

                for (byte surfaceLevel = 0; surfaceLevel < surfaceCount; ++surfaceLevel)
                {
                    for (byte mipLevel = 0; mipLevel < mipmapCount; ++mipLevel)
                    {
                        int ds = data.size();
                        data.writeBytes(texture.surfaces[surfaceLevel].mipmaps[mipLevel]);
                        data.align(0x10);
                        if (mipmapCount > 1 && surfaceLevel == 0)
                        {
                            o.writeInt(data.size() - ds);
                        }
                    }
                }
                o.align(0x10);

                if (texture.getNutFormat() == 14 || texture.getNutFormat() == 17)
                {
                    texture.SwapChannelOrderUp();
                }

                o.writeBytes(new byte[] { 0x65, 0x58, 0x74, 0x00 }); // "eXt\0"
                o.writeInt(0x20);
                o.writeInt(0x10);
                o.writeInt(0x00);

                o.writeBytes(new byte[] { 0x47, 0x49, 0x44, 0x58 }); // "GIDX"
                o.writeInt(0x10);
                o.writeInt(texture.HashId);
                o.writeInt(0);

                if (Version < 0x0200)
                {
                    o.writeOutput(data);
                    data = new FileOutput();
                }
            }

            if (Version >= 0x0200)
            {
                o.writeOutput(data);
            }

            return(o.getBytes());
        }