Example #1
0
 public Keyframe Copy()
 {
     Keyframe key = new Keyframe();
     key.Position = Position;
     key.Rotation = Rotation;
     key.Scale = Scale;
     key.Time = Time;
     return key;
 }
Example #2
0
        public static SEQ FromStream(EndianBinaryReader reader, ContentBase activeSHP)
        {
            SHP targetSHP = (SHP)activeSHP;
            /*=====================================================================
                TODO: add lenght
            =====================================================================*/
            // base ptr needed because the SEQ could be embedded.
            uint ptrBase = (uint)reader.BaseStream.Position;

            byte numFrames = reader.ReadByte(); // total number of frames?

            var unknownPaddingValue1 = reader.ReadByte(); // padding
            //Trace.Assert(unknownPaddingValue1 == 0);

            byte numBones = reader.ReadByte();

            var unknownPaddingValue2 = reader.ReadByte(); // padding
            //Trace.Assert(unknownPaddingValue2 == 0);

            uint size = reader.ReadUInt32();

            var unknownPaddingValue3 = reader.ReadUInt32(); // unknown
            //Trace.Assert(unknownPaddingValue3 == 0);

            uint ptrFrames = (uint)reader.ReadUInt32() + 8; // pointer to the frames data section
            uint ptrSequence = ptrFrames + (uint)numFrames; // pointer to the sequence section

            // number of animations
            //                  length of all the headers   /   length of one animation header
            int numAnimations = (((int)ptrSequence - numFrames) - 16) / (numBones * 4 + 10);

            List<AnimationHeader> headers = new List<AnimationHeader>();

            for (int i = 0; i < numAnimations; i++)
            {
                AnimationHeader animHeader = new AnimationHeader
                {
                    length = reader.ReadUInt16(),
                    idOtherAnimation = reader.ReadSByte(), // the intial source animation. Used to get initial frames.
                    mode = reader.ReadByte(),
                    ptrLooping = reader.ReadUInt16(), // seems to point to a data block that controls looping
                    ptrTranslation = reader.ReadUInt16(), // points to a translation vector for the animated mesh (root motion?)
                    ptrMove = reader.ReadUInt16(), // points to a data block that controls movement (root motion?)

                    ptrBones = new ushort[numBones],
                };

                // assign bone ptrs
                for (int p = 0; p < numBones; p++)
                {
                    animHeader.ptrBones[p] = reader.ReadUInt16();
                }

                for (int j = 0; j < numBones; j++)
                {
                    var unknownBoneValues = reader.ReadUInt16(); //TODO: this is 0 for all SEQs?
                    //Trace.Assert(unknownBoneValues == 0); // will show if value is ever NOT zero
                }

                headers.Add(animHeader);
            }

            // TODO: Never used!?
            sbyte[] frames = new sbyte[numFrames];
            for (int i = 0; i < numFrames; i++)
            {
                frames[i] = reader.ReadSByte();
            }

            // get source animation data from .SEQ
            List<Animation> animations = new List<Animation>();
            for (int i = 0; i < numAnimations; i++)
            {
                Animation animation = new Animation();
                // seek translation data
                long seekTranslationPtr = (long)(headers[i].ptrTranslation + ptrSequence + ptrBase);
                reader.BaseStream.Seek(seekTranslationPtr, SeekOrigin.Begin);

                reader.CurrentEndian = Endian.Big; // this is code used in the opcode portion (machine code uses Big)
                Int16 x = reader.ReadInt16();
                Int16 y = reader.ReadInt16();
                Int16 z = reader.ReadInt16();
                reader.CurrentEndian = Endian.Little;

                // TODO: implement move

                // set base animation

                if (headers[i].idOtherAnimation != -1)
                {
                    // TODO: FIX THIS
                    // should store other animation inside as base
                    // I assume it only references animations that
                    // have been constructed first otherwise it will hold a dead copy.
                    // animation.baseAnimation = animations[i];
                }

                // read base pose and keyframes
                animation.poses = new Vector3[numBones];
                animation.keyframes = new List<NullableVector4>[numBones];
                for (int k = 0; k < numBones; k++)
                {
                    animation.keyframes[k] = new List<NullableVector4>();
                    animation.keyframes[k].Add(NullableVector4.Zero());

                    // read pose
                    long seekBonePtr = (long)(headers[i].ptrBones[k] + ptrSequence + ptrBase);
                    reader.BaseStream.Seek(seekBonePtr, SeekOrigin.Begin);

                    reader.CurrentEndian = Endian.Big; // machine code uses Big
                    Int16 rx = reader.ReadInt16();
                    Int16 ry = reader.ReadInt16();
                    Int16 rz = reader.ReadInt16();
                    reader.CurrentEndian = Endian.Little;

                    animation.poses[k] = new Vector3(rx, ry, rz);

                    // read keyframe
                    float? f = 0;

                    while (true)
                    {
                        // this could be optimized using out values and an advanced way of recording and reading frames
                        NullableVector4 op = ReadOPCode(reader);
                        if (op == null) break;

                        f += op.W;

                        animation.keyframes[k].Add(op);

                        if (f >= headers[i].length - 1) break;
                    }
                }
                animations.Add(animation);
            }

            // build useable animation data
            for (int a = 0; a < numAnimations; a++)
            {
                // rotation bones
                for (int i = 0; i < numBones; i++)
                {
                    List<NullableVector4> keyframes = animations[a].keyframes[i];
                    Vector3 pose = animations[a].poses[i];

                    // multiplication by two at 0xad25c, 0xad274, 0xad28c
                    // value * (180f / uint16.max);
                    float rx = pose.X * 2;
                    float ry = pose.Y * 2;
                    float rz = pose.Z * 2;

                    List<Keyframe> keys = new List<Keyframe>();
                    float t = 0;

                    for (var j = 0; j < keyframes.Count; j++)
                    {
                        NullableVector4 keyframe = keyframes[j];

                        float f = (float)keyframe.W;

                        t += f;
                        if (keyframe.X == null) keyframe.X = keyframes[j - 1].X;
                        if (keyframe.Y == null) keyframe.Y = keyframes[j - 1].Y;
                        if (keyframe.Z == null) keyframe.Z = keyframes[j - 1].Z;

                        rx += (float)keyframe.X * f;
                        ry += (float)keyframe.Y * f;
                        rz += (float)keyframe.Z * f;

                        Quaternion q = VSTools.Rot2Quat(rx * VSTools.Rot13ToRad, ry * VSTools.Rot13ToRad, rz * VSTools.Rot13ToRad);

                        Keyframe key = new Keyframe();
                        key.Time = t * VSTools.TimeScale;
                        key.Rotation = q;
                        keys.Add(key);
                    }
                    animations[a].jointKeys.Add(keys);
                }

                // root's translation bone
                List<Keyframe> rootKey = new List<Keyframe>();
                rootKey.Add(new Keyframe());
                animations[a].jointKeys.Add(rootKey);

                // translation bones
                for (int t = 1; t < numBones; t++)
                {
                    List<Keyframe> transBone = new List<Keyframe>();
                    Keyframe key = new Keyframe();
                    key.Position = new Vector3(targetSHP.joints[t].boneLength, 0, 0);
                    transBone.Add(key);
                    animations[a].jointKeys.Add(transBone);
                }

                if (headers[a].idOtherAnimation != -1)
                {
                    animations[a].baseAnimation = animations[headers[a].idOtherAnimation];
                }
            }
            return new SEQ(animations);
        }