If you are still using the old URL (datacrystal.romhacking.net), please update your bookmarks! The old URL may stop working soon.
The current URL is datacrystal.tcrf.net.
The current URL is datacrystal.tcrf.net.
Vagrant Story/SEQ files
Jump to navigation
Jump to search
Seq (Sequence) Files are animation files that are used to animate the games 3D models. The file format is not yet understood. Much of what follows was decyphered by Valendian and another reverse engineer whose shall remain anonymous until I have their permission to reveal their identity.
typedef struct tSeqHeader { ubyte NumFrames; ubyte padding; uhalf NumJoints; word FileSize; } SEQ_HEADER; // Hdr.NumFrames # number of frames of animation // Hdr.NumJoints # number of joints in the target skeleton (must match that of the shp file) // Hdr.FileSize # size of file data (minus this header) in bytes aligned to a 4 byte boundary // the number of sequences must be calculated at runtime. its not actually needed but nice to know typedef struct tSeqPointerTable { // seq Pointer Table word PtrSection3; // [1][2][3][4] word PtrSection2; // [1][2][3] } SEQ_PTRTBL; // SeqPointerTable.PtrSection3 # pointer to the frame data section // SeqPointerTable.PtrSection2 # pointer to the next sequence section typedef struct tSeqFrameHeader { // seq Frame Header uhalf Unknown1; // [1] ubyte Unknown2; // [1] ubyte Unknown3; // [1][2] uhalf PtrNextFrame; // [1] uhalf PtrThisFrame; // [1][2] uhalf PtrUnknownFrame; // [1][2] uhalf JointPtr0[Hdr.NumJoints]; // [1][2] uhalf JointPtr1[Hdr.NumJoints]; // [1] } SEQ_FRAMEHDR[NumSequences]; // FrameHdr.Unknown1 # // FrameHdr.Unknown2 # // FrameHdr.Unknown3 # // FrameHdr.PtrNextFrame # // FrameHdr.PtrThisFrame # // FrameHdr.PtrUnknownFrame # // FrameHdr.JointPtr0[Hdr.NumJoints] # points to animation data for each joint per frame // FrameHdr.JointPtr1[Hdr.NumJoints] # points to animation data for each joint per frame ubyte Section2[Hdr.NumFrames]; // [1] // specifies the sequence that follows on from this one (or looping) typedef struct tSeqFrameDataHeader { // seq Frame Data Header ubyte Unknown0; // [1][2] # (unaligned half's are read as two bytes) ubyte Unknown1; // [1][2] # (unaligned half's are read as two bytes) ubyte Unknown2; // [1][2] # (unaligned half's are read as two bytes) } SEQ_FrameDataHDR; // FrameDatahdr.Unknown0 # // FrameDatahdr.Unknown1 # // FrameDatahdr.Unknown2 # typedef struct tSeqFrameOpcode { ubyte Opcode; ubyte Param1; ubyte Param2; ubyte Param3; ubyte Param4; uhalf Param5; } SEQ_FrameOpcode; // FrameOpcode.Opcode # the 3 most significant bits flag the existence of parameters // FrameOpcode.Param1 # present if ((FrameOpcode.Opcode & 0x80) == 0x80) // FrameOpcode.Param2 # present if ((FrameOpcode.Opcode & 0x40) == 0x40) // FrameOpcode.Param3 # present if ((FrameOpcode.Opcode & 0x20) == 0x20) // FrameOpcode.Param4 # present if (((FrameOpcode.Opcode & 0xE0) == 0x00) // && ((FrameOpcode.Opcode & 0x03) != 0x03)) // FrameOpcode.Param5 # present if ((FrameOpcode.Opcode & 0xE0) == 0x00) typedef struct tSeqSequenceEnd { // appears to control looping animations uhalf Unknown1; // [1][2] # (unaligned half's are read as two bytes) uhalf Unknown2; // [1][2] # (unaligned half's are read as two bytes) uhalf Unknown3; // [1][2] # (unaligned half's are read as two bytes) } SEQ_SequenceEnd; // SequenceEnd.Unknown1 # sometimes first byte is read as an opcode // SequenceEnd.Unknown2 # // SequenceEnd.Unknown3 # // putting it all together the file has the following layout runtime word NumSequences = (PtrTbl.PtrSection2 - &FrameHdr[0]) / (0x0A + 4*Hdr.NumJoints); SEQ_HEADER Hdr; SEQ_PTRTBL PtrTbl; SEQ_FRAMEHDR FrameHdr[NumSequences]; ubyte Section2[Hdr.NumFrames]; for (NumSequences) { SEQ_FrameDataHDR FrameDataHdr; for (?) { SEQ_FrameOpcode Opcode; } }