Skip to content

OBAN: object animations ​

An object animation moves one rigid thing: a door, the warehouse's forklifts and truck, a cutscene camera. It holds key frames, each with a rotation, a position and a frame number; between keys both are lerped. 1,067 of them are on the CD. The port: src/oban.c. The reference reader: tools/onioban.py. The check: tests/oban_test.c (all: hash=1f2bffdc, 334,386 frames).

Layout ​

Instance data (offsets as tm.h gives them, past the 8-byte instance header):

OffsetSizeWhat
0x0012Zero on the CD
0x0c4Flags (below)
0x1048Start matrix, 3×4 by columns: where the object stands before it plays
0x4048Base matrix, 3×4: applied under every frame's transform
0x702Ticks per frame, 80 on the CD (see playing: it changes nothing)
0x722Frames
0x742A door's open frame (50 for the doors, 0 for the others; inferred)
0x762Key count
0x780x20 eachKeys: quaternion x, y, z, w (floats), position x, y, z (floats), frame (u32)

The first key is at frame 0 and the last at frames − 1 in every animation on the CD.

Flags (from OBrAnim_Start 0x439580, PHrPhysics_Update_Animation 0x43a620 and OBrAnimation_GetMatrix 0x439610):

BitMeaningOn the CD
0x01Loop37
0x02Ping-pong: back and forthnone
0x04Random start framenone
0x08Starts by itselfnone
0x10Turned a quarter about x (the doors)13

The matrix at a frame ​

OBrAnimation_GetMatrix 0x439610 walks the keys:

  • A key at the frame gives its rotation and position.
  • Otherwise the first key after the frame and the one before it are mixed. t = (frame − before) / (after − before). The position is lerped (0x433ff0, t·after + (1 − t)·before) and the quaternion goes through MUrQuat_Lerp 0x433360. Before the first key or after the last, the original reads outside the keys. No animation on the CD asks for those frames; the port holds the nearest end.

The matrix is T(position) · R(rotation) · Base, by MUrMatrix_Multiply 0x4341c0 (a·b on 3×4 matrices stored by columns). R comes from MUrQuatToMatrix 0x4338c0, and the caller's flag 2 leaves it out. With flag 0x10, 0x434570 then puts a rotation of π/2 about x (a double at 0x529d40) in front.

Playing ​

The playing state: the animation, a state word (1 playing, 0x10 paused), the frame, the step (+1 or −1), a frame to stop at (0: none) and the time of the last step.

  • OBrAnim_Start 0x439580: playing, at frame 0 or with flag 0x04 a random one, (UUrRandom × frames) >> 16. The step becomes 1. A paused animation is unpaused with the time set to now (0x43a600).
  • PHrPhysics_Update_Animation 0x43a620, each tick:
    • An animation with flag 0x08 that isn't playing starts.
    • While playing, it steps when the last step's time is below the ticks field plus now. That holds on every tick, so the animation moves one frame per tick and the field changes nothing. This looks like an inverted test in the original; the port keeps it.
    • At the end (the frame count, or the stop frame), ping-pong turns back from frames − 1, loop goes to 0, and anything else stops (0x439540: the frame clamped into the animation, the playing bit cleared). A ping-pong at a negative frame turns forwards again at 0.
    • It returns true when the animation stopped that tick.

GPL-3.0. Oni is a trademark of its owners; this project is not affiliated with them and distributes none of their data. Credits