most stock _txt.gmfs now match

main
q3k 2022-04-15 00:45:26 +00:00
parent e4c810ab06
commit 68eb498238
6 changed files with 257 additions and 60 deletions

134
Cargo.lock generated
View File

@ -2,6 +2,45 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "env_logger"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "gmflib"
version = "0.1.0"
@ -22,9 +61,47 @@ dependencies = [
name = "gmftool"
version = "0.1.0"
dependencies = [
"env_logger",
"gmflib",
"log",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "libc"
version = "0.2.123"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd"
[[package]]
name = "log"
version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "proc-macro2"
version = "1.0.36"
@ -43,6 +120,23 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "syn"
version = "1.0.90"
@ -54,8 +148,48 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -187,6 +187,9 @@ pub struct TLV {
impl TLV {
pub fn check<R: std::io::Read>(&self, r: &mut ReadStream<R>) -> ReadResult<()> {
if self.length == 0 {
return Ok(())
}
let expected = self.start_pos + self.length as usize + 12usize;
if expected != r.pos {
return Err(ReadError {

View File

@ -4,6 +4,7 @@ use gmfmacros::{GMISerializable, GMASerializable};
use crate::{
gmi, gma,
gma::Atom,
gmi::Serializable as GMISerializable,
gma::Serializable as GMASerializable,
};
@ -182,12 +183,27 @@ pub enum Shading {
Blinn = 0xc,
}
#[derive(Debug, GMISerializable,GMASerializable)]
#[derive(Debug, GMISerializable)]
pub enum Falloff {
In = 0,
InTwoSided = 1,
}
impl gma::Serializable for Falloff {
fn write<W: io::Write, S: string::ToString>(&self, _name: S, w: &mut gma::WriteStream<W>) -> gma::WriteResult<()> {
match self {
Falloff::In => {
w.emit_pair("*MATERIAL_FALLOFF", "In")?;
},
Falloff::InTwoSided => {
w.emit("*MATERIAL_TWOSIDED")?;
w.emit_pair("*MATERIAL_FALLOFF", "In")?;
},
}
Ok(())
}
}
#[derive(Debug,GMISerializable,GMASerializable)]
pub enum XPType {
Other = 0,
@ -298,9 +314,9 @@ impl gmi::Serializable for Object {
(5, 3) => (Object::Light(r.read("light")?), false),
(21, 2) => (Object::AttachmentPoint(r.read("attachmentpoint")?), true),
(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),
(31, 4) => (Object::RBCollection(r.read("rigidbodycollection")?), true),
(42, 3) => (Object::ConstraintSolver(r.read("constraintsolver")?), true),
(49, 2) => (Object::AngularDashpot(r.read("angulardashpot")?), true),
_ => return Err(r.error(format!("unknown object type ({}, {})", tlv.tag, tlv.flags))),
};
if check {
@ -339,14 +355,10 @@ pub struct GeometryObject {
pub mesh: Mesh,
}
#[derive(Debug,GMISerializable,GMASerializable)]
#[gma_name("CAMERA")]
#[derive(Debug,GMISerializable)]
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,
@ -357,6 +369,25 @@ pub struct CameraObject {
pub tdist: f32,
}
impl gma::Serializable for CameraObject {
fn write<W: io::Write, S: string::ToString>(&self, _name: S, w: &mut gma::WriteStream<W>) -> gma::WriteResult<()> {
w.push("*CAMERA")?;
self.name.write("*NODE_NAME", w)?;
self.type_.write("*CAMERA_TYPE", w)?;
self.tm1.write("*NODE_TM", w)?;
self.tm2.write("*NODE_TM", w)?;
self.hither.write("*CAMERA_HITHER", w)?;
self.yon.write("*CAMERA_YON", w)?;
self.near.write("*CAMERA_NEAR", w)?;
self.far.write("*CAMERA_FAR", w)?;
self.fov.write("*CAMERA_FOV", w)?;
self.tdist.write("*CAMERA_TDIST", w)?;
w.pop()?;
Ok(())
}
}
#[derive(Debug,GMISerializable,GMASerializable)]
pub enum CameraType {
Target = 0,
@ -635,8 +666,7 @@ pub struct LightObject {
pub attn_start: f32,
pub attn_end: f32,
pub tdist: f32,
#[gma_name("USE FAR ATTENUATION = ")]
pub use_far_attenuation: u32,
pub use_far_attenuation: FarAttenuation,
}
#[derive(Debug,GMISerializable,GMASerializable)]
@ -662,6 +692,23 @@ impl gmi::Serializable for LightSpotShape {
}
}
#[derive(Debug)]
pub struct FarAttenuation(u32);
impl gmi::Serializable for FarAttenuation {
fn read<R: io::Read>(r: &mut gmi::ReadStream<R>) -> gmi::ReadResult<Self> {
// Uninitialized memory in stock .GMFs. Whoops.
let v = u32::read(r)? & 0xff;
Ok(FarAttenuation(v))
}
}
impl gma::Serializable for FarAttenuation {
fn write<W: io::Write, S: string::ToString>(&self, _name: S, w: &mut gma::WriteStream<W>) -> gma::WriteResult<()> {
w.emit(&format!("*USE FAR ATTENUATION = \t{}", self.0))
}
}
#[derive(Debug,GMISerializable,GMASerializable)]
#[gma_name("GMID_ATTACHMENTPT")]
pub struct AttachmentPointObject {
@ -686,7 +733,9 @@ pub struct ConstraintSolverObject {
#[derive(Debug,GMISerializable,GMASerializable)]
#[gmi_tagged_nolen(44, 2)]
#[gma_name("GMID_HAVOK_CONSTRAINT_LIST")]
pub struct ConstraintList {
#[gma_name("")]
pub constraints: Vec<Constraint>,
}
@ -699,14 +748,12 @@ pub enum Constraint {
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),
let res = match (tlv.tag, tlv.flags) {
(47, 2) => Constraint::Hinge(r.read("hinge")?),
(53, 2) => Constraint::PointToPoint(r.read("pointtopoint")?),
_ => return Err(r.error(format!("unknown constraint type ({}, {})", tlv.tag, tlv.flags))),
};
if check {
tlv.check(r)?;
}
tlv.check(r)?;
Ok(res)
}
}
@ -721,6 +768,7 @@ impl gma::Serializable for Constraint {
}
#[derive(Debug,GMISerializable,GMASerializable)]
#[gma_name("GMID_HAVOK_HINGE_CONSTRAINT")]
pub struct HingeConstraint {
#[gma_name("NODE_NAME")]
pub name: String,
@ -734,14 +782,17 @@ pub struct HingeConstraint {
#[gma_name("SPIN_AXIS")]
pub spin_axis: [f32; 3],
#[gma_name("IS_LIMITED")]
#[gma_space_delim]
pub is_limited: u8,
#[gma_name("FRICTION")]
#[gma_space_delim]
pub friction: f32,
#[gma_name("ANGLE_LIMITS")]
pub angle_limits: [f32; 2],
}
#[derive(Debug,GMISerializable,GMASerializable)]
#[gma_name("GMID_HAVOK_POINTTOPOINT")]
pub struct PointToPointConstraint {
#[gma_name("NODE_NAME")]
pub name: String,
@ -762,8 +813,8 @@ pub struct PTPPoints {
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))?;
w.emit(&format!("( {:.6}\t{:.6}\t{:.6} )", self.a.x, self.a.y, self.a.z))?;
w.emit(&format!("( {:.6}\t{:.6}\t{:.6} )", self.b.x, self.b.y, self.b.z))?;
Ok(())
}
}
@ -963,7 +1014,7 @@ 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))?;
w.emit(&format!("( {} )", values))?;
Ok(())
}
}

View File

@ -229,7 +229,7 @@ impl GMAValue {
}
}
#[proc_macro_derive(GMASerializable, attributes(gma_name, gma_name_bare, gma_value, gma_skip))]
#[proc_macro_derive(GMASerializable, attributes(gma_name, gma_name_bare, gma_value, gma_skip, gma_space_delim))]
pub fn gma_serializable_macro(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let ident = input.ident;
@ -267,6 +267,7 @@ pub fn gma_serializable_macro(input: TokenStream) -> TokenStream {
let writes: Vec<proc_macro2::TokenStream> = fields.named.iter().map(|field| {
let field_ident = &field.ident;
let field_skip = field.attrs.iter().any(|a| a.path.is_ident("gma_skip"));
let field_space = field.attrs.iter().any(|a| a.path.is_ident("gma_space_delim"));
let field_name = GMAName::from_attrs(&field.attrs)
.map(|s|
if s.bare {
@ -280,8 +281,14 @@ pub fn gma_serializable_macro(input: TokenStream) -> TokenStream {
if field_skip {
quote! { }
} else {
quote! {
self.#field_ident.write(#field_name, _w)?;
if field_space {
quote! {
_w.emit(&format!("{} {}", #field_name, self.#field_ident.atom()))?;
}
} else {
quote! {
self.#field_ident.write(#field_name, _w)?;
}
}
}
}).collect();

View File

@ -7,3 +7,5 @@ edition = "2021"
[dependencies]
gmflib = { path = "../gmflib" }
log = "0"
env_logger = "0"

View File

@ -1,43 +1,43 @@
fn main() -> std::io::Result<()> {
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",
];
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);
fn main() {
env_logger::init_from_env(
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"));
let f = std::fs::File::open(gmf_path).unwrap();
let gmf = gmflib::GMF::read_gmi(f).unwrap();
let args: Vec<String> = std::env::args().collect();
if args.len() != 3 {
log::error!("Usage: {} foo.gmf foo_txt.gmf", args[0]);
return;
}
let gmf_path = &args[1];
let txt_gmf_path = &args[2];
//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();
let f = match std::fs::File::open(gmf_path) {
Ok(f) => f,
Err(e) => {
log::error!("Could not open {}: {:?}", gmf_path, e);
return;
},
};
let mut res = match std::fs::File::create(txt_gmf_path) {
Ok(f) => f,
Err(e) => {
log::error!("Could not write {}: {:?}", txt_gmf_path, e);
return;
},
};
//gmf.write_gma(std::io::stdout()).unwrap();
Ok(())
let gmf = match gmflib::GMF::read_gmi(f) {
Ok(gmf) => gmf,
Err(e) => {
log::error!("Reading GMI failed: {}", e.msg);
log::info!("Parse stack:");
for frame in e.stack.iter() {
log::info!(" {} at offset {}", frame.name, frame.loc);
}
return;
},
};
if let Err(e) = gmf.write_gma(&mut res) {
log::error!("Writing GMA failed: {}", e.msg);
}
}