diff --git a/docs/README.md b/docs/README.md index 0ea419d7..1c309a3e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -18,6 +18,7 @@ Kaitai Struct allows you to define binary formats in a YAML-based `.ksy` file, w | [`savegame.ksy`](/docs/savegame.ksy) | `.GS` | Main game save data (game state, progress, customizations) | | [`players.ksy`](/docs/players.ksy) | `.gsi` | Player profile save data (usernames) | | [`history.ksy`](/docs/history.ksy) | `.gsi` | Score history and high scores | +| [`animation.ksy`](/docs/animation.ksy) | `.ani` | Animation data (keyframes, actor references, camera animation) | ## Using the Tools @@ -38,6 +39,9 @@ ksv samples/Players.gsi players.ksy # View a History.gsi file ksv samples/History.gsi history.ksy + +# View an animation file +ksv samples/pns065rd.ani animation.ksy ``` ### Kaitai Struct Dump (ksdump) @@ -53,11 +57,15 @@ ksdump --format json samples/Players.gsi players.ksy # Dump History.gsi to YAML ksdump --format yaml samples/History.gsi history.ksy + +# Dump an animation file to JSON +ksdump --format json samples/pns065rd.ani animation.ksy ``` ## Sample Files -The [`samples/`](/docs/samples/) directory contains example save files for testing: +The [`samples/`](/docs/samples/) directory contains example files for testing: - `G0.GS`, `G1.GS`, `G2.GS` - Sample main game save files (slots 0, 1, 2) - `Players.gsi` - Sample player profile data - `History.gsi` - Sample score history data +- `pns065rd.ani` - Sample animation file diff --git a/docs/animation.ksy b/docs/animation.ksy new file mode 100644 index 00000000..6f582904 --- /dev/null +++ b/docs/animation.ksy @@ -0,0 +1,310 @@ +meta: + id: animation + title: Animation File + application: LEGO Island + file-extension: ani + license: CC0-1.0 + endian: le +doc: | + Animation file format for LEGO Island (1997). Contains skeletal animation + data including actor references, keyframes for translation/rotation/scale, + morph visibility keys, and optional camera animation data. + + Animation files are embedded within SI (Interleaf) files and + parsed by LegoAnimPresenter. The format consists of a header with bounding + information, an actor list, animation duration, optional camera animation, + and a hierarchical tree of animation nodes. + +seq: + - id: magic + type: s4 + doc: | + Magic number identifying the file format. Must be 0x11 (17 decimal). + - id: bounding_radius + type: f4 + doc: | + Radius of the bounding sphere encompassing the entire animation. + Used for visibility culling and collision detection. + - id: center_x + type: f4 + doc: X coordinate of the bounding sphere center point. + - id: center_y + type: f4 + doc: Y coordinate of the bounding sphere center point. + - id: center_z + type: f4 + doc: Z coordinate of the bounding sphere center point. + - id: has_camera_anim + type: s4 + doc: | + Flag indicating whether camera animation data follows the actor list. + If non-zero, a camera_anim structure is present after the duration field. + - id: unused + type: s4 + doc: | + Unused field. Read by the parser but not used for anything. + - id: num_actors + type: u4 + doc: Number of actor entries in the actor list. + - id: actors + type: actor_entry + repeat: expr + repeat-expr: num_actors + doc: | + List of actors referenced by this animation. Each entry contains + the actor name and type, which determines how the actor ROI is + managed during animation playback. + - id: duration + type: s4 + doc: Total duration of the animation in milliseconds. + - id: camera_anim + type: camera_anim + if: has_camera_anim != 0 + doc: | + Camera animation data including position, target, and rotation keys. + Only present if has_camera_anim is non-zero. + - id: root_node + type: tree_node + doc: | + Root node of the animation tree. The tree structure mirrors the + skeletal hierarchy of the animated model, with each node containing + keyframe data for its corresponding bone/part. + +types: + actor_entry: + doc: | + An actor reference in the animation. The name identifies which ROI + (Realtime Object Instance) to animate, and the type determines + how the actor is managed by the character manager. + seq: + - id: name_length + type: u4 + doc: Length of the actor name in bytes. + - id: name + type: str + size: name_length + encoding: ASCII + if: name_length > 0 + doc: Actor name used to look up the ROI in the scene. + - id: actor_type + type: u4 + enum: actor_type + if: name_length > 0 + doc: | + Determines how the actor ROI is created and managed. + See actor_type enum for possible values. + + camera_anim: + doc: | + Camera animation data (LegoAnimScene). Contains keyframes for camera + position, look-at target position, and roll rotation around the + view axis. + seq: + - id: num_translation_keys + type: u2 + doc: Number of camera position keyframes. + - id: translation_keys + type: translation_key + repeat: expr + repeat-expr: num_translation_keys + doc: Camera position keyframes. + - id: num_target_keys + type: u2 + doc: Number of look-at target position keyframes. + - id: target_keys + type: translation_key + repeat: expr + repeat-expr: num_target_keys + doc: Look-at target position keyframes. + - id: num_rotation_keys + type: u2 + doc: Number of camera roll rotation keyframes. + - id: rotation_keys + type: rotation_z_key + repeat: expr + repeat-expr: num_rotation_keys + doc: Camera roll rotation keyframes (rotation around view axis). + + tree_node: + doc: | + A node in the animation tree hierarchy. Each node contains animation + data for one part of the model and references to child nodes. + seq: + - id: data + type: node_data + doc: Animation keyframe data for this node. + - id: num_children + type: u4 + doc: Number of child nodes. + - id: children + type: tree_node + repeat: expr + repeat-expr: num_children + doc: Child nodes in the animation hierarchy. + + node_data: + doc: | + Animation data for a single node (LegoAnimNodeData). Contains the + node name and arrays of keyframes for translation, rotation, scale, + and morph (visibility) animations. + seq: + - id: name_length + type: u4 + doc: Length of the node name in bytes. + - id: name + type: str + size: name_length + encoding: ASCII + if: name_length > 0 + doc: | + Node name used to match this animation data to a ROI in the scene. + Names starting with '*' indicate special handling (actor name + substitution). Names starting with '-' are ignored. + - id: num_translation_keys + type: u2 + doc: Number of translation keyframes. + - id: translation_keys + type: translation_key + repeat: expr + repeat-expr: num_translation_keys + doc: Translation (position) keyframes. + - id: num_rotation_keys + type: u2 + doc: Number of rotation keyframes. + - id: rotation_keys + type: rotation_key + repeat: expr + repeat-expr: num_rotation_keys + doc: Rotation keyframes (quaternion format). + - id: num_scale_keys + type: u2 + doc: Number of scale keyframes. + - id: scale_keys + type: scale_key + repeat: expr + repeat-expr: num_scale_keys + doc: Scale keyframes. + - id: num_morph_keys + type: u2 + doc: Number of morph (visibility) keyframes. + - id: morph_keys + type: morph_key + repeat: expr + repeat-expr: num_morph_keys + doc: Morph keyframes controlling visibility. + + anim_key: + doc: | + Base animation key containing time and flags. The time and flags + are packed into a single 32-bit value: bits 0-23 contain the time + in milliseconds, and bits 24-31 contain flags. + seq: + - id: time_and_flags + type: s4 + doc: | + Packed time and flags value. + - Bits 0-23: Time in milliseconds (mask with 0xFFFFFF) + - Bits 24-31: Flags (shift right by 24) + instances: + time: + value: time_and_flags & 0xFFFFFF + doc: Keyframe time in milliseconds. + flags: + value: (time_and_flags >> 24) & 0xFF + doc: | + Keyframe flags: + - 0x01 (active): Key has meaningful data + - 0x02 (negate_rotation): Negate quaternion for interpolation + - 0x04 (skip_interpolation): Use this key's value without blending + + translation_key: + doc: | + Translation keyframe containing position offset (LegoTranslationKey). + The translation is applied relative to the parent node's transform. + seq: + - id: key + type: anim_key + doc: Base key with time and flags. + - id: x + type: f4 + doc: X component of translation. + - id: y + type: f4 + doc: Y component of translation. + - id: z + type: f4 + doc: Z component of translation. + + rotation_key: + doc: | + Rotation keyframe containing a quaternion (LegoRotationKey). + The quaternion is stored as (angle, x, y, z) where angle is the + scalar/w component and (x, y, z) is the vector part. + seq: + - id: key + type: anim_key + doc: Base key with time and flags. + - id: angle + type: f4 + doc: | + Quaternion scalar component (w). A value of 1.0 with x=y=z=0 + represents no rotation (identity quaternion). + - id: x + type: f4 + doc: Quaternion x component. + - id: y + type: f4 + doc: Quaternion y component. + - id: z + type: f4 + doc: Quaternion z component. + + scale_key: + doc: | + Scale keyframe containing scale factors (LegoScaleKey). + Scale is applied relative to the local origin of the node. + seq: + - id: key + type: anim_key + doc: Base key with time and flags. + - id: x + type: f4 + doc: X scale factor (1.0 = no scaling). + - id: y + type: f4 + doc: Y scale factor (1.0 = no scaling). + - id: z + type: f4 + doc: Z scale factor (1.0 = no scaling). + + morph_key: + doc: | + Morph/visibility keyframe (LegoMorphKey). Controls whether the + node's ROI is visible at a given time. + seq: + - id: key + type: anim_key + doc: Base key with time and flags. + - id: visible + type: u1 + doc: Visibility flag. Non-zero means visible. + + rotation_z_key: + doc: | + Z-axis rotation keyframe (LegoRotationZKey). Used for camera roll + animation where only rotation around the view axis is needed. + seq: + - id: key + type: anim_key + doc: Base key with time and flags. + - id: z + type: f4 + doc: Rotation angle around the Z axis in radians. + +enums: + actor_type: + 2: managed_lego_actor + 3: managed_invisible_roi_trimmed + 4: managed_invisible_roi + 5: scene_roi_1 + 6: scene_roi_2 diff --git a/docs/samples/pns065rd.ani b/docs/samples/pns065rd.ani new file mode 100644 index 00000000..7a912883 Binary files /dev/null and b/docs/samples/pns065rd.ani differ