diff --git a/Cargo.lock b/Cargo.lock index 70a6c92..a7f3d48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,15 +31,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - [[package]] name = "allocator-api2" version = "0.2.16" @@ -82,15 +73,6 @@ dependencies = [ "libc", ] -[[package]] -name = "approx" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" -dependencies = [ - "num-traits", -] - [[package]] name = "array-init" version = "2.1.0" @@ -136,12 +118,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "binrw" version = "0.13.3" @@ -193,19 +169,6 @@ version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" -[[package]] -name = "blake3" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", -] - [[package]] name = "block" version = "0.1.6" @@ -237,15 +200,6 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" -[[package]] -name = "bv" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" -dependencies = [ - "feature-probe", -] - [[package]] name = "bytemuck" version = "1.14.1" @@ -266,12 +220,6 @@ dependencies = [ "syn 2.0.48", ] -[[package]] -name = "byteorder" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" - [[package]] name = "byteorder" version = "1.5.0" @@ -338,16 +286,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" -[[package]] -name = "cgmath" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a98d30140e3296250832bbaaff83b27dcd6fa3cc70fb6f1f3e5c9c0023b5317" -dependencies = [ - "approx", - "num-traits", -] - [[package]] name = "codespan-reporting" version = "0.11.1" @@ -414,12 +352,6 @@ version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec6d3da8e550377a85339063af6e3735f4b1d9392108da4e083a1b3b9820288" -[[package]] -name = "constant_time_eq" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" - [[package]] name = "core-foundation" version = "0.9.4" @@ -460,30 +392,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - [[package]] name = "crossbeam-utils" version = "0.8.19" @@ -514,7 +422,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479dfe1e6737aa9e96c6ac7b69689dc4c32da8383f2c12744739d76afa8b66c4" dependencies = [ "bitflags 2.4.2", - "byteorder 1.5.0", + "byteorder", "enum-primitive-derive", "num-traits", ] @@ -573,12 +481,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "feature-probe" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" - [[package]] name = "foreign-types" version = "0.5.0" @@ -769,15 +671,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "jni" version = "0.21.1" @@ -835,35 +728,6 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" -[[package]] -name = "lazy-regex" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d12be4595afdf58bd19e4a9f4e24187da2a66700786ff660a418e9059937a4c" -dependencies = [ - "lazy-regex-proc_macros", - "once_cell", - "regex", -] - -[[package]] -name = "lazy-regex-proc_macros" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bcd58e6c97a7fcbaffcdc95728b393b8d98933bfadad49ed4097845b57ef0b" -dependencies = [ - "proc-macro2", - "quote", - "regex", - "syn 2.0.48", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" version = "0.2.152" @@ -923,45 +787,6 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -[[package]] -name = "lz4" -version = "1.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" -dependencies = [ - "libc", - "lz4-sys", -] - -[[package]] -name = "lz4-sys" -version = "1.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "lzma" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "782ba3f542e8bc1349386c15e9dc3119ae6da96479f96b3863cc7a88bbdfd4e4" -dependencies = [ - "byteorder 0.5.3", -] - -[[package]] -name = "lzma-rs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" -dependencies = [ - "byteorder 1.5.0", - "crc", -] - [[package]] name = "malloc_buf" version = "0.0.6" @@ -1081,12 +906,6 @@ dependencies = [ "syn 2.0.48", ] -[[package]] -name = "obj" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "059c95245738cdc7b40078cdd51a23200252a4c0a0a6dd005136152b3f467a4a" - [[package]] name = "objc" version = "0.2.7" @@ -1225,12 +1044,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - [[package]] name = "presser" version = "0.3.1" @@ -1260,19 +1073,6 @@ name = "profiling" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135ede8821cf6376eb7a64148901e1690b788c11ae94dc297ae917dbc91dc0e" -dependencies = [ - "profiling-procmacros", -] - -[[package]] -name = "profiling-procmacros" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b322d7d65c1ab449be3c890fcbd0db6e1092d0dd05d79dba2dd28032cebeb05" -dependencies = [ - "quote", - "syn 2.0.48", -] [[package]] name = "quick-xml" @@ -1292,36 +1092,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - [[package]] name = "range-alloc" version = "0.1.3" @@ -1334,83 +1104,6 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544" -[[package]] -name = "rbx_binary" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6314dd6bf5c21d0598cdb53cf5d241aa643ba41da8b8abf7402b4a35096f03f6" -dependencies = [ - "log", - "lz4", - "profiling", - "rbx_dom_weak", - "rbx_reflection", - "rbx_reflection_database", - "thiserror", -] - -[[package]] -name = "rbx_dom_weak" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b67b56bac99849c2e3c57547b036927f71c57cf7f4d900d04e3e4ee774ec316" -dependencies = [ - "rbx_types", - "serde", -] - -[[package]] -name = "rbx_reflection" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d41509c991b53a7276a746a795eae2b9204f398164920f61976995b47fe1722" -dependencies = [ - "rbx_types", - "serde", - "thiserror", -] - -[[package]] -name = "rbx_reflection_database" -version = "0.2.10+roblox-607" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12e20c06fa41f7aadc79005c8354f592b2c2f4d0c61e1080ed5718dafc30aea0" -dependencies = [ - "lazy_static", - "rbx_reflection", - "rmp-serde", - "serde", -] - -[[package]] -name = "rbx_types" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca23bfd469d067d81ef14f65fe09aeddc25abcf576a889d1a7664fe021cf18c" -dependencies = [ - "base64", - "bitflags 1.3.2", - "blake3", - "lazy_static", - "rand", - "serde", - "thiserror", -] - -[[package]] -name = "rbx_xml" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c03f95500961c32340791d1fabd4587f6873bdbff077ecca6ae32db7960dea" -dependencies = [ - "base64", - "log", - "rbx_dom_weak", - "rbx_reflection", - "rbx_reflection_database", - "xml-rs", -] - [[package]] name = "redox_syscall" version = "0.3.5" @@ -1429,63 +1122,12 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "regex" -version = "1.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - [[package]] name = "renderdoc-sys" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "216080ab382b992234dda86873c18d4c48358f5cfcb70fd693d7f6f2131b628b" -[[package]] -name = "rmp" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20" -dependencies = [ - "byteorder 1.5.0", - "num-traits", - "paste", -] - -[[package]] -name = "rmp-serde" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a" -dependencies = [ - "byteorder 1.5.0", - "rmp", - "serde", -] - [[package]] name = "rustc-hash" version = "1.1.0" @@ -1640,17 +1282,10 @@ dependencies = [ "configparser", "ddsfile", "glam", - "lazy-regex", - "obj", "parking_lot", "pollster", - "rbx_binary", - "rbx_dom_weak", - "rbx_reflection_database", - "rbx_xml", "strafesnet_common", - "vbsp", - "vmdl", + "strafesnet_snf", "wgpu", "winit", ] @@ -1663,6 +1298,14 @@ dependencies = [ "glam", ] +[[package]] +name = "strafesnet_snf" +version = "0.1.0" +source = "git+https://git.itzana.me/StrafesNET/snf?rev=dea408daeef576cff8ffa61356c89a9d03d95f6b#dea408daeef576cff8ffa61356c89a9d03d95f6b" +dependencies = [ + "binrw", +] + [[package]] name = "strict-num" version = "0.1.1" @@ -1691,17 +1334,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "syn_util" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6754c4559b79657554e9d8a0d56e65e490c76d382b9c23108364ec4125dea23c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "termcolor" version = "1.4.1" @@ -1780,29 +1412,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", - "tracing-attributes", "tracing-core", ] -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - [[package]] name = "tracing-core" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] [[package]] name = "ttf-parser" @@ -1834,61 +1451,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" -[[package]] -name = "vbsp" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9267540dab0c93bb5201c40ba3b2d027e2717bf355a8f9bf25377b06a5b32f6" -dependencies = [ - "ahash", - "arrayvec", - "binrw", - "bitflags 2.4.2", - "bv", - "cgmath", - "itertools", - "lzma-rs", - "num_enum", - "static_assertions", - "thiserror", - "vbsp-derive", - "zip-lzma", -] - -[[package]] -name = "vbsp-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ade687fadf34b1b7502387fc9eb7b4032ddc9b93022d31356e9984c957abaad" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "syn_util", -] - [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "vmdl" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "892922743c4c107372331efd8f67c57282590f8c18c26b4465c4b0e1e6678664" -dependencies = [ - "arrayvec", - "bitflags 2.4.2", - "bytemuck", - "cgmath", - "itertools", - "static_assertions", - "thiserror", - "tracing", -] - [[package]] name = "walkdir" version = "2.4.0" @@ -2599,15 +2167,3 @@ dependencies = [ "quote", "syn 2.0.48", ] - -[[package]] -name = "zip-lzma" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b480cb31fccfb2786565c0e0712865fd6f1ea0ea850c50316f643c3948196e63" -dependencies = [ - "byteorder 1.5.0", - "crc32fast", - "crossbeam-utils", - "lzma", -] diff --git a/Cargo.toml b/Cargo.toml index 02d986d..950e154 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,17 +10,10 @@ bytemuck = { version = "1.13.1", features = ["derive"] } configparser = "3.0.2" ddsfile = "0.5.1" glam = "0.25.0" -lazy-regex = "3.0.2" -obj = "0.10.2" parking_lot = "0.12.1" pollster = "0.3.0" -rbx_binary = "0.7.1" -rbx_dom_weak = "2.5.0" -rbx_reflection_database = "0.2.7" -rbx_xml = "0.13.1" strafesnet_common = { git = "https://git.itzana.me/StrafesNET/common", rev = "434ca29aef7e3015c9ca1ed45de8fef42e33fdfb" } -vbsp = "0.5.0" -vmdl = "0.1.1" +strafesnet_snf = { git = "https://git.itzana.me/StrafesNET/snf", rev = "dea408daeef576cff8ffa61356c89a9d03d95f6b" } wgpu = "0.19.0" winit = "0.29.2" diff --git a/src/load_bsp.rs b/src/load_bsp.rs deleted file mode 100644 index d0cdeff..0000000 --- a/src/load_bsp.rs +++ /dev/null @@ -1,237 +0,0 @@ -use strafesnet_common::integer; - -const VALVE_SCALE:f32=1.0/16.0; -fn valve_transform(v:[f32;3])->integer::Planar64Vec3{ - integer::Planar64Vec3::try_from([v[0]*VALVE_SCALE,v[2]*VALVE_SCALE,-v[1]*VALVE_SCALE]).unwrap() -} -pub fn generate_indexed_models(input:&mut R)->Result{ - let mut s=Vec::new(); - - match input.read_to_end(&mut s){ - Ok(_)=>(), - Err(e)=>println!("load_bsp::generate_indexed_models read_to_end failed: {:?}",e), - } - - match vbsp::Bsp::read(s.as_slice()){ - Ok(bsp)=>{ - let mut spawn_point=integer::Planar64Vec3::ZERO; - - let vertices: Vec<_> = bsp - .vertices - .iter() - .map(|vertex|<[f32;3]>::from(vertex.position)) - .collect(); - - let mut name_from_texture_id=Vec::new(); - let mut texture_id_from_name=std::collections::HashMap::new(); - - let mut models=bsp.models().map(|world_model|{ - //non-deduplicated - let mut spam_pos=Vec::new(); - let mut spam_tex=Vec::new(); - let mut spam_normal=Vec::new(); - let mut spam_vertices=Vec::new(); - let groups=world_model.faces() - .filter(|face| face.is_visible())//TODO: look at this - .map(|face|{ - let face_texture=face.texture(); - let face_texture_data=face_texture.texture_data(); - let (texture_u,texture_v)=(glam::Vec3A::from_slice(&face_texture.texture_transforms_u[0..3]),glam::Vec3A::from_slice(&face_texture.texture_transforms_v[0..3])); - let texture_offset=glam::vec2(face_texture.texture_transforms_u[3],face_texture.texture_transforms_v[3]); - let texture_size=glam::vec2(face_texture_data.width as f32,face_texture_data.height as f32); - - //texture - let texture_id=if let Some(&texture_id)=texture_id_from_name.get(face_texture_data.name()){ - texture_id - }else{ - let texture_id=name_from_texture_id.len() as u32; - texture_id_from_name.insert(face_texture_data.name().to_string(),texture_id); - name_from_texture_id.push(face_texture_data.name().to_string()); - texture_id - }; - - //normal - let normal=face.normal(); - let normal_idx=spam_normal.len() as u32; - spam_normal.push(valve_transform(<[f32;3]>::from(normal))); - let mut vertices:Vec=face.vertex_indexes().map(|vertex_index|{ - let pos=glam::Vec3A::from_array(vertices[vertex_index as usize]); - let pos_idx=spam_pos.len(); - spam_pos.push(valve_transform(vertices[vertex_index as usize])); - - //calculate texture coordinates - let tex=(glam::vec2(pos.dot(texture_u),pos.dot(texture_v))+texture_offset)/texture_size; - let tex_idx=spam_tex.len() as u32; - spam_tex.push(tex); - - let i=spam_vertices.len() as u32; - spam_vertices.push(crate::model::IndexedVertex{ - pos: pos_idx as u32, - tex: tex_idx as u32, - normal: normal_idx, - color: 0, - }); - i - }).collect(); - vertices.reverse(); - crate::model::IndexedGroup{ - texture:Some(texture_id), - polys:vec![crate::model::IndexedPolygon{vertices}], - } - }).collect(); - crate::model::IndexedModel{ - unique_pos:spam_pos, - unique_tex:spam_tex, - unique_normal:spam_normal, - unique_color:vec![glam::Vec4::ONE], - unique_vertices:spam_vertices, - groups, - instances:vec![crate::model::ModelInstance{ - attributes:crate::model::CollisionAttributes::Decoration, - transform:integer::Planar64Affine3::new( - integer::Planar64Mat3::default(), - valve_transform(<[f32;3]>::from(world_model.origin)) - ), - ..Default::default() - }], - } - }).collect(); - - //dedupe prop models - let mut model_dedupe=std::collections::HashSet::new(); - for prop in bsp.static_props(){ - model_dedupe.insert(prop.model()); - } - - //generate unique meshes - let mut model_map=std::collections::HashMap::with_capacity(model_dedupe.len()); - let mut prop_models=Vec::new(); - for model_name in model_dedupe{ - let model_name_lower=model_name.to_lowercase(); - //.mdl, .vvd, .dx90.vtx - let mut path=std::path::PathBuf::from(model_name_lower.as_str()); - let file_name=std::path::PathBuf::from(path.file_stem().unwrap()); - path.pop(); - path.push(file_name); - let mut vvd_path=path.clone(); - let mut vtx_path=path.clone(); - vvd_path.set_extension("vvd"); - vtx_path.set_extension("dx90.vtx"); - match (bsp.pack.get(model_name_lower.as_str()),bsp.pack.get(vvd_path.as_os_str().to_str().unwrap()),bsp.pack.get(vtx_path.as_os_str().to_str().unwrap())){ - (Ok(Some(mdl_file)),Ok(Some(vvd_file)),Ok(Some(vtx_file)))=>{ - match (vmdl::mdl::Mdl::read(mdl_file.as_ref()),vmdl::vvd::Vvd::read(vvd_file.as_ref()),vmdl::vtx::Vtx::read(vtx_file.as_ref())){ - (Ok(mdl),Ok(vvd),Ok(vtx))=>{ - let model=vmdl::Model::from_parts(mdl,vtx,vvd); - let texture_paths=model.texture_directories(); - if texture_paths.len()!=1{ - println!("WARNING: multiple texture paths"); - } - let skin=model.skin_tables().nth(0).unwrap(); - - let mut spam_pos=Vec::with_capacity(model.vertices().len()); - let mut spam_normal=Vec::with_capacity(model.vertices().len()); - let mut spam_tex=Vec::with_capacity(model.vertices().len()); - let mut spam_vertices=Vec::with_capacity(model.vertices().len()); - for (i,vertex) in model.vertices().iter().enumerate(){ - spam_pos.push(valve_transform(<[f32;3]>::from(vertex.position))); - spam_normal.push(valve_transform(<[f32;3]>::from(vertex.normal))); - spam_tex.push(glam::Vec2::from_array(vertex.texture_coordinates)); - spam_vertices.push(crate::model::IndexedVertex{ - pos:i as u32, - tex:i as u32, - normal:i as u32, - color:0, - }); - } - - let model_id=prop_models.len(); - model_map.insert(model_name,model_id); - prop_models.push(crate::model::IndexedModel{ - unique_pos:spam_pos, - unique_normal:spam_normal, - unique_tex:spam_tex, - unique_color:vec![glam::Vec4::ONE], - unique_vertices:spam_vertices, - groups:model.meshes().map(|mesh|{ - let texture=if let (Some(texture_path),Some(texture_name))=(texture_paths.get(0),skin.texture(mesh.material_index())){ - let mut path=std::path::PathBuf::from(texture_path.as_str()); - path.push(texture_name); - let texture_location=path.as_os_str().to_str().unwrap(); - let texture_id=if let Some(&texture_id)=texture_id_from_name.get(texture_location){ - texture_id - }else{ - println!("texture! {}",texture_location); - let texture_id=name_from_texture_id.len() as u32; - texture_id_from_name.insert(texture_location.to_string(),texture_id); - name_from_texture_id.push(texture_location.to_string()); - texture_id - }; - Some(texture_id) - }else{ - None - }; - - crate::model::IndexedGroup{ - texture, - polys:{ - //looking at the code, it would seem that the strips are pre-deindexed into triangle lists when calling this function - mesh.vertex_strip_indices().map(|strip|{ - strip.collect::>().chunks(3).map(|tri|{ - crate::model::IndexedPolygon{vertices:vec![tri[0] as u32,tri[1] as u32,tri[2] as u32]} - }).collect::>() - }).flatten().collect() - }, - } - }).collect(), - instances:Vec::new(), - }); - }, - _=>println!("model_name={} error",model_name), - } - }, - _=>println!("no model name={}",model_name), - } - } - - //generate model instances - for prop in bsp.static_props(){ - let placement=prop.as_prop_placement(); - if let Some(&model_index)=model_map.get(placement.model){ - prop_models[model_index].instances.push(crate::model::ModelInstance{ - transform:integer::Planar64Affine3::new( - integer::Planar64Mat3::try_from( - glam::Mat3A::from_diagonal(glam::Vec3::splat(placement.scale)) - //TODO: figure this out - *glam::Mat3A::from_quat(glam::Quat::from_xyzw( - placement.rotation.v.x,//b - placement.rotation.v.y,//c - placement.rotation.v.z,//d - placement.rotation.s,//a - )) - ).unwrap(), - valve_transform(<[f32;3]>::from(placement.origin)), - ), - attributes:crate::model::CollisionAttributes::Decoration, - ..Default::default() - }); - }else{ - //println!("model not found {}",placement.model); - } - } - - //actually add the prop models - prop_models.append(&mut models); - - Ok(crate::model::IndexedModelInstances{ - textures:name_from_texture_id, - models:prop_models, - spawn_point, - modes:Vec::new(), - }) - }, - Err(e)=>{ - println!("rotten {:?}",e); - Err(e) - }, - } -} diff --git a/src/load_roblox.rs b/src/load_roblox.rs deleted file mode 100644 index 211208d..0000000 --- a/src/load_roblox.rs +++ /dev/null @@ -1,523 +0,0 @@ -use crate::primitives; -use strafesnet_common::integer::{Planar64,Planar64Vec3,Planar64Mat3,Planar64Affine3}; - -fn class_is_a(class: &str, superclass: &str) -> bool { - if class==superclass { - return true - } - let class_descriptor=rbx_reflection_database::get().classes.get(class); - if let Some(descriptor) = &class_descriptor { - if let Some(class_super) = &descriptor.superclass { - return class_is_a(&class_super, superclass) - } - } - return false -} -fn recursive_collect_superclass(objects: &mut std::vec::Vec,dom: &rbx_dom_weak::WeakDom, instance: &rbx_dom_weak::Instance, superclass: &str){ - let mut stack=vec![instance]; - while let Some(item)=stack.pop(){ - for &referent in item.children(){ - if let Some(c)=dom.get_by_ref(referent){ - if class_is_a(c.class.as_str(),superclass){ - objects.push(c.referent());//copy ref - } - stack.push(c); - } - } - } -} -fn planar64_affine3_from_roblox(cf:&rbx_dom_weak::types::CFrame,size:&rbx_dom_weak::types::Vector3)->Planar64Affine3{ - Planar64Affine3::new( - Planar64Mat3::from_cols( - Planar64Vec3::try_from([cf.orientation.x.x,cf.orientation.y.x,cf.orientation.z.x]).unwrap() - *Planar64::try_from(size.x/2.0).unwrap(), - Planar64Vec3::try_from([cf.orientation.x.y,cf.orientation.y.y,cf.orientation.z.y]).unwrap() - *Planar64::try_from(size.y/2.0).unwrap(), - Planar64Vec3::try_from([cf.orientation.x.z,cf.orientation.y.z,cf.orientation.z.z]).unwrap() - *Planar64::try_from(size.z/2.0).unwrap(), - ), - Planar64Vec3::try_from([cf.position.x,cf.position.y,cf.position.z]).unwrap() - ) -} -fn get_attributes(name:&str,can_collide:bool,velocity:Planar64Vec3,force_intersecting:bool)->crate::model::CollisionAttributes{ - let mut general=crate::model::GameMechanicAttributes::default(); - let mut intersecting=crate::model::IntersectingAttributes::default(); - let mut contacting=crate::model::ContactingAttributes::default(); - let mut force_can_collide=can_collide; - match name{ - "Water"=>{ - force_can_collide=false; - //TODO: read stupid CustomPhysicalProperties - intersecting.water=Some(crate::model::IntersectingWater{density:Planar64::ONE,viscosity:Planar64::ONE/10,velocity}); - }, - "Accelerator"=>{ - //although the new game supports collidable accelerators, this is a roblox compatability map loader - force_can_collide=false; - general.accelerator=Some(crate::model::GameMechanicAccelerator{acceleration:velocity}); - }, - // "UnorderedCheckpoint"=>general.teleport_behaviour=Some(crate::model::TeleportBehaviour::StageElement(crate::model::GameMechanicStageElement{ - // mode_id:0, - // stage_id:0, - // force:false, - // behaviour:crate::model::StageElementBehaviour::Unordered - // })), - "SetVelocity"=>general.trajectory=Some(crate::model::GameMechanicSetTrajectory::Velocity(velocity)), - "MapFinish"=>{force_can_collide=false;general.zone=Some(crate::model::GameMechanicZone{mode_id:0,behaviour:crate::model::ZoneBehaviour::Finish})}, - "MapAnticheat"=>{force_can_collide=false;general.zone=Some(crate::model::GameMechanicZone{mode_id:0,behaviour:crate::model::ZoneBehaviour::Anitcheat})}, - "Platform"=>general.teleport_behaviour=Some(crate::model::TeleportBehaviour::StageElement(crate::model::GameMechanicStageElement{ - mode_id:0, - stage_id:0, - force:false, - behaviour:crate::model::StageElementBehaviour::Platform, - })), - other=>{ - if let Some(captures)=lazy_regex::regex!(r"^(Force)?(Spawn|SpawnAt|Trigger|Teleport|Platform)(\d+)$") - .captures(other){ - general.teleport_behaviour=Some(crate::model::TeleportBehaviour::StageElement(crate::model::GameMechanicStageElement{ - mode_id:0, - stage_id:captures[3].parse::().unwrap(), - force:match captures.get(1){ - Some(m)=>m.as_str()=="Force", - None=>false, - }, - behaviour:match &captures[2]{ - "Spawn"|"SpawnAt"=>crate::model::StageElementBehaviour::SpawnAt, - //cancollide false so you don't hit the side - //NOT a decoration - "Trigger"=>{force_can_collide=false;crate::model::StageElementBehaviour::Trigger}, - "Teleport"=>{force_can_collide=false;crate::model::StageElementBehaviour::Teleport}, - "Platform"=>crate::model::StageElementBehaviour::Platform, - _=>panic!("regex1[2] messed up bad"), - } - })); - }else if let Some(captures)=lazy_regex::regex!(r"^(Force)?(Jump)(\d+)$") - .captures(other){ - general.teleport_behaviour=Some(crate::model::TeleportBehaviour::StageElement(crate::model::GameMechanicStageElement{ - mode_id:0, - stage_id:0, - force:match captures.get(1){ - Some(m)=>m.as_str()=="Force", - None=>false, - }, - behaviour:match &captures[2]{ - "Jump"=>crate::model::StageElementBehaviour::JumpLimit(captures[3].parse::().unwrap()), - _=>panic!("regex4[1] messed up bad"), - } - })); - }else if let Some(captures)=lazy_regex::regex!(r"^Bonus(Finish|Anticheat)(\d+)$") - .captures(other){ - force_can_collide=false; - match &captures[1]{ - "Finish"=>general.zone=Some(crate::model::GameMechanicZone{mode_id:captures[2].parse::().unwrap(),behaviour:crate::model::ZoneBehaviour::Finish}), - "Anticheat"=>general.zone=Some(crate::model::GameMechanicZone{mode_id:captures[2].parse::().unwrap(),behaviour:crate::model::ZoneBehaviour::Anitcheat}), - _=>panic!("regex2[1] messed up bad"), - } - }else if let Some(captures)=lazy_regex::regex!(r"^(WormholeIn)(\d+)$") - .captures(other){ - force_can_collide=false; - match &captures[1]{ - "WormholeIn"=>general.teleport_behaviour=Some(crate::model::TeleportBehaviour::Wormhole(crate::model::GameMechanicWormhole{destination_model_id:captures[2].parse::().unwrap()})), - _=>panic!("regex3[1] messed up bad"), - } - } - // else if let Some(captures)=lazy_regex::regex!(r"^(OrderedCheckpoint)(\d+)$") - // .captures(other){ - // match &captures[1]{ - // "OrderedCheckpoint"=>general.checkpoint=Some(crate::model::GameMechanicCheckpoint::Ordered{mode_id:0,checkpoint_id:captures[2].parse::().unwrap()}), - // _=>panic!("regex3[1] messed up bad"), - // } - // } - } - } - //need some way to skip this - if velocity!=Planar64Vec3::ZERO{ - general.booster=Some(crate::model::GameMechanicBooster::Velocity(velocity)); - } - match force_can_collide{ - true=>{ - match name{ - "Bounce"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Elastic(u32::MAX)), - "Surf"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Surf), - "Ladder"=>contacting.contact_behaviour=Some(crate::model::ContactingBehaviour::Ladder(crate::model::ContactingLadder{sticky:true})), - _=>(), - } - crate::model::CollisionAttributes::Contact{contacting,general} - }, - false=>if force_intersecting - ||general.any() - ||intersecting.any() - { - crate::model::CollisionAttributes::Intersect{intersecting,general} - }else{ - crate::model::CollisionAttributes::Decoration - }, - } -} - -struct RobloxAssetId(u64); -struct RobloxAssetIdParseErr; -impl std::str::FromStr for RobloxAssetId { - type Err=RobloxAssetIdParseErr; - fn from_str(s: &str) -> Result{ - let regman=lazy_regex::regex!(r"(\d+)$"); - if let Some(captures) = regman.captures(s) { - if captures.len()==2{//captures[0] is all captures concatenated, and then each individual capture - if let Ok(id) = captures[0].parse::() { - return Ok(Self(id)); - } - } - } - Err(RobloxAssetIdParseErr) - } -} -#[derive(Clone,Copy,PartialEq)] -struct RobloxTextureTransform{ - offset_u:f32, - offset_v:f32, - scale_u:f32, - scale_v:f32, -} -impl std::cmp::Eq for RobloxTextureTransform{}//???? -impl std::default::Default for RobloxTextureTransform{ - fn default() -> Self { - Self{offset_u:0.0,offset_v:0.0,scale_u:1.0,scale_v:1.0} - } -} -impl std::hash::Hash for RobloxTextureTransform { - fn hash(&self, state: &mut H) { - self.offset_u.to_ne_bytes().hash(state); - self.offset_v.to_ne_bytes().hash(state); - self.scale_u.to_ne_bytes().hash(state); - self.scale_v.to_ne_bytes().hash(state); - } -} -#[derive(Clone,PartialEq)] -struct RobloxFaceTextureDescription{ - texture:u32, - color:glam::Vec4, - transform:RobloxTextureTransform, -} -impl std::cmp::Eq for RobloxFaceTextureDescription{}//???? -impl std::hash::Hash for RobloxFaceTextureDescription { - fn hash(&self, state: &mut H) { - self.texture.hash(state); - self.transform.hash(state); - for &el in self.color.as_ref().iter() { - el.to_ne_bytes().hash(state); - } - } -} -impl RobloxFaceTextureDescription{ - fn to_face_description(&self)->primitives::FaceDescription{ - primitives::FaceDescription{ - texture:Some(self.texture), - transform:glam::Affine2::from_translation( - glam::vec2(self.transform.offset_u,self.transform.offset_v) - ) - *glam::Affine2::from_scale( - glam::vec2(self.transform.scale_u,self.transform.scale_v) - ), - color:self.color, - } - } -} -type RobloxPartDescription=[Option;6]; -type RobloxWedgeDescription=[Option;5]; -type RobloxCornerWedgeDescription=[Option;5]; -#[derive(Clone,Eq,Hash,PartialEq)] -enum RobloxBasePartDescription{ - Sphere(RobloxPartDescription), - Part(RobloxPartDescription), - Cylinder(RobloxPartDescription), - Wedge(RobloxWedgeDescription), - CornerWedge(RobloxCornerWedgeDescription), -} -pub fn generate_indexed_models(dom:rbx_dom_weak::WeakDom) -> crate::model::IndexedModelInstances{ - //IndexedModelInstances includes textures - let mut spawn_point=Planar64Vec3::ZERO; - - let mut indexed_models=Vec::new(); - let mut model_id_from_description=std::collections::HashMap::::new(); - - let mut texture_id_from_asset_id=std::collections::HashMap::::new(); - let mut asset_id_from_texture_id=Vec::new(); - - let mut object_refs=Vec::new(); - let mut temp_objects=Vec::new(); - recursive_collect_superclass(&mut object_refs, &dom, dom.root(),"BasePart"); - for object_ref in object_refs { - if let Some(object)=dom.get_by_ref(object_ref){ - if let ( - Some(rbx_dom_weak::types::Variant::CFrame(cf)), - Some(rbx_dom_weak::types::Variant::Vector3(size)), - Some(rbx_dom_weak::types::Variant::Vector3(velocity)), - Some(rbx_dom_weak::types::Variant::Float32(transparency)), - Some(rbx_dom_weak::types::Variant::Color3uint8(color3)), - Some(rbx_dom_weak::types::Variant::Bool(can_collide)), - ) = ( - object.properties.get("CFrame"), - object.properties.get("Size"), - object.properties.get("Velocity"), - object.properties.get("Transparency"), - object.properties.get("Color"), - object.properties.get("CanCollide"), - ) - { - let model_transform=planar64_affine3_from_roblox(cf,size); - - if model_transform.matrix3.determinant()==Planar64::ZERO{ - let mut parent_ref=object.parent(); - let mut full_path=object.name.clone(); - while let Some(parent)=dom.get_by_ref(parent_ref){ - full_path=format!("{}.{}",parent.name,full_path); - parent_ref=parent.parent(); - } - println!("Zero determinant CFrame at location {}",full_path); - println!("matrix3:{}",model_transform.matrix3); - continue; - } - - //push TempIndexedAttributes - let mut force_intersecting=false; - let mut temp_indexing_attributes=Vec::new(); - if let Some(attr)=match &object.name[..]{ - "MapStart"=>{ - spawn_point=model_transform.transform_point3(Planar64Vec3::ZERO)+Planar64Vec3::Y*5/2; - Some(crate::model::TempIndexedAttributes::Start(crate::model::TempAttrStart{mode_id:0})) - }, - other=>{ - let regman=lazy_regex::regex!(r"^(BonusStart|Spawn|ForceSpawn|WormholeOut)(\d+)$"); - if let Some(captures) = regman.captures(other) { - match &captures[1]{ - "BonusStart"=>Some(crate::model::TempIndexedAttributes::Start(crate::model::TempAttrStart{mode_id:captures[2].parse::().unwrap()})), - "Spawn"|"ForceSpawn"=>Some(crate::model::TempIndexedAttributes::Spawn(crate::model::TempAttrSpawn{mode_id:0,stage_id:captures[2].parse::().unwrap()})), - "WormholeOut"=>Some(crate::model::TempIndexedAttributes::Wormhole(crate::model::TempAttrWormhole{wormhole_id:captures[2].parse::().unwrap()})), - _=>None, - } - }else{ - None - } - } - }{ - force_intersecting=true; - temp_indexing_attributes.push(attr); - } - - //TODO: also detect "CylinderMesh" etc here - let shape=match &object.class[..]{ - "Part"=>{ - if let Some(rbx_dom_weak::types::Variant::Enum(shape))=object.properties.get("Shape"){ - match shape.to_u32(){ - 0=>primitives::Primitives::Sphere, - 1=>primitives::Primitives::Cube, - 2=>primitives::Primitives::Cylinder, - 3=>primitives::Primitives::Wedge, - 4=>primitives::Primitives::CornerWedge, - _=>panic!("Funky roblox PartType={};",shape.to_u32()), - } - }else{ - panic!("Part has no Shape!"); - } - }, - "TrussPart"=>primitives::Primitives::Cube, - "WedgePart"=>primitives::Primitives::Wedge, - "CornerWedgePart"=>primitives::Primitives::CornerWedge, - _=>{ - println!("Unsupported BasePart ClassName={}; defaulting to cube",object.class); - primitives::Primitives::Cube - } - }; - - //use the biggest one and cut it down later... - let mut part_texture_description:RobloxPartDescription=[None,None,None,None,None,None]; - temp_objects.clear(); - recursive_collect_superclass(&mut temp_objects, &dom, object,"Decal"); - for &decal_ref in &temp_objects{ - if let Some(decal)=dom.get_by_ref(decal_ref){ - if let ( - Some(rbx_dom_weak::types::Variant::Content(content)), - Some(rbx_dom_weak::types::Variant::Enum(normalid)), - Some(rbx_dom_weak::types::Variant::Color3(decal_color3)), - Some(rbx_dom_weak::types::Variant::Float32(decal_transparency)), - ) = ( - decal.properties.get("Texture"), - decal.properties.get("Face"), - decal.properties.get("Color3"), - decal.properties.get("Transparency"), - ) { - if let Ok(asset_id)=content.clone().into_string().parse::(){ - let texture_id=if let Some(&texture_id)=texture_id_from_asset_id.get(&asset_id.0){ - texture_id - }else{ - let texture_id=asset_id_from_texture_id.len() as u32; - texture_id_from_asset_id.insert(asset_id.0,texture_id); - asset_id_from_texture_id.push(asset_id.0); - texture_id - }; - let normal_id=normalid.to_u32(); - if normal_id<6{ - let (roblox_texture_color,roblox_texture_transform)=if decal.class=="Texture"{ - //generate tranform - if let ( - Some(rbx_dom_weak::types::Variant::Float32(ox)), - Some(rbx_dom_weak::types::Variant::Float32(oy)), - Some(rbx_dom_weak::types::Variant::Float32(sx)), - Some(rbx_dom_weak::types::Variant::Float32(sy)), - ) = ( - decal.properties.get("OffsetStudsU"), - decal.properties.get("OffsetStudsV"), - decal.properties.get("StudsPerTileU"), - decal.properties.get("StudsPerTileV"), - ) - { - let (size_u,size_v)=match normal_id{ - 0=>(size.z,size.y),//right - 1=>(size.x,size.z),//top - 2=>(size.x,size.y),//back - 3=>(size.z,size.y),//left - 4=>(size.x,size.z),//bottom - 5=>(size.x,size.y),//front - _=>panic!("unreachable"), - }; - ( - glam::vec4(decal_color3.r,decal_color3.g,decal_color3.b,1.0-*decal_transparency), - RobloxTextureTransform{ - offset_u:*ox/(*sx),offset_v:*oy/(*sy), - scale_u:size_u/(*sx),scale_v:size_v/(*sy), - } - ) - }else{ - (glam::Vec4::ONE,RobloxTextureTransform::default()) - } - }else{ - (glam::Vec4::ONE,RobloxTextureTransform::default()) - }; - part_texture_description[normal_id as usize]=Some(RobloxFaceTextureDescription{ - texture:texture_id, - color:roblox_texture_color, - transform:roblox_texture_transform, - }); - }else{ - println!("NormalId={} unsupported for shape={:?}",normal_id,shape); - } - } - } - } - } - //obscure rust syntax "slice pattern" - let [ - f0,//Cube::Right - f1,//Cube::Top - f2,//Cube::Back - f3,//Cube::Left - f4,//Cube::Bottom - f5,//Cube::Front - ]=part_texture_description; - let basepart_texture_description=match shape{ - primitives::Primitives::Sphere=>RobloxBasePartDescription::Sphere([f0,f1,f2,f3,f4,f5]), - primitives::Primitives::Cube=>RobloxBasePartDescription::Part([f0,f1,f2,f3,f4,f5]), - primitives::Primitives::Cylinder=>RobloxBasePartDescription::Cylinder([f0,f1,f2,f3,f4,f5]), - //use front face texture first and use top face texture as a fallback - primitives::Primitives::Wedge=>RobloxBasePartDescription::Wedge([ - f0,//Cube::Right->Wedge::Right - if f5.is_some(){f5}else{f1},//Cube::Front|Cube::Top->Wedge::TopFront - f2,//Cube::Back->Wedge::Back - f3,//Cube::Left->Wedge::Left - f4,//Cube::Bottom->Wedge::Bottom - ]), - //TODO: fix Left+Back texture coordinates to match roblox when not overwridden by Top - primitives::Primitives::CornerWedge=>RobloxBasePartDescription::CornerWedge([ - f0,//Cube::Right->CornerWedge::Right - if f2.is_some(){f2}else{f1.clone()},//Cube::Back|Cube::Top->CornerWedge::TopBack - if f3.is_some(){f3}else{f1},//Cube::Left|Cube::Top->CornerWedge::TopLeft - f4,//Cube::Bottom->CornerWedge::Bottom - f5,//Cube::Front->CornerWedge::Front - ]), - }; - //make new model if unit cube has not been created before - let model_id=if let Some(&model_id)=model_id_from_description.get(&basepart_texture_description){ - //push to existing texture model - model_id - }else{ - let model_id=indexed_models.len(); - model_id_from_description.insert(basepart_texture_description.clone(),model_id);//borrow checker going crazy - indexed_models.push(match basepart_texture_description{ - RobloxBasePartDescription::Sphere(part_texture_description) - |RobloxBasePartDescription::Cylinder(part_texture_description) - |RobloxBasePartDescription::Part(part_texture_description)=>{ - let mut cube_face_description=primitives::CubeFaceDescription::default(); - for (face_id,roblox_face_description) in part_texture_description.iter().enumerate(){ - cube_face_description.insert( - match face_id{ - 0=>primitives::CubeFace::Right, - 1=>primitives::CubeFace::Top, - 2=>primitives::CubeFace::Back, - 3=>primitives::CubeFace::Left, - 4=>primitives::CubeFace::Bottom, - 5=>primitives::CubeFace::Front, - _=>panic!("unreachable"), - }, - match roblox_face_description{ - Some(roblox_texture_transform)=>roblox_texture_transform.to_face_description(), - None=>primitives::FaceDescription::default(), - }); - } - primitives::generate_partial_unit_cube(cube_face_description) - }, - RobloxBasePartDescription::Wedge(wedge_texture_description)=>{ - let mut wedge_face_description=primitives::WedgeFaceDescription::default(); - for (face_id,roblox_face_description) in wedge_texture_description.iter().enumerate(){ - wedge_face_description.insert( - match face_id{ - 0=>primitives::WedgeFace::Right, - 1=>primitives::WedgeFace::TopFront, - 2=>primitives::WedgeFace::Back, - 3=>primitives::WedgeFace::Left, - 4=>primitives::WedgeFace::Bottom, - _=>panic!("unreachable"), - }, - match roblox_face_description{ - Some(roblox_texture_transform)=>roblox_texture_transform.to_face_description(), - None=>primitives::FaceDescription::default(), - }); - } - primitives::generate_partial_unit_wedge(wedge_face_description) - }, - RobloxBasePartDescription::CornerWedge(cornerwedge_texture_description)=>{ - let mut cornerwedge_face_description=primitives::CornerWedgeFaceDescription::default(); - for (face_id,roblox_face_description) in cornerwedge_texture_description.iter().enumerate(){ - cornerwedge_face_description.insert( - match face_id{ - 0=>primitives::CornerWedgeFace::Right, - 1=>primitives::CornerWedgeFace::TopBack, - 2=>primitives::CornerWedgeFace::TopLeft, - 3=>primitives::CornerWedgeFace::Bottom, - 4=>primitives::CornerWedgeFace::Front, - _=>panic!("unreachable"), - }, - match roblox_face_description{ - Some(roblox_texture_transform)=>roblox_texture_transform.to_face_description(), - None=>primitives::FaceDescription::default(), - }); - } - primitives::generate_partial_unit_cornerwedge(cornerwedge_face_description) - }, - }); - model_id - }; - indexed_models[model_id].instances.push(crate::model::ModelInstance { - transform:model_transform, - color:glam::vec4(color3.r as f32/255f32, color3.g as f32/255f32, color3.b as f32/255f32, 1.0-*transparency), - attributes:get_attributes(&object.name,*can_collide,Planar64Vec3::try_from([velocity.x,velocity.y,velocity.z]).unwrap(),force_intersecting), - temp_indexing:temp_indexing_attributes, - }); - } - } - } - crate::model::IndexedModelInstances{ - textures:asset_id_from_texture_id.iter().map(|t|t.to_string()).collect(), - models:indexed_models, - spawn_point, - modes:Vec::new(), - } -} diff --git a/src/main.rs b/src/main.rs index de83db1..6ffc40a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,9 +6,6 @@ mod worker; mod physics; mod graphics; mod settings; -mod primitives; -mod load_bsp; -mod load_roblox; mod face_crawler; mod compat_worker; mod model_physics; diff --git a/src/primitives.rs b/src/primitives.rs deleted file mode 100644 index 641a133..0000000 --- a/src/primitives.rs +++ /dev/null @@ -1,493 +0,0 @@ -use crate::model::{Color4,TextureCoordinate,IndexedModel,IndexedPolygon,IndexedGroup,IndexedVertex}; -use strafesnet_common::integer::Planar64Vec3; - -#[derive(Debug)] -pub enum Primitives{ - Sphere, - Cube, - Cylinder, - Wedge, - CornerWedge, -} -#[derive(Hash,PartialEq,Eq)] -pub enum CubeFace{ - Right, - Top, - Back, - Left, - Bottom, - Front, -} -const CUBE_DEFAULT_TEXTURE_COORDS:[TextureCoordinate;4]=[ - TextureCoordinate::new(0.0,0.0), - TextureCoordinate::new(1.0,0.0), - TextureCoordinate::new(1.0,1.0), - TextureCoordinate::new(0.0,1.0), -]; -const CUBE_DEFAULT_VERTICES:[Planar64Vec3;8]=[ - Planar64Vec3::int(-1,-1, 1),//0 left bottom back - Planar64Vec3::int( 1,-1, 1),//1 right bottom back - Planar64Vec3::int( 1, 1, 1),//2 right top back - Planar64Vec3::int(-1, 1, 1),//3 left top back - Planar64Vec3::int(-1, 1,-1),//4 left top front - Planar64Vec3::int( 1, 1,-1),//5 right top front - Planar64Vec3::int( 1,-1,-1),//6 right bottom front - Planar64Vec3::int(-1,-1,-1),//7 left bottom front -]; -const CUBE_DEFAULT_NORMALS:[Planar64Vec3;6]=[ - Planar64Vec3::int( 1, 0, 0),//CubeFace::Right - Planar64Vec3::int( 0, 1, 0),//CubeFace::Top - Planar64Vec3::int( 0, 0, 1),//CubeFace::Back - Planar64Vec3::int(-1, 0, 0),//CubeFace::Left - Planar64Vec3::int( 0,-1, 0),//CubeFace::Bottom - Planar64Vec3::int( 0, 0,-1),//CubeFace::Front -]; -const CUBE_DEFAULT_POLYS:[[[u32;3];4];6]=[ - // right (1, 0, 0) - [ - [6,2,0],//[vertex,tex,norm] - [5,1,0], - [2,0,0], - [1,3,0], - ], - // top (0, 1, 0) - [ - [5,3,1], - [4,2,1], - [3,1,1], - [2,0,1], - ], - // back (0, 0, 1) - [ - [0,3,2], - [1,2,2], - [2,1,2], - [3,0,2], - ], - // left (-1, 0, 0) - [ - [0,2,3], - [3,1,3], - [4,0,3], - [7,3,3], - ], - // bottom (0,-1, 0) - [ - [1,1,4], - [0,0,4], - [7,3,4], - [6,2,4], - ], - // front (0, 0,-1) - [ - [4,1,5], - [5,0,5], - [6,3,5], - [7,2,5], - ], -]; - -#[derive(Hash,PartialEq,Eq)] -pub enum WedgeFace{ - Right, - TopFront, - Back, - Left, - Bottom, -} -const WEDGE_DEFAULT_NORMALS:[Planar64Vec3;5]=[ - Planar64Vec3::int( 1, 0, 0),//Wedge::Right - Planar64Vec3::int( 0, 1,-1),//Wedge::TopFront - Planar64Vec3::int( 0, 0, 1),//Wedge::Back - Planar64Vec3::int(-1, 0, 0),//Wedge::Left - Planar64Vec3::int( 0,-1, 0),//Wedge::Bottom -]; -/* -local cornerWedgeVerticies = { - Vector3.new(-1/2,-1/2,-1/2),7 - Vector3.new(-1/2,-1/2, 1/2),0 - Vector3.new( 1/2,-1/2,-1/2),6 - Vector3.new( 1/2,-1/2, 1/2),1 - Vector3.new( 1/2, 1/2,-1/2),5 -} -*/ -#[derive(Hash,PartialEq,Eq)] -pub enum CornerWedgeFace{ - Right, - TopBack, - TopLeft, - Bottom, - Front, -} -const CORNERWEDGE_DEFAULT_NORMALS:[Planar64Vec3;5]=[ - Planar64Vec3::int( 1, 0, 0),//CornerWedge::Right - Planar64Vec3::int( 0, 1, 1),//CornerWedge::BackTop - Planar64Vec3::int(-1, 1, 0),//CornerWedge::LeftTop - Planar64Vec3::int( 0,-1, 0),//CornerWedge::Bottom - Planar64Vec3::int( 0, 0,-1),//CornerWedge::Front -]; -pub fn unit_sphere()->crate::model::IndexedModel{ - unit_cube() -} -#[derive(Default)] -pub struct CubeFaceDescription([Option;6]); -impl CubeFaceDescription{ - pub fn insert(&mut self,index:CubeFace,value:FaceDescription){ - self.0[index as usize]=Some(value); - } - pub fn pairs(self)->std::iter::FilterMap,6>>,impl FnMut((usize,Option))->Option<(usize,FaceDescription)>>{ - self.0.into_iter().enumerate().filter_map(|v|v.1.map(|u|(v.0,u))) - } -} -pub fn unit_cube()->crate::model::IndexedModel{ - let mut t=CubeFaceDescription::default(); - t.insert(CubeFace::Right,FaceDescription::default()); - t.insert(CubeFace::Top,FaceDescription::default()); - t.insert(CubeFace::Back,FaceDescription::default()); - t.insert(CubeFace::Left,FaceDescription::default()); - t.insert(CubeFace::Bottom,FaceDescription::default()); - t.insert(CubeFace::Front,FaceDescription::default()); - generate_partial_unit_cube(t) -} -pub fn unit_cylinder()->crate::model::IndexedModel{ - unit_cube() -} -#[derive(Default)] -pub struct WedgeFaceDescription([Option;5]); -impl WedgeFaceDescription{ - pub fn insert(&mut self,index:WedgeFace,value:FaceDescription){ - self.0[index as usize]=Some(value); - } - pub fn pairs(self)->std::iter::FilterMap,5>>,impl FnMut((usize,Option))->Option<(usize,FaceDescription)>>{ - self.0.into_iter().enumerate().filter_map(|v|v.1.map(|u|(v.0,u))) - } -} -pub fn unit_wedge()->crate::model::IndexedModel{ - let mut t=WedgeFaceDescription::default(); - t.insert(WedgeFace::Right,FaceDescription::default()); - t.insert(WedgeFace::TopFront,FaceDescription::default()); - t.insert(WedgeFace::Back,FaceDescription::default()); - t.insert(WedgeFace::Left,FaceDescription::default()); - t.insert(WedgeFace::Bottom,FaceDescription::default()); - generate_partial_unit_wedge(t) -} -#[derive(Default)] -pub struct CornerWedgeFaceDescription([Option;5]); -impl CornerWedgeFaceDescription{ - pub fn insert(&mut self,index:CornerWedgeFace,value:FaceDescription){ - self.0[index as usize]=Some(value); - } - pub fn pairs(self)->std::iter::FilterMap,5>>,impl FnMut((usize,Option))->Option<(usize,FaceDescription)>>{ - self.0.into_iter().enumerate().filter_map(|v|v.1.map(|u|(v.0,u))) - } -} -pub fn unit_cornerwedge()->crate::model::IndexedModel{ - let mut t=CornerWedgeFaceDescription::default(); - t.insert(CornerWedgeFace::Right,FaceDescription::default()); - t.insert(CornerWedgeFace::TopBack,FaceDescription::default()); - t.insert(CornerWedgeFace::TopLeft,FaceDescription::default()); - t.insert(CornerWedgeFace::Bottom,FaceDescription::default()); - t.insert(CornerWedgeFace::Front,FaceDescription::default()); - generate_partial_unit_cornerwedge(t) -} - -#[derive(Clone)] -pub struct FaceDescription{ - pub texture:Option, - pub transform:glam::Affine2, - pub color:Color4, -} -impl std::default::Default for FaceDescription{ - fn default()->Self { - Self{ - texture:None, - transform:glam::Affine2::IDENTITY, - color:Color4::new(1.0,1.0,1.0,0.0),//zero alpha to hide the default texture - } - } -} -//TODO: it's probably better to use a shared vertex buffer between all primitives and use indexed rendering instead of generating a unique vertex buffer for each primitive. -//implementation: put all roblox primitives into one model.groups <- this won't work but I forget why -pub fn generate_partial_unit_cube(face_descriptions:CubeFaceDescription)->crate::model::IndexedModel{ - let mut generated_pos=Vec::new(); - let mut generated_tex=Vec::new(); - let mut generated_normal=Vec::new(); - let mut generated_color=Vec::new(); - let mut generated_vertices=Vec::new(); - let mut groups=Vec::new(); - let mut transforms=Vec::new(); - //note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices. - for (face_id,face_description) in face_descriptions.pairs(){ - //assume that scanning short lists is faster than hashing. - let transform_index=if let Some(transform_index)=transforms.iter().position(|&transform|transform==face_description.transform){ - transform_index - }else{ - //create new transform_index - let transform_index=transforms.len(); - transforms.push(face_description.transform); - for tex in CUBE_DEFAULT_TEXTURE_COORDS{ - generated_tex.push(face_description.transform.transform_point2(tex)); - } - transform_index - } as u32; - let color_index=if let Some(color_index)=generated_color.iter().position(|&color|color==face_description.color){ - color_index - }else{ - //create new color_index - let color_index=generated_color.len(); - generated_color.push(face_description.color); - color_index - } as u32; - //always push normal - let normal_index=generated_normal.len() as u32; - generated_normal.push(CUBE_DEFAULT_NORMALS[face_id]); - //push vertices as they are needed - groups.push(IndexedGroup{ - texture:face_description.texture, - polys:vec![IndexedPolygon{ - vertices:CUBE_DEFAULT_POLYS[face_id].map(|tup|{ - let pos=CUBE_DEFAULT_VERTICES[tup[0] as usize]; - let pos_index=if let Some(pos_index)=generated_pos.iter().position(|&p|p==pos){ - pos_index - }else{ - //create new pos_index - let pos_index=generated_pos.len(); - generated_pos.push(pos); - pos_index - } as u32; - //always push vertex - let vertex=IndexedVertex{ - pos:pos_index, - tex:tup[1]+4*transform_index, - normal:normal_index, - color:color_index, - }; - let vert_index=generated_vertices.len(); - generated_vertices.push(vertex); - vert_index as u32 - }).to_vec(), - }], - }); - } - IndexedModel{ - unique_pos:generated_pos, - unique_tex:generated_tex, - unique_normal:generated_normal, - unique_color:generated_color, - unique_vertices:generated_vertices, - groups, - instances:Vec::new(), - } -} -//don't think too hard about the copy paste because this is all going into the map tool eventually... -pub fn generate_partial_unit_wedge(face_descriptions:WedgeFaceDescription)->crate::model::IndexedModel{ - let wedge_default_polys=vec![ - // right (1, 0, 0) - vec![ - [6,2,0],//[vertex,tex,norm] - [2,0,0], - [1,3,0], - ], - // FrontTop (0, 1, -1) - vec![ - [3,1,1], - [2,0,1], - [6,3,1], - [7,2,1], - ], - // back (0, 0, 1) - vec![ - [0,3,2], - [1,2,2], - [2,1,2], - [3,0,2], - ], - // left (-1, 0, 0) - vec![ - [0,2,3], - [3,1,3], - [7,3,3], - ], - // bottom (0,-1, 0) - vec![ - [1,1,4], - [0,0,4], - [7,3,4], - [6,2,4], - ], - ]; - let mut generated_pos=Vec::new(); - let mut generated_tex=Vec::new(); - let mut generated_normal=Vec::new(); - let mut generated_color=Vec::new(); - let mut generated_vertices=Vec::new(); - let mut groups=Vec::new(); - let mut transforms=Vec::new(); - //note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices. - for (face_id,face_description) in face_descriptions.pairs(){ - //assume that scanning short lists is faster than hashing. - let transform_index=if let Some(transform_index)=transforms.iter().position(|&transform|transform==face_description.transform){ - transform_index - }else{ - //create new transform_index - let transform_index=transforms.len(); - transforms.push(face_description.transform); - for tex in CUBE_DEFAULT_TEXTURE_COORDS{ - generated_tex.push(face_description.transform.transform_point2(tex)); - } - transform_index - } as u32; - let color_index=if let Some(color_index)=generated_color.iter().position(|&color|color==face_description.color){ - color_index - }else{ - //create new color_index - let color_index=generated_color.len(); - generated_color.push(face_description.color); - color_index - } as u32; - //always push normal - let normal_index=generated_normal.len() as u32; - generated_normal.push(WEDGE_DEFAULT_NORMALS[face_id]); - //push vertices as they are needed - groups.push(IndexedGroup{ - texture:face_description.texture, - polys:vec![IndexedPolygon{ - vertices:wedge_default_polys[face_id].iter().map(|tup|{ - let pos=CUBE_DEFAULT_VERTICES[tup[0] as usize]; - let pos_index=if let Some(pos_index)=generated_pos.iter().position(|&p|p==pos){ - pos_index - }else{ - //create new pos_index - let pos_index=generated_pos.len(); - generated_pos.push(pos); - pos_index - } as u32; - //always push vertex - let vertex=IndexedVertex{ - pos:pos_index, - tex:tup[1]+4*transform_index, - normal:normal_index, - color:color_index, - }; - let vert_index=generated_vertices.len(); - generated_vertices.push(vertex); - vert_index as u32 - }).collect(), - }], - }); - } - IndexedModel{ - unique_pos:generated_pos, - unique_tex:generated_tex, - unique_normal:generated_normal, - unique_color:generated_color, - unique_vertices:generated_vertices, - groups, - instances:Vec::new(), - } -} - -pub fn generate_partial_unit_cornerwedge(face_descriptions:CornerWedgeFaceDescription)->crate::model::IndexedModel{ - let cornerwedge_default_polys=vec![ - // right (1, 0, 0) - vec![ - [6,2,0],//[vertex,tex,norm] - [5,1,0], - [1,3,0], - ], - // BackTop (0, 1, 1) - vec![ - [5,3,1], - [0,1,1], - [1,0,1], - ], - // LeftTop (-1, 1, 0) - vec![ - [5,3,2], - [7,2,2], - [0,1,2], - ], - // bottom (0,-1, 0) - vec![ - [1,1,3], - [0,0,3], - [7,3,3], - [6,2,3], - ], - // front (0, 0,-1) - vec![ - [5,0,4], - [6,3,4], - [7,2,4], - ], - ]; - let mut generated_pos=Vec::new(); - let mut generated_tex=Vec::new(); - let mut generated_normal=Vec::new(); - let mut generated_color=Vec::new(); - let mut generated_vertices=Vec::new(); - let mut groups=Vec::new(); - let mut transforms=Vec::new(); - //note that on a cube every vertex is guaranteed to be unique, so there's no need to hash them against existing vertices. - for (face_id,face_description) in face_descriptions.pairs(){ - //assume that scanning short lists is faster than hashing. - let transform_index=if let Some(transform_index)=transforms.iter().position(|&transform|transform==face_description.transform){ - transform_index - }else{ - //create new transform_index - let transform_index=transforms.len(); - transforms.push(face_description.transform); - for tex in CUBE_DEFAULT_TEXTURE_COORDS{ - generated_tex.push(face_description.transform.transform_point2(tex)); - } - transform_index - } as u32; - let color_index=if let Some(color_index)=generated_color.iter().position(|&color|color==face_description.color){ - color_index - }else{ - //create new color_index - let color_index=generated_color.len(); - generated_color.push(face_description.color); - color_index - } as u32; - //always push normal - let normal_index=generated_normal.len() as u32; - generated_normal.push(CORNERWEDGE_DEFAULT_NORMALS[face_id]); - //push vertices as they are needed - groups.push(IndexedGroup{ - texture:face_description.texture, - polys:vec![IndexedPolygon{ - vertices:cornerwedge_default_polys[face_id].iter().map(|tup|{ - let pos=CUBE_DEFAULT_VERTICES[tup[0] as usize]; - let pos_index=if let Some(pos_index)=generated_pos.iter().position(|&p|p==pos){ - pos_index - }else{ - //create new pos_index - let pos_index=generated_pos.len(); - generated_pos.push(pos); - pos_index - } as u32; - //always push vertex - let vertex=IndexedVertex{ - pos:pos_index, - tex:tup[1]+4*transform_index, - normal:normal_index, - color:color_index, - }; - let vert_index=generated_vertices.len(); - generated_vertices.push(vertex); - vert_index as u32 - }).collect(), - }], - }); - } - IndexedModel{ - unique_pos:generated_pos, - unique_tex:generated_tex, - unique_normal:generated_normal, - unique_color:generated_color, - unique_vertices:generated_vertices, - groups, - instances:Vec::new(), - } -}