diff --git a/.idea/vulkano-test.iml b/.idea/vulkano-test.iml index cf84ae4..9a72d25 100644 --- a/.idea/vulkano-test.iml +++ b/.idea/vulkano-test.iml @@ -2,7 +2,9 @@ + + diff --git a/Cargo.lock b/Cargo.lock index ab26cd6..3700c7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,6 +24,12 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "ahash" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0453232ace82dee0dd0b4c87a59bd90f7b53b314f3e0f61fe2ee7c8a16482289" + [[package]] name = "ahash" version = "0.8.12" @@ -31,7 +37,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom", + "getrandom 0.3.4", "once_cell", "version_check", "zerocopy", @@ -88,6 +94,15 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + [[package]] name = "arbitrary" version = "1.4.2" @@ -141,6 +156,15 @@ dependencies = [ "libloading", ] +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -264,6 +288,12 @@ dependencies = [ "syn", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "byteorder-lite" version = "0.1.0" @@ -341,6 +371,15 @@ dependencies = [ "cc", ] +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.18", +] + [[package]] name = "color_quant" version = "1.1.0" @@ -424,6 +463,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -513,6 +558,18 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "equator" version = "0.4.2" @@ -684,10 +741,23 @@ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + [[package]] name = "gif" version = "0.14.1" @@ -698,6 +768,114 @@ dependencies = [ "weezl", ] +[[package]] +name = "glam" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "333928d5eb103c5d4050533cec0384302db6be8ef7d3cebd30ec6a35350353da" + +[[package]] +name = "glam" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3abb554f8ee44336b72d522e0a7fe86a29e09f839a36022fa869a7dfe941a54b" + +[[package]] +name = "glam" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4126c0479ccf7e8664c36a2d719f5f2c140fbb4f9090008098d2c291fa5b3f16" + +[[package]] +name = "glam" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01732b97afd8508eee3333a541b9f7610f454bb818669e66e90f5f57c93a776" + +[[package]] +name = "glam" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525a3e490ba77b8e326fb67d4b44b4bd2f920f44d4cc73ccec50adc68e3bee34" + +[[package]] +name = "glam" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8509e6791516e81c1a630d0bd7fbac36d2fa8712a9da8662e716b52d5051ca" + +[[package]] +name = "glam" +version = "0.20.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43e957e744be03f5801a55472f593d43fabdebf25a4585db250f04d86b1675f" + +[[package]] +name = "glam" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518faa5064866338b013ff9b2350dc318e14cc4fcd6cb8206d7e7c9886c98815" + +[[package]] +name = "glam" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f597d56c1bd55a811a1be189459e8fad2bbc272616375602443bdfb37fa774" + +[[package]] +name = "glam" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e4afd9ad95555081e109fe1d21f2a30c691b5f0919c67dfa690a2e1eb6bd51c" + +[[package]] +name = "glam" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" + +[[package]] +name = "glam" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" + +[[package]] +name = "glam" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e05e7e6723e3455f4818c7b26e855439f7546cf617ef669d1adedb8669e5cb9" + +[[package]] +name = "glam" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "779ae4bf7e8421cf91c0b3b64e7e8b40b862fba4d393f59150042de7c4965a94" + +[[package]] +name = "glam" +version = "0.29.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8babf46d4c1c9d92deac9f7be466f76dfc4482b6452fc5024b5e8daf6ffeb3ee" + +[[package]] +name = "glam" +version = "0.30.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9" + +[[package]] +name = "glam" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556f6b2ea90b8d15a74e0e7bb41671c9bdf38cd9f78c284d750b9ce58a2b5be7" + +[[package]] +name = "glam" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f70749695b063ecbf6b62949ccccde2e733ec3ecbbd71d467dca4e5c6c97cca0" + [[package]] name = "half" version = "2.7.1" @@ -710,24 +888,77 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +dependencies = [ + "ahash 0.4.8", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "serde", + "spin", + "stable_deref_trait", +] + [[package]] name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "image" version = "0.25.10" @@ -775,7 +1006,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] @@ -832,7 +1065,7 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom", + "getrandom 0.3.4", "libc", ] @@ -846,6 +1079,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "lebe" version = "0.5.3" @@ -926,6 +1165,16 @@ dependencies = [ "imgref", ] +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "rawpointer", +] + [[package]] name = "maybe-rayon" version = "0.1.1" @@ -977,6 +1226,51 @@ dependencies = [ "pxfm", ] +[[package]] +name = "nalgebra" +version = "0.34.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df76ea0ff5c7e6b88689085804d6132ded0ddb9de5ca5b8aeb9eeadc0508a70a" +dependencies = [ + "approx", + "glam 0.14.0", + "glam 0.15.2", + "glam 0.16.0", + "glam 0.17.3", + "glam 0.18.0", + "glam 0.19.0", + "glam 0.20.5", + "glam 0.21.3", + "glam 0.22.0", + "glam 0.23.0", + "glam 0.24.2", + "glam 0.25.0", + "glam 0.27.0", + "glam 0.28.0", + "glam 0.29.3", + "glam 0.30.10", + "glam 0.31.1", + "glam 0.32.1", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "973e7178a678cfd059ccec50887658d482ce16b0aa9da3888ddeab5cd5eb4889" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ndk" version = "0.9.0" @@ -1048,6 +1342,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-derive" version = "0.4.2" @@ -1499,6 +1802,19 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "heapless", + "serde", +] + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -1508,6 +1824,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro-crate" version = "3.5.0" @@ -1590,6 +1916,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" version = "0.9.2" @@ -1616,7 +1948,7 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom", + "getrandom 0.3.4", ] [[package]] @@ -1687,6 +2019,12 @@ dependencies = [ "objc2-quartz-core 0.3.2", ] +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.11.0" @@ -1749,6 +2087,15 @@ dependencies = [ "xmlparser", ] +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.44" @@ -1781,6 +2128,15 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "safe_arch" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" +dependencies = [ + "bytemuck", +] + [[package]] name = "same-file" version = "1.0.6" @@ -1815,6 +2171,12 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.228" @@ -1885,6 +2247,19 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simba" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c99284beb21666094ba2b75bbceda012e610f5479dfcc2d6e2426f53197ffd95" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + [[package]] name = "simd-adler32" version = "0.3.8" @@ -1952,6 +2327,15 @@ dependencies = [ "serde", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -2115,6 +2499,12 @@ version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +[[package]] +name = "typenum" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" + [[package]] name = "unicode-ident" version = "1.0.24" @@ -2127,6 +2517,23 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "uuid" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "v_frame" version = "0.3.9" @@ -2164,7 +2571,7 @@ dependencies = [ "crossbeam-queue", "foldhash", "half", - "heck", + "heck 0.4.1", "indexmap", "libloading", "nom 7.1.3", @@ -2204,7 +2611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bf501461be7cef2893c0e62c50945add9763cc482051d29053f6157089d5ea9" dependencies = [ "foldhash", - "heck", + "heck 0.4.1", "proc-macro2", "quote", "shaderc", @@ -2217,8 +2624,13 @@ name = "vulkano-test" version = "0.1.0" dependencies = [ "image", + "nalgebra", + "postcard", + "serde", + "uuid", "vulkano", "vulkano-shaders", + "wavefront", "winit", ] @@ -2241,6 +2653,15 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.114" @@ -2300,6 +2721,49 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "wavefront" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0162190f32ea78b07b7bc02b57a1c2a7c0874bc3da34f36eba41c86c4b03c4fb" +dependencies = [ + "hashbrown 0.9.1", +] + [[package]] name = "wayland-backend" version = "0.3.14" @@ -2435,6 +2899,16 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" +[[package]] +name = "wide" +version = "0.7.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "winapi-util" version = "0.1.11" @@ -2613,7 +3087,7 @@ version = "0.30.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6755fa58a9f8350bd1e472d4c3fcc25f824ec358933bba33306d0b63df5978d" dependencies = [ - "ahash", + "ahash 0.8.12", "android-activity", "atomic-waker", "bitflags 2.11.0", @@ -2673,6 +3147,88 @@ name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "x11-dl" diff --git a/Cargo.toml b/Cargo.toml index 1ec4aab..1084712 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,11 @@ edition = "2024" [dependencies] image = "0.25.10" +serde = { version = "1.0", features=[ "derive" ] } vulkano = "^0.35" vulkano-shaders = "^0.35" +wavefront = "0.2.3" winit = "0.30.13" +nalgebra = "*" +uuid = { version = "1.23.1", features = ["v4"] } +postcard = { version = "1.1", features = ["alloc"] } diff --git a/src/app.rs b/src/app.rs index 985176a..7ead46b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,6 +1,6 @@ use std::error::Error; use std::sync::Arc; -use vulkano::buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer}; +use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}; use vulkano::command_buffer::allocator::{StandardCommandBufferAllocator, StandardCommandBufferAllocatorCreateInfo}; use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer, RenderPassBeginInfo, SubpassBeginInfo, SubpassContents, SubpassEndInfo}; use vulkano::descriptor_set::allocator::{DescriptorSetAllocator, StandardDescriptorSetAllocator}; @@ -28,37 +28,10 @@ use winit::application::ApplicationHandler; use winit::event::WindowEvent; use winit::event_loop::ActiveEventLoop; use winit::window::{Window, WindowAttributes, WindowId}; -use crate::math::Vector2; +use crate::common::mesh::MeshRegistry; +use crate::gpu::vertex3::Vertex3; use crate::triangle; -/// The `Vertex2` is an intermediate structure used to represent the [`Vector2`] in the graphics -/// pipeline. It specifies a positional value and can be passed directly into the shaders. -/// Note that conversion between a `Vector2` and a `Vertex2` may take extra computation time. -/// -/// Honestly, I'm still not sure if this should be handled on a per-shader basis, as the position -/// argument changes with each shader. -#[derive(BufferContents, Vertex)] -#[repr(C)] -struct Vertex2 { - #[format(R32G32_SFLOAT)] - position: [f32; 2], -} - -impl From for Vertex2 { - fn from(v: Vector2) -> Self { - Self { - position: [v.x, v.y], - } - } -} - -#[derive(BufferContents, Vertex)] -#[repr(C)] -struct Vertex3 { - #[format(R32G32B32_SFLOAT)] - position: [f32; 3], -} - struct VulkanContext { window: Arc, device: Arc, @@ -73,9 +46,8 @@ struct VulkanContext { render_pass: Arc, framebuffers: Vec>, pipeline: Arc, - vertex_buffer: Arc>, - index_buffer: Arc>, cmd_buffers: Vec>, + mesh_registry: Arc, } impl VulkanContext { @@ -201,10 +173,10 @@ impl VulkanContext { ..Default::default() }, vec![ - Vertex2 { position: [0.5, 0.5] }, - Vertex2 { position: [-0.5, 0.5] }, - Vertex2 { position: [-0.5, -0.5] }, - Vertex2 { position: [0.5, -0.5] }, + Vertex3 { position: [0.5, 0.5, 0.0] }, + Vertex3 { position: [-0.5, 0.5, 0.0] }, + Vertex3 { position: [-0.5, -0.5, 0.0] }, + Vertex3 { position: [0.5, -0.5, 0.0] }, ] )?); @@ -234,6 +206,10 @@ impl VulkanContext { &index_buffer )?; + let mesh_registry = Arc::new(MeshRegistry::new( + mem_allocator.clone(), + )?); + Ok(Self { window, device, @@ -248,9 +224,8 @@ impl VulkanContext { frag_shader, framebuffers, pipeline, - vertex_buffer, - index_buffer, - cmd_buffers + cmd_buffers, + mesh_registry, }) } @@ -378,7 +353,7 @@ impl VulkanContext { let fs = frag_shader.entry_point("main") .ok_or("Failed to find fragment shader entry point")?; - let vertex_input_state = Vertex2::per_vertex() + let vertex_input_state = Vertex3::per_vertex() .definition(&vs)?; let stages = vec![ @@ -432,7 +407,7 @@ impl VulkanContext { queue: &Arc, pipeline: &Arc, framebuffers: &Vec>, - vertex_buffer: &Subbuffer<[Vertex2]>, + vertex_buffer: &Arc>, index_buffer: &Subbuffer<[u32]> ) -> Result>, Box> { let buffers = framebuffers.iter() @@ -456,7 +431,7 @@ impl VulkanContext { } ).ok()? .bind_pipeline_graphics(pipeline.clone()).ok()? - .bind_vertex_buffers(0, vertex_buffer.clone()).ok()? + .bind_vertex_buffers(0, vertex_buffer.as_ref().clone()).ok()? .bind_index_buffer(index_buffer.clone()).ok()? // .draw(vertex_buffer.len() as u32, 1, 0, 0).ok()? .draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0).ok()? @@ -506,8 +481,8 @@ impl VulkanContext { &self.queue, &new_pipeline, &self.framebuffers, - &self.vertex_buffer, - &self.index_buffer + &self.mesh_registry.vertex_buffer, + &self.mesh_registry.index_buffer )?; self.pipeline = new_pipeline; diff --git a/src/common/instance.rs b/src/common/instance.rs new file mode 100644 index 0000000..1f42e27 --- /dev/null +++ b/src/common/instance.rs @@ -0,0 +1,55 @@ +use nalgebra::{Matrix4, Vector3, Vector4}; +use crate::common::scene::SceneInstance; + +/// Contains all information about an instance of a mesh, specifically its translation, rotation, +/// and scale. Note that the rotation is a [`Vector4`], and not a `Quaternion`. +/// +/// This may be taken from a scene instance by calling the `Instance::from` method on the +/// corresponding [`SceneInstance`]. This is important, as the `Vector4` is not serializable. +/// +/// Before passing this instance into the shaders, construct a transformation matrix by calling +/// [`MeshInstance::transform_matrix`]. +pub struct MeshInstance { + /// The ID of the mesh corresponding to this instance. + pub mesh_id: String, + /// The translation of the instance from the center of the standard space. It is possible that + /// local translation will be required in the future. + pub translation: Vector4, + /// The rotation of the instance. Note that since this is a [`Vector4`], or Euler angle, it + /// suffers from gimbal lock. If this becomes a serious issue, an [`nalgebra::UnitQuaternion`] + /// should be used instead. + pub rotation: Vector4, + /// The scale of the instance, represented as the scaling in XYZ coordinates. + pub scale: Vector3, +} + +impl MeshInstance { + /// Constructs a transformation matrix from the current translation, rotation, and scale. + pub fn transform_matrix(&self) -> Matrix4 { + Matrix4::new_translation(&self.translation.xyz()) * + // There's a possibility that these can be altered. Sometimes they're multiplied in the + // order ZYX. They are technically applied in the opposite order written here, so in + // this case it's actually applying Z, then Y, then X. They *do* produce different results. + Matrix4::from_axis_angle(&Vector3::x_axis(), self.rotation.x) * + Matrix4::from_axis_angle(&Vector3::y_axis(), self.rotation.y) * + Matrix4::from_axis_angle(&Vector3::z_axis(), self.rotation.z) * + Matrix4::new_nonuniform_scaling(&self.scale) + } + + /// Constructs a `MeshInstance` from the given [`SceneInstance`] and mesh ID. + fn from_scene_instance( + mesh_id: String, + SceneInstance { + translation, + rotation, + scale, + }: SceneInstance, + ) -> Self { + Self { + mesh_id, + translation: Vector3::from(translation).to_homogeneous(), + rotation: Vector3::from(rotation).to_homogeneous(), + scale: Vector3::from(scale), + } + } +} diff --git a/src/common/mesh.rs b/src/common/mesh.rs new file mode 100644 index 0000000..aeeb5f5 --- /dev/null +++ b/src/common/mesh.rs @@ -0,0 +1,155 @@ +use std::collections::HashMap; +use std::error::Error; +use std::path::Path; +use std::sync::Arc; +use nalgebra::Vector3; +use uuid::Uuid; +use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer}; +use vulkano::memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryTypeFilter}; +use wavefront::Obj; +use crate::common::scene::Scene; +use crate::gpu::vertex3::Vertex3; + +/// This struct is slightly misleading - it doesn't actually contain the mesh information, but +/// the locations of the mesh's information in the overall application's vertex buffer, index buffer, +/// and other such structures. +/// +/// Once loaded, the mesh should be accessible via ID through a registry-type struct, which simply +/// maintains the list of meshes that have been loaded by the application so far and which assigns +/// the correct indices for buffer-to-render logic. +/// +/// That means that this `Mesh` struct is actually just an entry within that registry. They should +/// rarely be used directly, and should never be edited. +#[derive(Debug)] +pub struct Mesh { + pub id: String, + pub vertex_loc: usize, + pub index_loc: usize, +} + +impl Mesh { + pub fn new( + id: impl Into, + vertex_loc: usize, + index_loc: usize, + ) -> Self { + Self { + id: id.into(), + vertex_loc, + index_loc, + } + } +} + +/// # Mesh Registry +/// A wrapper around a series of [`Mesh`] structs, keyed by a unique ID, and the buffers that are +/// used by the rendering pipeline. +#[derive(Debug)] +pub struct MeshRegistry { + meshes: HashMap, + allocator: Arc, + pub vertex_buffer: Arc>, + pub index_buffer: Arc>, +} + +impl MeshRegistry { + pub fn new( + allocator: Arc, + ) -> Result> { + let vertex_buffer = Arc::new(Buffer::new_slice::( + allocator.clone(), + BufferCreateInfo { + usage: BufferUsage::VERTEX_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_HOST | + MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + 1_000_000, + )?); + + let index_buffer = Arc::new(Buffer::new_slice::( + allocator.clone(), + BufferCreateInfo { + usage: BufferUsage::INDEX_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_HOST | + MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + 3_000_000, + )?); + + Ok(Self { + meshes: HashMap::new(), + allocator, + vertex_buffer, + index_buffer, + }) + } + + /// Creates a `MeshRegistry` from the provided [`Scene`]. + /// + /// This method will load all the meshes indicated by the scene and allocate the required + /// buffers. This significantly simplifies the allocation process, as the buffers only need to + /// be allocated once. + pub fn from_scene(scene: &Scene, allocator: Arc) -> Self { + // First, load all the meshes into a single map. + println!("Loading meshes from scene"); + let meshes = scene.mesh_paths.iter().map(|(id, path)| + (id.clone(), Obj::from_file(path).expect("Couldn't read wavefront file")) + ).collect::>(); + + // Second, build two more maps that contain the vertex and index information. + let verts = meshes.iter().map(|(id, obj)| + (id.clone(), obj.vertices().map(|v| v.position().into()).collect()) + ).collect::>>>(); + + let indices = meshes.iter().map(|(id, obj)| + (id.clone(), obj.vertices().map(|v| v.position_index()).collect()) + ).collect::>>(); + + // Apply static transformations here. The general idea is that we don't want to have to read + // any information from the buffer without the correct information. We do want to keep track + // of what mesh is at what location in the list though. + println!("Applying static mesh transformations"); + + // Get Vector3's as a list of Vertex3's (CPU to GPU) + + // Third, allocate and fill buffers with this information. + // let vert_buffer = Self::alloc_vert_buffer(allocator, verts.values().collect()); + + // Fourth, return the struct. + + todo!() + } + + fn alloc_vert_buffer( + alloc: Arc, + verts: Vec + ) -> Arc> { + println!("Allocating vertex buffer"); + Arc::new(Buffer::from_iter( + alloc.clone(), + BufferCreateInfo { + usage: BufferUsage::VERTEX_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + memory_type_filter: MemoryTypeFilter::PREFER_HOST | + MemoryTypeFilter::HOST_SEQUENTIAL_WRITE, + ..Default::default() + }, + verts + ).expect("Couldn't allocate vertex buffer")) + } + + /// Attempts to find a [`Mesh`] with the given ID, returning `None` if it's not found. + pub fn get(&self, uuid: &str) -> Option<&Mesh> { + self.meshes.get(uuid) + } +} diff --git a/src/common/mod.rs b/src/common/mod.rs new file mode 100644 index 0000000..67f38a0 --- /dev/null +++ b/src/common/mod.rs @@ -0,0 +1,3 @@ +pub mod mesh; +pub mod scene; +pub mod instance; diff --git a/src/common/scene.rs b/src/common/scene.rs new file mode 100644 index 0000000..6506b7f --- /dev/null +++ b/src/common/scene.rs @@ -0,0 +1,74 @@ +use std::collections::HashMap; +use std::io::Read; +use std::path::Path; +use serde::{Deserialize, Serialize}; + +/// A scene, which holds all information required to render a world. +/// +/// This includes all mesh information, and all the information that is required to place +/// instances of these meshes in the world. +#[derive(Clone, Debug, Serialize, Deserialize)] +#[repr(C)] +pub struct Scene { + /// The name of the scene. + pub name: String, + /// The collection of paths to the meshes, relative to the current scene file. + /// This collection is keyed on the ID of the mesh, which can be used later on to place + /// the meshes in the scenes with specific instances. This ID will also be used to register + /// the meshes with the application's registries, which will allow the program to associate + /// specific behavior with the mesh. + pub mesh_paths: HashMap, + /// A collection of instances that are keyed by the mesh's IDs. Each instance can be used to + /// place a [`Mesh`] in the rendered scene. + pub instances: HashMap, +} + +impl Scene { + /// Converts this `Scene` into its byte representation. + pub fn bytes(&self) -> Vec { + postcard::to_allocvec(self) + .expect("Couldn't serialize scene") + } + + /// Reads a `scene` from the given path. Automatically resolves all paths for the meshes that + /// are referenced in the struct. + /// + /// Reading a scene file allows for all meshes to be loaded at once, which therefore allows + /// the program to allocate pipeline buffers just once during the load of this. It would likely + /// be reasonable to create a `MeshRegistry` and `InstanceRegistry` at the same time, with + /// respect to a single loaded `Scene`. + pub fn from_file>(path: P) -> Self { + let path = path.as_ref(); + let mut file = std::fs::File::open(path).unwrap(); + let mut contents = Vec::new(); + let _ = file.read_to_end(&mut contents).unwrap(); + + let mut scene: Self = postcard::from_bytes(contents.as_slice()) + .expect("Couldn't deserialize scene"); + + let base = path.parent().unwrap_or(&Path::new(".")); + scene.mesh_paths = scene.mesh_paths + .into_iter() + .map(|(id, mesh_path)| { + let res = base.join(mesh_path); + let str = res.to_str().unwrap_or_default(); + + (id, str.to_string()) + }).collect::>(); + + scene + } +} + +/// Contains all information about an instance in the scene, specifically the name of the mesh it +/// should use and the translation, rotation, and scale of it. +/// +/// After deserialization, this struct should be converted into an [`Instance`], which contains +/// defined vectors that can be used to work with the object before sending it to the shaders. +#[derive(Clone, Debug, Serialize, Deserialize)] +#[repr(C)] +pub struct SceneInstance { + pub translation: [f32; 3], + pub rotation: [f32; 3], + pub scale: [f32; 3], +} diff --git a/src/gpu/instance.rs b/src/gpu/instance.rs new file mode 100644 index 0000000..229760a --- /dev/null +++ b/src/gpu/instance.rs @@ -0,0 +1,29 @@ +use vulkano::buffer::BufferContents; +use vulkano::pipeline::graphics::vertex_input::Vertex; +use crate::common::instance::MeshInstance; + +/// A transformation matrix for a mesh that can be passed into the shaders. +#[derive(BufferContents, Vertex)] +#[repr(C)] +pub struct GpuInstance { + #[format(R32G32B32A32_SFLOAT)] + pub transform_col1: [f32; 4], + #[format(R32G32B32A32_SFLOAT)] + pub transform_col2: [f32; 4], + #[format(R32G32B32A32_SFLOAT)] + pub transform_col3: [f32; 4], + #[format(R32G32B32A32_SFLOAT)] + pub transform_col4: [f32; 4], +} + +impl Into for MeshInstance { + fn into(self) -> GpuInstance { + let m = self.transform_matrix(); + GpuInstance { + transform_col1: m.column(0).into(), + transform_col2: m.column(1).into(), + transform_col3: m.column(2).into(), + transform_col4: m.column(3).into(), + } + } +} diff --git a/src/gpu/mod.rs b/src/gpu/mod.rs new file mode 100644 index 0000000..c442b22 --- /dev/null +++ b/src/gpu/mod.rs @@ -0,0 +1,2 @@ +pub mod vertex3; +pub mod instance; diff --git a/src/gpu/vertex3.rs b/src/gpu/vertex3.rs new file mode 100644 index 0000000..561fdaa --- /dev/null +++ b/src/gpu/vertex3.rs @@ -0,0 +1,15 @@ +use vulkano::buffer::BufferContents; +use vulkano::pipeline::graphics::vertex_input::Vertex; + +#[derive(Debug, BufferContents, Vertex)] +#[repr(C)] +pub struct Vertex3 { + #[format(R32G32B32_SFLOAT)] + pub(crate) position: [f32; 3], +} + +impl From<&[f32; 3]> for Vertex3 { + fn from(v: &[f32; 3]) -> Self { + Self { position: v.clone() } + } +} diff --git a/src/main.rs b/src/main.rs index 382baa6..8030ae8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ mod app; pub mod math; +mod common; +pub mod gpu; use std::error::Error; use vulkano::swapchain::Surface; diff --git a/src/math/matrix2.rs b/src/math/matrix2.rs index 2ae41a4..b4aafd3 100644 --- a/src/math/matrix2.rs +++ b/src/math/matrix2.rs @@ -1,11 +1,11 @@ -use std::ops::{Add, Div, Index, IndexMut, Mul, Sub}; -use crate::math::traits::Matrix; -use crate::math::Vector2; +use std::ops::{Add, Index, IndexMut, Mul, Sub}; +use crate::math::traits::{Matrix, Vector}; +use crate::math::{Vector2}; #[derive(Clone, Debug, PartialEq, PartialOrd, Copy, Default)] pub struct Matrix2 { - row1: [f32; 2], - row2: [f32; 2], + row1: Vector2, + row2: Vector2, } impl Matrix2 { @@ -29,23 +29,23 @@ impl Matrix2 { } impl Index for Matrix2 { - type Output = [f32; 2]; + type Output = Vector2; - fn index(&self, index: usize) -> &Self::Output { - if index == 0 { - &self.row1 - } else { - &self.row2 + fn index(&self, idx: usize) -> &Self::Output { + match idx { + 0 => &self.row1, + 1 => &self.row2, + _ => panic!("Index out of bounds"), } } } impl IndexMut for Matrix2 { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - if index == 0 { - &mut self.row1 - } else { - &mut self.row2 + fn index_mut(&mut self, idx: usize) -> &mut Self::Output { + match idx { + 0 => &mut self.row1, + 1 => &mut self.row2, + _ => panic!("Index out of bounds"), } } } @@ -55,8 +55,8 @@ impl Add for Matrix2 { fn add(self, rhs: Self) -> Self::Output { Self { - row1: [self[0][0] + rhs[0][0], self[0][1] + rhs[0][1]], - row2: [self[1][0] + rhs[1][0], self[1][1] + rhs[1][1]], + row1: [self[0][0] + rhs[0][0], self[0][1] + rhs[0][1]].into(), + row2: [self[1][0] + rhs[1][0], self[1][1] + rhs[1][1]].into(), } } } @@ -66,19 +66,29 @@ impl Sub for Matrix2 { fn sub(self, rhs: Self) -> Self::Output { Self { - row1: [self[0][0] - rhs[0][0], self[0][1] - rhs[0][1]], - row2: [self[1][0] - rhs[1][0], self[1][1] - rhs[1][1]], + row1: [self[0][0] - rhs[0][0], self[0][1] - rhs[0][1]].into(), + row2: [self[1][0] - rhs[1][0], self[1][1] - rhs[1][1]].into(), } } } impl Mul for Matrix2 { - type Output = Self; - - fn mul(self, rhs: f32) -> Self::Output { + type Output = Matrix2; + fn mul(self, rhs: f32) -> Matrix2 { Self { - row1: [self[0][0] * rhs, self[0][1] * rhs], - row2: [self[1][0] * rhs, self[1][1] * rhs], + row1: self.row1 * rhs, + row2: self.row2 * rhs, + } + } +} + +impl Mul for Matrix2 { + type Output = Vector2; + + fn mul(self, rhs: Vector2) -> Self::Output { + Vector2 { + x: self[0].dot(rhs), + y: self[1].dot(rhs), } } } @@ -95,58 +105,62 @@ impl Mul for Matrix2 { type Output = Self; fn mul(self, rhs: Matrix2) -> Self::Output { + let other = rhs.transpose(); Self { - row1: [self[0][0] * rhs[0][0] + self[0][1] * rhs[1][0], self[0][0] * rhs[0][1] + self[0][1] * rhs[1][1]], - row2: [self[1][0] * rhs[0][0] + self[1][1] * rhs[1][0], self[1][0] * rhs[0][1] + self[1][1] * rhs[1][1]], + row1: [self[0].dot(other[0]), self[0].dot(other[1])].into(), + row2: [self[1].dot(other[0]), self[1].dot(other[1])].into(), } } } -impl Div for Matrix2 { - type Output = Self; - - fn div(self, rhs: f32) -> Self::Output { - todo!() - } -} - -impl Div for Matrix2 { - type Output = Self; - - fn div(self, rhs: Self) -> Self::Output { - todo!() - } -} - -impl Matrix for Matrix2 { +impl Matrix for Matrix2 { fn identity() -> Self { Self { - row1: [1.0, 0.0], - row2: [0.0, 1.0], + row1: [1.0, 0.0].into(), + row2: [0.0, 1.0].into(), } } - fn transpose(self) -> Self { + fn transpose(&self) -> Self { + Self { + row1: [self[0][0], self[1][0]].into(), + row2: [self[0][1], self[1][1]].into(), + } + } + + fn determinant(&self) -> f32 { + self[0][0] * self[1][1] - self[0][1] * self[1][0] + } + + fn minor(&self) -> Self { + Self { + row1: [self[1][1], self[1][0]].into(), + row2: [self[0][1], self[0][0]].into(), + } + } + + fn cofactor(&self) -> Self { + let mut minor = self.minor(); + for row in 0..2 { + for col in 0..2 { + let even = (row + col) % 2 == 0; + if even { + minor[row][col] = -minor[row][col]; + } + } + } + + minor + } + + fn adjugate(&self) -> Self { todo!() } - fn determinant(self) -> f32 { - todo!() - } + fn inverse(&self) -> Self { + let adj = self.adjugate(); + let det = self.determinant(); - fn minor(self) -> Self { - todo!() - } - - fn cofactor(self) -> Self { - todo!() - } - - fn adjugate(self) -> Self { - todo!() - } - - fn inverse(self) -> Self { - todo!() + (1.0 / det) * adj } } diff --git a/src/math/matrix4.rs b/src/math/matrix4.rs index e69de29..2a7afbb 100644 --- a/src/math/matrix4.rs +++ b/src/math/matrix4.rs @@ -0,0 +1,130 @@ +use std::ops::{Add, Div, Mul, Sub}; +use crate::math::traits::{Matrix, Vector}; +use crate::math::Vector4; + +#[derive(Debug, Clone, Default, Copy, PartialEq)] +pub struct Matrix4 { + row1: Vector4, + row2: Vector4, + row3: Vector4, + row4: Vector4, +} + +impl Matrix4 { +} + +impl Add for Matrix4 { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self { + row1: self.row1 + rhs.row1, + row2: self.row2 + rhs.row2, + row3: self.row3 + rhs.row3, + row4: self.row4 + rhs.row4, + } + } +} + +impl Sub for Matrix4 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Self { + row1: self.row1 - rhs.row1, + row2: self.row2 - rhs.row2, + row3: self.row3 - rhs.row3, + row4: self.row4 - rhs.row4, + } + } +} + +impl Div for Matrix4 { + type Output = Self; + + /// Equivalent to multiplying by the reciprocal of `rhs`. + fn div(self, rhs: f32) -> Self::Output { + let rhs = 1.0 / rhs; + self * rhs + } +} + +impl Mul for Matrix4 { + type Output = Self; + + fn mul(self, rhs: f32) -> Self::Output { + Self { + row1: self.row1 * rhs, + row2: self.row2 * rhs, + row3: self.row3 * rhs, + row4: self.row4 * rhs, + } + } +} + +impl Mul for Matrix4 { + type Output = Self; + + fn mul(self, rhs: Self) -> Self { + let rhs = rhs.transpose(); + Self { + row1: [self.row1.dot(rhs.row1), self.row1.dot(rhs.row2), self.row1.dot(rhs.row3), self.row1.dot(rhs.row4)].into(), + row2: [self.row2.dot(rhs.row1), self.row2.dot(rhs.row2), self.row2.dot(rhs.row3), self.row2.dot(rhs.row4)].into(), + row3: [self.row3.dot(rhs.row1), self.row3.dot(rhs.row2), self.row3.dot(rhs.row3), self.row3.dot(rhs.row4)].into(), + row4: [self.row4.dot(rhs.row1), self.row4.dot(rhs.row2), self.row4.dot(rhs.row3), self.row4.dot(rhs.row4)].into(), + } + } +} + +impl Mul for Matrix4 { + type Output = Vector4; + + fn mul(self, rhs: Vector4) -> Vector4 { + Vector4 { + x: self.row1.dot(rhs), + y: self.row2.dot(rhs), + z: self.row3.dot(rhs), + w: self.row4.dot(rhs), + } + } +} + +impl Matrix for Matrix4 { + fn identity() -> Self { + Self { + row1: Vector4::new(1.0, 0.0, 0.0, 0.0), + row2: Vector4::new(0.0, 1.0, 0.0, 0.0), + row3: Vector4::new(0.0, 0.0, 1.0, 0.0), + row4: Vector4::new(0.0, 0.0, 0.0, 1.0), + } + } + + fn transpose(&self) -> Self { + Self { + row1: [self.row1.x, self.row2.x, self.row3.x, self.row4.x].into(), + row2: [self.row1.y, self.row2.y, self.row3.y, self.row4.y].into(), + row3: [self.row1.z, self.row2.z, self.row3.z, self.row4.z].into(), + row4: [self.row1.w, self.row2.w, self.row3.w, self.row4.w].into(), + } + } + + fn determinant(&self) -> f32 { + todo!() + } + + fn minor(&self) -> Self { + todo!() + } + + fn cofactor(&self) -> Self { + todo!() + } + + fn adjugate(&self) -> Self { + todo!() + } + + fn inverse(&self) -> Self { + todo!() + } +} diff --git a/src/math/traits.rs b/src/math/traits.rs index 5b46b54..369ff3b 100644 --- a/src/math/traits.rs +++ b/src/math/traits.rs @@ -1,6 +1,8 @@ use std::ops::{Add, Div, Mul, Sub}; +use crate::math::Vector4; -pub trait Vector: Copy + Default + PartialEq + PartialOrd + Add + Sub + Div + Mul { +pub trait Vector: Clone + Copy + Default + PartialEq + Add + Sub + PartialOrd + + Div + Mul { /// Gets the dot product of the two vectors. fn dot(self, other: Self) -> f32; @@ -26,32 +28,42 @@ pub trait Vector: Copy + Default + PartialEq + PartialOrd + Add + Sub + Div + Div - + Mul + Mul { +/// # Matrix Trait +/// +/// Requires a few manual implementations, specifically the `identity`, `transpose`, and `determinant`. +/// All other information can be found by the trait itself. +/// +/// Note that this trait does not require implementation of the `Div` trait at all - this is because +/// matrices do not have division, only multiplication by a scalar value. This doesn't mean that the +/// scalar cannot be a decimal value, however. +pub trait Matrix: Clone + Copy + Default + PartialEq + Add + Sub + + Mul + Mul + + Mul +where TVec: Vector +{ /// Creates an identity matrix. fn identity() -> Self; /// Gets the transpose of this matrix. - fn transpose(self) -> Self; + fn transpose(&self) -> Self; /// Gets the determinant of this matrix. - fn determinant(self) -> f32; + fn determinant(&self) -> f32; /// Finds the minor of this matrix. The element at location (`i`, `j`) of the minor is the /// determinant of the submatrix obtained by removing row `i` and column `j` in the original /// matrix. - fn minor(self) -> Self; + fn minor(&self) -> Self; /// Finds the cofactor of this matrix. The element at location (`i`, `j`) of the cofactor is /// defined as -1^ij * Mij, where Mij is the element at (`i`, `j`) in the minor of the matrix. /// This is effectively flipping the sign of every other element in the minor of this matrix. - fn cofactor(self) -> Self; + fn cofactor(&self) -> Self; /// Gets the adjugate of this matrix. This is the transpose of the cofactor of this matrix. - fn adjugate(self) -> Self; + fn adjugate(&self) -> Self; /// Gets the inverse of this matrix. Note that this is a very expensive operation and should /// be used as sparingly as possible. - fn inverse(self) -> Self; + fn inverse(&self) -> Self; } diff --git a/src/math/vector2.rs b/src/math/vector2.rs index a5dcbd1..a0715f2 100644 --- a/src/math/vector2.rs +++ b/src/math/vector2.rs @@ -1,4 +1,4 @@ -use std::ops::{Add, Div, Mul, Sub}; +use std::ops::{Add, Div, Mul, Sub, Index, IndexMut}; use crate::math::traits::Vector; #[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd)] @@ -17,6 +17,27 @@ impl Vector2 { } } +impl Index for Vector2 { + type Output = f32; + fn index(&self, idx: usize) -> &f32 { + match idx { + 0 => &self.x, + 1 => &self.y, + _ => panic!("Index out of bounds"), + } + } +} + +impl IndexMut for Vector2 { + fn index_mut(&mut self, idx: usize) -> &mut f32 { + match idx { + 0 => &mut self.x, + 1 => &mut self.y, + _ => panic!("Index out of bounds"), + } + } +} + impl Add for Vector2 { type Output = Self; diff --git a/src/math/vector4.rs b/src/math/vector4.rs index 00aa430..28eb0f2 100644 --- a/src/math/vector4.rs +++ b/src/math/vector4.rs @@ -11,8 +11,24 @@ pub struct Vector4 { } impl Vector4 { - pub fn new() -> Self { - Self::default() + pub fn new( + x: f32, + y: f32, + z: f32, + w: f32, + ) -> Self { + Self { + x, y, z, w + } + } + + pub fn one() -> Self { + Self { + x: 1.0, + y: 1.0, + z: 1.0, + w: 1.0, + } } pub fn xyzw(&self) -> (f32, f32, f32, f32) { @@ -83,6 +99,20 @@ impl Mul for f32 { } } +impl Mul for Vector4 { + type Output = Self; + + /// Computes the Hadamard product of the two vectors. + fn mul(self, rhs: Self) -> Self { + Self { + x: self.x * rhs.x, + y: self.y * rhs.y, + z: self.z * rhs.z, + w: self.w * rhs.w, + } + } +} + impl Div for Vector4 { type Output = Self; @@ -119,12 +149,28 @@ impl Vector for Vector4 { } impl From<[f32; 4]> for Vector4 { - fn from(v: [f32; 4]) -> Self { + fn from([x, y, z, w]: [f32; 4]) -> Self { Self { - x: v[0], - y: v[1], - z: v[2], - w: v[3], + x, y, z, w, + } + } +} + +impl From<[f32; 3]> for Vector4 { + /// Creates a homogenous `Vector4` from a 3D positional vector. + fn from([x, y, z]: [f32; 3]) -> Self { + Self { + x, y, z, + w: 1.0, + } + } +} + +impl From for Vector4 { + fn from(Vector3 { x, y, z }: Vector3) -> Self { + Self { + x, y, z, + w: 1.0 } } } diff --git a/src/shaders/triangle_vert.glsl b/src/shaders/triangle_vert.glsl index 3f7245b..c2c73aa 100644 --- a/src/shaders/triangle_vert.glsl +++ b/src/shaders/triangle_vert.glsl @@ -1,7 +1,7 @@ #version 460 -layout(location = 0) in vec2 position; +layout(location = 0) in vec3 position; void main() { - gl_Position = vec4(position, 0.0, 1.0); + gl_Position = vec4(position, 1.0); }