コード例 #1
0
        private static ushort[] ReadFrames_(
            ushort tTrack,
            ushort limit,
            NormalAnimation animation)
        {
            ushort[] frames;

            // Constant
            if (tTrack < limit)
            {
                frames    = new ushort[1];
                frames[0] = animation.Angles[tTrack];
            }
            else
            {
                // Keyframes
                frames = new ushort[animation.FrameCount];
                for (var i2 = 0; i2 < animation.FrameCount; ++i2)
                {
                    try {
                        frames[i2] = animation.Angles[tTrack + i2];
                    } catch {
                        return(null);
                    }
                }
            }

            return(frames);
        }
コード例 #2
0
        /// <summary>
        ///   Parses a set of animations according to the spec at:
        ///   https://wiki.cloudmodding.com/oot/Animation_Format#Normal_Animations
        /// </summary>
        // TODO: Some jank still slips through, is there a proper list of these
        // addresses somewhere in the file?
        public IList <IAnimation>?GetCommonAnimations(
            IBank bank,
            int limbCount,
            ListBox animationList)
        {
            animationList.Items.Clear();

            uint trackCount = (uint)(limbCount * 3);
            var  animations = new List <IAnimation>();

            // Guesstimating the index by looking for an spot where the header's angle
            // address and track address have the same bank as the param at the top.
            for (var i = 4; i < bank.Count - 12; i += 4)
            {
                var attemptOffset = (uint)(i - 4);

                // Verifies the frame count is positive.
                var frameCount = IoUtil.ReadUInt16(bank, attemptOffset);
                if (frameCount == 0)
                {
                    continue;
                }

                var rotationValuesAddress = IoUtil.ReadUInt32(
                    bank,
                    attemptOffset + 4);
                IoUtil.SplitAddress(rotationValuesAddress,
                                    out var rotationValuesBank,
                                    out var rotationValuesOffset);

                // Verifies the rotation values address has a valid bank.
                if (!RamBanks.IsValidBank(rotationValuesBank))
                {
                    continue;
                }

                // Verifies the rotation indices address has a valid bank.
                var rotationIndicesAddress = IoUtil.ReadUInt32(
                    bank,
                    attemptOffset + 8);
                IoUtil.SplitAddress(rotationIndicesAddress,
                                    out var rotationIndicesBank,
                                    out var rotationIndicesOffset);
                if (!RamBanks.IsValidBank(rotationIndicesBank))
                {
                    continue;
                }

                // Obtains the specified banks.
                var rotationValuesBuffer =
                    Asserts.Assert(RamBanks.GetBankByIndex(rotationValuesBank));
                var rotationIndicesBuffer =
                    Asserts.Assert(RamBanks.GetBankByIndex(rotationIndicesBank));

                // Offsets should be within bounds of the bank.
                var validRotationValuesOffset =
                    rotationValuesOffset < rotationValuesBuffer.Count;
                var validRotationIndicesOffset =
                    rotationIndicesOffset < rotationIndicesBuffer.Count;

                if (!validRotationValuesOffset || !validRotationIndicesOffset)
                {
                    continue;
                }

                // Angle count should be greater than 0.
                var angleCount =
                    (uint)((rotationIndicesOffset - rotationValuesOffset) / 2L);
                var validAngleCount = rotationIndicesOffset > rotationValuesOffset &&
                                      angleCount > 0L;
                if (!validAngleCount)
                {
                    continue;
                }

                // Should have zeroes present in two spots of the animation header.
                var hasZeroes =
                    IoUtil.ReadUInt16(bank, attemptOffset + 2) == 0 &&
                    IoUtil.ReadUInt16(bank, attemptOffset + 14) == 0;
                if (!hasZeroes)
                {
                    continue;
                }

                // All values of "tTrack" should be within the bounds of .Angles.
                var validTTracks = true;
                var limit        = IoUtil.ReadUInt16(bank, attemptOffset + 12);
                for (var i1 = 0; i1 < 3 + trackCount; i1++)
                {
                    var tTrack = IoUtil.ReadUInt16(
                        rotationIndicesBuffer,
                        (uint)(rotationIndicesOffset + 2 * i1));
                    if (tTrack < limit)
                    {
                        if (tTrack >= angleCount)
                        {
                            validTTracks = false;
                            goto badTTracks;
                        }
                    }
                    else if ((uint)(tTrack + frameCount) > angleCount)
                    {
                        validTTracks = false;
                        goto badTTracks;
                    }
                }

badTTracks:
                if (!validTTracks)
                {
                    continue;
                }

                var animation = new NormalAnimation {
                    FrameCount  = frameCount,
                    TrackOffset = rotationIndicesOffset,
                    AngleCount  = angleCount
                };

                animation.Angles = new ushort[animation.AngleCount];
                for (var i1 = 0; i1 < animation.AngleCount; ++i1)
                {
                    animation.Angles[i1] =
                        IoUtil.ReadUInt16(rotationValuesBuffer,
                                          rotationValuesOffset);
                    rotationValuesOffset = (uint)(rotationValuesOffset + 2L);
                }

                // Translation is at the start.
                var xList =
                    ReadFrames_(
                        IoUtil.ReadUInt16(rotationIndicesBuffer,
                                          animation.TrackOffset + 0),
                        limit,
                        animation);
                var yList =
                    ReadFrames_(
                        IoUtil.ReadUInt16(rotationIndicesBuffer,
                                          animation.TrackOffset + 2),
                        limit,
                        animation);
                var zList =
                    ReadFrames_(
                        IoUtil.ReadUInt16(rotationIndicesBuffer,
                                          animation.TrackOffset + 4),
                        limit,
                        animation);

                animation.Positions = new Vec3s[animation.FrameCount];
                for (var pi = 0; pi < animation.FrameCount; ++pi)
                {
                    animation.Positions[pi] = new Vec3s {
                        X = (short)xList[Math.Min(pi, xList.Length - 1)],
                        Y = (short)yList[Math.Min(pi, yList.Length - 1)],
                        Z = (short)zList[Math.Min(pi, zList.Length - 1)],
                    };
                }

                animation.Tracks = new NormalAnimationTrack[trackCount];

                var tTrackOffset = (int)(animation.TrackOffset + 6L);
                for (var i1 = 0; i1 < trackCount; ++i1)
                {
                    var track = animation.Tracks[i1] = new NormalAnimationTrack();

                    var tTrack =
                        IoUtil.ReadUInt16(rotationIndicesBuffer,
                                          (uint)tTrackOffset);
                    if (tTrack < limit)
                    {
                        // Constant (single value)
                        track.Type      = 0;
                        track.Frames    = new ushort[1];
                        track.Frames[0] = animation.Angles[tTrack];
                    }
                    else
                    {
                        // Keyframes
                        track.Type   = 1;
                        track.Frames = new ushort[animation.FrameCount];
                        for (var i2 = 0; i2 < animation.FrameCount; ++i2)
                        {
                            try {
                                track.Frames[i2] = animation.Angles[tTrack + i2];
                            } catch {
                                return(null);
                            }
                        }
                    }

                    tTrackOffset += 2;
                }

                animations.Add(animation);

                animationList.Items.Add("0x" + Conversion.Hex(i));
            }

            return(animations.Count > 0 ? animations : null);
        }