commit f193f33f4e4608e6d02d7b58523cf3f70e1a872a Author: galister <22305755+galister@users.noreply.github.com> Date: Thu Nov 9 22:27:05 2023 +0900 nothing works diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..265b7f5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +.gdb_history diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..dac4990 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,4155 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ab_glyph" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80179d7dd5d7e8c285d67c4a1e652972a92de7475beddfb92028c76463b13225" +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 = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "alsa" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2562ad8dcf0f789f65c6fdaad8a8a9708ed6b488e649da28c01656ad66b8b47" +dependencies = [ + "alsa-sys", + "bitflags 1.3.2", + "libc", + "nix 0.24.3", +] + +[[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.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64529721f27c2314ced0890ce45e469574a73e5e6fdd6e9da1860eb29285f5e0" +dependencies = [ + "android-properties", + "bitflags 1.3.2", + "cc", + "jni-sys", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum 0.6.1", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[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 = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "aquamarine" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a941c39708478e8eea39243b5983f1c42d2717b3620ee91f4a52115fd02ac43f" +dependencies = [ + "itertools 0.9.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "ash" +version = "0.37.3+1.3.251" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" +dependencies = [ + "libloading 0.7.4", +] + +[[package]] +name = "ash-window" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b912285a7c29f3a8f87ca6f55afc48768624e5e33ec17dbd2f2075903f5e35ab" +dependencies = [ + "ash", + "raw-window-handle", + "raw-window-metal", +] + +[[package]] +name = "ashpd" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c018490e423efb6f032ef575f873ea57b61d44bec763cfe027b8e8852a027cf" +dependencies = [ + "async-std", + "enumflags2", + "futures-channel", + "futures-util", + "once_cell", + "rand", + "serde", + "serde_repr", + "url", + "zbus", +] + +[[package]] +name = "async-broadcast" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" +dependencies = [ + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0c4a4f319e45986f347ee47fef8bf5e81c9abc3f6f58dc2391439f30df65f0" +dependencies = [ + "async-lock 2.8.0", + "async-task", + "concurrent-queue", + "fastrand 2.0.1", + "futures-lite 1.13.0", + "slab", +] + +[[package]] +name = "async-fs" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "blocking", + "futures-lite 1.13.0", +] + +[[package]] +name = "async-global-executor" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +dependencies = [ + "async-channel", + "async-executor", + "async-io 1.13.0", + "async-lock 2.8.0", + "blocking", + "futures-lite 1.13.0", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.27", + "slab", + "socket2", + "waker-fn", +] + +[[package]] +name = "async-io" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9d5715c2d329bf1b4da8d60455b99b187f27ba726df2883799af9af60997" +dependencies = [ + "async-lock 3.0.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.0.1", + "parking", + "polling 3.3.0", + "rustix 0.38.21", + "slab", + "tracing", + "waker-fn", + "windows-sys 0.48.0", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e900cdcd39bb94a14487d3f7ef92ca222162e6c7c3fe7cb3550ea75fb486ed" +dependencies = [ + "event-listener 3.0.1", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" +dependencies = [ + "async-io 1.13.0", + "async-lock 2.8.0", + "async-signal", + "blocking", + "cfg-if", + "event-listener 3.0.1", + "futures-lite 1.13.0", + "rustix 0.38.21", + "windows-sys 0.48.0", +] + +[[package]] +name = "async-recursion" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "async-signal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e47d90f65a225c4527103a8d747001fc56e375203592b25ad103e1ca13124c5" +dependencies = [ + "async-io 2.2.0", + "async-lock 2.8.0", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 0.38.21", + "signal-hook-registry", + "slab", + "windows-sys 0.48.0", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-channel", + "async-global-executor", + "async-io 1.13.0", + "async-lock 2.8.0", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 1.13.0", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" + +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "autocxx" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba64dd33efd8f09724143d45ab91b48aebcee52f4fb11add3464c998fab47dc" +dependencies = [ + "aquamarine", + "autocxx-macro", + "cxx", + "moveit", +] + +[[package]] +name = "autocxx-bindgen" +version = "0.65.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c9fb7b8dd83a582e12157367773d8d1195f2dea54d4250aaf3426abae3237aa" +dependencies = [ + "bitflags 1.3.2", + "cexpr", + "clang-sys", + "itertools 0.10.5", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.39", + "which", +] + +[[package]] +name = "autocxx-build" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955e602d2d68b79ca5d674984259234fad2c8d869ad99011699e0a3cd76f38cd" +dependencies = [ + "autocxx-engine", + "env_logger 0.9.3", + "indexmap 1.9.3", + "syn 2.0.39", +] + +[[package]] +name = "autocxx-engine" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5918896fc1d44a647345fd5e8c74208424e394a76bdd2942398f4aff81ec7ab1" +dependencies = [ + "aquamarine", + "autocxx-bindgen", + "autocxx-parser", + "cc", + "cxx-gen", + "indexmap 1.9.3", + "indoc", + "itertools 0.10.5", + "log", + "miette", + "once_cell", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustversion", + "serde_json", + "strum_macros 0.24.3", + "syn 2.0.39", + "tempfile", + "thiserror", + "version_check", +] + +[[package]] +name = "autocxx-macro" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e594e68d030b6eb1ce7e2b40958f4f4ae7150c588c76d76b9f8178d41c47d80" +dependencies = [ + "autocxx-parser", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "autocxx-parser" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef00b2fc378804c31c4fbd693a7fea93f8a90467dce331dae1e4ce41e542953" +dependencies = [ + "indexmap 1.9.3", + "itertools 0.10.5", + "log", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 2.0.39", + "thiserror", +] + +[[package]] +name = "bindgen" +version = "0.66.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +dependencies = [ + "bitflags 2.4.1", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.39", +] + +[[package]] +name = "bindgen" +version = "0.68.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" +dependencies = [ + "bitflags 2.4.1", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.39", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-sys" +version = "0.1.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "block2" +version = "0.2.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42" +dependencies = [ + "block-sys", + "objc2-encode", +] + +[[package]] +name = "blocking" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c36a4d0d48574b3dd360b4b7d95cc651d2b6557b6402848a27d4b228a473e2a" +dependencies = [ + "async-channel", + "async-lock 2.8.0", + "async-task", + "fastrand 2.0.1", + "futures-io", + "futures-lite 1.13.0", + "piper", + "tracing", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "calloop" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e0d00eb1ea24371a97d2da6201c6747a633dc6dc1988ef503403b4c59504a8" +dependencies = [ + "bitflags 1.3.2", + "log", + "nix 0.25.1", + "slotmap", + "thiserror", + "vec_map", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[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-expr" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[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 = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.48.5", +] + +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading 0.7.4", +] + +[[package]] +name = "cmake" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +dependencies = [ + "cc", +] + +[[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 0.23.1", + "foreign-types 0.5.0", + "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 = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-cstr" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cookie-factory" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396de984970346b0d9e93d1415082923c679e5ae5c3ee3dcbd104f5610af126b" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types 0.3.2", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "970a29baf4110c26fedbc7f82107d42c23f7e88e404c4577ed73fe99ff85a212" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" +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.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8478e5bdad14dce236b9898ea002eabfa87cbe14f0aa538dbe3b6a4bec4332d" +dependencies = [ + "bindgen 0.68.1", +] + +[[package]] +name = "cpal" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d959d90e938c5493000514b446987c07aed46c668faaa7d34d6c7a67b1a578c" +dependencies = [ + "alsa", + "core-foundation-sys", + "coreaudio-rs", + "dasp_sample", + "jni 0.19.0", + "js-sys", + "libc", + "mach2", + "ndk", + "ndk-context", + "oboe", + "once_cell", + "parking_lot", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows", +] + +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cstr" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aa998c33a6d3271e3678950a22134cd7dd27cef86dee1b611b5b14207d1d90b" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "cxx" +version = "1.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7129e341034ecb940c9072817cd9007974ea696844fc4dd582dc1653a7fbe2e8" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-gen" +version = "0.7.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e0fc77e9f8d61724be90deb42a7e50ba3bf37c7c16dc91cdba821f69a5e0e9" +dependencies = [ + "codespan-reporting", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06fdd177fc61050d63f67f5bd6351fac6ab5526694ea8e359cd9cd3b75857f44" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "587663dd5fb3d10932c8aecfe7c844db1bcf0aee93eeab08fac13dc1212c2e7f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "dasp_sample" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[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 0.8.1", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "drm-fourcc" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "enumflags2" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5998b4f30320c9d93aed72f63af821bfdac50465b75428fce77b48ec482c3939" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f95e2801cd355d4a1a3e3953ce6ee5ae9603a5c833455343a8bfe3f44d418246" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "enumset" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cec0252c2afff729ee6f00e903d479fba81784c8e2bd77447673471fdfaea1" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96b852f1345da36d551b9473fa1e2b1eb5c5195585c6c018118bc92a8d91160" +dependencies = [ + "event-listener 3.0.1", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fdeflate" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d6dafc854908ff5da46ff3f8f473c6984119a2876a383a860246dd7841a868" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fontconfig-rs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4baadad5111c6820e97fc8bde5077258e6f272b5b38538db4b42e1812f29f3" +dependencies = [ + "const-cstr", + "once_cell", + "thiserror", + "yeslogic-fontconfig-sys", +] + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + +[[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 0.3.1", +] + +[[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.39", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "freetype-rs" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59c337e64822dd56a3a83ed75a662a470736bdb3a9fabfb588dff276b94a4e0" +dependencies = [ + "bitflags 1.3.2", + "freetype-sys", + "libc", +] + +[[package]] +name = "freetype-sys" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643148ca6cbad6bec384b52fbe1968547d578c4efe83109e035c43a71734ff88" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3831c2651acb5177cbd83943f3d9c8912c5ad03c76afcc0e9511ba568ec5ebb" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "futures-sink" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "glam" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" +dependencies = [ + "approx", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "half" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" +dependencies = [ + "bytemuck", + "cfg-if", + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "hound" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idmap" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dba885f996064df334b1639785897d1c58c0646750101b839b8359664cb26c0e" +dependencies = [ + "fixedbitset", +] + +[[package]] +name = "idmap-derive" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3f44aa1b60e7de7e2833ad2cc3bc79880171d1e1efdb44ca833a1acf8102870" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.2", +] + +[[package]] +name = "indoc" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" + +[[package]] +name = "input-linux" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f403224ea808abe6182696e3a36d9875c0e942ba7c99239f9ef545b96e35606" +dependencies = [ + "input-linux-sys", + "nix 0.26.4", +] + +[[package]] +name = "input-linux-sys" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a687a25a4973027df9153753a5589f97fe1e958f694a34eea5606ae65299ab8" +dependencies = [ + "libc", + "nix 0.26.4", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.3", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi 0.3.3", + "rustix 0.38.21", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[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.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "libredox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] + +[[package]] +name = "libspa" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0434617020ddca18b86067912970c55410ca654cdafd775480322f50b857a8c4" +dependencies = [ + "bitflags 2.4.1", + "cc", + "convert_case 0.6.0", + "cookie-factory", + "libc", + "libspa-sys", + "nix 0.26.4", + "nom", + "system-deps", +] + +[[package]] +name = "libspa-sys" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3e70ca3f3e70f858ef363046d06178c427b4e0b63d210c95fd87d752679d345" +dependencies = [ + "bindgen 0.66.1", + "cc", + "system-deps", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" +dependencies = [ + "cc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +dependencies = [ + "value-bag", +] + +[[package]] +name = "mach2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" +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.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memmap2" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49388d20533534cd19360ad3d6a7dadc885944aa802ba3995040c5ec11288c6" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miette" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" +dependencies = [ + "miette-derive", + "once_cell", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "moveit" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87d7335204cb6ef7bd647fa6db0be3e4d7aa25b5823a7aa030027ddf512cefba" +dependencies = [ + "cxx", +] + +[[package]] +name = "ndk" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +dependencies = [ + "bitflags 1.3.2", + "jni-sys", + "ndk-sys", + "num_enum 0.5.11", + "raw-window-handle", + "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.4.1+23.1.7779620" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nix" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "nix" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", + "pin-utils", +] + +[[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 = "normpath" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04aaf5e9cb0fbf883cc0423159eacdf96a9878022084b35c462c428cab73bcaf" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive 0.6.1", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[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-sys" +version = "0.2.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7" + +[[package]] +name = "objc2" +version = "0.3.0-beta.3.patch-leaks.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468" +dependencies = [ + "block2", + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "2.0.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "oboe" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8868cc237ee02e2d9618539a23a8d228b9bb3fc2e7a5b11eed3831de77c395d0" +dependencies = [ + "jni 0.20.0", + "ndk", + "ndk-context", + "num-derive", + "num-traits", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f44155e7fb718d3cfddcf70690b2b51ac4412f347cd9e4fbe511abe9cd7b5f2" +dependencies = [ + "cc", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "orbclient" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166" +dependencies = [ + "libredox", +] + +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "ovr_overlay" +version = "0.0.0" +dependencies = [ + "byteorder", + "derive_more", + "enumset", + "lazy_static", + "log", + "ovr_overlay_sys", + "slice-of-array", + "thiserror", +] + +[[package]] +name = "ovr_overlay_sys" +version = "0.0.0" +dependencies = [ + "autocxx", + "autocxx-build", + "cxx", + "normpath", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4586edfe4c648c71797a74c84bacb32b52b212eff5dfe2bb9f2c599844023e7" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +dependencies = [ + "atomic-waker", + "fastrand 2.0.1", + "futures-io", +] + +[[package]] +name = "pipewire" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d009c8dd65e890b515a71950f7e4c801523b8894ff33863a40830bf762e9e9" +dependencies = [ + "anyhow", + "bitflags 2.4.1", + "libc", + "libspa", + "libspa-sys", + "nix 0.26.4", + "once_cell", + "pipewire-sys", + "thiserror", +] + +[[package]] +name = "pipewire-sys" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "890c084e7b737246cb4799c86b71a0e4da536031ff7473dd639eba9f95039f64" +dependencies = [ + "bindgen 0.66.1", + "libspa-sys", + "system-deps", +] + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "png" +version = "0.17.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53b6af1f60f36f8c2ac2aad5459d75a5a9b4be1e8cdd40264f315d78193e531" +dependencies = [ + "cfg-if", + "concurrent-queue", + "pin-project-lite", + "rustix 0.38.21", + "tracing", + "windows-sys 0.48.0", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "prettyplease" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +dependencies = [ + "proc-macro2", + "syn 2.0.39", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + +[[package]] +name = "raw-window-metal" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac4ea493258d54c24cb46aa9345d099e58e2ea3f30dd63667fc54fc892f18e76" +dependencies = [ + "cocoa", + "core-graphics 0.23.1", + "objc", + "raw-window-handle", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[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 = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rodio" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b1bb7b48ee48471f55da122c0044fcc7600cfcc85db88240b89cb832935e611" +dependencies = [ + "cpal", + "hound", +] + +[[package]] +name = "roxmltree" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "921904a62e410e37e215c40381b7117f830d9d89ba60ab5236170541dd25646b" +dependencies = [ + "xmlparser", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys 0.4.11", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "rxscreen" +version = "0.1.6" +source = "git+https://github.com/galister/rxscreen.git#1d0eb4f66c0cd5f1ddfc7ee2bab930019cb9e0d5" +dependencies = [ + "libc", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[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.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda4e97be1fd174ccc2aae81c8b694e803fa99b34e8fd0f057a9d70698e3ed09" +dependencies = [ + "ab_glyph", + "log", + "memmap2 0.5.10", + "smithay-client-toolkit 0.16.1", + "tiny-skia", +] + +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" + +[[package]] +name = "serde" +version = "1.0.192" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.192" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "serde_spanned" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c" +dependencies = [ + "indexmap 2.1.0", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shaderc" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31cef52787a0db5108788ea20bed13d6bf4b96287c5c5201e55725f7070f3443" +dependencies = [ + "libc", + "shaderc-sys", +] + +[[package]] +name = "shaderc-sys" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e8f8439fffcffd6efcd74197204addf935dbab5752696bd990a6cd36d54cf64" +dependencies = [ + "cmake", + "libc", + "roxmltree", +] + +[[package]] +name = "shlex" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slice-of-array" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4f120bb98cb4cb0dab21c882968c3cbff79dd23b46f07b1cf5c25044945ce84" + +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + +[[package]] +name = "smithay-client-toolkit" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870427e30b8f2cbe64bf43ec4b86e88fe39b0a84b3f15efd9c9c2d020bc86eb9" +dependencies = [ + "bitflags 1.3.2", + "calloop", + "dlib", + "lazy_static", + "log", + "memmap2 0.5.10", + "nix 0.24.3", + "pkg-config", + "wayland-client 0.29.5", + "wayland-cursor 0.29.5", + "wayland-protocols 0.29.5", +] + +[[package]] +name = "smithay-client-toolkit" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1476c3d89bb67079264b88aaf4f14358353318397e083b7c4e8c14517f55de7" +dependencies = [ + "bitflags 1.3.2", + "calloop", + "dlib", + "lazy_static", + "log", + "memmap2 0.5.10", + "nix 0.26.4", + "pkg-config", + "thiserror", + "wayland-backend", + "wayland-client 0.30.2", + "wayland-cursor 0.30.0", + "wayland-protocols 0.30.1", + "wayland-protocols-wlr", + "wayland-scanner 0.30.1", + "xkbcommon", +] + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros 0.25.3", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.39", +] + +[[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.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-deps" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2d580ff6a20c55dfb86be5f9c238f67835d0e81cbdea8bf5680e0897320331" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" + +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand 2.0.1", + "redox_syscall 0.4.1", + "rustix 0.38.21", + "windows-sys 0.48.0", +] + +[[package]] +name = "termcolor" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiny-skia" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "png", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adbfb5d3f3dd57a0e11d12f4f13d4ebbbc1b5c15b7ab0a156d030b21da5f677c" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.21.0", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.1.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "ttf-parser" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "uds_windows" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d" +dependencies = [ + "tempfile", + "winapi", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" + +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "value-bag" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a72e1902dde2bd6441347de2b70b7f5d59bf157c6c62f0c44572607a1d55bbe" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vk-parse" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6a0bda9bbe6b9e50e6456c80aa8fe4cca3b21e4311a1130c41e4915ec2e32a" +dependencies = [ + "xml-rs", +] + +[[package]] +name = "vulkano" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e1f15eeb9d93a05eb3c237332a10806eac1eb82444e54485bfcc1859c483c23" +dependencies = [ + "ahash", + "ash", + "bytemuck", + "core-graphics-types", + "crossbeam-queue", + "half", + "heck", + "indexmap 1.9.3", + "libloading 0.7.4", + "objc", + "once_cell", + "parking_lot", + "proc-macro2", + "quote", + "regex", + "serde", + "serde_json", + "smallvec", + "thread_local", + "vk-parse", + "vulkano-macros", +] + +[[package]] +name = "vulkano-macros" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "895b8a2cac1e7650d2d0552f2392da0970a358515ac11a34adaf19bfdc771b98" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "vulkano-shaders" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f8cf18e9becbc6d39f1c39e26bcf69546c93989553eb5748cd734a8a697a6e5" +dependencies = [ + "ahash", + "heck", + "proc-macro2", + "quote", + "shaderc", + "syn 1.0.109", + "vulkano", +] + +[[package]] +name = "vulkano-util" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a71b6df05a391161c1baec645a918437c2949d3494bf74c8358fde291d37f5f4" +dependencies = [ + "ahash", + "vulkano", + "vulkano-win", + "winit", +] + +[[package]] +name = "vulkano-win" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666c77efe5ea82837781961a6bcd957ee2e926777e8de0005f580335d6eaefe7" +dependencies = [ + "core-graphics-types", + "objc", + "raw-window-handle", + "vulkano", + "winit", +] + +[[package]] +name = "waker-fn" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +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.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" + +[[package]] +name = "wayland-backend" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b48e27457e8da3b2260ac60d0a94512f5cba36448679f3747c0865b7893ed8" +dependencies = [ + "cc", + "downcast-rs", + "io-lifetimes", + "nix 0.26.4", + "scoped-tls", + "smallvec", + "wayland-sys 0.30.1", +] + +[[package]] +name = "wayland-client" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" +dependencies = [ + "bitflags 1.3.2", + "downcast-rs", + "libc", + "nix 0.24.3", + "scoped-tls", + "wayland-commons", + "wayland-scanner 0.29.5", + "wayland-sys 0.29.5", +] + +[[package]] +name = "wayland-client" +version = "0.30.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489c9654770f674fc7e266b3c579f4053d7551df0ceb392f153adb1f9ed06ac8" +dependencies = [ + "bitflags 1.3.2", + "calloop", + "nix 0.26.4", + "wayland-backend", + "wayland-scanner 0.30.1", +] + +[[package]] +name = "wayland-commons" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" +dependencies = [ + "nix 0.24.3", + "once_cell", + "smallvec", + "wayland-sys 0.29.5", +] + +[[package]] +name = "wayland-cursor" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" +dependencies = [ + "nix 0.24.3", + "wayland-client 0.29.5", + "xcursor", +] + +[[package]] +name = "wayland-cursor" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d0c3a0d5b4b688b07b0442362d3ed6bf04724fcc16cd69ab6285b90dbc487aa" +dependencies = [ + "nix 0.26.4", + "wayland-client 0.30.2", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" +dependencies = [ + "bitflags 1.3.2", + "wayland-client 0.29.5", + "wayland-commons", + "wayland-scanner 0.29.5", +] + +[[package]] +name = "wayland-protocols" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b28101e5ca94f70461a6c2d610f76d85ad223d042dd76585ab23d3422dd9b4d" +dependencies = [ + "bitflags 1.3.2", + "wayland-backend", + "wayland-client 0.30.2", + "wayland-scanner 0.30.1", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fce991093320e4a6a525876e6b629ab24da25f9baef0c2e0080ad173ec89588a" +dependencies = [ + "bitflags 1.3.2", + "wayland-backend", + "wayland-client 0.30.2", + "wayland-protocols 0.30.1", + "wayland-scanner 0.30.1", +] + +[[package]] +name = "wayland-scanner" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" +dependencies = [ + "proc-macro2", + "quote", + "xml-rs", +] + +[[package]] +name = "wayland-scanner" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9b873b257fbc32ec909c0eb80dea312076a67014e65e245f5eb69a6b8ab330e" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" +dependencies = [ + "dlib", + "lazy_static", + "pkg-config", +] + +[[package]] +name = "wayland-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b2a02ac608e07132978689a6f9bf4214949c85998c247abadd4f4129b1aa06" +dependencies = [ + "dlib", + "log", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[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 0.38.21", +] + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[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.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", +] + +[[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.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[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_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_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_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_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_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_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_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 = "winit" +version = "0.28.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9596d90b45384f5281384ab204224876e8e8bf7d58366d9b795ad99aa9894b94" +dependencies = [ + "android-activity", + "bitflags 1.3.2", + "cfg_aliases", + "core-foundation", + "core-graphics 0.22.3", + "dispatch", + "instant", + "libc", + "log", + "mio", + "ndk", + "objc2", + "once_cell", + "orbclient", + "percent-encoding", + "raw-window-handle", + "redox_syscall 0.3.5", + "sctk-adwaita", + "smithay-client-toolkit 0.16.1", + "wasm-bindgen", + "wayland-client 0.29.5", + "wayland-commons", + "wayland-protocols 0.29.5", + "wayland-scanner 0.29.5", + "web-sys", + "windows-sys 0.45.0", + "x11-dl", +] + +[[package]] +name = "winnow" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" +dependencies = [ + "memchr", +] + +[[package]] +name = "wlx-capture" +version = "0.1.0" +dependencies = [ + "ashpd", + "drm-fourcc", + "libc", + "libspa-sys", + "log", + "once_cell", + "pipewire", + "rxscreen", + "smithay-client-toolkit 0.17.0", + "wayland-client 0.30.2", + "wayland-protocols 0.30.1", + "xcb", +] + +[[package]] +name = "wlx-overlay-s" +version = "0.1.0" +dependencies = [ + "ash-window", + "chrono", + "cstr", + "env_logger 0.10.0", + "fontconfig-rs", + "freetype-rs", + "glam", + "idmap", + "idmap-derive", + "input-linux", + "libc", + "log", + "once_cell", + "ovr_overlay", + "png", + "raw-window-handle", + "regex", + "rodio", + "serde", + "serde_yaml", + "smallvec", + "strum", + "tinyvec", + "vulkano", + "vulkano-shaders", + "vulkano-util", + "vulkano-win", + "winit", + "wlx-capture", +] + +[[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 = "xcb" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb3acf6b0945550d37d3a683b8f7de9d9f66b2c14dc390313b34d7ac6f1b4089" +dependencies = [ + "bitflags 1.3.2", + "libc", + "quick-xml", +] + +[[package]] +name = "xcursor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" +dependencies = [ + "nom", +] + +[[package]] +name = "xdg-home" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2769203cd13a0c6015d515be729c526d041e9cf2c0cc478d57faee85f40c6dcd" +dependencies = [ + "nix 0.26.4", + "winapi", +] + +[[package]] +name = "xkbcommon" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52db25b599e92bf6e3904134618728eeb7b49a5a4f38f107f92399bb9c496b88" +dependencies = [ + "libc", + "memmap2 0.7.1", +] + +[[package]] +name = "xml-rs" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" + +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + +[[package]] +name = "yeslogic-fontconfig-sys" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2bbd69036d397ebbff671b1b8e4d918610c181c5a16073b96f984a38d08c386" +dependencies = [ + "const-cstr", + "dlib", + "once_cell", + "pkg-config", +] + +[[package]] +name = "zbus" +version = "3.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31de390a2d872e4cd04edd71b425e29853f786dc99317ed72d73d6fcf5ebb948" +dependencies = [ + "async-broadcast", + "async-executor", + "async-fs", + "async-io 1.13.0", + "async-lock 2.8.0", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "byteorder", + "derivative", + "enumflags2", + "event-listener 2.5.3", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix 0.26.4", + "once_cell", + "ordered-stream", + "rand", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "winapi", + "xdg-home", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "3.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d1794a946878c0e807f55a397187c11fc7a038ba5d868e7db4f3bd7760bc9d" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb80bb776dbda6e23d705cf0123c3b95df99c4ebeaec6c2599d4a5419902b4a9" +dependencies = [ + "serde", + "static_assertions", + "zvariant", +] + +[[package]] +name = "zerocopy" +version = "0.7.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "zvariant" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44b291bee0d960c53170780af148dca5fa260a63cdd24f1962fa82e03e53338c" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde", + "static_assertions", + "url", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "934d7a7dfc310d6ee06c87ffe88ef4eca7d3e37bb251dece2ef93da8f17d8ecd" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..bf8c76e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "wlx-overlay-s" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ash-window = "0.12.0" +chrono = "0.4.29" +cstr = "0.2.11" +env_logger = "0.10.0" +fontconfig-rs = { version = "0.1.1", features = ["dlopen"] } +freetype-rs = "0.32.0" +glam = { version = "0.24.1", features = ["approx"] } +idmap = "0.2.21" +idmap-derive = "0.1.2" +input-linux = "0.6.0" +libc = "0.2.147" +log = "0.4.20" +once_cell = "1.18.0" +ovr_overlay = { features = ["ovr_input", "ovr_system"], path = "../ovr_overlay_oyasumi" } +png = "0.17.10" +raw-window-handle = "0.5.2" +regex = "1.9.5" +rodio = { version = "0.17.1", default-features = false, features = ["wav", "hound"] } +serde = { version = "1.0.188", features = ["derive"] } +serde_yaml = "0.9.25" +smallvec = "1.11.0" +strum = { version = "0.25.0", features = ["derive"] } +tinyvec = "1.6.0" +vulkano = { version = "0.33.0", features = ["serde"] } +vulkano-shaders = "0.33.0" +vulkano-util = "0.33.0" +vulkano-win = "0.33.0" +winit = "0.28.6" +wlx-capture = { version = "0.1.0", path = "../wlx-capture" } + diff --git a/src/backend/common.rs b/src/backend/common.rs new file mode 100644 index 0000000..25bff55 --- /dev/null +++ b/src/backend/common.rs @@ -0,0 +1,152 @@ +use std::{collections::VecDeque, time::Instant}; + +use glam::{Affine3A, Vec2, Vec3, Vec3A}; +use ovr_overlay::TrackedDeviceIndex; + +pub struct InputState { + pub hmd: Affine3A, + pub pointers: [Pointer; 2], + pub devices: Vec, + pub(super) data: TState, +} + +impl InputState { + pub fn pre_update(&mut self) { + self.pointers[0].before = self.pointers[0].now; + self.pointers[1].before = self.pointers[1].now; + } + + pub fn post_update(&mut self) { + for hand in &mut self.pointers { + if hand.now.click_modifier_right { + hand.interaction.mode = PointerMode::Right; + continue; + } + + if hand.now.click_modifier_middle { + hand.interaction.mode = PointerMode::Middle; + continue; + } + + let hmd_up = self.hmd.transform_vector3a(Vec3A::Y); + let dot = + hmd_up.dot(hand.pose.transform_vector3a(Vec3A::X)) * (1.0 - 2.0 * hand.hand as f32); + + hand.interaction.mode = if dot < -0.85 { + PointerMode::Right + } else if dot > 0.7 { + PointerMode::Middle + } else { + PointerMode::Left + }; + + let middle_click_orientation = false; + let right_click_orientation = false; + match hand.interaction.mode { + PointerMode::Middle => { + if !middle_click_orientation { + hand.interaction.mode = PointerMode::Left; + } + } + PointerMode::Right => { + if !right_click_orientation { + hand.interaction.mode = PointerMode::Left; + } + } + _ => {} + }; + } + } +} + +pub struct Pointer { + pub hand: usize, + pub pose: Affine3A, + pub now: PointerState, + pub before: PointerState, + pub(super) interaction: InteractionState, + pub(super) data: THand, +} + +#[derive(Debug, Clone, Copy, Default)] +pub struct PointerState { + pub scroll: f32, + pub click: bool, + pub grab: bool, + pub alt_click: bool, + pub show_hide: bool, + pub space_drag: bool, + pub click_modifier_right: bool, + pub click_modifier_middle: bool, +} + +pub struct InteractionState { + pub mode: PointerMode, + pub grabbed: Option, + pub clicked_id: Option, + pub hovered_id: Option, + pub release_actions: VecDeque>, + pub next_push: Instant, +} + +impl Default for InteractionState { + fn default() -> Self { + Self { + mode: PointerMode::Left, + grabbed: None, + clicked_id: None, + hovered_id: None, + release_actions: VecDeque::new(), + next_push: Instant::now(), + } + } +} + +pub struct PointerHit { + pub hand: usize, + pub mode: PointerMode, + pub primary: bool, + pub uv: Vec2, + pub dist: f32, +} + +struct RayHit { + idx: usize, + ray_pos: Vec3, + hit_pos: Vec3, + uv: Vec2, + dist: f32, +} + +#[derive(Debug, Clone, Copy, Default)] +pub struct GrabData { + pub offset: Vec3, + pub grabbed_id: usize, +} + +#[repr(u8)] +#[derive(Debug, Clone, Copy, Default)] +pub enum PointerMode { + #[default] + Left, + Right, + Middle, +} + +pub struct TrackedDevice { + pub index: TrackedDeviceIndex, + pub valid: bool, + pub soc: Option, + pub charging: bool, + pub role: TrackedDeviceRole, +} + +#[repr(u8)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TrackedDeviceRole { + None, + Hmd, + LeftHand, + RightHand, + Tracker, +} diff --git a/src/backend/mod.rs b/src/backend/mod.rs new file mode 100644 index 0000000..55f52d2 --- /dev/null +++ b/src/backend/mod.rs @@ -0,0 +1,3 @@ +pub mod common; +pub mod openvr; +pub mod openxr; diff --git a/src/backend/openvr/input.rs b/src/backend/openvr/input.rs new file mode 100644 index 0000000..d943943 --- /dev/null +++ b/src/backend/openvr/input.rs @@ -0,0 +1,288 @@ +use std::array; + +use glam::Affine3A; +use ovr_overlay::{ + input::{ActionHandle, ActionSetHandle, ActiveActionSet, InputManager, InputValueHandle}, + sys::{ + k_unMaxTrackedDeviceCount, ETrackedControllerRole, ETrackedDeviceClass, + ETrackedDeviceProperty, ETrackingUniverseOrigin, HmdMatrix34_t, + }, + system::SystemManager, + TrackedDeviceIndex, +}; + +use crate::backend::common::{ + InputState, InteractionState, Pointer, PointerState, TrackedDevice, TrackedDeviceRole, +}; + +macro_rules! result_str { + ( $e:expr ) => { + match $e { + Ok(x) => Ok(x), + Err(y) => Err(y.description()), + } + }; +} + +const SET_DEFAULT: &str = "/actions/default"; +const INPUT_SOURCES: [&str; 2] = ["/user/hand/left", "/user/hand/right"]; +const PATH_POSES: [&str; 2] = [ + "/actions/default/in/LeftHand", + "/actions/default/in/RightHand", +]; +const PATH_HAPTICS: [&str; 2] = [ + "/actions/default/out/HapticsLeft", + "/actions/default/out/HapticsRight", +]; + +const PATH_CLICK: &str = "/actions/default/in/Click"; +const PATH_GRAB: &str = "/actions/default/in/Grab"; +const PATH_SCROLL: &str = "/actions/default/in/Scroll"; +const PATH_ALT_CLICK: &str = "/actions/default/in/AltClick"; +const PATH_SHOW_HIDE: &str = "/actions/default/in/ShowHide"; +const PATH_SPACE_DRAG: &str = "/actions/default/in/SpaceDrag"; +const PATH_CLICK_MODIFIER_RIGHT: &str = "/actions/default/in/ClickModifierRight"; +const PATH_CLICK_MODIFIER_MIDDLE: &str = "/actions/default/in/ClickModifierMiddle"; + +const INPUT_ANY: InputValueHandle = InputValueHandle(ovr_overlay::sys::k_ulInvalidInputValueHandle); + +pub(super) struct OpenVrInputState { + set_hnd: ActionSetHandle, + click_hnd: ActionHandle, + grab_hnd: ActionHandle, + scroll_hnd: ActionHandle, + alt_click_hnd: ActionHandle, + show_hide_hnd: ActionHandle, + space_drag_hnd: ActionHandle, + click_modifier_right_hnd: ActionHandle, + click_modifier_middle_hnd: ActionHandle, +} + +pub(super) struct OpenVrHandState { + has_pose: bool, + input_hnd: InputValueHandle, + pose_hnd: ActionHandle, + haptics_hnd: ActionHandle, +} + +impl InputState { + pub fn new(input: &mut InputManager) -> Result { + let set_hnd = result_str!(input.get_action_set_handle(SET_DEFAULT))?; + + let click_hnd = result_str!(input.get_action_handle(PATH_CLICK))?; + let grab_hnd = result_str!(input.get_action_handle(PATH_GRAB))?; + let scroll_hnd = result_str!(input.get_action_handle(PATH_SCROLL))?; + let alt_click_hnd = result_str!(input.get_action_handle(PATH_ALT_CLICK))?; + let show_hide_hnd = result_str!(input.get_action_handle(PATH_SHOW_HIDE))?; + let space_drag_hnd = result_str!(input.get_action_handle(PATH_SPACE_DRAG))?; + let click_modifier_right_hnd = + result_str!(input.get_action_handle(PATH_CLICK_MODIFIER_RIGHT))?; + let click_modifier_middle_hnd = + result_str!(input.get_action_handle(PATH_CLICK_MODIFIER_MIDDLE))?; + + let input_hnd: Vec = INPUT_SOURCES + .iter() + .map(|path| Ok(result_str!(input.get_input_source_handle(path))?)) + .collect::>()?; + + let pose_hnd: Vec = PATH_POSES + .iter() + .map(|path| Ok(result_str!(input.get_action_handle(path))?)) + .collect::>()?; + + let haptics_hnd: Vec = PATH_HAPTICS + .iter() + .map(|path| Ok(result_str!(input.get_action_handle(path))?)) + .collect::>()?; + + let hands: [Pointer; 2] = array::from_fn(|i| Pointer:: { + hand: i, + now: PointerState::default(), + before: PointerState::default(), + pose: Affine3A::IDENTITY, + interaction: InteractionState::default(), + data: OpenVrHandState { + has_pose: false, + input_hnd: input_hnd[i], + pose_hnd: pose_hnd[i], + haptics_hnd: haptics_hnd[i], + }, + }); + + Ok(InputState { + hmd: Affine3A::IDENTITY, + pointers: hands, + devices: vec![], + data: OpenVrInputState { + set_hnd, + click_hnd, + grab_hnd, + scroll_hnd, + alt_click_hnd, + show_hide_hnd, + space_drag_hnd, + click_modifier_right_hnd, + click_modifier_middle_hnd, + }, + }) + } + + pub fn update(&mut self, input: &mut InputManager, system: &mut SystemManager) { + let aas = ActiveActionSet { + 0: ovr_overlay::sys::VRActiveActionSet_t { + ulActionSet: self.data.set_hnd.0, + ulRestrictedToDevice: 0, + ulSecondaryActionSet: 0, + unPadding: 0, + nPriority: 0, + }, + }; + + let _ = input.update_actions(&mut [aas]); + + let universe = ETrackingUniverseOrigin::TrackingUniverseStanding; + + for i in 0..2 { + let hand = &mut self.pointers[i]; + + hand.data.has_pose = false; + + let _ = input + .get_pose_action_data_relative_to_now( + hand.data.pose_hnd, + universe.clone(), + 0.005, + INPUT_ANY, + ) + .and_then(|pose| { + copy_from_hmd(&pose.0.pose.mDeviceToAbsoluteTracking, &mut hand.pose); + hand.data.has_pose = true; + Ok(()) + }); + + hand.now.click = input + .get_digital_action_data(self.data.click_hnd, hand.data.input_hnd) + .map(|x| x.0.bState) + .unwrap_or(false); + + hand.now.grab = input + .get_digital_action_data(self.data.grab_hnd, hand.data.input_hnd) + .map(|x| x.0.bState) + .unwrap_or(false); + + hand.now.alt_click = input + .get_digital_action_data(self.data.alt_click_hnd, hand.data.input_hnd) + .map(|x| x.0.bState) + .unwrap_or(false); + + hand.now.show_hide = input + .get_digital_action_data(self.data.show_hide_hnd, hand.data.input_hnd) + .map(|x| x.0.bState) + .unwrap_or(false); + + hand.now.space_drag = input + .get_digital_action_data(self.data.space_drag_hnd, hand.data.input_hnd) + .map(|x| x.0.bState) + .unwrap_or(false); + + hand.now.click_modifier_right = input + .get_digital_action_data(self.data.click_modifier_right_hnd, hand.data.input_hnd) + .map(|x| x.0.bState) + .unwrap_or(false); + + hand.now.click_modifier_middle = input + .get_digital_action_data(self.data.click_modifier_middle_hnd, hand.data.input_hnd) + .map(|x| x.0.bState) + .unwrap_or(false); + + hand.now.scroll = input + .get_analog_action_data(self.data.scroll_hnd, hand.data.input_hnd) + .map(|x| x.0.x) + .unwrap_or(0.0); + } + + let devices = system.get_device_to_absolute_tracking_pose(universe, 0.005); + copy_from_hmd(&devices[0].mDeviceToAbsoluteTracking, &mut self.hmd); + } + + pub fn update_devices(&mut self, system: &mut SystemManager) { + self.devices.clear(); + for i in 0..k_unMaxTrackedDeviceCount { + let index = TrackedDeviceIndex(i); + let maybe_role = match system.get_tracked_device_class(index) { + ETrackedDeviceClass::TrackedDeviceClass_HMD => Some(TrackedDeviceRole::Hmd), + ETrackedDeviceClass::TrackedDeviceClass_Controller => { + let sys_role = system.get_controller_role_for_tracked_device_index(index); + match sys_role { + ETrackedControllerRole::TrackedControllerRole_LeftHand => { + Some(TrackedDeviceRole::LeftHand) + } + ETrackedControllerRole::TrackedControllerRole_RightHand => { + Some(TrackedDeviceRole::RightHand) + } + _ => None, + } + } + ETrackedDeviceClass::TrackedDeviceClass_GenericTracker => { + Some(TrackedDeviceRole::Tracker) + } + _ => None, + }; + + if let Some(role) = maybe_role { + if let Some(device) = get_tracked_device(system, index, role) { + self.devices.push(device); + } + } + } + self.devices.sort_by(|a, b| { + (a.role as u8) + .cmp(&(b.role as u8)) + .then(a.index.0.cmp(&b.index.0)) + }); + } +} + +fn get_tracked_device( + system: &mut SystemManager, + index: TrackedDeviceIndex, + role: TrackedDeviceRole, +) -> Option { + let soc = system + .get_tracked_device_property( + index, + ETrackedDeviceProperty::Prop_DeviceBatteryPercentage_Float, + ) + .ok(); + + let charging = if soc.is_some() { + system + .get_tracked_device_property(index, ETrackedDeviceProperty::Prop_DeviceIsCharging_Bool) + .unwrap_or(false) + } else { + false + }; + + Some(TrackedDevice { + valid: true, + index, + soc, + charging, + role, + }) +} + +fn copy_from_hmd(in_mat: &HmdMatrix34_t, out_mat: &mut Affine3A) { + out_mat.x_axis[0] = in_mat.m[0][0]; + out_mat.x_axis[1] = in_mat.m[1][0]; + out_mat.x_axis[2] = in_mat.m[2][0]; + out_mat.y_axis[0] = in_mat.m[0][1]; + out_mat.y_axis[1] = in_mat.m[1][1]; + out_mat.y_axis[2] = in_mat.m[2][1]; + out_mat.z_axis[0] = in_mat.m[0][2]; + out_mat.z_axis[1] = in_mat.m[1][2]; + out_mat.z_axis[2] = in_mat.m[2][2]; + out_mat.w_axis[0] = in_mat.m[0][3]; + out_mat.w_axis[1] = in_mat.m[1][3]; + out_mat.w_axis[2] = in_mat.m[2][3]; +} diff --git a/src/backend/openvr/mod.rs b/src/backend/openvr/mod.rs new file mode 100644 index 0000000..b2aa43d --- /dev/null +++ b/src/backend/openvr/mod.rs @@ -0,0 +1,100 @@ +use std::{ + path::Path, + time::{Duration, Instant}, +}; + +use log::{error, info}; +use ovr_overlay::{ + sys::{ETrackedDeviceProperty, EVRApplicationType, EVREventType}, + TrackedDeviceIndex, +}; + +use super::common::InputState; + +pub mod input; +pub mod overlay; + +fn openvr_run() { + let app_type = EVRApplicationType::VRApplication_Overlay; + let Ok(context) = ovr_overlay::Context::init(app_type) else { + error!("Failed to initialize OpenVR"); + return; + }; + + let mut overlay = context.overlay_mngr(); + let mut settings = context.settings_mngr(); + let mut input = context.input_mngr(); + let mut system = context.system_mngr(); + let mut compositor = context.compositor_mngr(); + + let Ok(_) = input.set_action_manifest(Path::new("resources/actions.json")) else { + error!("Failed to set action manifest"); + return; + }; + + let Ok(mut input_state) = InputState::new(&mut input) else { + error!("Failed to initialize input"); + return; + }; + + let Ok(refresh_rate) = system.get_tracked_device_property::(TrackedDeviceIndex::HMD, ETrackedDeviceProperty::Prop_DisplayFrequency_Float) else { + error!("Failed to get display refresh rate"); + return; + }; + + let frame_time = (1000.0 / refresh_rate).floor() * 0.001; + let mut next_device_update = Instant::now(); + + loop { + while let Some(event) = system.poll_next_event() { + match event.event_type { + EVREventType::VREvent_Quit => { + info!("Received quit event, shutting down."); + return; + } + EVREventType::VREvent_TrackedDeviceActivated + | EVREventType::VREvent_TrackedDeviceDeactivated + | EVREventType::VREvent_TrackedDeviceUpdated => { + next_device_update = Instant::now(); + } + _ => {} + } + + if next_device_update <= Instant::now() { + input_state.update_devices(&mut system); + next_device_update = Instant::now() + Duration::from_secs(30); + } + + input_state.pre_update(); + input_state.update(&mut input, &mut system); + input_state.post_update(); + + // task scheduler + + // after input + + // interactions + + // show overlays + + // chaperone + + // render overlays + + // hide overlays + + // close font handles + + // playspace moved end frame + + let mut seconds_since_vsync = 0f32; + std::thread::sleep(Duration::from_secs_f32( + if system.get_time_since_last_vsync(&mut seconds_since_vsync, &mut 0u64) { + frame_time - seconds_since_vsync + } else { + 0.011 + }, + )); + } + } +} diff --git a/src/backend/openvr/overlay.rs b/src/backend/openvr/overlay.rs new file mode 100644 index 0000000..85ba9e4 --- /dev/null +++ b/src/backend/openvr/overlay.rs @@ -0,0 +1,15 @@ +use ovr_overlay::sys::VRVulkanTextureData_t; + +use crate::overlays::OverlayData; + +pub(super) struct OpenVrOverlayManager { + pub(super) overlays: Vec, +} + +pub(super) struct OpenVrOverlay { + pub(super) visible: bool, + pub(super) color: [f32; 4], + overlay: OverlayData, + handle: u32, + ovr_texture: VRVulkanTextureData_t, +} diff --git a/src/backend/openxr.rs b/src/backend/openxr.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/graphics.rs b/src/graphics.rs new file mode 100644 index 0000000..725b3a3 --- /dev/null +++ b/src/graphics.rs @@ -0,0 +1,559 @@ +use std::{sync::Arc, slice::Iter, io::Cursor, error::Error}; + +use log::{info,error}; +use vulkano::{format::Format, device::{physical::PhysicalDeviceType, QueueFlags, DeviceExtensions, Device, DeviceCreateInfo, Features, QueueCreateInfo, Queue}, Version, VulkanLibrary, instance::{Instance, InstanceCreateInfo}, memory::allocator::{StandardMemoryAllocator, AllocationCreateInfo, MemoryUsage}, command_buffer::{allocator::StandardCommandBufferAllocator, CommandBufferUsage, AutoCommandBufferBuilder, PrimaryAutoCommandBuffer, RenderingAttachmentInfo, RenderingInfo, PrimaryCommandBufferAbstract, CommandBufferExecFuture, SubpassContents, SecondaryAutoCommandBuffer, CommandBufferInheritanceInfo, CommandBufferInheritanceRenderPassType, CommandBufferInheritanceRenderingInfo}, descriptor_set::{allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet}, buffer::{Buffer, BufferCreateInfo, BufferUsage, BufferContents, Subbuffer, allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}}, sampler::{Filter, SamplerCreateInfo, SamplerAddressMode, Sampler}, pipeline::{GraphicsPipeline, Pipeline, graphics::{render_pass::PipelineRenderingCreateInfo, vertex_input::Vertex, input_assembly::InputAssemblyState, viewport::{ViewportState, Viewport}, color_blend::{ColorBlendState, AttachmentBlend}}, PipelineBindPoint}, image::{ImageViewAbstract, ImageUsage, SwapchainImage, ImageDimensions, ImmutableImage, MipmapsCount, StorageImage, ImageError, SubresourceData, ImageCreateFlags, AttachmentImage}, swapchain::{Surface, Swapchain, SwapchainCreateInfo, CompositeAlpha}, shader::ShaderModule, render_pass::{StoreOp, LoadOp}, sync::future::NowFuture}; +use winit::{event_loop::EventLoop, window::{WindowBuilder, Window}}; +use vulkano_win::VkSurfaceBuild; +use wlx_capture::frame::{DmabufFrame, DRM_FORMAT_ABGR8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888}; + +#[repr(C)] +#[derive(BufferContents, Vertex, Copy, Clone, Debug)] +pub struct Vert2Uv { + #[format(R32G32_SFLOAT)] + pub in_pos: [f32; 2], + #[format(R32G32_SFLOAT)] + pub in_uv: [f32; 2], +} + +pub const INDICES : [u16; 6] = [2, 1, 0, 1, 2, 3]; + +pub struct WlxGraphics { + pub instance: Arc, + pub device: Arc, + pub queue: Arc, + + pub surface: Arc, + + pub memory_allocator: Arc, + pub command_buffer_allocator: Arc, + pub descriptor_set_allocator: Arc, + + pub quad_indices: Subbuffer<[u16]>, +} + +impl WlxGraphics { + pub fn new() -> (Arc, EventLoop<()>) { + #[cfg(debug_assertions)] + let layers = vec!["VK_LAYER_KHRONOS_validation".to_owned()]; + #[cfg(not(debug_assertions))] + let layers = vec![]; + + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + enabled_layers: layers, + enumerate_portability: true, + ..Default::default() + }, + ) + .unwrap(); + + let mut device_extensions = DeviceExtensions { + khr_swapchain: true, + khr_external_memory: true, + khr_external_memory_fd: true, + ext_external_memory_dma_buf: true, + ext_image_drm_format_modifier: true, + ..DeviceExtensions::empty() + }; + + // TODO headless + let event_loop = EventLoop::new(); + let surface = WindowBuilder::new() + .build_vk_surface(&event_loop, instance.clone()) + .unwrap(); + + + let (physical_device, queue_family_index) = instance + .enumerate_physical_devices() + .unwrap() + .filter(|p| { + p.api_version() >= Version::V1_3 || p.supported_extensions().khr_dynamic_rendering + }) + .filter(|p| { + p.supported_extensions().contains(&device_extensions) + }) + .filter_map(|p| { + p.queue_family_properties() + .iter() + .enumerate() + .position(|(i, q)| { + q.queue_flags.intersects(QueueFlags::GRAPHICS) + && p.surface_support(i as u32, &surface).unwrap_or(false) + }) + .map(|i| (p, i as u32)) + }) + .min_by_key(|(p, _)| { + match p.properties().device_type { + PhysicalDeviceType::DiscreteGpu => 0, + PhysicalDeviceType::IntegratedGpu => 1, + PhysicalDeviceType::VirtualGpu => 2, + PhysicalDeviceType::Cpu => 3, + PhysicalDeviceType::Other => 4, + _ => 5, + } + }) + .expect("no suitable physical device found"); + + info!( + "Nice {} you have there.", + physical_device.properties().device_name, + ); + + if physical_device.api_version() < Version::V1_3 { + device_extensions.khr_dynamic_rendering = true; + } + + let (device, mut queues) = Device::new( + physical_device, + DeviceCreateInfo { + enabled_extensions: device_extensions, + enabled_features: Features { + dynamic_rendering: true, + ..Features::empty() + }, + queue_create_infos: vec![QueueCreateInfo { + queue_family_index, + ..Default::default() + }], + ..Default::default() + }, + ) + .unwrap(); + + let queue = queues.next().unwrap(); + + let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone())); + let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new(device.clone(), Default::default())); + let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new(device.clone())); + + let quad_indices = Buffer::from_iter( + &memory_allocator, + BufferCreateInfo { + usage: BufferUsage::INDEX_BUFFER, + ..Default::default() + }, + AllocationCreateInfo { + usage: MemoryUsage::Upload, + ..Default::default() + }, + INDICES.iter().cloned(), + ).unwrap(); + + let me = Self { + instance, + device, + queue, + surface, + memory_allocator, + command_buffer_allocator, + descriptor_set_allocator, + quad_indices, + }; + + (Arc::new(me), event_loop) + } + + pub fn create_swapchain(&self, format: Option) -> (Arc, Vec>) { + let (min_image_count, composite_alpha, image_format) = if let Some(format) = format { + (1, CompositeAlpha::Opaque, format) + } else { + let surface_capabilities = self.device + .physical_device() + .surface_capabilities(&self.surface, Default::default()) + .unwrap(); + + let composite_alpha = surface_capabilities.supported_composite_alpha.into_iter().next().unwrap(); + + let image_format = Some( + self.device + .physical_device() + .surface_formats(&self.surface, Default::default()) + .unwrap()[0] + .0, + ); + (surface_capabilities.min_image_count, composite_alpha, image_format.unwrap()) + }; + let window = self.surface.object().unwrap().downcast_ref::().unwrap(); + let swapchain = Swapchain::new( + self.device.clone(), + self.surface.clone(), + SwapchainCreateInfo { + min_image_count, + image_format: Some(image_format), + image_extent: window.inner_size().into(), + image_usage: ImageUsage::COLOR_ATTACHMENT, + composite_alpha, + ..Default::default() + }, + ) + .unwrap(); + + swapchain + } + + pub fn upload_verts(&self, width: f32, height: f32, x: f32, y: f32, w: f32, h: f32) -> Subbuffer<[Vert2Uv]> { + let rw = width; + let rh = height; + + let x0 = x / rw; + let y0 = y / rh; + + let x1 = w / rw + x0; + let y1 = h / rh + y0; + + let vertices = [ + Vert2Uv { in_pos: [x0, y0], in_uv: [0.0, 0.0] }, + Vert2Uv { in_pos: [x0, y1], in_uv: [0.0, 1.0] }, + Vert2Uv { in_pos: [x1, y0], in_uv: [1.0, 0.0] }, + Vert2Uv { in_pos: [x1, y1], in_uv: [1.0, 1.0] }, + ]; + self.upload_buffer(BufferUsage::VERTEX_BUFFER, vertices.iter()) + } + + pub fn upload_buffer(&self, usage: BufferUsage, contents: Iter<'_, T>) -> Subbuffer<[T]> + where T: BufferContents + Clone { + Buffer::from_iter( + &self.memory_allocator, + BufferCreateInfo { + usage, + ..Default::default() + }, + AllocationCreateInfo { + usage: MemoryUsage::Upload, + ..Default::default() + }, + contents.cloned(), + ).unwrap() + } + + pub fn dmabuf_texture(&self, frame: DmabufFrame) -> Result, ImageError> { + let dimensions = ImageDimensions::Dim2d { + width: frame.format.width, + height: frame.format.height, + array_layers: 1, + }; + + let format = match frame.format.fourcc { + DRM_FORMAT_ABGR8888 => Format::R8G8B8A8_UNORM, + DRM_FORMAT_XBGR8888 => Format::R8G8B8A8_UNORM, + DRM_FORMAT_ARGB8888 => Format::B8G8R8A8_UNORM, + DRM_FORMAT_XRGB8888 => Format::B8G8R8A8_UNORM, + _ => panic!("Unsupported dmabuf format {:x}", frame.format.fourcc), + }; + + let planes = frame.planes + .iter() + .take(frame.num_planes) + .filter_map(|plane| { + let Some(fd) = plane.fd else { + return None; + }; + Some(SubresourceData { + fd, + offset: plane.offset as _, + row_pitch: plane.stride as _, + }) + }).collect(); + + StorageImage::new_from_dma_buf_fd( + &self.memory_allocator, + self.device.clone(), + dimensions, + format, + ImageUsage::SAMPLED | ImageUsage::TRANSFER_SRC, + ImageCreateFlags::empty(), + [self.queue.queue_family_index()], + planes, + frame.format.modifier, + ) + } + pub fn render_texture(&self, width: u32, height: u32, format: Format) -> Arc { + let tex = AttachmentImage::with_usage( + &self.memory_allocator, + [width, height], + format, + ImageUsage::SAMPLED | ImageUsage::TRANSFER_SRC | ImageUsage::COLOR_ATTACHMENT, + ).unwrap(); + + tex + } + pub fn create_pipeline(self: &Arc, vert: Arc, frag: Arc, format: Format) -> Arc { + Arc::new(WlxPipeline::new(self.clone(), vert, frag, format)) + } + pub fn create_command_buffer(self: &Arc, usage: CommandBufferUsage) -> WlxCommandBuffer { + let command_buffer = AutoCommandBufferBuilder::primary( + &self.command_buffer_allocator, + self.queue.queue_family_index(), + usage, + ).unwrap(); + WlxCommandBuffer { graphics: self.clone(), command_buffer } + } + +} + +pub struct WlxCommandBuffer { + graphics: Arc, + command_buffer: AutoCommandBufferBuilder>, +} + +impl WlxCommandBuffer { + pub fn inner(&self) -> &AutoCommandBufferBuilder> { + &self.command_buffer + } + + pub fn inner_mut(&mut self) -> &mut AutoCommandBufferBuilder> { + &mut self.command_buffer + } + + pub fn to_inner(self) -> AutoCommandBufferBuilder> { + self.command_buffer + } + + pub fn begin(mut self, render_target: Arc) -> Self + { + self.command_buffer + .begin_rendering(RenderingInfo { + contents: SubpassContents::SecondaryCommandBuffers, + color_attachments: vec![Some(RenderingAttachmentInfo { + load_op: LoadOp::Clear, + store_op: StoreOp::Store, + clear_value: Some([0.0, 0.0, 0.0, 0.0].into()), + ..RenderingAttachmentInfo::image_view( + render_target.clone(), + ) + })], + ..Default::default() + }).unwrap(); + self + } + + pub fn run_ref(&mut self, pass: &WlxPass) -> &mut Self + { + let _ = self.command_buffer.execute_commands(pass.command_buffer.clone()).unwrap(); + self + } + + pub fn run(mut self, pass: &WlxPass) -> Self + { + let _ = self.command_buffer.execute_commands(pass.command_buffer.clone()); + self + } + + pub fn texture2d(&mut self, width: u32, height: u32, format: Format, data: Vec) -> Arc { + let dimensions = ImageDimensions::Dim2d { + width, + height, + array_layers: 1, + }; + + ImmutableImage::from_iter( + &self.graphics.memory_allocator, + data, + dimensions, + MipmapsCount::One, + format, + &mut self.command_buffer, + ) + .unwrap() + } + + pub fn texture2d_png(&mut self, bytes: Vec) -> Arc { + let cursor = Cursor::new(bytes); + let decoder = png::Decoder::new(cursor); + let mut reader = decoder.read_info().unwrap(); + let info = reader.info(); + let width = info.width; + let height = info.height; + let mut image_data = Vec::new(); + image_data.resize((info.width * info.height * 4) as usize, 0); + reader.next_frame(&mut image_data).unwrap(); + self.texture2d(width, height, Format::R8G8B8A8_UNORM, image_data) + } + +} + +impl WlxCommandBuffer { + pub fn end_render_and_continue(&mut self) { + self.command_buffer.end_rendering().unwrap(); + } + + pub fn end_render(self) -> PrimaryAutoCommandBuffer { + let mut buf = self.command_buffer; + buf.end_rendering().unwrap(); + + buf.build().unwrap() + } + + pub fn end(self) -> PrimaryAutoCommandBuffer { + self.command_buffer.build().unwrap() + } + + pub fn end_render_and_execute(self) -> CommandBufferExecFuture { + let mut buf = self.command_buffer; + buf.end_rendering().unwrap(); + let buf = buf.build().unwrap(); + buf.execute(self.graphics.queue.clone()).unwrap() + } + + pub fn end_and_execute(self) -> CommandBufferExecFuture { + let buf = self.command_buffer; + let buf = buf.build().unwrap(); + buf.execute(self.graphics.queue.clone()).unwrap() + } +} + +pub struct WlxPipeline { + pub graphics: Arc, + pub pipeline: Arc, + pub format: Format, +} + +impl WlxPipeline { + fn new(graphics: Arc, vert: Arc, frag: Arc, format: Format) -> Self { + let vep = vert.entry_point("main").unwrap(); + let fep = frag.entry_point("main").unwrap(); + let pipeline = GraphicsPipeline::start() + .render_pass(PipelineRenderingCreateInfo { + color_attachment_formats: vec![Some(format)], + ..Default::default() + }) + .color_blend_state(ColorBlendState::default().blend( + AttachmentBlend::alpha() + )) + .vertex_input_state(Vert2Uv::per_vertex()) + .input_assembly_state(InputAssemblyState::new()) + .vertex_shader(vep, ()) + .viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant()) + .fragment_shader(fep, ()) + .build(graphics.device.clone()) + .unwrap(); + + Self { graphics, pipeline, format} + } + + pub fn inner(&self) -> Arc { + self.pipeline.clone() + } + + pub fn graphics(&self) -> Arc { + self.graphics.clone() + } + + pub fn uniform_sampler(&self, set: usize, texture: Arc, filter: Filter) -> Arc { + let sampler = Sampler::new( + self.graphics.device.clone(), + SamplerCreateInfo { + mag_filter: filter, + min_filter: filter, + address_mode: [SamplerAddressMode::Repeat; 3], + ..Default::default() + }, + ) + .unwrap(); + + let layout = self.pipeline.layout().set_layouts().get(set).unwrap(); + + PersistentDescriptorSet::new( + &self.graphics.descriptor_set_allocator, + layout.clone(), + [WriteDescriptorSet::image_view_sampler(0, texture, sampler)], + ) + .unwrap() + } + + pub fn uniform_buffer(&self, set: usize, data: Vec) -> Arc + where T: BufferContents + Copy { + let uniform_buffer = SubbufferAllocator::new( + self.graphics.memory_allocator.clone(), + SubbufferAllocatorCreateInfo { + buffer_usage: BufferUsage::UNIFORM_BUFFER, + ..Default::default() + }, + ); + + let uniform_buffer_subbuffer = { + let subbuffer = uniform_buffer.allocate_slice(data.len() as _).unwrap(); + subbuffer.write().unwrap().copy_from_slice(data.as_slice()); + subbuffer + }; + + let layout = self.pipeline.layout().set_layouts().get(set).unwrap(); + PersistentDescriptorSet::new( + &self.graphics.descriptor_set_allocator, + layout.clone(), + [WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)] + ).unwrap() + } + + pub fn create_pass(self: &Arc, dimensions: [f32; 2], vertex_buffer: Subbuffer<[Vert2Uv]>, index_buffer: Subbuffer<[u16]>, descriptor_sets: Vec>) -> WlxPass { + WlxPass::new(self.clone(), dimensions, vertex_buffer, index_buffer, descriptor_sets) + } +} + +pub struct WlxPass +{ + pipeline: Arc, + vertex_buffer: Subbuffer<[Vert2Uv]>, + index_buffer: Subbuffer<[u16]>, + descriptor_sets: Vec>, + pub command_buffer: Arc, +} + +impl WlxPass +{ + fn new(pipeline: Arc, dimensions: [f32; 2], vertex_buffer: Subbuffer<[Vert2Uv]>, index_buffer: Subbuffer<[u16]>, descriptor_sets: Vec>) -> Self { + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0..1.0, + }; + + let pipeline_inner = pipeline.inner().clone(); + let mut command_buffer = AutoCommandBufferBuilder::secondary( + &pipeline.graphics.command_buffer_allocator, + pipeline.graphics.queue.queue_family_index(), + CommandBufferUsage::MultipleSubmit, + CommandBufferInheritanceInfo { + render_pass: Some(CommandBufferInheritanceRenderPassType::BeginRendering( + CommandBufferInheritanceRenderingInfo { + color_attachment_formats: vec![Some(pipeline.format)], + ..Default::default() + })), + ..Default::default() + } + ) + .unwrap(); + + command_buffer.set_viewport(0, [viewport]) + .bind_pipeline_graphics(pipeline_inner) + .bind_descriptor_sets( + PipelineBindPoint::Graphics, + pipeline.inner().layout().clone(), + 0, + descriptor_sets.clone(), + ) + .bind_vertex_buffers(0, vertex_buffer.clone()) + .bind_index_buffer(index_buffer.clone()) + .draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0) + .or_else(|err| { + if let Some(source) = err.source() { + error!("Failed to draw: {}", source); + } + Err(err) + }).unwrap(); + + Self { + pipeline, + vertex_buffer, + index_buffer, + descriptor_sets, + command_buffer: Arc::new(command_buffer.build().unwrap()), + } + } +} + diff --git a/src/graphics.rs.bak2 b/src/graphics.rs.bak2 new file mode 100644 index 0000000..c2be221 --- /dev/null +++ b/src/graphics.rs.bak2 @@ -0,0 +1,1197 @@ +use core::slice; +use std::{sync::Arc, slice::Iter, io::Cursor, error::Error, borrow::{Cow, BorrowMut}, cell::RefCell, fs::File, os::fd::{FromRawFd, IntoRawFd}, mem}; + +use ash::{extensions::{ + ext::DebugUtils, + khr::{Surface,Swapchain, self}, +}, util::Align}; + +use ash::vk; +use cstr::cstr; +use glam::f32::Vec4; +use libc::c_char; +use log::{info,error}; +use raw_window_handle::*; +use smallvec::smallvec; +use std::env; +use std::ffi::CStr; +use winit::{event_loop::{EventLoop, self, ControlFlow}, window::{WindowBuilder, Window}, event::{WindowEvent, KeyboardInput, ElementState, VirtualKeyCode, Event}, platform::run_return::EventLoopExtRunReturn}; +use wlx_capture::frame::{DmabufFrame, DRM_FORMAT_ABGR8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888}; + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct Vertex { + pub in_pos: Vec4, + pub in_uv: Vec4, +} + +const APP_NAME: &str = env!("CARGO_PKG_NAME"); +pub const INDICES : [u16; 6] = [2, 1, 0, 1, 2, 3]; + +pub const VERTICES : [Vertex; 4] = [ + Vertex{ in_pos: Vec4::new(0.0, 0.0, 0.0, 0.0), in_uv: Vec4::new(0.0, 0.0, 0.0, 0.0) }, + Vertex{ in_pos: Vec4::new(0.0, 1.0, 0.0, 0.0), in_uv: Vec4::new(0.0, 1.0, 0.0, 0.0) }, + Vertex{ in_pos: Vec4::new(1.0, 0.0, 0.0, 0.0), in_uv: Vec4::new(1.0, 0.0, 0.0, 0.0) }, + Vertex{ in_pos: Vec4::new(1.0, 1.0, 0.0, 0.0), in_uv: Vec4::new(1.0, 1.0, 0.0, 0.0) }, + ]; + +// Simple offset_of macro akin to C++ offsetof +#[macro_export] +macro_rules! offset_of { + ($base:path, $field:ident) => {{ + #[allow(unused_unsafe)] + unsafe { + let b: $base = mem::zeroed(); + std::ptr::addr_of!(b.$field) as isize - std::ptr::addr_of!(b) as isize + } + }}; +} + +pub struct VkGraphics { + pub event_loop: RefCell>, + pub entry: ash::Entry, + + pub instance: ash::Instance, + pub device: ash::Device, + + pub surface_loader: Surface, + pub swapchain_loader: Swapchain, + pub window: winit::window::Window, + + pub device_properies: vk::PhysicalDeviceProperties, + pub device_memory_properties: vk::PhysicalDeviceMemoryProperties, + pub queue_family_index: u32, + pub present_queue: vk::Queue, + + pub surface: vk::SurfaceKHR, + pub surface_format: vk::SurfaceFormatKHR, + pub surface_resolution: vk::Extent2D, + + pub swapchain: vk::SwapchainKHR, + pub swapchain_format: vk::Format, + pub present_images: Vec, + pub present_image_views: Vec, + + pub pool: vk::CommandPool, + pub draw_command_buffer: vk::CommandBuffer, + pub setup_command_buffer: vk::CommandBuffer, + + pub draw_commands_reuse_fence: vk::Fence, + pub setup_commands_reuse_fence: vk::Fence, + + #[cfg(debug_assertions)] + pub debug_utils_loader: DebugUtils, + #[cfg(debug_assertions)] + pub debug_call_back: vk::DebugUtilsMessengerEXT, +} + +impl VkGraphics { + pub fn new() -> Arc { + unsafe { + let window_size = [1920, 1080]; + + let event_loop = EventLoop::new(); + let window = WindowBuilder::new() + .with_title("Vulkan") + .with_inner_size(winit::dpi::LogicalSize::new( + window_size[0], + window_size[1], + )) + .build(&event_loop) + .unwrap(); + + let entry = ash::Entry::load().unwrap(); + let app_name = cstr!(APP_NAME); + let layer_names = [ + #[cfg(debug_assertions)] + cstr!("VK_LAYER_KHRONOS_validation"), + ]; + let layers_names_raw: Vec<*const c_char> = layer_names + .iter() + .map(|raw_name| raw_name.as_ptr()) + .collect(); + + let mut extension_names = ash_window::enumerate_required_extensions(window.raw_display_handle()) + .unwrap() + .to_vec(); + + #[cfg(debug_assertions)] + extension_names.push(DebugUtils::name().as_ptr()); + + let appinfo = vk::ApplicationInfo::builder() + .application_name(app_name) + .application_version(0) + .engine_name(app_name) + .engine_version(0) + .api_version(vk::make_api_version(0, 1, 3, 0)); + + let create_info = vk::InstanceCreateInfo::builder() + .application_info(&appinfo) + .enabled_layer_names(&layers_names_raw) + .enabled_extension_names(&extension_names) + .flags(vk::InstanceCreateFlags::default()); + + let instance: ash::Instance = entry + .create_instance(&create_info, None) + .expect("Could not create Vulkan instance."); + + #[cfg(debug_assertions)] + let (debug_utils_loader, debug_call_back) = + { + let loader = DebugUtils::new(&entry, &instance); + let info = vk::DebugUtilsMessengerCreateInfoEXT::builder() + .message_severity( + vk::DebugUtilsMessageSeverityFlagsEXT::ERROR + | vk::DebugUtilsMessageSeverityFlagsEXT::WARNING + | vk::DebugUtilsMessageSeverityFlagsEXT::INFO + | vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE, + ) + .message_type( + vk::DebugUtilsMessageTypeFlagsEXT::GENERAL + | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION + | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE, + ) + .pfn_user_callback(Some(vulkan_debug_callback)) + .build(); + + let callback = loader + .create_debug_utils_messenger(&info, None) + .unwrap(); + (loader, callback) + }; + + let surface = ash_window::create_surface( + &entry, + &instance, + window.raw_display_handle(), + window.raw_window_handle(), + None, + ) + .unwrap(); + + let surface_loader = Surface::new(&entry, &instance); + + let pdevices = instance + .enumerate_physical_devices() + .expect("Physical device error"); + + let (pdevice, queue_family_index) = pdevices + .iter() + .find_map(|pdevice| { + instance + .get_physical_device_queue_family_properties(*pdevice) + .iter() + .enumerate() + .find_map(|(index, info)| { + let supports_graphic_and_surface = + info.queue_flags.contains(vk::QueueFlags::GRAPHICS) + && surface_loader + .get_physical_device_surface_support( + *pdevice, + index as u32, + surface, + ) + .unwrap(); + if supports_graphic_and_surface { + Some((*pdevice, index)) + } else { + None + } + }) + }) + .expect("Couldn't find suitable device."); + + let queue_family_index = queue_family_index as u32; + let device_extension_names_raw = [ + Swapchain::name().as_ptr(), + vk::KhrExternalMemoryFn::name().as_ptr(), + vk::KhrExternalMemoryFdFn::name().as_ptr(), + vk::ExtExternalMemoryDmaBufFn::name().as_ptr(), + vk::ExtImageDrmFormatModifierFn::name().as_ptr(), + ]; + + let priorities = [1.0]; + + let queue_info = vk::DeviceQueueCreateInfo::builder() + .queue_family_index(queue_family_index) + .queue_priorities(&priorities); + + let physical_device_features = vk::PhysicalDeviceFeatures::builder().shader_clip_distance(true).build(); + let mut physical_device_vulkan_13_features = vk::PhysicalDeviceVulkan13Features::builder().dynamic_rendering(true).synchronization2(true).build(); + + let mut features = vk::PhysicalDeviceFeatures2::builder() + .features(physical_device_features) + .push_next(&mut physical_device_vulkan_13_features) + .build(); + + let device_create_info = vk::DeviceCreateInfo::builder() + .queue_create_infos(std::slice::from_ref(&queue_info)) + .enabled_extension_names(&device_extension_names_raw) + .push_next(&mut features); + + let device: ash::Device = instance + .create_device(pdevice, &device_create_info, None) + .unwrap(); + + let present_queue = device.get_device_queue(queue_family_index, 0); + + let surface_format = surface_loader + .get_physical_device_surface_formats(pdevice, surface) + .unwrap()[0]; + + let surface_capabilities = surface_loader + .get_physical_device_surface_capabilities(pdevice, surface) + .unwrap(); + + let desired_image_count = surface_capabilities.min_image_count; + let surface_resolution = match surface_capabilities.current_extent.width { + std::u32::MAX => vk::Extent2D { + width: window_size[0], + height: window_size[1], + }, + _ => surface_capabilities.current_extent, + }; + + let pre_transform = if surface_capabilities + .supported_transforms + .contains(vk::SurfaceTransformFlagsKHR::IDENTITY) + { + vk::SurfaceTransformFlagsKHR::IDENTITY + } else { + surface_capabilities.current_transform + }; + let present_modes = surface_loader + .get_physical_device_surface_present_modes(pdevice, surface) + .unwrap(); + let present_mode = present_modes + .iter() + .cloned() + .find(|&mode| mode == vk::PresentModeKHR::MAILBOX) + .unwrap_or(vk::PresentModeKHR::FIFO); + + let swapchain_loader = Swapchain::new(&instance, &device); + + #[allow(unused)] + let dmabuf_loader = vk::ExtImageDrmFormatModifierFn::load(|name| { + std::mem::transmute(instance.get_device_proc_addr(device.handle(), name.as_ptr())) + }); + + let swapchain_create_info = vk::SwapchainCreateInfoKHR::builder() + .surface(surface) + .min_image_count(desired_image_count) + .image_color_space(surface_format.color_space) + .image_format(surface_format.format) + .image_extent(surface_resolution) + .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT) + .image_sharing_mode(vk::SharingMode::EXCLUSIVE) + .pre_transform(pre_transform) + .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE) + .present_mode(present_mode) + .clipped(true) + .image_array_layers(1); + + let swapchain = swapchain_loader + .create_swapchain(&swapchain_create_info, None) + .unwrap(); + + let pool_create_info = vk::CommandPoolCreateInfo::builder() + .flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER) + .queue_family_index(queue_family_index); + + let pool = device.create_command_pool(&pool_create_info, None).unwrap(); + + let command_buffer_allocate_info = vk::CommandBufferAllocateInfo::builder() + .command_buffer_count(2) + .command_pool(pool) + .level(vk::CommandBufferLevel::PRIMARY); + + let command_buffers = device + .allocate_command_buffers(&command_buffer_allocate_info) + .unwrap(); + + let setup_command_buffer = command_buffers[0]; + let draw_command_buffer = command_buffers[1]; + + let present_images = swapchain_loader.get_swapchain_images(swapchain).unwrap(); + let present_image_views: Vec = present_images + .iter() + .map(|&image| { + let create_view_info = vk::ImageViewCreateInfo::builder() + .view_type(vk::ImageViewType::TYPE_2D) + .format(surface_format.format) + .components(vk::ComponentMapping { + r: vk::ComponentSwizzle::R, + g: vk::ComponentSwizzle::G, + b: vk::ComponentSwizzle::B, + a: vk::ComponentSwizzle::A, + }) + .subresource_range(vk::ImageSubresourceRange { + aspect_mask: vk::ImageAspectFlags::COLOR, + base_mip_level: 0, + level_count: 1, + base_array_layer: 0, + layer_count: 1, + }) + .image(image); + device.create_image_view(&create_view_info, None).unwrap() + }) + .collect(); + let device_memory_properties = instance.get_physical_device_memory_properties(pdevice); + + let device_properies = instance.get_physical_device_properties(pdevice); + + let fence_create_info = + vk::FenceCreateInfo::builder().flags(vk::FenceCreateFlags::SIGNALED); + + let draw_commands_reuse_fence = device + .create_fence(&fence_create_info, None) + .expect("Create fence failed."); + let setup_commands_reuse_fence = device + .create_fence(&fence_create_info, None) + .expect("Create fence failed."); + + let me = Self { + event_loop: RefCell::new(event_loop), + entry, + instance, + device, + queue_family_index, + device_properies, + device_memory_properties, + window, + surface_loader, + surface_format, + present_queue, + surface_resolution, + swapchain_loader, + swapchain, + swapchain_format: surface_format.format, + present_images, + present_image_views, + pool, + draw_command_buffer, + setup_command_buffer, + draw_commands_reuse_fence, + setup_commands_reuse_fence, + surface, + #[cfg(debug_assertions)] + debug_call_back, + #[cfg(debug_assertions)] + debug_utils_loader, + }; + Arc::new(me) + } + } + + pub fn render_loop(&self, f: F) { + self.event_loop + .borrow_mut() + .run_return(|event, _, control_flow| { + *control_flow = ControlFlow::Poll; + match event { + Event::WindowEvent { + event: + WindowEvent::CloseRequested + | WindowEvent::KeyboardInput { + input: + KeyboardInput { + state: ElementState::Pressed, + virtual_keycode: Some(VirtualKeyCode::Escape), + .. + }, + .. + }, + .. + } => *control_flow = ControlFlow::Exit, + Event::MainEventsCleared => f(), + _ => (), + } + }); + } + + pub fn create_frame(self: &Arc) -> VkFrame { + VkFrame::new(self.clone()) + } + + pub fn create_shader(self: &Arc, spv_bytes: &[u8], descriptor_types: Option>) -> Arc { + VkShader::new(self.clone(), spv_bytes, descriptor_types) + } + + pub fn create_pipeline(self: &Arc, vert: Arc, frag: Arc, format: vk::Format) -> VkPipeline { + VkPipeline::new(self.clone(), vert, frag, format) + } + + pub fn create_buffer(self: &Arc, usage: vk::BufferUsageFlags, data: &[T]) -> Arc + where T: Copy { + VkBuffer::new(self.clone(), usage, data) + } +} + +impl Drop for VkGraphics { + fn drop(&mut self) { + unsafe { + self.device.device_wait_idle().unwrap(); + self.device + .destroy_fence(self.draw_commands_reuse_fence, None); + self.device + .destroy_fence(self.setup_commands_reuse_fence, None); + for &image_view in self.present_image_views.iter() { + self.device.destroy_image_view(image_view, None); + } + self.device.destroy_command_pool(self.pool, None); + self.swapchain_loader + .destroy_swapchain(self.swapchain, None); + self.surface_loader.destroy_surface(self.surface, None); + self.debug_utils_loader + .destroy_debug_utils_messenger(self.debug_call_back, None); + self.instance.destroy_instance(None); + self.device.destroy_device(None); + } + } +} + +pub struct VkFrame { + pub graphics: Arc, + + pub command_pool: vk::CommandPool, + pub command_buffer: vk::CommandBuffer, + + pub present_semaphore: vk::Semaphore, + pub render_semaphore: vk::Semaphore, + + pub fence: vk::Fence, +} + +impl VkFrame { + pub fn new(graphics: Arc) -> Self { + let command_pool = unsafe { graphics.device.create_command_pool(&vk::CommandPoolCreateInfo::default(), None) }.unwrap(); + let command_buffer = unsafe { graphics.device.allocate_command_buffers(&vk::CommandBufferAllocateInfo::builder().command_pool(command_pool).command_buffer_count(1).build()) }.unwrap()[0]; + let present_semaphore = unsafe { graphics.device.create_semaphore(&vk::SemaphoreCreateInfo::default(), None) }.unwrap(); + let render_semaphore = unsafe { graphics.device.create_semaphore(&vk::SemaphoreCreateInfo::default(), None) }.unwrap(); + let fence = unsafe { graphics.device.create_fence(&vk::FenceCreateInfo::builder().flags(vk::FenceCreateFlags::SIGNALED).build(), None) }.unwrap(); + + Self { + graphics, + command_pool, + command_buffer, + present_semaphore, + render_semaphore, + fence, + } + } +} + +impl Drop for VkFrame { + fn drop(&mut self) { + unsafe { + self.graphics.device.destroy_command_pool(self.command_pool, None); + self.graphics + .device + .destroy_semaphore(self.present_semaphore, None); + self.graphics + .device + .destroy_semaphore(self.render_semaphore, None); + self.graphics.device.destroy_fence(self.fence, None); + } + } +} + +pub struct VkBuffer { + pub graphics: Arc, + pub buffer: vk::Buffer, + pub memory: vk::DeviceMemory, +} + +impl VkBuffer +{ + pub fn new(graphics: Arc, usage: vk::BufferUsageFlags, data: &[T]) -> Arc + where T: Copy + { + unsafe { + let buffer_size = std::mem::size_of::() * data.len(); + + let buffer_create_info = vk::BufferCreateInfo::builder() + .size(buffer_size as _) + .usage(usage) + .sharing_mode(vk::SharingMode::EXCLUSIVE); + + let buffer = graphics.device.create_buffer(&buffer_create_info, None).unwrap(); + + let memory_req = graphics.device.get_buffer_memory_requirements(buffer); + + let memory_index = find_memorytype_index( + &memory_req, + &graphics.device_memory_properties, + vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT, + ) + .expect("Unable to find suitable memory index for vertex buffer."); + + let memory_allocate_info = vk::MemoryAllocateInfo::builder() + .allocation_size(memory_req.size) + .memory_type_index(memory_index) + .build(); + + let memory = graphics + .device + .allocate_memory(&memory_allocate_info, None) + .unwrap(); + + let memory_ptr = graphics + .device + .map_memory(memory, 0, memory_req.size, vk::MemoryMapFlags::empty()) + .unwrap(); + + let mut slice = Align::::new(memory_ptr, std::mem::align_of::() as _, memory_req.size); + slice.copy_from_slice(data); + + graphics.device.unmap_memory(memory); + graphics.device.bind_buffer_memory(buffer, memory, 0).unwrap(); + + Arc::new(Self { + graphics, + buffer, + memory, + }) + } + } +} + +impl Drop for VkBuffer{ + fn drop(&mut self) { + unsafe { + self.graphics.device.free_memory(self.memory, None); + self.graphics.device.destroy_buffer(self.buffer, None); + } + } +} + +pub struct VkImage { + pub graphics: Arc, + pub image: vk::Image, + pub memory: vk::DeviceMemory, + pub view: Option, + pub sampler: Option, + pub buffer: Option>, +} + +impl VkImage { + pub fn new_empty(graphics: Arc, width: u32, height: u32) -> Self { + todo!(); + } + + pub fn new_from_bytes(&self, graphics: Arc, width: u32, height: u32, format: vk::Format, data: &[u8]) -> Self { + let image_extent = vk::Extent3D { width, height, depth: 1 }; + let image = { + let image_create_info = vk::ImageCreateInfo::builder() + .image_type(vk::ImageType::TYPE_2D) + .format(vk::Format::R8G8B8A8_UNORM) + .extent(image_extent) + .mip_levels(1) + .array_layers(1) + .samples(vk::SampleCountFlags::TYPE_1) + .tiling(vk::ImageTiling::OPTIMAL) + .usage(vk::ImageUsageFlags::TRANSFER_DST + | vk::ImageUsageFlags::TRANSFER_SRC + | vk::ImageUsageFlags::SAMPLED) + .sharing_mode(vk::SharingMode::EXCLUSIVE); + + unsafe { graphics.device.create_image(&image_create_info, None).unwrap() } + }; + + let image_buffer = VkBuffer::new(graphics.clone(), vk::BufferUsageFlags::TRANSFER_SRC, data); + let memory_requirements = unsafe { graphics.device.get_image_memory_requirements(image) }; + let memory_type_index = find_memorytype_index( + &memory_requirements, + &graphics.device_memory_properties, + vk::MemoryPropertyFlags::DEVICE_LOCAL, + ).unwrap(); + + let memory = { + let alloc_info = vk::MemoryAllocateInfo::builder() + .allocation_size(memory_requirements.size) + .memory_type_index(memory_type_index) + .build(); + + unsafe { graphics.device.allocate_memory(&alloc_info, None).unwrap() } + }; + + unsafe { graphics.device.bind_image_memory(image, memory, 0).unwrap() }; + + record_submit_commandbuffer( + &graphics.device, + graphics.setup_command_buffer, + graphics.setup_commands_reuse_fence, + graphics.present_queue, + &[], + &[], + &[], + |device, texture_command_buffer| { + let barrier = vk::ImageMemoryBarrier { + dst_access_mask: vk::AccessFlags::TRANSFER_WRITE, + new_layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL, + image, + subresource_range: vk::ImageSubresourceRange { + aspect_mask: vk::ImageAspectFlags::COLOR, + level_count: 1, + layer_count: 1, + ..Default::default() + }, + ..Default::default() + }; + + unsafe { device.cmd_pipeline_barrier( + texture_command_buffer, + vk::PipelineStageFlags::BOTTOM_OF_PIPE, + vk::PipelineStageFlags::TRANSFER, + vk::DependencyFlags::empty(), + &[], + &[], + &[barrier], + ) }; + + let buffer_copy_regions = vk::BufferImageCopy::builder() + .image_subresource( + vk::ImageSubresourceLayers::builder() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .layer_count(1) + .build() + ) + .image_extent(image_extent) + .build(); + + unsafe { device.cmd_copy_buffer_to_image( + texture_command_buffer, + image_buffer.buffer, + image, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + &[buffer_copy_regions], + ) }; + + let barrier_end = vk::ImageMemoryBarrier { + src_access_mask: vk::AccessFlags::TRANSFER_WRITE, + dst_access_mask: vk::AccessFlags::SHADER_READ, + old_layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL, + new_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, + image, + subresource_range: vk::ImageSubresourceRange { + aspect_mask: vk::ImageAspectFlags::COLOR, + level_count: 1, + layer_count: 1, + ..Default::default() + }, + ..Default::default() + }; + + unsafe { device.cmd_pipeline_barrier( + texture_command_buffer, + vk::PipelineStageFlags::TRANSFER, + vk::PipelineStageFlags::FRAGMENT_SHADER, + vk::DependencyFlags::empty(), + &[], + &[], + &[barrier_end], + ) }; + + }, + ); + + Self { + graphics: graphics.clone(), + image, + memory, + buffer: Some(image_buffer), + view: None, + sampler: None, + } + } + + pub fn new_from_dmabuf(graphics: Arc, frame: &DmabufFrame) -> Self { + debug_assert!(frame.num_planes == 1); + let plane = &frame.planes[0]; + debug_assert!(plane.fd.is_some()); + + let format = match frame.format.fourcc { + DRM_FORMAT_ABGR8888 => vk::Format::R8G8B8A8_UNORM, + DRM_FORMAT_XBGR8888 => vk::Format::R8G8B8A8_UNORM, + DRM_FORMAT_ARGB8888 => vk::Format::B8G8R8A8_UNORM, + DRM_FORMAT_XRGB8888 => vk::Format::B8G8R8A8_UNORM, + _ => panic!("Unsupported dmabuf format {:x}", frame.format.fourcc), + }; + + let image = { + let layout = vk::SubresourceLayout::builder() + .offset(plane.offset as _) + .row_pitch(plane.stride as _) + .size(0) + .array_pitch(0) + .depth_pitch(0) + .build(); + + let mut drm_info = vk::ImageDrmFormatModifierExplicitCreateInfoEXT::builder() + .drm_format_modifier(frame.format.modifier) + .plane_layouts(slice::from_ref(&layout)); + + let mut mem_info = vk::ExternalMemoryImageCreateInfo::builder() + .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); + + let image_create_info = vk::ImageCreateInfo::builder() + .image_type(vk::ImageType::TYPE_2D) + .format(format) + .extent(vk::Extent3D { + width: frame.format.width, + height: frame.format.height, + depth: 1, + }) + .mip_levels(1) + .array_layers(1) + .samples(vk::SampleCountFlags::TYPE_1) + .tiling(vk::ImageTiling::DRM_FORMAT_MODIFIER_EXT) + .usage(vk::ImageUsageFlags::TRANSFER_SRC | vk::ImageUsageFlags::SAMPLED) + .sharing_mode(vk::SharingMode::EXCLUSIVE) + .push_next(&mut drm_info) + .push_next(&mut mem_info) + .build(); + + unsafe { graphics.device.create_image(&image_create_info, None).unwrap() } + }; + + let memory_requirements = unsafe { graphics.device.get_image_memory_requirements(image) }; + let memory_type_index = find_memorytype_index( + &memory_requirements, + &graphics.device_memory_properties, + vk::MemoryPropertyFlags::DEVICE_LOCAL, + ).unwrap(); + + let memory = { + let mut fd_info = vk::ImportMemoryFdInfoKHR::builder() + .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT) + .fd(plane.fd.unwrap()) + .build(); + + let mut ded_req = vk::MemoryDedicatedAllocateInfo::builder() + .image(image) + .build(); + + let alloc_info = vk::MemoryAllocateInfo::builder() + .allocation_size(memory_requirements.size) + .memory_type_index(memory_type_index) + .push_next(&mut fd_info) + .push_next(&mut ded_req) + .build(); + + unsafe { graphics.device.allocate_memory(&alloc_info, None).unwrap() } + }; + + unsafe { graphics.device.bind_image_memory(image, memory, 0).unwrap() }; + + Self { + graphics: graphics.clone(), + image, + memory, + buffer: None, + view: None, + sampler: None, + } + } +} + +impl Drop for VkImage { + fn drop(&mut self) { + unsafe { + if let Some(buffer) = self.buffer.as_ref() { + self.graphics.device.free_memory(buffer.memory, None); + self.graphics.device.destroy_buffer(buffer.buffer, None); + } + if let Some(view) = self.view { + self.graphics.device.destroy_image_view(view, None); + } + self.graphics.device.free_memory(self.memory, None); + self.graphics.device.destroy_image(self.image, None); + } + } +} + +const ENTRY_POINT_MAIN: &'static CStr = cstr!("main"); +pub struct VkShader { + pub graphics: Arc, + pub module: vk::ShaderModule, + pub descriptor_types: Option>, +} + +impl VkShader { + fn new(graphics: Arc, bytes: &[u8], descriptor_types: Option>) -> Arc { + let mut spv = ash::util::read_spv(&mut Cursor::new(bytes)).unwrap(); + let module_create_info = vk::ShaderModuleCreateInfo::builder().code(&mut spv); + let module = unsafe { graphics.device.create_shader_module(&module_create_info, None).unwrap() }; + + Arc::new(Self { + graphics, + module, + descriptor_types, + }) + } +} + +impl Drop for VkShader { + fn drop(&mut self) { + unsafe { + self.graphics.device.destroy_shader_module(self.module, None); + } + } +} + +pub struct VkPipeline { + pub graphics: Arc, + pub pipeline: vk::Pipeline, + pub pipeline_layout: vk::PipelineLayout, + pub desc_set_layouts: Vec, + pub descriptor_pool: vk::DescriptorPool, + pub descriptor_sets: Vec, + pub index_buffer: Arc, + pub vertex_buffer: Arc, +} + +impl VkPipeline { + pub fn new(graphics: Arc, vert: Arc, frag: Arc, format: vk::Format) -> Self { + let shader_stage_create_infos = [ + vk::PipelineShaderStageCreateInfo { + module: vert.module, + p_name: ENTRY_POINT_MAIN.as_ptr(), + stage: vk::ShaderStageFlags::VERTEX, + ..Default::default() + }, + vk::PipelineShaderStageCreateInfo { + module: frag.module, + p_name: ENTRY_POINT_MAIN.as_ptr(), + stage: vk::ShaderStageFlags::FRAGMENT, + ..Default::default() + }, + ]; + + let vertex_input_binding_descriptions = [vk::VertexInputBindingDescription { + binding: 0, + stride: mem::size_of::() as u32, + input_rate: vk::VertexInputRate::VERTEX, + }]; + + let vertex_input_attribute_descriptions = [ + vk::VertexInputAttributeDescription { + location: 0, + binding: 0, + format: vk::Format::R32G32_SFLOAT, + offset: offset_of!(Vertex, in_pos) as u32, + }, + vk::VertexInputAttributeDescription { + location: 1, + binding: 0, + format: vk::Format::R32G32_SFLOAT, + offset: offset_of!(Vertex, in_uv) as u32, + }, + ]; + + let vertex_input_state_info = vk::PipelineVertexInputStateCreateInfo::builder() + .vertex_attribute_descriptions(&vertex_input_attribute_descriptions) + .vertex_binding_descriptions(&vertex_input_binding_descriptions) + .build(); + + let vertex_input_assembly_state_info = vk::PipelineInputAssemblyStateCreateInfo::builder() + .topology(vk::PrimitiveTopology::TRIANGLE_LIST) + .build(); + + let desc_layout_bindings = frag.descriptor_types.iter().flatten().enumerate().map(|(i, &desc_type)| { + vk::DescriptorSetLayoutBinding { + binding: i as u32, + descriptor_type: desc_type, + descriptor_count: 1, + stage_flags: vk::ShaderStageFlags::FRAGMENT, + ..Default::default() + } + }).collect::>(); + + let descriptor_info = + vk::DescriptorSetLayoutCreateInfo::builder() + .bindings(&desc_layout_bindings); + + let desc_set_layouts = unsafe { + vec![graphics + .device + .create_descriptor_set_layout(&descriptor_info, None) + .unwrap()] + }; + + let layout_create_info = + vk::PipelineLayoutCreateInfo::builder().set_layouts(&desc_set_layouts); + + let pipeline_layout = unsafe { + graphics + .device + .create_pipeline_layout(&layout_create_info, None) + .unwrap() + }; + + let viewport = vk::Viewport::builder().width(1.0).height(1.0).max_depth(1.0).build(); + let scissor = vk::Rect2D::builder().extent(vk::Extent2D { width: 1, height: 1 }).build(); + + let viewport_state_info = vk::PipelineViewportStateCreateInfo::builder() + .scissors(slice::from_ref(&scissor)) + .viewports(slice::from_ref(&viewport)) + .build(); + + let rasterization_info = vk::PipelineRasterizationStateCreateInfo::builder() + .front_face(vk::FrontFace::COUNTER_CLOCKWISE) + .line_width(1.0) + .polygon_mode(vk::PolygonMode::FILL) + .build(); + + let multisample_state_info = vk::PipelineMultisampleStateCreateInfo::builder() + .rasterization_samples(vk::SampleCountFlags::TYPE_1) + .build(); + + let color_blend_attachment_states = [vk::PipelineColorBlendAttachmentState { + blend_enable: 1, + src_color_blend_factor: vk::BlendFactor::SRC_COLOR, + dst_color_blend_factor: vk::BlendFactor::ONE_MINUS_DST_COLOR, + color_blend_op: vk::BlendOp::ADD, + src_alpha_blend_factor: vk::BlendFactor::ZERO, + dst_alpha_blend_factor: vk::BlendFactor::ZERO, + alpha_blend_op: vk::BlendOp::ADD, + color_write_mask: vk::ColorComponentFlags::RGBA, + }]; + + let color_blend_state = vk::PipelineColorBlendStateCreateInfo::builder() + .logic_op(vk::LogicOp::CLEAR) + .attachments(&color_blend_attachment_states) + .build(); + + let dynamic_state = [vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR]; + let dynamic_state_info = + vk::PipelineDynamicStateCreateInfo::builder() + .dynamic_states(&dynamic_state) + .build(); + + let mut pipeline_rendering_create_info = vk::PipelineRenderingCreateInfo::builder() + .color_attachment_formats(slice::from_ref(&format)); + + let info = vk::GraphicsPipelineCreateInfo::builder() + .stages(&shader_stage_create_infos) + .vertex_input_state(&vertex_input_state_info) + .input_assembly_state(&vertex_input_assembly_state_info) + .viewport_state(&viewport_state_info) + .rasterization_state(&rasterization_info) + .multisample_state(&multisample_state_info) + .color_blend_state(&color_blend_state) + .dynamic_state(&dynamic_state_info) + .layout(pipeline_layout) + .push_next(&mut pipeline_rendering_create_info) + .build(); + + let pipeline = unsafe { graphics.device.create_graphics_pipelines(vk::PipelineCache::null(), slice::from_ref(&info), None).unwrap()[0] }; + + let descriptor_sizes = frag.descriptor_types.iter().flatten().map(|&desc_type| { + vk::DescriptorPoolSize { + ty: desc_type, + descriptor_count: 1, + } + }).collect::>(); + + let descriptor_pool_info = vk::DescriptorPoolCreateInfo::builder() + .pool_sizes(&descriptor_sizes) + .max_sets(1) + .build(); + + let descriptor_pool = unsafe { graphics.device.create_descriptor_pool(&descriptor_pool_info, None).unwrap() }; + + let desc_alloc_info = vk::DescriptorSetAllocateInfo::builder() + .descriptor_pool(descriptor_pool) + .set_layouts(&desc_set_layouts) + .build(); + + let descriptor_sets = unsafe { graphics.device.allocate_descriptor_sets(&desc_alloc_info).unwrap() }; + + let index_buffer = graphics.create_buffer(vk::BufferUsageFlags::INDEX_BUFFER, &INDICES); + let vertex_buffer = graphics.create_buffer(vk::BufferUsageFlags::VERTEX_BUFFER, &VERTICES); + + Self { + graphics, + pipeline, + pipeline_layout, + descriptor_pool, + desc_set_layouts, + descriptor_sets, + index_buffer, + vertex_buffer, + } + } + + pub fn render(&self, frame: &VkFrame, rect: vk::Rect2D) { + unsafe { + self.graphics.device.cmd_bind_pipeline(frame.command_buffer, vk::PipelineBindPoint::GRAPHICS, self.pipeline); + + let viewport = vk::Viewport::builder().width(rect.extent.width as _).height(rect.extent.height as _).max_depth(1.0).build(); + + self.graphics.device.cmd_set_viewport(frame.command_buffer, 0, slice::from_ref(&viewport)); + self.graphics.device.cmd_set_scissor(frame.command_buffer, 0, slice::from_ref(&rect)); + + self.graphics.device.cmd_bind_vertex_buffers(frame.command_buffer, 0, slice::from_ref(&self.vertex_buffer.buffer), &[0]); + self.graphics.device.cmd_bind_index_buffer(frame.command_buffer, self.index_buffer.buffer, 0, vk::IndexType::UINT16); + + self.graphics.device.cmd_draw_indexed(frame.command_buffer, 6, 1, 0, 0, 1); + } + } + + pub fn bind_descriptors(&self, descriptors: &[VkDescriptor]) { + let descriptor_write = descriptors.iter().enumerate().map(|(i, desciptor)| { + match desciptor { + VkDescriptor::Image(image) => { + let descriptor_image_info = vk::DescriptorImageInfo { + sampler: vk::Sampler::null(), + image_view: image.view.unwrap(), + image_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, + }; + vk::WriteDescriptorSet::builder() + .dst_set(self.descriptor_sets[0]) + .dst_binding(i as u32) + .descriptor_type(vk::DescriptorType::SAMPLED_IMAGE) + .image_info(&[descriptor_image_info]) + .build() + }, + VkDescriptor::Buffer(buffer) => { + let descriptor_buffer_info = vk::DescriptorBufferInfo { + buffer: buffer.buffer, + offset: 0, + range: vk::WHOLE_SIZE, + }; + vk::WriteDescriptorSet::builder() + .dst_set(self.descriptor_sets[0]) + .dst_binding(i as u32) + .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) + .buffer_info(&[descriptor_buffer_info]) + .build() + }, + } + }).collect::>(); + println!("x"); + unsafe { self.graphics.device.update_descriptor_sets(&descriptor_write, &[]) }; + println!("y"); + } +} + +impl Drop for VkPipeline { + fn drop(&mut self) { + unsafe { + self.graphics.device.destroy_pipeline(self.pipeline, None); + self.graphics.device.destroy_pipeline_layout(self.pipeline_layout, None); + self.graphics.device.destroy_descriptor_pool(self.descriptor_pool, None); + for &desc_set_layout in self.desc_set_layouts.iter() { + self.graphics.device.destroy_descriptor_set_layout(desc_set_layout, None); + } + } + } +} + +pub enum VkDescriptor { + Image(Arc), + Buffer(Arc), +} + +pub fn find_memorytype_index( + memory_req: &vk::MemoryRequirements, + memory_prop: &vk::PhysicalDeviceMemoryProperties, + flags: vk::MemoryPropertyFlags, +) -> Option { + memory_prop.memory_types[..memory_prop.memory_type_count as _] + .iter() + .enumerate() + .find(|(index, memory_type)| { + (1 << index) & memory_req.memory_type_bits != 0 + && memory_type.property_flags & flags == flags + }) + .map(|(index, _memory_type)| index as _) +} + +/// Helper function for submitting command buffers. Immediately waits for the fence before the command buffer +/// is executed. That way we can delay the waiting for the fences by 1 frame which is good for performance. +/// Make sure to create the fence in a signaled state on the first use. +#[allow(clippy::too_many_arguments)] +pub fn record_submit_commandbuffer( + device: &ash::Device, + command_buffer: vk::CommandBuffer, + command_buffer_reuse_fence: vk::Fence, + submit_queue: vk::Queue, + wait_mask: &[vk::PipelineStageFlags], + wait_semaphores: &[vk::Semaphore], + signal_semaphores: &[vk::Semaphore], + f: F, +) { + unsafe { + device + .wait_for_fences(&[command_buffer_reuse_fence], true, std::u64::MAX) + .expect("Wait for fence failed."); + + device + .reset_fences(&[command_buffer_reuse_fence]) + .expect("Reset fences failed."); + + device + .reset_command_buffer( + command_buffer, + vk::CommandBufferResetFlags::RELEASE_RESOURCES, + ) + .expect("Reset command buffer failed."); + + let command_buffer_begin_info = vk::CommandBufferBeginInfo::builder() + .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT); + + device + .begin_command_buffer(command_buffer, &command_buffer_begin_info) + .expect("Begin commandbuffer"); + f(device, command_buffer); + device + .end_command_buffer(command_buffer) + .expect("End commandbuffer"); + + let command_buffers = vec![command_buffer]; + + let submit_info = vk::SubmitInfo::builder() + .wait_semaphores(wait_semaphores) + .wait_dst_stage_mask(wait_mask) + .command_buffers(&command_buffers) + .signal_semaphores(signal_semaphores); + + device + .queue_submit( + submit_queue, + &[submit_info.build()], + command_buffer_reuse_fence, + ) + .expect("queue submit failed."); + } +} + +unsafe extern "system" fn vulkan_debug_callback( + message_severity: vk::DebugUtilsMessageSeverityFlagsEXT, + message_type: vk::DebugUtilsMessageTypeFlagsEXT, + p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT, + _user_data: *mut std::os::raw::c_void, +) -> vk::Bool32 { + let callback_data = *p_callback_data; + let message_id_number = callback_data.message_id_number; + + let message_id_name = if callback_data.p_message_id_name.is_null() { + Cow::from("") + } else { + CStr::from_ptr(callback_data.p_message_id_name).to_string_lossy() + }; + + let message = if callback_data.p_message.is_null() { + Cow::from("") + } else { + CStr::from_ptr(callback_data.p_message).to_string_lossy() + }; + + println!( + "{message_severity:?}:\n{message_type:?} [{message_id_name} ({message_id_number})] : {message}\n", + ); + + vk::FALSE +} diff --git a/src/gui/font.rs b/src/gui/font.rs new file mode 100644 index 0000000..19641b5 --- /dev/null +++ b/src/gui/font.rs @@ -0,0 +1,211 @@ +use std::{rc::Rc, str::FromStr, sync::Arc}; + +use fontconfig::{FontConfig, OwnedPattern}; +use freetype::{bitmap::PixelMode, face::LoadFlag, Face, Library}; +use idmap::IdMap; +use log::debug; +use vulkano::{format::Format, command_buffer::CommandBufferUsage, image::ImmutableImage}; + +use crate::graphics::WlxGraphics; + +const PRIMARY_FONT: &str = "LiberationSans"; + +pub struct FontCache { + fc: FontConfig, + ft: Library, + collections: IdMap, +} + +struct FontCollection { + fonts: Vec, + cp_map: IdMap, +} + +struct Font { + face: Face, + path: String, + index: isize, + size: isize, + glyphs: IdMap>, +} + +pub struct Glyph { + pub tex: Option>, + pub top: f32, + pub left: f32, + pub width: f32, + pub height: f32, + pub advance: f32, +} + +impl FontCache { + pub fn new() -> Self { + let ft = Library::init().expect("Failed to initialize freetype"); + let fc = FontConfig::default(); + + FontCache { + fc, + ft, + collections: IdMap::new(), + } + } + + pub fn get_text_size(&mut self, text: &str, size: isize, graphics: Arc) -> (f32, f32) { + let sizef = size as f32; + + let height = sizef + ((text.lines().count() as f32) - 1f32) * (sizef * 1.5); + + let mut max_w = sizef * 0.33; + for line in text.lines() { + let w: f32 = line + .chars() + .map(|c| self.get_glyph_for_cp(c as usize, size, graphics.clone()).advance) + .sum(); + + if w > max_w { + max_w = w; + } + } + (max_w, height) + } + + pub fn get_glyphs(&mut self, text: &str, size: isize, graphics: Arc) -> Vec> { + let mut glyphs = Vec::new(); + for line in text.lines() { + for c in line.chars() { + glyphs.push(self.get_glyph_for_cp(c as usize, size, graphics.clone())); + } + } + glyphs + } + + fn get_font_for_cp(&mut self, cp: usize, size: isize) -> usize { + if !self.collections.contains_key(size) { + self.collections.insert( + size, + FontCollection { + fonts: Vec::new(), + cp_map: IdMap::new(), + }, + ); + } + let coll = self.collections.get_mut(size).unwrap(); + + if let Some(font) = coll.cp_map.get(cp) { + return *font; + } + + let pattern_str = format!("{PRIMARY_FONT}-{size}:style=bold:charset={cp:04x}"); + + let mut pattern = + OwnedPattern::from_str(&pattern_str).expect("Failed to create fontconfig pattern"); + self.fc + .substitute(&mut pattern, fontconfig::MatchKind::Pattern); + pattern.default_substitute(); + + let pattern = pattern.font_match(&mut self.fc); + + if let Some(path) = pattern.filename() { + debug!( + "Loading font: {} {}pt", + pattern.name().unwrap_or(path), + size + ); + + let font_idx = pattern.face_index().unwrap_or(0); + + let face = self + .ft + .new_face(path, font_idx as _) + .expect("Failed to load font face"); + face.set_char_size(size << 6, size << 6, 96, 96) + .expect("Failed to set font size"); + + let idx = coll.fonts.len(); + for cp in 0..0xFFFF { + if coll.cp_map.contains_key(cp) { + continue; + } + let g = face.get_char_index(cp); + if g > 0 { + coll.cp_map.insert(cp, idx); + } + } + + let zero_glyph = Rc::new(Glyph { + tex: None, + top: 0., + left: 0., + width: 0., + height: 0., + advance: size as f32 / 3., + }); + let mut glyphs = IdMap::new(); + glyphs.insert(0, zero_glyph); + + let font = Font { + face, + path: path.to_string(), + size, + index: font_idx as _, + glyphs, + }; + coll.fonts.push(font); + + idx + } else { + coll.cp_map.insert(cp, 0); + 0 + } + } + + fn get_glyph_for_cp(&mut self, cp: usize, size: isize, graphics: Arc) -> Rc { + let key = self.get_font_for_cp(cp, size); + + let font = &mut self.collections[size].fonts[key]; + + if let Some(glyph) = font.glyphs.get(cp) { + return glyph.clone(); + } + + if font.face.load_char(cp, LoadFlag::DEFAULT).is_err() { + return font.glyphs[0].clone(); + } + + let glyph = font.face.glyph(); + if glyph.render_glyph(freetype::RenderMode::Normal).is_err() { + return font.glyphs[0].clone(); + } + + let bmp = glyph.bitmap(); + let buf = bmp.buffer().to_vec(); + if buf.len() == 0 { + return font.glyphs[0].clone(); + } + + let metrics = glyph.metrics(); + + let format = match bmp.pixel_mode() { + Ok(PixelMode::Gray) => Format::R8_UNORM, + Ok(PixelMode::Gray2) => Format::R16_SFLOAT, + Ok(PixelMode::Gray4) => Format::R32_SFLOAT, + _ => return font.glyphs[0].clone(), + }; + + let mut cmd_buffer = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit); + let texture = cmd_buffer.texture2d(bmp.width() as _, bmp.rows() as _, format, buf); + let _ = cmd_buffer.end_and_execute(); + + let g = Glyph { + tex: Some(texture), + top: (metrics.horiBearingY >> 6i64) as _, + left: (metrics.horiBearingX >> 6i64) as _, + advance: (metrics.horiAdvance >> 6i64) as _, + width: bmp.width() as _, + height: bmp.rows() as _, + }; + + font.glyphs.insert(cp, Rc::new(g)); + font.glyphs[cp].clone() + } +} diff --git a/src/gui/mod.rs b/src/gui/mod.rs new file mode 100644 index 0000000..cfb9734 --- /dev/null +++ b/src/gui/mod.rs @@ -0,0 +1,669 @@ +use std::sync::Arc; + +use glam::{Vec2, Vec3}; +use vulkano::{ + command_buffer::{CommandBufferUsage, PrimaryAutoCommandBuffer}, + format::Format, + image::{view::ImageView, AttachmentImage}, + sampler::Filter, +}; + +use crate::{ + graphics::{WlxCommandBuffer, WlxGraphics, WlxPass, WlxPipeline}, + overlays::{ + interactions::{InteractionHandler, PointerHit}, + OverlayBackend, OverlayRenderer, + }, + shaders::{frag_color, frag_glyph, frag_sprite, vert_common}, + state::AppState, +}; + +pub mod font; + +const RES_DIVIDER: usize = 4; + +struct Rect { + x: f32, + y: f32, + w: f32, + h: f32, +} + +// Parses a color from a HTML hex string +pub fn color_parse(html_hex: &str) -> Vec3 { + let mut color = Vec3::ZERO; + color.x = u8::from_str_radix(&html_hex[1..3], 16).unwrap() as f32 / 255.; + color.y = u8::from_str_radix(&html_hex[3..5], 16).unwrap() as f32 / 255.; + color.z = u8::from_str_radix(&html_hex[5..7], 16).unwrap() as f32 / 255.; + color +} + +pub struct CanvasBuilder { + canvas: Canvas, + + pub fg_color: Vec3, + pub bg_color: Vec3, + pub font_size: isize, +} + +impl CanvasBuilder { + pub fn new( + width: usize, + height: usize, + graphics: Arc, + format: Format, + data: D, + ) -> Self { + Self { + canvas: Canvas::new(width, height, graphics, format, data), + bg_color: Vec3::ZERO, + fg_color: Vec3::ONE, + font_size: 16, + } + } + + pub fn build(self) -> Canvas { + self.canvas + } + + // Creates a panel with bg_color inherited from the canvas + pub fn panel(&mut self, x: f32, y: f32, w: f32, h: f32) -> &mut Control { + let idx = self.canvas.controls.len(); + self.canvas.controls.push(Control { + rect: Rect { x, y, w, h }, + bg_color: self.bg_color, + on_render_bg: Some(Control::render_rect), + ..Control::new() + }); + &mut self.canvas.controls[idx] + } + + // Creates a label with fg_color, font_size inherited from the canvas + pub fn label(&mut self, x: f32, y: f32, w: f32, h: f32, text: Arc) -> &mut Control { + let idx = self.canvas.controls.len(); + self.canvas.controls.push(Control { + rect: Rect { x, y, w, h }, + text, + fg_color: self.fg_color, + size: self.font_size, + on_render_fg: Some(Control::render_text), + ..Control::new() + }); + &mut self.canvas.controls[idx] + } + + // Creates a label with fg_color, font_size inherited from the canvas + pub fn label_centered( + &mut self, + x: f32, + y: f32, + w: f32, + h: f32, + text: Arc, + ) -> &mut Control { + let idx = self.canvas.controls.len(); + self.canvas.controls.push(Control { + rect: Rect { x, y, w, h }, + text, + fg_color: self.fg_color, + size: self.font_size, + on_render_fg: Some(Control::render_text_centered), + ..Control::new() + }); + &mut self.canvas.controls[idx] + } + + // Creates a button with fg_color, bg_color, font_size inherited from the canvas + pub fn button(&mut self, x: f32, y: f32, w: f32, h: f32, text: Arc) -> &mut Control { + let idx = self.canvas.controls.len(); + + self.canvas.interactive_set_idx(x, y, w, h, idx); + self.canvas.controls.push(Control { + rect: Rect { x, y, w, h }, + text, + fg_color: self.fg_color, + bg_color: self.bg_color, + size: self.font_size, + on_render_bg: Some(Control::render_rect), + on_render_fg: Some(Control::render_text_centered), + on_render_hl: Some(Control::render_highlight), + ..Control::new() + }); + + &mut self.canvas.controls[idx] + } + + pub fn key_button( + &mut self, + x: f32, + y: f32, + w: f32, + h: f32, + label: &Vec, + ) -> &mut Control { + let idx = self.canvas.controls.len(); + self.canvas.interactive_set_idx(x, y, w, h, idx); + + self.canvas.controls.push(Control { + rect: Rect { x, y, w, h }, + bg_color: self.bg_color, + on_render_bg: Some(Control::render_rect), + on_render_hl: Some(Control::render_highlight), + ..Control::new() + }); + + for (i, item) in label.iter().enumerate().take(label.len().min(2)) { + self.canvas.controls.push(Control { + rect: if i == 0 { + Rect { + x: x + 4., + y: y + (self.font_size as f32) + 4., + w, + h, + } + } else { + Rect { + x: x + w * 0.5, + y: y + h - (self.font_size as f32) + 4., + w, + h, + } + }, + text: Arc::from(item.as_str()), + fg_color: self.fg_color, + size: self.font_size, + on_render_fg: Some(Control::render_text), + ..Control::new() + }); + } + + &mut self.canvas.controls[idx] + } +} + +pub struct CanvasData { + pub data: D, + pub width: usize, + pub height: usize, + + graphics: Arc, + + pipeline_color: Arc, + pipeline_glyph: Arc, +} + +pub struct Canvas { + controls: Vec>, + canvas: CanvasData, + + hover_controls: [Option; 2], + pressed_controls: [Option; 2], + + interact_map: Vec>, + interact_stride: usize, + interact_rows: usize, + + tex_fg: Arc, + view_fg: Arc>, + tex_bg: Arc, + view_bg: Arc>, + tex_final: Arc, + view_final: Arc>, + + pass_fg: WlxPass, + pass_bg: WlxPass, +} + +impl Canvas { + fn new( + width: usize, + height: usize, + graphics: Arc, + format: Format, + data: D, + ) -> Self { + let pipeline_color = graphics.create_pipeline( + vert_common::load(graphics.device.clone()).unwrap(), + frag_color::load(graphics.device.clone()).unwrap(), + format, + ); + + let pipeline_glyph = graphics.create_pipeline( + vert_common::load(graphics.device.clone()).unwrap(), + frag_glyph::load(graphics.device.clone()).unwrap(), + format, + ); + + let vertex_buffer = + graphics.upload_verts(width as _, height as _, 0., 0., width as _, height as _); + + let pipeline = graphics.create_pipeline( + vert_common::load(graphics.device.clone()).unwrap(), + frag_sprite::load(graphics.device.clone()).unwrap(), + format, + ); + + let tex_fg = graphics.render_texture(width as _, height as _, format); + let tex_bg = graphics.render_texture(width as _, height as _, format); + let tex_final = graphics.render_texture(width as _, height as _, format); + + let view_fg = ImageView::new_default(tex_fg.clone()).unwrap(); + let view_bg = ImageView::new_default(tex_bg.clone()).unwrap(); + let view_final = ImageView::new_default(tex_final.clone()).unwrap(); + + let set_fg = pipeline.uniform_sampler(0, view_fg.clone(), Filter::Nearest); + let set_bg = pipeline.uniform_sampler(0, view_bg.clone(), Filter::Nearest); + let pass_fg = pipeline.create_pass( + [width as _, height as _], + vertex_buffer.clone(), + graphics.quad_indices.clone(), + vec![set_fg], + ); + let pass_bg = pipeline.create_pass( + [width as _, height as _], + vertex_buffer.clone(), + graphics.quad_indices.clone(), + vec![set_bg], + ); + + let stride = width / RES_DIVIDER; + let rows = height / RES_DIVIDER; + + Self { + canvas: CanvasData { + data, + width, + height, + graphics, + pipeline_color, + pipeline_glyph, + }, + controls: Vec::new(), + hover_controls: [None, None], + pressed_controls: [None, None], + interact_map: vec![None; stride * rows], + interact_stride: stride, + interact_rows: rows, + tex_fg, + view_fg, + tex_bg, + view_bg, + tex_final, + view_final, + pass_fg, + pass_bg, + } + } + + fn interactive_set_idx(&mut self, x: f32, y: f32, w: f32, h: f32, idx: usize) { + let (x, y, w, h) = (x as usize, y as usize, w as usize, h as usize); + + let x_min = (x / RES_DIVIDER).max(0); + let y_min = (y / RES_DIVIDER).max(0); + let x_max = (x_min + (w / RES_DIVIDER)).min(self.interact_stride - 1); + let y_max = (y_min + (h / RES_DIVIDER)).min(self.interact_rows - 1); + + for y in y_min..y_max { + for x in x_min..x_max { + self.interact_map[y * self.interact_stride + x] = Some(idx as u8); + } + } + } + + fn interactive_get_idx(&self, uv: Vec2) -> Option { + let x = (uv.x * self.canvas.width as f32) as usize; + let y = (uv.y * self.canvas.height as f32) as usize; + let x = (x / RES_DIVIDER).max(0).min(self.interact_stride - 1); + let y = (y / RES_DIVIDER).max(0).min(self.interact_rows - 1); + self.interact_map[y * self.interact_stride + x].map(|x| x as usize) + } + + fn render_bg(&mut self, app: &mut AppState) { + let mut cmd_buffer = self + .canvas + .graphics + .create_command_buffer(CommandBufferUsage::OneTimeSubmit) + .begin(self.view_bg.clone()); + for c in self.controls.iter_mut() { + if let Some(fun) = c.on_render_bg { + fun(c, &self.canvas, app, &mut cmd_buffer); + } + } + let _ = cmd_buffer.end_render_and_execute(); + } + + fn render_fg(&mut self, app: &mut AppState) { + let mut cmd_buffer = self + .canvas + .graphics + .create_command_buffer(CommandBufferUsage::OneTimeSubmit) + .begin(self.view_fg.clone()); + for c in self.controls.iter_mut() { + if let Some(fun) = c.on_render_fg { + fun(c, &self.canvas, app, &mut cmd_buffer); + } + } + let _ = cmd_buffer.end_render_and_execute(); + } + + pub fn render_view(&self) -> Arc> { + self.view_final.clone() + } +} + +impl InteractionHandler for Canvas { + fn on_left(&mut self, _app: &mut AppState, hand: usize) { + self.hover_controls[hand] = None; + } + fn on_hover(&mut self, _app: &mut AppState, hit: &PointerHit) { + if let Some(i) = self.interactive_get_idx(hit.uv) { + self.hover_controls[hit.hand] = Some(i); + } else { + self.hover_controls[hit.hand] = None; + } + } + fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) { + let idx = if pressed { + self.interactive_get_idx(hit.uv) + } else { + self.pressed_controls[hit.hand] + }; + + if let Some(idx) = idx { + let c = &mut self.controls[idx]; + if pressed { + if let Some(ref mut f) = c.on_press { + self.pressed_controls[hit.hand] = Some(idx); + f(c, &mut self.canvas.data, app); + } + } else if let Some(ref mut f) = c.on_release { + self.pressed_controls[hit.hand] = None; + f(c, &mut self.canvas.data, app); + } + } + } + fn on_scroll(&mut self, _app: &mut AppState, _hit: &PointerHit, _delta: f32) {} +} + +impl OverlayRenderer for Canvas { + fn init(&mut self, app: &mut AppState) { + self.render_bg(app); + + self.render_fg(app); + } + fn pause(&mut self, _app: &mut AppState) {} + fn resume(&mut self, _app: &mut AppState) {} + fn render(&mut self, app: &mut AppState) { + let mut dirty = false; + + for c in self.controls.iter_mut() { + if let Some(fun) = c.on_update { + fun(c, &mut self.canvas.data, app); + } + if c.dirty { + dirty = true; + c.dirty = false; + } + } + + let mut cmd_buffer = self + .canvas + .graphics + .create_command_buffer(CommandBufferUsage::OneTimeSubmit) + .begin(self.view_final.clone()); + + if dirty { + self.render_fg(app); + } + + // static background + cmd_buffer.run_ref(&self.pass_bg); + + for (i, c) in self.controls.iter_mut().enumerate() { + if let Some(render) = c.on_render_hl { + if let Some(test) = c.test_highlight { + if test(c, &mut self.canvas.data, app) { + render(c, &self.canvas, app, &mut cmd_buffer, true); + } + } + if self.hover_controls.contains(&Some(i)) { + render(c, &self.canvas, app, &mut cmd_buffer, false); + } + } + } + + // mostly static text + cmd_buffer.run_ref(&self.pass_fg); + + let _ = cmd_buffer.end_render_and_execute(); + } + fn view(&mut self) -> Arc { + self.view_final.clone() + } +} + +impl OverlayBackend for Canvas {} + +pub struct Control { + pub state: Option, + rect: Rect, + fg_color: Vec3, + bg_color: Vec3, + text: Arc, + size: isize, + dirty: bool, + pass_hl: Option<(WlxPass, WlxPass)>, + + pub on_update: Option, + pub on_press: Option, + pub on_release: Option, + pub test_highlight: Option bool>, + + on_render_bg: Option< + fn(&Self, &CanvasData, &mut AppState, &mut WlxCommandBuffer), + >, + on_render_hl: Option< + fn( + &Self, + &CanvasData, + &mut AppState, + &mut WlxCommandBuffer, + bool, + ), + >, + on_render_fg: Option< + fn(&Self, &CanvasData, &mut AppState, &mut WlxCommandBuffer), + >, +} + +impl Control { + fn new() -> Self { + Self { + rect: Rect { + x: 0., + y: 0., + w: 0., + h: 0., + }, + fg_color: Vec3::ONE, + bg_color: Vec3::ZERO, + text: Arc::from(""), + dirty: false, + size: 24, + state: None, + on_update: None, + on_render_bg: None, + on_render_hl: None, + on_render_fg: None, + test_highlight: None, + on_press: None, + on_release: None, + pass_hl: None, + } + } + + #[inline(always)] + pub fn set_text(&mut self, text: &str) { + if *self.text == *text { + return; + } + self.text = text.into(); + self.dirty = true; + } + + #[inline(always)] + pub fn get_text(&self) -> &str { + &self.text + } + + fn render_rect( + &self, + canvas: &CanvasData, + _: &mut AppState, + cmd_buffer: &mut WlxCommandBuffer, + ) { + let pass = { + let vertex_buffer = canvas.graphics.upload_verts( + canvas.width as _, + canvas.height as _, + self.rect.x, + self.rect.y, + self.rect.w, + self.rect.h, + ); + let set0 = canvas.pipeline_color.uniform_buffer( + 0, + vec![self.bg_color.x, self.bg_color.y, self.bg_color.z, 1.], + ); + canvas.pipeline_color.create_pass( + [canvas.width as _, canvas.height as _], + vertex_buffer, + canvas.graphics.quad_indices.clone(), + vec![set0], + ) + }; + + cmd_buffer.run_ref(&pass); + } + + fn render_highlight( + &self, + canvas: &CanvasData, + _: &mut AppState, + cmd_buffer: &mut WlxCommandBuffer, + strong: bool, + ) { + let vertex_buffer = canvas.graphics.upload_verts( + canvas.width as _, + canvas.height as _, + self.rect.x, + self.rect.y, + self.rect.w, + self.rect.h, + ); + let set0 = canvas.pipeline_color.uniform_buffer( + 0, + vec![ + self.bg_color.x, + self.bg_color.y, + self.bg_color.z, + if strong { 0.5 } else { 0.3 }, + ], + ); + let pass = canvas.pipeline_color.create_pass( + [canvas.width as _, canvas.height as _], + vertex_buffer.clone(), + canvas.graphics.quad_indices.clone(), + vec![set0], + ); + + cmd_buffer.run_ref(&pass); + } + + fn render_text( + &self, + canvas: &CanvasData, + app: &mut AppState, + cmd_buffer: &mut WlxCommandBuffer, + ) { + let mut cur_y = self.rect.y; + for line in self.text.lines() { + let mut cur_x = self.rect.x; + for glyph in app.fc.get_glyphs(line, self.size, canvas.graphics.clone()) { + if let Some(tex) = glyph.tex.clone() { + let vertex_buffer = canvas.graphics.upload_verts( + canvas.width as _, + canvas.height as _, + cur_x + glyph.left, + cur_y - glyph.top, + glyph.width, + glyph.height, + ); + let set0 = canvas.pipeline_glyph.uniform_sampler( + 0, + ImageView::new_default(tex).unwrap(), + Filter::Nearest, + ); + let set1 = canvas.pipeline_glyph.uniform_buffer( + 1, + vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.], + ); + let pass = canvas.pipeline_glyph.create_pass( + [canvas.width as _, canvas.height as _], + vertex_buffer, + canvas.graphics.quad_indices.clone(), + vec![set0, set1], + ); + cmd_buffer.run_ref(&pass); + } + cur_x += glyph.advance; + } + cur_y += (self.size as f32) * 1.5; + } + } + fn render_text_centered( + &self, + canvas: &CanvasData, + app: &mut AppState, + cmd_buffer: &mut WlxCommandBuffer, + ) { + let (w, h) = app + .fc + .get_text_size(&self.text, self.size, canvas.graphics.clone()); + + let mut cur_y = self.rect.y + (self.rect.h) - (h * 0.5); + for line in self.text.lines() { + let mut cur_x = self.rect.x + (self.rect.w * 0.5) - (w * 0.5); + for glyph in app.fc.get_glyphs(line, self.size, canvas.graphics.clone()) { + if let Some(tex) = glyph.tex.clone() { + let vertex_buffer = canvas.graphics.upload_verts( + canvas.width as _, + canvas.height as _, + cur_x + glyph.left, + cur_y - glyph.top, + glyph.width, + glyph.height, + ); + let set0 = canvas.pipeline_glyph.uniform_sampler( + 0, + ImageView::new_default(tex).unwrap(), + Filter::Nearest, + ); + let set1 = canvas.pipeline_glyph.uniform_buffer( + 1, + vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.], + ); + let pass = canvas.pipeline_glyph.create_pass( + [canvas.width as _, canvas.height as _], + vertex_buffer, + canvas.graphics.quad_indices.clone(), + vec![set0, set1], + ); + cmd_buffer.run_ref(&pass); + } + cur_x += glyph.advance; + } + cur_y += (self.size as f32) * 1.5; + } + } +} diff --git a/src/image.png b/src/image.png new file mode 100644 index 0000000..b9e2802 Binary files /dev/null and b/src/image.png differ diff --git a/src/input.rs b/src/input.rs new file mode 100644 index 0000000..569a4a2 --- /dev/null +++ b/src/input.rs @@ -0,0 +1,431 @@ +use glam::Vec2; +use idmap::{idmap, IdMap}; +use idmap_derive::IntegerId; +use input_linux::{ + AbsoluteAxis, AbsoluteInfo, AbsoluteInfoSetup, EventKind, InputId, Key, RelativeAxis, + UInputHandle, +}; +use libc::{input_event, timeval}; +use log::{error, info}; +use once_cell::sync::Lazy; +use std::fs::File; +use std::mem::transmute; +use strum::{EnumIter, EnumString, IntoEnumIterator}; + +pub fn initialize_input() -> Box { + if let Some(uinput) = UInputProvider::try_new() { + info!("Initialized uinput."); + return Box::new(uinput); + } + error!("Could not create uinput provider. Keyboard/Mouse input will not work!"); + error!("Check if you're in `input` group: `id -nG`"); + Box::new(DummyProvider {}) +} + +pub trait InputProvider { + fn mouse_move(&mut self, pos: Vec2); + fn send_button(&self, button: u16, down: bool); + fn wheel(&self, delta: i32); + fn set_modifiers(&mut self, mods: u8); + fn send_key(&self, key: u16, down: bool); + fn set_desktop_extent(&mut self, extent: Vec2); + fn on_new_frame(&mut self); +} + +pub struct UInputProvider { + handle: UInputHandle, + desktop_extent: Vec2, + mouse_moved: bool, + cur_modifiers: u8, +} + +pub struct DummyProvider; + +pub const MOUSE_LEFT: u16 = 0x110; +pub const MOUSE_RIGHT: u16 = 0x111; +pub const MOUSE_MIDDLE: u16 = 0x112; + +const MOUSE_EXTENT: f32 = 32768.; + +const EV_SYN: u16 = 0x0; +const EV_KEY: u16 = 0x1; +const EV_REL: u16 = 0x2; +const EV_ABS: u16 = 0x3; + +impl UInputProvider { + fn try_new() -> Option { + if let Ok(file) = File::create("/dev/uinput") { + let handle = UInputHandle::new(file); + + let id = InputId { + bustype: 0x03, + vendor: 0x4711, + product: 0x0819, + version: 5, + }; + + let name = b"WlxOverlay Keyboard-Mouse Hybrid Thing\0"; + + let abs_info = vec![ + AbsoluteInfoSetup { + axis: input_linux::AbsoluteAxis::X, + info: AbsoluteInfo { + value: 0, + minimum: 0, + maximum: MOUSE_EXTENT as _, + fuzz: 0, + flat: 0, + resolution: 10, + }, + }, + AbsoluteInfoSetup { + axis: input_linux::AbsoluteAxis::Y, + info: AbsoluteInfo { + value: 0, + minimum: 0, + maximum: MOUSE_EXTENT as _, + fuzz: 0, + flat: 0, + resolution: 10, + }, + }, + ]; + + if handle.set_evbit(EventKind::Key).is_err() { + return None; + } + if handle.set_evbit(EventKind::Absolute).is_err() { + return None; + } + if handle.set_evbit(EventKind::Relative).is_err() { + return None; + } + + for btn in MOUSE_LEFT..=MOUSE_MIDDLE { + let key: Key = unsafe { transmute(btn) }; + if handle.set_keybit(key).is_err() { + return None; + } + } + + for key in VirtualKey::iter() { + let key: Key = unsafe { transmute(key as u16) }; + if handle.set_keybit(key).is_err() { + return None; + } + } + + if handle.set_absbit(AbsoluteAxis::X).is_err() { + return None; + } + if handle.set_absbit(AbsoluteAxis::Y).is_err() { + return None; + } + if handle.set_relbit(RelativeAxis::Wheel).is_err() { + return None; + } + + if handle.create(&id, name, 0, &abs_info).is_ok() { + return Some(UInputProvider { + handle, + desktop_extent: Vec2::ZERO, + mouse_moved: false, + cur_modifiers: 0, + }); + } + } + None + } +} + +impl InputProvider for UInputProvider { + fn mouse_move(&mut self, pos: Vec2) { + if self.mouse_moved { + return; + } + self.mouse_moved = true; + + let pos = pos * (MOUSE_EXTENT / self.desktop_extent); + + let time = get_time(); + let events = [ + new_event(time, EV_ABS, AbsoluteAxis::X as _, pos.x as i32), + new_event(time, EV_ABS, AbsoluteAxis::Y as _, pos.y as i32), + new_event(time, EV_SYN, 0, 0), + ]; + if let Err(res) = self.handle.write(&events) { + error!("{}", res.to_string()); + } + } + fn send_button(&self, button: u16, down: bool) { + let time = get_time(); + let events = [ + new_event(time, EV_KEY, button, down as _), + new_event(time, EV_SYN, 0, 0), + ]; + if let Err(res) = self.handle.write(&events) { + error!("{}", res.to_string()); + } + } + fn wheel(&self, delta: i32) { + let time = get_time(); + let events = [ + new_event(time, EV_REL, RelativeAxis::Wheel as _, delta), + new_event(time, EV_SYN, 0, 0), + ]; + if let Err(res) = self.handle.write(&events) { + error!("{}", res.to_string()); + } + } + fn set_modifiers(&mut self, modifiers: u8) { + let changed = self.cur_modifiers ^ modifiers; + for i in 0..7 { + let m = 1 << i; + if changed & m != 0 { + let vk = MODS_TO_KEYS.get(m).unwrap()[0] as u16; + self.send_key(vk, modifiers & m != 0); + } + } + self.cur_modifiers = modifiers; + } + fn send_key(&self, key: u16, down: bool) { + let time = get_time(); + let events = [ + new_event(time, EV_KEY, key - 8, down as _), + new_event(time, EV_SYN, 0, 0), + ]; + if let Err(res) = self.handle.write(&events) { + error!("{}", res.to_string()); + } + } + fn set_desktop_extent(&mut self, extent: Vec2) { + info!("Desktop extent: {:?}", extent); + self.desktop_extent = extent; + } + fn on_new_frame(&mut self) { + self.mouse_moved = false; + } +} + +impl InputProvider for DummyProvider { + fn mouse_move(&mut self, _pos: Vec2) {} + fn send_button(&self, _button: u16, _down: bool) {} + fn wheel(&self, _delta: i32) {} + fn set_modifiers(&mut self, _modifiers: u8) {} + fn send_key(&self, _key: u16, _down: bool) {} + fn set_desktop_extent(&mut self, _extent: Vec2) {} + fn on_new_frame(&mut self) {} +} + +#[inline] +fn get_time() -> timeval { + let mut time = timeval { + tv_sec: 0, + tv_usec: 0, + }; + unsafe { libc::gettimeofday(&mut time, std::ptr::null_mut()) }; + time +} + +#[inline] +fn new_event(time: timeval, type_: u16, code: u16, value: i32) -> input_event { + input_event { + time, + type_, + code, + value, + } +} + +pub type KeyModifier = u8; +pub const SHIFT: KeyModifier = 0x01; +pub const CAPS_LOCK: KeyModifier = 0x02; +pub const CTRL: KeyModifier = 0x04; +pub const ALT: KeyModifier = 0x08; +pub const NUM_LOCK: KeyModifier = 0x10; +pub const SUPER: KeyModifier = 0x40; +pub const META: KeyModifier = 0x80; + +#[allow(non_camel_case_types)] +#[derive(Debug, PartialEq, Clone, Copy, IntegerId, EnumString, EnumIter)] +pub enum VirtualKey { + Escape = 9, + N1, // number row + N2, + N3, + N4, + N5, + N6, + N7, + N8, + N9, + N0, + Minus, + Plus, + BackSpace, + Tab, + Q, + W, + E, + R, + T, + Y, + U, + I, + O, + P, + Oem4, // [ { + Oem6, // ] } + Return, + LCtrl, + A, + S, + D, + F, + G, + H, + J, + K, + L, + Oem1, // ; : + Oem7, // ' " + Oem3, // ` ~ + LShift, + Oem5, // \ | + Z, + X, + C, + V, + B, + N, + M, + Comma, // , < + Period, // . > + Oem2, // / ? + RShift, + KP_Multiply, + LAlt, + Space, + Caps, + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + NumLock, + Scroll, + KP_7, // KeyPad + KP_8, + KP_9, + KP_Subtract, + KP_4, + KP_5, + KP_6, + KP_Add, + KP_1, + KP_2, + KP_3, + KP_0, + KP_Decimal, + Oem102 = 94, // Optional key usually between LShift and Z + F11, + F12, + AbntC1, + Katakana, + Hiragana, + Henkan, + Kana, + Muhenkan, + KP_Enter = 104, + RCtrl, + KP_Divide, + Print, + Meta, // Right Alt aka AltGr + Home = 110, + Up, + Prior, + Left, + Right, + End, + Down, + Next, + Insert, + Delete, + XF86AudioMute = 121, + XF86AudioLowerVolume, + XF86AudioRaiseVolume, + Pause = 127, + AbntC2 = 129, + Hangul, + Hanja, + LSuper = 133, + RSuper, + Menu, + Help = 146, + XF86MenuKB, + XF86Sleep = 150, + XF86Xfer = 155, + XF86Launch1, + XF86Launch2, + XF86WWW, + XF86Mail = 163, + XF86Favorites, + XF86MyComputer, + XF86Back, + XF86Forward, + XF86AudioNext = 171, + XF86AudioPlay, + XF86AudioPrev, + XF86AudioStop, + XF86HomePage = 180, + XF86Reload, + F13 = 191, + F14, + F15, + F16, + F17, + F18, + F19, + F20, + F21, + F22, + F23, + F24, + Hyper = 207, + XF86Launch3, + XF86Launch4, + XF86LaunchB, + XF86Search = 225, +} + +pub static KEYS_TO_MODS: Lazy> = Lazy::new(|| { + idmap! { + VirtualKey::LShift => SHIFT, + VirtualKey::RShift => SHIFT, + VirtualKey::Caps => CAPS_LOCK, + VirtualKey::LCtrl => CTRL, + VirtualKey::RCtrl => CTRL, + VirtualKey::LAlt => ALT, + VirtualKey::NumLock => NUM_LOCK, + VirtualKey::LSuper => SUPER, + VirtualKey::RSuper => SUPER, + VirtualKey::Meta => META, + } +}); + +pub static MODS_TO_KEYS: Lazy>> = Lazy::new(|| { + idmap! { + SHIFT => vec![VirtualKey::LShift, VirtualKey::RShift], + CAPS_LOCK => vec![VirtualKey::Caps], + CTRL => vec![VirtualKey::LCtrl, VirtualKey::RCtrl], + ALT => vec![VirtualKey::LAlt], + NUM_LOCK => vec![VirtualKey::NumLock], + SUPER => vec![VirtualKey::LSuper, VirtualKey::RSuper], + META => vec![VirtualKey::Meta], + } +}); diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..fac077a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,271 @@ +#[allow(dead_code)] +mod backend; +mod graphics; +mod gui; +mod input; +mod overlays; +mod ovr; +mod shaders; +mod state; + +use std::collections::VecDeque; +use std::sync::Arc; + +use crate::graphics::{Vert2Uv, WlxGraphics, INDICES}; +use crate::input::initialize_input; +use crate::overlays::watch::create_watch; +use crate::{ + shaders::{frag_sprite, vert_common}, + state::AppState, +}; +use env_logger::Env; +use log::{info, warn}; +use vulkano::{ + buffer::BufferUsage, + command_buffer::CommandBufferUsage, + image::{ + view::{ImageView, ImageViewCreateInfo}, + ImageAccess, ImageSubresourceRange, ImageViewType, SwapchainImage, + }, + pipeline::graphics::viewport::Viewport, + sampler::Filter, + swapchain::{ + acquire_next_image, AcquireError, SwapchainCreateInfo, SwapchainCreationError, + SwapchainPresentInfo, + }, + sync::{self, FlushError, GpuFuture}, +}; +use winit::{ + event::{Event, WindowEvent}, + event_loop::ControlFlow, + window::Window, +}; +use wlx_capture::{frame::WlxFrame, wayland::WlxClient, wlr::WlrDmabufCapture, WlxCapture}; + +fn main() { + env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); + info!( + "Welcome to {} version {}!", + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_VERSION") + ); + + let (graphics, event_loop) = WlxGraphics::new(); + let (mut swapchain, images) = graphics.create_swapchain(None); + + let mut app = AppState { + fc: crate::gui::font::FontCache::new(), + session: crate::state::AppSession::load(), + tasks: VecDeque::with_capacity(16), + graphics: graphics.clone(), + format: swapchain.image_format(), + input: initialize_input(), + }; + + let wl = WlxClient::new().unwrap(); + let output_id = wl.outputs[0].id; + let mut capture = WlrDmabufCapture::new(wl, output_id).unwrap(); + let rx = capture.init(); + + let vertices = [ + Vert2Uv { + in_pos: [0., 0.], + in_uv: [0., 0.], + }, + Vert2Uv { + in_pos: [0., 1.], + in_uv: [0., 1.], + }, + Vert2Uv { + in_pos: [1., 0.], + in_uv: [1., 0.], + }, + Vert2Uv { + in_pos: [1., 1.], + in_uv: [1., 1.], + }, + ]; + + let vertex_buffer = graphics.upload_buffer(BufferUsage::VERTEX_BUFFER, vertices.iter()); + let index_buffer = graphics.upload_buffer(BufferUsage::INDEX_BUFFER, INDICES.iter()); + + let vs = vert_common::load(graphics.device.clone()).unwrap(); + let fs = frag_sprite::load(graphics.device.clone()).unwrap(); + + let uploads = graphics.create_command_buffer(CommandBufferUsage::OneTimeSubmit); + + let mut watch = create_watch(&app, vec![]); + watch.init(&mut app); + watch.render(&mut app); + + let pipeline1 = graphics.create_pipeline(vs.clone(), fs.clone(), swapchain.image_format()); + let set1 = pipeline1.uniform_sampler(0, watch.view(), Filter::Nearest); + + capture.request_new_frame(); + + let pipeline = graphics.create_pipeline(vs, fs, swapchain.image_format()); + let set0; + loop { + if let Ok(frame) = rx.try_recv() { + match frame { + WlxFrame::Dmabuf(dmabuf_frame) => match graphics.dmabuf_texture(dmabuf_frame) { + Ok(tex) => { + let format = tex.format(); + let view = ImageView::new( + tex, + ImageViewCreateInfo { + format: Some(format), + view_type: ImageViewType::Dim2d, + subresource_range: ImageSubresourceRange::from_parameters( + format, 1, 1, + ), + ..Default::default() + }, + ) + .unwrap(); + set0 = pipeline.uniform_sampler(0, view, Filter::Nearest); + break; + } + Err(e) => { + warn!("Failed to create texture from dmabuf: {}", e); + } + }, + _ => { + warn!("Received non-dmabuf frame"); + } + } + } + } + + //let set1 = graphics.uniform_buffer(1, vec![1.0, 1.0, 1.0, 1.0]); + let image_extent_f32 = [ + swapchain.image_extent()[0] as f32, + swapchain.image_extent()[1] as f32, + ]; + let image_extent2_f32 = [ + swapchain.image_extent()[0] as f32 / 2., + swapchain.image_extent()[1] as f32 / 2., + ]; + let pass = pipeline.create_pass( + image_extent_f32, + vertex_buffer.clone(), + index_buffer.clone(), + vec![set0], + ); + let pass2 = pipeline1.create_pass(image_extent2_f32, vertex_buffer, index_buffer, vec![set1]); + + let mut viewport = Viewport { + origin: [0.0, 0.0], + dimensions: [1024.0, 1024.0], + depth_range: 0.0..1.0, + }; + + let mut attachment_image_views = window_size_dependent_setup(&images, &mut viewport); + + //let set1 = pipeline.uniform_buffer(1, vec![1.0, 0.0, 1.0, 1.0]); + + let mut recreate_swapchain = false; + let mut previous_frame_end = //Some(sync::now(graphics.device.clone()).boxed()); + Some(uploads.end_and_execute().boxed()); + + event_loop.run(move |event, _, control_flow| match event { + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => { + *control_flow = ControlFlow::Exit; + } + Event::WindowEvent { + event: WindowEvent::Resized(_), + .. + } => { + recreate_swapchain = true; + } + Event::RedrawEventsCleared => { + previous_frame_end.as_mut().unwrap().cleanup_finished(); + + if recreate_swapchain { + let window = graphics + .surface + .object() + .unwrap() + .downcast_ref::() + .unwrap(); + let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { + image_extent: window.inner_size().into(), + ..swapchain.create_info() + }) { + Ok(r) => r, + Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return, + Err(e) => panic!("failed to recreate swapchain: {e}"), + }; + + swapchain = new_swapchain; + attachment_image_views = window_size_dependent_setup(&new_images, &mut viewport); + recreate_swapchain = false; + } + + let (image_index, suboptimal, acquire_future) = + match acquire_next_image(swapchain.clone(), None) { + Ok(r) => r, + Err(AcquireError::OutOfDate) => { + recreate_swapchain = true; + return; + } + Err(e) => panic!("failed to acquire next image: {e}"), + }; + + if suboptimal { + recreate_swapchain = true; + } + + let cmd = graphics + .create_command_buffer(CommandBufferUsage::OneTimeSubmit) + .begin(attachment_image_views[image_index as usize].clone()) + .run(&pass) + .run(&pass2) + .end_render(); + + let future = previous_frame_end + .take() + .unwrap() + .join(acquire_future) + .then_execute(graphics.queue.clone(), cmd) + .unwrap() + .then_swapchain_present( + graphics.queue.clone(), + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), + ) + .then_signal_fence_and_flush(); + + match future { + Ok(future) => { + previous_frame_end = Some(future.boxed()); + } + Err(FlushError::OutOfDate) => { + recreate_swapchain = true; + previous_frame_end = Some(sync::now(graphics.device.clone()).boxed()); + } + Err(e) => { + println!("failed to flush future: {e}"); + previous_frame_end = Some(sync::now(graphics.device.clone()).boxed()); + } + } + } + _ => (), + }); +} + +/// This function is called once during initialization, then again whenever the window is resized. +fn window_size_dependent_setup( + images: &[Arc], + viewport: &mut Viewport, +) -> Vec>> { + let dimensions = images[0].dimensions().width_height(); + viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + + images + .iter() + .map(|image| ImageView::new_default(image.clone()).unwrap()) + .collect::>() +} diff --git a/src/main.rs.bak2 b/src/main.rs.bak2 new file mode 100644 index 0000000..8630400 --- /dev/null +++ b/src/main.rs.bak2 @@ -0,0 +1,159 @@ +#[allow(dead_code)] +#[allow(unused_imports)] + +mod graphics; +//mod gui; +//mod interactions; +//mod overlay; +//mod state; + +use core::slice; + +use ash::vk; +use env_logger::Env; +use glam::f32::Vec4; +use log::{info, warn}; +use wlx_capture::{wlr::WlrDmabufCapture, wayland::WlxClient, WlxCapture, frame::WlxFrame}; + +use crate::{graphics::{VkGraphics, VkDescriptor}}; + +fn main() { + env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); + info!("Welcome to {} version {}!", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); + +// let mut app = AppState { +// fc: gui::font::FontCache::new(), +// session: state::AppSession::load(), +// }; + + let wl = WlxClient::new().unwrap(); + let output_id = wl.outputs[0].id; + let mut capture = WlrDmabufCapture::new(wl, output_id).unwrap(); + let rx = capture.init(); + + let gfx = VkGraphics::new(); + let vert = gfx.create_shader(include_bytes!("shaders/vert-common.spv"), None); + let frag_sprite = gfx.create_shader( + include_bytes!("shaders/frag-sprite.spv"), + Some(vec![vk::DescriptorType::COMBINED_IMAGE_SAMPLER]) + ); + let frag_srgb = gfx.create_shader( + include_bytes!("shaders/frag-srgb.spv"), + Some(vec![vk::DescriptorType::COMBINED_IMAGE_SAMPLER]) + ); + let frag_glyph = gfx.create_shader( + include_bytes!("shaders/frag-glyph.spv"), + Some(vec![vk::DescriptorType::COMBINED_IMAGE_SAMPLER, vk::DescriptorType::UNIFORM_BUFFER]) + ); + let frag_color = gfx.create_shader( + include_bytes!("shaders/frag-color.spv"), + Some(vec![vk::DescriptorType::UNIFORM_BUFFER]) + ); + + let pipeline = gfx.create_pipeline(vert, frag_color, gfx.swapchain_format); + + let color_buf = gfx.create_buffer(vk::BufferUsageFlags::UNIFORM_BUFFER, &[Vec4::new(1.0, 0.0, 1.0, 1.0); 16]); + + gfx.render_loop(|| { + let frame = gfx.create_frame(); + + unsafe { gfx.device.reset_command_pool(frame.command_pool, vk::CommandPoolResetFlags::RELEASE_RESOURCES) }.unwrap(); + + let (present_index, _) = unsafe { + gfx.swapchain_loader.acquire_next_image( + gfx.swapchain, + std::u64::MAX, + frame.present_semaphore, + vk::Fence::null() + ).unwrap() + }; + + let command_buffer_begin_info = vk::CommandBufferBeginInfo::builder() + .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT) + .build(); + + unsafe { gfx.device.begin_command_buffer(frame.command_buffer, &command_buffer_begin_info) }.unwrap(); + + let image = gfx.present_images[present_index as usize]; + + let image_memory_barrier = vk::ImageMemoryBarrier2::builder() + .src_stage_mask(vk::PipelineStageFlags2::TOP_OF_PIPE) + .dst_stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) + .dst_access_mask(vk::AccessFlags2::COLOR_ATTACHMENT_WRITE) + .old_layout(vk::ImageLayout::UNDEFINED) + .new_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL) + .image(image) + .subresource_range(vk::ImageSubresourceRange::builder().aspect_mask(vk::ImageAspectFlags::COLOR).level_count(1).layer_count(1).build()) + .build(); + + unsafe { gfx.device.cmd_pipeline_barrier2(frame.command_buffer, &vk::DependencyInfo::builder().image_memory_barriers(slice::from_ref(&image_memory_barrier)).build()) }; + + let color_attachment = vk::RenderingAttachmentInfo::builder() + .image_view(gfx.present_image_views[present_index as usize]) + .image_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL) + .load_op(vk::AttachmentLoadOp::CLEAR) + .store_op(vk::AttachmentStoreOp::STORE) + .clear_value(vk::ClearValue { + color: vk::ClearColorValue { + float32: [0.0, 0.0, 0.0, 1.0] + } + }); + + let rendering_info = vk::RenderingInfo::builder() + .render_area(vk::Rect2D::builder().extent(vk::Extent2D::builder().width(1600).height(900).build()).build()) + .layer_count(1) + .color_attachments(slice::from_ref(&color_attachment)) + .build(); + + + unsafe { gfx.device.cmd_begin_rendering(frame.command_buffer, &rendering_info) }; + + let descriptor = VkDescriptor::Buffer(color_buf.clone()); + pipeline.bind_descriptors(slice::from_ref(&descriptor)); + pipeline.render(&frame, vk::Rect2D { + offset: vk::Offset2D { x: 0, y: 0 }, + extent: vk::Extent2D { width: 1600, height: 900 } + }); + + unsafe { gfx.device.cmd_end_rendering(frame.command_buffer) }; + + + let image_memory_barrier = vk::ImageMemoryBarrier2::builder() + .src_stage_mask(vk::PipelineStageFlags2::COLOR_ATTACHMENT_OUTPUT) + .src_access_mask(vk::AccessFlags2::COLOR_ATTACHMENT_WRITE) + .dst_stage_mask(vk::PipelineStageFlags2::BOTTOM_OF_PIPE) + .old_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL) + .new_layout(vk::ImageLayout::PRESENT_SRC_KHR) + .image(image) + .subresource_range(vk::ImageSubresourceRange::builder().aspect_mask(vk::ImageAspectFlags::COLOR).level_count(1).layer_count(1).build()) + .build(); + + unsafe { + gfx.device.cmd_pipeline_barrier2(frame.command_buffer, &vk::DependencyInfo::builder().image_memory_barriers(slice::from_ref(&image_memory_barrier)).build()); + }; + + unsafe { gfx.device.end_command_buffer(frame.command_buffer) }.unwrap(); + + let wait_semaphores = [frame.present_semaphore]; + let wait_dst_stage_mask = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; + + let submit_info = vk::SubmitInfo::builder() + .wait_semaphores(&wait_semaphores) + .wait_dst_stage_mask(&wait_dst_stage_mask) + .command_buffers(slice::from_ref(&frame.command_buffer)) + .signal_semaphores(slice::from_ref(&frame.render_semaphore)); + + unsafe { gfx.device.queue_submit(gfx.present_queue, slice::from_ref(&submit_info), frame.fence) }.unwrap(); + + let present_info = vk::PresentInfoKHR::builder() + .wait_semaphores(slice::from_ref(&frame.present_semaphore)) + .swapchains(slice::from_ref(&gfx.swapchain)) + .image_indices(slice::from_ref(&present_index)) + .build(); + + unsafe { gfx.swapchain_loader.queue_present(gfx.present_queue, &present_info).unwrap() }; + }); + + unsafe { gfx.device.device_wait_idle().unwrap() }; +} + diff --git a/src/overlays/interactions.rs b/src/overlays/interactions.rs new file mode 100644 index 0000000..6f05226 --- /dev/null +++ b/src/overlays/interactions.rs @@ -0,0 +1,41 @@ +use std::{collections::VecDeque, time::Instant}; + +use glam::{Affine3A, Vec2, Vec3}; + +use crate::state::AppState; + +pub const HAND_LEFT: usize = 0; +pub const HAND_RIGHT: usize = 1; + +pub const POINTER_NORM: u16 = 0; +pub const POINTER_SHIFT: u16 = 1; +pub const POINTER_ALT: u16 = 2; + +pub trait InteractionHandler { + fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit); + fn on_left(&mut self, app: &mut AppState, hand: usize); + fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool); + fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32); +} + +// --- Dummies & plumbing below --- + +impl Default for PointerState { + fn default() -> Self { + Self { + click: false, + grab: false, + show_hide: false, + scroll: 0., + } + } +} + +pub struct DummyInteractionHandler; + +impl InteractionHandler for DummyInteractionHandler { + fn on_left(&mut self, _app: &mut AppState, _hand: usize) {} + fn on_hover(&mut self, _app: &mut AppState, _hit: &PointerHit) {} + fn on_pointer(&mut self, _app: &mut AppState, _hit: &PointerHit, _pressed: bool) {} + fn on_scroll(&mut self, _app: &mut AppState, _hit: &PointerHit, _delta: f32) {} +} diff --git a/src/overlays/keyboard.rs b/src/overlays/keyboard.rs new file mode 100644 index 0000000..63540ac --- /dev/null +++ b/src/overlays/keyboard.rs @@ -0,0 +1,354 @@ +use std::{ + collections::HashMap, + env::var, + fs, + io::Cursor, + path::PathBuf, + process::{Child, Command}, + str::FromStr, + sync::Arc, +}; + +use crate::{ + gui::{color_parse, CanvasBuilder, Control}, + input::{KeyModifier, VirtualKey, KEYS_TO_MODS}, + state::AppState, +}; +use glam::{vec2, vec3}; +use log::error; +use once_cell::sync::Lazy; +use regex::Regex; +use rodio::{Decoder, OutputStream, Source}; +use serde::{Deserialize, Serialize}; + +use super::OverlayData; + +const PIXELS_PER_UNIT: f32 = 80.; +const BUTTON_PADDING: f32 = 4.; + +pub fn create_keyboard(app: &AppState) -> OverlayData { + let size = vec2( + LAYOUT.row_size * PIXELS_PER_UNIT, + (LAYOUT.main_layout.len() as f32) * PIXELS_PER_UNIT, + ); + + let data = KeyboardData { + modifiers: 0, + processes: vec![], + audio_stream: None, + }; + + let mut canvas = CanvasBuilder::new( + size.x as _, + size.y as _, + app.graphics.clone(), + app.format, + data, + ); + + canvas.bg_color = color_parse("#101010"); + canvas.panel(0., 0., size.x, size.y); + + canvas.font_size = 18; + canvas.bg_color = color_parse("#202020"); + + let unit_size = size.x / LAYOUT.row_size; + let h = unit_size - 2. * BUTTON_PADDING; + + for row in 0..LAYOUT.key_sizes.len() { + let y = unit_size * (row as f32) + BUTTON_PADDING; + let mut sum_size = 0f32; + + for col in 0..LAYOUT.key_sizes[row].len() { + let my_size = LAYOUT.key_sizes[row][col]; + let x = unit_size * sum_size + BUTTON_PADDING; + let w = unit_size * my_size - 2. * BUTTON_PADDING; + + if let Some(key) = LAYOUT.main_layout[row][col].as_ref() { + let mut maybe_state: Option = None; + if let Ok(vk) = VirtualKey::from_str(key) { + if let Some(mods) = KEYS_TO_MODS.get(vk) { + maybe_state = Some(KeyButtonData::Modifier { + modifier: *mods, + sticky: false, + pressed: false, + }); + } else { + maybe_state = Some(KeyButtonData::Key { vk, pressed: false }); + } + } else if let Some(macro_verbs) = LAYOUT.macros.get(key) { + maybe_state = Some(KeyButtonData::Macro { + verbs: key_events_for_macro(macro_verbs), + }); + } else if let Some(exec_args) = LAYOUT.exec_commands.get(key) { + maybe_state = Some(KeyButtonData::Exec { + program: exec_args.first().unwrap().clone(), + args: exec_args.iter().skip(1).cloned().collect(), + }); + } else { + error!("Unknown key: {}", key); + } + + if let Some(state) = maybe_state { + let label = LAYOUT.label_for_key(key); + let button = canvas.key_button(x, y, w, h, &label); + button.state = Some(state); + button.on_press = Some(key_press); + button.on_release = Some(key_release); + button.test_highlight = Some(test_highlight); + } + } + + sum_size += my_size; + } + } + + let canvas = canvas.build(); + + OverlayData { + name: Arc::from("Kbd"), + show_hide: true, + width: LAYOUT.row_size * 0.05, + size: (size.x as _, size.y as _), + grabbable: true, + spawn_point: vec3(0., -0.5, -1.), + backend: Box::new(canvas), + ..Default::default() + } +} + +fn key_press( + control: &mut Control, + data: &mut KeyboardData, + app: &mut AppState, +) { + match control.state.as_mut() { + Some(KeyButtonData::Key { vk, pressed }) => { + data.key_click(); + app.input.send_key(*vk as _, true); + *pressed = true; + } + Some(KeyButtonData::Modifier { + modifier, + sticky, + pressed, + }) => { + *sticky = data.modifiers & *modifier == 0; + data.modifiers |= *modifier; + data.key_click(); + app.input.set_modifiers(data.modifiers); + *pressed = true; + } + Some(KeyButtonData::Macro { verbs }) => { + data.key_click(); + for (vk, press) in verbs { + app.input.send_key(*vk as _, *press); + } + } + Some(KeyButtonData::Exec { program, args }) => { + // Reap previous processes + data.processes + .retain_mut(|child| !matches!(child.try_wait(), Ok(Some(_)))); + + data.key_click(); + if let Ok(child) = Command::new(program).args(args).spawn() { + data.processes.push(child); + } + } + None => {} + } +} + +fn key_release( + control: &mut Control, + data: &mut KeyboardData, + app: &mut AppState, +) { + match control.state.as_mut() { + Some(KeyButtonData::Key { vk, pressed }) => { + app.input.send_key(*vk as _, false); + *pressed = false; + } + Some(KeyButtonData::Modifier { + modifier, + sticky, + pressed, + }) => { + if !*sticky { + data.modifiers &= !*modifier; + app.input.set_modifiers(data.modifiers); + *pressed = false; + } + } + _ => {} + } +} + +fn test_highlight( + control: &Control, + _data: &mut KeyboardData, + _app: &mut AppState, +) -> bool { + match control.state.as_ref() { + Some(KeyButtonData::Key { pressed, .. }) => *pressed, + Some(KeyButtonData::Modifier { pressed, .. }) => *pressed, + _ => false, + } +} + +struct KeyboardData { + modifiers: KeyModifier, + processes: Vec, + audio_stream: Option, +} + +impl KeyboardData { + fn key_click(&mut self) { + let wav = include_bytes!("../res/421581.wav"); + let cursor = Cursor::new(wav); + let source = Decoder::new_wav(cursor).unwrap(); + self.audio_stream = None; + if let Ok((stream, handle)) = OutputStream::try_default() { + let _ = handle.play_raw(source.convert_samples()); + self.audio_stream = Some(stream); + } else { + error!("Failed to play key click"); + } + } +} + +enum KeyButtonData { + Key { + vk: VirtualKey, + pressed: bool, + }, + Modifier { + modifier: KeyModifier, + sticky: bool, + pressed: bool, + }, + Macro { + verbs: Vec<(VirtualKey, bool)>, + }, + Exec { + program: String, + args: Vec, + }, +} + +static KEYBOARD_YAML: Lazy = Lazy::new(|| { + let home = &var("HOME").unwrap(); + [home, ".config/wlxoverlay/keyboard.yaml"].iter().collect() //TODO other paths +}); + +static LAYOUT: Lazy = Lazy::new(Layout::load_from_disk); + +static MACRO_REGEX: Lazy = + Lazy::new(|| Regex::new(r"^([A-Za-z0-1_-]+)(?: +(UP|DOWN))?$").unwrap()); + +#[derive(Debug, Deserialize, Serialize)] +struct Layout { + name: String, + row_size: f32, + key_sizes: Vec>, + main_layout: Vec>>, + exec_commands: HashMap>, + macros: HashMap>, + labels: HashMap>, +} + +impl Layout { + fn load_from_disk() -> Layout { + let mut yaml = fs::read_to_string(KEYBOARD_YAML.as_path()).ok(); + + if yaml.is_none() { + yaml = Some(include_str!("../res/keyboard.yaml").to_string()); + } + + let mut layout: Layout = + serde_yaml::from_str(&yaml.unwrap()).expect("Failed to parse keyboard.yaml"); + layout.post_load(); + + layout + } + + fn post_load(&mut self) { + for i in 0..self.key_sizes.len() { + let row = &self.key_sizes[i]; + let width: f32 = row.iter().sum(); + if (width - self.row_size).abs() > 0.001 { + panic!( + "Row {} has a width of {}, but the row size is {}", + i, width, self.row_size + ); + } + } + + for i in 0..self.main_layout.len() { + let row = &self.main_layout[i]; + let width = row.len(); + if width != self.key_sizes[i].len() { + panic!( + "Row {} has {} keys, needs to have {} according to key_sizes", + i, + width, + self.key_sizes[i].len() + ); + } + } + } + + fn label_for_key(&self, key: &str) -> Vec { + if let Some(label) = self.labels.get(key) { + return label.clone(); + } + if key.is_empty() { + return vec![]; + } + if key.len() == 1 { + return vec![key.to_string().to_lowercase()]; + } + let mut key = key; + if key.starts_with("KP_") { + key = &key[3..]; + } + if key.contains('_') { + key = key.split('_').next().unwrap(); + } + vec![format!( + "{}{}", + key.chars().next().unwrap().to_uppercase(), + &key[1..].to_lowercase() + )] + } +} + +fn key_events_for_macro(macro_verbs: &Vec) -> Vec<(VirtualKey, bool)> { + let mut key_events = vec![]; + for verb in macro_verbs { + if let Some(caps) = MACRO_REGEX.captures(verb) { + if let Ok(virtual_key) = VirtualKey::from_str(&caps[1]) { + if let Some(state) = caps.get(2) { + if state.as_str() == "UP" { + key_events.push((virtual_key, false)); + } else if state.as_str() == "DOWN" { + key_events.push((virtual_key, true)); + } else { + error!( + "Unknown key state in macro: {}, looking for UP or DOWN.", + state.as_str() + ); + return vec![]; + } + } else { + key_events.push((virtual_key, true)); + key_events.push((virtual_key, false)); + } + } else { + error!("Unknown virtual key: {}", &caps[1]); + return vec![]; + } + } + } + key_events +} diff --git a/src/overlays/mod.rs b/src/overlays/mod.rs new file mode 100644 index 0000000..a49a8a9 --- /dev/null +++ b/src/overlays/mod.rs @@ -0,0 +1,145 @@ +use std::sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, +}; + +use glam::{Affine3A, Quat, Vec3}; +use vulkano::image::ImageViewAbstract; + +use crate::state::AppState; + +use self::interactions::{DummyInteractionHandler, InteractionHandler, PointerHit}; + +pub mod interactions; +pub mod keyboard; +pub mod watch; + +static AUTO_INCREMENT: AtomicUsize = AtomicUsize::new(0); + +pub enum RelativeTo { + None, + Head, + Hand(usize), +} + +pub trait OverlayBackend: OverlayRenderer + InteractionHandler {} + +pub struct OverlayData { + pub id: usize, + pub name: Arc, + pub width: f32, + pub size: (i32, i32), + pub want_visible: bool, + pub show_hide: bool, + pub grabbable: bool, + pub transform: Affine3A, + pub spawn_point: Vec3, + pub spawn_rotation: Quat, + pub relative_to: RelativeTo, + pub interaction_transform: Affine3A, + pub backend: Box, + pub primary_pointer: Option, +} +impl Default for OverlayData { + fn default() -> OverlayData { + OverlayData { + id: AUTO_INCREMENT.fetch_add(1, Ordering::Relaxed), + name: Arc::from(""), + width: 1., + size: (0, 0), + want_visible: false, + show_hide: false, + grabbable: false, + relative_to: RelativeTo::None, + spawn_point: Vec3::NEG_Z, + spawn_rotation: Quat::IDENTITY, + transform: Affine3A::IDENTITY, + interaction_transform: Affine3A::IDENTITY, + backend: Box::new(SplitOverlayBackend::default()), + primary_pointer: None, + } + } +} + +impl OverlayData { + pub fn reset(&mut self, app: &mut AppState) { + todo!() + } + pub fn init(&mut self, app: &mut AppState) { + self.backend.init(app); + } + pub fn render(&mut self, app: &mut AppState) { + self.backend.render(app); + } + pub fn view(&mut self) -> Arc { + self.backend.view() + } +} + +pub trait OverlayRenderer { + fn init(&mut self, app: &mut AppState); + fn pause(&mut self, app: &mut AppState); + fn resume(&mut self, app: &mut AppState); + fn render(&mut self, app: &mut AppState); + fn view(&mut self) -> Arc; +} + +pub struct FallbackRenderer; + +impl OverlayRenderer for FallbackRenderer { + fn init(&mut self, _app: &mut AppState) {} + fn pause(&mut self, _app: &mut AppState) {} + fn resume(&mut self, _app: &mut AppState) {} + fn render(&mut self, _app: &mut AppState) {} + fn view(&mut self) -> Arc { + unimplemented!() + } +} +// Boilerplate and dummies + +pub struct SplitOverlayBackend { + pub renderer: Box, + pub interaction: Box, +} + +impl Default for SplitOverlayBackend { + fn default() -> SplitOverlayBackend { + SplitOverlayBackend { + renderer: Box::new(FallbackRenderer), + interaction: Box::new(DummyInteractionHandler), + } + } +} + +impl OverlayBackend for SplitOverlayBackend {} +impl OverlayRenderer for SplitOverlayBackend { + fn init(&mut self, app: &mut AppState) { + self.renderer.init(app); + } + fn pause(&mut self, app: &mut AppState) { + self.renderer.pause(app); + } + fn resume(&mut self, app: &mut AppState) { + self.renderer.resume(app); + } + fn render(&mut self, app: &mut AppState) { + self.renderer.render(app); + } + fn view(&mut self) -> Arc { + self.renderer.view() + } +} +impl InteractionHandler for SplitOverlayBackend { + fn on_left(&mut self, app: &mut AppState, hand: usize) { + self.interaction.on_left(app, hand); + } + fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) { + self.interaction.on_hover(app, hit); + } + fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta: f32) { + self.interaction.on_scroll(app, hit, delta); + } + fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) { + self.interaction.on_pointer(app, hit, pressed); + } +} diff --git a/src/overlays/screen.rs b/src/overlays/screen.rs new file mode 100644 index 0000000..7256607 --- /dev/null +++ b/src/overlays/screen.rs @@ -0,0 +1,31 @@ + +pub struct ScreenInteractionData { + next_scroll: Instant, + next_move: Instant, + mouse_transform: Affine2, +} +impl ScreenInteractionData { + fn new(pos: Vec2, size: Vec2, transform: Transform) -> ScreenInteractionHandler { + let transform = match transform { + Transform::_90 | Transform::Flipped90 => + Affine2::from_cols(vec2(0., size.y), vec2(-size.x, 0.), vec2(pos.x + size.x, pos.y)), + Transform::_180 | Transform::Flipped180 => + Affine2::from_cols(vec2(-size.x, 0.), vec2(0., -size.y), vec2(pos.x + size.x, pos.y + size.y)), + Transform::_270 | Transform::Flipped270 => + Affine2::from_cols(vec2(0., -size.y), vec2(size.x, 0.), vec2(pos.x, pos.y + size.y)), + _ => + Affine2::from_cols(vec2(size.x, 0.), vec2(0., size.y), pos), + }; + + ScreenInteractionHandler { + next_scroll: Instant::now(), + next_move: Instant::now(), + mouse_transform: transform, + } + } +} + +struct ScreenInteractionHandler { + +} + diff --git a/src/overlays/watch.rs b/src/overlays/watch.rs new file mode 100644 index 0000000..98922e0 --- /dev/null +++ b/src/overlays/watch.rs @@ -0,0 +1,170 @@ +use std::{sync::Arc, time::Instant}; + +use chrono::Local; +use glam::{Quat, Vec3}; + +use crate::{ + gui::{color_parse, CanvasBuilder}, + state::AppState, +}; + +use super::{OverlayData, RelativeTo}; + +pub const WATCH_DEFAULT_POS: Vec3 = Vec3::new(0., 0., 0.15); +pub const WATCH_DEFAULT_ROT: Quat = Quat::from_xyzw(0.7071066, 0., 0.7071066, 0.0007963); + +pub fn create_watch(state: &AppState, screens: Vec<(usize, Arc)>) -> OverlayData { + let mut canvas = CanvasBuilder::new(400, 200, state.graphics.clone(), state.format, ()); + let empty_str: Arc = Arc::from(""); + + // Background + canvas.bg_color = color_parse("#353535"); + canvas.panel(0., 0., 400., 200.); + + // Time display + canvas.font_size = 46; + let clock = canvas.label(19., 100., 200., 50., empty_str.clone()); + clock.on_update = Some(|control, _data, _app| { + let date = Local::now(); + control.set_text(&format!("{}", &date.format("%H:%M"))); + }); + + canvas.font_size = 14; + let date = canvas.label(20., 125., 200., 50., empty_str.clone()); + date.on_update = Some(|control, _data, _app| { + let date = Local::now(); + control.set_text(&format!("{}", &date.format("%x"))); + }); + + let day_of_week = canvas.label(20., 150., 200., 50., empty_str); + day_of_week.on_update = Some(|control, _data, _app| { + let date = Local::now(); + control.set_text(&format!("{}", &date.format("%A"))); + }); + + // Volume controls + canvas.bg_color = color_parse("#222222"); + canvas.fg_color = color_parse("#AAAAAA"); + canvas.font_size = 14; + + canvas.bg_color = color_parse("#303030"); + canvas.fg_color = color_parse("#353535"); + + let vol_up = canvas.button(327., 116., 46., 32., "+".into()); + vol_up.on_press = Some(|_control, _data, _app| { + println!("Volume up!"); //TODO + }); + + let vol_dn = canvas.button(327., 52., 46., 32., "-".into()); + vol_dn.on_press = Some(|_control, _data, _app| { + println!("Volume down!"); //TODO + }); + + canvas.bg_color = color_parse("#303030"); + canvas.fg_color = color_parse("#353535"); + + let settings = canvas.button(2., 162., 36., 36., "☰".into()); + settings.on_press = Some(|_control, _data, _app| { + println!("Settings!"); //TODO + }); + + canvas.fg_color = color_parse("#CCBBAA"); + canvas.bg_color = color_parse("#406050"); + // Bottom row + let num_buttons = screens.len() + 1; + let button_width = 360. / num_buttons as f32; + let mut button_x = 40.; + + let keyboard = canvas.button(button_x + 2., 162., button_width - 4., 36., "Kbd".into()); + keyboard.state = Some(WatchButtonState { + pressed_at: Instant::now(), + scr_idx: 0, + }); + + keyboard.on_press = Some(|control, _data, _app| { + if let Some(state) = control.state.as_mut() { + state.pressed_at = Instant::now(); + } + }); + keyboard.on_release = Some(|control, _data, app| { + if let Some(state) = control.state.as_ref() { + if Instant::now() + .saturating_duration_since(state.pressed_at) + .as_millis() + < 2000 + { + app.tasks.push_back(Box::new(|_app, o| { + for overlay in o { + if &*overlay.name == "Kbd" { + overlay.want_visible = !overlay.want_visible; + return; + } + } + })); + } else { + app.tasks.push_back(Box::new(|app, o| { + for overlay in o { + if &*overlay.name == "Kbd" { + overlay.reset(app); + } + } + })); + } + } + }); + button_x += button_width; + + canvas.bg_color = color_parse("#405060"); + + for (scr_idx, scr_name) in screens.into_iter() { + let button = canvas.button(button_x + 2., 162., button_width - 4., 36., scr_name); + button.state = Some(WatchButtonState { + pressed_at: Instant::now(), + scr_idx, + }); + + button.on_press = Some(|control, _data, _app| { + if let Some(state) = control.state.as_mut() { + state.pressed_at = Instant::now(); + } + }); + button.on_release = Some(|control, _data, app| { + if let Some(state) = control.state.as_ref() { + let scr_idx = state.scr_idx; + if Instant::now() + .saturating_duration_since(state.pressed_at) + .as_millis() + < 2000 + { + app.tasks.push_back(Box::new(move |_app, o| { + o[scr_idx].want_visible = !o[scr_idx].want_visible; + })); + } else { + app.tasks.push_back(Box::new(move |app, o| { + o[scr_idx].reset(app); + })); + } + } + }); + button_x += button_width; + } + + let relative_to = RelativeTo::Hand(state.session.watch_hand); + + OverlayData { + name: "Watch".into(), + size: (400, 200), + width: 0.065, + backend: Box::new(canvas.build()), + want_visible: true, + relative_to, + spawn_point: state.session.watch_pos, + spawn_rotation: state.session.watch_rot, + ..Default::default() + } +} + +struct WatchButtonState { + pressed_at: Instant, + scr_idx: usize, +} diff --git a/src/ovr.rs b/src/ovr.rs new file mode 100644 index 0000000..9831f5d --- /dev/null +++ b/src/ovr.rs @@ -0,0 +1,64 @@ +use std::{path::Path, sync::Arc}; + +use vulkano::{ + image::{ + sys::{Image, RawImage}, + ImageViewAbstract, + }, + Handle, VulkanObject, +}; + +use crate::graphics::WlxGraphics; + +pub struct OpenVrState { + pub context: ovr_overlay::Context, +} + + +pub struct OvrTextureData { + image_handle: u64, + device: u64, + physical: u64, + instance: u64, + queue: u64, + queue_family_index: u32, + width: u32, + height: u32, + format: u32, + sample_count: u32, +} + +impl OvrTextureData { + pub fn new(graphics: Arc, view: Arc) -> OvrTextureData { + let image = view.image(); + + let device = graphics.device.handle().as_raw(); + let physical = graphics.device.physical_device().handle().as_raw(); + let instance = graphics.instance.handle().as_raw(); + let queue = graphics.queue.handle().as_raw(); + let queue_family_index = graphics.queue.queue_family_index(); + + let (width, height) = { + let dim = image.dimensions(); + (dim.width() as u32, dim.height() as u32) + }; + + let sample_count = image.samples() as u32; + let format = image.format() as u32; + + let image_handle = image.inner().image.handle().as_raw(); + + OvrTextureData { + image_handle, + device, + physical, + instance, + queue, + queue_family_index, + width, + height, + format, + sample_count, + } + } +} diff --git a/src/res/421581.wav b/src/res/421581.wav new file mode 100644 index 0000000..11b767e Binary files /dev/null and b/src/res/421581.wav differ diff --git a/src/res/660533.wav b/src/res/660533.wav new file mode 100644 index 0000000..3910bdf Binary files /dev/null and b/src/res/660533.wav differ diff --git a/src/res/actions.json b/src/res/actions.json new file mode 100644 index 0000000..0411b91 --- /dev/null +++ b/src/res/actions.json @@ -0,0 +1,83 @@ +{ + "actions": [ + { + "name": "/actions/default/in/Click", + "type": "boolean", + "requirement": "mandatory" + }, + { + "name": "/actions/default/in/Grab", + "type": "boolean", + "requirement": "mandatory" + }, + { + "name": "/actions/default/in/Scroll", + "type": "vector2", + "requirement": "mandatory" + }, + { + "name": "/actions/default/in/ShowHide", + "type": "boolean", + "requirement": "mandatory" + }, + { + "name": "/actions/default/in/AltClick", + "type": "boolean", + "requirement": "optional" + }, + { + "name": "/actions/default/in/ClickModifierRight", + "type": "boolean", + "requirement": "optional" + }, + { + "name": "/actions/default/in/ClickModifierMiddle", + "type": "boolean", + "requirement": "optional" + }, + { + "name": "/actions/default/in/SpaceDrag", + "type": "boolean", + "requirement": "optional" + }, + { + "name": "/actions/default/in/LeftHand", + "type": "pose", + "requirement": "optional" + }, + { + "name": "/actions/default/in/RightHand", + "type": "pose", + "requirement": "optional" + }, + { + "name": "/actions/default/out/HapticsLeft", + "type": "vibration" + }, + { + "name": "/actions/default/out/HapticsRight", + "type": "vibration" + } + ], + "action_sets": [ + { + "name": "/actions/default", + "usage": "leftright" + } + ], + "default_bindings": [ + { + "controller_type": "knuckles", + "binding_url": "actions_binding_knuckles.json" + }, + { + "controller_type": "oculus_touch", + "binding_url": "actions_binding_oculus.json" + }, + { + "controller_type": "vive_controller", + "binding_url": "actions_binding_vive.json" + } + ], + "localization": [] +} diff --git a/src/res/actions_binding_knuckles.json b/src/res/actions_binding_knuckles.json new file mode 100644 index 0000000..1f19b08 --- /dev/null +++ b/src/res/actions_binding_knuckles.json @@ -0,0 +1,173 @@ +{ + "action_manifest_version" : 0, + "app_key" : "galister.wlxoverlay", + "bindings" : { + "/actions/default" : { + "haptics" : [ + { + "output" : "/actions/default/out/hapticsleft", + "path" : "/user/hand/left/output/haptic" + }, + { + "output" : "/actions/default/out/hapticsright", + "path" : "/user/hand/right/output/haptic" + } + ], + "poses" : [ + { + "output" : "/actions/default/in/lefthand", + "path" : "/user/hand/left/pose/tip" + }, + { + "output" : "/actions/default/in/righthand", + "path" : "/user/hand/right/pose/tip" + } + ], + "sources" : [ + { + "inputs" : { + "double" : { + "output" : "/actions/default/in/showhide" + }, + "touch" : { + "output": "/actions/default/in/clickmodifierright" + } + }, + "mode" : "button", + "path" : "/user/hand/left/input/b" + }, + { + "path": "/user/hand/left/input/a", + "mode": "button", + "inputs": { + "touch": { + "output": "/actions/default/in/clickmodifiermiddle" + } + } + }, + { + "path": "/user/hand/right/input/b", + "mode": "button", + "inputs": { + "touch": { + "output": "/actions/default/in/clickmodifierright" + } + } + }, + { + "path": "/user/hand/right/input/a", + "mode": "button", + "inputs": { + "touch": { + "output": "/actions/default/in/clickmodifiermiddle" + } + } + }, + { + "inputs" : { + "click" : { + "output" : "/actions/default/in/click" + } + }, + "mode" : "button", + "parameters" : { + "click_activate_threshold" : "0.35", + "click_deactivate_threshold" : "0.31" + }, + "path" : "/user/hand/left/input/trigger" + }, + { + "inputs" : { + "click" : { + "output" : "/actions/default/in/click" + } + }, + "mode" : "button", + "parameters" : { + "click_activate_threshold" : "0.35", + "click_deactivate_threshold" : "0.31" + }, + "path" : "/user/hand/right/input/trigger" + }, + { + "inputs" : { + "click" : { + "output" : "/actions/default/in/altclick" + } + }, + "mode" : "button", + "path" : "/user/hand/right/input/trackpad" + }, + { + "inputs" : { + "click" : { + "output" : "/actions/default/in/altclick" + } + }, + "mode" : "button", + "path" : "/user/hand/left/input/trackpad" + }, + { + "inputs" : { + "grab" : { + "output" : "/actions/default/in/grab" + } + }, + "mode" : "grab", + "parameters" : { + "value_hold_threshold" : "1.3", + "value_release_threshold" : "1.1" + }, + "path" : "/user/hand/left/input/grip" + }, + { + "inputs" : { + "grab" : { + "output" : "/actions/default/in/grab" + } + }, + "mode" : "grab", + "parameters" : { + "value_hold_threshold" : "1.3", + "value_release_threshold" : "1.1" + }, + "path" : "/user/hand/right/input/grip" + }, + { + "inputs" : { + "scroll" : { + "output" : "/actions/default/in/scroll" + } + }, + "mode" : "scroll", + "parameters" : { + "scroll_mode" : "smooth" + }, + "path" : "/user/hand/left/input/thumbstick" + }, + { + "inputs" : { + "scroll" : { + "output" : "/actions/default/in/scroll" + } + }, + "mode" : "scroll", + "parameters" : { + "scroll_mode" : "smooth" + }, + "path" : "/user/hand/right/input/thumbstick" + } + ] + } + }, + "category" : "steamvr_input", + "controller_type" : "knuckles", + "description" : "Ver1", + "interaction_profile" : "", + "name" : "WlxOverlay configuration for Index Controller", + "options" : { + "mirror_actions" : false, + "simulated_controller_type" : "none" + }, + "simulated_actions" : [] +} diff --git a/src/res/actions_binding_oculus.json b/src/res/actions_binding_oculus.json new file mode 100644 index 0000000..37c8268 --- /dev/null +++ b/src/res/actions_binding_oculus.json @@ -0,0 +1,139 @@ +{ + "action_manifest_version" : 0, + "app_key" : "galister.wlxoverlay", + "bindings" : { + "/actions/default" : { + "haptics" : [ + { + "output" : "/actions/default/out/hapticsleft", + "path" : "/user/hand/left/output/haptic" + }, + { + "output" : "/actions/default/out/hapticsright", + "path" : "/user/hand/right/output/haptic" + } + ], + "poses" : [ + { + "output" : "/actions/default/in/lefthand", + "path" : "/user/hand/left/pose/tip" + }, + { + "output" : "/actions/default/in/righthand", + "path" : "/user/hand/right/pose/tip" + } + ], + "sources" : [ + { + "inputs" : { + "double" : { + "output" : "/actions/default/in/showhide" + }, + "touch" : { + "output": "/actions/default/in/clickmodifierright" + } + }, + "mode" : "button", + "path" : "/user/hand/left/input/y" + }, + { + "path": "/user/hand/left/input/x", + "mode": "button", + "inputs": { + "touch": { + "output": "/actions/default/in/clickmodifiermiddle" + } + } + }, + { + "path": "/user/hand/right/input/b", + "mode": "button", + "inputs": { + "touch": { + "output": "/actions/default/in/clickmodifierright" + } + } + }, + { + "path": "/user/hand/right/input/a", + "mode": "button", + "inputs": { + "touch": { + "output": "/actions/default/in/clickmodifiermiddle" + } + } + }, + { + "inputs" : { + "click" : { + "output" : "/actions/default/in/click" + } + }, + "mode": "button", + "path" : "/user/hand/left/input/trigger" + }, + { + "inputs" : { + "click" : { + "output" : "/actions/default/in/click" + } + }, + "mode": "button", + "path" : "/user/hand/right/input/trigger" + }, + { + "inputs" : { + "click" : { + "output" : "/actions/default/in/grab" + } + }, + "mode": "button", + "path" : "/user/hand/left/input/grip" + }, + { + "inputs" : { + "click" : { + "output" : "/actions/default/in/grab" + } + }, + "mode": "button", + "path" : "/user/hand/right/input/grip" + }, + { + "inputs" : { + "scroll" : { + "output" : "/actions/default/in/scroll" + } + }, + "mode" : "scroll", + "parameters" : { + "scroll_mode" : "smooth" + }, + "path" : "/user/hand/left/input/joystick" + }, + { + "inputs" : { + "scroll" : { + "output" : "/actions/default/in/scroll" + } + }, + "mode" : "scroll", + "parameters" : { + "scroll_mode" : "smooth" + }, + "path" : "/user/hand/right/input/joystick" + } + ] + } + }, + "category" : "steamvr_input", + "controller_type" : "oculus_touch", + "description" : "Ver1", + "interaction_profile" : "", + "name" : "WlxOverlay configuration for Oculus Touch Controller", + "options" : { + "mirror_actions" : false, + "simulated_controller_type" : "none" + }, + "simulated_actions" : [] +} diff --git a/src/res/actions_binding_vive.json b/src/res/actions_binding_vive.json new file mode 100644 index 0000000..a3db7d8 --- /dev/null +++ b/src/res/actions_binding_vive.json @@ -0,0 +1,126 @@ +{ + "action_manifest_version" : 0, + "app_key" : "galister.wlxoverlay", + "bindings" : { + "/actions/default": { + "haptics" : [ + { + "output" : "/actions/default/out/hapticsleft", + "path" : "/user/hand/left/output/haptic" + }, + { + "output" : "/actions/default/out/hapticsright", + "path" : "/user/hand/right/output/haptic" + } + ], + "sources": [ + { + "path": "/user/hand/left/input/grip", + "mode": "button", + "inputs": { + "click": { + "output": "/actions/default/in/grab" + } + } + }, + { + "path": "/user/hand/right/input/grip", + "mode": "button", + "inputs": { + "click": { + "output": "/actions/default/in/grab" + } + } + }, + { + "path": "/user/hand/left/input/trigger", + "mode": "button", + "inputs": { + "click": { + "output": "/actions/default/in/click" + } + } + }, + { + "path": "/user/hand/right/input/trigger", + "mode": "trigger", + "inputs": { + "click": { + "output": "/actions/default/in/click" + } + } + }, + { + "path": "/user/hand/right/input/trackpad", + "mode": "scroll", + "parameters": { + "scroll_mode": "smooth" + }, + "inputs": { + "scroll": { + "output": "/actions/default/in/scroll" + } + } + }, + { + "path": "/user/hand/left/input/trackpad", + "mode": "scroll", + "inputs": { + "scroll": { + "output": "/actions/default/in/scroll" + } + } + }, + { + "path": "/user/hand/left/input/application_menu", + "mode": "button", + "inputs": { + "double": { + "output": "/actions/default/in/showhide" + } + } + }, + { + "path": "/user/hand/right/input/trackpad", + "mode": "dpad", + "parameters": { + "sub_mode": "touch" + }, + "inputs": { + "west": { + "output": "/actions/default/in/clickmodifiermiddle" + }, + "east": { + "output": "/actions/default/in/clickmodifierright" + } + } + }, + { + "path": "/user/hand/left/input/trackpad", + "mode": "dpad", + "parameters": { + "sub_mode": "touch" + }, + "inputs": { + "west": { + "output": "/actions/default/in/clickmodifiermiddle" + }, + "east": { + "output": "/actions/default/in/clickmodifierright" + } + } + } + ] + } + }, + "category" : "steamvr_input", + "controller_type" : "vive_controller", + "description" : "Ver1", + "interaction_profile" : "", + "name" : "WlxOverlay configuration for Vive Controller", + "options" : { + "mirror_actions" : false, + "simulated_controller_type" : "none" + }, + "simulated_actions" : [] +} diff --git a/src/res/keyboard.yaml b/src/res/keyboard.yaml new file mode 100644 index 0000000..ac760d2 --- /dev/null +++ b/src/res/keyboard.yaml @@ -0,0 +1,127 @@ +--- + +# This file contains all data needed to generate the keyboard. +# You can create any layout, as long as: +# - All keys are rectangular with 1 unit of height. +# This means: +# - We're limited to the flat & boring ANSI enter key. +# - Numpad + and Enter might not look so great. + +# *** Important *** +# The keyboard layout uses virtual key codes, so they are layout-independent. +# For example, Q on a French layout actually results in A. +# If you're using a non-english layout, chances are you only need to edit the label section below. + +# Not used for anything right now +name: "en-us_full" + +# How many units of key size in each row? 1 = standard letter key size +row_size: 23 + +# Specifies the size of each key. The sum of any given row must equal RowSize +key_sizes: + - [1.5,0.5, 1, 1, 1, 1,0.5,1, 1, 1, 1,0.5,1, 1, 1, 1, 0.5, 1, 1, 1, 4.5] + - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0.5, 1, 1, 1, 0.5, 1, 1, 1, 1] + - [1.5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.5, 0.5, 1, 1, 1, 0.5, 1, 1, 1, 1] + - [1.75, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2.25, 4, 1, 1, 1, 1] + - [2.25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2.75, 1.5, 1, 1.5, 1, 1, 1, 1] + - [1.25, 1.25, 1.25, 6.25, 1.25, 1.25, 1.25, 1.25, 0.5, 1, 1, 1, 0.5, 2, 1, 1] + +# The main (blue) layout of the keyboard. +# Accepted are: +# - virtual keys, for a full list go to https://github.com/galister/X11Overlay/blob/master/Types/VirtualKey.cs +# - ExecCommands (defined below) +# - Macros (defined below) +# - ~ (null) will leave an empty space with the corresponding size from key_sizes +main_layout: + - ["Escape", ~, "F1", "F2", "F3", "F4", ~, "F5", "F6", "F7", "F8", ~, "F9", "F10", "F11", "F12", ~, "Print", "Scroll", "Pause", ~] + - ["Oem3", "N1", "N2", "N3", "N4", "N5", "N6", "N7", "N8", "N9", "N0", "Minus", "Plus", "BackSpace", ~, "Insert", "Home", "Prior", ~, "NumLock", "KP_Divide", "KP_Multiply", "KP_Subtract"] + - ["Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "Oem4", "Oem6", "Oem5", ~, "Delete", "End", "Next", ~, "KP_7", "KP_8", "KP_9", "KP_Add"] + - ["XF86Favorites", "A", "S", "D", "F", "G", "H", "J", "K", "L", "Oem1", "Oem7", "Return", ~, "KP_4", "KP_5", "KP_6", ~] + - ["LShift", "Z", "X", "C", "V", "B", "N", "M", "Comma", "Period", "Oem2", "RShift", ~, "Up", ~, "KP_1", "KP_2", "KP_3", "KP_Enter"] + - ["LCtrl", "LSuper", "LAlt", "Space", "Meta", "RSuper", "Menu", "RCtrl", ~, "Left", "Down", "Right", ~, "KP_0", "KP_Decimal", ~] + +# When using the purple pointer... +# None - No special functionality when using purple pointer +# Shift - Use same functionality as the orange pointer +# Ctrl - Use Main layout with Ctrl modifier +# Super - Use Main layout with Super (WinKey) modifier +# Meta - Use Main layout with Meta (AltGr) modifier +# Layout - Use the alt_layout defined below +alt_layout_mode: Ctrl + +# The alt (fn) layout of the keyboard. Only takes effect when alt_layout_mode: Layout +# Accepted values are the same as for MainLayout. +# The default layout here is a dummy. Change it to fit your liking. +alt_layout: + - ["Escape", ~, "F1", "F2", "F3", "F4", ~, "F5", "F6", "F7", "F8", ~, "F9", "F10", "F11", "F12", ~, "Print", "Scroll", "Pause", ~, "COPY", "PASTE"] + - ["Oem3", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "Minus", "Plus", "BackSpace", ~, "Insert", "Home", "Prior", ~, "NumLock", "KP_Divide", "KP_Multiply", "KP_Subtract"] + - ["Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "Oem4", "Oem6", "Oem5", ~, "Delete", "End", "Next", ~, "KP_7", "KP_8", "KP_9", "KP_Add"] + - ["XF86Favorites", "A", "S", "D", "F", "G", "H", "J", "K", "L", "Oem1", "Oem7", "Return", ~, "KP_4", "KP_5", "KP_6", ~] + - ["LShift", "Oem102", "Z", "X", "C", "V", "B", "N", "M", "Comma", "Period", "Oem2", "RShift", ~, "Up", ~, "KP_1", "KP_2", "KP_3", "KP_Enter"] + - ["LCtrl", "LSuper", "LAlt", "Space", "Meta", "RSuper", "Menu", "RCtrl", ~, "Left", "Down", "Right", ~, "KP_0", "KP_Decimal", ~] + +# Shell commands to be used in a layout. +# Value is an array of string arguments. +exec_commands: + STT: [ "whisper_stt", "--lang", "en" ] + +# Series of keypresses to be used in a layout. +# Format: keyName [DOWN|UP] +# keyName must be a valid key from `xmodmap -pke` +# DOWN|UP: can be omitted for an implicit "keyName DOWN, keyName UP" +macros: + KILL: [ "LSuper DOWN", "LCtrl DOWN", "Escape", "LCtrl UP", "LSuper UP" ] + COPY: [ "LCtrl DOWN", "C", "LCtrl UP" ] + PASTE: [ "LCtrl DOWN", "V", "LCtrl UP" ] + +# Custom labels to use. +# Key: element of MainLayout / AltLayout +# Value: Array of strings. 0th element is the upper row, 1st element is lower row. +# For empty labels, use [] (do not use ~) +labels: + "N1": ["1", "!"] + "N2": ["2", "@"] + "N3": ["3", "#"] + "N4": ["4", "$"] + "N5": ["5", "%"] + "N6": ["6", "^"] + "N7": ["7", "&"] + "N8": ["8", "*"] + "N9": ["9", "("] + "N0": ["0", ")"] + "Escape": ["Esc"] + "Prior": ["PgUp"] + "Next": ["PgDn"] + "NumLock": ["Num"] + "Space": [] + "LAlt": ["Alt"] + "LCtrl": ["Ctrl"] + "RCtrl": ["Ctrl"] + "LSuper": ["Super"] + "RSuper": ["Super"] + "LShift": ["Shift"] + "RShift": ["Shift"] + "Insert": ["Ins"] + "Delete": ["Del"] + "Minus": ["-", "_"] + "Plus": ["=", "+"] + "BackSpace": ["<<"] + "Comma": [" ,", "<"] + "Period": [" .", ">"] + "Oem1": [" ;", ":"] + "Oem2": [" /", "?"] + "Oem3": ["`", "~"] + "Oem4": [" [", "{"] + "Oem5": [" \\", "|"] + "Oem6": [" ]", "}"] + "Oem7": [" '", "\""] + "Oem102": [" \\", "|"] + "KP_Divide": [" /"] + "KP_Add": [" +"] + "KP_Multiply": [" *"] + "KP_Decimal": [" ."] + "KP_Subtract": [" -"] + "KP_Enter": ["Ent"] + "XF86Favorites": ["Rofi"] + diff --git a/src/shaders/frag-color.spv b/src/shaders/frag-color.spv new file mode 100644 index 0000000..4cab844 Binary files /dev/null and b/src/shaders/frag-color.spv differ diff --git a/src/shaders/frag-glyph.spv b/src/shaders/frag-glyph.spv new file mode 100644 index 0000000..c7c4c7e Binary files /dev/null and b/src/shaders/frag-glyph.spv differ diff --git a/src/shaders/frag-sprite.spv b/src/shaders/frag-sprite.spv new file mode 100644 index 0000000..662225b Binary files /dev/null and b/src/shaders/frag-sprite.spv differ diff --git a/src/shaders/frag-srgb.spv b/src/shaders/frag-srgb.spv new file mode 100644 index 0000000..513121a Binary files /dev/null and b/src/shaders/frag-srgb.spv differ diff --git a/src/shaders/mod.rs b/src/shaders/mod.rs new file mode 100644 index 0000000..15e979a --- /dev/null +++ b/src/shaders/mod.rs @@ -0,0 +1,108 @@ +pub mod vert_common { + vulkano_shaders::shader! { + ty: "vertex", + src: r"#version 310 es + precision highp float; + + layout (location = 0) in vec2 in_pos; + layout (location = 1) in vec2 in_uv; + layout (location = 0) out vec2 out_uv; + + void main() { + out_uv = in_uv; + gl_Position = vec4(in_pos * 2. - 1., 0., 1.); + } + ", + } +} + +pub mod frag_color { + vulkano_shaders::shader! { + ty: "fragment", + src: r"#version 310 es + precision highp float; + + layout (location = 0) in vec2 in_uv; + layout (location = 0) out vec4 out_color; + + layout (set = 0, binding = 0) uniform ColorBlock { + uniform vec4 in_color; + }; + + void main() + { + out_color = in_color; + } + ", + } +} + +pub mod frag_glyph { + vulkano_shaders::shader! { + ty: "fragment", + src: r"#version 310 es + precision highp float; + + layout (location = 0) in vec2 in_uv; + layout (location = 0) out vec4 out_color; + + layout (set = 0, binding = 0) uniform sampler2D in_texture; + + layout (set = 1, binding = 0) uniform ColorBlock { + uniform vec4 in_color; + }; + + void main() + { + float r = texture(in_texture, in_uv).r; + out_color = vec4(r,r,r,r) * in_color; + } + ", + } +} + +pub mod frag_sprite { + vulkano_shaders::shader! { + ty: "fragment", + src: r"#version 310 es + precision highp float; + + layout (location = 0) in vec2 in_uv; + layout (location = 0) out vec4 out_color; + + layout (set = 0, binding = 0) uniform sampler2D in_texture; + + void main() + { + vec4 c = texture(in_texture, in_uv); + out_color.rgb = c.rgb; + out_color.a = min((c.r + c.g + c.b)*100.0, 1.0); + } + ", + } +} + +pub mod frag_srgb { + vulkano_shaders::shader! { + ty: "fragment", + src: r"#version 310 es + precision highp float; + + layout (location = 0) in vec2 in_uv; + layout (location = 0) out vec4 out_color; + + layout (set = 0, binding = 0) uniform sampler2D in_texture; + + void main() + { + out_color = texture(in_texture, in_uv); + + bvec4 cutoff = lessThan(out_color, vec4(0.04045)); + vec4 higher = pow((out_color + vec4(0.055))/vec4(1.055), vec4(2.4)); + vec4 lower = out_color/vec4(12.92); + + out_color = mix(higher, lower, cutoff); + } + ", + } +} diff --git a/src/shaders/src/color.frag b/src/shaders/src/color.frag new file mode 100644 index 0000000..e776b5a --- /dev/null +++ b/src/shaders/src/color.frag @@ -0,0 +1,15 @@ +#version 310 es +precision highp float; + +layout (location = 0) in vec2 in_uv; +layout (location = 0) out vec4 out_color; + +layout (set = 0, binding = 0) uniform ColorBlock { + uniform vec4 in_color; +}; + +void main() +{ + out_color = in_color; +} + diff --git a/src/shaders/src/common.vert b/src/shaders/src/common.vert new file mode 100644 index 0000000..1cd48e8 --- /dev/null +++ b/src/shaders/src/common.vert @@ -0,0 +1,12 @@ +#version 310 es +precision highp float; + +layout (location = 0) in vec2 in_pos; +layout (location = 1) in vec2 in_uv; +layout (location = 0) out vec2 out_uv; + +void main() { + out_uv = in_uv; + gl_Position = vec4(in_pos * 2. - 1., 0., 1.); +} + diff --git a/src/shaders/src/glyph.frag b/src/shaders/src/glyph.frag new file mode 100644 index 0000000..397bf68 --- /dev/null +++ b/src/shaders/src/glyph.frag @@ -0,0 +1,18 @@ +#version 310 es +precision highp float; + +layout (location = 0) in vec2 in_uv; +layout (location = 0) out vec4 out_color; + +layout (set = 0, binding = 0) uniform sampler2D in_texture; + +layout (set = 0, binding = 1) uniform ColorBlock { + uniform vec4 in_color; +}; + +void main() +{ + float r = texture(in_texture, in_uv).r; + out_color = vec4(r,r,r,r) * in_color; +} + diff --git a/src/shaders/src/sprite.frag b/src/shaders/src/sprite.frag new file mode 100644 index 0000000..d3245f0 --- /dev/null +++ b/src/shaders/src/sprite.frag @@ -0,0 +1,14 @@ +#version 310 es +precision highp float; + +layout (location = 0) in vec2 in_uv; +layout (location = 0) out vec4 out_color; + +layout (set = 0, binding = 0) uniform sampler2D in_texture; + +void main() +{ + out_color = texture(in_texture, in_uv); + out_color.a = 1.; +} + diff --git a/src/shaders/src/srgb.frag b/src/shaders/src/srgb.frag new file mode 100644 index 0000000..388593d --- /dev/null +++ b/src/shaders/src/srgb.frag @@ -0,0 +1,19 @@ +#version 310 es +precision highp float; + +layout (location = 0) in vec2 in_uv; +layout (location = 0) out vec4 out_color; + +layout (set = 0, binding = 0) uniform sampler2D in_texture; + +void main() +{ + out_color = texture(in_texture, in_uv); + + bvec4 cutoff = lessThan(out_color, vec4(0.04045)); + vec4 higher = pow((out_color + vec4(0.055))/vec4(1.055), vec4(2.4)); + vec4 lower = out_color/vec4(12.92); + + out_color = mix(higher, lower, cutoff); +} + diff --git a/src/shaders/vert-common.spv b/src/shaders/vert-common.spv new file mode 100644 index 0000000..8107a01 Binary files /dev/null and b/src/shaders/vert-common.spv differ diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..6eeb1b7 --- /dev/null +++ b/src/state.rs @@ -0,0 +1,103 @@ +use std::{collections::VecDeque, env::VarError, path::Path, sync::Arc}; + +use glam::{Quat, Vec3}; +use log::warn; + +use crate::{ + graphics::WlxGraphics, gui::font::FontCache, input::InputProvider, overlays::OverlayData, +}; + +pub const WATCH_DEFAULT_POS: Vec3 = Vec3::new(0., 0., 0.15); +pub const WATCH_DEFAULT_ROT: Quat = Quat::from_xyzw(0.7071066, 0., 0.7071066, 0.0007963); + +pub type Task = Box; + +pub struct AppState { + pub fc: FontCache, + //pub input: InputState, + pub session: AppSession, + pub tasks: VecDeque, + pub graphics: Arc, + pub format: vulkano::format::Format, + pub input: Box, +} + +pub struct AppSession { + pub config_path: String, + + pub show_screens: Vec, + pub show_keyboard: bool, + pub keyboard_volume: f32, + + pub screen_flip_h: bool, + pub screen_flip_v: bool, + pub screen_invert_color: bool, + + pub watch_hand: usize, + pub watch_pos: Vec3, + pub watch_rot: Quat, + + pub primary_hand: usize, + + pub capture_method: String, + + pub color_norm: Vec3, + pub color_shift: Vec3, + pub color_alt: Vec3, + pub color_grab: Vec3, + + pub click_freeze_time_ms: u64, +} + +impl AppSession { + pub fn load() -> AppSession { + let config_path = std::env::var("XDG_CONFIG_HOME") + .or_else(|_| std::env::var("HOME").map(|home| format!("{}/.config", home))) + .or_else(|_| { + warn!("Err: $XDG_CONFIG_HOME and $HOME are not set, using /tmp/wlxoverlay"); + Ok::("/tmp".to_string()) + }) + .map(|config| Path::new(&config).join("wlxoverlay")) + .ok() + .and_then(|path| path.to_str().map(|path| path.to_string())) + .unwrap(); + + let _ = std::fs::create_dir(&config_path); + + AppSession { + config_path, + show_screens: vec!["DP-3".to_string()], + keyboard_volume: 0.5, + show_keyboard: false, + screen_flip_h: false, + screen_flip_v: false, + screen_invert_color: false, + capture_method: "auto".to_string(), + primary_hand: 1, + watch_hand: 1, + watch_pos: WATCH_DEFAULT_POS, + watch_rot: WATCH_DEFAULT_ROT, + color_norm: Vec3 { + x: 0., + y: 1., + z: 1., + }, + color_shift: Vec3 { + x: 1., + y: 1., + z: 0., + }, + color_alt: Vec3 { + x: 1., + y: 0., + z: 1., + }, + color_grab: Vec3 { + x: 1., + y: 0., + z: 0., + }, + click_freeze_time_ms: 300, + } + } +}