From e4c810ab06879d596d14444b4b0695fa2b63af55 Mon Sep 17 00:00:00 2001 From: Serge Bazanski Date: Thu, 14 Apr 2022 22:51:49 +0000 Subject: [PATCH] all ra2 stock files with corresponding _txt are parsed --- gmflib/src/gma.rs | 5 +- gmflib/src/gmi.rs | 7 -- gmflib/src/types.rs | 162 +++++++++++++++++++++++++++++++++++++++++-- gmfmacros/src/lib.rs | 4 +- gmftool/src/main.rs | 41 ++++++++++- 5 files changed, 199 insertions(+), 20 deletions(-) diff --git a/gmflib/src/gma.rs b/gmflib/src/gma.rs index 2534ec7..0e026bb 100644 --- a/gmflib/src/gma.rs +++ b/gmflib/src/gma.rs @@ -36,9 +36,10 @@ impl Atom for f32 { } } -impl Serializable for [f32; 3] { +impl Serializable for [f32; N] { fn write(&self, name: S, w: &mut WriteStream) -> WriteResult<()> { - w.emit(&format!("{} {:.6}\t{:.6}\t{:.6}", name.to_string(), self[0], self[1], self[2])) + let fields = self.iter().map(|v| format!("{:.6}", v)).collect::>().join("\t"); + w.emit(&format!("{} {}", name.to_string(), fields)) } } diff --git a/gmflib/src/gmi.rs b/gmflib/src/gmi.rs index 39d9c6a..4111d55 100644 --- a/gmflib/src/gmi.rs +++ b/gmflib/src/gmi.rs @@ -186,13 +186,6 @@ pub struct TLV { } impl TLV { - pub fn error(&self, msg: S) -> ReadError { - ReadError { - msg: msg.to_string(), - stack: vec![], - } - } - pub fn check(&self, r: &mut ReadStream) -> ReadResult<()> { let expected = self.start_pos + self.length as usize + 12usize; if expected != r.pos { diff --git a/gmflib/src/types.rs b/gmflib/src/types.rs index 866df40..ae0cba8 100644 --- a/gmflib/src/types.rs +++ b/gmflib/src/types.rs @@ -96,6 +96,7 @@ pub enum MapKind { Diffuse = 1, SelfIllum = 5, Opacity = 6, + Reflect = 9, } impl gma::Serializable for MapKind { @@ -104,12 +105,15 @@ impl gma::Serializable for MapKind { MapKind::Diffuse => w.emit("*MAP_DIFFUSE"), MapKind::SelfIllum => w.emit("*MAP_SELFILLUM"), MapKind::Opacity => w.emit("*MAP_OPACITY"), + MapKind::Reflect => w.emit("*MAP_REFLECT"), } } } #[derive(Debug,GMISerializable,GMASerializable)] pub enum MapType { + Explicit = 0, + Spherical = 1, Screen = 4, } @@ -181,12 +185,14 @@ pub enum Shading { #[derive(Debug, GMISerializable,GMASerializable)] pub enum Falloff { In = 0, + InTwoSided = 1, } #[derive(Debug,GMISerializable,GMASerializable)] pub enum XPType { Other = 0, Filter = 1, + Additive = 3, } #[derive(Debug,GMISerializable,GMASerializable)] @@ -274,11 +280,13 @@ pub struct ObjectList { #[derive(Debug)] pub enum Object { Geometry(GeometryObject), + Camera(CameraObject), Light(LightObject), AttachmentPoint(AttachmentPointObject), - ConstraintSolver(ConstraintSolverObject), Simulation(SimulationObject), RBCollection(RBCollectionObject), + ConstraintSolver(ConstraintSolverObject), + AngularDashpot(AngularDashpotObject), } impl gmi::Serializable for Object { @@ -286,11 +294,13 @@ impl gmi::Serializable for Object { let tlv = r.tlv()?; let (res, check) = match (tlv.tag, tlv.flags) { (2, 4) => (Object::Geometry(r.read("geometry")?), false), + (4, 2) => (Object::Camera(r.read("camera")?), 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), (31, 4) => (Object::RBCollection(r.read("rigidbodycollection")?), false), + (42, 3) => (Object::ConstraintSolver(r.read("constraintsolver")?), false), + (49, 2) => (Object::AngularDashpot(r.read("angulardashpot")?), false), _ => return Err(r.error(format!("unknown object type ({}, {})", tlv.tag, tlv.flags))), }; if check { @@ -304,11 +314,13 @@ impl gma::Serializable for Object { fn write(&self, _name: S, w: &mut gma::WriteStream) -> gma::WriteResult<()> { match self { Object::Geometry(o) => o.write("", w), + Object::Camera(o) => o.write("", w), Object::Light(o) => o.write("", w), Object::AttachmentPoint(o) => o.write("", w), - Object::ConstraintSolver(o) => o.write("", w), Object::Simulation(o) => o.write("", w), Object::RBCollection(o) => o.write("", w), + Object::ConstraintSolver(o) => o.write("", w), + Object::AngularDashpot(o) => o.write("", w), } } } @@ -327,6 +339,29 @@ pub struct GeometryObject { pub mesh: Mesh, } +#[derive(Debug,GMISerializable,GMASerializable)] +#[gma_name("CAMERA")] +pub struct CameraObject { + #[gma_name("NODE_NAME")] + pub name: String, + #[gma_name("NODE_TM")] + pub tm1: TransformMatrix, + #[gma_name("NODE_TM")] + pub tm2: Option, + pub type_: CameraType, + pub hither: f32, + pub yon: f32, + pub near: f32, + pub far: f32, + pub fov: f32, + pub tdist: f32, +} + +#[derive(Debug,GMISerializable,GMASerializable)] +pub enum CameraType { + Target = 0, +} + #[derive(Debug,GMISerializable,GMASerializable)] #[gmi_tagged(17, 2)] #[gma_name("NODE_TM")] @@ -612,6 +647,8 @@ pub enum LightType { #[derive(Debug,GMISerializable,GMASerializable)] pub enum LightShadows { Off = 0, + Mapped = 1, + Raytraced = 2, } #[derive(Debug,GMASerializable)] @@ -648,14 +685,87 @@ pub struct ConstraintSolverObject { } #[derive(Debug,GMISerializable,GMASerializable)] -#[gmi_tagged(44, 2)] +#[gmi_tagged_nolen(44, 2)] pub struct ConstraintList { pub constraints: Vec, } -#[derive(Debug,GMISerializable,GMASerializable)] +#[derive(Debug)] pub enum Constraint { - Foo = 1, + Hinge(HingeConstraint), + PointToPoint(PointToPointConstraint), +} + +impl gmi::Serializable for Constraint { + fn read(r: &mut gmi::ReadStream) -> gmi::ReadResult { + let tlv = r.tlv()?; + let (res, check) = match (tlv.tag, tlv.flags) { + (47, 2) => (Constraint::Hinge(r.read("hinge")?), false), + (53, 2) => (Constraint::PointToPoint(r.read("pointtopoint")?), false), + _ => return Err(r.error(format!("unknown constraint type ({}, {})", tlv.tag, tlv.flags))), + }; + if check { + tlv.check(r)?; + } + Ok(res) + } +} + +impl gma::Serializable for Constraint { + fn write(&self, _name: S, w: &mut gma::WriteStream) -> gma::WriteResult<()> { + match self { + Constraint::Hinge(o) => o.write("", w), + Constraint::PointToPoint(o) => o.write("", w), + } + } +} + +#[derive(Debug,GMISerializable,GMASerializable)] +pub struct HingeConstraint { + #[gma_name("NODE_NAME")] + pub name: String, + pub tm: TransformMatrix, + #[gma_name("BODY1")] + pub body1: String, + #[gma_name("BODY2")] + pub body2: String, + #[gma_name("POINT")] + pub point: [f32; 3], + #[gma_name("SPIN_AXIS")] + pub spin_axis: [f32; 3], + #[gma_name("IS_LIMITED")] + pub is_limited: u8, + #[gma_name("FRICTION")] + pub friction: f32, + #[gma_name("ANGLE_LIMITS")] + pub angle_limits: [f32; 2], +} + +#[derive(Debug,GMISerializable,GMASerializable)] +pub struct PointToPointConstraint { + #[gma_name("NODE_NAME")] + pub name: String, + pub tm: TransformMatrix, + #[gma_name("BODY1")] + pub body1: String, + #[gma_name("BODY2")] + pub body2: String, + pub points: PTPPoints, +} + +#[derive(Debug,GMISerializable)] +pub struct PTPPoints { + a: Point, + b: Point, +} + +impl gma::Serializable for PTPPoints { + fn write(&self, _name: S, w: &mut gma::WriteStream) -> gma::WriteResult<()> { + w.emit("*POINT 1")?; + w.emit(&format!("(\t{:.6}\t{:.6}\t{:.6}\t)", self.a.x, self.a.y, self.a.z))?; + w.emit(&format!("(\t{:.6}\t{:.6}\t{:.6}\t)", self.b.x, self.b.y, self.b.z))?; + Ok(()) + } } #[derive(Debug,GMISerializable,GMASerializable)] @@ -796,6 +906,7 @@ impl gma::Serializable for NestedRigidBodyList { #[derive(Debug,GMISerializable,GMASerializable)] pub enum GeoType { Standard = 0, + Plane = 1, } #[derive(Debug,GMISerializable,GMASerializable)] @@ -818,3 +929,42 @@ impl gma::Serializable for DisabledCollisionPair { self.a, self.b)) } } + +#[derive(Debug,GMISerializable,GMASerializable)] +#[gma_name("GMID_HAVOK_ANGULAR_DASHPOT")] +pub struct AngularDashpotObject { + #[gma_name("NODE_NAME")] + pub name: String, + pub tm: TransformMatrix, + #[gma_name("BODY1")] + pub body1: String, + #[gma_name("BODY2")] + pub body2: String, + #[gma_name("STRENGTH")] + pub strength: f32, + #[gma_name("DAMPING")] + pub damping: f32, + #[gma_name("ALLOW_INTERPENETRATIONS")] + pub allow_interpenetrations: u8, + #[gma_name("QUATERNION")] + pub quaternion: Quaternion, +} + +#[derive(Debug)] +pub struct Quaternion([f32; 4]); + +impl gmi::Serializable for Quaternion { + fn read(r: &mut gmi::ReadStream) -> gmi::ReadResult { + <[f32; 4]>::read(r).map(|el| Quaternion(el)) + } +} + +impl gma::Serializable for Quaternion { + fn write(&self, name: S, w: &mut gma::WriteStream) -> gma::WriteResult<()> { + w.emit(&name.to_string())?; + let values = self.0.iter().map(|v| format!("{:.6}", v)).collect::>().join("\t"); + w.emit(&format!("(\t{}\t)", values))?; + Ok(()) + } +} + diff --git a/gmfmacros/src/lib.rs b/gmfmacros/src/lib.rs index 742ab83..f0321db 100644 --- a/gmfmacros/src/lib.rs +++ b/gmfmacros/src/lib.rs @@ -82,7 +82,7 @@ pub fn gmi_serializable_macro(input: TokenStream) -> TokenStream { tlv_header = quote! { let tlv = _r.tlv()?; if tlv.tag != #ty || tlv.flags != #flags { - return Err(tlv.error(format!("unsupported tag/flags (wanted {}/{}, got {}/{})", #ty, #flags, tlv.tag, tlv.flags))); + return Err(_r.error(format!("unsupported tag/flags (wanted {}/{}, got {}/{})", #ty, #flags, tlv.tag, tlv.flags))); } }; if !tagged.nolen { @@ -109,7 +109,7 @@ pub fn gmi_serializable_macro(input: TokenStream) -> TokenStream { let v: u32 = _r.read("value")?; let res = match v { #(#branches)* - _ => return Err(_r.error("unknown ")), + _ => return Err(_r.error(format!("unknown enum value {}", v))), }; #tlv_footer Ok(res) diff --git a/gmftool/src/main.rs b/gmftool/src/main.rs index f900823..9df7865 100644 --- a/gmftool/src/main.rs +++ b/gmftool/src/main.rs @@ -1,8 +1,43 @@ fn main() -> std::io::Result<()> { - let f = std::fs::File::open("/home/q3k/Games/RA2/Robot Arena 2 v1.4/Arenas/box/boxarena.gmf")?; - let gmf = gmflib::GMF::read_gmi(f).unwrap(); + let txt_gmfs = vec![ + "Arenas/practice arena/practice_arena_txt.gmf", + "Arenas/octagon/octagon_txt.gmf", + "Arenas/parkinglot/parkinglot_txt.gmf", + "Arenas/flextop/flextop_txt.gmf", + "Arenas/barrels/barrels_txt.gmf", + "Arenas/cones/cones_txt.gmf", + "Arenas/skull/skull_txt.gmf", + "Arenas/crates/crates_txt.gmf", + "Arenas/bridge/bridge_txt.gmf", + "Arenas/cinderblocks/blocks_txt.gmf", + "Arenas/event_results/event_results_txt.gmf", + "Arenas/compressor/compressor_txt.gmf", + "Arenas/hilltop/hilltop_txt.gmf", + "Arenas/kingofhill/king_txt.gmf", + "Arenas/electric/electric_txt.gmf", + "Arenas/half/half_txt.gmf", + "Arenas/box/boxarena_txt.gmf", + "Arenas/tabletop/clawtop_txt.gmf", + "Arenas/ramps/ramps_txt.gmf", + "UI/botlab/AP_box_selected_txt.gmf", + "UI/botlab/heading_arrow_txt.gmf", + "UI/botlab/AP_box_unselected_txt.gmf", + "Components/cannon/cannon_txt.gmf", + ]; - gmf.write_gma(std::io::stdout()).unwrap(); + for txt_gmf_path in txt_gmfs.iter() { + let txt_gmf_path = "/home/q3k/Games/RA2/Robot Arena 2 v1.4/".to_string() + txt_gmf_path; + let gmf_path = txt_gmf_path.replace("_txt.gmf", ".gmf"); + println!("Testing {} vs {}...", txt_gmf_path, gmf_path); + + let f = std::fs::File::open(gmf_path).unwrap(); + let gmf = gmflib::GMF::read_gmi(f).unwrap(); + } + + //let f = std::fs::File::open("/home/q3k/Games/RA2/Robot Arena 2 v1.4/Arenas/barrels/barrels.gmf")?; + //let gmf = gmflib::GMF::read_gmi(f).unwrap(); + + //gmf.write_gma(std::io::stdout()).unwrap(); Ok(()) }