diff --git a/lib/bsp_loader/.gitignore b/lib/bsp_loader/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/lib/bsp_loader/.gitignore @@ -0,0 +1 @@ +/target diff --git a/lib/bsp_loader/Cargo.lock b/lib/bsp_loader/Cargo.lock new file mode 100644 index 0000000..403d681 --- /dev/null +++ b/lib/bsp_loader/Cargo.lock @@ -0,0 +1,822 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" + +[[package]] +name = "binrw" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f36b7cb3ab9ff6a2858650d8dc360e783a5d14dc29594db48c56a3c233cc265" +dependencies = [ + "array-init", + "binrw_derive", + "bytemuck", +] + +[[package]] +name = "binrw_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20ea7a8c5c8eeffffac6d54d172444e15beffac6f817fac714460a9a9aa88da3" +dependencies = [ + "either", + "owo-colors", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bnum" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50202def95bf36cb7d1d7a7962cea1c36a3f8ad42425e5d2b71d7acb8041b5b8" + +[[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.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[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 = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +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.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "fixed_wide" +version = "0.1.1" +source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" +checksum = "d9c2cf115b3785ede870fada07e8b1aeba3378345b4ca86fe3c772ecabc05c0f" +dependencies = [ + "arrayvec", + "bnum", + "paste", + "ratio_ops", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "glam" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28091a37a5d09b555cb6628fd954da299b536433834f5b8e59eba78e0cbbf8a" + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + +[[package]] +name = "id" +version = "0.1.0" +source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" +checksum = "2337e7a6c273082b672e377e159d7a168fb51438461b7c4033c79a515dd7a25a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" + +[[package]] +name = "linear_ops" +version = "0.1.0" +source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" +checksum = "b2e6977ac24f47086d8a7a2d4ae1c720e86dfdc8407cf5e34c18bfa01053c456" +dependencies = [ + "fixed_wide", + "paste", + "ratio_ops", +] + +[[package]] +name = "logos" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c6b6e02facda28ca5fb8dbe4b152496ba3b1bd5a4b40bb2b1b2d8ad74e0f39b" +dependencies = [ + "logos-derive", +] + +[[package]] +name = "logos-codegen" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32eb6b5f26efacd015b000bfc562186472cd9b34bdba3f6b264e2a052676d10" +dependencies = [ + "beef", + "fnv", + "lazy_static", + "proc-macro2", + "quote", + "regex-syntax", + "syn 2.0.79", +] + +[[package]] +name = "logos-derive" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e5d0c5463c911ef55624739fc353238b4e310f0144be1f875dc42fec6bfd5ec" +dependencies = [ + "logos-codegen", +] + +[[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 = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miette" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4edc8853320c2a0dab800fbda86253c8938f6ea88510dc92c5f1ed20e794afc1" +dependencies = [ + "cfg-if", + "miette-derive", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "once_cell" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "parse-display" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914a1c2265c98e2446911282c6ac86d8524f495792c38c5bd884f80499c7538a" +dependencies = [ + "parse-display-derive", + "regex", + "regex-syntax", +] + +[[package]] +name = "parse-display-derive" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae7800a4c974efd12df917266338e79a7a74415173caf7e70aa0a0707345281" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "regex-syntax", + "structmeta", + "syn 2.0.79", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "portable-atomic" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ratio_ops" +version = "0.1.0" +source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" +checksum = "01239195d6afe0509e7e3511b716c0540251dfe7ece0a9a5a27116afb766c42c" + +[[package]] +name = "regex" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strafesnet_bsp_loader" +version = "0.2.2" +dependencies = [ + "glam", + "strafesnet_common", + "vbsp", + "vmdl", +] + +[[package]] +name = "strafesnet_common" +version = "0.5.2" +source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/" +checksum = "91cc1f3699bd8248da18bf5d11273264396a257b5d47b8558acb2cb4e1761219" +dependencies = [ + "arrayvec", + "bitflags", + "fixed_wide", + "glam", + "id", + "linear_ops", + "ratio_ops", +] + +[[package]] +name = "structmeta" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329" +dependencies = [ + "proc-macro2", + "quote", + "structmeta-derive", + "syn 2.0.79", +] + +[[package]] +name = "structmeta-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[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.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.40" +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.79", +] + +[[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 = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "vbsp" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f14a5685e0bb386aac9b9c6046a05152a46a0bc58d53afb3fbe577f1a1c2bb05" +dependencies = [ + "ahash", + "arrayvec", + "binrw", + "bitflags", + "bv", + "cgmath", + "itertools", + "lzma-rs", + "num_enum", + "serde", + "static_assertions", + "thiserror", + "vdf-reader", + "zip-lzma", +] + +[[package]] +name = "vdf-reader" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "543945fdc3d51b20e3e0f5fd845ddeca4a270e56522035cf152105bc144ffd65" +dependencies = [ + "logos", + "miette", + "parse-display", + "serde", + "thiserror", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vmdl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2f6b8c22da8937403a5da864e7ea390f30cd40b7a077079e40279aa6a4f553" +dependencies = [ + "arrayvec", + "bitflags", + "bytemuck", + "cgmath", + "half", + "itertools", + "num_enum", + "static_assertions", + "thiserror", + "tracing", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[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/lib/bsp_loader/Cargo.toml b/lib/bsp_loader/Cargo.toml new file mode 100644 index 0000000..62aaaf7 --- /dev/null +++ b/lib/bsp_loader/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "strafesnet_bsp_loader" +version = "0.2.2" +edition = "2021" +repository = "https://git.itzana.me/StrafesNET/bsp_loader" +license = "MIT OR Apache-2.0" +description = "Convert Valve BSP files to StrafesNET data structures." +authors = ["Rhys Lloyd "] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +glam = "0.29.0" +strafesnet_common = { version = "0.5.2", registry = "strafesnet" } +vbsp = "0.6.0" +vmdl = "0.2.0" diff --git a/lib/bsp_loader/LICENSE-APACHE b/lib/bsp_loader/LICENSE-APACHE new file mode 100644 index 0000000..a7e77cb --- /dev/null +++ b/lib/bsp_loader/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/lib/bsp_loader/LICENSE-MIT b/lib/bsp_loader/LICENSE-MIT new file mode 100644 index 0000000..468cd79 --- /dev/null +++ b/lib/bsp_loader/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/lib/bsp_loader/README.md b/lib/bsp_loader/README.md new file mode 100644 index 0000000..c9800e2 --- /dev/null +++ b/lib/bsp_loader/README.md @@ -0,0 +1,19 @@ +StrafesNET BSP Loader +===================== + +## Convert Valve BSP files into StrafesNET data structures + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
+ + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + \ No newline at end of file diff --git a/lib/bsp_loader/src/bsp.rs b/lib/bsp_loader/src/bsp.rs new file mode 100644 index 0000000..def11ee --- /dev/null +++ b/lib/bsp_loader/src/bsp.rs @@ -0,0 +1,333 @@ +use strafesnet_common::{map,model,integer,gameplay_attributes}; + +const VALVE_SCALE:f32=1.0/16.0; +fn valve_transform([x,y,z]:[f32;3])->integer::Planar64Vec3{ + integer::vec3::try_from_f32_array([x*VALVE_SCALE,z*VALVE_SCALE,-y*VALVE_SCALE]).unwrap() +} +pub fn convert_bsp( + bsp:&vbsp::Bsp, + mut acquire_render_config_id:AcquireRenderConfigId, + mut acquire_mesh_id:AcquireMeshId +)->PartialMap1 +where + AcquireRenderConfigId:FnMut(Option<&str>)->model::RenderConfigId, + AcquireMeshId:FnMut(&str)->model::MeshId, +{ + //figure out real attributes later + let mut unique_attributes=Vec::new(); + unique_attributes.push(gameplay_attributes::CollisionAttributes::Decoration); + const TEMP_TOUCH_ME_ATTRIBUTE:gameplay_attributes::CollisionAttributesId=gameplay_attributes::CollisionAttributesId::new(0); + + let mut prop_mesh_count=0; + //declare all prop models to Loader + let prop_models=bsp.static_props().map(|prop|{ + //get or create mesh_id + let mesh_id=acquire_mesh_id(prop.model()); + //not the most failsafe code but this is just for the map tool lmao + if prop_mesh_count==mesh_id.get(){ + prop_mesh_count+=1; + }; + let placement=prop.as_prop_placement(); + model::Model{ + mesh:mesh_id, + attributes:TEMP_TOUCH_ME_ATTRIBUTE, + transform:integer::Planar64Affine3::new( + integer::mat3::try_from_f32_array_2d(( + glam::Mat3A::from_diagonal(glam::Vec3::splat(placement.scale)) + //TODO: figure this out + *glam::Mat3A::from_quat(glam::Quat::from_array(placement.rotation.into())) + ).to_cols_array_2d()).unwrap(), + valve_transform(placement.origin.into()), + ), + color:glam::Vec4::ONE, + } + }).collect(); + + //TODO: make the main map one single mesh with a bunch of different physics groups and graphics groups + + //the generated MeshIds in here will collide with the Loader Mesh Ids + //but I can't think of a good workaround other than just remapping one later. + let world_meshes:Vec=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 mut graphics_groups=Vec::new(); + let mut physics_group=model::IndexedPhysicsGroup::default(); + let polygon_groups=world_model.faces().enumerate().map(|(polygon_group_id,face)|{ + let polygon_group_id=model::PolygonGroupId::new(polygon_group_id as u32); + let face_texture=face.texture(); + let face_texture_data=face_texture.texture_data(); + //this would be better as a 4x2 matrix + let texture_transform_u=glam::Vec4::from_array(face_texture.texture_transforms_u)/(face_texture_data.width as f32); + let texture_transform_v=glam::Vec4::from_array(face_texture.texture_transforms_v)/(face_texture_data.height as f32); + + //this automatically figures out what the texture is trying to do and creates + //a render config for it, and then returns the id to that render config + let render_id=acquire_render_config_id(Some(face_texture_data.name())); + + //normal + let normal=face.normal(); + let normal_idx=spam_normal.len() as u32; + spam_normal.push(valve_transform(normal.into())); + let mut polygon_iter=face.vertex_positions().map(|vertex_position|{ + //world_model.origin seems to always be 0,0,0 + let vertex_xyz=(world_model.origin+vertex_position).into(); + let pos_idx=spam_pos.len(); + spam_pos.push(valve_transform(vertex_xyz)); + + //calculate texture coordinates + let pos=glam::Vec3::from_array(vertex_xyz).extend(1.0); + let tex=glam::vec2(texture_transform_u.dot(pos),texture_transform_v.dot(pos)); + let tex_idx=spam_tex.len() as u32; + spam_tex.push(tex); + + let vertex_id=model::VertexId::new(spam_vertices.len() as u32); + spam_vertices.push(model::IndexedVertex{ + pos:model::PositionId::new(pos_idx as u32), + tex:model::TextureCoordinateId::new(tex_idx as u32), + normal:model::NormalId::new(normal_idx), + color:model::ColorId::new(0), + }); + vertex_id + }); + let polygon_list=std::iter::from_fn(move||{ + match (polygon_iter.next(),polygon_iter.next(),polygon_iter.next()){ + (Some(v1),Some(v2),Some(v3))=>Some(vec![v1,v2,v3]), + //ignore extra vertices, not sure what to do in this case, failing the whole conversion could be appropriate + _=>None, + } + }).collect(); + if face.is_visible(){ + //TODO: deduplicate graphics groups by render id + graphics_groups.push(model::IndexedGraphicsGroup{ + render:render_id, + groups:vec![polygon_group_id], + }) + } + physics_group.groups.push(polygon_group_id); + model::PolygonGroup::PolygonList(model::PolygonList::new(polygon_list)) + }).collect(); + model::Mesh{ + unique_pos:spam_pos, + unique_tex:spam_tex, + unique_normal:spam_normal, + unique_color:vec![glam::Vec4::ONE], + unique_vertices:spam_vertices, + polygon_groups, + graphics_groups, + physics_groups:vec![physics_group], + } + }).collect(); + + let world_models:Vec= + //one instance of the main world mesh + std::iter::once(( + //world_model + model::MeshId::new(0), + //model_origin + vbsp::Vector::from([0.0,0.0,0.0]), + //model_color + vbsp::Color{r:255,g:255,b:255}, + )).chain( + //entities sprinkle instances of the other meshes around + bsp.entities.iter() + .flat_map(|ent|ent.parse())//ignore entity parsing errors + .filter_map(|ent|match ent{ + vbsp::Entity::Brush(brush)=>Some(brush), + vbsp::Entity::BrushIllusionary(brush)=>Some(brush), + vbsp::Entity::BrushWall(brush)=>Some(brush), + vbsp::Entity::BrushWallToggle(brush)=>Some(brush), + _=>None, + }).flat_map(|brush| + //The first character of brush.model is '*' + brush.model[1..].parse().map(|mesh_id|//ignore parse int errors + (model::MeshId::new(mesh_id),brush.origin,brush.color) + ) + ) + ).map(|(mesh_id,model_origin,vbsp::Color{r,g,b})|{ + model::Model{ + mesh:mesh_id, + attributes:TEMP_TOUCH_ME_ATTRIBUTE, + transform:integer::Planar64Affine3::new( + integer::mat3::identity(), + valve_transform(model_origin.into()) + ), + color:(glam::Vec3::from_array([r as f32,g as f32,b as f32])/255.0).extend(1.0), + } + }).collect(); + + PartialMap1{ + attributes:unique_attributes, + world_meshes, + prop_models, + world_models, + modes:strafesnet_common::gameplay_modes::Modes::new(Vec::new()), + } +} + +//partially constructed map types +pub struct PartialMap1{ + attributes:Vec, + prop_models:Vec, + world_meshes:Vec, + world_models:Vec, + modes:strafesnet_common::gameplay_modes::Modes, +} +impl PartialMap1{ + pub fn add_prop_meshes( + self, + prop_meshes:impl IntoIterator, + mut acquire_render_config_id:AcquireRenderConfigId, + )->PartialMap2 + where + AcquireRenderConfigId:FnMut(Option<&str>)->model::RenderConfigId, + { + PartialMap2{ + attributes:self.attributes, + prop_meshes:prop_meshes.into_iter().filter_map(|(mesh_id,model_data)| + //this will generate new render ids and texture ids + match convert_mesh(model_data,&mut acquire_render_config_id){ + Ok(mesh)=>Some((mesh_id,mesh)), + Err(e)=>{ + println!("error converting mesh: {e}"); + None + } + } + ).collect(), + prop_models:self.prop_models, + world_meshes:self.world_meshes, + world_models:self.world_models, + modes:self.modes, + } + } +} +pub struct PartialMap2{ + attributes:Vec, + prop_meshes:Vec<(model::MeshId,model::Mesh)>, + prop_models:Vec, + world_meshes:Vec, + world_models:Vec, + modes:strafesnet_common::gameplay_modes::Modes, +} +impl PartialMap2{ + pub fn add_render_configs_and_textures( + mut self, + render_configs:impl IntoIterator, + textures:impl IntoIterator)>, + )->map::CompleteMap{ + //merge mesh and model lists, flatten and remap all ids + let mesh_id_offset=self.world_meshes.len(); + println!("prop_meshes.len()={}",self.prop_meshes.len()); + let (mut prop_meshes,prop_mesh_id_map):(Vec,std::collections::HashMap) + =self.prop_meshes.into_iter().enumerate().map(|(new_mesh_id,(old_mesh_id,mesh))|{ + (mesh,(old_mesh_id,model::MeshId::new((mesh_id_offset+new_mesh_id) as u32))) + }).unzip(); + self.world_meshes.append(&mut prop_meshes); + //there is no modes or runtime behaviour with references to the model ids currently + //so just relentlessly cull them if the mesh is missing + self.world_models.extend(self.prop_models.into_iter().filter_map(|mut model| + prop_mesh_id_map.get(&model.mesh).map(|&new_mesh_id|{ + model.mesh=new_mesh_id; + model + }) + )); + //let mut models=Vec::new(); + let (textures,texture_id_map):(Vec>,std::collections::HashMap) + =textures.into_iter() + //.filter_map(f) cull unused textures + .enumerate().map(|(new_texture_id,(old_texture_id,texture))|{ + (texture,(old_texture_id,model::TextureId::new(new_texture_id as u32))) + }).unzip(); + let render_configs=render_configs.into_iter().map(|(render_config_id,mut render_config)|{ + //this may generate duplicate no-texture render configs but idc + render_config.texture=render_config.texture.and_then(|texture_id| + texture_id_map.get(&texture_id).copied() + ); + render_config + }).collect(); + map::CompleteMap{ + modes:self.modes, + attributes:self.attributes, + meshes:self.world_meshes, + models:self.world_models, + textures, + render_configs, + } + } +} + +fn convert_mesh( + model_data:crate::data::ModelData, + acquire_render_config_id:&mut AcquireRenderConfigId, +)->Result +where + AcquireRenderConfigId:FnMut(Option<&str>)->model::RenderConfigId, +{ + let model=model_data.read_model()?; + 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(vertex.position.into())); + spam_normal.push(valve_transform(vertex.normal.into())); + spam_tex.push(glam::Vec2::from_array(vertex.texture_coordinates)); + spam_vertices.push(model::IndexedVertex{ + pos:model::PositionId::new(i as u32), + tex:model::TextureCoordinateId::new(i as u32), + normal:model::NormalId::new(i as u32), + color:model::ColorId::new(0), + }); + } + let mut graphics_groups=Vec::new(); + let mut physics_groups=Vec::new(); + let polygon_groups=model.meshes().enumerate().map(|(polygon_group_id,mesh)|{ + let polygon_group_id=model::PolygonGroupId::new(polygon_group_id as u32); + + let render_id=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); + acquire_render_config_id(path.as_os_str().to_str()) + }else{ + acquire_render_config_id(None) + }; + + graphics_groups.push(model::IndexedGraphicsGroup{ + render:render_id, + groups:vec![polygon_group_id], + }); + physics_groups.push(model::IndexedPhysicsGroup{ + groups:vec![polygon_group_id], + }); + model::PolygonGroup::PolygonList(model::PolygonList::new( + //looking at the code, it would seem that the strips are pre-deindexed into triangle lists when calling this function + mesh.vertex_strip_indices().flat_map(|mut strip| + std::iter::from_fn(move||{ + match (strip.next(),strip.next(),strip.next()){ + (Some(v1),Some(v2),Some(v3))=>Some([v1,v2,v3].map(|vertex_id|model::VertexId::new(vertex_id as u32)).to_vec()), + //ignore extra vertices, not sure what to do in this case, failing the whole conversion could be appropriate + _=>None, + } + }) + ).collect() + )) + }).collect(); + Ok(model::Mesh{ + unique_pos:spam_pos, + unique_normal:spam_normal, + unique_tex:spam_tex, + unique_color:vec![glam::Vec4::ONE], + unique_vertices:spam_vertices, + polygon_groups, + graphics_groups, + physics_groups, + }) +} diff --git a/lib/bsp_loader/src/data.rs b/lib/bsp_loader/src/data.rs new file mode 100644 index 0000000..83ca678 --- /dev/null +++ b/lib/bsp_loader/src/data.rs @@ -0,0 +1,60 @@ +pub struct Bsp(vbsp::Bsp); +impl Bsp{ + pub const fn new(value:vbsp::Bsp)->Self{ + Self(value) + } +} +impl AsRef for Bsp{ + fn as_ref(&self)->&vbsp::Bsp{ + &self.0 + } +} + +pub struct MdlData(Vec); +impl MdlData{ + pub const fn new(value:Vec)->Self{ + Self(value) + } +} +impl AsRef<[u8]> for MdlData{ + fn as_ref(&self)->&[u8]{ + self.0.as_ref() + } +} +pub struct VtxData(Vec); +impl VtxData{ + pub const fn new(value:Vec)->Self{ + Self(value) + } +} +impl AsRef<[u8]> for VtxData{ + fn as_ref(&self)->&[u8]{ + self.0.as_ref() + } +} +pub struct VvdData(Vec); +impl VvdData{ + pub const fn new(value:Vec)->Self{ + Self(value) + } +} +impl AsRef<[u8]> for VvdData{ + fn as_ref(&self)->&[u8]{ + self.0.as_ref() + } +} + +pub struct ModelData{ + pub mdl:MdlData, + pub vtx:VtxData, + pub vvd:VvdData, +} +impl ModelData{ + pub fn read_model(&self)->Result{ + Ok(vmdl::Model::from_parts( + vmdl::mdl::Mdl::read(self.mdl.as_ref())?, + vmdl::vtx::Vtx::read(self.vtx.as_ref())?, + vmdl::vvd::Vvd::read(self.vvd.as_ref())?, + )) + } +} \ No newline at end of file diff --git a/lib/bsp_loader/src/lib.rs b/lib/bsp_loader/src/lib.rs new file mode 100644 index 0000000..e8d4d91 --- /dev/null +++ b/lib/bsp_loader/src/lib.rs @@ -0,0 +1,37 @@ +mod bsp; +pub mod data; + +pub use data::Bsp; + +#[derive(Debug)] +pub enum ReadError{ + Bsp(vbsp::BspError), + Io(std::io::Error), +} +impl std::fmt::Display for ReadError{ + fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ + write!(f,"{self:?}") + } +} +impl std::error::Error for ReadError{} + +pub fn read(mut input:R)->Result{ + let mut s=Vec::new(); + + //TODO: mmap + input.read_to_end(&mut s).map_err(ReadError::Io)?; + + vbsp::Bsp::read(s.as_slice()).map(Bsp::new).map_err(ReadError::Bsp) +} + +pub fn convert( + bsp:&Bsp, + acquire_render_config_id:AcquireRenderConfigId, + acquire_mesh_id:AcquireMeshId +)->bsp::PartialMap1 +where + AcquireRenderConfigId:FnMut(Option<&str>)->strafesnet_common::model::RenderConfigId, + AcquireMeshId:FnMut(&str)->strafesnet_common::model::MeshId, +{ + bsp::convert_bsp(bsp.as_ref(),acquire_render_config_id,acquire_mesh_id) +} \ No newline at end of file