JBA File Structure - SWTOR-Slicers/WikiPedia GitHub Wiki

  1. File Layout
  2. File Header
  3. Block Header
  4. Bone Data
  5. Block Data
    1. Keyframe Layout
    2. Keyframe Encoding
  6. World Space
  7. Bone Names

File Layout

  1. File Header
  2. Block Header, one per block
  3. Run-time initialized values, 4 bytes per block
  4. Array of Bone Data structs, 128-byte aligned, length equals number of bones
  5. Array of Block Data structs, 128-byte aligned, length equals number of blocks
  6. World Space, 128-byte aligned
  7. Bone Names

File Header

Offset (h) Type Count Description Values
00 uint32 1 Run-time initialized value 0
04 float 1 Animation length N/A
08 float 1 FPS 15.0,30.0
0C uint32 1 Number of blocks 1-20
10 uint32 2 Run-time initialized values 0
18 uint32 1 Number of bones N/A
1C uint32 1 Unknown 0
20 uint32 1 Pointer to keyframes (run-time initialized) 0FFFFFFFh
24 uint32 1 Unknown 0

Block Header

Offset (h) Type Count Description Values
00 uint32 1 Starting frame N/A
04 uint32 1 Size of the data structure N/A

Bone Data

Offset (h) Type Count Description Values
00 float 3 Translation stride N/A
0C float 3 Translation base N/A
18 float 3 Rotation stride N/A
2A float 3 Rotation base N/A

Block Data

Offset (h) Type Count Description Values
00 uint32 1 Number of bones N/A
04 uint32 1 Unknown 0
08 uint32 4 * number of bones Keyframe layout N/A
N/A uint16 N/A Keyframes (48-bit quaternion + optional 32-bit translation) N/A

Keyframe Layout

Keyframe layout contains four integer values per bone, where the first value represents a number of rotation poses and the third value represents a number of translation poses (optional).

Keyframes are stored according to this layout:

  • Bone 0: keyframe 0 rotation
  • Bone 0: keyframe 1 rotation
  • Bone 0: keyframe 0 translation (optional)
  • Bone 0: keyframe 1 translation (optional)
  • Bone 1: keyframe 0 rotation
  • Bone 1: keyframe 1 rotation
  • Bone 1: keyframe 0 translation (optional)
  • Bone 1: keyframe 1 translation (optional)

Keyframe Encoding

Rotation (on disk): Sign(1)-X(15)-Y(16)-Z(16)

Translation (on disk): Z(10)-Y(11)-X(11)

Decoding in Python:

val = ruint32(file)
pos_x = base.x + (val >> 21) * stride.x
pos_y = base.y + ((val >> 10) & 0x7ff) * stride.y
pos_z = base.z + (val & 0x3ff) * stride.z
pos = Vector((pos_x, pos_y, pos_z))

rot_x_raw = ruint16(file)
rot_x = base.x + (rot_x_raw & 0x7fff) * stride.x
rot_y = base.y + ruint16(file) * stride.y
rot_z = base.z + ruint16(file) * stride.z
rot_dot = rot_x * rot_x + rot_y * rot_y + rot_z * rot_z
rot_w = 0.0 if rot_dot > 1.0 else math.sqrt(1.0 - rot_dot)
if rot_x_raw & 0x8000:
    rot_w *= -1.0
rot = Quaternion((rot_w, rot_x, rot_y, rot_z))

Rotations and translations are in the "morpheme" space. Below is its transformation matrix:

1000.0    0.0     0.0   0.0
   0.0    0.0 -1000.0   0.0
   0.0 1000.0     0.0   0.0
   0.0    0.0     0.0   1.0

World Space

Offset (h) Type Count Description Values
00 uint32 1 Unknown 0
04 float 1 FPS 15.0/30.0
08 float 3 Translation stride N/A
14 float 3 Translation base N/A
20 float 3 Rotation stride N/A
2C float 3 Rotation base N/A
38 uint32 1 Number of rotations N/A
3C uint32 1 Pointer to rotations (run-time initialized) 0
40 uint32 1 Number of translations N/A
44 uint32 1 Pointer to translations (run-time initialized) 0
48 uint16 3 * number of rotations Compressed rotations (run-time initialized?) N/A
N/A uint32 Number of translations Compressed translations, 4-byte aligned N/A

Bone Names

Offset (h) Type Count Description Values
00 uint32 1 Number of names N/A
04 uint32 1 Unknown N/A
08 uint32 1 Offset to indices 20
0C uint32 1 Offset to offsets 20+4*(number of names)
10 uint32 1 Offset to names 20+8*(number of names)
14 uint32 number of names Indices 0-N
N/A uint32 number of names Offsets into the names array N/A
N/A char N/A Null-terminated names N/A