Esempio n. 1
0
        public override byte[] Rebuild()
        {
            FileOutput f = new FileOutput();

            f.Endian = Endianness.Big;

            f.writeHex("4C494748"); //LIGH
            f.writeInt(version);
            f.writeInt(frameCount);
            if (version == 5)
            {
                f.writeInt(frameDuration);
            }

            //Offsets
            int padding = 0;

            while ((((frameCount * 3) + padding) % 4) != 0) //All offsets must be multiples of 4 or the game won't use the file properly
            {
                padding++;
            }

            int[] offsets = new int[6];
            int   currOff = 0x24;

            if (version == 4)
            {
                currOff = 0x24;
            }
            else if (version == 5)
            {
                currOff = 0x28;
            }

            for (int i = 0; i < 5; i++)
            {
                offsets[i + 1] = (rgbProperties[i].enabled) ? currOff : 0x0;
                if (rgbProperties[i].enabled)
                {
                    currOff += (frameCount * 3) + padding;
                }
            }
            offsets[0] = currOff;

            for (int i = 0; i < 6; i++)
            {
                f.writeInt(offsets[i]);
            }

            //RGB properties
            for (int i = 0; i < 5; i++)
            {
                for (int j = 0; j < frameCount; j++)
                {
                    for (int k = 0; k < 3; k++)
                    {
                        f.writeByte(rgbProperties[i].frames[j][k]);
                    }
                }

                for (int j = 0; j < padding; j++)
                {
                    f.writeByte(0);
                }
            }

            //Light data
            for (int i = 0; i < frameCount; i++)
            {
                for (int j = 0; j < 17; j++)
                {
                    for (int k = 0; k < 4; k++)
                    {
                        f.writeInt((int)lightFrames[i].lightSets[j].lights[k].enabled);
                        for (int l = 0; l < 3; l++)
                        {
                            f.writeFloat(lightFrames[i].lightSets[j].lights[k].angle[l]);
                        }
                        f.writeFloat(lightFrames[i].lightSets[j].lights[k].colorHue);
                        f.writeFloat(lightFrames[i].lightSets[j].lights[k].colorSat);
                        f.writeFloat(lightFrames[i].lightSets[j].lights[k].colorVal);
                    }
                    f.writeByte(lightFrames[i].lightSets[j].fog.unknown);
                    for (int k = 0; k < 3; k++)
                    {
                        f.writeByte(lightFrames[i].lightSets[j].fog.color[k]);
                    }
                }
                f.writeByte(lightFrames[i].effect.unknown);
                for (int j = 0; j < 3; j++)
                {
                    f.writeByte(lightFrames[i].effect.color[j]);
                }
                for (int j = 0; j < 3; j++)
                {
                    f.writeFloat(lightFrames[i].effect.position[j]);
                }
            }

            return(f.getBytes());
        }
Esempio n. 2
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());
        }