all ra2 stock files with corresponding _txt are parsed

main
q3k 2022-04-14 22:51:49 +00:00
parent 13c9fe6678
commit e4c810ab06
5 changed files with 199 additions and 20 deletions

View File

@ -36,9 +36,10 @@ impl Atom for f32 {
} }
} }
impl Serializable for [f32; 3] { impl<const N: usize> Serializable for [f32; N] {
fn write<W: std::io::Write, S: std::string::ToString>(&self, name: S, w: &mut WriteStream<W>) -> WriteResult<()> { fn write<W: std::io::Write, S: std::string::ToString>(&self, name: S, w: &mut WriteStream<W>) -> 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::<Vec<String>>().join("\t");
w.emit(&format!("{} {}", name.to_string(), fields))
} }
} }

View File

@ -186,13 +186,6 @@ pub struct TLV {
} }
impl TLV { impl TLV {
pub fn error<S: std::string::ToString>(&self, msg: S) -> ReadError {
ReadError {
msg: msg.to_string(),
stack: vec![],
}
}
pub fn check<R: std::io::Read>(&self, r: &mut ReadStream<R>) -> ReadResult<()> { pub fn check<R: std::io::Read>(&self, r: &mut ReadStream<R>) -> ReadResult<()> {
let expected = self.start_pos + self.length as usize + 12usize; let expected = self.start_pos + self.length as usize + 12usize;
if expected != r.pos { if expected != r.pos {

View File

@ -96,6 +96,7 @@ pub enum MapKind {
Diffuse = 1, Diffuse = 1,
SelfIllum = 5, SelfIllum = 5,
Opacity = 6, Opacity = 6,
Reflect = 9,
} }
impl gma::Serializable for MapKind { impl gma::Serializable for MapKind {
@ -104,12 +105,15 @@ impl gma::Serializable for MapKind {
MapKind::Diffuse => w.emit("*MAP_DIFFUSE"), MapKind::Diffuse => w.emit("*MAP_DIFFUSE"),
MapKind::SelfIllum => w.emit("*MAP_SELFILLUM"), MapKind::SelfIllum => w.emit("*MAP_SELFILLUM"),
MapKind::Opacity => w.emit("*MAP_OPACITY"), MapKind::Opacity => w.emit("*MAP_OPACITY"),
MapKind::Reflect => w.emit("*MAP_REFLECT"),
} }
} }
} }
#[derive(Debug,GMISerializable,GMASerializable)] #[derive(Debug,GMISerializable,GMASerializable)]
pub enum MapType { pub enum MapType {
Explicit = 0,
Spherical = 1,
Screen = 4, Screen = 4,
} }
@ -181,12 +185,14 @@ pub enum Shading {
#[derive(Debug, GMISerializable,GMASerializable)] #[derive(Debug, GMISerializable,GMASerializable)]
pub enum Falloff { pub enum Falloff {
In = 0, In = 0,
InTwoSided = 1,
} }
#[derive(Debug,GMISerializable,GMASerializable)] #[derive(Debug,GMISerializable,GMASerializable)]
pub enum XPType { pub enum XPType {
Other = 0, Other = 0,
Filter = 1, Filter = 1,
Additive = 3,
} }
#[derive(Debug,GMISerializable,GMASerializable)] #[derive(Debug,GMISerializable,GMASerializable)]
@ -274,11 +280,13 @@ pub struct ObjectList {
#[derive(Debug)] #[derive(Debug)]
pub enum Object { pub enum Object {
Geometry(GeometryObject), Geometry(GeometryObject),
Camera(CameraObject),
Light(LightObject), Light(LightObject),
AttachmentPoint(AttachmentPointObject), AttachmentPoint(AttachmentPointObject),
ConstraintSolver(ConstraintSolverObject),
Simulation(SimulationObject), Simulation(SimulationObject),
RBCollection(RBCollectionObject), RBCollection(RBCollectionObject),
ConstraintSolver(ConstraintSolverObject),
AngularDashpot(AngularDashpotObject),
} }
impl gmi::Serializable for Object { impl gmi::Serializable for Object {
@ -286,11 +294,13 @@ impl gmi::Serializable for Object {
let tlv = r.tlv()?; let tlv = r.tlv()?;
let (res, check) = match (tlv.tag, tlv.flags) { let (res, check) = match (tlv.tag, tlv.flags) {
(2, 4) => (Object::Geometry(r.read("geometry")?), false), (2, 4) => (Object::Geometry(r.read("geometry")?), false),
(4, 2) => (Object::Camera(r.read("camera")?), false),
(5, 3) => (Object::Light(r.read("light")?), false), (5, 3) => (Object::Light(r.read("light")?), false),
(21, 2) => (Object::AttachmentPoint(r.read("attachmentpoint")?), true), (21, 2) => (Object::AttachmentPoint(r.read("attachmentpoint")?), true),
(42, 3) => (Object::ConstraintSolver(r.read("constraintsolver")?), false),
(30, 2) => (Object::Simulation(r.read("simulation")?), false), (30, 2) => (Object::Simulation(r.read("simulation")?), false),
(31, 4) => (Object::RBCollection(r.read("rigidbodycollection")?), 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))), _ => return Err(r.error(format!("unknown object type ({}, {})", tlv.tag, tlv.flags))),
}; };
if check { if check {
@ -304,11 +314,13 @@ impl gma::Serializable for Object {
fn write<W: io::Write, S: string::ToString>(&self, _name: S, w: &mut gma::WriteStream<W>) -> gma::WriteResult<()> { fn write<W: io::Write, S: string::ToString>(&self, _name: S, w: &mut gma::WriteStream<W>) -> gma::WriteResult<()> {
match self { match self {
Object::Geometry(o) => o.write("", w), Object::Geometry(o) => o.write("", w),
Object::Camera(o) => o.write("", w),
Object::Light(o) => o.write("", w), Object::Light(o) => o.write("", w),
Object::AttachmentPoint(o) => o.write("", w), Object::AttachmentPoint(o) => o.write("", w),
Object::ConstraintSolver(o) => o.write("", w),
Object::Simulation(o) => o.write("", w), Object::Simulation(o) => o.write("", w),
Object::RBCollection(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, 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<TransformMatrix>,
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)] #[derive(Debug,GMISerializable,GMASerializable)]
#[gmi_tagged(17, 2)] #[gmi_tagged(17, 2)]
#[gma_name("NODE_TM")] #[gma_name("NODE_TM")]
@ -612,6 +647,8 @@ pub enum LightType {
#[derive(Debug,GMISerializable,GMASerializable)] #[derive(Debug,GMISerializable,GMASerializable)]
pub enum LightShadows { pub enum LightShadows {
Off = 0, Off = 0,
Mapped = 1,
Raytraced = 2,
} }
#[derive(Debug,GMASerializable)] #[derive(Debug,GMASerializable)]
@ -648,14 +685,87 @@ pub struct ConstraintSolverObject {
} }
#[derive(Debug,GMISerializable,GMASerializable)] #[derive(Debug,GMISerializable,GMASerializable)]
#[gmi_tagged(44, 2)] #[gmi_tagged_nolen(44, 2)]
pub struct ConstraintList { pub struct ConstraintList {
pub constraints: Vec<Constraint>, pub constraints: Vec<Constraint>,
} }
#[derive(Debug,GMISerializable,GMASerializable)] #[derive(Debug)]
pub enum Constraint { pub enum Constraint {
Foo = 1, Hinge(HingeConstraint),
PointToPoint(PointToPointConstraint),
}
impl gmi::Serializable for Constraint {
fn read<R: io::Read>(r: &mut gmi::ReadStream<R>) -> gmi::ReadResult<Self> {
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<W: io::Write, S: string::ToString>(&self, _name: S, w: &mut gma::WriteStream<W>) -> 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<W: io::Write, S: string::ToString>(&self, _name: S, w: &mut gma::WriteStream<W>) -> 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)] #[derive(Debug,GMISerializable,GMASerializable)]
@ -796,6 +906,7 @@ impl gma::Serializable for NestedRigidBodyList {
#[derive(Debug,GMISerializable,GMASerializable)] #[derive(Debug,GMISerializable,GMASerializable)]
pub enum GeoType { pub enum GeoType {
Standard = 0, Standard = 0,
Plane = 1,
} }
#[derive(Debug,GMISerializable,GMASerializable)] #[derive(Debug,GMISerializable,GMASerializable)]
@ -818,3 +929,42 @@ impl gma::Serializable for DisabledCollisionPair {
self.a, self.b)) 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: io::Read>(r: &mut gmi::ReadStream<R>) -> gmi::ReadResult<Self> {
<[f32; 4]>::read(r).map(|el| Quaternion(el))
}
}
impl gma::Serializable for Quaternion {
fn write<W: io::Write, S: string::ToString>(&self, name: S, w: &mut gma::WriteStream<W>) -> gma::WriteResult<()> {
w.emit(&name.to_string())?;
let values = self.0.iter().map(|v| format!("{:.6}", v)).collect::<Vec<_>>().join("\t");
w.emit(&format!("(\t{}\t)", values))?;
Ok(())
}
}

View File

@ -82,7 +82,7 @@ pub fn gmi_serializable_macro(input: TokenStream) -> TokenStream {
tlv_header = quote! { tlv_header = quote! {
let tlv = _r.tlv()?; let tlv = _r.tlv()?;
if tlv.tag != #ty || tlv.flags != #flags { 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 { if !tagged.nolen {
@ -109,7 +109,7 @@ pub fn gmi_serializable_macro(input: TokenStream) -> TokenStream {
let v: u32 = _r.read("value")?; let v: u32 = _r.read("value")?;
let res = match v { let res = match v {
#(#branches)* #(#branches)*
_ => return Err(_r.error("unknown ")), _ => return Err(_r.error(format!("unknown enum value {}", v))),
}; };
#tlv_footer #tlv_footer
Ok(res) Ok(res)

View File

@ -1,8 +1,43 @@
fn main() -> std::io::Result<()> { 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 txt_gmfs = vec![
let gmf = gmflib::GMF::read_gmi(f).unwrap(); "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(()) Ok(())
} }