diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..e48029d --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,298 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "anmclean" +version = "0.1.0" +dependencies = [ + "xfbin", +] + +[[package]] +name = "anyhow" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" + +[[package]] +name = "array-init" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" + +[[package]] +name = "autocfg" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "binrw" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f846d8732b2a55b569b885852ecc925a2b1f24568f4707f8b1ccd5dc6805ea9b" +dependencies = [ + "array-init", + "binrw_derive", + "bytemuck", +] + +[[package]] +name = "binrw_derive" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2aa66a5e35daf7f91ed44c945886597ef4c327f34f68b6bbf22951a250ceeb" +dependencies = [ + "either", + "owo-colors", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "getrandom" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "libc" +version = "0.2.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustversion" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.43", +] + +[[package]] +name = "serde_json" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "xfbin" +version = "0.1.0" +dependencies = [ + "anyhow", + "binrw", + "downcast-rs", + "hashbrown 0.11.2", + "indexmap", + "itertools", + "serde", + "serde_json", + "strum", + "strum_macros", +] diff --git a/Cargo.toml b/Cargo.toml index 43738ad..3c3ddd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,4 +7,5 @@ description = "A simple program that removes redundant keyframes from a CyberCon # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -binrw = "0.10.0" +# used for reading and writing CyberConnect2's XFBIN files +xfbin = { path = "../xfbin-dev" } diff --git a/src/clean.rs b/src/clean.rs new file mode 100644 index 0000000..afa63b7 --- /dev/null +++ b/src/clean.rs @@ -0,0 +1,82 @@ +use std::collections::HashSet; + + +use xfbin::nucc_chunk::nucc_chunk_anm::{Curve, CurveHeader, AnmCurveFormat}; +use xfbin::nucc_chunk::nucc_helper::*; +use xfbin::nucc::NuccAnm; + +pub fn clean_anm(nucc_anm: &mut NuccAnm) { + for entry in nucc_anm.entries.iter_mut() { + for (curve, curve_header) in entry.curves.iter_mut().zip(&mut entry.curve_headers) { + clean_curve(curve, curve_header); + } + } +} + +pub fn clean_curve(curve: &mut Curve, curve_header: &mut CurveHeader) { + match curve { + Curve::KeyframeVector3(keyframes) => { + let values: Vec = keyframes.iter_mut().map(|keyframe| keyframe.value.clone()).collect(); + let set: HashSet = values.into_iter().collect(); + + if set.len() == 1 { + let first = keyframes.first().unwrap().clone(); + let clean_curve = Curve::Vector3(vec![first.value.clone()]); + *curve = clean_curve; + curve_header.curve_format = AnmCurveFormat::FLOAT3 as u16 + } + } + + Curve::KeyframeVector4(keyframes) => { + let values: Vec = keyframes.iter_mut().map(|keyframe| keyframe.value.clone()).collect(); + let set: HashSet = values.into_iter().collect(); + + if set.len() == 1 { + let first = keyframes.first().unwrap().clone(); + keyframes.clear(); + keyframes.push(first); + } + + curve.append_null_keyframe(); + curve_header.frame_count += 1; + } + + Curve::KeyframeFloat(keyframes) => { + let values: Vec = keyframes.iter_mut().map(|keyframe| keyframe.value.clone()).collect(); + let set: HashSet = values.into_iter().map(|x| x as u64).collect(); + + if set.len() == 1 { + let first = keyframes.first().unwrap().clone(); + let clean_curve = Curve::Float(vec![first.value.clone()]); + *curve = clean_curve; + curve_header.curve_format = AnmCurveFormat::FLOAT1 as u16 + } + } + + Curve::QuaternionShort(keyframes) => { + let values: Vec = keyframes.iter_mut().map(|keyframe| keyframe.clone()).collect(); + let set: HashSet = values.into_iter().collect(); + + if set.len() == 1 { + let first = keyframes.first().unwrap().clone(); + let clean_curve = Curve::QuaternionShort(vec![first.clone()]); + *curve = clean_curve; + curve_header.curve_format = AnmCurveFormat::SHORT4 as u16 + } + } + + Curve::RGB(values) => { + let rgb_values: Vec = values.iter_mut().map(|v| v.clone()).collect(); + let set: HashSet = rgb_values.into_iter().collect(); + + if set.len() == 1 { + let first = values.first().unwrap().clone(); + let clean_curve = Curve::RGB(vec![first.clone()]); + *curve = clean_curve; + curve_header.curve_format = AnmCurveFormat::BYTE3 as u16 + } + } + _ => {} + } +} + diff --git a/src/main.rs b/src/main.rs index 4411b31..15c1749 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,29 +1,31 @@ -use std::{fs::File, path::Path}; -use binrw::{BinReaderExt, BinWriterExt}; +mod clean; -mod structure; -mod utils; +use std::path::Path; -use crate::structure::anm::NuccAnm; -use crate::structure::clean::*; +use xfbin::{read_xfbin, write_xfbin}; +use xfbin::nucc::{NuccAnm, NuccStruct}; +use clean::*; fn main() { let args: Vec = std::env::args().collect(); let filepath = Path::new(&args[1]); - let mut anm = File::open(filepath) - .unwrap() - .read_be::() - .unwrap(); + if filepath.extension().unwrap() != "xfbin" { + panic!("File does not end with .xfbin"); + } + + let mut xfbin = read_xfbin(&Path::new(filepath)).unwrap(); - for entry in anm.entries.iter_mut() { - for (curve, curve_header) in entry.curves.iter_mut().zip(&mut entry.curve_headers) { - clean_curve(curve, curve_header); - update_header(curve, curve_header); + for nucc_page in xfbin.pages.iter_mut() { + for nucc_struct in nucc_page.structs.iter_mut() { + if let Some(nucc_anm) = nucc_struct.downcast_mut::() { + clean_anm(nucc_anm); + *nucc_struct = Box::new(nucc_anm.clone()) as Box; + } } } - - let mut file = File::create(filepath).unwrap(); - file.write_be(&anm).unwrap(); + + write_xfbin(xfbin, &Path::new(filepath)).unwrap(); + } \ No newline at end of file