diff --git a/.gitignore b/.gitignore index 432d6a2..d92e239 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -/shrooms-vb -/shrooms-vb.exe -.vscode -output \ No newline at end of file +/shrooms-vb +/shrooms-vb.exe +.vscode +output +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..a61b2f2 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,3034 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ab_glyph" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" + +[[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 = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "alsa" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" +dependencies = [ + "alsa-sys", + "bitflags 2.6.0", + "cfg-if", + "libc", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "android-activity" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" +dependencies = [ + "android-properties", + "bitflags 2.6.0", + "cc", + "cesu8", + "jni", + "jni-sys", + "libc", + "log", + "ndk 0.9.0", + "ndk-context", + "ndk-sys 0.6.0+11769913", + "num_enum", + "thiserror", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + +[[package]] +name = "anyhow" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + +[[package]] +name = "ascii" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" + +[[package]] +name = "ash" +version = "0.38.0+1.3.281" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.87", +] + +[[package]] +name = "bit-set" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0481a0e032742109b1133a095184ee93d88f3dc9e0d28a5d033dc77a073f44f" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytemuck" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "bytes" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" + +[[package]] +name = "calloop" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" +dependencies = [ + "bitflags 2.6.0", + "log", + "polling", + "rustix", + "slab", + "thiserror", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" +dependencies = [ + "calloop", + "rustix", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "cc" +version = "1.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b9470d453346108f93a59222a9a1a5724db32d0a4727b7ab7ace4b4d822dc9" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chlorine" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e10e7569f6ca78ef7664d7d651115172d4875c4410c050306bccde856a99a49" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "cocoa" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" +dependencies = [ + "bitflags 1.3.2", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-foundation", + "core-graphics-types", + "libc", + "objc", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "com" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6" +dependencies = [ + "com_macros", +] + +[[package]] +name = "com_macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5" +dependencies = [ + "com_macros_support", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "com_macros_support" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "coreaudio-rs" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" +dependencies = [ + "bitflags 1.3.2", + "core-foundation-sys", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ce857aa0b77d77287acc1ac3e37a05a8c95a2af3647d23b15f263bdaeb7562b" +dependencies = [ + "bindgen", +] + +[[package]] +name = "cpal" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" +dependencies = [ + "alsa", + "core-foundation-sys", + "coreaudio-rs", + "dasp_sample", + "jni", + "js-sys", + "libc", + "mach2", + "ndk 0.8.0", + "ndk-context", + "oboe", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows 0.54.0", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "cursor-icon" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" + +[[package]] +name = "d3d12" +version = "22.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdbd1f579714e3c809ebd822c81ef148b1ceaeb3d535352afc73fd0c4c6a0017" +dependencies = [ + "bitflags 2.6.0", + "libloading", + "winapi", +] + +[[package]] +name = "dasp_sample" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", +] + +[[package]] +name = "document-features" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" +dependencies = [ + "litrs", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dpi" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" + +[[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 = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "gethostname" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +dependencies = [ + "libc", + "windows-targets 0.48.5", +] + +[[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 = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "glow" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a4e1951bbd9434a81aa496fe59ccc2235af3820d27b85f9314e279609211e2c" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "gpu-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.6.0", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "gpu-allocator" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd4240fc91d3433d5e5b0fc5b67672d771850dc19bbee03c1381e19322803d7" +dependencies = [ + "log", + "presser", + "thiserror", + "winapi", + "windows 0.52.0", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c08c1f623a8d0b722b8b99f821eb0ba672a1618f0d3b16ddbee1cedd2dd8557" +dependencies = [ + "bitflags 2.6.0", + "gpu-descriptor-types", + "hashbrown 0.14.5", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + +[[package]] +name = "hassle-rs" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" +dependencies = [ + "bitflags 2.6.0", + "com", + "libc", + "libloading", + "thiserror", + "widestring", + "winapi", +] + +[[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.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "imgui" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8addafa5cecf0515812226e806913814e02ce38d10215778082af5174abe5669" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "imgui-sys", + "mint", + "parking_lot", +] + +[[package]] +name = "imgui-sys" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ead193f9f4b60398e8b8f4ab1483e2321640d87aeebdaa3e5f44c55633ccd804" +dependencies = [ + "cc", + "cfg-if", + "chlorine", + "mint", +] + +[[package]] +name = "imgui-wgpu" +version = "0.25.0" +source = "git+https://github.com/Yatekii/imgui-wgpu-rs?rev=2edd348#2edd348a0fc11e9e72f19060c34a6e45c760b116" +dependencies = [ + "bytemuck", + "imgui", + "log", + "smallvec", + "wgpu", +] + +[[package]] +name = "imgui-winit-support" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff7fcccfa9efab56c94274c0fec9939bb14149342b49e6a425883a5b7dda6a3f" +dependencies = [ + "imgui", + "winit", +] + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading", + "pkg-config", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall 0.5.7", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "mach2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +dependencies = [ + "libc", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +dependencies = [ + "libc", +] + +[[package]] +name = "metal" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" +dependencies = [ + "bitflags 2.6.0", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", + "paste", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "mint" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff" + +[[package]] +name = "naga" +version = "22.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd5a652b6faf21496f2cfd88fc49989c8db0825d1f6746b1a71a6ede24a63ad" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags 2.6.0", + "cfg_aliases 0.1.1", + "codespan-reporting", + "hexf-parse", + "indexmap", + "log", + "rustc-hash", + "spirv", + "termcolor", + "thiserror", + "unicode-xid", +] + +[[package]] +name = "native-dialog" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84e7038885d2aeab236bd60da9e159a5967b47cde3292da3b15ff1bec27c039f" +dependencies = [ + "ascii", + "block", + "cocoa", + "core-foundation", + "dirs-next", + "objc", + "objc-foundation", + "objc_id", + "once_cell", + "raw-window-handle 0.5.2", + "thiserror", + "versions", + "wfd", + "which", + "winapi", +] + +[[package]] +name = "ndk" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +dependencies = [ + "bitflags 2.6.0", + "jni-sys", + "log", + "ndk-sys 0.5.0+25.2.9519653", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.6.0", + "jni-sys", + "log", + "ndk-sys 0.6.0+11769913", + "num_enum", + "raw-window-handle 0.6.2", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[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.87", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.6.0", + "block2", + "libc", + "objc2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2", + "objc2", + "objc2-contacts", + "objc2-foundation", +] + +[[package]] +name = "objc2-encode" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.6.0", + "block2", + "dispatch", + "libc", + "objc2", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "oboe" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" +dependencies = [ + "jni", + "ndk 0.8.0", + "ndk-context", + "num-derive", + "num-traits", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d" +dependencies = [ + "cc", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "orbclient" +version = "0.3.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba0b26cec2e24f08ed8bb31519a9333140a6599b867dac464bb150bdb796fd43" +dependencies = [ + "libredox", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.7", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "polling" +version = "3.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "pollster" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" + +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + +[[package]] +name = "primal-check" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0d895b311e3af9902528fbb8f928688abbd95872819320517cc24ca6b2bd08" +dependencies = [ + "num-integer", +] + +[[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.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" + +[[package]] +name = "quick-xml" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "range-alloc" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" + +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "realfft" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "390252372b7f2aac8360fc5e72eba10136b166d6faeed97e6d0c8324eb99b2b1" +dependencies = [ + "rustfft", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +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 = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + +[[package]] +name = "rtrb" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f94e84c073f3b85d4012b44722fa8842b9986d741590d4f2636ad0a5b14143" + +[[package]] +name = "rubato" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd96992d7e24b3d7f35fdfe02af037a356ac90d41b466945cf3333525a86eea" +dependencies = [ + "num-complex", + "num-integer", + "num-traits", + "realfft", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustfft" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43806561bc506d0c5d160643ad742e3161049ac01027b5e6d7524091fd401d86" +dependencies = [ + "num-complex", + "num-integer", + "num-traits", + "primal-check", + "strength_reduce", + "transpose", + "version_check", +] + +[[package]] +name = "rustix" +version = "0.38.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sctk-adwaita" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit", + "tiny-skia", +] + +[[package]] +name = "serde" +version = "1.0.214" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.214" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "shrooms-vb" +version = "0.1.0" +dependencies = [ + "anyhow", + "bitflags 2.6.0", + "bytemuck", + "cc", + "clap", + "cpal", + "imgui", + "imgui-wgpu", + "imgui-winit-support", + "itertools 0.13.0", + "native-dialog", + "num-derive", + "num-traits", + "pollster", + "rtrb", + "rubato", + "thread-priority", + "wgpu", + "winit", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "smithay-client-toolkit" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" +dependencies = [ + "bitflags 2.6.0", + "calloop", + "calloop-wayland-source", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix", + "thiserror", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[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.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "thread-priority" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe075d7053dae61ac5413a34ea7d4913b6e6207844fd726bdd858b37ff72bf5" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "libc", + "log", + "rustversion", + "winapi", +] + +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[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-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" + +[[package]] +name = "transpose" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad61aed86bc3faea4300c7aee358b4c6d0c8d6ccc36524c96e4c92ccf26e77e" +dependencies = [ + "num-integer", + "strength_reduce", +] + +[[package]] +name = "ttf-parser" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5902c5d130972a0000f60860bfbf46f7ca3db5391eddfedd1b8728bd9dc96c0e" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "versions" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c73a36bc44e3039f51fbee93e39f41225f6b17b380eb70cc2aab942df06b34dd" +dependencies = [ + "itertools 0.11.0", + "nom", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.87", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + +[[package]] +name = "wayland-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" +dependencies = [ + "cc", + "downcast-rs", + "rustix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" +dependencies = [ + "bitflags 2.6.0", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-csd-frame" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" +dependencies = [ + "bitflags 2.6.0", + "cursor-icon", + "wayland-backend", +] + +[[package]] +name = "wayland-cursor" +version = "0.31.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b08bc3aafdb0035e7fe0fdf17ba0c09c268732707dca4ae098f60cb28c9e4c" +dependencies = [ + "rustix", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b31cab548ee68c7eb155517f2212049dc151f7cd7910c2b66abfd31c3ee12bd" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "782e12f6cd923c3c316130d56205ebab53f55d6666b7faddfad36cecaeeb4022" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wfd" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e713040b67aae5bf1a0ae3e1ebba8cc29ab2b90da9aa1bff6e09031a8a41d7a8" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "wgpu" +version = "22.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d1c4ba43f80542cf63a0a6ed3134629ae73e8ab51e4b765a67f3aa062eb433" +dependencies = [ + "arrayvec", + "cfg_aliases 0.1.1", + "document-features", + "js-sys", + "log", + "naga", + "parking_lot", + "profiling", + "raw-window-handle 0.6.2", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "22.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0348c840d1051b8e86c3bcd31206080c5e71e5933dabd79be1ce732b0b2f089a" +dependencies = [ + "arrayvec", + "bit-vec", + "bitflags 2.6.0", + "cfg_aliases 0.1.1", + "document-features", + "indexmap", + "log", + "naga", + "once_cell", + "parking_lot", + "profiling", + "raw-window-handle 0.6.2", + "rustc-hash", + "smallvec", + "thiserror", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "22.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6bbf4b4de8b2a83c0401d9e5ae0080a2792055f25859a02bf9be97952bbed4f" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags 2.6.0", + "block", + "cfg_aliases 0.1.1", + "core-graphics-types", + "d3d12", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-allocator", + "gpu-descriptor", + "hassle-rs", + "js-sys", + "khronos-egl", + "libc", + "libloading", + "log", + "metal", + "naga", + "ndk-sys 0.5.0+25.2.9519653", + "objc", + "once_cell", + "parking_lot", + "profiling", + "range-alloc", + "raw-window-handle 0.6.2", + "renderdoc-sys", + "rustc-hash", + "smallvec", + "thiserror", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "winapi", +] + +[[package]] +name = "wgpu-types" +version = "22.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc9d91f0e2c4b51434dfa6db77846f2793149d8e73f800fa2e41f52b8eac3c5d" +dependencies = [ + "bitflags 2.6.0", + "js-sys", + "web-sys", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core 0.52.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" +dependencies = [ + "windows-core 0.54.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winit" +version = "0.30.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0be9e76a1f1077e04a411f0b989cbd3c93339e1771cb41e71ac4aee95bfd2c67" +dependencies = [ + "ahash", + "android-activity", + "atomic-waker", + "bitflags 2.6.0", + "block2", + "bytemuck", + "calloop", + "cfg_aliases 0.2.1", + "concurrent-queue", + "core-foundation", + "core-graphics", + "cursor-icon", + "dpi", + "js-sys", + "libc", + "memmap2", + "ndk 0.9.0", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "orbclient", + "percent-encoding", + "pin-project", + "raw-window-handle 0.6.2", + "redox_syscall 0.4.1", + "rustix", + "sctk-adwaita", + "smithay-client-toolkit", + "smol_str", + "tracing", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "web-sys", + "web-time", + "windows-sys 0.52.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading", + "once_cell", + "rustix", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" + +[[package]] +name = "xcursor" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.6.0", + "dlib", + "log", + "once_cell", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + +[[package]] +name = "xml-rs" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" + +[[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.87", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..73f97d5 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "shrooms-vb" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1" +bitflags = "2" +bytemuck = { version = "1", features = ["derive"] } +clap = { version = "4", features = ["derive"] } +cpal = "0.15" +imgui = { version = "0.12", features = ["tables-api"] } +imgui-wgpu = { git = "https://github.com/Yatekii/imgui-wgpu-rs", rev = "2edd348" } +imgui-winit-support = "0.13" +itertools = "0.13" +native-dialog = "0.7" +num-derive = "0.4" +num-traits = "0.2" +pollster = "0.4" +rtrb = "0.3" +rubato = "0.16" +thread-priority = "1" +wgpu = "22.1" +winit = "0.30" + +[build-dependencies] +cc = "1" + +[profile.release] +lto = true \ No newline at end of file diff --git a/README.md b/README.md index 35758eb..1f18a68 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ # Shrooms VB (native) -An SDL-based implementation of shrooms-vb. +A native implementation of shrooms-vb. Written in Rust, using winit, wgpu, and Dear ImGui. Should run on any major OS. ## Setup Install the following dependencies: - - `gcc` (or MinGW on Windows) (or whatever, just set `CC`) - - `pkg-config` - - sdl2 + - `cargo` Run ```sh -make build -``` \ No newline at end of file +cargo build --release +``` + +The executable will be in `target/release/shrooms-vb[.exe]` \ No newline at end of file diff --git a/assets.h b/assets.h deleted file mode 100644 index 3d8d26d..0000000 --- a/assets.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef SHROOMS_VB_NATIVE_ASSETS_ -#define SHROOMS_VB_NATIVE_ASSETS_ - -#include - -extern const uint8_t _binary_assets_lefteye_bin_start; -const uint8_t *LEFT_EYE_DEFAULT = &_binary_assets_lefteye_bin_start; - -extern const uint8_t _binary_assets_righteye_bin_start; -const uint8_t *RIGHT_EYE_DEFAULT = &_binary_assets_righteye_bin_start; - -#endif diff --git a/assets/lefteye.bin b/assets/lefteye.bin deleted file mode 100644 index f17761d..0000000 Binary files a/assets/lefteye.bin and /dev/null differ diff --git a/assets/righteye.bin b/assets/righteye.bin deleted file mode 100644 index d323a3c..0000000 Binary files a/assets/righteye.bin and /dev/null differ diff --git a/assets/selawk.ttf b/assets/selawk.ttf new file mode 100644 index 0000000..736bac3 Binary files /dev/null and b/assets/selawk.ttf differ diff --git a/audio.c b/audio.c deleted file mode 100644 index 169886e..0000000 --- a/audio.c +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include - -void audioCallback(void *userdata, uint8_t *stream, int len) { - AudioContext *aud; - SDL_assert(len == 834 * 4); - - aud = userdata; - if (!aud->filled) { - /* too little data, play silence */ - SDL_memset4(stream, 0, 834); - return; - } - SDL_memcpy4(stream, aud->buffers[aud->current], 834); - ++aud->current; - aud->current %= 2; - aud->filled -= 1; -} - -int audioInit(AudioContext *aud) { - SDL_AudioSpec spec; - spec.freq = 41700; - spec.format = AUDIO_S16; - spec.channels = 2; - spec.samples = 834; - spec.callback = &audioCallback; - spec.userdata = aud; - - aud->id = SDL_OpenAudioDevice(NULL, 0, &spec, NULL, 0); - aud->paused = true; - if (!aud->id) { - fprintf(stderr, "could not open audio device: %s\n", SDL_GetError()); - return -1; - } - aud->current = 0; - aud->filled = 0; - return 0; -} - -int audioUpdate(AudioContext *aud, void *data, uint32_t bytes) { - int filled; - if (!aud->id) return -1; - SDL_assert(bytes == 834 * 4); - - SDL_LockAudioDevice(aud->id); - if (aud->filled < 2) { - int next = (aud->current + aud->filled) % 2; - SDL_memcpy4(aud->buffers[next], data, bytes / 4); - aud->filled += 1; - } - filled = aud->filled; - SDL_UnlockAudioDevice(aud->id); - - if (aud->paused) { - SDL_PauseAudioDevice(aud->id, false); - aud->paused = false; - } - - while (filled > 1) { - SDL_Delay(0); - filled = aud->filled; - } - - return 0; -} \ No newline at end of file diff --git a/audio.h b/audio.h deleted file mode 100644 index 644724f..0000000 --- a/audio.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef SHROOMS_VB_NATIVE_AUDIO_ -#define SHROOMS_VB_NATIVE_AUDIO_ - -#include -#include - -typedef struct { - SDL_AudioDeviceID id; - bool paused; - uint32_t buffers[2][834]; - int current; - int filled; -} AudioContext; - -int audioInit(AudioContext *aud); -int audioUpdate(AudioContext *aud, void *data, uint32_t bytes); - -#endif \ No newline at end of file diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..17bd565 --- /dev/null +++ b/build.rs @@ -0,0 +1,12 @@ +use std::path::Path; + +fn main() { + println!("cargo::rerun-if-changed=shrooms-vb-core"); + cc::Build::new() + .include(Path::new("shrooms-vb-core/core")) + .opt_level(2) + .flag_if_supported("-flto") + .flag_if_supported("-fno-strict-aliasing") + .file(Path::new("shrooms-vb-core/core/vb.c")) + .compile("vb"); +} diff --git a/cli.c b/cli.c deleted file mode 100644 index 7328a09..0000000 --- a/cli.c +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include - -int parseCLIArgs(int argc, char **argv, CLIArgs *args) { - if (argc != 2) { - fprintf(stderr, "usage: %s /path/to/rom.vb\n", argv[0]); - return 1; - } - args->filename = argv[1]; - return 0; -} \ No newline at end of file diff --git a/cli.h b/cli.h deleted file mode 100644 index 580265d..0000000 --- a/cli.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef SHROOMS_VB_NATIVE_CLI_ -#define SHROOMS_VB_NATIVE_CLI_ - -typedef struct { - char *filename; -} CLIArgs; - -int parseCLIArgs(int argc, char **argv, CLIArgs *args); - -#endif \ No newline at end of file diff --git a/controller.c b/controller.c deleted file mode 100644 index 54979a4..0000000 --- a/controller.c +++ /dev/null @@ -1,65 +0,0 @@ -#include - -#define VB_PWR 0x0001 -#define VB_SGN 0x0002 -#define VB_A 0x0004 -#define VB_B 0x0008 -#define VB_RT 0x0010 -#define VB_LT 0x0020 -#define VB_RU 0x0040 -#define VB_RR 0x0080 -#define VB_LR 0x0100 -#define VB_LL 0x0200 -#define VB_LD 0x0400 -#define VB_LU 0x0800 -#define VB_STA 0x1000 -#define VB_SEL 0x2000 -#define VB_RL 0x4000 -#define VB_RD 0x8000 - -static uint16_t symToMask(SDL_KeyCode sym) { - switch (sym) { - default: return 0; - case SDLK_a: - return VB_SEL; - case SDLK_s: - return VB_STA; - case SDLK_d: - return VB_B; - case SDLK_f: - return VB_A; - case SDLK_e: - return VB_LT; - case SDLK_r: - return VB_RT; - case SDLK_i: - return VB_RU; - case SDLK_j: - return VB_RL; - case SDLK_k: - return VB_RD; - case SDLK_l: - return VB_RR; - case SDLK_UP: - return VB_LU; - case SDLK_LEFT: - return VB_LL; - case SDLK_DOWN: - return VB_LD; - case SDLK_RIGHT: - return VB_LR; - } -} - -void ctrlInit(ControllerState *ctrl) { - ctrl->keys = VB_SGN; -} -void ctrlKeyDown(ControllerState *ctrl, SDL_Keycode sym) { - ctrl->keys |= symToMask(sym); -} -void ctrlKeyUp(ControllerState *ctrl, SDL_Keycode sym) { - ctrl->keys &= ~symToMask(sym); -} -uint16_t ctrlKeys(ControllerState *ctrl) { - return ctrl->keys; -} \ No newline at end of file diff --git a/controller.h b/controller.h deleted file mode 100644 index fe9dabe..0000000 --- a/controller.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef SHROOMS_VB_NATIVE_CONTROLLER_ -#define SHROOMS_VB_NATIVE_CONTROLLER_ - -#include -#include - -typedef struct { - uint16_t keys; -} ControllerState; - -void ctrlInit(ControllerState *ctrl); -void ctrlKeyDown(ControllerState *ctrl, SDL_Keycode sym); -void ctrlKeyUp(ControllerState *ctrl, SDL_Keycode sym); -uint16_t ctrlKeys(ControllerState *ctrl); - -#endif \ No newline at end of file diff --git a/game.c b/game.c deleted file mode 100644 index 3461611..0000000 --- a/game.c +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -typedef struct { - GraphicsContext *gfx; - AudioContext aud; - int16_t audioBuffer[834 * 2]; -} GameState; - -int onFrame(VB *sim) { - static uint8_t leftEye[384*224]; - static uint8_t rightEye[384*224]; - GameState *state; - void *samples; - uint32_t samplePairs; - - state = vbGetUserData(sim); - - vbGetPixels(sim, leftEye, 1, 384, rightEye, 1, 384); - gfxUpdateLeftEye(state->gfx, leftEye); - gfxUpdateRightEye(state->gfx, rightEye); - - samples = vbGetSamples(sim, NULL, NULL, &samplePairs); - audioUpdate(&state->aud, samples, samplePairs * 4); - vbSetSamples(sim, samples, VB_S16, 834); - gfxRender(state->gfx); - return 1; -} - -#define MAX_STEP_CLOCKS 20000000 - -int runGame(VB *sim, GraphicsContext *gfx) { - uint32_t clocks; - SDL_Event event; - GameState state; - ControllerState ctrl; - - state.gfx = gfx; - audioInit(&state.aud); - vbSetSamples(sim, &state.audioBuffer, VB_S16, 834); - vbSetUserData(sim, &state); - vbSetFrameCallback(sim, &onFrame); - - ctrlInit(&ctrl); - - gfxUpdateLeftEye(gfx, LEFT_EYE_DEFAULT); - gfxUpdateRightEye(gfx, RIGHT_EYE_DEFAULT); - - while (1) { - clocks = MAX_STEP_CLOCKS; - vbEmulate(sim, &clocks); - - while (SDL_PollEvent(&event)) { - if (event.type == SDL_QUIT) { - return 0; - } - if (event.type == SDL_KEYDOWN) { - ctrlKeyDown(&ctrl, event.key.keysym.sym); - } - if (event.type == SDL_KEYUP) { - ctrlKeyUp(&ctrl, event.key.keysym.sym); - } - } - vbSetKeys(sim, ctrlKeys(&ctrl)); - } -} diff --git a/game.h b/game.h deleted file mode 100644 index 9984eea..0000000 --- a/game.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef SHROOMS_VB_NATIVE_GAME_ -#define SHROOMS_VB_NATIVE_GAME_ - -#include "graphics.h" -#include "shrooms-vb-core/core/vb.h" - -int runGame(VB *sim, GraphicsContext *gfx); - -#endif \ No newline at end of file diff --git a/graphics.c b/graphics.c deleted file mode 100644 index 9aa589c..0000000 --- a/graphics.c +++ /dev/null @@ -1,92 +0,0 @@ -#include - -static void copyScreenTexture(uint8_t *dst, const uint8_t *src, int pitch) { - int x, y, i; - uint8_t color; - int delta = pitch / 384; - for (y = 0; y < 224; ++y) { - for (x = 0; x < 384; x += 1) { - color = src[(y * 384) + x]; - for (i = 0; i < delta; ++i) { - dst[(y * pitch) + (x * delta) + i] = color; - } - } - } -} - -int gfxInit(GraphicsContext *gfx) { - gfx->window = SDL_CreateWindow("Shrooms VB", - SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - 1536, 896, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI); - if (!gfx->window) { - fprintf(stderr, "Error creating window: %s\n", SDL_GetError()); - return 1; - } - - gfx->renderer = SDL_CreateRenderer(gfx->window, -1, 0); - if (!gfx->renderer) { - fprintf(stderr, "Error creating renderer: %s\n", SDL_GetError()); - goto cleanup_window; - } - - gfx->winSurface = SDL_GetWindowSurface(gfx->window); - if (!gfx->winSurface) { - fprintf(stderr, "Error getting surface: %s\n", SDL_GetError()); - goto cleanup_window; - } - - gfx->leftEye = SDL_CreateTexture(gfx->renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, 384, 224); - if (!gfx->leftEye) { - fprintf(stderr, "Error creating left eye texture: %s\n", SDL_GetError()); - goto cleanup_window; - } - SDL_SetTextureColorMod(gfx->leftEye, 0xff, 0, 0); - - gfx->rightEye = SDL_CreateTexture(gfx->renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, 384, 224); - if (!gfx->rightEye) { - fprintf(stderr, "Error creating left eye texture: %s\n", SDL_GetError()); - goto cleanup_left_eye; - } - SDL_SetTextureColorMod(gfx->rightEye, 0, 0xc6, 0xf0); - SDL_SetTextureBlendMode(gfx->rightEye, SDL_BLENDMODE_ADD); - - return 0; - -cleanup_left_eye: - SDL_DestroyTexture(gfx->leftEye); -cleanup_window: - SDL_DestroyWindow(gfx->window); - return 1; -} - -void gfxDestroy(GraphicsContext *gfx) { - SDL_DestroyTexture(gfx->rightEye); - SDL_DestroyTexture(gfx->leftEye); - SDL_DestroyWindow(gfx->window); -} - -static void gfxUpdateEye(SDL_Texture *eye, const uint8_t *bytes) { - void *target; - int pitch; - if (SDL_LockTexture(eye, NULL, &target, &pitch)) { - fprintf(stderr, "Error locking buffer for eye: %s\n", SDL_GetError()); - return; - } - copyScreenTexture(target, bytes, pitch); - SDL_UnlockTexture(eye); -} - -void gfxUpdateLeftEye(GraphicsContext *gfx, const uint8_t *bytes) { - gfxUpdateEye(gfx->leftEye, bytes); -} -void gfxUpdateRightEye(GraphicsContext *gfx, const uint8_t *bytes) { - gfxUpdateEye(gfx->rightEye, bytes); -} - -void gfxRender(GraphicsContext *gfx) { - SDL_RenderClear(gfx->renderer); - SDL_RenderCopy(gfx->renderer, gfx->leftEye, NULL, NULL); - SDL_RenderCopy(gfx->renderer, gfx->rightEye, NULL, NULL); - SDL_RenderPresent(gfx->renderer); -} - diff --git a/graphics.h b/graphics.h deleted file mode 100644 index aa4485b..0000000 --- a/graphics.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef SHROOMS_VB_NATIVE_GRAPHICS_ -#define SHROOMS_VB_NATIVE_GRAPHICS_ - -#include - -typedef struct { - SDL_Window *window; - SDL_Surface *winSurface; - SDL_Renderer *renderer; - SDL_Texture *leftEye; - SDL_Texture *rightEye; -} GraphicsContext; - -int gfxInit(GraphicsContext *gfx); -void gfxDestroy(GraphicsContext *gfx); - -void gfxUpdateLeftEye(GraphicsContext *gfx, const uint8_t *bytes); -void gfxUpdateRightEye(GraphicsContext *gfx, const uint8_t *bytes); - -void gfxRender(GraphicsContext *gfx); - -#endif diff --git a/main.c b/main.c deleted file mode 100644 index eb7eedf..0000000 --- a/main.c +++ /dev/null @@ -1,85 +0,0 @@ -#include -#include -#include -#include -#include "shrooms-vb-core/core/vb.h" -#include - -uint8_t *readROM(char *filename, uint32_t *size) { - FILE *file = fopen(filename, "rb"); - uint8_t *rom; - long filesize; - - if (!file) { - perror("could not open file"); - return NULL; - } - - if (fseek(file, 0, SEEK_END)) { - perror("could not seek file end"); - return NULL; - } - filesize = ftell(file); - if (filesize == -1) { - perror("could not read file size"); - return NULL; - } - if (fseek(file, 0, SEEK_SET)) { - perror("could not seek file start"); - return NULL; - } - - *size = (uint32_t) filesize; - rom = malloc(*size); - if (!rom) { - perror("could not allocate ROM"); - return NULL; - } - fread(rom, 1, *size, file); - if (ferror(file)) { - perror("could not read file"); - return NULL; - } - if (fclose(file)) { - perror("could not close file"); - return NULL; - } - - return rom; -} - -int main(int argc, char **argv) { - VB *sim; - uint8_t *rom; - uint32_t romSize; - GraphicsContext gfx; - CLIArgs args; - int status; - - if (parseCLIArgs(argc, argv, &args)) { - return 1; - } - - rom = readROM(args.filename, &romSize); - if (!rom) { - return 1; - } - - sim = malloc(vbSizeOf()); - vbInit(sim); - vbSetCartROM(sim, rom, romSize); - - if (SDL_Init(SDL_INIT_EVERYTHING)) { - fprintf(stderr, "Error initializing SDL: %s\n", SDL_GetError()); - return 1; - } - - if (gfxInit(&gfx)) { - SDL_Quit(); - return 1; - } - - status = runGame(sim, &gfx); - SDL_Quit(); - return status; -} diff --git a/makefile b/makefile deleted file mode 100644 index 71115dc..0000000 --- a/makefile +++ /dev/null @@ -1,48 +0,0 @@ -CC?=gcc -LD?=ld -SHROOMSFLAGS=shrooms-vb-core/core/vb.c -I shrooms-vb-core/core -msys_version := $(if $(findstring Msys, $(shell uname -o)),$(word 1, $(subst ., ,$(shell uname -r))),0) - -ifeq ($(msys_version), 0) -SDL2FLAGS=$(shell pkg-config sdl2 --cflags --libs) -BINLINKFLAGS=-z noexecstack -else -SDL2FLAGS=$(shell pkg-config sdl2 --cflags --libs) -mwindows -mconsole -BINLINKFLAGS= -endif - -.PHONY: clean build -clean: - @rm -rf shrooms-vb output - -CFILES := $(foreach dir,./,$(notdir $(wildcard $(dir)/*.c))) -BINFILES := $(foreach dir,assets/,$(notdir $(wildcard $(dir)/*.bin))) - -COBJS := $(CFILES:%.c=output/%.o) -SHROOMSOBJS := output/vb.o -BINOBJS := $(BINFILES:%.bin=output/%.o) - -OFILES := $(COBJS) $(SHROOMSOBJS) $(BINOBJS) - -output/%.o: %.c - @mkdir -p output - @$(CC) -c -o $@ $< -I . \ - -I shrooms-vb-core/core $(SDL2FLAGS) \ - -O3 -flto -fno-strict-aliasing \ - -Werror -std=c90 -Wall -Wextra -Wpedantic - -output/vb.o: shrooms-vb-core/core/vb.c - @mkdir -p output - @$(CC) -c -o $@ $< -I . \ - -I shrooms-vb-core/core $(SDL2FLAGS) \ - -O3 -flto -fno-strict-aliasing \ - -Werror -std=c90 -Wall -Wextra -Wpedantic - -output/%.o: assets/%.bin - @mkdir -p output - @$(LD) -r -b binary $(BINLINKFLAGS) -o $@ $< - -shrooms-vb: $(OFILES) - @$(CC) -o $@ $(OFILES) $(SDL2FLAGS) -flto - -build: shrooms-vb \ No newline at end of file diff --git a/src/anaglyph.wgsl b/src/anaglyph.wgsl new file mode 100644 index 0000000..0483665 --- /dev/null +++ b/src/anaglyph.wgsl @@ -0,0 +1,55 @@ +// Vertex shader + +struct VertexOutput { + @builtin(position) clip_position: vec4, + @location(0) tex_coords: vec2, +}; + +@vertex +fn vs_main( + @builtin(vertex_index) in_vertex_index: u32, +) -> VertexOutput { + var out: VertexOutput; + var x: f32; + var y: f32; + switch in_vertex_index { + case 0u, 3u: { + x = -1.0; + y = 1.0; + } + case 1u: { + x = -1.0; + y = -1.0; + } + case 2u, 4u: { + x = 1.0; + y = -1.0; + } + default: { + x = 1.0; + y = 1.0; + } + } + out.clip_position = vec4(x, y, 0.0, 1.0); + out.tex_coords = vec2((x + 1.0) / 2.0, (1.0 - y) / 2.0); + return out; +} + +// Fragment shader +@group(0) @binding(0) +var u_texture: texture_2d; +@group(0) @binding(1) +var u_sampler: sampler; + +struct Colors { + left: vec4, + right: vec4, +}; +@group(0) @binding(2) +var colors: Colors; + +@fragment +fn fs_main(in: VertexOutput) -> @location(0) vec4 { + let brt = textureSample(u_texture, u_sampler, in.tex_coords); + return colors.left * brt[0] + colors.right * brt[1]; +} diff --git a/src/app.rs b/src/app.rs new file mode 100644 index 0000000..a5d62ac --- /dev/null +++ b/src/app.rs @@ -0,0 +1,131 @@ +use std::{ + collections::HashMap, + fmt::Debug, + sync::{Arc, RwLock}, +}; + +use game::GameWindow; +use winit::{ + application::ApplicationHandler, + event::{Event, WindowEvent}, + event_loop::{ActiveEventLoop, EventLoopProxy}, + window::WindowId, +}; + +use crate::{ + controller::ControllerState, + emulator::{EmulatorClient, EmulatorCommand}, + input::InputMapper, +}; + +mod common; +mod game; +mod input; + +pub struct App { + windows: HashMap>, + client: EmulatorClient, + input_mapper: Arc>, + controller: ControllerState, + proxy: EventLoopProxy, +} + +impl App { + pub fn new(client: EmulatorClient, proxy: EventLoopProxy) -> Self { + let input_mapper = Arc::new(RwLock::new(InputMapper::new())); + let controller = ControllerState::new(input_mapper.clone()); + Self { + windows: HashMap::new(), + client, + input_mapper, + controller, + proxy, + } + } +} + +impl ApplicationHandler for App { + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + let mut window = GameWindow::new( + event_loop, + self.client.clone(), + self.input_mapper.clone(), + self.proxy.clone(), + ); + window.init(); + self.windows.insert(window.id(), Box::new(window)); + } + + fn window_event( + &mut self, + event_loop: &ActiveEventLoop, + window_id: WindowId, + event: WindowEvent, + ) { + if let WindowEvent::KeyboardInput { event, .. } = &event { + if self.controller.key_event(event) { + self.client + .send_command(EmulatorCommand::SetKeys(self.controller.pressed())); + } + } + let Some(window) = self.windows.get_mut(&window_id) else { + return; + }; + window.handle_event(event_loop, &Event::WindowEvent { window_id, event }); + } + + fn user_event(&mut self, _event_loop: &ActiveEventLoop, event: UserEvent) { + match event { + UserEvent::OpenWindow(mut window) => { + window.init(); + self.windows.insert(window.id(), window); + } + UserEvent::CloseWindow(window_id) => { + self.windows.remove(&window_id); + } + } + } + + fn device_event( + &mut self, + event_loop: &ActiveEventLoop, + device_id: winit::event::DeviceId, + event: winit::event::DeviceEvent, + ) { + for window in self.windows.values_mut() { + window.handle_event( + event_loop, + &Event::DeviceEvent { + device_id, + event: event.clone(), + }, + ); + } + } + + fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) { + for window in self.windows.values_mut() { + window.handle_event(event_loop, &Event::AboutToWait); + } + } +} + +pub trait AppWindow { + fn id(&self) -> WindowId; + fn init(&mut self); + fn handle_event(&mut self, event_loop: &ActiveEventLoop, event: &Event); +} + +pub enum UserEvent { + OpenWindow(Box), + CloseWindow(WindowId), +} + +impl Debug for UserEvent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::OpenWindow(window) => f.debug_tuple("OpenWindow").field(&window.id()).finish(), + Self::CloseWindow(window_id) => f.debug_tuple("CloseWindow").field(window_id).finish(), + } + } +} diff --git a/src/app/common.rs b/src/app/common.rs new file mode 100644 index 0000000..396acb2 --- /dev/null +++ b/src/app/common.rs @@ -0,0 +1,264 @@ +use std::{ + ops::{Deref, DerefMut}, + sync::Arc, + time::Instant, +}; + +use imgui::{FontSource, MouseCursor, SuspendedContext, WindowToken}; +use imgui_wgpu::{Renderer, RendererConfig}; +use imgui_winit_support::WinitPlatform; +use pollster::block_on; +#[cfg(target_os = "windows")] +use winit::platform::windows::{CornerPreference, WindowAttributesExtWindows as _}; +use winit::{ + dpi::{LogicalSize, PhysicalSize, Size}, + event_loop::ActiveEventLoop, + window::{Window, WindowAttributes}, +}; + +pub struct WindowStateBuilder<'a> { + event_loop: &'a ActiveEventLoop, + attributes: WindowAttributes, +} +impl<'a> WindowStateBuilder<'a> { + pub fn new(event_loop: &'a ActiveEventLoop) -> Self { + let attributes = Window::default_attributes(); + #[cfg(target_os = "windows")] + let attributes = attributes.with_corner_preference(CornerPreference::DoNotRound); + Self { + event_loop, + attributes, + } + } + + pub fn with_title>(self, title: T) -> Self { + Self { + attributes: self.attributes.with_title(title), + ..self + } + } + + pub fn with_inner_size>(self, size: S) -> Self { + Self { + attributes: self.attributes.with_inner_size(size), + ..self + } + } + + pub fn build(self) -> WindowState { + WindowState::new(self.event_loop, self.attributes) + } +} + +#[derive(Debug)] +pub struct WindowState { + pub device: wgpu::Device, + pub queue: Arc, + pub window: Arc, + pub surface_desc: wgpu::SurfaceConfiguration, + pub surface: wgpu::Surface<'static>, + pub hidpi_factor: f64, + pub minimized: bool, +} + +impl WindowState { + fn new(event_loop: &ActiveEventLoop, attributes: WindowAttributes) -> Self { + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends: wgpu::Backends::PRIMARY, + ..Default::default() + }); + + let window = Arc::new(event_loop.create_window(attributes).unwrap()); + + let size = window.inner_size(); + let hidpi_factor = window.scale_factor(); + let surface = instance.create_surface(window.clone()).unwrap(); + + let adapter = block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::HighPerformance, + compatible_surface: Some(&surface), + force_fallback_adapter: false, + })) + .unwrap(); + + let (device, queue) = + block_on(adapter.request_device(&wgpu::DeviceDescriptor::default(), None)).unwrap(); + let queue = Arc::new(queue); + + // Set up swap chain + let surface_desc = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: wgpu::TextureFormat::Bgra8UnormSrgb, + width: size.width, + height: size.height, + present_mode: wgpu::PresentMode::Fifo, + desired_maximum_frame_latency: 2, + alpha_mode: wgpu::CompositeAlphaMode::Auto, + view_formats: vec![wgpu::TextureFormat::Bgra8Unorm], + }; + + surface.configure(&device, &surface_desc); + + Self { + device, + queue, + window, + surface_desc, + surface, + hidpi_factor, + minimized: false, + } + } + + pub fn logical_size(&self) -> LogicalSize { + PhysicalSize::new(self.surface_desc.width, self.surface_desc.height) + .to_logical(self.hidpi_factor) + } + + pub fn handle_resize(&mut self, size: &PhysicalSize) { + if size.width > 0 && size.height > 0 { + self.minimized = false; + self.surface_desc.width = size.width; + self.surface_desc.height = size.height; + self.surface.configure(&self.device, &self.surface_desc); + } else { + self.minimized = true; + } + } +} + +pub struct ImguiState { + pub context: ContextGuard, + pub platform: WinitPlatform, + pub renderer: Renderer, + pub clear_color: wgpu::Color, + pub last_frame: Instant, + pub last_cursor: Option, +} +impl ImguiState { + pub fn new(window: &WindowState) -> Self { + let mut context_guard = ContextGuard::new(); + let mut context = context_guard.lock().unwrap(); + + let mut platform = imgui_winit_support::WinitPlatform::new(&mut context); + platform.attach_window( + context.io_mut(), + &window.window, + imgui_winit_support::HiDpiMode::Default, + ); + context.set_ini_filename(None); + + let font_size = (16.0 * window.hidpi_factor) as f32; + context.io_mut().font_global_scale = (1.0 / window.hidpi_factor) as f32; + + context.fonts().add_font(&[FontSource::TtfData { + data: include_bytes!("../../assets/selawk.ttf"), + size_pixels: font_size, + config: Some(imgui::FontConfig { + oversample_h: 1, + pixel_snap_h: true, + size_pixels: font_size, + ..Default::default() + }), + }]); + + let style = context.style_mut(); + style.use_light_colors(); + + // + // Set up dear imgui wgpu renderer + // + let renderer_config = RendererConfig { + texture_format: window.surface_desc.format, + ..Default::default() + }; + + let renderer = Renderer::new(&mut context, &window.device, &window.queue, renderer_config); + + let last_frame = Instant::now(); + let last_cursor = None; + + drop(context); + Self { + context: context_guard, + platform, + renderer, + clear_color: wgpu::Color::BLACK, + last_frame, + last_cursor, + } + } +} + +pub struct ContextGuard { + value: Option, +} + +impl ContextGuard { + fn new() -> Self { + Self { + value: Some(SuspendedContext::create()), + } + } + + pub fn lock(&mut self) -> Option> { + let sus = self.value.take()?; + match sus.activate() { + Ok(ctx) => Some(ContextLock { + ctx: Some(ctx), + holder: self, + }), + Err(sus) => { + self.value = Some(sus); + None + } + } + } +} + +pub struct ContextLock<'a> { + ctx: Option, + holder: &'a mut ContextGuard, +} + +impl<'a> Deref for ContextLock<'a> { + type Target = imgui::Context; + fn deref(&self) -> &Self::Target { + self.ctx.as_ref().unwrap() + } +} + +impl<'a> DerefMut for ContextLock<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.ctx.as_mut().unwrap() + } +} + +impl<'a> Drop for ContextLock<'a> { + fn drop(&mut self) { + self.holder.value = self.ctx.take().map(|c| c.suspend()) + } +} + +pub trait UiExt { + fn fullscreen_window(&self) -> Option>; + fn right_align_text>(&self, text: T, space: f32); +} + +impl UiExt for imgui::Ui { + fn fullscreen_window(&self) -> Option> { + self.window("fullscreen") + .position([0.0, 0.0], imgui::Condition::Always) + .size(self.io().display_size, imgui::Condition::Always) + .flags(imgui::WindowFlags::NO_DECORATION) + .begin() + } + + fn right_align_text>(&self, text: T, space: f32) { + let width = self.calc_text_size(text.as_ref())[0]; + let [left, y] = self.cursor_pos(); + let right = left + space; + self.set_cursor_pos([right - width, y]); + self.text(text); + } +} diff --git a/src/app/game.rs b/src/app/game.rs new file mode 100644 index 0000000..efbeae0 --- /dev/null +++ b/src/app/game.rs @@ -0,0 +1,384 @@ +use std::{ + sync::{Arc, RwLock}, + time::Instant, +}; +use wgpu::util::DeviceExt as _; +use winit::{ + dpi::LogicalSize, + event::{Event, WindowEvent}, + event_loop::{ActiveEventLoop, EventLoopProxy}, + window::WindowId, +}; + +use crate::{ + emulator::{EmulatorClient, EmulatorCommand}, + input::InputMapper, + renderer::GameRenderer, +}; + +use super::{ + common::{ImguiState, WindowState, WindowStateBuilder}, + input::InputWindow, + AppWindow, UserEvent, +}; + +pub struct GameWindow { + window: WindowState, + imgui: Option, + pipeline: wgpu::RenderPipeline, + bind_group: wgpu::BindGroup, + client: EmulatorClient, + input_mapper: Arc>, + proxy: EventLoopProxy, + paused_due_to_minimize: bool, +} + +impl GameWindow { + pub fn new( + event_loop: &ActiveEventLoop, + client: EmulatorClient, + input_mapper: Arc>, + proxy: EventLoopProxy, + ) -> Self { + let window = WindowStateBuilder::new(event_loop) + .with_title("Shrooms VB") + .with_inner_size(LogicalSize::new(384, 244)) + .build(); + let device = &window.device; + + let eyes = Arc::new(GameRenderer::create_texture(device, "eye")); + client.send_command(EmulatorCommand::SetRenderer(GameRenderer { + queue: window.queue.clone(), + eyes: eyes.clone(), + })); + let eyes = eyes.create_view(&wgpu::TextureViewDescriptor::default()); + let sampler = device.create_sampler(&wgpu::SamplerDescriptor::default()); + let colors = Colors { + left: [1.0, 0.0, 0.0, 1.0], + right: [0.0, 0.7734375, 0.9375, 1.0], + }; + let color_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("colors"), + contents: bytemuck::bytes_of(&colors), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }); + let texture_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("texture bind group layout"), + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 2, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, + ], + }); + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("bind group"), + layout: &texture_bind_group_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&eyes), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&sampler), + }, + wgpu::BindGroupEntry { + binding: 2, + resource: color_buf.as_entire_binding(), + }, + ], + }); + + let shader = device.create_shader_module(wgpu::include_wgsl!("../anaglyph.wgsl")); + let render_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("render pipeline layout"), + bind_group_layouts: &[&texture_bind_group_layout], + push_constant_ranges: &[], + }); + let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("render pipeline"), + layout: Some(&render_pipeline_layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + buffers: &[], + compilation_options: wgpu::PipelineCompilationOptions::default(), + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + targets: &[Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Bgra8UnormSrgb, + blend: Some(wgpu::BlendState::REPLACE), + write_mask: wgpu::ColorWrites::ALL, + })], + compilation_options: wgpu::PipelineCompilationOptions::default(), + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: Some(wgpu::Face::Back), + polygon_mode: wgpu::PolygonMode::Fill, + unclipped_depth: false, + conservative: false, + }, + depth_stencil: None, + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + multiview: None, + cache: None, + }); + + Self { + window, + imgui: None, + pipeline: render_pipeline, + bind_group, + client, + input_mapper, + proxy, + paused_due_to_minimize: false, + } + } + + fn draw(&mut self, event_loop: &ActiveEventLoop) { + let window = &mut self.window; + let imgui = self.imgui.as_mut().unwrap(); + let mut context = imgui.context.lock().unwrap(); + let mut new_size = None; + + let now = Instant::now(); + context.io_mut().update_delta_time(now - imgui.last_frame); + imgui.last_frame = now; + + let frame = match window.surface.get_current_texture() { + Ok(frame) => frame, + Err(e) => { + if !self.window.minimized { + eprintln!("dropped frame: {e:?}"); + } + return; + } + }; + imgui + .platform + .prepare_frame(context.io_mut(), &window.window) + .expect("Failed to prepare frame"); + let ui = context.new_frame(); + let mut menu_height = 0.0; + ui.main_menu_bar(|| { + menu_height = ui.window_size()[1]; + ui.menu("ROM", || { + if ui.menu_item("Open ROM") { + let rom = native_dialog::FileDialog::new() + .add_filter("Virtual Boy ROMs", &["vb", "vbrom"]) + .show_open_single_file() + .unwrap(); + if let Some(path) = rom { + self.client.send_command(EmulatorCommand::LoadGame(path)); + } + } + if ui.menu_item("Quit") { + event_loop.exit(); + } + }); + ui.menu("Emulation", || { + let has_game = self.client.has_game(); + if self.client.is_running() { + if ui.menu_item_config("Pause").enabled(has_game).build() { + self.client.send_command(EmulatorCommand::Pause); + } + } else if ui.menu_item_config("Resume").enabled(has_game).build() { + self.client.send_command(EmulatorCommand::Resume); + } + if ui.menu_item_config("Reset").enabled(has_game).build() { + self.client.send_command(EmulatorCommand::Reset); + } + }); + ui.menu("Video", || { + let current_dims = window.logical_size(); + for scale in 1..=4 { + let label = format!("x{scale}"); + let dims = LogicalSize::new(384 * scale, 224 * scale + 20); + let selected = dims == current_dims; + if ui.menu_item_config(label).selected(selected).build() { + if let Some(size) = window.window.request_inner_size(dims) { + window.handle_resize(&size); + new_size = Some(size); + } + } + } + }); + ui.menu("Input", || { + if ui.menu_item("Bind Inputs") { + let input_window = Box::new(InputWindow::new( + event_loop, + self.input_mapper.clone(), + self.proxy.clone(), + )); + self.proxy + .send_event(UserEvent::OpenWindow(input_window)) + .unwrap(); + } + }); + }); + + let mut encoder: wgpu::CommandEncoder = window + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + + if imgui.last_cursor != ui.mouse_cursor() { + imgui.last_cursor = ui.mouse_cursor(); + imgui.platform.prepare_render(ui, &window.window); + } + + let view = frame + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(imgui.clear_color), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + + // Draw the game + rpass.set_pipeline(&self.pipeline); + let window_width = window.surface_desc.width as f32; + let window_height = window.surface_desc.height as f32; + let menu_height = menu_height * window.hidpi_factor as f32; + let ((x, y), (width, height)) = + compute_game_bounds(window_width, window_height, menu_height); + rpass.set_viewport(x, y, width, height, 0.0, 1.0); + rpass.set_bind_group(0, &self.bind_group, &[]); + rpass.draw(0..6, 0..1); + + // Draw the menu on top of the game + rpass.set_viewport(0.0, 0.0, window_width, window_height, 0.0, 1.0); + imgui + .renderer + .render(context.render(), &window.queue, &window.device, &mut rpass) + .expect("Rendering failed"); + + drop(rpass); + + if let Some(size) = new_size { + imgui.platform.handle_event::( + context.io_mut(), + &window.window, + &Event::WindowEvent { + window_id: window.window.id(), + event: WindowEvent::Resized(size), + }, + ); + } + + window.queue.submit(Some(encoder.finish())); + + frame.present(); + } +} + +impl AppWindow for GameWindow { + fn id(&self) -> WindowId { + self.window.window.id() + } + + fn init(&mut self) { + self.imgui = Some(ImguiState::new(&self.window)); + self.window.window.request_redraw(); + } + + fn handle_event(&mut self, event_loop: &ActiveEventLoop, event: &Event) { + match event { + Event::WindowEvent { event, .. } => match event { + WindowEvent::Resized(size) => { + self.window.handle_resize(size); + if self.window.minimized { + if self.client.is_running() { + self.client.send_command(EmulatorCommand::Pause); + self.paused_due_to_minimize = true; + } + } else if self.paused_due_to_minimize { + self.client.send_command(EmulatorCommand::Resume); + self.paused_due_to_minimize = false; + } + } + WindowEvent::CloseRequested => event_loop.exit(), + WindowEvent::RedrawRequested => self.draw(event_loop), + _ => (), + }, + Event::AboutToWait => { + self.window.window.request_redraw(); + } + _ => (), + } + let window = &self.window; + let Some(imgui) = self.imgui.as_mut() else { + return; + }; + let mut context = imgui.context.lock().unwrap(); + imgui + .platform + .handle_event(context.io_mut(), &window.window, event); + } +} + +fn compute_game_bounds( + window_width: f32, + window_height: f32, + menu_height: f32, +) -> ((f32, f32), (f32, f32)) { + let available_width = window_width; + let available_height = window_height - menu_height; + + let width = available_width.min(available_height * 384.0 / 224.0); + let height = available_height.min(available_width * 224.0 / 384.0); + let x = (available_width - width) / 2.0; + let y = menu_height + (available_height - height) / 2.0; + ((x, y), (width, height)) +} + +#[derive(Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)] +#[repr(C)] +struct Colors { + left: [f32; 4], + right: [f32; 4], +} diff --git a/src/app/input.rs b/src/app/input.rs new file mode 100644 index 0000000..d5ffe7e --- /dev/null +++ b/src/app/input.rs @@ -0,0 +1,223 @@ +use std::{ + sync::{Arc, RwLock}, + time::Instant, +}; + +use winit::{ + dpi::LogicalSize, + event::{Event, KeyEvent, WindowEvent}, + event_loop::{ActiveEventLoop, EventLoopProxy}, + platform::modifier_supplement::KeyEventExtModifierSupplement, +}; + +use crate::{input::InputMapper, shrooms_vb_core::VBKey}; + +use super::{ + common::{ImguiState, UiExt, WindowState, WindowStateBuilder}, + AppWindow, UserEvent, +}; + +pub struct InputWindow { + window: WindowState, + imgui: Option, + input_mapper: Arc>, + proxy: EventLoopProxy, + now_binding: Option, +} + +const KEY_NAMES: [(VBKey, &str); 14] = [ + (VBKey::LU, "Up"), + (VBKey::LD, "Down"), + (VBKey::LL, "Left"), + (VBKey::LR, "Right"), + (VBKey::SEL, "Select"), + (VBKey::STA, "Start"), + (VBKey::B, "B"), + (VBKey::A, "A"), + (VBKey::LT, "L-Trigger"), + (VBKey::RT, "R-Trigger"), + (VBKey::RU, "R-Up"), + (VBKey::RD, "R-Down"), + (VBKey::RL, "R-Left"), + (VBKey::RR, "R-Right"), +]; + +impl InputWindow { + pub fn new( + event_loop: &ActiveEventLoop, + input_mapper: Arc>, + proxy: EventLoopProxy, + ) -> Self { + let window = WindowStateBuilder::new(event_loop) + .with_title("Bind Inputs") + .with_inner_size(LogicalSize::new(600, 400)) + .build(); + Self { + window, + imgui: None, + input_mapper, + now_binding: None, + proxy, + } + } + + fn draw(&mut self) { + let window = &mut self.window; + let imgui = self.imgui.as_mut().unwrap(); + let mut context = imgui.context.lock().unwrap(); + + let now = Instant::now(); + context.io_mut().update_delta_time(now - imgui.last_frame); + imgui.last_frame = now; + + let frame = match window.surface.get_current_texture() { + Ok(frame) => frame, + Err(e) => { + if !self.window.minimized { + eprintln!("dropped frame: {e:?}"); + } + return; + } + }; + imgui + .platform + .prepare_frame(context.io_mut(), &window.window) + .expect("Failed to prepare frame"); + let ui = context.new_frame(); + + let mut render_key_bindings = || { + if let Some(table) = ui.begin_table("controls", 2) { + let binding_names = { + let mapper = self.input_mapper.read().unwrap(); + mapper.binding_names() + }; + ui.table_next_row(); + + for (key, name) in KEY_NAMES { + let binding = binding_names.get(&key).map(|s| s.as_str()); + ui.table_next_column(); + let [space, _] = ui.content_region_avail(); + ui.group(|| { + ui.right_align_text(name, space * 0.20); + ui.same_line(); + let label_text = if self.now_binding == Some(key) { + "Press any input" + } else { + binding.unwrap_or("") + }; + let label = format!("{}##{}", label_text, name); + if ui.button_with_size(label, [space * 0.60, 0.0]) { + self.now_binding = Some(key); + } + }); + ui.same_line(); + if ui.button(format!("Clear##{name}")) { + let mut mapper = self.input_mapper.write().unwrap(); + mapper.clear_binding(key); + } + } + + table.end(); + } + }; + + if let Some(window) = ui.fullscreen_window() { + if let Some(tabs) = ui.tab_bar("tabs") { + if let Some(tab) = ui.tab_item("Player 1") { + render_key_bindings(); + tab.end(); + } + tabs.end(); + } + window.end(); + } + let mut encoder: wgpu::CommandEncoder = window + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + + if imgui.last_cursor != ui.mouse_cursor() { + imgui.last_cursor = ui.mouse_cursor(); + imgui.platform.prepare_render(ui, &window.window); + } + + let view = frame + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(imgui.clear_color), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + + // Draw the game + imgui + .renderer + .render(context.render(), &window.queue, &window.device, &mut rpass) + .expect("Rendering failed"); + + drop(rpass); + + window.queue.submit(Some(encoder.finish())); + + frame.present(); + } + + fn try_bind_key(&mut self, event: &KeyEvent) { + if !event.state.is_pressed() { + return; + } + let Some(vb) = self.now_binding.take() else { + return; + }; + let mut mapper = self.input_mapper.write().unwrap(); + mapper.bind_key(vb, event.key_without_modifiers()); + } +} + +impl AppWindow for InputWindow { + fn id(&self) -> winit::window::WindowId { + self.window.window.id() + } + + fn init(&mut self) { + self.imgui = Some(ImguiState::new(&self.window)); + self.window.window.request_redraw(); + } + + fn handle_event(&mut self, _: &ActiveEventLoop, event: &Event) { + match event { + Event::WindowEvent { event, .. } => match event { + WindowEvent::Resized(size) => self.window.handle_resize(size), + WindowEvent::CloseRequested => self + .proxy + .send_event(UserEvent::CloseWindow(self.id())) + .unwrap(), + WindowEvent::KeyboardInput { event, .. } => self.try_bind_key(event), + WindowEvent::RedrawRequested => self.draw(), + _ => (), + }, + Event::AboutToWait => { + self.window.window.request_redraw(); + } + _ => (), + } + + let window = &self.window; + let Some(imgui) = self.imgui.as_mut() else { + return; + }; + let mut context = imgui.context.lock().unwrap(); + imgui + .platform + .handle_event(context.io_mut(), &window.window, event); + } +} diff --git a/src/audio.rs b/src/audio.rs new file mode 100644 index 0000000..2486830 --- /dev/null +++ b/src/audio.rs @@ -0,0 +1,101 @@ +use anyhow::{bail, Result}; +use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; +use itertools::Itertools; +use rubato::{FftFixedInOut, Resampler}; + +pub struct Audio { + #[allow(unused)] + stream: cpal::Stream, + sampler: FftFixedInOut, + input_buffer: Vec>, + output_buffer: Vec>, + sample_sink: rtrb::Producer, +} + +impl Audio { + pub fn init() -> Result { + let host = cpal::default_host(); + let Some(device) = host.default_output_device() else { + bail!("No output device available"); + }; + let Some(config) = device + .supported_output_configs()? + .find(|c| c.channels() == 2 && c.sample_format().is_float()) + else { + bail!("No suitable output config available"); + }; + let mut config = config.with_max_sample_rate().config(); + let sampler = FftFixedInOut::new(41700, config.sample_rate.0 as usize, 834, 2)?; + config.buffer_size = cpal::BufferSize::Fixed(sampler.output_frames_max() as u32); + + let input_buffer = sampler.input_buffer_allocate(true); + let output_buffer = sampler.output_buffer_allocate(true); + let (sample_sink, mut sample_source) = + rtrb::RingBuffer::new(sampler.output_frames_max() * 4); + + let stream = device.build_output_stream( + &config, + move |data: &mut [f32], _| { + let requested = data.len(); + let chunk = match sample_source.read_chunk(data.len()) { + Ok(c) => c, + Err(rtrb::chunks::ChunkError::TooFewSlots(n)) => { + sample_source.read_chunk(n).unwrap() + } + }; + let len = chunk.len(); + let (first, second) = chunk.as_slices(); + data[0..first.len()].copy_from_slice(first); + data[first.len()..len].copy_from_slice(second); + for rest in &mut data[len..requested] { + *rest = 0.0; + } + chunk.commit_all(); + }, + move |err| eprintln!("stream error: {err}"), + None, + )?; + stream.play()?; + Ok(Self { + stream, + sampler, + input_buffer, + output_buffer, + sample_sink, + }) + } + + pub fn update(&mut self, samples: &[f32]) { + for sample in samples.chunks_exact(2) { + for (channel, value) in self.input_buffer.iter_mut().zip(sample) { + channel.push(*value); + } + if self.input_buffer[0].len() >= self.sampler.input_frames_next() { + let (_, output_samples) = self + .sampler + .process_into_buffer(&self.input_buffer, &mut self.output_buffer, None) + .unwrap(); + + let chunk = match self.sample_sink.write_chunk_uninit(output_samples * 2) { + Ok(c) => c, + Err(rtrb::chunks::ChunkError::TooFewSlots(n)) => { + self.sample_sink.write_chunk_uninit(n).unwrap() + } + }; + let interleaved = self.output_buffer[0] + .iter() + .interleave(self.output_buffer[1].iter()) + .cloned(); + chunk.fill_from_iter(interleaved); + + for channel in &mut self.input_buffer { + channel.clear(); + } + } + } + + while self.sample_sink.slots() < self.sampler.output_frames_max() * 2 { + std::hint::spin_loop(); + } + } +} diff --git a/src/controller.rs b/src/controller.rs new file mode 100644 index 0000000..70861ab --- /dev/null +++ b/src/controller.rs @@ -0,0 +1,50 @@ +use std::sync::{Arc, RwLock}; + +use winit::event::{ElementState, KeyEvent}; + +use crate::{input::InputMapper, shrooms_vb_core::VBKey}; + +pub struct ControllerState { + input_mapper: Arc>, + pressed: VBKey, +} + +impl ControllerState { + pub fn new(input_mapper: Arc>) -> Self { + Self { + input_mapper, + pressed: VBKey::SGN, + } + } + + pub fn pressed(&self) -> VBKey { + self.pressed + } + + pub fn key_event(&mut self, event: &KeyEvent) -> bool { + let Some(input) = self.key_event_to_input(event) else { + return false; + }; + match event.state { + ElementState::Pressed => { + if self.pressed.contains(input) { + return false; + } + self.pressed.insert(input); + true + } + ElementState::Released => { + if !self.pressed.contains(input) { + return false; + } + self.pressed.remove(input); + true + } + } + } + + fn key_event_to_input(&self, event: &KeyEvent) -> Option { + let mapper = self.input_mapper.read().unwrap(); + mapper.key_event(event) + } +} diff --git a/src/emulator.rs b/src/emulator.rs new file mode 100644 index 0000000..38fdab6 --- /dev/null +++ b/src/emulator.rs @@ -0,0 +1,199 @@ +use std::{ + fs, + path::{Path, PathBuf}, + sync::{ + atomic::{AtomicBool, Ordering}, + mpsc::{self, RecvError, TryRecvError}, + Arc, + }, +}; + +use anyhow::Result; + +use crate::{ + audio::Audio, + renderer::GameRenderer, + shrooms_vb_core::{CoreVB, VBKey}, +}; + +pub struct EmulatorBuilder { + rom: Option, + commands: mpsc::Receiver, + running: Arc, + has_game: Arc, +} + +impl EmulatorBuilder { + pub fn new() -> (Self, EmulatorClient) { + let (queue, commands) = mpsc::channel(); + let builder = Self { + rom: None, + commands, + running: Arc::new(AtomicBool::new(false)), + has_game: Arc::new(AtomicBool::new(false)), + }; + let client = EmulatorClient { + queue, + running: builder.running.clone(), + has_game: builder.has_game.clone(), + }; + (builder, client) + } + + pub fn with_rom(self, path: &Path) -> Self { + Self { + rom: Some(path.into()), + ..self + } + } + + pub fn build(self) -> Result { + let mut emulator = Emulator::new(self.commands, self.running, self.has_game)?; + if let Some(path) = self.rom { + emulator.load_rom(&path)?; + } + Ok(emulator) + } +} + +pub struct Emulator { + sim: CoreVB, + audio: Audio, + commands: mpsc::Receiver, + renderer: Option, + running: Arc, + has_game: Arc, +} + +impl Emulator { + fn new( + commands: mpsc::Receiver, + running: Arc, + has_game: Arc, + ) -> Result { + Ok(Self { + sim: CoreVB::new(), + audio: Audio::init()?, + commands, + renderer: None, + running, + has_game, + }) + } + + pub fn load_rom(&mut self, path: &Path) -> Result<()> { + let bytes = fs::read(path)?; + self.sim.reset(); + self.sim.load_rom(bytes)?; + self.has_game.store(true, Ordering::Release); + self.running.store(true, Ordering::Release); + Ok(()) + } + + pub fn run(&mut self) { + let mut eye_contents = vec![0u8; 384 * 224 * 2]; + let mut audio_samples = vec![]; + loop { + let mut idle = true; + if self.running.load(Ordering::Acquire) { + idle = false; + self.sim.emulate_frame(); + } + if let Some(renderer) = &mut self.renderer { + if self.sim.read_pixels(&mut eye_contents) { + idle = false; + renderer.render(&eye_contents); + } + } + self.sim.read_samples(&mut audio_samples); + if !audio_samples.is_empty() { + idle = false; + self.audio.update(&audio_samples); + audio_samples.clear(); + } + if idle { + // The game is paused, and we have output all the video/audio we have. + // Block the thread until a new command comes in. + match self.commands.recv() { + Ok(command) => self.handle_command(command), + Err(RecvError) => { + return; + } + } + } + loop { + match self.commands.try_recv() { + Ok(command) => self.handle_command(command), + Err(TryRecvError::Empty) => { + break; + } + Err(TryRecvError::Disconnected) => { + return; + } + } + } + } + } + + fn handle_command(&mut self, command: EmulatorCommand) { + match command { + EmulatorCommand::SetRenderer(renderer) => { + self.renderer = Some(renderer); + } + EmulatorCommand::LoadGame(path) => { + if let Err(error) = self.load_rom(&path) { + eprintln!("error loading rom: {}", error); + } + } + EmulatorCommand::Pause => { + self.running.store(false, Ordering::Release); + } + EmulatorCommand::Resume => { + if self.has_game.load(Ordering::Acquire) { + self.running.store(true, Ordering::Relaxed); + } + } + EmulatorCommand::Reset => { + self.sim.reset(); + self.running.store(true, Ordering::Release); + } + EmulatorCommand::SetKeys(keys) => { + self.sim.set_keys(keys); + } + } + } +} + +#[derive(Debug)] +pub enum EmulatorCommand { + SetRenderer(GameRenderer), + LoadGame(PathBuf), + Pause, + Resume, + Reset, + SetKeys(VBKey), +} + +#[derive(Clone)] +pub struct EmulatorClient { + queue: mpsc::Sender, + running: Arc, + has_game: Arc, +} + +impl EmulatorClient { + pub fn is_running(&self) -> bool { + self.running.load(Ordering::Acquire) + } + pub fn has_game(&self) -> bool { + self.has_game.load(Ordering::Acquire) + } + pub fn send_command(&self, command: EmulatorCommand) { + if let Err(err) = self.queue.send(command) { + eprintln!( + "could not send command {:?} as emulator is shut down", + err.0 + ); + } + } +} diff --git a/src/input.rs b/src/input.rs new file mode 100644 index 0000000..5367d60 --- /dev/null +++ b/src/input.rs @@ -0,0 +1,71 @@ +use std::collections::HashMap; + +use winit::{ + event::KeyEvent, + keyboard::{Key, NamedKey}, + platform::modifier_supplement::KeyEventExtModifierSupplement, +}; + +use crate::shrooms_vb_core::VBKey; + +pub struct InputMapper { + vb_bindings: HashMap, + key_bindings: HashMap, +} + +impl InputMapper { + pub fn new() -> Self { + let mut mapper = Self { + vb_bindings: HashMap::new(), + key_bindings: HashMap::new(), + }; + mapper.bind_key(VBKey::SEL, Key::Character("a".into())); + mapper.bind_key(VBKey::STA, Key::Character("s".into())); + mapper.bind_key(VBKey::B, Key::Character("d".into())); + mapper.bind_key(VBKey::A, Key::Character("f".into())); + mapper.bind_key(VBKey::LT, Key::Character("e".into())); + mapper.bind_key(VBKey::RT, Key::Character("r".into())); + mapper.bind_key(VBKey::RU, Key::Character("i".into())); + mapper.bind_key(VBKey::RL, Key::Character("j".into())); + mapper.bind_key(VBKey::RD, Key::Character("k".into())); + mapper.bind_key(VBKey::RR, Key::Character("l".into())); + mapper.bind_key(VBKey::LU, Key::Named(NamedKey::ArrowUp)); + mapper.bind_key(VBKey::LL, Key::Named(NamedKey::ArrowLeft)); + mapper.bind_key(VBKey::LD, Key::Named(NamedKey::ArrowDown)); + mapper.bind_key(VBKey::LR, Key::Named(NamedKey::ArrowRight)); + mapper + } + + pub fn binding_names(&self) -> HashMap { + self.vb_bindings + .iter() + .map(|(k, v)| { + let name = match v { + Key::Character(char) => char.to_string(), + Key::Named(key) => format!("{:?}", key), + k => format!("{:?}", k), + }; + (*k, name) + }) + .collect() + } + + pub fn bind_key(&mut self, vb: VBKey, key: Key) { + if let Some(old) = self.vb_bindings.insert(vb, key.clone()) { + self.key_bindings.remove(&old); + } + self.key_bindings.insert(key, vb); + } + + pub fn clear_binding(&mut self, vb: VBKey) { + if let Some(old) = self.vb_bindings.remove(&vb) { + self.key_bindings.remove(&old); + } + } + + pub fn key_event(&self, event: &KeyEvent) -> Option { + self.key_bindings + .get(&event.key_without_modifiers()) + .cloned() + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..b8de1cf --- /dev/null +++ b/src/main.rs @@ -0,0 +1,50 @@ +use std::{path::PathBuf, process}; + +use anyhow::Result; +use app::App; +use clap::Parser; +use emulator::EmulatorBuilder; +use thread_priority::{ThreadBuilder, ThreadPriority}; +use winit::event_loop::{ControlFlow, EventLoop}; + +mod app; +mod audio; +mod controller; +mod emulator; +mod input; +mod renderer; +mod shrooms_vb_core; + +#[derive(Parser)] +struct Args { + rom: Option, +} + +fn main() -> Result<()> { + let args = Args::parse(); + + let (mut builder, client) = EmulatorBuilder::new(); + if let Some(path) = args.rom { + builder = builder.with_rom(&path); + } + + ThreadBuilder::default() + .name("Emulator".to_owned()) + .priority(ThreadPriority::Max) + .spawn_careless(move || { + let mut emulator = match builder.build() { + Ok(e) => e, + Err(err) => { + eprintln!("Error initializing emulator: {err}"); + process::exit(1); + } + }; + emulator.run(); + })?; + + let event_loop = EventLoop::with_user_event().build().unwrap(); + event_loop.set_control_flow(ControlFlow::Poll); + let proxy = event_loop.create_proxy(); + event_loop.run_app(&mut App::new(client, proxy))?; + Ok(()) +} diff --git a/src/renderer.rs b/src/renderer.rs new file mode 100644 index 0000000..a97e9e7 --- /dev/null +++ b/src/renderer.rs @@ -0,0 +1,53 @@ +use std::sync::Arc; + +use wgpu::{ + Extent3d, ImageCopyTexture, ImageDataLayout, Origin3d, Queue, Texture, TextureDescriptor, + TextureFormat, TextureUsages, +}; + +#[derive(Debug)] +pub struct GameRenderer { + pub queue: Arc, + pub eyes: Arc, +} + +impl GameRenderer { + pub fn render(&self, buffer: &[u8]) { + let texture = ImageCopyTexture { + texture: &self.eyes, + mip_level: 0, + origin: Origin3d::ZERO, + aspect: wgpu::TextureAspect::All, + }; + let size = Extent3d { + width: 384, + height: 224, + depth_or_array_layers: 1, + }; + let data_layout = ImageDataLayout { + offset: 0, + bytes_per_row: Some(384 * 2), + rows_per_image: Some(224), + }; + self.queue.write_texture(texture, buffer, data_layout, size); + } + pub fn create_texture(device: &wgpu::Device, name: &str) -> Texture { + let desc = TextureDescriptor { + label: Some(name), + size: Extent3d { + width: 384, + height: 224, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: TextureFormat::Rg8Unorm, + usage: TextureUsages::COPY_SRC + | TextureUsages::COPY_DST + | TextureUsages::TEXTURE_BINDING, + view_formats: &[TextureFormat::Rg8Unorm], + }; + device.create_texture(&desc) + } +} diff --git a/src/shrooms_vb_core.rs b/src/shrooms_vb_core.rs new file mode 100644 index 0000000..324689d --- /dev/null +++ b/src/shrooms_vb_core.rs @@ -0,0 +1,251 @@ +use std::{ffi::c_void, ptr, slice}; + +use anyhow::{anyhow, Result}; +use bitflags::bitflags; +use num_derive::{FromPrimitive, ToPrimitive}; + +#[repr(C)] +struct VB { + _data: [u8; 0], +} + +#[allow(non_camel_case_types)] +type c_int = i32; +#[allow(non_camel_case_types)] +type c_uint = u32; + +#[repr(u32)] +#[derive(FromPrimitive, ToPrimitive)] +enum VBDataType { + S8 = 0, + U8 = 1, + S16 = 2, + U16 = 3, + S32 = 4, + F32 = 5, +} + +bitflags! { + #[repr(transparent)] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + pub struct VBKey: u16 { + const PWR = 0x0001; + const SGN = 0x0002; + const A = 0x0004; + const B = 0x0008; + const RT = 0x0010; + const LT = 0x0020; + const RU = 0x0040; + const RR = 0x0080; + const LR = 0x0100; + const LL = 0x0200; + const LD = 0x0400; + const LU = 0x0800; + const STA = 0x1000; + const SEL = 0x2000; + const RL = 0x4000; + const RD = 0x8000; + } +} + +type OnFrame = extern "C" fn(sim: *mut VB) -> c_int; + +#[link(name = "vb")] +extern "C" { + #[link_name = "vbEmulate"] + fn vb_emulate(sim: *mut VB, cycles: *mut u32) -> c_int; + #[link_name = "vbGetCartROM"] + fn vb_get_cart_rom(sim: *mut VB, size: *mut u32) -> *mut c_void; + #[link_name = "vbGetPixels"] + fn vb_get_pixels( + sim: *mut VB, + left: *mut c_void, + left_stride_x: c_int, + left_stride_y: c_int, + right: *mut c_void, + right_stride_x: c_int, + right_stride_y: c_int, + ); + #[link_name = "vbGetSamples"] + fn vb_get_samples( + sim: *mut VB, + typ_: *mut VBDataType, + capacity: *mut c_uint, + position: *mut c_uint, + ) -> *mut c_void; + #[link_name = "vbGetUserData"] + fn vb_get_user_data(sim: *mut VB) -> *mut c_void; + #[link_name = "vbInit"] + fn vb_init(sim: *mut VB) -> *mut VB; + #[link_name = "vbReset"] + fn vb_reset(sim: *mut VB); + #[link_name = "vbSetCartROM"] + fn vb_set_cart_rom(sim: *mut VB, rom: *mut c_void, size: u32) -> c_int; + #[link_name = "vbSetKeys"] + fn vb_set_keys(sim: *mut VB, keys: u16) -> u16; + #[link_name = "vbSetFrameCallback"] + fn vb_set_frame_callback(sim: *mut VB, on_frame: OnFrame); + #[link_name = "vbSetSamples"] + fn vb_set_samples( + sim: *mut VB, + samples: *mut c_void, + typ_: VBDataType, + capacity: c_uint, + ) -> c_int; + #[link_name = "vbSetUserData"] + fn vb_set_user_data(sim: *mut VB, tag: *mut c_void); + #[link_name = "vbSizeOf"] + fn vb_size_of() -> usize; +} + +extern "C" fn on_frame(sim: *mut VB) -> i32 { + // SAFETY: the *mut VB owns its userdata. + // There is no way for the userdata to be null or otherwise invalid. + let data: &mut VBState = unsafe { &mut *vb_get_user_data(sim).cast() }; + data.frame_seen = true; + 1 +} + +const AUDIO_CAPACITY_SAMPLES: usize = 834 * 4; +const AUDIO_CAPACITY_FLOATS: usize = AUDIO_CAPACITY_SAMPLES * 2; + +struct VBState { + frame_seen: bool, +} + +pub struct CoreVB { + sim: *mut VB, +} + +// SAFETY: the memory pointed to by sim is valid +unsafe impl Send for CoreVB {} + +impl CoreVB { + pub fn new() -> Self { + // init the VB instance itself + let size = unsafe { vb_size_of() }; + // allocate a vec of u64 so that this memory is 8-byte aligned + let memory = vec![0u64; size.div_ceil(4)]; + let sim: *mut VB = Box::into_raw(memory.into_boxed_slice()).cast(); + unsafe { vb_init(sim) }; + unsafe { vb_reset(sim) }; + + // set up userdata + let state = VBState { frame_seen: false }; + unsafe { vb_set_user_data(sim, Box::into_raw(Box::new(state)).cast()) }; + unsafe { vb_set_frame_callback(sim, on_frame) }; + + // set up audio buffer + let audio_buffer = vec![0.0f32; AUDIO_CAPACITY_FLOATS]; + let samples: *mut c_void = Box::into_raw(audio_buffer.into_boxed_slice()).cast(); + unsafe { vb_set_samples(sim, samples, VBDataType::F32, AUDIO_CAPACITY_SAMPLES as u32) }; + + CoreVB { sim } + } + + pub fn reset(&mut self) { + unsafe { vb_reset(self.sim) }; + } + + pub fn load_rom(&mut self, rom: Vec) -> Result<()> { + self.unload_rom(); + + let size = rom.len() as u32; + let rom = Box::into_raw(rom.into_boxed_slice()).cast(); + let status = unsafe { vb_set_cart_rom(self.sim, rom, size) }; + if status == 0 { + Ok(()) + } else { + let _: Vec = + unsafe { Vec::from_raw_parts(rom.cast(), size as usize, size as usize) }; + Err(anyhow!("Invalid ROM size of {} bytes", size)) + } + } + + fn unload_rom(&mut self) -> Option> { + let mut size = 0; + let rom = unsafe { vb_get_cart_rom(self.sim, &mut size) }; + if rom.is_null() { + return None; + } + unsafe { vb_set_cart_rom(self.sim, ptr::null_mut(), 0) }; + let vec = unsafe { Vec::from_raw_parts(rom.cast(), size as usize, size as usize) }; + Some(vec) + } + + pub fn emulate_frame(&mut self) { + let mut cycles = 20_000_000; + unsafe { vb_emulate(self.sim, &mut cycles) }; + } + + pub fn read_pixels(&mut self, buffers: &mut [u8]) -> bool { + // SAFETY: the *mut VB owns its userdata. + // There is no way for the userdata to be null or otherwise invalid. + let data: &mut VBState = unsafe { &mut *vb_get_user_data(self.sim).cast() }; + if !data.frame_seen { + return false; + } + data.frame_seen = false; + + // the buffer must be big enough for our data + assert!(buffers.len() >= 384 * 224 * 2); + unsafe { + vb_get_pixels( + self.sim, + buffers.as_mut_ptr().cast(), + 2, + 384 * 2, + buffers.as_mut_ptr().offset(1).cast(), + 2, + 384 * 2, + ); + }; + true + } + + pub fn read_samples(&mut self, samples: &mut Vec) { + let mut position = 0; + let ptr = + unsafe { vb_get_samples(self.sim, ptr::null_mut(), ptr::null_mut(), &mut position) }; + // SAFETY: position is an offset in a buffer of (f32, f32). so, position * 2 is an offset in a buffer of f32. + let read_samples: &mut [f32] = + unsafe { slice::from_raw_parts_mut(ptr.cast(), position as usize * 2) }; + samples.extend_from_slice(read_samples); + + unsafe { + vb_set_samples( + self.sim, + ptr, + VBDataType::F32, + AUDIO_CAPACITY_SAMPLES as u32, + ) + }; + } + + pub fn set_keys(&mut self, keys: VBKey) { + unsafe { vb_set_keys(self.sim, keys.bits()) }; + } +} + +impl Drop for CoreVB { + fn drop(&mut self) { + let ptr = + unsafe { vb_get_samples(self.sim, ptr::null_mut(), ptr::null_mut(), ptr::null_mut()) }; + // SAFETY: the audio buffer originally came from a Vec + let floats: Vec = unsafe { + Vec::from_raw_parts(ptr.cast(), AUDIO_CAPACITY_FLOATS, AUDIO_CAPACITY_FLOATS) + }; + drop(floats); + + // SAFETY: the *mut VB owns its userdata. + // There is no way for the userdata to be null or otherwise invalid. + let ptr: *mut VBState = unsafe { vb_get_user_data(self.sim).cast() }; + // SAFETY: we made this pointer ourselves, we can for sure free it + unsafe { drop(Box::from_raw(ptr)) }; + + let len = unsafe { vb_size_of() }.div_ceil(4); + // SAFETY: the sim's memory originally came from a Vec + let bytes: Vec = unsafe { Vec::from_raw_parts(self.sim.cast(), len, len) }; + drop(bytes); + } +}