Major improvements to VPP, PEG, and ASM parsers: vpp.xscript: - Support all VPP versions (4-10) for Saints Row 1-4 and Red Faction - Add container type detection (str2, packfile, etc.) - Improved compression handling (zlib, LZO, auto-detection) - Better recursive parsing of nested archives peg.xscript: - Full PEG texture container parsing - Support for multiple texture formats (DXT1, DXT3, DXT5, etc.) - Xbox 360 and PC format variants asm.xscript: - Animation state machine container parsing New format definitions: - anim.xscript: Animation data - audio.xscript: Audio containers (bank files) - mesh.xscript: 3D mesh geometry - morph.xscript: Morph targets - rig.xscript: Skeletal rigs - sim.xscript: Simulation data - zone.xscript: Level zone data Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
126 lines
3.5 KiB
Plaintext
126 lines
3.5 KiB
Plaintext
// Volition Mesh Format (csmesh/ccmesh/clmesh)
|
|
// Used by: Saints Row 3/4, Red Faction series
|
|
// Magic: 0x00043854 (v_file_header signature)
|
|
// c* = CPU header data, g* = GPU geometry data
|
|
// ccmesh = character (rigged), csmesh = static, clmesh = level
|
|
|
|
type volition_mesh ui("Volition Mesh", root) byteorder LE
|
|
{
|
|
criteria {
|
|
require _ext == "csmesh_pc" || _ext == "csmesh_xbox2" || _ext == "csmesh_ps3" ||
|
|
_ext == "ccmesh_pc" || _ext == "ccmesh_xbox2" || _ext == "ccmesh_ps3" ||
|
|
_ext == "clmesh_pc" || _ext == "clmesh_xbox2" || _ext == "clmesh_ps3";
|
|
require u32at(0) == 0x00043854;
|
|
}
|
|
|
|
// Detect platform
|
|
is_xbox = ends_with(_ext, "xbox2");
|
|
is_ps3 = ends_with(_ext, "ps3");
|
|
|
|
if (is_xbox || is_ps3) {
|
|
parse_here("volition_mesh_be");
|
|
} else {
|
|
parse_here("volition_mesh_impl");
|
|
}
|
|
}
|
|
|
|
// Big-endian wrapper for Xbox 360/PS3
|
|
type volition_mesh_be ui("Mesh") byteorder BE
|
|
{
|
|
parse_here("volition_mesh_impl");
|
|
}
|
|
|
|
// Shared implementation
|
|
type volition_mesh_impl ui("Mesh")
|
|
{
|
|
// Detect mesh type from extension
|
|
is_character = contains(_ext, "ccmesh");
|
|
is_static = contains(_ext, "csmesh");
|
|
is_level = contains(_ext, "clmesh");
|
|
|
|
mesh_type = "Unknown Mesh";
|
|
if (is_character) { mesh_type = "Character Mesh (Rigged)"; }
|
|
if (is_static) { mesh_type = "Static Mesh"; }
|
|
if (is_level) { mesh_type = "Level Mesh"; }
|
|
set_name(mesh_type);
|
|
|
|
// v_file_header (streaming reference header)
|
|
u32 signature ui("Signature"); // 0x00043854
|
|
u32 data_size ui("Data Size");
|
|
u32 unknown_08 ui("Unknown 0x08");
|
|
u32 file_count ui("File Count");
|
|
|
|
// Mesh info header
|
|
u32 mesh_magic ui("Mesh Magic"); // 0x424bdood
|
|
u32 mesh_version ui("Version"); // Usually 0x2a (42)
|
|
|
|
// Model data block
|
|
u32 nine ui("Nine"); // Always 9
|
|
u32 crc ui("CRC");
|
|
u32 model_data_size ui("Model Data Size");
|
|
u32 gmesh_size ui("GPU Mesh Size");
|
|
u32 flags ui("Flags");
|
|
u32 indices_count ui("Index Count");
|
|
u32 index_stride ui("Index Stride");
|
|
u32 bones_count ui("Bone Count");
|
|
f32 scale_x ui("Scale X");
|
|
f32 scale_y ui("Scale Y");
|
|
f32 scale_z ui("Scale Z");
|
|
u32 vertex_count ui("Vertex Count");
|
|
u32 vertex_stride ui("Vertex Stride");
|
|
|
|
// Bounding sphere
|
|
f32 bound_x ui("Bound Center X");
|
|
f32 bound_y ui("Bound Center Y");
|
|
f32 bound_z ui("Bound Center Z");
|
|
f32 bound_radius ui("Bound Radius");
|
|
|
|
// Texture name count
|
|
u32 texture_count ui("Texture Count");
|
|
|
|
// Parse texture names
|
|
if (texture_count > 0 && texture_count < 100) {
|
|
tex_idx = 0;
|
|
repeat(texture_count) {
|
|
tex_name = cstring();
|
|
ctx_set("_mesh_tex_name", tex_name);
|
|
ctx_set("_mesh_tex_idx", tex_idx);
|
|
tex_entry = bytesat(0, 1) |> parse volition_mesh_texture_ref;
|
|
push("textures", tex_entry);
|
|
tex_entry = 0;
|
|
tex_idx = tex_idx + 1;
|
|
}
|
|
}
|
|
|
|
// Summary info
|
|
type_display = mesh_type ui("Mesh Type");
|
|
total_file_size = size() ui("File Size");
|
|
}
|
|
|
|
// Texture reference entry
|
|
type volition_mesh_texture_ref ui("Texture Reference")
|
|
{
|
|
tex_name = ctx_get("_mesh_tex_name");
|
|
set_name(tex_name);
|
|
index = ctx_get("_mesh_tex_idx") ui("Index");
|
|
name = tex_name ui("Texture Name");
|
|
}
|
|
|
|
// Nested mesh type for VPP parsing
|
|
type volition_mesh_nested ui("Mesh") byteorder LE
|
|
{
|
|
file_name = ctx_get("_vpp_file_name");
|
|
set_name(file_name);
|
|
|
|
// Detect platform from context
|
|
is_xbox = ctx_get("_vpp_is_xbox");
|
|
is_ps3 = ctx_get("_vpp_is_ps3");
|
|
|
|
// Use truthiness check for boolean context values
|
|
if (is_xbox || is_ps3) {
|
|
parse_here("volition_mesh_be");
|
|
} else {
|
|
parse_here("volition_mesh_impl");
|
|
}
|
|
}
|