436 lines
10 KiB
Rust
436 lines
10 KiB
Rust
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: std::io::Read>(r: R) -> ReadResult<Self> {
|
|
let mut r = ReadStream::new(r);
|
|
r.read("gmi")
|
|
}
|
|
}
|
|
|
|
impl GMFElement for GMI {
|
|
fn read<R: std::io::Read>(r: &mut ReadStream<R>) -> ReadResult<Self> {
|
|
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<Material>,
|
|
}
|
|
|
|
#[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<TextureList>,
|
|
pub sub: Option<MaterialList>,
|
|
}
|
|
|
|
#[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<Texture>,
|
|
}
|
|
|
|
#[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<TextureList>,
|
|
}
|
|
|
|
#[derive(Debug,GMFElement)]
|
|
#[gmf_tagged(18,2)]
|
|
pub struct ObjectList {
|
|
pub objects: Vec<Object>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum Object {
|
|
Geometry(GeometryObject),
|
|
Light(LightObject),
|
|
AttachmentPoint(AttachmentPointObject),
|
|
ConstraintSolver(ConstraintSolverObject),
|
|
Simulation(SimulationObject),
|
|
RBCollection(RBCollectionObject),
|
|
}
|
|
|
|
impl GMFElement for Object {
|
|
fn read<R: std::io::Read>(r: &mut ReadStream<R>) -> ReadResult<Self> {
|
|
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<Point>,
|
|
pub faces: Vec<Face>,
|
|
|
|
pub tvertices: Vec<Point>,
|
|
pub tfaces: Vec<TFace>,
|
|
|
|
pub channels: Option<Vec<TextureChannel>>,
|
|
|
|
pub cvertices: Vec<Point>,
|
|
pub cfaces: Vec<TFace>,
|
|
|
|
pub normals: Vec<FaceNormal>,
|
|
|
|
pub backface_cull: u32,
|
|
}
|
|
|
|
impl GMFElement for Mesh {
|
|
fn read<R: std::io::Read>(r: &mut ReadStream<R>) -> ReadResult<Self> {
|
|
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::<ReadResult<Vec<Point>>>()?,
|
|
faces: (0..face_count).map(|_| r.read("faces")).collect::<ReadResult<Vec<Face>>>()?,
|
|
tvertices: (0..tvertex_count).map(|_| r.read("tvertices")).collect::<ReadResult<Vec<Point>>>()?,
|
|
tfaces: if tvertex_count > 0 {
|
|
(0..face_count).map(|_| r.read("tfaces")).collect::<ReadResult<Vec<TFace>>>()?
|
|
} else {
|
|
vec![]
|
|
},
|
|
channels: r.read("channels")?,
|
|
cvertices: (0..cvertex_count).map(|_| r.read("cvertices")).collect::<ReadResult<Vec<Point>>>()?,
|
|
cfaces: if cvertex_count > 0 {
|
|
(0..face_count).map(|_| r.read("cfaces")).collect::<ReadResult<Vec<TFace>>>()?
|
|
} else {
|
|
vec![]
|
|
},
|
|
normals: (0..face_count).map(|_| r.read("normals")).collect::<ReadResult<Vec<FaceNormal>>>()?,
|
|
|
|
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<Point>,
|
|
pub tfaces: Vec<TFace>,
|
|
}
|
|
|
|
impl GMFElement for TextureChannel {
|
|
fn read<R: std::io::Read>(r: &mut ReadStream<R>) -> ReadResult<Self> {
|
|
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::<ReadResult<Vec<_>>>()?,
|
|
tfaces: if tvertex_count > 0 {
|
|
(0..face_count).map(|_| r.read("tfaces")).collect::<ReadResult<Vec<_>>>()?
|
|
} 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<ConstraintList>,
|
|
}
|
|
|
|
#[derive(Debug,GMFElement)]
|
|
#[gmf_tagged(44, 2)]
|
|
pub struct ConstraintList {
|
|
pub constraints: Vec<Constraint>,
|
|
}
|
|
|
|
#[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,
|
|
}
|