Exemple #1
0
        /// <summary>
        /// Reads direct information from track
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="flags"></param>
        /// <returns></returns>
        private object ReadDirect(SSBHParser reader, uint flags)
        {
            if (CheckFlag(flags, 0x00FF, ANIM_TRACKFLAGS.Transform))
            {
                var Transform = new AnimTrackTransform()
                {
                    SX = reader.ReadSingle(),
                    SY = reader.ReadSingle(),
                    SZ = reader.ReadSingle(),
                    RX = reader.ReadSingle(),
                    RY = reader.ReadSingle(),
                    RZ = reader.ReadSingle(),
                    RW = reader.ReadSingle(),
                    X  = reader.ReadSingle(),
                    Y  = reader.ReadSingle(),
                    Z  = reader.ReadSingle(),
                    CompensateScale = reader.ReadInt32()
                };

                return(Transform);
            }

            if (CheckFlag(flags, 0x00FF, ANIM_TRACKFLAGS.Texture))
            {
                return(new AnimTrackTexture()
                {
                    UnkFloat1 = reader.ReadSingle(),
                    UnkFloat2 = reader.ReadSingle(),
                    UnkFloat3 = reader.ReadSingle(),
                    UnkFloat4 = reader.ReadSingle(),
                    Unknown = reader.ReadInt32()
                });
            }

            if (CheckFlag(flags, 0x00FF, ANIM_TRACKFLAGS.Float))
            {
                return(reader.ReadSingle());
            }

            if (CheckFlag(flags, 0x00FF, ANIM_TRACKFLAGS.PatternIndex))
            {
                return(reader.ReadInt32());
            }

            if (CheckFlag(flags, 0x00FF, ANIM_TRACKFLAGS.Boolean))
            {
                return(reader.ReadByte() == 1);
            }

            if (CheckFlag(flags, 0x00FF, ANIM_TRACKFLAGS.Vector4))
            {
                return(new AnimTrackCustomVector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()));
            }

            return(null);
        }
        /// <summary>
        /// Reads direct information from track
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="flags"></param>
        /// <returns></returns>
        private object ReadDirect(SsbhParser reader, uint flags)
        {
            if (CheckFlag(flags, 0x00FF, AnimTrackFlags.Transform))
            {
                var transform = new AnimTrackTransform()
                {
                    Sx = reader.ReadSingle(),
                    Sy = reader.ReadSingle(),
                    Sz = reader.ReadSingle(),
                    Rx = reader.ReadSingle(),
                    Ry = reader.ReadSingle(),
                    Rz = reader.ReadSingle(),
                    Rw = reader.ReadSingle(),
                    X  = reader.ReadSingle(),
                    Y  = reader.ReadSingle(),
                    Z  = reader.ReadSingle(),
                    CompensateScale = reader.ReadInt32()
                };

                return(transform);
            }

            if (CheckFlag(flags, 0x00FF, AnimTrackFlags.Texture))
            {
                return(new AnimTrackTexture()
                {
                    UnkFloat1 = reader.ReadSingle(),
                    UnkFloat2 = reader.ReadSingle(),
                    UnkFloat3 = reader.ReadSingle(),
                    UnkFloat4 = reader.ReadSingle(),
                    Unknown = reader.ReadInt32()
                });
            }

            if (CheckFlag(flags, 0x00FF, AnimTrackFlags.Float))
            {
                return(reader.ReadSingle());
            }

            if (CheckFlag(flags, 0x00FF, AnimTrackFlags.PatternIndex))
            {
                return(reader.ReadInt32());
            }

            if (CheckFlag(flags, 0x00FF, AnimTrackFlags.Boolean))
            {
                return(reader.ReadByte() == 1);
            }

            if (CheckFlag(flags, 0x00FF, AnimTrackFlags.Vector4))
            {
                return(new AnimTrackCustomVector4(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()));
            }

            return(null);
        }
Exemple #3
0
        /// <summary>
        /// Compresses <see cref="AnimTrackTransform" track and writes to writer/>
        /// </summary>
        /// <param name="w"></param>
        /// <param name="values"></param>
        private void CompressTransformTracks(BinaryWriter w, IList <object> values)
        {
            Quantanizer SX = new Quantanizer();
            Quantanizer SY = new Quantanizer();
            Quantanizer SZ = new Quantanizer();
            Quantanizer RX = new Quantanizer();
            Quantanizer RY = new Quantanizer();
            Quantanizer RZ = new Quantanizer();
            Quantanizer X  = new Quantanizer();
            Quantanizer Y  = new Quantanizer();
            Quantanizer Z  = new Quantanizer();

            // pre-process
            foreach (AnimTrackTransform transform in values)
            {
                SX.Add(transform.SX);
                SY.Add(transform.SY);
                SZ.Add(transform.SZ);
                RX.Add(transform.RX);
                RY.Add(transform.RY);
                RZ.Add(transform.RZ);
                X.Add(transform.X);
                Y.Add(transform.Y);
                Z.Add(transform.Z);
            }

            short  Flags        = 0;
            ushort BitsPerEntry = 0;

            bool hasScale    = (!SX.Constant || !SY.Constant || !SZ.Constant);
            bool hasRotation = (!RX.Constant || !RY.Constant || !RZ.Constant);
            bool hasPosition = (!X.Constant || !Y.Constant || !Z.Constant);


            if (!hasScale)
            {
                Flags |= 0x02;
            }
            else
            {
                BitsPerEntry += (ushort)((SX.Constant ? 0 : SX.GetBitCount(Epsilon)) + (SY.Constant ? 0 : SY.GetBitCount(Epsilon)) + (SZ.Constant ? 0 : SZ.GetBitCount(Epsilon)));
                Flags        |= 0x01;
            }
            if (hasRotation)
            {
                BitsPerEntry += (ushort)((RX.Constant ? 0 : RX.GetBitCount(Epsilon)) + (RY.Constant ? 0 : RY.GetBitCount(Epsilon)) + (RZ.Constant ? 0 : RZ.GetBitCount(Epsilon)) + 1); // the 1 is for extra w rotation bit
                Flags        |= 0x04;
            }
            if (hasPosition)
            {
                BitsPerEntry += (ushort)((X.Constant ? 0 : X.GetBitCount(Epsilon)) + (Y.Constant ? 0 : Y.GetBitCount(Epsilon)) + (Z.Constant ? 0 : Z.GetBitCount(Epsilon)));
                Flags        |= 0x08;
            }

            // Compressed Header
            w.Write((short)0x04);
            w.Write(Flags);
            w.Write((short)(0x10 + 0x10 * 9));             // default values offset
            w.Write(BitsPerEntry);
            w.Write(0x10 + 0x10 * 9 + sizeof(float) * 11); // compressed data start
            w.Write(values.Count);                         // frame count

            // write chunks
            w.Write(SX.Min); w.Write(SX.Max); w.Write((long)SX.GetBitCount(Epsilon));
            w.Write(SY.Min); w.Write(SY.Max); w.Write((long)SY.GetBitCount(Epsilon));
            w.Write(SZ.Min); w.Write(SZ.Max); w.Write((long)SZ.GetBitCount(Epsilon));
            w.Write(RX.Min); w.Write(RX.Max); w.Write((long)RX.GetBitCount(Epsilon));
            w.Write(RY.Min); w.Write(RY.Max); w.Write((long)RY.GetBitCount(Epsilon));
            w.Write(RZ.Min); w.Write(RZ.Max); w.Write((long)RZ.GetBitCount(Epsilon));
            w.Write(X.Min); w.Write(X.Max); w.Write((long)X.GetBitCount(Epsilon));
            w.Write(Y.Min); w.Write(Y.Max); w.Write((long)Y.GetBitCount(Epsilon));
            w.Write(Z.Min); w.Write(Z.Max); w.Write((long)Z.GetBitCount(Epsilon));

            // write default values
            AnimTrackTransform defaultValue = (AnimTrackTransform)values[0];

            w.Write(defaultValue.SX);
            w.Write(defaultValue.SY);
            w.Write(defaultValue.SZ);
            w.Write(defaultValue.RX);
            w.Write(defaultValue.RY);
            w.Write(defaultValue.RZ);
            w.Write(defaultValue.RW);
            w.Write(defaultValue.X);
            w.Write(defaultValue.Y);
            w.Write(defaultValue.Z);
            w.Write(0);

            // write compressed values
            BitWriter writer = new BitWriter();

            foreach (AnimTrackTransform transform in values)
            {
                if (hasScale)
                {
                    writer.WriteBits(SX.GetQuantanizedValue(transform.SX), SX.GetBitCount(Epsilon));
                    writer.WriteBits(SY.GetQuantanizedValue(transform.SY), SY.GetBitCount(Epsilon));
                    writer.WriteBits(SZ.GetQuantanizedValue(transform.SZ), SZ.GetBitCount(Epsilon));
                }
                if (hasRotation)
                {
                    writer.WriteBits(RX.GetQuantanizedValue(transform.RX), RX.GetBitCount(Epsilon));
                    writer.WriteBits(RY.GetQuantanizedValue(transform.RY), RY.GetBitCount(Epsilon));
                    writer.WriteBits(RZ.GetQuantanizedValue(transform.RZ), RZ.GetBitCount(Epsilon));
                }
                if (hasPosition)
                {
                    writer.WriteBits(X.GetQuantanizedValue(transform.X), X.GetBitCount(Epsilon));
                    writer.WriteBits(Y.GetQuantanizedValue(transform.Y), Y.GetBitCount(Epsilon));
                    writer.WriteBits(Z.GetQuantanizedValue(transform.Z), Z.GetBitCount(Epsilon));
                }
                if (hasRotation)
                {
                    // flip w bit

                    float calculateW = (float)Math.Sqrt(Math.Abs(1 - (
                                                                     RX.DecompressedValue(transform.RX) * RX.DecompressedValue(transform.RX) +
                                                                     RY.DecompressedValue(transform.RY) * RY.DecompressedValue(transform.RY) +
                                                                     RZ.DecompressedValue(transform.RZ) * RZ.DecompressedValue(transform.RZ))));

                    writer.WriteBits(Math.Sign((int)transform.RW) != Math.Sign((int)calculateW) ? 1 : 0, 1);
                }
            }

            w.Write(writer.GetBytes());
        }
        /// <summary>
        /// decompresses transform values from a track
        /// </summary>
        /// <param name="parser"></param>
        /// <param name="dataOffset"></param>
        /// <param name="header"></param>
        /// <returns></returns>
        private AnimTrackTransform[] DecompressTransform(SsbhParser parser, uint dataOffset, SsbhAnimCompressedHeader header)
        {
            AnimTrackTransform[] transforms = new AnimTrackTransform[header.FrameCount];

            // PreProcess
            SsbhAnimCompressedItem[] items = parser.ByteToType <SsbhAnimCompressedItem>(9);

            parser.Seek(dataOffset + header.DefaultDataOffset);

            float xsca = parser.ReadSingle();
            float ysca = parser.ReadSingle();
            float zsca = parser.ReadSingle();
            float xrot = parser.ReadSingle();
            float yrot = parser.ReadSingle();
            float zrot = parser.ReadSingle();
            float wrot = parser.ReadSingle();
            float xpos = parser.ReadSingle();
            float ypos = parser.ReadSingle();
            float zpos = parser.ReadSingle();
            float csca = parser.ReadSingle();

            parser.Seek(dataOffset + header.CompressedDataOffset);
            for (int frame = 0; frame < header.FrameCount; frame++)
            {
                AnimTrackTransform transform = new AnimTrackTransform()
                {
                    X  = xpos,
                    Y  = ypos,
                    Z  = zpos,
                    Rx = xrot,
                    Ry = yrot,
                    Rz = zrot,
                    Rw = wrot,
                    Sx = xsca,
                    Sy = ysca,
                    Sz = zsca,
                    CompensateScale = csca
                };
                for (int itemIndex = 0; itemIndex < items.Length; itemIndex++)
                {
                    // First check if this track should be parsed
                    // TODO: Don't hard code these flags.
                    if (!((itemIndex == 0 && (header.Flags & 0x3) == 0x3) || //isotropic scale
                          (itemIndex >= 0 && itemIndex <= 2 && (header.Flags & 0x3) == 0x1) ||       //normal scale
                          (itemIndex > 2 && itemIndex <= 5 && (header.Flags & 0x4) > 0) ||
                          (itemIndex > 5 && itemIndex <= 8 && (header.Flags & 0x8) > 0)))
                    {
                        continue;
                    }

                    var item = items[itemIndex];

                    // Decompress
                    int valueBitCount = (int)item.Count;
                    if (valueBitCount == 0)
                    {
                        continue;
                    }

                    int value = parser.ReadBits(valueBitCount);
                    int scale = 0;
                    for (int k = 0; k < valueBitCount; k++)
                    {
                        scale |= 0x1 << k;
                    }

                    float frameValue = Lerp(item.Start, item.End, 0, 1, value / (float)scale);
                    if (float.IsNaN(frameValue))
                    {
                        frameValue = 0;
                    }

                    // the Transform type relies a lot on flags

                    if ((header.Flags & 0x3) == 0x3)
                    {
                        //Scale Compensate
                        if (itemIndex == 0)
                        {
                            transform.CompensateScale = frameValue;
                        }
                    }
                    if ((header.Flags & 0x3) == 0x1)
                    {
                        //Scale normal
                        switch (itemIndex)
                        {
                        case 0:
                            transform.Sx = frameValue;
                            break;

                        case 1:
                            transform.Sy = frameValue;
                            break;

                        case 2:
                            transform.Sz = frameValue;
                            break;
                        }
                    }
                    //Rotation and Position
                    switch (itemIndex)
                    {
                    case 3:
                        transform.Rx = frameValue;
                        break;

                    case 4:
                        transform.Ry = frameValue;
                        break;

                    case 5:
                        transform.Rz = frameValue;
                        break;

                    case 6:
                        transform.X = frameValue;
                        break;

                    case 7:
                        transform.Y = frameValue;
                        break;

                    case 8:
                        transform.Z = frameValue;
                        break;
                    }
                }

                // Rotations have an extra bit at the end
                if ((header.Flags & 0x4) > 0)
                {
                    bool wFlip = parser.ReadBits(1) == 1;

                    // W is calculated
                    transform.Rw = (float)Math.Sqrt(Math.Abs(1 - (transform.Rx * transform.Rx + transform.Ry * transform.Ry + transform.Rz * transform.Rz)));

                    if (wFlip)
                    {
                        transform.Rw = -transform.Rw;
                    }
                }

                transforms[frame] = transform;
            }

            return(transforms);
        }
        /// <summary>
        /// Compresses <see cref="AnimTrackTransform"></see> track and writes to writer
        /// </summary>
        /// <param name="w"></param>
        /// <param name="values"></param>
        private void CompressTransformTracks(BinaryWriter w, IList <object> values)
        {
            Quantanizer sx = new Quantanizer();
            Quantanizer sy = new Quantanizer();
            Quantanizer sz = new Quantanizer();
            Quantanizer rx = new Quantanizer();
            Quantanizer ry = new Quantanizer();
            Quantanizer rz = new Quantanizer();
            Quantanizer x  = new Quantanizer();
            Quantanizer y  = new Quantanizer();
            Quantanizer z  = new Quantanizer();

            // pre-process
            foreach (AnimTrackTransform transform in values)
            {
                sx.Add(transform.Sx);
                sy.Add(transform.Sy);
                sz.Add(transform.Sz);
                rx.Add(transform.Rx);
                ry.Add(transform.Ry);
                rz.Add(transform.Rz);
                x.Add(transform.X);
                y.Add(transform.Y);
                z.Add(transform.Z);
            }

            short  flags        = 0;
            ushort bitsPerEntry = 0;

            bool hasScale    = (!sx.Constant || !sy.Constant || !sz.Constant);
            bool hasRotation = (!rx.Constant || !ry.Constant || !rz.Constant);
            bool hasPosition = (!x.Constant || !y.Constant || !z.Constant);

            if (sx.GetBitCount(epsilon) == -1 || sy.GetBitCount(epsilon) == -1 || (sz.GetBitCount(epsilon) == -1 || rx.GetBitCount(epsilon) == -1) || (ry.GetBitCount(epsilon) == -1 || rz.GetBitCount(epsilon) == -1 || (x.GetBitCount(epsilon) == -1 || y.GetBitCount(epsilon) == -1)) || z.GetBitCount(epsilon) == -1)
            {
                throw new Exception("Compression Level is too small to compress!");
            }

            if (!hasScale)
            {
                flags |= 0x02;
            }
            else
            {
                bitsPerEntry += (ushort)((sx.Constant ? 0 : sx.GetBitCount(epsilon)) + (sy.Constant ? 0 : sy.GetBitCount(epsilon)) + (sz.Constant ? 0 : sz.GetBitCount(epsilon)));
                flags        |= 0x01;
            }
            if (hasRotation)
            {
                bitsPerEntry += (ushort)((rx.Constant ? 0 : rx.GetBitCount(epsilon)) + (ry.Constant ? 0 : ry.GetBitCount(epsilon)) + (rz.Constant ? 0 : rz.GetBitCount(epsilon)) + 1); // the 1 is for extra w rotation bit
                flags        |= 0x04;
            }
            if (hasPosition)
            {
                bitsPerEntry += (ushort)((x.Constant ? 0 : x.GetBitCount(epsilon)) + (y.Constant ? 0 : y.GetBitCount(epsilon)) + (z.Constant ? 0 : z.GetBitCount(epsilon)));
                flags        |= 0x08;
            }

            // Compressed Header
            w.Write((short)0x04);
            w.Write(flags);
            w.Write((short)160);
            w.Write(bitsPerEntry);
            w.Write(204);
            w.Write(values.Count);
            w.Write(sx.Min);
            w.Write(sx.Max);
            w.Write(hasScale ? sx.GetBitCount(epsilon) : 16L);
            w.Write(sy.Min);
            w.Write(sy.Max);
            w.Write(hasScale ? sy.GetBitCount(epsilon) : 16L);
            w.Write(sz.Min);
            w.Write(sz.Max);
            w.Write(hasScale ? sz.GetBitCount(epsilon) : 16L);
            w.Write(rx.Min);
            w.Write(rx.Max);
            w.Write(hasRotation ? rx.GetBitCount(epsilon) : 16L);
            w.Write(ry.Min);
            w.Write(ry.Max);
            w.Write(hasRotation ? ry.GetBitCount(epsilon) : 16L);
            w.Write(rz.Min);
            w.Write(rz.Max);
            w.Write(hasRotation ? rz.GetBitCount(epsilon) : 16L);
            w.Write(x.Min);
            w.Write(x.Max);
            w.Write(hasPosition ? x.GetBitCount(epsilon) : 16L);
            w.Write(y.Min);
            w.Write(y.Max);
            w.Write(hasPosition ? y.GetBitCount(epsilon) : 16L);
            w.Write(z.Min);
            w.Write(z.Max);
            w.Write(hasPosition ? z.GetBitCount(epsilon) : 16L);
            AnimTrackTransform defaultValue = (AnimTrackTransform)values[0];

            w.Write(defaultValue.Sx);
            w.Write(defaultValue.Sy);
            w.Write(defaultValue.Sz);
            w.Write(defaultValue.Rx);
            w.Write(defaultValue.Ry);
            w.Write(defaultValue.Rz);
            w.Write(defaultValue.Rw);
            w.Write(defaultValue.X);
            w.Write(defaultValue.Y);
            w.Write(defaultValue.Z);
            w.Write(0);

            // write compressed values
            BitWriter writer = new BitWriter();

            foreach (AnimTrackTransform transform in values)
            {
                if (hasScale)
                {
                    writer.WriteBits(sx.GetQuantanizedValue(transform.Sx), sx.GetBitCount(epsilon));
                    writer.WriteBits(sy.GetQuantanizedValue(transform.Sy), sy.GetBitCount(epsilon));
                    writer.WriteBits(sz.GetQuantanizedValue(transform.Sz), sz.GetBitCount(epsilon));
                }
                if (hasRotation)
                {
                    writer.WriteBits(rx.GetQuantanizedValue(transform.Rx), rx.GetBitCount(epsilon));
                    writer.WriteBits(ry.GetQuantanizedValue(transform.Ry), ry.GetBitCount(epsilon));
                    writer.WriteBits(rz.GetQuantanizedValue(transform.Rz), rz.GetBitCount(epsilon));
                }
                if (hasPosition)
                {
                    writer.WriteBits(x.GetQuantanizedValue(transform.X), x.GetBitCount(epsilon));
                    writer.WriteBits(y.GetQuantanizedValue(transform.Y), y.GetBitCount(epsilon));
                    writer.WriteBits(z.GetQuantanizedValue(transform.Z), z.GetBitCount(epsilon));
                }
                if (hasRotation)
                {
                    // flip w bit

                    float calculateW = (float)Math.Sqrt(Math.Abs(1 - (
                                                                     rx.DecompressedValue(transform.Rx) * rx.DecompressedValue(transform.Rx) +
                                                                     ry.DecompressedValue(transform.Ry) * ry.DecompressedValue(transform.Ry) +
                                                                     rz.DecompressedValue(transform.Rz) * rz.DecompressedValue(transform.Rz))));

                    writer.WriteBits(Math.Sign(transform.Rw) != Math.Sign(calculateW) ? 1 : 0, 1);
                }
            }

            w.Write(writer.GetBytes());
        }
Exemple #6
0
        /// <summary>
        /// decompresses transform values from a track
        /// </summary>
        /// <param name="parser"></param>
        /// <param name="dataOffset"></param>
        /// <param name="header"></param>
        /// <returns></returns>
        private AnimTrackTransform[] DecompressTransform(SSBHParser parser, uint dataOffset, SSBHAnimCompressedHeader header)
        {
            AnimTrackTransform[] transforms = new AnimTrackTransform[header.FrameCount];

            // PreProcess
            SSBHAnimCompressedItem[] items = parser.ByteToType <SSBHAnimCompressedItem>(9);

            parser.Seek(dataOffset + header.DefaultDataOffset);

            float XSCA = parser.ReadSingle();
            float YSCA = parser.ReadSingle();
            float ZSCA = parser.ReadSingle();
            float XROT = parser.ReadSingle();
            float YROT = parser.ReadSingle();
            float ZROT = parser.ReadSingle();
            float WROT = parser.ReadSingle();
            float XPOS = parser.ReadSingle();
            float YPOS = parser.ReadSingle();
            float ZPOS = parser.ReadSingle();
            float CSCA = parser.ReadSingle();

            parser.Seek(dataOffset + header.CompressedDataOffset);
            for (int frame = 0; frame < header.FrameCount; frame++)
            {
                AnimTrackTransform transform = new AnimTrackTransform()
                {
                    X  = XPOS,
                    Y  = YPOS,
                    Z  = ZPOS,
                    RX = XROT,
                    RY = YROT,
                    RZ = ZROT,
                    RW = WROT,
                    SX = XSCA,
                    SY = YSCA,
                    SZ = ZSCA,
                    CompensateScale = CSCA
                };
                for (int itemIndex = 0; itemIndex < items.Length; itemIndex++)
                {
                    // First check if this track should be parsed
                    // TODO: Don't hard code these flags.
                    if (!((itemIndex == 0 && (header.Flags & 0x3) == 0x3) || //isotropic scale
                          (itemIndex >= 0 && itemIndex <= 2 && (header.Flags & 0x3) == 0x1) ||       //normal scale
                          (itemIndex > 2 && itemIndex <= 5 && (header.Flags & 0x4) > 0) ||
                          (itemIndex > 5 && itemIndex <= 8 && (header.Flags & 0x8) > 0)))
                    {
                        continue;
                    }

                    var item = items[itemIndex];

                    // Decompress
                    int valueBitCount = (int)item.Count;
                    if (valueBitCount == 0)
                    {
                        continue;
                    }

                    int value = parser.ReadBits(valueBitCount);
                    int scale = 0;
                    for (int k = 0; k < valueBitCount; k++)
                    {
                        scale |= 0x1 << k;
                    }

                    float frameValue = Lerp(item.Start, item.End, 0, 1, value / (float)scale);
                    if (float.IsNaN(frameValue))
                    {
                        frameValue = 0;
                    }

                    // the Transform type relies a lot on flags

                    if ((header.Flags & 0x3) == 0x3)
                    {
                        //Scale Compensate
                        if (itemIndex == 0)
                        {
                            transform.CompensateScale = frameValue;
                        }
                    }
                    if ((header.Flags & 0x3) == 0x1)
                    {
                        //Scale normal
                        switch (itemIndex)
                        {
                        case 0:
                            transform.SX = frameValue;
                            break;

                        case 1:
                            transform.SY = frameValue;
                            break;

                        case 2:
                            transform.SZ = frameValue;
                            break;
                        }
                    }
                    //Rotation and Position
                    switch (itemIndex)
                    {
                    case 3:
                        transform.RX = frameValue;
                        break;

                    case 4:
                        transform.RY = frameValue;
                        break;

                    case 5:
                        transform.RZ = frameValue;
                        break;

                    case 6:
                        transform.X = frameValue;
                        break;

                    case 7:
                        transform.Y = frameValue;
                        break;

                    case 8:
                        transform.Z = frameValue;
                        break;
                    }
                }

                // Rotations have an extra bit at the end
                if ((header.Flags & 0x4) > 0)
                {
                    bool wFlip = parser.ReadBits(1) == 1;

                    // W is calculated
                    transform.RW = (float)Math.Sqrt(Math.Abs(1 - (transform.RX * transform.RX + transform.RY * transform.RY + transform.RZ * transform.RZ)));

                    if (wFlip)
                    {
                        transform.RW = -transform.RW;
                    }
                }

                transforms[frame] = transform;
            }

            return(transforms);
        }
Exemple #7
0
        /// <summary>
        /// Compresses <see cref="AnimTrackTransform"></see> track and writes to writer
        /// </summary>
        /// <param name="w"></param>
        /// <param name="values"></param>
        private void CompressTransformTracks(BinaryWriter w, IList <object> values)
        {
            Quantanizer sx = new Quantanizer();
            Quantanizer sy = new Quantanizer();
            Quantanizer sz = new Quantanizer();
            Quantanizer rx = new Quantanizer();
            Quantanizer ry = new Quantanizer();
            Quantanizer rz = new Quantanizer();
            Quantanizer x  = new Quantanizer();
            Quantanizer y  = new Quantanizer();
            Quantanizer z  = new Quantanizer();

            // pre-process
            foreach (AnimTrackTransform transform in values)
            {
                sx.Add(transform.Sx);
                sy.Add(transform.Sy);
                sz.Add(transform.Sz);
                rx.Add(transform.Rx);
                ry.Add(transform.Ry);
                rz.Add(transform.Rz);
                x.Add(transform.X);
                y.Add(transform.Y);
                z.Add(transform.Z);
            }

            short  flags        = 0;
            ushort bitsPerEntry = 0;

            bool hasScale    = (!sx.Constant || !sy.Constant || !sz.Constant);
            bool hasRotation = (!rx.Constant || !ry.Constant || !rz.Constant);
            bool hasPosition = (!x.Constant || !y.Constant || !z.Constant);


            if (!hasScale)
            {
                flags |= 0x02;
            }
            else
            {
                bitsPerEntry += (ushort)((sx.Constant ? 0 : sx.GetBitCount(epsilon)) + (sy.Constant ? 0 : sy.GetBitCount(epsilon)) + (sz.Constant ? 0 : sz.GetBitCount(epsilon)));
                flags        |= 0x01;
            }
            if (hasRotation)
            {
                bitsPerEntry += (ushort)((rx.Constant ? 0 : rx.GetBitCount(epsilon)) + (ry.Constant ? 0 : ry.GetBitCount(epsilon)) + (rz.Constant ? 0 : rz.GetBitCount(epsilon)) + 1); // the 1 is for extra w rotation bit
                flags        |= 0x04;
            }
            if (hasPosition)
            {
                bitsPerEntry += (ushort)((x.Constant ? 0 : x.GetBitCount(epsilon)) + (y.Constant ? 0 : y.GetBitCount(epsilon)) + (z.Constant ? 0 : z.GetBitCount(epsilon)));
                flags        |= 0x08;
            }

            // Compressed Header
            w.Write((short)0x04);
            w.Write(flags);
            w.Write((short)(0x10 + 0x10 * 9));             // default values offset
            w.Write(bitsPerEntry);
            w.Write(0x10 + 0x10 * 9 + sizeof(float) * 11); // compressed data start
            w.Write(values.Count);                         // frame count

            // write chunks
            w.Write(sx.Min); w.Write(sx.Max); w.Write((long)sx.GetBitCount(epsilon));
            w.Write(sy.Min); w.Write(sy.Max); w.Write((long)sy.GetBitCount(epsilon));
            w.Write(sz.Min); w.Write(sz.Max); w.Write((long)sz.GetBitCount(epsilon));
            w.Write(rx.Min); w.Write(rx.Max); w.Write((long)rx.GetBitCount(epsilon));
            w.Write(ry.Min); w.Write(ry.Max); w.Write((long)ry.GetBitCount(epsilon));
            w.Write(rz.Min); w.Write(rz.Max); w.Write((long)rz.GetBitCount(epsilon));
            w.Write(x.Min); w.Write(x.Max); w.Write((long)x.GetBitCount(epsilon));
            w.Write(y.Min); w.Write(y.Max); w.Write((long)y.GetBitCount(epsilon));
            w.Write(z.Min); w.Write(z.Max); w.Write((long)z.GetBitCount(epsilon));

            // write default values
            AnimTrackTransform defaultValue = (AnimTrackTransform)values[0];

            w.Write(defaultValue.Sx);
            w.Write(defaultValue.Sy);
            w.Write(defaultValue.Sz);
            w.Write(defaultValue.Rx);
            w.Write(defaultValue.Ry);
            w.Write(defaultValue.Rz);
            w.Write(defaultValue.Rw);
            w.Write(defaultValue.X);
            w.Write(defaultValue.Y);
            w.Write(defaultValue.Z);
            w.Write(0);

            // write compressed values
            BitWriter writer = new BitWriter();

            foreach (AnimTrackTransform transform in values)
            {
                if (hasScale)
                {
                    writer.WriteBits(sx.GetQuantanizedValue(transform.Sx), sx.GetBitCount(epsilon));
                    writer.WriteBits(sy.GetQuantanizedValue(transform.Sy), sy.GetBitCount(epsilon));
                    writer.WriteBits(sz.GetQuantanizedValue(transform.Sz), sz.GetBitCount(epsilon));
                }
                if (hasRotation)
                {
                    writer.WriteBits(rx.GetQuantanizedValue(transform.Rx), rx.GetBitCount(epsilon));
                    writer.WriteBits(ry.GetQuantanizedValue(transform.Ry), ry.GetBitCount(epsilon));
                    writer.WriteBits(rz.GetQuantanizedValue(transform.Rz), rz.GetBitCount(epsilon));
                }
                if (hasPosition)
                {
                    writer.WriteBits(x.GetQuantanizedValue(transform.X), x.GetBitCount(epsilon));
                    writer.WriteBits(y.GetQuantanizedValue(transform.Y), y.GetBitCount(epsilon));
                    writer.WriteBits(z.GetQuantanizedValue(transform.Z), z.GetBitCount(epsilon));
                }
                if (hasRotation)
                {
                    // flip w bit

                    float calculateW = (float)Math.Sqrt(Math.Abs(1 - (
                                                                     rx.DecompressedValue(transform.Rx) * rx.DecompressedValue(transform.Rx) +
                                                                     ry.DecompressedValue(transform.Ry) * ry.DecompressedValue(transform.Ry) +
                                                                     rz.DecompressedValue(transform.Rz) * rz.DecompressedValue(transform.Rz))));

                    writer.WriteBits(Math.Sign((int)transform.Rw) != Math.Sign((int)calculateW) ? 1 : 0, 1);
                }
            }

            w.Write(writer.GetBytes());
        }
        public object[] ReadTrack(AnimTrack Track)
        {
            Console.WriteLine(Track.Name + " " + Track.Flags.ToString() + " " + Track.FrameCount + " " + Track.DataOffset.ToString("X"));
            List <object> output = new List <object>();

            using (SSBHParser parser = new SSBHParser(new MemoryStream(AnimFile.Buffer)))
            {
                parser.Seek(Track.DataOffset);

                if (CheckFlag(Track.Flags, 0x00FF, ANIM_TRACKFLAGS.Boolean))
                {
                    if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.Animated))
                    {
                        int Unk_4      = parser.ReadInt16();
                        int TrackFlag  = parser.ReadInt16();
                        int Unk1       = parser.ReadInt16();
                        int Unk2       = parser.ReadInt16();
                        int DataStart  = parser.ReadInt32();
                        int FrameCount = parser.ReadInt32();

                        parser.Seek((int)Track.DataOffset + DataStart);
                        for (int i = 0; i < FrameCount; i++)
                        {
                            output.Add(new AnimTrackBool(parser.ReadBits(1) == 1));
                        }
                    }
                    else
                    if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.Constant))
                    {
                        output.Add(new AnimTrackBool(parser.ReadBits(1) == 1));
                    }
                }
                if (CheckFlag(Track.Flags, 0x00FF, ANIM_TRACKFLAGS.Vector4))
                {
                    if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.Animated))
                    {
                        int Unk_4      = parser.ReadInt16();
                        int TrackFlag  = parser.ReadInt16();
                        int Unk1       = parser.ReadInt16();
                        int Unk2       = parser.ReadInt16();
                        int DataStart  = parser.ReadInt32();
                        int FrameCount = parser.ReadInt32();

                        int[]   ByteCounts = new int[9];
                        int[]   BitCounts  = new int[9];
                        float[] Start      = new float[9];
                        float[] End        = new float[9];
                        for (int i = 0; i < 4; i++)
                        {
                            Start[i] = parser.ReadSingle();
                            End[i]   = parser.ReadSingle();
                            long Count = parser.ReadInt64();
                            long bytes = (Count >> 3);
                            int  bits  = ((int)Count & 0x7);

                            if ((i >= 0 && i <= 0 && (TrackFlag & 0x3) == 0x3) || //isotrophic scale
                                (i >= 0 && i <= 2 && (TrackFlag & 0x3) == 0x1) || //normal scale
                                (i > 2 && i <= 5 && (TrackFlag & 0x4) > 0) ||
                                (i > 5 && i <= 8 && (TrackFlag & 0x8) > 0))
                            {
                                //reads
                                {
                                    BitCounts[i]  = bits;
                                    ByteCounts[i] = (int)bytes;
                                }
                            }
                        }

                        float X = parser.ReadSingle();
                        float Y = parser.ReadSingle();
                        float Z = parser.ReadSingle();
                        float W = parser.ReadSingle();

                        parser.Seek((int)Track.DataOffset + DataStart);
                        for (int i = 0; i < FrameCount; i++)
                        {
                            AnimTrackCustomVector4 Vector = new AnimTrackCustomVector4();
                            for (int j = 0; j < 4; j++)
                            {
                                int ValueBitCount = ByteCounts[j] * 8 + BitCounts[j];
                                int Value         = parser.ReadBits(ValueBitCount);
                                int scale         = 0;
                                for (int k = 0; k < ValueBitCount; k++)
                                {
                                    scale |= 0x1 << k;
                                }

                                float FrameValue = Lerp(Start[j], End[j], 0, 1, Value / (float)scale);
                                if (float.IsNaN(FrameValue))
                                {
                                    FrameValue = 0;
                                }

                                switch (j)
                                {
                                case 0: if (ValueBitCount > 0)
                                    {
                                        Vector.X = FrameValue;
                                    }
                                    else
                                    {
                                        Vector.X = X;
                                    } break;

                                case 1: if (ValueBitCount > 0)
                                    {
                                        Vector.Y = FrameValue;
                                    }
                                    else
                                    {
                                        Vector.Y = Y;
                                    } break;

                                case 2: if (ValueBitCount > 0)
                                    {
                                        Vector.Z = FrameValue;
                                    }
                                    else
                                    {
                                        Vector.Z = Z;
                                    } break;

                                case 3: if (ValueBitCount > 0)
                                    {
                                        Vector.W = FrameValue;
                                    }
                                    else
                                    {
                                        Vector.W = W;
                                    } break;
                                }
                            }

                            output.Add(Vector);
                        }
                    }
                    else
                    if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.Constant))
                    {
                        output.Add(new AnimTrackCustomVector4()
                        {
                            X = parser.ReadSingle(),
                            Y = parser.ReadSingle(),
                            Z = parser.ReadSingle(),
                            W = parser.ReadSingle()
                        });
                    }
                }
                if (CheckFlag(Track.Flags, 0x00FF, ANIM_TRACKFLAGS.Transform))
                {
                    if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.Animated))
                    {
                        int Unk_4      = parser.ReadInt16();
                        int TrackFlag  = parser.ReadInt16();
                        int Unk1       = parser.ReadInt16();
                        int Unk2       = parser.ReadInt16();
                        int DataStart  = parser.ReadInt32();
                        int FrameCount = parser.ReadInt32();

                        int[]   ByteCounts = new int[9];
                        int[]   BitCounts  = new int[9];
                        float[] Start      = new float[9];
                        float[] End        = new float[9];
                        for (int i = 0; i < 9; i++)
                        {
                            Start[i] = parser.ReadSingle();
                            End[i]   = parser.ReadSingle();
                            long Count = parser.ReadInt64();
                            long bytes = (Count >> 3);
                            int  bits  = ((int)Count & 0x7);

                            if ((i >= 0 && i <= 0 && (TrackFlag & 0x3) == 0x3) || //isotrophic scale
                                (i >= 0 && i <= 2 && (TrackFlag & 0x3) == 0x1) || //normal scale
                                (i > 2 && i <= 5 && (TrackFlag & 0x4) > 0) ||
                                (i > 5 && i <= 8 && (TrackFlag & 0x8) > 0))
                            {
                                //reads
                                {
                                    BitCounts[i]  = bits;
                                    ByteCounts[i] = (int)bytes;
                                }
                            }
                        }

                        float XSCA = parser.ReadSingle();
                        float YSCA = parser.ReadSingle();
                        float ZSCA = parser.ReadSingle();
                        float XROT = parser.ReadSingle();
                        float YROT = parser.ReadSingle();
                        float ZROT = parser.ReadSingle();
                        float WROT = parser.ReadSingle();
                        float XPOS = parser.ReadSingle();
                        float YPOS = parser.ReadSingle();
                        float ZPOS = parser.ReadSingle();

                        parser.ReadInt32(); // ????

                        parser.Seek((int)Track.DataOffset + DataStart);
                        for (int i = 0; i < FrameCount; i++)
                        {
                            AnimTrackTransform Transform = new AnimTrackTransform();
                            for (int j = 0; j < 9; j++)
                            {
                                int ValueBitCount = ByteCounts[j] * 8 + BitCounts[j];
                                int Value         = parser.ReadBits(ValueBitCount);
                                int scale         = 0;
                                for (int k = 0; k < ValueBitCount; k++)
                                {
                                    scale |= 0x1 << k;
                                }

                                float FrameValue = Lerp(Start[j], End[j], 0, 1, Value / (float)scale);
                                if (float.IsNaN(FrameValue))
                                {
                                    FrameValue = 0;
                                }

                                if ((TrackFlag & 0x3) == 0x3)
                                {
                                    //Scale Isotropic
                                    if (j == 0)
                                    {
                                        Transform.SX = FrameValue;
                                        Transform.SY = FrameValue;
                                        Transform.SZ = FrameValue;
                                    }
                                }
                                else if ((TrackFlag & 0x3) == 0x1)
                                {
                                    //Scale normal
                                    switch (j)
                                    {
                                    case 0:
                                        if (ValueBitCount > 0)
                                        {
                                            Transform.SX = FrameValue;
                                        }
                                        else
                                        {
                                            Transform.SX = XSCA;
                                        }
                                        break;

                                    case 1:
                                        if (ValueBitCount > 0)
                                        {
                                            Transform.SY = FrameValue;
                                        }
                                        else
                                        {
                                            Transform.SY = YSCA;
                                        }
                                        break;

                                    case 2:
                                        if (ValueBitCount > 0)
                                        {
                                            Transform.SZ = FrameValue;
                                        }
                                        else
                                        {
                                            Transform.SZ = ZSCA;
                                        }
                                        break;
                                    }
                                }
                                else
                                {
                                    Transform.SX = XSCA;
                                    Transform.SY = YSCA;
                                    Transform.SZ = ZSCA;
                                }

                                //Rotation
                                if ((TrackFlag & 0x4) > 0)
                                {
                                    switch (j)
                                    {
                                    case 3:
                                        if (ValueBitCount > 0)
                                        {
                                            Transform.RX = FrameValue;
                                        }
                                        else
                                        {
                                            Transform.RX = XROT;
                                        }
                                        break;

                                    case 4:
                                        if (ValueBitCount > 0)
                                        {
                                            Transform.RY = FrameValue;
                                        }
                                        else
                                        {
                                            Transform.RY = YROT;
                                        }
                                        break;

                                    case 5:
                                        if (ValueBitCount > 0)
                                        {
                                            Transform.RZ = FrameValue;
                                        }
                                        else
                                        {
                                            Transform.RZ = ZROT;
                                        }
                                        break;
                                    }
                                }
                                else
                                {
                                    Transform.RX = XROT;
                                    Transform.RY = YROT;
                                    Transform.RZ = ZROT;
                                    Transform.RW = WROT;
                                }

                                // Position
                                if ((TrackFlag & 0x8) > 0)
                                {
                                    switch (j)
                                    {
                                    case 6:
                                        if (ValueBitCount > 0)
                                        {
                                            Transform.X = FrameValue;
                                        }
                                        else
                                        {
                                            Transform.X = XPOS;
                                        }
                                        break;

                                    case 7:
                                        if (ValueBitCount > 0)
                                        {
                                            Transform.Y = FrameValue;
                                        }
                                        else
                                        {
                                            Transform.Y = YPOS;
                                        }
                                        break;

                                    case 8:
                                        if (ValueBitCount > 0)
                                        {
                                            Transform.Z = FrameValue;
                                        }
                                        else
                                        {
                                            Transform.Z = ZPOS;
                                        }
                                        break;
                                    }
                                }
                                else
                                {
                                    Transform.X = XPOS;
                                    Transform.Y = YPOS;
                                    Transform.Z = ZPOS;
                                }
                            }
                            if ((TrackFlag & 0x4) > 0)
                            {
                                // Rotation w
                                bool Wflip = parser.ReadBits(1) == 1;// (TrackFlag & 0x1) == 0 ? parser.ReadBits(1) == 1 : true;

                                Transform.RW = (float)Math.Sqrt(Math.Abs(1 - (Transform.RX * Transform.RX + Transform.RY * Transform.RY + Transform.RZ * Transform.RZ)));

                                if (Wflip)
                                {
                                    Transform.RW = -Transform.RW;
                                }
                            }

                            output.Add(Transform);
                        }
                    }
                    else if (CheckFlag(Track.Flags, 0xFF00, ANIM_TRACKFLAGS.ConstTransform))
                    {
                        output.Add(new AnimTrackTransform()
                        {
                            SX = parser.ReadSingle(),
                            SY = parser.ReadSingle(),
                            SZ = parser.ReadSingle(),
                            RX = parser.ReadSingle(),
                            RY = parser.ReadSingle(),
                            RZ = parser.ReadSingle(),
                            RW = parser.ReadSingle(),
                            X  = parser.ReadSingle(),
                            Y  = parser.ReadSingle(),
                            Z  = parser.ReadSingle(),
                        });

                        parser.ReadInt32(); // ????
                    }
                }
            }

            return(output.ToArray());
        }