XPlor/definitions/volition/rig.xscript

127 lines
3.0 KiB
Plaintext
Raw Normal View History

// Volition Rig/Skeleton Format
// Used by: Saints Row 3/4, Red Faction series
// Contains bone hierarchy for character animation
type volition_rig ui("Volition Rig", root) byteorder LE
{
criteria {
require _ext == "rig_pc" || _ext == "rig_xbox2" || _ext == "rig_ps3";
// Rig files typically have reasonable bone counts (1-200)
bone_count_check = u32at(0);
require bone_count_check > 0 && bone_count_check < 500;
}
is_xbox = ends_with(_ext, "xbox2");
is_ps3 = ends_with(_ext, "ps3");
if (is_xbox) {
set_name("Rig (Xbox 360)");
parse_here("volition_rig_be");
} else if (is_ps3) {
set_name("Rig (PS3)");
parse_here("volition_rig_be");
} else {
set_name("Rig (PC)");
parse_here("volition_rig_impl");
}
}
type volition_rig_be ui("Rig") byteorder BE
{
parse_here("volition_rig_impl");
}
type volition_rig_impl ui("Rig")
{
// Rig header - 36 bytes of padding/reserved data
skip(36);
u32 bone_count ui("Bone Count");
u32 rig_flags ui("Flags");
u32 rig_value ui("Value");
// Parse bone data
if (bone_count > 0 && bone_count < 500) {
bone_idx = 0;
repeat(bone_count) {
i16 parent_id;
skip(2); // padding
f32 pos_x;
f32 pos_y;
f32 pos_z;
f32 rot_x;
f32 rot_y;
f32 rot_z;
f32 rot_w;
ctx_set("_rig_bone_idx", bone_idx);
ctx_set("_rig_parent_id", parent_id);
ctx_set("_rig_pos", pos_x + ", " + pos_y + ", " + pos_z);
bone_entry = bytesat(0, 1) |> parse volition_rig_bone;
push("bones", bone_entry);
bone_entry = 0;
bone_idx = bone_idx + 1;
}
}
// Bone names at end (null-terminated strings)
names_start = pos();
remaining = size() - pos();
if (remaining > 0) {
name_idx = 0;
while (pos() < size() && name_idx < bone_count) {
bone_name = cstring();
if (len(bone_name) > 0) {
ctx_set("_rig_name_idx", name_idx);
ctx_set("_rig_bone_name", bone_name);
name_entry = bytesat(0, 1) |> parse volition_rig_bone_name;
push("bone_names", name_entry);
name_entry = 0;
name_idx = name_idx + 1;
}
}
}
total_bones = bone_count ui("Total Bones");
file_size = size() ui("File Size");
}
type volition_rig_bone ui("Bone")
{
idx = ctx_get("_rig_bone_idx");
parent = ctx_get("_rig_parent_id");
position = ctx_get("_rig_pos");
set_name("Bone " + idx);
index = idx ui("Index");
parent_id = parent ui("Parent ID");
pos_display = position ui("Position");
}
type volition_rig_bone_name ui("Bone Name")
{
idx = ctx_get("_rig_name_idx");
name = ctx_get("_rig_bone_name");
set_name(name);
index = idx ui("Index");
bone_name = name ui("Name");
}
// Nested type for VPP parsing
type volition_rig_nested ui("Rig") byteorder LE
{
file_name = ctx_get("_vpp_file_name");
set_name(file_name);
is_xbox = ctx_get("_vpp_is_xbox");
is_ps3 = ctx_get("_vpp_is_ps3");
// Use truthiness check instead of == 1 for boolean context values
if (is_xbox || is_ps3) {
parse_here("volition_rig_be");
} else {
parse_here("volition_rig_impl");
}
}