use gmfmacros::GMFElement; use crate::machinery::{ReadResult, ReadStream, GMFElement}; #[derive(Debug)] pub struct GMI { pub version: u32, pub model_type: ModelType, pub unk1: u32, pub unk2: u32, pub scene: Scene, pub materials: MaterialList, pub objects: ObjectList, } impl GMI { pub fn parse(r: R) -> ReadResult { let mut r = ReadStream::new(r); r.read("gmi") } } impl GMFElement for GMI { fn read(r: &mut ReadStream) -> ReadResult { if r.bytes(3)? != b"GMI".to_vec() { return Err(r.error("invaid magic")); } let version: u32 = r.read("version")?; let model_type = r.read("model_type")?; let unk1: u32 = r.read("unk1")?; if unk1 != 0 { return Err(r.error("invalid unk1")); } let unk2: u32 = r.read("unk2")?; if unk2 != 15 { return Err(r.error("invalid unk2")); } Ok(Self { version, model_type, unk1, unk2, scene: r.read("scene")?, materials: r.read("material_list")?, objects: r.read("object_list")?, }) } } #[derive(Debug,GMFElement)] pub struct Color { pub r: u8, pub g: u8, pub b: u8, pub a: u8, } #[derive(Debug,GMFElement)] pub enum MapKind { Diffuse = 1, SelfIllum = 5, Opacity = 6, } #[derive(Debug,GMFElement)] pub enum MapType { Screen = 4, } #[derive(Debug,GMFElement)] pub enum BitmapFilter { Pyramidal = 0, SAT = 1, } #[derive(Debug, GMFElement)] pub enum ModelType { BasicModel = 1, } #[derive(Debug,GMFElement)] #[gmf_tagged(1,2)] pub struct Scene { pub filename: String, pub first_frame: u32, pub last_frame: u32, pub frame_speed: u32, pub ticks_per_frame: u32, pub background: Color, pub ambient: Color, } #[derive(Debug,GMFElement)] #[gmf_tagged(7, 2)] pub struct MaterialList { pub materials: Vec, } #[derive(Debug,GMFElement)] #[gmf_tagged(8, 2)] pub struct Material { pub ref_no: u32, pub name: String, pub class: String, pub ambient: Color, pub diffuse: Color, pub specular: Color, pub shine: f32, pub shine_strength: f32, pub wiresize: f32, pub transparency: f32, pub shading: Shading, pub xp_falloff: f32, pub selfillum: f32, pub falloff: Falloff, pub xp_type: XPType, pub textures: Option, pub sub: Option, } #[derive(Debug,GMFElement)] pub enum Shading { Other = 0, Blinn = 0xc, } #[derive(Debug, GMFElement)] pub enum Falloff { In = 0, } #[derive(Debug,GMFElement)] pub enum XPType { Other = 0, Filter = 1, } #[derive(Debug,GMFElement)] #[gmf_tagged(14, 2)] pub struct TextureList { pub textures: Vec, } #[derive(Debug,GMFElement)] #[gmf_tagged(15, 4)] pub struct Texture { pub name: String, pub class: String, pub bitmap: String, pub amount: f32, pub kind: MapKind, pub map_type: MapType, pub u_offset: f32, pub v_offset: f32, pub u_tiling: f32, pub v_tiling: f32, pub angle: f32, pub blur: f32, pub blur_offset: f32, pub noise_amt: f32, pub noise_size: f32, pub noise_level: u32, pub noise_phase: f32, pub invert: u32, pub unknown: u32, pub filter: BitmapFilter, pub channel: u32, pub sub: Option, } #[derive(Debug,GMFElement)] #[gmf_tagged(18,2)] pub struct ObjectList { pub objects: Vec, } #[derive(Debug)] pub enum Object { Geometry(GeometryObject), Light(LightObject), AttachmentPoint(AttachmentPointObject), ConstraintSolver(ConstraintSolverObject), Simulation(SimulationObject), RBCollection(RBCollectionObject), } impl GMFElement for Object { fn read(r: &mut ReadStream) -> ReadResult { let tlv = r.tlv()?; let (res, check) = match (tlv.tag, tlv.flags) { (2, 4) => (Object::Geometry(r.read("geometry")?), false), (5, 3) => (Object::Light(r.read("light")?), false), (21, 2) => (Object::AttachmentPoint(r.read("attachmentpoint")?), true), (42, 3) => (Object::ConstraintSolver(r.read("constraintsolver")?), false), (30, 2) => (Object::Simulation(r.read("simulation")?), false), _ => return Err(r.error(format!("unknown object type ({}, {})", tlv.tag, tlv.flags))), }; println!("{:#?}", res); if check { tlv.check(r)?; } Ok(res) } } #[derive(Debug,GMFElement)] pub struct GeometryObject { pub name: String, pub parent: String, pub shade_verts: u8, pub tm: TransformMatrix, pub mesh: Mesh, } #[derive(Debug,GMFElement)] #[gmf_tagged(17, 2)] pub struct TransformMatrix { pub name: String, pub data: [f32; 12], } #[derive(Debug)] pub struct Mesh { pub time: u32, pub vertex_count: u32, pub face_count: u32, pub tvertex_count: u32, pub cvertex_count: u32, pub material_ref: u32, pub vertices: Vec, pub faces: Vec, pub tvertices: Vec, pub tfaces: Vec, pub channels: Option>, pub cvertices: Vec, pub cfaces: Vec, pub normals: Vec, pub backface_cull: u32, } impl GMFElement for Mesh { fn read(r: &mut ReadStream) -> ReadResult { let tlv = r.tlv()?; if tlv.tag != 16 || tlv.flags != 4 { return Err(r.error("unexpected tag/flags (wanted 16/4)")); } let time = r.read("time")?; let vertex_count = r.read("vertex_count")?; let face_count = r.read("face_count")?; let tvertex_count = r.read("tvertex_count")?; let cvertex_count = r.read("cvertex_count")?; let material_ref = r.read("material_ref")?; let res = Self { time, vertex_count, face_count, tvertex_count, cvertex_count, material_ref, vertices: (0..vertex_count).map(|_| r.read("vertices")).collect::>>()?, faces: (0..face_count).map(|_| r.read("faces")).collect::>>()?, tvertices: (0..tvertex_count).map(|_| r.read("tvertices")).collect::>>()?, tfaces: if tvertex_count > 0 { (0..face_count).map(|_| r.read("tfaces")).collect::>>()? } else { vec![] }, channels: r.read("channels")?, cvertices: (0..cvertex_count).map(|_| r.read("cvertices")).collect::>>()?, cfaces: if cvertex_count > 0 { (0..face_count).map(|_| r.read("cfaces")).collect::>>()? } else { vec![] }, normals: (0..face_count).map(|_| r.read("normals")).collect::>>()?, backface_cull: r.read("backface_cull")?, }; // Broken for stock files. //tlv.check(r)?; Ok(res) } } #[derive(Debug,GMFElement)] pub struct Point { pub x: f32, pub y: f32, pub z: f32, } #[derive(Debug,GMFElement)] pub struct Face { pub a: u32, pub b: u32, pub c: u32, pub mtlid: u32, } #[derive(Debug,GMFElement)] pub struct TFace { pub a: u32, pub b: u32, pub c: u32, } #[derive(Debug,GMFElement)] pub struct FaceNormal { pub face: [f32; 3], pub vertex: [[f32; 3]; 3], } #[derive(Debug)] pub struct TextureChannel { pub unk1: u32, pub tvertex_count: u32, pub unk2: u32, pub face_count: u32, pub unk3: u32, pub unk4: u32, pub tvertex_count2: u32, pub face_count2: u32, pub tvertices: Vec, pub tfaces: Vec, } impl GMFElement for TextureChannel { fn read(r: &mut ReadStream) -> ReadResult { let unk1 = r.read("unk1")?; let tvertex_count = r.read("tvertex_count")?; let unk2 = r.read("unk2")?; let face_count = r.read("face_count")?; let unk3 = r.read("unk3")?; let unk4 = r.read("unk4")?; let tvertex_count2 = r.read("tvertex_count2")?; let face_count2 = r.read("face_count2")?; let res = Self { unk1, tvertex_count, unk2, face_count, unk3, unk4, tvertex_count2, face_count2, tvertices: (0..tvertex_count).map(|_| r.read("tvertices")).collect::>>()?, tfaces: if tvertex_count > 0 { (0..face_count).map(|_| r.read("tfaces")).collect::>>()? } else { vec![] }, }; Ok(res) } } #[derive(Debug,GMFElement)] pub struct LightObject { pub name: String, pub tm: TransformMatrix, pub target: String, pub light_type: LightType, pub shadows: LightShadows, pub uselight: u32, pub color: Color, pub intensity: f32, pub aspect: f32, pub unk1: [u8; 8], pub attn_start: f32, pub attn_end: f32, pub tdist: f32, pub use_for_attn: u32, } #[derive(Debug,GMFElement)] pub enum LightType { Omni = 0, } #[derive(Debug,GMFElement)] pub enum LightShadows { Off = 0, } #[derive(Debug,GMFElement)] pub struct AttachmentPointObject { pub name: String, pub tm: TransformMatrix, pub user_data: String, } #[derive(Debug,GMFElement)] pub struct ConstraintSolverObject { pub name: String, pub threshold: f32, pub rb_collection_name: String, pub constraints: Option, } #[derive(Debug,GMFElement)] #[gmf_tagged(44, 2)] pub struct ConstraintList { pub constraints: Vec, } #[derive(Debug,GMFElement)] pub enum Constraint { Foo = 1, } #[derive(Debug,GMFElement)] pub struct SimulationObject { pub name: String, pub gravity: Point, pub worldscale: f32, pub simtolerance: f32, pub resolver: u32, pub incl_drag: u8, pub linear_drag: f32, pub angular_drag: f32, pub incl_deactivator: u8, pub shortfreq: f32, pub longfreq: f32, pub last_subspace: u8, pub updates_per_timestamp: f32, pub collision_pairs: u32, } #[derive(Debug,GMFElement)] pub struct RBCollectionObject { pub name: String, }