diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 116149cf..00000000 --- a/Cargo.lock +++ /dev/null @@ -1,6541 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "ab_glyph" -version = "0.2.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79faae4620f45232f599d9bc7b290f88247a0834162c4495ab2f02d60004adfb" -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 = "accesskit" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74a4b14f3d99c1255dcba8f45621ab1a2e7540a0009652d33989005a4d0bfc6b" - -[[package]] -name = "accesskit_consumer" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c17cca53c09fbd7288667b22a201274b9becaa27f0b91bf52a526db95de45e6" -dependencies = [ - "accesskit", -] - -[[package]] -name = "accesskit_macos" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3b6ae1eabbfbced10e840fd3fce8a93ae84f174b3e4ba892ab7bcb42e477a7" -dependencies = [ - "accesskit", - "accesskit_consumer", - "objc2 0.3.0-beta.3.patch-leaks.3", - "once_cell", -] - -[[package]] -name = "accesskit_windows" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afcae27ec0974fc7c3b0b318783be89fd1b2e66dd702179fe600166a38ff4a0b" -dependencies = [ - "accesskit", - "accesskit_consumer", - "once_cell", - "paste", - "static_assertions", - "windows 0.48.0", -] - -[[package]] -name = "accesskit_winit" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f8f7c9f66d454d5fd8e344c8c8c7324b57194e1041b955519fc58a01e77a25" -dependencies = [ - "accesskit", - "accesskit_macos", - "accesskit_windows", - "raw-window-handle 0.6.2", - "winit", -] - -[[package]] -name = "addr2line" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "getrandom", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "allocator-api2" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" - -[[package]] -name = "alsa" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" -dependencies = [ - "alsa-sys", - "bitflags 2.6.0", - "cfg-if", - "libc", -] - -[[package]] -name = "alsa-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "android-activity" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" -dependencies = [ - "android-properties", - "bitflags 2.6.0", - "cc", - "cesu8", - "jni", - "jni-sys", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-sys", - "num_enum", - "thiserror", -] - -[[package]] -name = "android-properties" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_log-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.6.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" - -[[package]] -name = "anstyle-parse" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - -[[package]] -name = "anyhow" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" - -[[package]] -name = "approx" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" -dependencies = [ - "num-traits", -] - -[[package]] -name = "arboard" -version = "3.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4" -dependencies = [ - "clipboard-win", - "core-graphics", - "image 0.25.2", - "log", - "objc2 0.5.2", - "objc2-app-kit", - "objc2-foundation", - "parking_lot", - "windows-sys 0.48.0", - "x11rb", -] - -[[package]] -name = "arrayref" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "as-raw-xcb-connection" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" - -[[package]] -name = "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 = "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 = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-executor" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand 2.1.1", - "futures-lite 2.3.0", - "slab", -] - -[[package]] -name = "async-fs" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" -dependencies = [ - "async-lock", - "blocking", - "futures-lite 2.3.0", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener 5.3.1", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[package]] -name = "atk-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "251e0b7d90e33e0ba930891a505a9a35ece37b2dd37a14f3ffc306c13b980009" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide 0.8.0", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "bevy" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65b9eadaacf8fe971331bc3f250f35c18bc9dace3f96b483062f38ac07e3a1b4" -dependencies = [ - "bevy_internal", -] - -[[package]] -name = "bevy_a11y" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8ef2795f7f5c816a4eda04834083eb5a92e8fef603bc21d2091c6e3b63621a" -dependencies = [ - "accesskit", - "bevy_app", - "bevy_derive", - "bevy_ecs", -] - -[[package]] -name = "bevy_animation" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e553d68bc937586010ed2194ac66b751bc6238cf622b3ed5a86f4e1581e94509" -dependencies = [ - "bevy_app", - "bevy_asset", - "bevy_core", - "bevy_ecs", - "bevy_hierarchy", - "bevy_math", - "bevy_reflect", - "bevy_render", - "bevy_time", - "bevy_transform", - "bevy_utils", -] - -[[package]] -name = "bevy_app" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab348a32e46d21c5d61794294a92d415a770d26c7ba8951830b127b40b53ccc4" -dependencies = [ - "bevy_derive", - "bevy_ecs", - "bevy_reflect", - "bevy_tasks", - "bevy_utils", - "downcast-rs", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "bevy_asset" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50028e0d4f28a9f6aab48f61b688ba2793141188f88cdc9aa6c2bca2cc02ad35" -dependencies = [ - "async-broadcast", - "async-fs", - "async-lock", - "bevy_app", - "bevy_asset_macros", - "bevy_ecs", - "bevy_log", - "bevy_reflect", - "bevy_tasks", - "bevy_utils", - "bevy_winit", - "blake3", - "crossbeam-channel", - "downcast-rs", - "futures-io", - "futures-lite 2.3.0", - "js-sys", - "parking_lot", - "ron", - "serde", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "bevy_asset_macros" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6617475908368418d815360148fdbb82f879dc255a70d2d7baa3766f0cd4bfd7" -dependencies = [ - "bevy_macro_utils", - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "bevy_audio" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0f12495e230cd5cf59c6051cdd820c97d7fe4f0597d4d9c3240c62e9c65b485" -dependencies = [ - "bevy_app", - "bevy_asset", - "bevy_derive", - "bevy_ecs", - "bevy_math", - "bevy_reflect", - "bevy_transform", - "bevy_utils", - "cpal", - "rodio", -] - -[[package]] -name = "bevy_core" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b0042f241ba7cd61487aadd8addfb56f7eeb662d713ac1577026704508fc6c" -dependencies = [ - "bevy_app", - "bevy_ecs", - "bevy_math", - "bevy_reflect", - "bevy_tasks", - "bevy_utils", - "bytemuck", -] - -[[package]] -name = "bevy_core_pipeline" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48b7a471cb8ba665f12f7a167faa5566c11386f5bfc77d2e10bfde22b179f7b3" -dependencies = [ - "bevy_app", - "bevy_asset", - "bevy_core", - "bevy_derive", - "bevy_ecs", - "bevy_log", - "bevy_math", - "bevy_reflect", - "bevy_render", - "bevy_transform", - "bevy_utils", - "bitflags 2.6.0", - "radsort", - "serde", -] - -[[package]] -name = "bevy_derive" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0e01f8343f391e2d6a63b368b82fb5b252ed43c8713fc87f9a8f2d59407dd00" -dependencies = [ - "bevy_macro_utils", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "bevy_diagnostic" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1401cdccec7e49378d013dfb0ff62c251f85b3be19dcdf04cfd827f793d1ee9" -dependencies = [ - "bevy_app", - "bevy_core", - "bevy_ecs", - "bevy_log", - "bevy_time", - "bevy_utils", - "const-fnv1a-hash", - "sysinfo", -] - -[[package]] -name = "bevy_ecs" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98e612a8e7962ead849e370f3a7e972b88df879ced05cd9dad6a0286d14650cf" -dependencies = [ - "async-channel", - "bevy_ecs_macros", - "bevy_ptr", - "bevy_reflect", - "bevy_tasks", - "bevy_utils", - "downcast-rs", - "fixedbitset", - "rustc-hash", - "serde", - "thiserror", - "thread_local", -] - -[[package]] -name = "bevy_ecs_macros" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "807b5106c3410e58f4f523b55ea3c071e2a09e31e9510f3c22021c6a04732b5b" -dependencies = [ - "bevy_macro_utils", - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "bevy_egui" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0118223ec165efe20f2e017811539ee1ba1f62b03a878022fbaec9e9bfd56bc" -dependencies = [ - "arboard", - "bevy", - "console_log", - "crossbeam-channel", - "egui", - "js-sys", - "log", - "thread_local", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webbrowser", - "winit", -] - -[[package]] -name = "bevy_encase_derive" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "887087a5e522d9f20733a84dd7e6e9ca04cd8fdfac659220ed87d675eebc83a7" -dependencies = [ - "bevy_macro_utils", - "encase_derive_impl", -] - -[[package]] -name = "bevy_gilrs" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d133c65ab756f130c65cf00f37dc293fb9a9336c891802baf006c63e300d0e2" -dependencies = [ - "bevy_app", - "bevy_ecs", - "bevy_input", - "bevy_log", - "bevy_time", - "bevy_utils", - "gilrs", - "thiserror", -] - -[[package]] -name = "bevy_gizmos" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "054df3550a9d423a961de65b459946ff23304f97f25af8a62c23f4259db8506d" -dependencies = [ - "bevy_app", - "bevy_asset", - "bevy_core", - "bevy_core_pipeline", - "bevy_ecs", - "bevy_gizmos_macros", - "bevy_log", - "bevy_math", - "bevy_pbr", - "bevy_reflect", - "bevy_render", - "bevy_sprite", - "bevy_transform", - "bevy_utils", -] - -[[package]] -name = "bevy_gizmos_macros" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abdcaf74d8cd34aa5c3293527e7a012826840886ad3496c1b963ed8b66b1619f" -dependencies = [ - "bevy_macro_utils", - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "bevy_gltf" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21ecf404295055deb7fe037495891bc135ca10d46bc5b6c55f9ab7b7ebc61d31" -dependencies = [ - "base64 0.21.7", - "bevy_animation", - "bevy_app", - "bevy_asset", - "bevy_core", - "bevy_core_pipeline", - "bevy_ecs", - "bevy_hierarchy", - "bevy_log", - "bevy_math", - "bevy_pbr", - "bevy_reflect", - "bevy_render", - "bevy_scene", - "bevy_tasks", - "bevy_transform", - "bevy_utils", - "gltf", - "percent-encoding", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "bevy_gltf_export" -version = "0.1.0" -source = "git+https://github.com/luca-della-vedova/bevy_gltf_export?branch=bevy_0.13#64bf50df30405e851f9d25dda0f2deb0fe926feb" -dependencies = [ - "bevy_asset", - "bevy_pbr", - "bevy_render", - "bevy_transform", - "gltf", - "gltf-json", - "image 0.24.9", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "bevy_hierarchy" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb3dfad24866a6713dafa3065a91c5cf5e355f6e1b191c25d704ae54185246c" -dependencies = [ - "bevy_app", - "bevy_core", - "bevy_ecs", - "bevy_log", - "bevy_reflect", - "bevy_utils", -] - -[[package]] -name = "bevy_impulse" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51233836b91a5460ea24b9647661229cd87cce03e916ee52fa24e9e232623d18" -dependencies = [ - "anyhow", - "arrayvec", - "async-task", - "backtrace", - "bevy_app", - "bevy_core", - "bevy_derive", - "bevy_ecs", - "bevy_hierarchy", - "bevy_impulse_derive", - "bevy_tasks", - "bevy_time", - "bevy_utils", - "futures", - "itertools 0.13.0", - "smallvec", - "thiserror", - "tokio", -] - -[[package]] -name = "bevy_impulse_derive" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bc0cd7c08a0188545e1126d07f83efcd23d7ab55f5df1ba0fb93e850838c3d2" -dependencies = [ - "quote", - "syn 2.0.77", -] - -[[package]] -name = "bevy_infinite_grid" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "151c9b8d3b060330fcfce3bbb997cd9e441681b128677eb0324add922f03d192" -dependencies = [ - "bevy", -] - -[[package]] -name = "bevy_input" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47f2b2b3df168c6ef661d25e09abf5bd4fecaacd400f27e5db650df1c3fa3a3b" -dependencies = [ - "bevy_app", - "bevy_ecs", - "bevy_math", - "bevy_reflect", - "bevy_utils", - "smol_str", - "thiserror", -] - -[[package]] -name = "bevy_internal" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58ec0ce77603df9474cde61f429126bfe06eb79094440e9141afb4217751c79" -dependencies = [ - "bevy_a11y", - "bevy_animation", - "bevy_app", - "bevy_asset", - "bevy_audio", - "bevy_core", - "bevy_core_pipeline", - "bevy_derive", - "bevy_diagnostic", - "bevy_ecs", - "bevy_gilrs", - "bevy_gizmos", - "bevy_gltf", - "bevy_hierarchy", - "bevy_input", - "bevy_log", - "bevy_math", - "bevy_pbr", - "bevy_ptr", - "bevy_reflect", - "bevy_render", - "bevy_scene", - "bevy_sprite", - "bevy_tasks", - "bevy_text", - "bevy_time", - "bevy_transform", - "bevy_ui", - "bevy_utils", - "bevy_window", - "bevy_winit", -] - -[[package]] -name = "bevy_log" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5eea6c527fd828b7fef8d0f518167f27f405b904a16f227b644687d3f46a809" -dependencies = [ - "android_log-sys", - "bevy_app", - "bevy_ecs", - "bevy_utils", - "console_error_panic_hook", - "tracing-log 0.1.4", - "tracing-subscriber", - "tracing-wasm", -] - -[[package]] -name = "bevy_macro_utils" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb270c98a96243b29465139ed10bda2f675d00a11904f6588a5f7fc4774119c7" -dependencies = [ - "proc-macro2", - "quote", - "rustc-hash", - "syn 2.0.77", - "toml_edit 0.21.1", -] - -[[package]] -name = "bevy_math" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f06daa26ffb82d90ba772256c0ba286f6c305c392f6976c9822717974805837c" -dependencies = [ - "glam", - "serde", -] - -[[package]] -name = "bevy_mikktspace" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d7ef7f2a826d0b19f059035831ce00a5e930435cc53c61e045773d0483f67a" -dependencies = [ - "glam", -] - -[[package]] -name = "bevy_mod_outline" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5822bcdc76304f6c9090c6377c279978feaf346e1d67ab7d42302557b8634fe" -dependencies = [ - "bevy", - "bitfield 0.14.0", - "interpolation", - "thiserror", - "wgpu-types", -] - -[[package]] -name = "bevy_mod_raycast" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca646aeaab4a170e1f3e8284b925e2f990eb18616e95d7826c873c8e26ee945" -dependencies = [ - "bevy_app", - "bevy_asset", - "bevy_derive", - "bevy_ecs", - "bevy_gizmos", - "bevy_math", - "bevy_reflect", - "bevy_render", - "bevy_sprite", - "bevy_transform", - "bevy_utils", - "bevy_window", - "crossbeam-channel", -] - -[[package]] -name = "bevy_obj" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d935d4459450e0aa346451483a038f6ac78034999a05deb268abe5ac81713daf" -dependencies = [ - "anyhow", - "bevy_app", - "bevy_asset", - "bevy_ecs", - "bevy_pbr", - "bevy_render", - "bevy_scene", - "bevy_utils", - "thiserror", - "tobj", -] - -[[package]] -name = "bevy_pbr" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b29c80269fa6db55c9e33701edd3ecb73d8866ca8cb814d49a9d3fb72531b6" -dependencies = [ - "bevy_app", - "bevy_asset", - "bevy_core_pipeline", - "bevy_derive", - "bevy_ecs", - "bevy_math", - "bevy_reflect", - "bevy_render", - "bevy_transform", - "bevy_utils", - "bevy_window", - "bitflags 2.6.0", - "bytemuck", - "fixedbitset", - "radsort", - "smallvec", - "thread_local", -] - -[[package]] -name = "bevy_polyline" -version = "0.9.0" -source = "git+https://github.com/luca-della-vedova/bevy_polyline?branch=luca/bevy_0.13_panic#4853b1c51a6d083fbba7bf2acb8e3fe15aa341d9" -dependencies = [ - "bevy", - "bitflags 2.6.0", -] - -[[package]] -name = "bevy_ptr" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8050e2869fe341db6874203b5a01ff12673807a2c7c80cb829f6c7bea6997268" - -[[package]] -name = "bevy_reflect" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccbd7de21d586457a340a0962ad0747dc5098ff925eb6b27a918c4bdd8252f7b" -dependencies = [ - "bevy_math", - "bevy_ptr", - "bevy_reflect_derive", - "bevy_utils", - "downcast-rs", - "erased-serde", - "glam", - "serde", - "smol_str", - "thiserror", -] - -[[package]] -name = "bevy_reflect_derive" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ce33051bd49036d4a5a62aa3f2068672ec55f3ebe92aa0d003a341f15cc37ac" -dependencies = [ - "bevy_macro_utils", - "proc-macro2", - "quote", - "syn 2.0.77", - "uuid", -] - -[[package]] -name = "bevy_render" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b2c4b644c739c0b474b6f8f7b0bc68ac13d83b59688781e9a7753c52780177" -dependencies = [ - "async-channel", - "bevy_app", - "bevy_asset", - "bevy_core", - "bevy_derive", - "bevy_ecs", - "bevy_encase_derive", - "bevy_hierarchy", - "bevy_log", - "bevy_math", - "bevy_mikktspace", - "bevy_reflect", - "bevy_render_macros", - "bevy_tasks", - "bevy_time", - "bevy_transform", - "bevy_utils", - "bevy_window", - "bitflags 2.6.0", - "bytemuck", - "codespan-reporting", - "downcast-rs", - "encase", - "futures-lite 2.3.0", - "hexasphere", - "image 0.24.9", - "js-sys", - "ktx2", - "naga", - "naga_oil", - "ruzstd", - "serde", - "thiserror", - "thread_local", - "wasm-bindgen", - "web-sys", - "wgpu", -] - -[[package]] -name = "bevy_render_macros" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "720b88406e786e378829b7d43c1ffb5300186912b99904d0d4d8ec6698a4f210" -dependencies = [ - "bevy_macro_utils", - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "bevy_scene" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3d2caa1bfe7542dbe2c62e1bcc10791ba181fb744d2fe6711d1d373354da7c" -dependencies = [ - "bevy_app", - "bevy_asset", - "bevy_derive", - "bevy_ecs", - "bevy_hierarchy", - "bevy_reflect", - "bevy_render", - "bevy_transform", - "bevy_utils", - "serde", - "thiserror", - "uuid", -] - -[[package]] -name = "bevy_sprite" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cad1b555161f50e5d62b7fdf7ebeef1b24338aae7a88e51985da9553cd60ddf" -dependencies = [ - "bevy_app", - "bevy_asset", - "bevy_core_pipeline", - "bevy_derive", - "bevy_ecs", - "bevy_log", - "bevy_math", - "bevy_reflect", - "bevy_render", - "bevy_transform", - "bevy_utils", - "bitflags 2.6.0", - "bytemuck", - "fixedbitset", - "guillotiere", - "radsort", - "rectangle-pack", - "thiserror", -] - -[[package]] -name = "bevy_stl" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f9c2b71604c560149a181044b049a5564c5c4f79f1d72abde608e8d57fc98" -dependencies = [ - "anyhow", - "bevy", - "futures-lite 2.3.0", - "stl_io", - "thiserror", -] - -[[package]] -name = "bevy_tasks" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f07fcc4969b357de143509925b39c9a2c56eaa8750828d97f319ca9ed41897cb" -dependencies = [ - "async-channel", - "async-executor", - "async-task", - "concurrent-queue", - "futures-lite 2.3.0", - "wasm-bindgen-futures", -] - -[[package]] -name = "bevy_text" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e8456ae0bea7d6b7621e42c1c12bf66c0891381e62c948ab23920673ce611c" -dependencies = [ - "ab_glyph", - "bevy_app", - "bevy_asset", - "bevy_ecs", - "bevy_math", - "bevy_reflect", - "bevy_render", - "bevy_sprite", - "bevy_transform", - "bevy_utils", - "bevy_window", - "glyph_brush_layout", - "serde", - "thiserror", -] - -[[package]] -name = "bevy_time" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ea5ae9fe7f56f555dbb05a88d34931907873e3f0c7dc426591839eef72fe3e" -dependencies = [ - "bevy_app", - "bevy_ecs", - "bevy_reflect", - "bevy_utils", - "crossbeam-channel", - "thiserror", -] - -[[package]] -name = "bevy_transform" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d51a1f332cc00939d2f19ed6b909e5ed7037e39c7e25cc86930d79d432163e" -dependencies = [ - "bevy_app", - "bevy_ecs", - "bevy_hierarchy", - "bevy_math", - "bevy_reflect", - "thiserror", -] - -[[package]] -name = "bevy_ui" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bbc30be39cfbfa3a073b541d22aea43ab14452dea12d7411ce201df17ff7b1" -dependencies = [ - "bevy_a11y", - "bevy_app", - "bevy_asset", - "bevy_core_pipeline", - "bevy_derive", - "bevy_ecs", - "bevy_hierarchy", - "bevy_input", - "bevy_log", - "bevy_math", - "bevy_reflect", - "bevy_render", - "bevy_sprite", - "bevy_text", - "bevy_transform", - "bevy_utils", - "bevy_window", - "bytemuck", - "taffy", - "thiserror", -] - -[[package]] -name = "bevy_utils" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9f845a985c00e0ee8dc2d8af3f417be925fb52aad4bda5b96e2e58a2b4d2eb" -dependencies = [ - "ahash", - "bevy_utils_proc_macros", - "getrandom", - "hashbrown 0.14.5", - "nonmax", - "petgraph", - "smallvec", - "thiserror", - "tracing", - "uuid", - "web-time", -] - -[[package]] -name = "bevy_utils_proc_macros" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef158627f30503d5c18c20c60b444829f698d343516eeaf6eeee078c9a45163" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "bevy_window" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976202d2ed838176595b550ac654b15ae236e0178a6f19a94ca6d58f2a96ca60" -dependencies = [ - "bevy_a11y", - "bevy_app", - "bevy_ecs", - "bevy_input", - "bevy_math", - "bevy_reflect", - "bevy_utils", - "raw-window-handle 0.6.2", - "smol_str", -] - -[[package]] -name = "bevy_winit" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa66539aa93d8522b146bf82de429714ea6370a6061fc1f1ff7bcacd4e64c6c4" -dependencies = [ - "accesskit_winit", - "approx", - "bevy_a11y", - "bevy_app", - "bevy_derive", - "bevy_ecs", - "bevy_hierarchy", - "bevy_input", - "bevy_math", - "bevy_tasks", - "bevy_utils", - "bevy_window", - "crossbeam-channel", - "raw-window-handle 0.6.2", - "wasm-bindgen", - "web-sys", - "winit", -] - -[[package]] -name = "bindgen" -version = "0.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" -dependencies = [ - "bitflags 2.6.0", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.77", -] - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bit_field" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" - -[[package]] -name = "bitfield" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" - -[[package]] -name = "bitfield" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f798d2d157e547aa99aab0967df39edd0b70307312b6f8bd2848e6abe40896e0" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -dependencies = [ - "serde", -] - -[[package]] -name = "blake3" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", -] - -[[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 0.2.0-beta.2", -] - -[[package]] -name = "block-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" -dependencies = [ - "objc-sys 0.3.5", -] - -[[package]] -name = "block2" -version = "0.2.0-alpha.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42" -dependencies = [ - "block-sys 0.1.0-beta.1", - "objc2-encode 2.0.0-pre.2", -] - -[[package]] -name = "block2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" -dependencies = [ - "block-sys 0.2.1", - "objc2 0.4.1", -] - -[[package]] -name = "block2" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" -dependencies = [ - "objc2 0.5.2", -] - -[[package]] -name = "blocking" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" -dependencies = [ - "async-channel", - "async-task", - "futures-io", - "futures-lite 2.3.0", - "piper", -] - -[[package]] -name = "bstr" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "bytemuck" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "byteorder-lite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" - -[[package]] -name = "bytes" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" - -[[package]] -name = "cairo-sys-rs" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" -dependencies = [ - "libc", - "system-deps", -] - -[[package]] -name = "calloop" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" -dependencies = [ - "bitflags 2.6.0", - "log", - "polling", - "rustix", - "slab", - "thiserror", -] - -[[package]] -name = "calloop-wayland-source" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" -dependencies = [ - "calloop", - "rustix", - "wayland-backend", - "wayland-client", -] - -[[package]] -name = "cc" -version = "1.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45bcde016d64c21da4be18b655631e5ab6d3107607e71a73a9f53eb48aae23fb" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-expr" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" -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 = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", - "windows-targets 0.52.6", -] - -[[package]] -name = "chrono-tz" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" -dependencies = [ - "chrono", - "chrono-tz-build", - "phf", -] - -[[package]] -name = "chrono-tz-build" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" -dependencies = [ - "parse-zoneinfo", - "phf", - "phf_codegen", -] - -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading 0.8.5", -] - -[[package]] -name = "clap" -version = "4.5.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "clap_lex" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" - -[[package]] -name = "clipboard-win" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" -dependencies = [ - "error-code", -] - -[[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 = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - -[[package]] -name = "colorchoice" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" - -[[package]] -name = "com" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6" -dependencies = [ - "com_macros", -] - -[[package]] -name = "com_macros" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5" -dependencies = [ - "com_macros_support", - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "com_macros_support" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "console_log" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" -dependencies = [ - "log", - "web-sys", -] - -[[package]] -name = "const-fnv1a-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b13ea120a812beba79e34316b3942a857c86ec1593cb34f27bb28272ce2cca" - -[[package]] -name = "const_panic" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7782af8f90fe69a4bb41e460abe1727d493403d8b2cc43201a3a3e906b24379f" - -[[package]] -name = "const_soft_float" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ca1caa64ef4ed453e68bb3db612e51cf1b2f5b871337f0fcab1c8f87cc3dff" - -[[package]] -name = "constant_time_eq" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" - -[[package]] -name = "constgebra" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1aaf9b65849a68662ac6c0810c8893a765c960b907dd7cfab9c4a50bf764fbc" -dependencies = [ - "const_soft_float", -] - -[[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 = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "core-graphics" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-graphics-types", - "foreign-types", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "libc", -] - -[[package]] -name = "coreaudio-rs" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" -dependencies = [ - "bitflags 1.3.2", - "core-foundation-sys", - "coreaudio-sys", -] - -[[package]] -name = "coreaudio-sys" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ce857aa0b77d77287acc1ac3e37a05a8c95a2af3647d23b15f263bdaeb7562b" -dependencies = [ - "bindgen", -] - -[[package]] -name = "cpal" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" -dependencies = [ - "alsa", - "core-foundation-sys", - "coreaudio-rs", - "dasp_sample", - "jni", - "js-sys", - "libc", - "mach2", - "ndk", - "ndk-context", - "oboe", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows 0.54.0", -] - -[[package]] -name = "cpufeatures" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "critical-section" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242" - -[[package]] -name = "crossbeam-channel" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "cursor-icon" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" - -[[package]] -name = "d3d12" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e3d747f100290a1ca24b752186f61f6637e1deffe3bf6320de6fcb29510a307" -dependencies = [ - "bitflags 2.6.0", - "libloading 0.8.5", - "winapi", -] - -[[package]] -name = "dasp_sample" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" - -[[package]] -name = "data-encoding" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" - -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "deunicode" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00" - -[[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 = "dirs" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.48.0", -] - -[[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.5", -] - -[[package]] -name = "document-features" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" -dependencies = [ - "litrs", -] - -[[package]] -name = "downcast-rs" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" - -[[package]] -name = "earcutr" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79127ed59a85d7687c409e9978547cffb7dc79675355ed22da6b66fd5f6ead01" -dependencies = [ - "itertools 0.11.0", - "num-traits", -] - -[[package]] -name = "ecolor" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20930a432bbd57a6d55e07976089708d4893f3d556cf42a0d79e9e321fa73b10" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "egui" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "584c5d1bf9a67b25778a3323af222dbe1a1feb532190e103901187f92c7fe29a" -dependencies = [ - "ahash", - "epaint", - "nohash-hasher", -] - -[[package]] -name = "ehttp" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e598cc2bfc28612f26426259ed99a978270e9433d63ae6d2843e30fb0974cd02" -dependencies = [ - "async-channel", - "document-features", - "js-sys", - "ureq", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "emath" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c3a552cfca14630702449d35f41c84a0d15963273771c6059175a803620f3f" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "encase" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ed933078d2e659745df651f4c180511cd582e5b9414ff896e7d50d207e3103" -dependencies = [ - "const_panic", - "encase_derive", - "glam", - "thiserror", -] - -[[package]] -name = "encase_derive" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ce1449c7d19eba6cc0abd231150ad81620a8dce29601d7f8d236e5d431d72a" -dependencies = [ - "encase_derive_impl", -] - -[[package]] -name = "encase_derive_impl" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92959a9e8d13eaa13b8ae8c7b583c3bf1669ca7a8e7708a088d12587ba86effc" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "epaint" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b381f8b149657a4acf837095351839f32cd5c4aec1817fc4df84e18d76334176" -dependencies = [ - "ab_glyph", - "ahash", - "bytemuck", - "ecolor", - "emath", - "nohash-hasher", - "parking_lot", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "erased-serde" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" -dependencies = [ - "serde", - "typeid", -] - -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "error-code" -version = "3.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" - -[[package]] -name = "euclid" -version = "0.22.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48" -dependencies = [ - "num-traits", -] - -[[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 = "5.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" -dependencies = [ - "event-listener 5.3.1", - "pin-project-lite", -] - -[[package]] -name = "exr" -version = "1.72.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" -dependencies = [ - "bit_field", - "flume", - "half", - "lebe", - "miniz_oxide 0.7.4", - "rayon-core", - "smallvec", - "zune-inflate", -] - -[[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.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" - -[[package]] -name = "fdeflate" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" -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.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" -dependencies = [ - "crc32fast", - "miniz_oxide 0.8.0", -] - -[[package]] -name = "float-cmp" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" -dependencies = [ - "num-traits", -] - -[[package]] -name = "float_eq" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a80e3145d8ad11ba0995949bbcf48b9df2be62772b3d351ef017dff6ecb853" - -[[package]] -name = "float_next_after" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8" - -[[package]] -name = "flume" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" -dependencies = [ - "spin", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[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.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[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.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" -dependencies = [ - "fastrand 2.1.1", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "gdk-pixbuf-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gdk-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31ff856cb3386dae1703a920f803abafcc580e9b5f711ca62ed1620c25b51ff2" -dependencies = [ - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "pkg-config", - "system-deps", -] - -[[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 = "geo" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4841b40fdbccd4b7042bd6195e4de91da54af34c50632e371bcbfcdfb558b873" -dependencies = [ - "earcutr", - "float_next_after", - "geo-types", - "geographiclib-rs", - "log", - "num-traits", - "robust", - "rstar", - "spade", -] - -[[package]] -name = "geo-types" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff16065e5720f376fbced200a5ae0f47ace85fd70b7e54269790281353b6d61" -dependencies = [ - "approx", - "num-traits", - "rstar", - "serde", -] - -[[package]] -name = "geographiclib-rs" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e5ed84f8089c70234b0a8e0aedb6dc733671612ddc0d37c6066052f9781960" -dependencies = [ - "libm", -] - -[[package]] -name = "gethostname" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" -dependencies = [ - "libc", - "windows-targets 0.48.5", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "gif" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" -dependencies = [ - "color_quant", - "weezl", -] - -[[package]] -name = "gilrs" -version = "0.10.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a556964c6d62458084356ce9770676f5104bd667e12e9a795691076e8a17c5cf" -dependencies = [ - "fnv", - "gilrs-core", - "log", - "uuid", - "vec_map", -] - -[[package]] -name = "gilrs-core" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "732dadc05170599ddec9a89653f10d7a2af54da9181b3fa6e2bd49907ec8f7e4" -dependencies = [ - "core-foundation", - "inotify", - "io-kit-sys", - "js-sys", - "libc", - "libudev-sys", - "log", - "nix", - "uuid", - "vec_map", - "wasm-bindgen", - "web-sys", - "windows 0.58.0", -] - -[[package]] -name = "gimli" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" - -[[package]] -name = "gio-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", - "winapi", -] - -[[package]] -name = "gl_generator" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" -dependencies = [ - "khronos_api", - "log", - "xml-rs", -] - -[[package]] -name = "glam" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" -dependencies = [ - "bytemuck", - "serde", -] - -[[package]] -name = "glib-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" -dependencies = [ - "libc", - "system-deps", -] - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "globset" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", -] - -[[package]] -name = "globwalk" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" -dependencies = [ - "bitflags 2.6.0", - "ignore", - "walkdir", -] - -[[package]] -name = "glow" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" -dependencies = [ - "js-sys", - "slotmap", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gltf" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ce1918195723ce6ac74e80542c5a96a40c2b26162c1957a5cd70799b8cacf7" -dependencies = [ - "byteorder", - "gltf-json", - "lazy_static", - "serde_json", -] - -[[package]] -name = "gltf-derive" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14070e711538afba5d6c807edb74bcb84e5dbb9211a3bf5dea0dfab5b24f4c51" -dependencies = [ - "inflections", - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "gltf-json" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6176f9d60a7eab0a877e8e96548605dedbde9190a7ae1e80bbcc1c9af03ab14" -dependencies = [ - "gltf-derive", - "serde", - "serde_derive", - "serde_json", -] - -[[package]] -name = "glutin_wgl_sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" -dependencies = [ - "gl_generator", -] - -[[package]] -name = "glyph_brush_layout" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1e288bfd2f6c0313f78bf5aa538356ad481a3bb97e9b7f93220ab0066c5992" -dependencies = [ - "ab_glyph", - "approx", - "xi-unicode", -] - -[[package]] -name = "gobject-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gpu-alloc" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" -dependencies = [ - "bitflags 2.6.0", - "gpu-alloc-types", -] - -[[package]] -name = "gpu-alloc-types" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" -dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "gpu-allocator" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884" -dependencies = [ - "log", - "presser", - "thiserror", - "winapi", - "windows 0.52.0", -] - -[[package]] -name = "gpu-descriptor" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" -dependencies = [ - "bitflags 2.6.0", - "gpu-descriptor-types", - "hashbrown 0.14.5", -] - -[[package]] -name = "gpu-descriptor-types" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c" -dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "grid" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eec1c01eb1de97451ee0d60de7d81cf1e72aabefb021616027f3d1c3ec1c723c" - -[[package]] -name = "gtk-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771437bf1de2c1c0b496c11505bdf748e26066bbe942dfc8f614c9460f6d7722" -dependencies = [ - "atk-sys", - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "system-deps", -] - -[[package]] -name = "guillotiere" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62d5865c036cb1393e23c50693df631d3f5d7bcca4c04fe4cc0fd592e74a782" -dependencies = [ - "euclid", - "svg_fmt", -] - -[[package]] -name = "gz-fuel" -version = "0.1.0" -source = "git+https://github.com/open-rmf/gz-fuel-rs?branch=main#cbdb4b587834ac9af78d0018c6dcd9ab3efd3cb2" -dependencies = [ - "crossbeam-channel", - "dirs", - "ehttp", - "futures-lite 2.3.0", - "itertools 0.13.0", - "serde", - "serde_json", -] - -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", -] - -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - -[[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.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", - "serde", -] - -[[package]] -name = "hassle-rs" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" -dependencies = [ - "bitflags 2.6.0", - "com", - "libc", - "libloading 0.8.5", - "thiserror", - "widestring", - "winapi", -] - -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "spin", - "stable_deref_trait", -] - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - -[[package]] -name = "hexasphere" -version = "10.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f33ddb7f7143d9e703c072e88b98cd8b9719f174137a671429351bd2ee43c02a" -dependencies = [ - "constgebra", - "glam", -] - -[[package]] -name = "hexf-parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "humansize" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" -dependencies = [ - "libm", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core 0.52.0", -] - -[[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 = "icrate" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" -dependencies = [ - "block2 0.3.0", - "dispatch", - "objc2 0.4.1", -] - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "ignore" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" -dependencies = [ - "crossbeam-deque", - "globset", - "log", - "memchr", - "regex-automata 0.4.7", - "same-file", - "walkdir", - "winapi-util", -] - -[[package]] -name = "image" -version = "0.24.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" -dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "exr", - "gif", - "jpeg-decoder", - "num-traits", - "png", - "qoi", - "tiff", -] - -[[package]] -name = "image" -version = "0.25.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10" -dependencies = [ - "bytemuck", - "byteorder-lite", - "num-traits", - "png", - "tiff", -] - -[[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", -] - -[[package]] -name = "indexmap" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" -dependencies = [ - "equivalent", - "hashbrown 0.14.5", -] - -[[package]] -name = "inflections" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" - -[[package]] -name = "inotify" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd168d97690d0b8c412d6b6c10360277f4d7ee495c5d0d5d5fe0854923255cc" -dependencies = [ - "bitflags 1.3.2", - "inotify-sys", - "libc", -] - -[[package]] -name = "inotify-sys" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" -dependencies = [ - "libc", -] - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "interpolation" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c13ae9d91148fcb4aab6654c4c2a7d02a15395ea9e23f65170f175f8b269ce" - -[[package]] -name = "io-kit-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b" -dependencies = [ - "core-foundation-sys", - "mach2", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "jni" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine", - "jni-sys", - "log", - "thiserror", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "jobserver" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] - -[[package]] -name = "jpeg-decoder" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" -dependencies = [ - "rayon", -] - -[[package]] -name = "js-sys" -version = "0.3.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "khronos-egl" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" -dependencies = [ - "libc", - "libloading 0.8.5", - "pkg-config", -] - -[[package]] -name = "khronos_api" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" - -[[package]] -name = "ktx2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87d65e08a9ec02e409d27a0139eaa6b9756b4d81fe7cde71f6941a83730ce838" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "lebe" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" - -[[package]] -name = "lewton" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030" -dependencies = [ - "byteorder", - "ogg", - "tinyvec", -] - -[[package]] -name = "libc" -version = "0.2.158" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" - -[[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.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" -dependencies = [ - "cfg-if", - "windows-targets 0.52.6", -] - -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - -[[package]] -name = "libredox" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" -dependencies = [ - "bitflags 2.6.0", - "libc", - "redox_syscall 0.4.1", -] - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.6.0", - "libc", -] - -[[package]] -name = "libudev-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - -[[package]] -name = "litrs" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "mach2" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" -dependencies = [ - "libc", -] - -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "matrixmultiply" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" -dependencies = [ - "autocfg", - "rawpointer", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "memmap2" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" -dependencies = [ - "libc", -] - -[[package]] -name = "metal" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25" -dependencies = [ - "bitflags 2.6.0", - "block", - "core-graphics-types", - "foreign-types", - "log", - "objc", - "paste", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", - "simd-adler32", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" -dependencies = [ - "adler2", -] - -[[package]] -name = "naga" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e3524642f53d9af419ab5e8dd29d3ba155708267667c2f3f06c88c9e130843" -dependencies = [ - "bit-set", - "bitflags 2.6.0", - "codespan-reporting", - "hexf-parse", - "indexmap 2.5.0", - "log", - "num-traits", - "pp-rs", - "rustc-hash", - "spirv", - "termcolor", - "thiserror", - "unicode-xid", -] - -[[package]] -name = "naga_oil" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ea62ae0f2787456afca7209ca180522b41f00cbe159ee369eba1e07d365cd1" -dependencies = [ - "bit-set", - "codespan-reporting", - "data-encoding", - "indexmap 2.5.0", - "naga", - "once_cell", - "regex", - "regex-syntax 0.8.4", - "rustc-hash", - "thiserror", - "tracing", - "unicode-ident", -] - -[[package]] -name = "nalgebra" -version = "0.32.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5c17de023a86f59ed79891b2e5d5a94c705dbe904a5b5c9c952ea6221b03e4" -dependencies = [ - "approx", - "matrixmultiply", - "nalgebra-macros", - "num-complex", - "num-rational", - "num-traits", - "simba", - "typenum", -] - -[[package]] -name = "nalgebra-macros" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "254a5372af8fc138e36684761d3c0cdb758a4410e938babcff1c860ce14ddbfc" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "ndk" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" -dependencies = [ - "bitflags 2.6.0", - "jni-sys", - "log", - "ndk-sys", - "num_enum", - "raw-window-handle 0.6.2", - "thiserror", -] - -[[package]] -name = "ndk-context" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" - -[[package]] -name = "ndk-sys" -version = "0.5.0+25.2.9519653" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" -dependencies = [ - "jni-sys", -] - -[[package]] -name = "nix" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "cfg_aliases 0.2.1", - "libc", -] - -[[package]] -name = "nohash-hasher" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" - -[[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 = "nonmax" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" - -[[package]] -name = "ntapi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" -dependencies = [ - "winapi", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "num_enum" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", - "objc_exception", -] - -[[package]] -name = "objc-foundation" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" -dependencies = [ - "block", - "objc", - "objc_id", -] - -[[package]] -name = "objc-sys" -version = "0.2.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7" - -[[package]] -name = "objc-sys" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" - -[[package]] -name = "objc2" -version = "0.3.0-beta.3.patch-leaks.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468" -dependencies = [ - "block2 0.2.0-alpha.6", - "objc-sys 0.2.0-beta.2", - "objc2-encode 2.0.0-pre.2", -] - -[[package]] -name = "objc2" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" -dependencies = [ - "objc-sys 0.3.5", - "objc2-encode 3.0.0", -] - -[[package]] -name = "objc2" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" -dependencies = [ - "objc-sys 0.3.5", - "objc2-encode 4.0.3", -] - -[[package]] -name = "objc2-app-kit" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" -dependencies = [ - "bitflags 2.6.0", - "block2 0.5.1", - "libc", - "objc2 0.5.2", - "objc2-core-data", - "objc2-core-image", - "objc2-foundation", - "objc2-quartz-core", -] - -[[package]] -name = "objc2-core-data" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" -dependencies = [ - "bitflags 2.6.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation", -] - -[[package]] -name = "objc2-core-image" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" -dependencies = [ - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation", - "objc2-metal", -] - -[[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 0.2.0-beta.2", -] - -[[package]] -name = "objc2-encode" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" - -[[package]] -name = "objc2-encode" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" - -[[package]] -name = "objc2-foundation" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" -dependencies = [ - "bitflags 2.6.0", - "block2 0.5.1", - "libc", - "objc2 0.5.2", -] - -[[package]] -name = "objc2-metal" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" -dependencies = [ - "bitflags 2.6.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" -dependencies = [ - "bitflags 2.6.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation", - "objc2-metal", -] - -[[package]] -name = "objc_exception" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" -dependencies = [ - "cc", -] - -[[package]] -name = "objc_id" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" -dependencies = [ - "objc", -] - -[[package]] -name = "object" -version = "0.36.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" -dependencies = [ - "memchr", -] - -[[package]] -name = "oboe" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" -dependencies = [ - "jni", - "ndk", - "ndk-context", - "num-derive", - "num-traits", - "oboe-sys", -] - -[[package]] -name = "oboe-sys" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d" -dependencies = [ - "cc", -] - -[[package]] -name = "ogg" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e" -dependencies = [ - "byteorder", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "orbclient" -version = "0.3.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166" -dependencies = [ - "libredox 0.0.2", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "owned_ttf_parser" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490d3a563d3122bf7c911a59b0add9389e5ec0f5f0c3ac6b91ff235a0e6a7f90" -dependencies = [ - "ttf-parser", -] - -[[package]] -name = "pango-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.5.4", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "parse-zoneinfo" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" -dependencies = [ - "regex", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "pathdiff" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pest" -version = "2.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c73c26c01b8c87956cea613c907c9d6ecffd8d18a2a5908e5de0adfaa185cea" -dependencies = [ - "memchr", - "thiserror", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664d22978e2815783adbdd2c588b455b1bd625299ce36b2a99881ac9627e6d8d" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2d5487022d5d33f4c30d91c22afa240ce2a644e87fe08caad974d4eab6badbe" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "pest_meta" -version = "2.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0091754bbd0ea592c4deb3a122ce8ecbb0753b738aa82bc055fcc2eccc8d8174" -dependencies = [ - "once_cell", - "pest", - "sha2", -] - -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.5.0", -] - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_codegen" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" -dependencies = [ - "phf_generator", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared", - "rand", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand 2.1.1", - "futures-io", -] - -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "png" -version = "0.17.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide 0.7.4", -] - -[[package]] -name = "polling" -version = "3.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi", - "pin-project-lite", - "rustix", - "tracing", - "windows-sys 0.59.0", -] - -[[package]] -name = "pp-rs" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb458bb7f6e250e6eb79d5026badc10a3ebb8f9a15d1fff0f13d17c71f4d6dee" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "presser" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" - -[[package]] -name = "proc-macro-crate" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" -dependencies = [ - "toml_edit 0.22.21", -] - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "profiling" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" - -[[package]] -name = "qoi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "quick-xml" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96a05e2e8efddfa51a84ca47cec303fac86c8541b686d37cac5efc0e094417bc" -dependencies = [ - "memchr", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radsort" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "019b4b213425016d7d84a153c4c73afb0946fbb4840e4eece7ba8848b9d6da22" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "range-alloc" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" - -[[package]] -name = "raw-window-handle" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" - -[[package]] -name = "raw-window-handle" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" - -[[package]] -name = "rawpointer" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "rectangle-pack" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d463f2884048e7153449a55166f91028d5b0ea53c79377099ce4e8cf0cf9bb" - -[[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 = "redox_syscall" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" -dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom", - "libredox 0.1.3", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.4", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - -[[package]] -name = "renderdoc-sys" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" - -[[package]] -name = "rfd" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c9e7b57df6e8472152674607f6cc68aa14a748a3157a857a94f516e11aeacc2" -dependencies = [ - "block", - "dispatch", - "glib-sys", - "gobject-sys", - "gtk-sys", - "js-sys", - "log", - "objc", - "objc-foundation", - "objc_id", - "raw-window-handle 0.5.2", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows-sys 0.48.0", -] - -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rmf_site_editor" -version = "0.0.1" -dependencies = [ - "bevy", - "bevy_egui", - "bevy_gltf_export", - "bevy_impulse", - "bevy_infinite_grid", - "bevy_mod_outline", - "bevy_mod_raycast", - "bevy_obj", - "bevy_polyline", - "bevy_stl", - "bitfield 0.17.0", - "clap", - "console_error_panic_hook", - "crossbeam-channel", - "dirs", - "ehttp", - "futures-lite 1.13.0", - "geo", - "gz-fuel", - "itertools 0.13.0", - "nalgebra", - "pathdiff", - "rfd", - "rmf_site_format", - "sdformat_rs", - "serde", - "serde_json", - "serde_yaml", - "smallvec", - "tera", - "thiserror", - "thread_local", - "tracing", - "tracing-subscriber", - "urdf-rs", - "utm", - "wasm-bindgen", - "yaserde", -] - -[[package]] -name = "rmf_site_format" -version = "0.0.1" -dependencies = [ - "bevy", - "float_eq", - "glam", - "once_cell", - "pathdiff", - "ron", - "sdformat_rs", - "serde", - "serde_json", - "serde_yaml", - "thiserror", - "urdf-rs", - "uuid", - "yaserde", -] - -[[package]] -name = "robust" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf4a6aa5f6d6888f39e980649f3ad6b666acdce1d78e95b8a2cb076e687ae30" - -[[package]] -name = "rodio" -version = "0.17.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b1bb7b48ee48471f55da122c0044fcc7600cfcc85db88240b89cb832935e611" -dependencies = [ - "cpal", - "lewton", -] - -[[package]] -name = "ron" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" -dependencies = [ - "base64 0.21.7", - "bitflags 2.6.0", - "serde", - "serde_derive", -] - -[[package]] -name = "rstar" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73111312eb7a2287d229f06c00ff35b51ddee180f017ab6dec1f69d62ac098d6" -dependencies = [ - "heapless", - "num-traits", - "smallvec", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[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.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" -dependencies = [ - "bitflags 2.6.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls" -version = "0.23.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" -dependencies = [ - "log", - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pki-types" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" - -[[package]] -name = "rustls-webpki" -version = "0.102.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "ruzstd" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" -dependencies = [ - "byteorder", - "derive_more", - "twox-hash", -] - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "safe_arch" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a" -dependencies = [ - "bytemuck", -] - -[[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.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70b31447ca297092c5a9916fc3b955203157b37c19ca8edde4f52e9843e602c7" -dependencies = [ - "ab_glyph", - "log", - "memmap2", - "smithay-client-toolkit", - "tiny-skia", -] - -[[package]] -name = "sdformat_rs" -version = "0.1.0" -source = "git+https://github.com/open-rmf/sdf_rust_experimental?rev=9fc35f2#9fc35f2b5f55afab37a4c1906c395fc22d069322" -dependencies = [ - "convert_case", - "nalgebra", - "xmltree", - "yaserde", - "yaserde_derive", -] - -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" - -[[package]] -name = "serde" -version = "1.0.210" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.210" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "serde_json" -version = "1.0.128" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_spanned" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_yaml" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" -dependencies = [ - "indexmap 1.9.3", - "ryu", - "serde", - "yaml-rust", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "simba" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" -dependencies = [ - "approx", - "num-complex", - "num-traits", - "paste", - "wide", -] - -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "slotmap" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" -dependencies = [ - "version_check", -] - -[[package]] -name = "slug" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" -dependencies = [ - "deunicode", - "wasm-bindgen", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -dependencies = [ - "serde", -] - -[[package]] -name = "smithay-client-toolkit" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" -dependencies = [ - "bitflags 2.6.0", - "calloop", - "calloop-wayland-source", - "cursor-icon", - "libc", - "log", - "memmap2", - "rustix", - "thiserror", - "wayland-backend", - "wayland-client", - "wayland-csd-frame", - "wayland-cursor", - "wayland-protocols", - "wayland-protocols-wlr", - "wayland-scanner", - "xkeysym", -] - -[[package]] -name = "smol_str" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" -dependencies = [ - "serde", -] - -[[package]] -name = "spade" -version = "2.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f5ef1f863aca7d1d7dda7ccfc36a0a4279bd6d3c375176e5e0712e25cb4889" -dependencies = [ - "hashbrown 0.14.5", - "num-traits", - "robust", - "smallvec", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "spirv" -version = "0.3.0+sdk-1.3.268.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" -dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "stl_io" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d520eb03e632e666ac32f3c0cf018ac6dcd535ab0be1420937e2d896f44f7cf7" -dependencies = [ - "byteorder", - "float-cmp", -] - -[[package]] -name = "strict-num" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "svg_fmt" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20e16a0f46cf5fd675563ef54f26e83e20f2366bcf027bcb3cc3ed2b98aaf2ca" - -[[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.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sysinfo" -version = "0.30.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3" -dependencies = [ - "cfg-if", - "core-foundation-sys", - "libc", - "ntapi", - "once_cell", - "windows 0.52.0", -] - -[[package]] -name = "system-deps" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" -dependencies = [ - "cfg-expr", - "heck 0.5.0", - "pkg-config", - "toml", - "version-compare", -] - -[[package]] -name = "taffy" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1315457ccd9c3def787a18fae91914e623e4dcff019b64ce39f5268ded53d3d" -dependencies = [ - "arrayvec", - "grid", - "num-traits", - "slotmap", -] - -[[package]] -name = "target-lexicon" -version = "0.12.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" - -[[package]] -name = "tera" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab9d851b45e865f178319da0abdbfe6acbc4328759ff18dafc3a41c16b4cd2ee" -dependencies = [ - "chrono", - "chrono-tz", - "globwalk", - "humansize", - "lazy_static", - "percent-encoding", - "pest", - "pest_derive", - "rand", - "regex", - "serde", - "serde_json", - "slug", - "unic-segment", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "1.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "tiff" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" -dependencies = [ - "flate2", - "jpeg-decoder", - "weezl", -] - -[[package]] -name = "tiny-skia" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" -dependencies = [ - "arrayref", - "arrayvec", - "bytemuck", - "cfg-if", - "log", - "tiny-skia-path", -] - -[[package]] -name = "tiny-skia-path" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" -dependencies = [ - "arrayref", - "bytemuck", - "strict-num", -] - -[[package]] -name = "tinyvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" -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 = "tobj" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bd4ba05f29e4c65b6c0c11a58b6465ffa820bac890d76ad407b4e81d8372e8" -dependencies = [ - "ahash", - "log", -] - -[[package]] -name = "tokio" -version = "1.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" -dependencies = [ - "backtrace", - "pin-project-lite", -] - -[[package]] -name = "toml" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.22.21", -] - -[[package]] -name = "toml_datetime" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" -dependencies = [ - "indexmap 2.5.0", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" -dependencies = [ - "indexmap 2.5.0", - "serde", - "serde_spanned", - "toml_datetime", - "winnow 0.6.18", -] - -[[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.77", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log 0.2.0", -] - -[[package]] -name = "tracing-wasm" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" -dependencies = [ - "tracing", - "tracing-subscriber", - "wasm-bindgen", -] - -[[package]] -name = "ttf-parser" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be21190ff5d38e8b4a2d3b6a3ae57f612cc39c96e83cedeaf7abc338a8bac4a" - -[[package]] -name = "twox-hash" -version = "1.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" -dependencies = [ - "cfg-if", - "static_assertions", -] - -[[package]] -name = "typeid" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "ucd-trie" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" -dependencies = [ - "unic-ucd-segment", -] - -[[package]] -name = "unic-ucd-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-ident" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-width" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" - -[[package]] -name = "unicode-xid" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "urdf-rs" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98e716107a1f06d9261b044b3c0518b1884f9fb4b2b2e124aad43a53d206c7fd" -dependencies = [ - "once_cell", - "regex", - "thiserror", - "yaserde", - "yaserde_derive", -] - -[[package]] -name = "ureq" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" -dependencies = [ - "base64 0.22.1", - "flate2", - "log", - "once_cell", - "rustls", - "rustls-pki-types", - "url", - "webpki-roots", -] - -[[package]] -name = "url" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "utm" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b09e3b3a0abd1ccb77673a6b7b8875d9d1c80626154add451cf18392dc4c3c" - -[[package]] -name = "uuid" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" -dependencies = [ - "getrandom", - "serde", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[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.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" -dependencies = [ - "cfg-if", - "once_cell", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.77", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" - -[[package]] -name = "wayland-backend" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" -dependencies = [ - "cc", - "downcast-rs", - "rustix", - "scoped-tls", - "smallvec", - "wayland-sys", -] - -[[package]] -name = "wayland-client" -version = "0.31.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3f45d1222915ef1fd2057220c1d9d9624b7654443ea35c3877f7a52bd0a5a2d" -dependencies = [ - "bitflags 2.6.0", - "rustix", - "wayland-backend", - "wayland-scanner", -] - -[[package]] -name = "wayland-csd-frame" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" -dependencies = [ - "bitflags 2.6.0", - "cursor-icon", - "wayland-backend", -] - -[[package]] -name = "wayland-cursor" -version = "0.31.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a94697e66e76c85923b0d28a0c251e8f0666f58fc47d316c0f4da6da75d37cb" -dependencies = [ - "rustix", - "wayland-client", - "xcursor", -] - -[[package]] -name = "wayland-protocols" -version = "0.31.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" -dependencies = [ - "bitflags 2.6.0", - "wayland-backend", - "wayland-client", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols-plasma" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" -dependencies = [ - "bitflags 2.6.0", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols-wlr" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" -dependencies = [ - "bitflags 2.6.0", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-scanner", -] - -[[package]] -name = "wayland-scanner" -version = "0.31.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" -dependencies = [ - "proc-macro2", - "quick-xml", - "quote", -] - -[[package]] -name = "wayland-sys" -version = "0.31.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" -dependencies = [ - "dlib", - "log", - "once_cell", - "pkg-config", -] - -[[package]] -name = "web-sys" -version = "0.3.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webbrowser" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db67ae75a9405634f5882791678772c94ff5f16a66535aae186e26aa0841fc8b" -dependencies = [ - "core-foundation", - "home", - "jni", - "log", - "ndk-context", - "objc", - "raw-window-handle 0.5.2", - "url", - "web-sys", -] - -[[package]] -name = "webpki-roots" -version = "0.26.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "weezl" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" - -[[package]] -name = "wgpu" -version = "0.19.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbd7311dbd2abcfebaabf1841a2824ed7c8be443a0f29166e5d3c6a53a762c01" -dependencies = [ - "arrayvec", - "cfg-if", - "cfg_aliases 0.1.1", - "js-sys", - "log", - "naga", - "parking_lot", - "profiling", - "raw-window-handle 0.6.2", - "smallvec", - "static_assertions", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "wgpu-core", - "wgpu-hal", - "wgpu-types", -] - -[[package]] -name = "wgpu-core" -version = "0.19.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b94525fc99ba9e5c9a9e24764f2bc29bad0911a7446c12f446a8277369bf3a" -dependencies = [ - "arrayvec", - "bit-vec", - "bitflags 2.6.0", - "cfg_aliases 0.1.1", - "codespan-reporting", - "indexmap 2.5.0", - "log", - "naga", - "once_cell", - "parking_lot", - "profiling", - "raw-window-handle 0.6.2", - "rustc-hash", - "smallvec", - "thiserror", - "web-sys", - "wgpu-hal", - "wgpu-types", -] - -[[package]] -name = "wgpu-hal" -version = "0.19.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfabcfc55fd86611a855816326b2d54c3b2fd7972c27ce414291562650552703" -dependencies = [ - "android_system_properties", - "arrayvec", - "ash", - "bit-set", - "bitflags 2.6.0", - "block", - "cfg_aliases 0.1.1", - "core-graphics-types", - "d3d12", - "glow", - "glutin_wgl_sys", - "gpu-alloc", - "gpu-allocator", - "gpu-descriptor", - "hassle-rs", - "js-sys", - "khronos-egl", - "libc", - "libloading 0.8.5", - "log", - "metal", - "naga", - "ndk-sys", - "objc", - "once_cell", - "parking_lot", - "profiling", - "range-alloc", - "raw-window-handle 0.6.2", - "renderdoc-sys", - "rustc-hash", - "smallvec", - "thiserror", - "wasm-bindgen", - "web-sys", - "wgpu-types", - "winapi", -] - -[[package]] -name = "wgpu-types" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b671ff9fb03f78b46ff176494ee1ebe7d603393f42664be55b64dc8d53969805" -dependencies = [ - "bitflags 2.6.0", - "js-sys", - "web-sys", -] - -[[package]] -name = "wide" -version = "0.7.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b828f995bf1e9622031f8009f8481a85406ce1f4d4588ff746d872043e855690" -dependencies = [ - "bytemuck", - "safe_arch", -] - -[[package]] -name = "widestring" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-implement 0.48.0", - "windows-interface 0.48.0", - "windows-targets 0.48.5", -] - -[[package]] -name = "windows" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" -dependencies = [ - "windows-core 0.52.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows" -version = "0.54.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" -dependencies = [ - "windows-core 0.54.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.54.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" -dependencies = [ - "windows-result 0.1.2", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" -dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-implement" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e2ee588991b9e7e6c8338edf3333fbe4da35dc72092643958ebb43f0ab2c49c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "windows-interface" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6fb8df20c9bcaa8ad6ab513f7b40104840c8867d5751126e4df3b08388d0cc7" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "windows-result" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winit" -version = "0.29.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" -dependencies = [ - "ahash", - "android-activity", - "atomic-waker", - "bitflags 2.6.0", - "bytemuck", - "calloop", - "cfg_aliases 0.1.1", - "core-foundation", - "core-graphics", - "cursor-icon", - "icrate", - "js-sys", - "libc", - "log", - "memmap2", - "ndk", - "ndk-sys", - "objc2 0.4.1", - "once_cell", - "orbclient", - "percent-encoding", - "raw-window-handle 0.6.2", - "redox_syscall 0.3.5", - "rustix", - "sctk-adwaita", - "smithay-client-toolkit", - "smol_str", - "unicode-segmentation", - "wasm-bindgen", - "wasm-bindgen-futures", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-protocols-plasma", - "web-sys", - "web-time", - "windows-sys 0.48.0", - "x11-dl", - "x11rb", - "xkbcommon-dl", -] - -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" -dependencies = [ - "memchr", -] - -[[package]] -name = "x11-dl" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" -dependencies = [ - "libc", - "once_cell", - "pkg-config", -] - -[[package]] -name = "x11rb" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" -dependencies = [ - "as-raw-xcb-connection", - "gethostname", - "libc", - "libloading 0.8.5", - "once_cell", - "rustix", - "x11rb-protocol", -] - -[[package]] -name = "x11rb-protocol" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" - -[[package]] -name = "xcursor" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61" - -[[package]] -name = "xi-unicode" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" - -[[package]] -name = "xkbcommon-dl" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" -dependencies = [ - "bitflags 2.6.0", - "dlib", - "log", - "once_cell", - "xkeysym", -] - -[[package]] -name = "xkeysym" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" - -[[package]] -name = "xml-rs" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" - -[[package]] -name = "xmltree" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb" -dependencies = [ - "xml-rs", -] - -[[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] - -[[package]] -name = "yaserde" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2776ec5bb20e76d89268e87e1ea66c078b94f55e9771e4d648adda3019f87fc" -dependencies = [ - "log", - "xml-rs", -] - -[[package]] -name = "yaserde_derive" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c0b0a4701f203ebaecce4971a6bb8575aa07b617bdc39ddfc6ffeff3a38530d" -dependencies = [ - "heck 0.3.3", - "log", - "proc-macro2", - "quote", - "syn 1.0.109", - "xml-rs", -] - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - -[[package]] -name = "zune-inflate" -version = "0.2.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" -dependencies = [ - "simd-adler32", -] diff --git a/rmf_site_editor/Cargo.toml b/rmf_site_editor/Cargo.toml index ca4d1601..44271f17 100644 --- a/rmf_site_editor/Cargo.toml +++ b/rmf_site_editor/Cargo.toml @@ -50,6 +50,7 @@ pathdiff = "*" tera = "1.19.1" ehttp = { version = "0.4", features = ["native-async"] } nalgebra = "0.32.5" +anyhow = "*" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] clap = { version = "4.0.10", features = ["color", "derive", "help", "usage", "suggestions"] } diff --git a/rmf_site_editor/src/interaction/anchor.rs b/rmf_site_editor/src/interaction/anchor.rs index 5a9f2ca0..beef344b 100644 --- a/rmf_site_editor/src/interaction/anchor.rs +++ b/rmf_site_editor/src/interaction/anchor.rs @@ -23,6 +23,12 @@ use crate::{ }; use bevy::prelude::*; +/// Use this resource to indicate whether anchors should be constantly highlighted. +/// This is used during anchor selection modes to make it easier for users to know +/// where selectable anchors are. +#[derive(Clone, Copy, Debug, Resource)] +pub struct HighlightAnchors(pub bool); + #[derive(Component, Debug, Clone, Copy)] pub struct AnchorVisualization { pub body: Entity, @@ -37,6 +43,7 @@ pub fn add_anchor_visual_cues( >, categories: Query<&Category>, site_assets: Res, + highlight: Res, ) { for (e, parent, subordinate, anchor) in &new_anchors { let body_mesh = match categories.get(parent.get()).unwrap() { @@ -65,12 +72,29 @@ pub fn add_anchor_visual_cues( .insert(OutlineVisualization::Anchor { body }) .add_child(body); - // 3D anchors should always be visible with arrow cue meshes - if anchor.is_3D() { - entity_commands.insert(VisualCue::outline()); + let cue = if anchor.is_3D() { + // 3D anchors should always be visible with arrow cue meshes + VisualCue::outline() } else { - entity_commands.insert(VisualCue::outline().irregular()); - } + let mut cue = VisualCue::outline().irregular(); + cue.xray.set_always(highlight.0); + cue + }; + + entity_commands.insert(cue); + } +} + +pub fn on_highlight_anchors_change( + highlight: Res, + mut anchor_visual_cues: Query<&mut VisualCue, With>, +) { + if !highlight.is_changed() { + return; + } + + for mut cue in &mut anchor_visual_cues { + cue.xray.set_always(highlight.0); } } @@ -110,12 +134,12 @@ pub fn update_anchor_proximity_xray( } let p_c = match intersect_ground_params.ground_plane_intersection() { - Some(p) => p, + Some(p) => p.translation, None => return, }; for (anchor_tf, mut cue) in &mut anchors { - // TODO(MXG): Make the proximity range configurable + // TODO(@mxgrey): Make the proximity range configurable let proximity = { // We make the xray effect a little "sticky" so that there isn't an // ugly flicker for anchors that are right at the edge of the @@ -156,22 +180,6 @@ pub fn update_unassigned_anchor_cues( } } -pub fn update_anchor_cues_for_mode( - mode: Res, - mut anchors: Query<&mut VisualCue, With>, -) { - if !mode.is_changed() { - return; - } - - let anchor_always_visible = mode.is_selecting_anchor(); - for mut cue in &mut anchors { - if cue.xray.always() != anchor_always_visible { - cue.xray.set_always(anchor_always_visible); - } - } -} - pub fn update_anchor_visual_cues( mut commands: Commands, mut anchors: Query< @@ -191,10 +199,11 @@ pub fn update_anchor_visual_cues( mut visibility: Query<&mut Visibility>, mut materials: Query<&mut Handle>, deps: Query<&Dependents>, - cursor: Res, + mut cursor: ResMut, site_assets: Res, interaction_assets: Res, debug_mode: Option>, + gizmo_blockers: Res, ) { for ( a, @@ -235,8 +244,10 @@ pub fn update_anchor_visual_cues( .set_support_hovered(!hovered.support_hovering.is_empty()); } - if hovered.is_hovered { - set_visibility(cursor.frame, &mut visibility, false); + if hovered.is_hovered && !gizmo_blockers.blocking() { + cursor.add_blocker(a, &mut visibility); + } else { + cursor.remove_blocker(a, &mut visibility); } if hovered.cue() && selected.cue() { @@ -303,7 +314,7 @@ pub fn update_anchor_visual_cues( } // NOTE(MXG): Currently only anchors ever have support cues, so we filter down -// to entities with AnchorVisualCues. We will need to broaden that if any other +// to entities with AnchorVisualization. We will need to broaden that if any other // visual cue types ever have a supporting role. pub fn remove_deleted_supports_from_visual_cues( mut hovered: Query<&mut Hovered, With>, diff --git a/rmf_site_editor/src/interaction/assets.rs b/rmf_site_editor/src/interaction/assets.rs index 36b29400..daf17cd5 100644 --- a/rmf_site_editor/src/interaction/assets.rs +++ b/rmf_site_editor/src/interaction/assets.rs @@ -202,11 +202,14 @@ impl InteractionAssets { commands.entity(drag_parent).with_children(|parent| { for (polyline, material) in &self.centimeter_finite_grid { - parent.spawn(PolylineBundle { - polyline: polyline.clone(), - material: material.clone(), - ..default() - }); + parent.spawn(( + PolylineBundle { + polyline: polyline.clone(), + material: material.clone(), + ..default() + }, + DisableXray, + )); } }); diff --git a/rmf_site_editor/src/interaction/camera_controls/cursor.rs b/rmf_site_editor/src/interaction/camera_controls/cursor.rs index c26f0584..da96fb0a 100644 --- a/rmf_site_editor/src/interaction/camera_controls/cursor.rs +++ b/rmf_site_editor/src/interaction/camera_controls/cursor.rs @@ -20,7 +20,7 @@ use super::{ CameraCommandType, CameraControls, ProjectionMode, MAX_FOV, MAX_SCALE, MIN_FOV, MIN_SCALE, }; use crate::interaction::SiteRaycastSet; -use bevy::input::mouse::MouseWheel; +use bevy::input::mouse::{MouseScrollUnit, MouseWheel}; use bevy::prelude::*; use bevy::window::PrimaryWindow; use bevy_mod_raycast::deferred::RaycastSource; @@ -92,15 +92,10 @@ pub fn update_cursor_command( // Scroll input let mut scroll_motion = 0.0; for ev in mouse_wheel.read() { - #[cfg(not(target_arch = "wasm32"))] - { - scroll_motion += ev.y; - } - #[cfg(target_arch = "wasm32")] - { - // scrolling in wasm is a different beast - scroll_motion += 0.4 * ev.y / ev.y.abs(); - } + scroll_motion += match ev.unit { + MouseScrollUnit::Line => ev.y, + MouseScrollUnit::Pixel => ev.y / 100.0, + }; } // Command type, return if inactive diff --git a/rmf_site_editor/src/interaction/camera_controls/keyboard.rs b/rmf_site_editor/src/interaction/camera_controls/keyboard.rs index 6dba913d..32bdacd0 100644 --- a/rmf_site_editor/src/interaction/camera_controls/keyboard.rs +++ b/rmf_site_editor/src/interaction/camera_controls/keyboard.rs @@ -187,7 +187,7 @@ pub fn update_keyboard_command( // Set camera selection as orbit center, discard once orbit operation complete let camera_selection = match keyboard_command.camera_selection { - Some(camera_selection) => camera_selection, + Some(camera_selection) => Some(camera_selection), None => get_camera_selected_point( &camera, &camera_global_transform, @@ -195,6 +195,12 @@ pub fn update_keyboard_command( immediate_raycast, ), }; + + let Some(camera_selection) = camera_selection else { + warn!("Point could not be calculated for camera"); + return; + }; + if command_type == CameraCommandType::Orbit { camera_controls.orbit_center = Some(camera_selection); } diff --git a/rmf_site_editor/src/interaction/camera_controls/utils.rs b/rmf_site_editor/src/interaction/camera_controls/utils.rs index bd0885f7..f09e8fa9 100644 --- a/rmf_site_editor/src/interaction/camera_controls/utils.rs +++ b/rmf_site_editor/src/interaction/camera_controls/utils.rs @@ -71,12 +71,11 @@ pub fn get_camera_selected_point( camera_global_transform: &GlobalTransform, user_camera_display: Res, mut immediate_raycast: Raycast, -) -> Vec3 { +) -> Option { // Assume that the camera spans the full window, covered by egui panels let available_viewport_center = user_camera_display.region.center(); - let camera_ray = camera - .viewport_to_world(camera_global_transform, available_viewport_center) - .expect("Active camera does not have a valid ray from center of its viewport"); + let camera_ray = + camera.viewport_to_world(camera_global_transform, available_viewport_center)?; let camera_ray = Ray3d::new(camera_ray.origin, *camera_ray.direction); let raycast_setting = RaycastSettings::default() .always_early_exit() @@ -86,13 +85,13 @@ pub fn get_camera_selected_point( let intersections = immediate_raycast.cast_ray(camera_ray, &raycast_setting); if intersections.len() > 0 { let (_, intersection_data) = &intersections[0]; - return intersection_data.position(); + return Some(intersection_data.position()); } else { - return get_groundplane_else_default_selection( + return Some(get_groundplane_else_default_selection( camera_ray.origin, *camera_ray.direction, *camera_ray.direction, - ); + )); } } diff --git a/rmf_site_editor/src/interaction/cursor.rs b/rmf_site_editor/src/interaction/cursor.rs index 891a7bb5..d4590134 100644 --- a/rmf_site_editor/src/interaction/cursor.rs +++ b/rmf_site_editor/src/interaction/cursor.rs @@ -21,12 +21,12 @@ use crate::{ site::{AnchorBundle, Pending, SiteAssets, Trashcan}, }; use bevy::{ecs::system::SystemParam, prelude::*, window::PrimaryWindow}; -use bevy_mod_raycast::{ - deferred::RaycastMesh, - deferred::RaycastSource, - primitives::rays::{ray_from_screenspace, to_aligned_transform}, +use bevy_mod_raycast::primitives::{ + rays::{intersects_primitive, ray_from_screenspace}, + Primitive3d, }; -use rmf_site_format::{FloorMarker, Model, ModelMarker, PrimitiveShape, WallMarker, WorkcellModel}; + +use rmf_site_format::{FloorMarker, Model, WallMarker, WorkcellModel}; use std::collections::HashSet; /// A resource that keeps track of the unique entities that play a role in @@ -97,6 +97,14 @@ impl Cursor { } } + pub fn clear_blockers(&mut self, visibility: &mut Query<&mut Visibility>) { + let had_blockers = !self.blockers.is_empty(); + self.blockers.clear(); + if had_blockers { + self.toggle_visibility(visibility); + } + } + fn toggle_visibility(&mut self, visibility: &mut Query<&mut Visibility>) { if let Ok(mut v) = visibility.get_mut(self.frame) { let new_visible = if self.should_be_visible() { @@ -110,9 +118,12 @@ impl Cursor { } } - fn remove_preview(&mut self, commands: &mut Commands) { + pub fn remove_preview(&mut self, commands: &mut Commands) { if let Some(current_preview) = self.preview_model { - commands.entity(current_preview).set_parent(self.trashcan); + commands.get_entity(current_preview).map(|mut e_mut| { + e_mut.set_parent(self.trashcan); + }); + self.preview_model = None; } } @@ -287,7 +298,23 @@ pub struct IntersectGroundPlaneParams<'w, 's> { } impl<'w, 's> IntersectGroundPlaneParams<'w, 's> { - pub fn ground_plane_intersection(&self) -> Option { + pub fn ground_plane_intersection(&self) -> Option { + let ground_plane = Primitive3d::Plane { + point: Vec3::ZERO, + normal: Vec3::Z, + }; + self.primitive_intersection(ground_plane) + } + + pub fn frame_plane_intersection(&self, frame: Entity) -> Option { + let tf = self.global_transforms.get(frame).ok()?; + let affine = tf.affine(); + let point = affine.translation.into(); + let normal = affine.matrix3.col(2).into(); + self.primitive_intersection(Primitive3d::Plane { point, normal }) + } + + pub fn primitive_intersection(&self, primitive: Primitive3d) -> Option { let window = self.primary_windows.get_single().ok()?; let cursor_position = window.cursor_position()?; let e_active_camera = self.camera_controls.active_camera(); @@ -295,145 +322,17 @@ impl<'w, 's> IntersectGroundPlaneParams<'w, 's> { let camera_tf = self.global_transforms.get(e_active_camera).ok()?; let primary_window = self.primary_window.get_single().ok()?; let ray = ray_from_screenspace(cursor_position, active_camera, camera_tf, primary_window)?; - let n_p = Vec3::Z; - let n_r = ray.direction; - let denom = n_p.dot(*n_r); - if denom.abs() < 1e-3 { - // Too close to parallel - return None; - } - - Some(ray.origin - n_r * ray.origin.dot(n_p) / denom) - } -} - -pub fn update_cursor_transform( - mode: Res, - cursor: Res, - raycast_sources: Query<&RaycastSource>, - models: Query<(), Or<(With, With)>>, - mut transforms: Query<&mut Transform>, - hovering: Res, - intersect_ground_params: IntersectGroundPlaneParams, - mut visibility: Query<&mut Visibility>, -) { - match &*mode { - InteractionMode::Inspect => { - // TODO(luca) this will not work if more than one raycast source exist - let Ok(source) = raycast_sources.get_single() else { - return; - }; - let intersection = match source.get_nearest_intersection() { - Some((_, intersection)) => intersection, - None => { - return; - } - }; - - let mut transform = match transforms.get_mut(cursor.frame) { - Ok(transform) => transform, - Err(_) => { - return; - } - }; - - let ray = Ray3d::new(intersection.position(), intersection.normal()); - *transform = Transform::from_matrix(to_aligned_transform(ray, [0., 0., 1.].into())); - } - InteractionMode::SelectAnchor(_) => { - let intersection = match intersect_ground_params.ground_plane_intersection() { - Some(intersection) => intersection, - None => { - return; - } - }; - - let mut transform = match transforms.get_mut(cursor.frame) { - Ok(transform) => transform, - Err(_) => { - return; - } - }; - - *transform = Transform::from_translation(intersection); - } - // TODO(luca) snap to features of meshes - InteractionMode::SelectAnchor3D(_mode) => { - let mut transform = match transforms.get_mut(cursor.frame) { - Ok(transform) => transform, - Err(_) => { - error!("No cursor transform found"); - return; - } - }; - - let Ok(source) = raycast_sources.get_single() else { - return; - }; - - // Check if there is an intersection to a mesh, if there isn't fallback to ground plane - if let Some((_, intersection)) = source.get_nearest_intersection() { - let Some(triangle) = intersection.triangle() else { - return; - }; - // Make sure we are hovering over a model and not anything else (i.e. anchor) - match cursor.preview_model { - None => { - if hovering.0.and_then(|e| models.get(e).ok()).is_some() { - // Find the closest triangle vertex - // TODO(luca) Also snap to edges of triangles or just disable altogether and snap - // to area, then populate a MeshConstraint component to be used by downstream - // spawning methods - // TODO(luca) there must be a better way to find a minimum given predicate in Rust - let triangle_vecs = vec![triangle[1], triangle[2]]; - let position = intersection.position(); - let mut closest_vertex = triangle[0]; - let mut closest_dist = position.distance(triangle[0].into()); - for v in triangle_vecs { - let dist = position.distance(v.into()); - if dist < closest_dist { - closest_dist = dist; - closest_vertex = v; - } - } - //closest_vertex = *triangle_vecs.iter().min_by(|position, ver| position.distance(**ver).cmp(closest_dist)).unwrap(); - let ray = Ray3d::new(closest_vertex.into(), intersection.normal()); - *transform = Transform::from_matrix(to_aligned_transform( - ray, - [0., 0., 1.].into(), - )); - set_visibility(cursor.frame, &mut visibility, true); - } else { - // Hide the cursor - set_visibility(cursor.frame, &mut visibility, false); - } - } - Some(_) => { - // If we are placing a model avoid snapping to faced and just project to - // ground plane - let intersection = match intersect_ground_params.ground_plane_intersection() - { - Some(intersection) => intersection, - None => { - return; - } - }; - set_visibility(cursor.frame, &mut visibility, true); - *transform = Transform::from_translation(intersection); - } - } - } else { - let intersection = match intersect_ground_params.ground_plane_intersection() { - Some(intersection) => intersection, - None => { - return; - } - }; - set_visibility(cursor.frame, &mut visibility, true); - *transform = Transform::from_translation(intersection); + let n = *match &primitive { + Primitive3d::Plane { normal, .. } => normal, + _ => { + warn!("Unsupported primitive type found"); + return None; } - } + }; + let p = intersects_primitive(ray, primitive).map(|intersection| intersection.position())?; + + Some(Transform::from_translation(p).with_rotation(aligned_z_axis(n))) } } @@ -475,16 +374,19 @@ pub fn update_cursor_hover_visualization( } } -// This system makes sure model previews are not picked up by raycasting -pub fn make_model_previews_not_selectable( - mut commands: Commands, - new_models: Query, Added)>, - cursor: Res, -) { - if let Some(e) = cursor.preview_model.and_then(|m| new_models.get(m).ok()) { - commands - .entity(e) - .remove::() - .remove::>(); +pub fn aligned_z_axis(z: Vec3) -> Quat { + let z_length = z.length(); + if z_length < 1e-8 { + // The given direction is too close to singular + return Quat::IDENTITY; + } + + let axis = Vec3::Z.cross(z); + let axis_length = axis.length(); + if axis_length < 1e-8 { + // The change in angle is too close to zero + return Quat::IDENTITY; } + let angle = f32::asin(axis_length / z_length); + Quat::from_axis_angle(axis / axis_length, angle) } diff --git a/rmf_site_editor/src/interaction/gizmo.rs b/rmf_site_editor/src/interaction/gizmo.rs index 56261ee8..5093b061 100644 --- a/rmf_site_editor/src/interaction/gizmo.rs +++ b/rmf_site_editor/src/interaction/gizmo.rs @@ -36,6 +36,23 @@ pub struct GizmoMaterialSet { pub drag: Handle, } +#[derive(Resource)] +pub struct GizmoBlockers { + pub selecting: bool, +} + +impl GizmoBlockers { + pub fn blocking(&self) -> bool { + self.selecting + } +} + +impl Default for GizmoBlockers { + fn default() -> Self { + Self { selecting: false } + } +} + impl GizmoMaterialSet { pub fn make_x_axis(materials: &mut Mut>) -> Self { Self { @@ -136,6 +153,7 @@ pub struct DragAxisBundle { pub gizmo: Gizmo, pub draggable: Draggable, pub axis: DragAxis, + pub selectable: Selectable, } impl DragAxisBundle { @@ -147,6 +165,10 @@ impl DragAxisBundle { along, frame: FrameOfReference::Local, }, + selectable: Selectable { + is_selectable: true, + element: for_entity, + }, } } @@ -174,6 +196,7 @@ pub struct DragPlaneBundle { pub gizmo: Gizmo, pub draggable: Draggable, pub plane: DragPlane, + pub selectable: Selectable, } impl DragPlaneBundle { @@ -185,6 +208,10 @@ impl DragPlaneBundle { in_plane, frame: FrameOfReference::Local, }, + selectable: Selectable { + is_selectable: true, + element: for_entity, + }, } } @@ -242,6 +269,7 @@ pub fn update_gizmo_click_start( &mut Handle, )>, mut selection_blocker: ResMut, + gizmo_blocker: Res, mut visibility: Query<&mut Visibility>, mouse_button_input: Res>, transforms: Query<(&Transform, &GlobalTransform)>, @@ -252,6 +280,16 @@ pub fn update_gizmo_click_start( mut click: EventWriter, mut removed_gizmos: RemovedComponents, ) { + if gizmo_blocker.blocking() { + if gizmo_blocker.is_changed() { + // This has started being blocked since the last cycle + cursor.clear_blockers(&mut visibility); + } + + // Don't start any gizmos + return; + } + for e in removed_gizmos.read() { cursor.remove_blocker(e, &mut visibility); } @@ -327,12 +365,14 @@ pub fn update_gizmo_click_start( pub fn update_gizmo_release( mut draggables: Query<(&Gizmo, &mut Draggable, &mut Handle)>, mut selection_blockers: ResMut, + gizmo_blockers: Res, mut gizmo_state: ResMut, mouse_button_input: Res>, - picked: Res, - mut change_pick: EventWriter, + mut picked: ResMut, ) { - if mouse_button_input.just_released(MouseButton::Left) { + let mouse_released = mouse_button_input.just_released(MouseButton::Left); + let gizmos_blocked = gizmo_blockers.blocking(); + if mouse_released || gizmos_blocked { if let GizmoState::Dragging(e) = *gizmo_state { if let Ok((gizmo, mut draggable, mut material)) = draggables.get_mut(e) { draggable.drag = None; @@ -348,10 +388,7 @@ pub fn update_gizmo_release( // to move the cursor off of whatever object it happens to be // hovering over after the drag is finished before interactions like // selecting or dragging can resume. - change_pick.send(ChangePick { - from: None, - to: picked.0, - }); + picked.refresh = true; } } } diff --git a/rmf_site_editor/src/interaction/lift.rs b/rmf_site_editor/src/interaction/lift.rs index efbf9457..0262ccc9 100644 --- a/rmf_site_editor/src/interaction/lift.rs +++ b/rmf_site_editor/src/interaction/lift.rs @@ -57,7 +57,7 @@ pub fn handle_lift_doormat_clicks( for click in clicks.read() { if let Ok(doormat) = doormats.get(click.0) { toggle.send(doormat.toggle_availability()); - select.send(Select(Some(doormat.for_lift))); + select.send(Select::new(Some(doormat.for_lift))); } } } diff --git a/rmf_site_editor/src/interaction/light.rs b/rmf_site_editor/src/interaction/light.rs index 0caf3fc1..3fa79985 100644 --- a/rmf_site_editor/src/interaction/light.rs +++ b/rmf_site_editor/src/interaction/light.rs @@ -16,7 +16,7 @@ */ use crate::{ - interaction::{DragPlaneBundle, HeadlightToggle, InteractionAssets, Selectable}, + interaction::{DragPlaneBundle, HeadlightToggle, InteractionAssets}, site::LightKind, }; use bevy::prelude::*; @@ -94,7 +94,6 @@ pub fn add_physical_light_visual_cues( material: assets.physical_light_cover_material.clone(), ..default() }) - .insert(Selectable::new(e)) .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); point @@ -103,7 +102,6 @@ pub fn add_physical_light_visual_cues( material: light_material.clone(), ..default() }) - .insert(Selectable::new(e)) .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); }) .id(); @@ -123,7 +121,6 @@ pub fn add_physical_light_visual_cues( material: assets.physical_light_cover_material.clone(), ..default() }) - .insert(Selectable::new(e)) .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); spot.spawn(PbrBundle { @@ -131,7 +128,6 @@ pub fn add_physical_light_visual_cues( material: light_material.clone(), ..default() }) - .insert(Selectable::new(e)) .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); }) .id(); @@ -151,7 +147,6 @@ pub fn add_physical_light_visual_cues( material: assets.direction_light_cover_material.clone(), ..default() }) - .insert(Selectable::new(e)) .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); dir.spawn(PbrBundle { @@ -159,7 +154,6 @@ pub fn add_physical_light_visual_cues( material: light_material.clone(), ..default() }) - .insert(Selectable::new(e)) .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); }) .id(); diff --git a/rmf_site_editor/src/interaction/mod.rs b/rmf_site_editor/src/interaction/mod.rs index bc7b6a1f..a977f693 100644 --- a/rmf_site_editor/src/interaction/mod.rs +++ b/rmf_site_editor/src/interaction/mod.rs @@ -55,9 +55,6 @@ pub use lift::*; pub mod light; pub use light::*; -pub mod mode; -pub use mode::*; - pub mod model_preview; pub use model_preview::*; @@ -82,9 +79,6 @@ pub use preview::*; pub mod select; pub use select::*; -pub mod select_anchor; -pub use select_anchor::*; - pub mod visual_cue; pub use visual_cue::*; @@ -134,8 +128,9 @@ pub enum InteractionUpdateSet { impl Plugin for InteractionPlugin { fn build(&self, app: &mut App) { app.init_state::() + .init_resource::() .configure_sets( - Update, + PostUpdate, ( SiteUpdateSet::AssignOrphansFlush, InteractionUpdateSet::AddVisuals, @@ -155,17 +150,10 @@ impl Plugin for InteractionPlugin { .init_resource::() .init_resource::() .init_resource::() - .init_resource::() - .init_resource::() - .init_resource::() .init_resource::() - .init_resource::() - .init_resource::() + .insert_resource(HighlightAnchors(false)) .add_event::() - .add_event::() + .add_event::() + .add_event::() + .add_systems( + Update, + ( + (apply_deferred, flush_impulses()) + .chain() + .in_set(SelectionServiceStages::PickFlush), + (apply_deferred, flush_impulses()) + .chain() + .in_set(SelectionServiceStages::HoverFlush), + (apply_deferred, flush_impulses()) + .chain() + .in_set(SelectionServiceStages::SelectFlush), + ), + ) + .add_plugins(( + InspectorServicePlugin::default(), + AnchorSelectionPlugin::default(), + ObjectPlacementPlugin::default(), + )); + + let inspector_service = app.world.resource::().inspector_service; + let new_selector_service = app.spawn_event_streaming_service::(Update); + let selection_workflow = app.world.spawn_io_workflow(build_selection_workflow( + inspector_service, + new_selector_service, + )); + + // Get the selection workflow running + app.world.command(|commands| { + commands.request((), selection_workflow).detach(); + }); + } +} + +/// This builder function creates the high-level workflow that manages "selection" +/// behavior, which is largely driven by mouse interactions. "Selection" behaviors +/// determine how the application responds to the mouse cursor hovering over +/// objects in the scene and what happens when the mouse is clicked. +/// +/// The default selection behavior is the "inspector" service which allows the +/// user to select objects in the scene so that their properties get displayed +/// in the inspector panel. The inspector service will automatically be run by +/// this workflow at startup. +/// +/// When the user asks for some other type of mouse interaction to begin, such as +/// drawing walls and floors, or placing models in the scene, this workflow will +/// "trim" (stop) the inspector workflow and inject the new requested interaction +/// mode into the workflow. The requested interaction mode is represented by a +/// service specified by the `selector` field of [`RunSelector`]. When that +/// service terminates, this workflow will resume running the inspector service +/// until the user requests some other mouse interaction service to run. +/// +/// In most cases downstream users will not need to call this function since the +/// [`SelectionPlugin`] will use this to build and run the default selection +/// workflow. If you are not using the [`SelectionPlugin`] that we provide and +/// want to customize the inspector service, then you could use this to build a +/// customized selection workflow by passingin a custom inspector service. +pub fn build_selection_workflow( + inspector_service: Service<(), ()>, + new_selector_service: Service<(), (), StreamOf>, +) -> impl FnOnce(Scope<(), ()>, &mut Builder) -> DeliverySettings { + move |scope, builder| { + // This creates a service that will listen to run_service_buffer. + // The job of this service is to atomically pull the most recent item + // out of the buffer and also close the buffer gate to ensure that we + // never have multiple selector services racing to be injected. If we + // don't bother to close the gate after pulling exactly one selection + // service, then it's theoretically possible for multiple selection + // services to get simultaneously injected after the trim operation + // finishes. + let process_new_selector_service = builder + .commands() + .spawn_service(process_new_selector.into_blocking_service()); + + // The run_service_buffer queues up the most recent RunSelector request + // sent in by the user. That request will be held in this buffer while + // we wait for any ongoing mouse interaction services to cleanly exit + // after we trigger the trim operation. + let run_service_buffer = builder.create_buffer::(BufferSettings::keep_last(1)); + let input = scope.input.fork_clone(builder); + // Run the default inspector service + let inspector = input.clone_chain(builder).then_node(inspector_service); + + // Create a node that reads RunSelector events from the world and streams + // them into the workflow. + let new_selector_node = input.clone_chain(builder).then_node(new_selector_service); + builder.connect(new_selector_node.output, scope.terminate); + new_selector_node + .streams + .chain(builder) + .inner() + .connect(run_service_buffer.input_slot()); + + let open_gate = builder.create_gate_open(run_service_buffer); + // Create an operation that trims the gate opening operation, the injected + // selector service, and the default inspector service. + let trim = builder.create_trim([TrimBranch::between(open_gate.input, inspector.input)]); + builder.connect(trim.output, open_gate.input); + + // Create a sequence where we listen for updates in the run service buffer, + // then pull an item out of the buffer (if available), then begin the + // trim of all ongoing selection services, then opening the gate of the + // buffer to allow new selection services to be started. + builder + .listen(run_service_buffer) + .then(process_new_selector_service) + .dispose_on_none() + .connect(trim.input); + + // After we open the gate it is safe to inject the user-requested selecion + // service. Once that service finishes, we will trigger the inspector to + // resume. + open_gate + .output + .chain(builder) + .map_block(|r: RunSelector| (r.input, r.selector)) + .then_injection() + .trigger() + .connect(inspector.input); + + // This workflow only makes sense to run in serial. + DeliverySettings::Serial + } +} + +fn process_new_selector( + In(key): In>, + mut access: BufferAccessMut, +) -> Option { + let Ok(mut buffer) = access.get_mut(&key) else { + return None; + }; + + let output = buffer.pull(); + if output.is_some() { + // We should lock the gate while the trim is going on so we can't have + // multiple new selectors trying to start at the same time + buffer.close_gate(); + } + + output +} + +#[derive(Debug, Clone, Copy, Event)] +pub struct RunSelector { + /// The select workflow will run this service until it terminates and then + /// revert back to the inspector selector. + selector: Service, ()>, + /// If there is input for the selector, it will be stored in a [`SelectorInput`] + /// component in this entity. The entity will be despawned as soon as the + /// input is extracted. + input: Option, +} + +#[derive(Component)] +pub struct SelectorInput(T); /// This component is put on entities with meshes to mark them as items that can /// be interacted with to @@ -97,11 +326,46 @@ pub struct Selection(pub Option); pub struct Hovering(pub Option); /// Used as an event to command a change in the selected entity. -#[derive(Default, Debug, Clone, Copy, Deref, DerefMut, Event)] -pub struct Select(pub Option); +#[derive(Default, Debug, Clone, Copy, Deref, DerefMut, Event, Stream)] +pub struct Select(pub Option); + +impl Select { + pub fn new(candidate: Option) -> Select { + Select(candidate.map(|c| SelectionCandidate::new(c))) + } + + pub fn provisional(candidate: Entity) -> Select { + Select(Some(SelectionCandidate::provisional(candidate))) + } +} + +#[derive(Debug, Clone, Copy)] +pub struct SelectionCandidate { + /// The entity that's being requested as a selection + pub candidate: Entity, + /// The entity was created specifically to be selected, so if it ends up + /// going unused by the workflow then it should be despawned. + pub provisional: bool, +} + +impl SelectionCandidate { + pub fn new(candidate: Entity) -> SelectionCandidate { + SelectionCandidate { + candidate, + provisional: false, + } + } + + pub fn provisional(candidate: Entity) -> SelectionCandidate { + SelectionCandidate { + candidate, + provisional: true, + } + } +} /// Used as an event to command a change in the hovered entity. -#[derive(Default, Debug, Clone, Copy, Deref, DerefMut, Event)] +#[derive(Default, Debug, Clone, Copy, Deref, DerefMut, Event, Stream)] pub struct Hover(pub Option); /// A resource to track what kind of blockers are preventing the selection @@ -110,22 +374,17 @@ pub struct Hover(pub Option); pub struct SelectionBlockers { /// An entity is being dragged pub dragging: bool, - /// An entity is being placed - pub placing: bool, } impl SelectionBlockers { pub fn blocking(&self) -> bool { - self.dragging || self.placing + self.dragging } } impl Default for SelectionBlockers { fn default() -> Self { - SelectionBlockers { - dragging: false, - placing: false, - } + SelectionBlockers { dragging: false } } } @@ -155,75 +414,372 @@ pub fn make_selectable_entities_pickable( } } -pub fn handle_selection_picking( - blockers: Option>, - mode: Res, - selectables: Query<&Selectable>, - anchors: Query<(), With>, +/// This allows an [`App`] to spawn a service that can stream Hover and +/// Select events that are managed by a filter. This can only be used with +/// [`App`] because some of the internal services are continuous, so they need +/// to be added to the schedule. +pub trait SpawnSelectionServiceExt { + fn spawn_selection_service( + &mut self, + ) -> Service<(), (), (Hover, Select)> + where + for<'w, 's> F::Item<'w, 's>: SelectionFilter; +} + +impl SpawnSelectionServiceExt for App { + fn spawn_selection_service( + &mut self, + ) -> Service<(), (), (Hover, Select)> + where + for<'w, 's> F::Item<'w, 's>: SelectionFilter, + { + let picking_service = self.spawn_continuous_service( + Update, + picking_service:: + .configure(|config: SystemConfigs| config.in_set(SelectionServiceStages::Pick)), + ); + + let hover_service = self.spawn_continuous_service( + Update, + hover_service:: + .configure(|config: SystemConfigs| config.in_set(SelectionServiceStages::Hover)), + ); + + let select_service = self.spawn_continuous_service( + Update, + select_service:: + .configure(|config: SystemConfigs| config.in_set(SelectionServiceStages::Select)), + ); + + self.world + .spawn_workflow::<_, _, (Hover, Select), _>(|scope, builder| { + let hover = builder.create_node(hover_service); + builder.connect(hover.streams, scope.streams.0); + builder.connect(hover.output, scope.terminate); + + let select = builder.create_node(select_service); + builder.connect(select.streams, scope.streams.1); + builder.connect(select.output, scope.terminate); + + // Activate all the services at the start + scope.input.chain(builder).fork_clone(( + |chain: Chain<_>| { + chain + .then(refresh_picked.into_blocking_callback()) + .then(picking_service) + .connect(scope.terminate) + }, + |chain: Chain<_>| chain.connect(hover.input), + |chain: Chain<_>| chain.connect(select.input), + )); + + // This is just a dummy buffer to let us have a cleanup workflow + let buffer = builder.create_buffer::<()>(BufferSettings::keep_all()); + builder.on_cleanup(buffer, |scope, builder| { + scope + .input + .chain(builder) + .trigger() + .then(clear_hover_select.into_blocking_callback()) + .connect(scope.terminate); + }); + }) + } +} + +// TODO(@mxgrey): Remove flush stages when we move to bevy 0.13 which can infer +// when to flush +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] +pub enum SelectionServiceStages { + Pick, + PickFlush, + Hover, + HoverFlush, + Select, + SelectFlush, +} + +#[derive(Resource)] +pub struct InspectorService { + /// Workflow that updates the [`Selection`] as well as [`Hovered`] and + /// [`Selected`] states in the application. + pub inspector_service: Service<(), ()>, + /// Workflow that outputs hover and select streams that are compatible with + /// a general inspector. This service never terminates. + pub inspector_select_service: Service<(), (), (Hover, Select)>, + pub inspector_cursor_transform: Service<(), ()>, + pub selection_update: Service, +} + +#[derive(Default)] +pub struct InspectorServicePlugin {} + +impl Plugin for InspectorServicePlugin { + fn build(&self, app: &mut App) { + let inspector_select_service = app.spawn_selection_service::(); + let inspector_cursor_transform = app.spawn_continuous_service( + Update, + inspector_cursor_transform + .configure(|config: SystemConfigs| config.in_set(SelectionServiceStages::Pick)), + ); + let selection_update = app.spawn_service(selection_update); + let keyboard_just_pressed = app + .world + .resource::() + .keyboard_just_pressed; + + let inspector_service = app.world.spawn_workflow(|scope, builder| { + let fork_input = scope.input.fork_clone(builder); + fork_input + .clone_chain(builder) + .then(inspector_cursor_transform) + .unused(); + fork_input + .clone_chain(builder) + .then_node(keyboard_just_pressed) + .streams + .chain(builder) + .inner() + .then(deselect_on_esc.into_blocking_callback()) + .unused(); + let selection = fork_input + .clone_chain(builder) + .then_node(inspector_select_service); + selection + .streams + .1 + .chain(builder) + .then(selection_update) + .unused(); + builder.connect(selection.output, scope.terminate); + }); + + app.world.insert_resource(InspectorService { + inspector_service, + inspector_select_service, + inspector_cursor_transform, + selection_update, + }); + } +} + +pub fn deselect_on_esc(In(code): In, mut select: EventWriter; +} + +#[derive(SystemParam)] +pub struct InspectorFilter<'w, 's> { + selectables: Query<'w, 's, &'static Selectable, (Without, Without)>, +} + +impl<'w, 's> SelectionFilter for InspectorFilter<'w, 's> { + fn filter_pick(&mut self, select: Entity) -> Option { + self.selectables + .get(select) + .ok() + .map(|selectable| selectable.element) + } + fn filter_select(&mut self, target: Entity) -> Option { + Some(target) + } + fn on_click(&mut self, hovered: Hover) -> Option, - mode: Res, blockers: Option>, -) { + filter: StaticSystemParam, + selection_blockers: Res, +) where + for<'w, 's> Filter::Item<'w, 's>: SelectionFilter, +{ + let Some(mut orders) = orders.get_mut(&key) else { + return; + }; + + if orders.is_empty() { + // Nothing is asking for this service to run + return; + } + + if selection_blockers.blocking() { + return; + } + + let mut filter = filter.into_inner(); + if let Some(new_hovered) = hover.read().last() { - if hovering.0 != new_hovered.0 { + let new_hovered = new_hovered.0.and_then(|e| filter.filter_select(e)); + if hovering.0 != new_hovered { if let Some(previous_hovered) = hovering.0 { if let Ok(mut hovering) = hovered.get_mut(previous_hovered) { hovering.is_hovered = false; } } - if let Some(new_hovered) = new_hovered.0 { + if let Some(new_hovered) = new_hovered { if let Ok(mut hovering) = hovered.get_mut(new_hovered) { hovering.is_hovered = true; } } - hovering.0 = new_hovered.0; + hovering.0 = new_hovered; + orders.for_each(|order| order.streams().send(Hover(new_hovered))); } } @@ -232,46 +788,148 @@ pub fn maintain_hovered_entities( let blocked = blockers.filter(|x| x.blocking()).is_some(); if clicked && !blocked { - if let Some(current_hovered) = hovering.0 { - // TODO(luca) refactor to remove this hack - // Skip if we are in SelectAnchor3D mode - if let InteractionMode::SelectAnchor3D(_) = &*mode { - return; - } - select.send(Select(Some(current_hovered))); + if let Some(new_select) = filter.on_click(Hover(hovering.0)) { + select.send(new_select); } } } -pub fn maintain_selected_entities( - mode: Res, - mut selected: Query<&mut Selected>, - mut selection: ResMut, +/// A continuous service that filters [`Select`] events and issues out a +/// [`Hover`] stream. +/// +/// This complements [`hover_service`] and [`hover_picking`] +/// and is the final piece of the [`SelectionService`] workflow. +pub fn select_service( + In(ContinuousService { key }): ContinuousServiceInput<(), (), Select>, + mut orders: ContinuousQuery<(), (), Select>, mut select: EventReader, + mut selected: Query<&mut Selected>, + mut selection: ResMut, +) { + if selection.0 != new_selection.map(|s| s.candidate) { + if let Some(previous_selection) = selection.0 { + if let Ok(mut selected) = selected.get_mut(previous_selection) { + selected.is_selected = false; } + } - selection.0 = new_selection.0; + if let Some(new_selection) = new_selection { + if let Ok(mut selected) = selected.get_mut(new_selection.candidate) { + selected.is_selected = true; + } } + + selection.0 = new_selection.map(|s| s.candidate); } } + +/// This is used to clear out the currently picked item at the start of a new +/// selection workflow to make sure the Hover events don't get lost during the +/// workflow switch. +pub fn refresh_picked(In(_): In<()>, mut picked: ResMut) { + picked.refresh = true; +} + +/// This is used to clear out hoverings and selections from a workflow that is +/// cleaning up so that these properties don't spill over into other workflows. +pub fn clear_hover_select( + In(_): In<()>, + mut hovered: Query<&mut Hovered>, + mut hovering: ResMut, + mut selected: Query<&mut Selected>, + mut selection: ResMut, +) { + if let Some(previous_hovering) = hovering.0.take() { + if let Ok(mut hovered) = hovered.get_mut(previous_hovering) { + hovered.is_hovered = false; + } + } + + if let Some(previous_selection) = selection.0.take() { + if let Ok(mut selected) = selected.get_mut(previous_selection) { + selected.is_selected = false; + } + } +} + +/// Update the virtual cursor (dagger and circle) transform while in inspector mode +pub fn inspector_cursor_transform( + In(ContinuousService { key }): ContinuousServiceInput<(), ()>, + orders: ContinuousQuery<(), ()>, + cursor: Res, + raycast_sources: Query<&RaycastSource>, + mut transforms: Query<&mut Transform>, +) { + let Some(orders) = orders.view(&key) else { + return; + }; + + if orders.is_empty() { + return; + } + + let Ok(source) = raycast_sources.get_single() else { + return; + }; + let intersection = match source.get_nearest_intersection() { + Some((_, intersection)) => intersection, + None => { + return; + } + }; + + let mut transform = match transforms.get_mut(cursor.frame) { + Ok(transform) => transform, + Err(_) => { + return; + } + }; + + let ray = Ray3d::new(intersection.position(), intersection.normal()); + *transform = Transform::from_matrix(to_aligned_transform(ray, [0., 0., 1.].into())); +} diff --git a/rmf_site_editor/src/interaction/select/create_edges.rs b/rmf_site_editor/src/interaction/select/create_edges.rs new file mode 100644 index 00000000..aa75a250 --- /dev/null +++ b/rmf_site_editor/src/interaction/select/create_edges.rs @@ -0,0 +1,405 @@ +/* + * Copyright (C) 2024 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +use crate::{ + interaction::*, + site::{ChangeDependent, Pending, TextureNeedsAssignment}, +}; +use bevy::prelude::*; +use bevy_impulse::*; +use rmf_site_format::{Edge, Side}; +use std::borrow::Borrow; + +pub fn spawn_create_edges_service( + helpers: &AnchorSelectionHelpers, + app: &mut App, +) -> Service, ()> { + let anchor_setup = + app.spawn_service(anchor_selection_setup::.into_blocking_service()); + let state_setup = app.spawn_service(create_edges_setup.into_blocking_service()); + let update_preview = app.spawn_service(on_hover_for_create_edges.into_blocking_service()); + let update_current = app.spawn_service(on_select_for_create_edges.into_blocking_service()); + let handle_key_code = app.spawn_service(on_keyboard_for_create_edges.into_blocking_service()); + let cleanup_state = app.spawn_service(cleanup_create_edges.into_blocking_service()); + + helpers.spawn_anchor_selection_workflow( + anchor_setup, + state_setup, + update_preview, + update_current, + handle_key_code, + cleanup_state, + &mut app.world, + ) +} + +pub struct CreateEdges { + pub spawn_edge: fn(Edge, &mut Commands) -> Entity, + pub preview_edge: Option, + pub continuity: EdgeContinuity, + pub scope: AnchorScope, +} + +impl CreateEdges { + pub fn new>>( + continuity: EdgeContinuity, + scope: AnchorScope, + ) -> Self { + Self { + spawn_edge: create_edge::, + preview_edge: None, + continuity, + scope, + } + } + + pub fn new_with_texture>>( + continuity: EdgeContinuity, + scope: AnchorScope, + ) -> Self { + Self { + spawn_edge: create_edge_with_texture::, + preview_edge: None, + continuity, + scope, + } + } + + pub fn initialize_preview(&mut self, anchor: Entity, commands: &mut Commands) { + let edge = Edge::new(anchor, anchor); + let edge = (self.spawn_edge)(edge, commands); + self.preview_edge = Some(PreviewEdge { + edge, + side: Side::start(), + provisional_start: false, + }); + + commands.add(ChangeDependent::add(anchor, edge)); + } +} + +impl Borrow for CreateEdges { + fn borrow(&self) -> &AnchorScope { + &self.scope + } +} + +fn create_edge>>( + edge: Edge, + commands: &mut Commands, +) -> Entity { + let new_bundle: T = edge.into(); + commands.spawn((new_bundle, Pending)).id() +} + +fn create_edge_with_texture>>( + edge: Edge, + commands: &mut Commands, +) -> Entity { + let new_bundle: T = edge.into(); + commands + .spawn((new_bundle, TextureNeedsAssignment, Pending)) + .id() +} + +#[derive(Clone, Copy)] +pub struct PreviewEdge { + pub edge: Entity, + pub side: Side, + /// True if the start anchor of the edge was created specifically to build + /// this edge. If this true, we will despawn the anchor during cleanup if + /// the edge does not get completed. + pub provisional_start: bool, +} + +impl PreviewEdge { + pub fn cleanup( + &self, + edges: &Query<&'static Edge>, + commands: &mut Commands, + ) -> SelectionNodeResult { + let edge = edges.get(self.edge).or_broken_query()?; + for anchor in edge.array() { + commands.add(ChangeDependent::remove(anchor, self.edge)); + } + + if self.provisional_start { + // The start anchor was created specifically for this preview edge + // which we are about to despawn. Let's despawn both so we aren't + // littering the scene with unintended anchors. + commands + .get_entity(edge.start()) + .or_broken_query()? + .despawn_recursive(); + } + + commands + .get_entity(self.edge) + .or_broken_query()? + .despawn_recursive(); + Ok(()) + } +} + +pub enum EdgeContinuity { + /// Create just a single edge + Single, + /// Create a sequence of separate edges + Separate, + /// Create edges continuously, i.e. the beginning of the next edge will + /// automatically be the end of the previous edge. + Continuous, +} + +pub fn create_edges_setup( + In(key): In>, + mut access: BufferAccessMut, + cursor: Res, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + + if state.preview_edge.is_none() { + state.initialize_preview(cursor.level_anchor_placement, &mut commands); + } + Ok(()) +} + +pub fn on_hover_for_create_edges( + In((hover, key)): In<(Hover, BufferKey)>, + mut access: BufferAccessMut, + mut cursor: ResMut, + mut visibility: Query<&mut Visibility>, + mut edges: Query<&mut Edge>, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + + // TODO(@mxgrey): Consider moving this logic into AnchorFilter since it gets + // used by all the different anchor selection modes. + let anchor = match hover.0 { + Some(anchor) => { + cursor.remove_mode(SELECT_ANCHOR_MODE_LABEL, &mut visibility); + anchor + } + None => { + cursor.add_mode(SELECT_ANCHOR_MODE_LABEL, &mut visibility); + cursor.level_anchor_placement + } + }; + + if let Some(preview) = &mut state.preview_edge { + // If we already have an active preview, then use the new anchor for the + // side that we currently need to select for. + let index = preview.side.index(); + let mut edge = edges.get_mut(preview.edge).or_broken_query()?; + + let old_anchor = edge.array()[index]; + if old_anchor != anchor { + let opposite_anchor = edge.array()[preview.side.opposite().index()]; + if opposite_anchor != old_anchor { + commands.add(ChangeDependent::remove(old_anchor, preview.edge)); + } + + edge.array_mut()[index] = anchor; + commands.add(ChangeDependent::add(anchor, preview.edge)); + } + } else { + // There is currently no active preview, so we need to create one. + let edge = Edge::new(anchor, anchor); + let edge = (state.spawn_edge)(edge, &mut commands); + state.preview_edge = Some(PreviewEdge { + edge, + side: Side::start(), + provisional_start: false, + }); + commands.add(ChangeDependent::add(anchor, edge)); + } + + Ok(()) +} + +pub fn on_select_for_create_edges( + In((selection, key)): In<(SelectionCandidate, BufferKey)>, + mut access: BufferAccessMut, + mut edges: Query<&mut Edge>, + mut commands: Commands, + cursor: Res, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + + let anchor = selection.candidate; + if let Some(preview) = &mut state.preview_edge { + match preview.side { + Side::Left => { + // We are pinning down the first anchor of the edge + let mut edge = edges.get_mut(preview.edge).or_broken_query()?; + commands.add(ChangeDependent::remove(edge.left(), preview.edge)); + *edge.left_mut() = anchor; + commands.add(ChangeDependent::add(anchor, preview.edge)); + + if edge.right() != anchor { + commands.add(ChangeDependent::remove(edge.right(), preview.edge)); + } + + *edge.right_mut() = cursor.level_anchor_placement; + commands.add(ChangeDependent::add( + cursor.level_anchor_placement, + preview.edge, + )); + + preview.side = Side::Right; + preview.provisional_start = selection.provisional; + } + Side::Right => { + // We are finishing the edge + let mut edge = edges.get_mut(preview.edge).or_broken_query()?; + if edge.left() == anchor { + // The user is trying to use the same point for the start + // and end of an edge. Issue a warning and exit early. + warn!( + "You are trying to select an anchor {:?} for both the \ + start and end points of an edge, which is not allowed.", + anchor, + ); + return Ok(()); + } + *edge.right_mut() = anchor; + commands.add(ChangeDependent::add(anchor, preview.edge)); + commands + .get_entity(preview.edge) + .or_broken_query()? + .remove::(); + + match state.continuity { + EdgeContinuity::Single => { + state.preview_edge = None; + // This simply means we are terminating the workflow now + // because we have finished drawing the single edge + return Err(None); + } + EdgeContinuity::Separate => { + // Start drawing a new edge from a blank slate with the + // next selection + state.initialize_preview(cursor.level_anchor_placement, &mut commands); + } + EdgeContinuity::Continuous => { + // Start drawing a new edge, picking up from the end + // point of the previous edge + let edge = Edge::new(anchor, cursor.level_anchor_placement); + let edge = (state.spawn_edge)(edge, &mut commands); + state.preview_edge = Some(PreviewEdge { + edge, + side: Side::end(), + provisional_start: false, + }); + commands.add(ChangeDependent::add(anchor, edge)); + commands.add(ChangeDependent::add(cursor.level_anchor_placement, edge)); + } + } + } + } + } else { + // We have no preview at all yet somehow, so we'll need to create a + // fresh new edge to insert the selected anchor into + let edge = Edge::new(anchor, anchor); + let edge = (state.spawn_edge)(edge, &mut commands); + state.preview_edge = Some(PreviewEdge { + edge, + side: Side::start(), + provisional_start: selection.provisional, + }); + } + + Ok(()) +} + +pub fn on_keyboard_for_create_edges( + In((button, key)): In<(KeyCode, BufferKey)>, + mut access: BufferAccessMut, + mut edges: Query<&'static mut Edge>, + cursor: Res, + mut commands: Commands, +) -> SelectionNodeResult { + if !matches!(button, KeyCode::Escape) { + // The button was not the escape key, so there's nothing for us to do + // here. + return Ok(()); + } + + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + + if let Some(preview) = &mut state.preview_edge { + if preview.side == Side::end() { + // We currently have an active preview edge and are selecting for + // the second point in the edge. Esc means we should back out of the + // current edge without exiting the edge creation workflow so the + // user can choose a different start point. + let mut edge = edges.get_mut(preview.edge).or_broken_query()?; + for anchor in edge.array() { + commands.add(ChangeDependent::remove(anchor, preview.edge)); + } + if preview.provisional_start { + commands + .get_entity(edge.start()) + .or_broken_query()? + .despawn_recursive(); + } + + *edge.left_mut() = cursor.level_anchor_placement; + *edge.right_mut() = cursor.level_anchor_placement; + preview.side = Side::start(); + preview.provisional_start = false; + commands.add(ChangeDependent::add( + cursor.level_anchor_placement, + preview.edge, + )); + } else { + // We are selecting for the first point in the edge. If the user has + // pressed Esc then that means they want to stop creating edges + // altogether. Return Err(None) to indicate that the workflow should + // exit cleaning. + return Err(None); + } + } else { + // We currently have no preview active at all. If the user hits Esc then + // they want to exit the workflow altogether. + return Err(None); + } + + Ok(()) +} + +pub fn cleanup_create_edges( + In(key): In>, + mut access: BufferAccessMut, + edges: Query<&'static Edge>, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.pull().or_broken_state()?; + + if let Some(preview) = state.preview_edge { + // We created a preview, so we should despawn it while cleaning up + preview.cleanup(&edges, &mut commands)?; + } + Ok(()) +} diff --git a/rmf_site_editor/src/interaction/select/create_path.rs b/rmf_site_editor/src/interaction/select/create_path.rs new file mode 100644 index 00000000..3df425f2 --- /dev/null +++ b/rmf_site_editor/src/interaction/select/create_path.rs @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2024 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +use crate::{ + interaction::*, + site::{ChangeDependent, Pending, TextureNeedsAssignment}, +}; +use bevy::prelude::*; +use bevy_impulse::*; +use rmf_site_format::Path; +use std::borrow::Borrow; + +use std::collections::HashSet; + +pub fn spawn_create_path_service( + helpers: &AnchorSelectionHelpers, + app: &mut App, +) -> Service, ()> { + let anchor_setup = + app.spawn_service(anchor_selection_setup::.into_blocking_service()); + let state_setup = app.spawn_service(create_path_setup.into_blocking_service()); + let update_preview = app.spawn_service(on_hover_for_create_path.into_blocking_service()); + let update_current = app.spawn_service(on_select_for_create_path.into_blocking_service()); + let handle_key_code = app.spawn_service(exit_on_esc::.into_blocking_service()); + let cleanup_state = app.spawn_service(cleanup_create_path.into_blocking_service()); + + helpers.spawn_anchor_selection_workflow( + anchor_setup, + state_setup, + update_preview, + update_current, + handle_key_code, + cleanup_state, + &mut app.world, + ) +} + +pub struct CreatePath { + /// Function pointer for spawning an initial path. + pub spawn_path: fn(Path, &mut Commands) -> Entity, + /// The path which is being built. This will initially be [`None`] until setup + /// happens, then `spawn_path` will be used to create this. For all the + /// services in the `create_path` workflow besides setup, this should + /// contain [`Some`]. + /// + /// If points are being added to an existing path, this could be initialized + /// as [`Some`] before the state is passed into the workflow. + pub path: Option, + /// A minimum for how many points need to be selected for the path to be + /// considered valid. Use 0 if there is no minimum. + pub minimum_points: usize, + /// Whether the path is allowed to have an inner loop. E.g. + /// `A -> B -> C -> D -> B` would be an inner loop. + pub allow_inner_loops: bool, + /// The path is implied to always be a complete loop. This has two consequences: + /// 1. If the first point gets re-selected later in the path then we automatically + /// consider the path to be finished. + /// 2. When (1) occurs, the first point does not get re-added to the path. + pub implied_complete_loop: bool, + /// A list of all anchors being used in the path which are provisional, + /// meaning they should be despawned if the path creation ends before + /// reaching the minimum number of points. + pub provisional_anchors: HashSet, + pub scope: AnchorScope, +} + +impl CreatePath { + pub fn new( + spawn_path: fn(Path, &mut Commands) -> Entity, + minimum_points: usize, + allow_inner_loops: bool, + implied_complete_loop: bool, + scope: AnchorScope, + ) -> Self { + Self { + spawn_path, + path: None, + allow_inner_loops, + minimum_points, + implied_complete_loop, + scope, + provisional_anchors: Default::default(), + } + } + + pub fn set_last( + &self, + chosen: Entity, + path_mut: &mut Path, + commands: &mut Commands, + ) -> SelectionNodeResult { + let path = self.path.or_broken_state()?; + let last = path_mut.0.last_mut().or_broken_state()?; + if chosen == *last { + // Nothing to change + return Ok(()); + } + + let previous = *last; + *last = chosen; + if !path_mut.0.contains(&previous) { + commands.add(ChangeDependent::remove(previous, path)); + } + + commands.add(ChangeDependent::add(chosen, path)); + Ok(()) + } +} + +impl Borrow for CreatePath { + fn borrow(&self) -> &AnchorScope { + &self.scope + } +} + +pub fn create_path_with_texture>>( + path: Path, + commands: &mut Commands, +) -> Entity { + let new_bundle: T = path.into(); + commands + .spawn((new_bundle, TextureNeedsAssignment, Pending)) + .id() +} + +pub fn create_path_setup( + In(key): In>, + mut access: BufferAccessMut, + cursor: Res, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + + if state.path.is_none() { + let path = Path(vec![cursor.level_anchor_placement]); + let path = (state.spawn_path)(path, &mut commands); + commands.add(ChangeDependent::add(cursor.level_anchor_placement, path)); + state.path = Some(path); + } + + Ok(()) +} + +pub fn on_hover_for_create_path( + In((hover, key)): In<(Hover, BufferKey)>, + mut access: BufferAccessMut, + mut cursor: ResMut, + mut visibility: Query<&mut Visibility>, + mut paths: Query<&mut Path>, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + + let chosen = match hover.0 { + Some(anchor) => { + cursor.remove_mode(SELECT_ANCHOR_MODE_LABEL, &mut visibility); + anchor + } + None => { + cursor.add_mode(SELECT_ANCHOR_MODE_LABEL, &mut visibility); + cursor.level_anchor_placement + } + }; + + let path = state.path.or_broken_state()?; + let mut path_mut = paths.get_mut(path).or_broken_query()?; + state.set_last(chosen, path_mut.as_mut(), &mut commands) +} + +pub fn on_select_for_create_path( + In((selection, key)): In<(SelectionCandidate, BufferKey)>, + mut access: BufferAccessMut, + mut paths: Query<&mut Path>, + mut commands: Commands, + cursor: Res, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + + let chosen = selection.candidate; + let provisional = selection.provisional; + let path = state.path.or_broken_state()?; + let mut path_mut = paths.get_mut(path).or_broken_query()?; + + if state.implied_complete_loop { + let first = path_mut.0.first().or_broken_state()?; + if chosen == *first && path_mut.0.len() >= state.minimum_points { + // The user has re-selected the first point and there are enough + // points in the path to meet the minimum requirement, so we can + // just end the workflow. + return Err(None); + } + } + + if !state.allow_inner_loops { + for a in &path_mut.0[..path_mut.0.len() - 1] { + if *a == chosen { + warn!( + "Attempting to create an inner loop in a type of path \ + which does not allow inner loops." + ); + return Ok(()); + } + } + } + + if path_mut.0.len() >= 2 { + if let Some(second_to_last) = path_mut.0.get(path_mut.0.len() - 2) { + if *second_to_last == chosen { + // Even if inner loops are allowed, we should never allow the same + // anchor to be chosen twice in a row. + warn!("Trying to select the same anchor for a path twice in a row"); + return Ok(()); + } + } + } + + state.set_last(chosen, path_mut.as_mut(), &mut commands)?; + if provisional { + state.provisional_anchors.insert(chosen); + } + + path_mut.0.push(cursor.level_anchor_placement); + commands.add(ChangeDependent::add(cursor.level_anchor_placement, path)); + + Ok(()) +} + +pub fn cleanup_create_path( + In(key): In>, + mut access: BufferAccessMut, + mut paths: Query<&'static mut Path>, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.pull().or_broken_state()?; + + let Some(path) = state.path else { + // If there is no path then there is nothing to cleanup. This might + // happen if the setup needed to bail out for some reason. + return Ok(()); + }; + commands + .get_entity(path) + .or_broken_query()? + .remove::(); + let mut path_mut = paths.get_mut(path).or_broken_query()?; + + // First check if the len-1 meets the minimum point requirement. If not we + // should despawn the path as well as any provisional anchors that it used. + if path_mut.0.len() - 1 < state.minimum_points { + // We did not collect enough points for the path so we should despawn it + // as well as any provisional points it contains. + for a in &path_mut.0 { + commands.add(ChangeDependent::remove(*a, path)); + } + + for a in state.provisional_anchors { + if let Some(a_mut) = commands.get_entity(a) { + a_mut.despawn_recursive(); + } + } + + commands + .get_entity(path) + .or_broken_query()? + .despawn_recursive(); + } else { + if let Some(a) = path_mut.0.last() { + // The last point in the path is always a preview point so we need + // to pop it. + let a = *a; + path_mut.0.pop(); + if !path_mut.contains(&a) { + // Remove the dependency on the last point since it no longer + // exists in the path + commands.add(ChangeDependent::remove(a, path)); + } + } + + if path_mut.0.is_empty() { + // The path is empty... we shouldn't keep an empty path so let's + // just despawn it. + commands + .get_entity(path) + .or_broken_query()? + .despawn_recursive(); + } + } + + Ok(()) +} diff --git a/rmf_site_editor/src/interaction/select/create_point.rs b/rmf_site_editor/src/interaction/select/create_point.rs new file mode 100644 index 00000000..645d5dc1 --- /dev/null +++ b/rmf_site_editor/src/interaction/select/create_point.rs @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2024 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +use crate::{ + interaction::*, + site::{ChangeDependent, Pending}, +}; +use bevy::prelude::*; +use bevy_impulse::*; +use rmf_site_format::Point; +use std::borrow::Borrow; + +pub fn spawn_create_point_service( + helpers: &AnchorSelectionHelpers, + app: &mut App, +) -> Service, ()> { + let anchor_setup = + app.spawn_service(anchor_selection_setup::.into_blocking_service()); + let state_setup = app.spawn_service(create_point_setup.into_blocking_service()); + let update_preview = app.spawn_service(on_hover_for_create_point.into_blocking_service()); + let update_current = app.spawn_service(on_select_for_create_point.into_blocking_service()); + let handle_key_code = app.spawn_service(exit_on_esc::.into_blocking_service()); + let cleanup_state = app.spawn_service(cleanup_create_point.into_blocking_service()); + + helpers.spawn_anchor_selection_workflow( + anchor_setup, + state_setup, + update_preview, + update_current, + handle_key_code, + cleanup_state, + &mut app.world, + ) +} + +pub struct CreatePoint { + /// Function pointer for spawning a point. + pub spawn_point: fn(Point, &mut Commands) -> Entity, + /// The point which is being created. This will initially be [`None`] until + /// setup happens, then `spawn_point` will be used to create this. For all + /// the services in the `create_point` workflow besides setup, this should + /// contain [`Some`]. + pub point: Option, + /// True if we should keep creating new points until the user presses Esc, + /// False if we should only create one point. + pub repeating: bool, + pub scope: AnchorScope, +} + +impl CreatePoint { + pub fn new>>(repeating: bool, scope: AnchorScope) -> Self { + Self { + spawn_point: create_point::, + point: None, + repeating, + scope, + } + } + + pub fn create_new_point(&mut self, anchor: Entity, commands: &mut Commands) { + let point = Point(anchor); + let point = (self.spawn_point)(point, commands); + commands.add(ChangeDependent::add(anchor, point)); + self.point = Some(point); + } +} + +impl Borrow for CreatePoint { + fn borrow(&self) -> &AnchorScope { + &self.scope + } +} + +fn create_point>>( + point: Point, + commands: &mut Commands, +) -> Entity { + let new_bundle: T = point.into(); + commands.spawn((new_bundle, Pending)).id() +} + +pub fn create_point_setup( + In(key): In>, + mut access: BufferAccessMut, + cursor: Res, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + + if state.point.is_none() { + state.create_new_point(cursor.level_anchor_placement, &mut commands); + } + + Ok(()) +} + +fn change_point( + chosen: Entity, + point: Entity, + points: &mut Query<&mut Point>, + commands: &mut Commands, +) -> SelectionNodeResult { + let mut point_mut = points.get_mut(point).or_broken_query()?; + if point_mut.0 == chosen { + return Ok(()); + } + + commands.add(ChangeDependent::remove(point_mut.0, point)); + commands.add(ChangeDependent::add(chosen, point)); + point_mut.0 = chosen; + Ok(()) +} + +pub fn on_hover_for_create_point( + In((hover, key)): In<(Hover, BufferKey)>, + mut access: BufferAccessMut, + mut cursor: ResMut, + mut visibility: Query<&mut Visibility>, + mut points: Query<&mut Point>, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + + let chosen = match hover.0 { + Some(anchor) => { + cursor.remove_mode(SELECT_ANCHOR_MODE_LABEL, &mut visibility); + anchor + } + None => { + cursor.add_mode(SELECT_ANCHOR_MODE_LABEL, &mut visibility); + cursor.level_anchor_placement + } + }; + + let point = state.point.or_broken_state()?; + change_point(chosen, point, &mut points, &mut commands) +} + +pub fn on_select_for_create_point( + In((selection, key)): In<(SelectionCandidate, BufferKey)>, + mut access: BufferAccessMut, + cursor: Res, + mut points: Query<&mut Point>, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + let point = state.point.or_broken_state()?; + change_point(selection.candidate, point, &mut points, &mut commands)?; + commands + .get_entity(point) + .or_broken_query()? + .remove::(); + if state.repeating { + state.create_new_point(cursor.level_anchor_placement, &mut commands); + return Ok(()); + } else { + state.point = None; + return Err(None); + } +} + +pub fn cleanup_create_point( + In(key): In>, + mut access: BufferAccessMut, + points: Query<&'static Point>, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.pull().or_broken_state()?; + + let Some(point) = state.point else { + // If there is no point then there is nothing to cleanup. + return Ok(()); + }; + + let point_ref = points.get(point).or_broken_query()?; + commands.add(ChangeDependent::remove(point_ref.0, point)); + commands + .get_entity(point) + .or_broken_query()? + .despawn_recursive(); + + Ok(()) +} diff --git a/rmf_site_editor/src/interaction/select/place_object.rs b/rmf_site_editor/src/interaction/select/place_object.rs new file mode 100644 index 00000000..96a9f346 --- /dev/null +++ b/rmf_site_editor/src/interaction/select/place_object.rs @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2024 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +use crate::{interaction::select::*, site::Model}; +use bevy::ecs::system::SystemParam; + +#[derive(Default)] +pub struct ObjectPlacementPlugin {} + +impl Plugin for ObjectPlacementPlugin { + fn build(&self, app: &mut App) { + let services = ObjectPlacementServices::from_app(app); + app.insert_resource(services); + } +} + +#[derive(Resource, Clone, Copy)] +pub struct ObjectPlacementServices { + pub place_object_2d: Service, ()>, + pub place_object_3d: Service, ()>, + pub replace_parent_3d: Service, ()>, + pub hover_service_object_3d: Service<(), (), Hover>, +} + +impl ObjectPlacementServices { + pub fn from_app(app: &mut App) -> Self { + let hover_service_object_3d = app.spawn_continuous_service( + Update, + hover_service:: + .configure(|config: SystemConfigs| config.in_set(SelectionServiceStages::Hover)), + ); + let place_object_2d = spawn_place_object_2d_workflow(app); + let place_object_3d = spawn_place_object_3d_workflow(hover_service_object_3d, app); + let replace_parent_3d = spawn_replace_parent_3d_workflow(hover_service_object_3d, app); + Self { + place_object_2d, + place_object_3d, + replace_parent_3d, + hover_service_object_3d, + } + } +} + +#[derive(SystemParam)] +pub struct ObjectPlacement<'w, 's> { + pub services: Res<'w, ObjectPlacementServices>, + pub commands: Commands<'w, 's>, +} + +impl<'w, 's> ObjectPlacement<'w, 's> { + pub fn place_object_2d(&mut self, object: Model, level: Entity) { + let state = self + .commands + .spawn(SelectorInput(PlaceObject2d { object, level })) + .id(); + self.send(RunSelector { + selector: self.services.place_object_2d, + input: Some(state), + }); + } + + pub fn place_object_3d( + &mut self, + object: PlaceableObject, + parent: Option, + workspace: Entity, + ) { + let state = self + .commands + .spawn(SelectorInput(PlaceObject3d { + object, + parent, + workspace, + })) + .id(); + self.send(RunSelector { + selector: self.services.place_object_3d, + input: Some(state), + }); + } + + pub fn replace_parent_3d(&mut self, object: Entity, workspace: Entity) { + let state = self + .commands + .spawn(SelectorInput(ReplaceParent3d { object, workspace })) + .id(); + self.send(RunSelector { + selector: self.services.replace_parent_3d, + input: Some(state), + }); + } + + fn send(&mut self, run: RunSelector) { + self.commands.add(move |world: &mut World| { + world.send_event(run); + }); + } +} diff --git a/rmf_site_editor/src/interaction/select/place_object_2d.rs b/rmf_site_editor/src/interaction/select/place_object_2d.rs new file mode 100644 index 00000000..58c053bb --- /dev/null +++ b/rmf_site_editor/src/interaction/select/place_object_2d.rs @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2024 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +use crate::{interaction::select::*, site::Model}; +use bevy::prelude::ButtonInput; + +pub const PLACE_OBJECT_2D_MODE_LABEL: &'static str = "place_object_2d"; + +pub fn spawn_place_object_2d_workflow(app: &mut App) -> Service, ()> { + let setup = app.spawn_service(place_object_2d_setup.into_blocking_service()); + let find_position = app.spawn_continuous_service(Update, place_object_2d_find_placement); + let placement_chosen = app.spawn_service(on_placement_chosen_2d.into_blocking_service()); + let handle_key_code = + app.spawn_service(on_keyboard_for_place_object_2d.into_blocking_service()); + let cleanup = app.spawn_service(place_object_2d_cleanup.into_blocking_service()); + + let keyboard_just_pressed = app + .world + .resource::() + .keyboard_just_pressed; + + app.world.spawn_io_workflow(build_place_object_2d_workflow( + setup, + find_position, + placement_chosen, + handle_key_code, + cleanup, + keyboard_just_pressed, + )) +} + +pub fn build_place_object_2d_workflow( + setup: Service, SelectionNodeResult>, + find_placement: Service<(), Transform>, + placement_chosen: Service<(Transform, BufferKey), SelectionNodeResult>, + handle_key_code: Service, + cleanup: Service, ()>, + keyboard_just_pressed: Service<(), (), StreamOf>, +) -> impl FnOnce(Scope, ()>, &mut Builder) { + move |scope, builder| { + let buffer = builder.create_buffer::(BufferSettings::keep_last(1)); + + let setup_finished = scope + .input + .chain(builder) + .then(extract_selector_input::.into_blocking_callback()) + .branch_for_err(|err| err.connect(scope.terminate)) + .cancel_on_none() + .then_push(buffer) + .then_access(buffer) + .then(setup) + .branch_for_err(|err| err.map_block(print_if_err).connect(scope.terminate)) + .output() + .fork_clone(builder); + + setup_finished + .clone_chain(builder) + .then(find_placement) + .with_access(buffer) + .then(placement_chosen) + .fork_result( + |ok| ok.connect(scope.terminate), + |err| err.map_block(print_if_err).connect(scope.terminate), + ); + + let keyboard_node = setup_finished + .clone_chain(builder) + .then_node(keyboard_just_pressed); + keyboard_node + .streams + .chain(builder) + .inner() + .then(handle_key_code) + .fork_result( + |ok| ok.connect(scope.terminate), + |err| err.map_block(print_if_err).connect(scope.terminate), + ); + + builder.on_cleanup(buffer, move |scope, builder| { + scope + .input + .chain(builder) + .then(cleanup) + .connect(scope.terminate); + }); + } +} + +pub struct PlaceObject2d { + pub object: Model, + pub level: Entity, +} + +pub fn place_object_2d_setup( + In(key): In>, + mut access: BufferAccessMut, + mut cursor: ResMut, + mut visibility: Query<&mut Visibility>, + mut commands: Commands, + mut gizmo_blockers: ResMut, + mut highlight: ResMut, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_buffer()?; + + cursor.set_model_preview(&mut commands, Some(state.object.clone())); + set_visibility(cursor.dagger, &mut visibility, false); + set_visibility(cursor.halo, &mut visibility, false); + + highlight.0 = false; + gizmo_blockers.selecting = true; + + cursor.add_mode(PLACE_OBJECT_2D_MODE_LABEL, &mut visibility); + + Ok(()) +} + +pub fn place_object_2d_cleanup( + In(_): In>, + mut cursor: ResMut, + mut visibility: Query<&mut Visibility>, + mut commands: Commands, + mut gizmo_blockers: ResMut, +) { + cursor.remove_preview(&mut commands); + cursor.remove_mode(PLACE_OBJECT_2D_MODE_LABEL, &mut visibility); + gizmo_blockers.selecting = false; +} + +pub fn place_object_2d_find_placement( + In(ContinuousService { key }): ContinuousServiceInput<(), Transform>, + mut orders: ContinuousQuery<(), Transform>, + cursor: Res, + mut transforms: Query<&mut Transform>, + intersect_ground_params: IntersectGroundPlaneParams, + mouse_button_input: Res>, + blockers: Option>, +) { + let Some(mut orders) = orders.get_mut(&key) else { + return; + }; + + let Some(order) = orders.get_mut(0) else { + return; + }; + + // TODO(@mxgrey): Consider allowing models to be snapped to existing objects + // similar to how they can for the 3D object placement workflow. Either we + // need to introduce parent frames to the 2D sites or just don't bother with + // parenting. + if let Some(intersection) = intersect_ground_params.ground_plane_intersection() { + match transforms.get_mut(cursor.frame) { + Ok(mut transform) => { + *transform = intersection; + } + Err(err) => { + error!("No cursor transform found: {err}"); + } + } + + let clicked = mouse_button_input.just_pressed(MouseButton::Left); + let blocked = blockers.filter(|x| x.blocking()).is_some(); + if clicked && !blocked { + order.respond(intersection); + } + } else { + warn!("Unable to find a placement position. Try adjusting your camera angle."); + } +} + +pub fn on_keyboard_for_place_object_2d(In(key): In) -> SelectionNodeResult { + if matches!(key, KeyCode::Escape) { + // Simply end the workflow if the escape key was pressed + info!("Exiting 2D object placement"); + return Err(None); + } + + Ok(()) +} + +pub fn on_placement_chosen_2d( + In((placement, key)): In<(Transform, BufferKey)>, + mut access: BufferAccessMut, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let mut state = access.pull().or_broken_state()?; + + state.object.pose = placement.into(); + commands.spawn(state.object).set_parent(state.level); + + Ok(()) +} diff --git a/rmf_site_editor/src/interaction/select/place_object_3d.rs b/rmf_site_editor/src/interaction/select/place_object_3d.rs new file mode 100644 index 00000000..54910168 --- /dev/null +++ b/rmf_site_editor/src/interaction/select/place_object_3d.rs @@ -0,0 +1,505 @@ +/* + * Copyright (C) 2024 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +use crate::{ + interaction::select::*, + site::{ + Anchor, AnchorBundle, Dependents, FrameMarker, Model, NameInSite, NameInWorkcell, Pending, + SiteID, WorkcellModel, + }, + widgets::canvas_tooltips::CanvasTooltips, +}; +use bevy::{ecs::system::SystemParam, prelude::ButtonInput}; +use bevy_mod_raycast::deferred::RaycastSource; +use std::borrow::Cow; + +pub const PLACE_OBJECT_3D_MODE_LABEL: &'static str = "place_object_3d"; + +pub fn spawn_place_object_3d_workflow( + hover_service: Service<(), (), Hover>, + app: &mut App, +) -> Service, ()> { + let setup = app.spawn_service(place_object_3d_setup); + let find_position = app.spawn_continuous_service(Update, place_object_3d_find_placement); + let placement_chosen = app.spawn_service(on_placement_chosen_3d.into_blocking_service()); + let handle_key_code = app.spawn_service(on_keyboard_for_place_object_3d); + let cleanup = app.spawn_service(place_object_3d_cleanup.into_blocking_service()); + let selection_update = app.world.resource::().selection_update; + let keyboard_just_pressed = app + .world + .resource::() + .keyboard_just_pressed; + + app.world.spawn_io_workflow(build_place_object_3d_workflow( + setup, + find_position, + placement_chosen, + handle_key_code, + cleanup, + hover_service.optional_stream_cast(), + selection_update, + keyboard_just_pressed, + )) +} + +pub fn build_place_object_3d_workflow( + setup: Service, SelectionNodeResult, Select>, + find_placement: Service, Transform, Select>, + placement_chosen: Service<(Transform, BufferKey), SelectionNodeResult>, + handle_key_code: Service<(KeyCode, BufferKey), SelectionNodeResult, Select>, + cleanup: Service, SelectionNodeResult>, + // Used to manage highlighting prospective parent frames + hover_service: Service<(), ()>, + // Used to manage highlighting the current parent frame + selection_update: Service, + keyboard_just_pressed: Service<(), (), StreamOf>, +) -> impl FnOnce(Scope, ()>, &mut Builder) { + move |scope, builder| { + let buffer = builder.create_buffer::(BufferSettings::keep_last(1)); + let selection_update_node = builder.create_node(selection_update); + let setup_node = scope + .input + .chain(builder) + .then(extract_selector_input::.into_blocking_callback()) + .branch_for_err(|err| err.connect(scope.terminate)) + .cancel_on_none() + .then_push(buffer) + .then_access(buffer) + .then_node(setup); + + builder.connect(setup_node.streams, selection_update_node.input); + + let begin_input_services = setup_node + .output + .chain(builder) + .branch_for_err(|err| err.map_block(print_if_err).connect(scope.terminate)) + .output() + .fork_clone(builder); + + let find_placement_node = begin_input_services + .clone_chain(builder) + .then_access(buffer) + .then_node(find_placement); + + find_placement_node + .output + .chain(builder) + .with_access(buffer) + .then(placement_chosen) + .fork_result( + |ok| ok.connect(scope.terminate), + |err| err.map_block(print_if_err).connect(scope.terminate), + ); + + builder.connect(find_placement_node.streams, selection_update_node.input); + + begin_input_services + .clone_chain(builder) + .then(hover_service) + .connect(scope.terminate); + + let keyboard = begin_input_services + .clone_chain(builder) + .then_node(keyboard_just_pressed); + let handle_key_node = keyboard + .streams + .chain(builder) + .inner() + .with_access(buffer) + .then_node(handle_key_code); + + handle_key_node + .output + .chain(builder) + .dispose_on_ok() + .map_block(print_if_err) + .connect(scope.terminate); + + builder.connect(handle_key_node.streams, selection_update_node.input); + + builder.on_cleanup(buffer, move |scope, builder| { + scope.input.chain(builder).then(cleanup).fork_result( + |ok| ok.connect(scope.terminate), + |err| err.map_block(print_if_err).connect(scope.terminate), + ); + }); + } +} + +pub struct PlaceObject3d { + pub object: PlaceableObject, + pub parent: Option, + pub workspace: Entity, +} + +#[derive(Clone, Debug)] +pub enum PlaceableObject { + Model(Model), + Anchor, + VisualMesh(WorkcellModel), + CollisionMesh(WorkcellModel), +} + +pub fn place_object_3d_setup( + In(srv): BlockingServiceInput, Select>, + mut access: BufferAccessMut, + mut cursor: ResMut, + mut visibility: Query<&mut Visibility>, + mut commands: Commands, + mut highlight: ResMut, + mut filter: PlaceObject3dFilter, + mut gizmo_blockers: ResMut, +) -> SelectionNodeResult { + let mut access = access.get_mut(&srv.request).or_broken_buffer()?; + let state = access.newest_mut().or_broken_buffer()?; + + match &state.object { + PlaceableObject::Anchor => { + // Make the anchor placement component of the cursor visible + set_visibility(cursor.frame_placement, &mut visibility, true); + set_visibility(cursor.dagger, &mut visibility, true); + set_visibility(cursor.halo, &mut visibility, true); + } + PlaceableObject::Model(m) => { + // Spawn the model as a child of the cursor + cursor.set_model_preview(&mut commands, Some(m.clone())); + set_visibility(cursor.dagger, &mut visibility, false); + set_visibility(cursor.halo, &mut visibility, false); + } + PlaceableObject::VisualMesh(m) | PlaceableObject::CollisionMesh(m) => { + // Spawn the model as a child of the cursor + cursor.set_workcell_model_preview(&mut commands, Some(m.clone())); + set_visibility(cursor.dagger, &mut visibility, false); + set_visibility(cursor.halo, &mut visibility, false); + } + } + + if let Some(parent) = state.parent { + let parent = filter.filter_select(parent); + state.parent = parent; + } + srv.streams.send(Select::new(state.parent)); + + highlight.0 = true; + gizmo_blockers.selecting = true; + + cursor.add_mode(PLACE_OBJECT_3D_MODE_LABEL, &mut visibility); + + Ok(()) +} + +pub fn place_object_3d_cleanup( + In(_): In>, + mut cursor: ResMut, + mut visibility: Query<&mut Visibility>, + mut commands: Commands, + mut highlight: ResMut, + mut gizmo_blockers: ResMut, +) -> SelectionNodeResult { + cursor.remove_preview(&mut commands); + cursor.remove_mode(PLACE_OBJECT_3D_MODE_LABEL, &mut visibility); + set_visibility(cursor.frame_placement, &mut visibility, false); + highlight.0 = false; + gizmo_blockers.selecting = false; + + Ok(()) +} + +pub fn place_object_3d_find_placement( + In(ContinuousService { key: srv_key }): ContinuousServiceInput< + BufferKey, + Transform, + Select, + >, + mut orders: ContinuousQuery, Transform, Select>, + mut buffer: BufferAccessMut, + mut cursor: ResMut, + raycast_sources: Query<&RaycastSource>, + mut transforms: Query<&mut Transform>, + intersect_ground_params: IntersectGroundPlaneParams, + mut visibility: Query<&mut Visibility>, + mut tooltips: ResMut, + keyboard_input: Res>, + mut hover: EventWriter, + hovering: Res, + mouse_button_input: Res>, + blockers: Option>, + meta: Query<(Option<&'static NameInSite>, Option<&'static SiteID>)>, + mut filter: PlaceObject3dFilter, +) { + let Some(mut orders) = orders.get_mut(&srv_key) else { + return; + }; + + let Some(order) = orders.get_mut(0) else { + return; + }; + + let key = order.request(); + let Ok(mut buffer) = buffer.get_mut(key) else { + error!("Unable to retrieve buffer in place_object_3d_cursor_transform"); + return; + }; + let Some(state) = buffer.newest_mut() else { + error!("Missing state in place_object_3d_cursor_transform"); + return; + }; + + if state.parent.is_some() { + tooltips.add(Cow::Borrowed("Esc: deselect current parent")); + } + + let project_to_plane = keyboard_input.any_pressed([KeyCode::ShiftLeft, KeyCode::ShiftRight]); + + let mut transform = match transforms.get_mut(cursor.frame) { + Ok(transform) => transform, + Err(err) => { + error!("No cursor transform found: {err}"); + return; + } + }; + + let Ok(source) = raycast_sources.get_single() else { + return; + }; + + // Check if there is an intersection with a mesh + let mut intersection: Option = None; + let mut new_hover = None; + let mut select_new_parent = false; + if !project_to_plane { + for (e, i) in source.intersections() { + let Some(e) = filter.filter_pick(*e) else { + continue; + }; + + if let Some(parent) = state.parent { + if e == parent { + new_hover = Some(parent); + cursor.add_mode(PLACE_OBJECT_3D_MODE_LABEL, &mut visibility); + tooltips.add(Cow::Borrowed("Click to place")); + tooltips.add(Cow::Borrowed("+Shift: Project to parent frame")); + + // Don't use the intersection with the parent if the parent + // is an anchor because that results in silly orientations + // which the user probably does not want. + if !filter.anchors.contains(e) { + intersection = Some( + Transform::from_translation(i.position()) + .with_rotation(aligned_z_axis(i.normal())), + ); + } + break; + } + } else { + new_hover = Some(e); + select_new_parent = true; + cursor.remove_mode(PLACE_OBJECT_3D_MODE_LABEL, &mut visibility); + tooltips.add(Cow::Borrowed("Click to set as parent")); + tooltips.add(Cow::Borrowed("+Shift: Project to ground plane")); + break; + } + } + } else { + cursor.add_mode(PLACE_OBJECT_3D_MODE_LABEL, &mut visibility); + } + + if new_hover != hovering.0 { + hover.send(Hover(new_hover)); + } + + if !select_new_parent { + intersection = intersection.or_else(|| { + if let Some(parent) = state.parent { + tooltips.add(Cow::Borrowed("Click to place")); + cursor.add_mode(PLACE_OBJECT_3D_MODE_LABEL, &mut visibility); + intersect_ground_params.frame_plane_intersection(parent) + } else { + tooltips.add(Cow::Borrowed("Click to place")); + cursor.add_mode(PLACE_OBJECT_3D_MODE_LABEL, &mut visibility); + intersect_ground_params.ground_plane_intersection() + } + }); + + if let Some(intersection) = intersection { + *transform = intersection; + } + } + + let clicked = mouse_button_input.just_pressed(MouseButton::Left); + let blocked = blockers.filter(|x| x.blocking()).is_some(); + if clicked && !blocked { + if select_new_parent { + if let Some(new_parent) = new_hover { + state.parent = Some(new_parent); + order.streams().send(Select::new(Some(new_parent))); + if let Ok((name, id)) = meta.get(new_parent) { + let id = id.map(|id| id.0.to_string()); + info!( + "Placing object in the frame of [{}], id: {}", + name.map(|name| name.0.as_str()).unwrap_or(""), + id.as_ref().map(|id| id.as_str()).unwrap_or("*"), + ); + } + } + } else { + if let Some(intersection) = intersection { + // The user is choosing a location to place the object. + order.respond(intersection); + } else { + warn!("Unable to find a placement position. Try adjusting your camera angle."); + } + } + } +} + +#[derive(SystemParam)] +pub struct PlaceObject3dFilter<'w, 's> { + inspect: InspectorFilter<'w, 's>, + ignore: Query<'w, 's, (), Or<(With, With)>>, + // We aren't using this in the filter functions, we're sneaking this query + // into this system param to skirt around the 16-parameter limit for + // place_object_3d_find_placement + anchors: Query<'w, 's, (), With>, +} + +impl<'w, 's> SelectionFilter for PlaceObject3dFilter<'w, 's> { + fn filter_pick(&mut self, target: Entity) -> Option { + let e = self.inspect.filter_pick(target); + + if let Some(e) = e { + if self.ignore.contains(e) { + return None; + } + } + e + } + + fn filter_select(&mut self, target: Entity) -> Option { + self.inspect.filter_select(target) + } + + fn on_click(&mut self, _: Hover) -> Option, +) { + let Some(mut orders) = orders.get_mut(&key) else { + selected.clear(); + return; + }; + + let Some(order) = orders.get_mut(0) else { + // Clear the selected reader so we don't mistake an earlier signal as + // being intended for this workflow. + selected.clear(); + return; + }; + + let object = *order.request(); + for s in selected.read() { + // Allow users to signal the choice of parent by means other than clicking + match s.0 { + Some(s) => { + if let Some(e) = filter.filter_pick(s.candidate) { + order.respond(Some(e)); + return; + } + + info!( + "Received parent replacement selection signal for an invalid parent candidate" + ); + } + None => { + // The user has sent a signal to remove the object from its parent + order.respond(None); + return; + } + } + } + + let Ok(source) = raycast_sources.get_single() else { + return; + }; + + let mut hovered: Option = None; + let mut ignore_click = false; + for (e, _) in source.intersections() { + let Some(e) = filter.filter_pick(*e) else { + continue; + }; + + if AncestorIter::new(&parents, e) + .filter(|e| *e == object) + .next() + .is_some() + { + ignore_click = true; + tooltips.add(Cow::Borrowed( + "Cannot select a child of the object to be its parent", + )); + break; + } + + if e == object { + ignore_click = true; + tooltips.add(Cow::Borrowed( + "Cannot select an object to be its own parent", + )); + break; + } + + hovered = Some(e); + } + + if hovered.is_some() { + tooltips.add(Cow::Borrowed("Click to select this as the parent")); + } else if !ignore_click { + tooltips.add(Cow::Borrowed("Click to remove parent")); + } + + if hovered != hovering.0 { + hover.send(Hover(hovered)); + } + + let clicked = mouse_button_input.just_pressed(MouseButton::Left); + let blocked = blockers.filter(|x| x.blocking()).is_some(); + if clicked && !blocked && !ignore_click { + order.respond(hovered); + } +} + +pub fn replace_parent_3d_parent_chosen( + In((parent, key)): In<(Option, BufferKey)>, + access: BufferAccess, + mut dependents: Query<&mut Dependents>, + mut poses: Query<&mut Pose>, + global_tfs: Query<&GlobalTransform>, + parents: Query<&Parent>, + frames: Query<(), With>, + mut commands: Commands, + mut anchors: Query<&mut Anchor>, +) -> SelectionNodeResult { + let access = access.get(&key).or_broken_buffer()?; + let state = access.newest().or_broken_state()?; + + let parent = parent + .and_then(|p| { + if frames.contains(p) { + Some(p) + } else { + // The selected parent is not a frame, so find its first ancestor + // that contains a FrameMarker + AncestorIter::new(&parents, p).find(|e| frames.contains(*e)) + } + }) + .unwrap_or(state.workspace); + + let previous_parent = parents.get(state.object).or_broken_query()?.get(); + if parent == previous_parent { + info!("Object's parent remains the same"); + return Ok(()); + } + + let object_tf = global_tfs.get(state.object).or_broken_query()?.affine(); + let inv_parent_tf = global_tfs.get(parent).or_broken_query()?.affine().inverse(); + let relative_pose: Pose = Transform::from_matrix((inv_parent_tf * object_tf).into()).into(); + + let [mut previous_deps, mut new_deps] = dependents + .get_many_mut([previous_parent, parent]) + .or_broken_query()?; + + if let Ok(mut pose_mut) = poses.get_mut(state.object) { + *pose_mut = relative_pose; + } else { + let mut anchor = anchors.get_mut(state.object).or_broken_query()?; + *anchor = Anchor::Pose3D(relative_pose); + } + + // Do all mutations after everything is successfully queried so we don't + // risk an inconsistent/broken world due to a query failing. + commands + .get_entity(state.object) + .or_broken_query()? + .set_parent(parent); + previous_deps.remove(&state.object); + new_deps.insert(state.object); + + Ok(()) +} + +pub fn on_keyboard_for_replace_parent_3d(In(code): In) -> SelectionNodeResult { + if matches!(code, KeyCode::Escape) { + // Simply exit the workflow if the user presses esc + return Err(None); + } + + Ok(()) +} diff --git a/rmf_site_editor/src/interaction/select/replace_point.rs b/rmf_site_editor/src/interaction/select/replace_point.rs new file mode 100644 index 00000000..54339714 --- /dev/null +++ b/rmf_site_editor/src/interaction/select/replace_point.rs @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2024 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +use crate::{ + interaction::*, + site::{ChangeDependent, Original}, +}; +use bevy::prelude::*; +use bevy_impulse::*; +use rmf_site_format::Point; +use std::borrow::Borrow; + +pub fn spawn_replace_point_service( + helpers: &AnchorSelectionHelpers, + app: &mut App, +) -> Service, ()> { + let anchor_setup = + app.spawn_service(anchor_selection_setup::.into_blocking_service()); + let state_setup = app.spawn_service(replace_point_setup.into_blocking_service()); + let update_preview = app.spawn_service(on_hover_for_replace_point.into_blocking_service()); + let update_current = app.spawn_service(on_select_for_replace_point.into_blocking_service()); + let handle_key_code = app.spawn_service(exit_on_esc::.into_blocking_service()); + let cleanup_state = app.spawn_service(cleanup_replace_point.into_blocking_service()); + + helpers.spawn_anchor_selection_workflow( + anchor_setup, + state_setup, + update_preview, + update_current, + handle_key_code, + cleanup_state, + &mut app.world, + ) +} + +pub struct ReplacePoint { + /// The point whose anchor is being replaced + pub point: Entity, + /// The original value of the point. This is None until setup occurs, then + /// its value will be available. + pub original: Option>, + /// The scope that the point exists in + pub scope: AnchorScope, + /// Keeps track of whether the replacement really happened. If false, the + /// cleanup will revert the point to its original state. If true, the cleanup + /// will not need to do anything. + pub replaced: bool, +} + +impl ReplacePoint { + pub fn new(point: Entity, scope: AnchorScope) -> Self { + Self { + point, + original: None, + scope, + replaced: false, + } + } + + pub fn set_chosen( + &mut self, + chosen: Entity, + points: &mut Query<&mut Point>, + commands: &mut Commands, + ) -> SelectionNodeResult { + let mut point_mut = points.get_mut(self.point).or_broken_query()?; + commands.add(ChangeDependent::remove(point_mut.0, self.point)); + point_mut.0 = chosen; + commands.add(ChangeDependent::add(chosen, self.point)); + Ok(()) + } +} + +impl Borrow for ReplacePoint { + fn borrow(&self) -> &AnchorScope { + &self.scope + } +} + +pub fn replace_point_setup( + In(key): In>, + mut access: BufferAccessMut, + mut points: Query<&'static mut Point>, + cursor: Res, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + + let original = *points.get(state.point).or_broken_query()?; + state.original = Some(original); + commands.entity(state.point).insert(Original(original)); + state.set_chosen(cursor.level_anchor_placement, &mut points, &mut commands)?; + + Ok(()) +} + +pub fn on_hover_for_replace_point( + In((hover, key)): In<(Hover, BufferKey)>, + mut access: BufferAccessMut, + mut cursor: ResMut, + mut visibility: Query<&mut Visibility>, + mut points: Query<&mut Point>, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + + let chosen = match hover.0 { + Some(anchor) => { + cursor.remove_mode(SELECT_ANCHOR_MODE_LABEL, &mut visibility); + anchor + } + None => { + cursor.add_mode(SELECT_ANCHOR_MODE_LABEL, &mut visibility); + cursor.level_anchor_placement + } + }; + + state.set_chosen(chosen, &mut points, &mut commands) +} + +pub fn on_select_for_replace_point( + In((selection, key)): In<(SelectionCandidate, BufferKey)>, + mut access: BufferAccessMut, + mut points: Query<&mut Point>, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + state.set_chosen(selection.candidate, &mut points, &mut commands)?; + state.replaced = true; + // Since the selection has been made, we should exit the workflow now + Err(None) +} + +pub fn cleanup_replace_point( + In(key): In>, + mut access: BufferAccessMut, + mut points: Query<&'static mut Point>, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let mut state = access.pull().or_broken_state()?; + + commands + .get_entity(state.point) + .or_broken_query()? + .remove::>>(); + + if state.replaced { + // The anchor was fully replaced, so nothing furtehr to do + return Ok(()); + } + + let Some(original) = state.original else { + return Ok(()); + }; + + state.set_chosen(original.0, &mut points, &mut commands)?; + + Ok(()) +} diff --git a/rmf_site_editor/src/interaction/select/replace_side.rs b/rmf_site_editor/src/interaction/select/replace_side.rs new file mode 100644 index 00000000..fa0608ab --- /dev/null +++ b/rmf_site_editor/src/interaction/select/replace_side.rs @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2024 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +use crate::{ + interaction::*, + site::{ChangeDependent, Original}, +}; +use bevy::prelude::*; +use bevy_impulse::*; +use rmf_site_format::{Edge, Side}; +use std::borrow::Borrow; + +pub fn spawn_replace_side_service( + helpers: &AnchorSelectionHelpers, + app: &mut App, +) -> Service, ()> { + let anchor_setup = + app.spawn_service(anchor_selection_setup::.into_blocking_service()); + let state_setup = app.spawn_service(replace_side_setup.into_blocking_service()); + let update_preview = app.spawn_service(on_hover_for_replace_side.into_blocking_service()); + let update_current = app.spawn_service(on_select_for_replace_side.into_blocking_service()); + let handle_key_code = app.spawn_service(exit_on_esc::.into_blocking_service()); + let cleanup_state = app.spawn_service(cleanup_replace_side.into_blocking_service()); + + helpers.spawn_anchor_selection_workflow( + anchor_setup, + state_setup, + update_preview, + update_current, + handle_key_code, + cleanup_state, + &mut app.world, + ) +} + +pub struct ReplaceSide { + /// The edge whose anchor is being replaced + pub edge: Entity, + /// The side of the edge which is being replaced + pub side: Side, + /// The original values for the edge. This is None until setup occurs, then + /// its value will be available. + pub original: Option>, + /// The scope that the edge exists in + pub scope: AnchorScope, + /// Keeps track of whether the replacement really happened. If false, the + /// cleanup will revert the edge to its original state. If true, the cleanup + /// will not need to do anything. + pub replaced: bool, +} + +impl ReplaceSide { + pub fn new(edge: Entity, side: Side, scope: AnchorScope) -> Self { + Self { + edge, + side, + scope, + original: None, + replaced: false, + } + } + + pub fn set_chosen( + &mut self, + chosen: Entity, + edges: &mut Query<&mut Edge>, + commands: &mut Commands, + ) -> SelectionNodeResult { + let original = self.original.or_broken_buffer()?; + let mut edge_mut = edges.get_mut(self.edge).or_broken_query()?; + + for a in edge_mut.array() { + // Remove both current dependencies in case both of them change. + // If either dependency doesn't change then they'll be added back + // later anyway. + commands.add(ChangeDependent::remove(a, self.edge)); + } + + if chosen == original.array()[self.side.opposite().index()] { + // The user is choosing the anchor on the opposite side of the edge as + // the replacement anchor. We take this to mean that the user wants to + // flip the edge. + *edge_mut.left_mut() = original.right(); + *edge_mut.right_mut() = original.left(); + } else { + edge_mut.array_mut()[self.side.index()] = chosen; + let opp = self.side.opposite().index(); + edge_mut.array_mut()[opp] = original.array()[opp]; + } + + for a in edge_mut.array() { + commands.add(ChangeDependent::add(a, self.edge)); + } + + Ok(()) + } +} + +impl Borrow for ReplaceSide { + fn borrow(&self) -> &AnchorScope { + &self.scope + } +} + +pub fn replace_side_setup( + In(key): In>, + mut access: BufferAccessMut, + mut edges: Query<&'static mut Edge>, + cursor: Res, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + + let edge_ref = edges.get(state.edge).or_broken_query()?; + let original_edge: Edge = *edge_ref; + state.original = Some(original_edge); + commands.entity(state.edge).insert(Original(original_edge)); + state.set_chosen(cursor.level_anchor_placement, &mut edges, &mut commands)?; + + Ok(()) +} + +pub fn on_hover_for_replace_side( + In((hover, key)): In<(Hover, BufferKey)>, + mut access: BufferAccessMut, + mut cursor: ResMut, + mut visibility: Query<&mut Visibility>, + mut edges: Query<&mut Edge>, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + + let chosen = match hover.0 { + Some(anchor) => { + cursor.remove_mode(SELECT_ANCHOR_MODE_LABEL, &mut visibility); + anchor + } + None => { + cursor.add_mode(SELECT_ANCHOR_MODE_LABEL, &mut visibility); + cursor.level_anchor_placement + } + }; + + state.set_chosen(chosen, &mut edges, &mut commands) +} + +pub fn on_select_for_replace_side( + In((selection, key)): In<(SelectionCandidate, BufferKey)>, + mut access: BufferAccessMut, + mut edges: Query<&mut Edge>, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let state = access.newest_mut().or_broken_state()?; + state.set_chosen(selection.candidate, &mut edges, &mut commands)?; + state.replaced = true; + // Since the selection has been made, we should exit the workflow now + Err(None) +} + +pub fn cleanup_replace_side( + In(key): In>, + mut access: BufferAccessMut, + mut edges: Query<&'static mut Edge>, + mut commands: Commands, +) -> SelectionNodeResult { + let mut access = access.get_mut(&key).or_broken_buffer()?; + let mut state = access.pull().or_broken_state()?; + + commands + .get_entity(state.edge) + .or_broken_query()? + .remove::>>(); + + if state.replaced { + // The anchor was fully replaced, so nothing further to do + return Ok(()); + } + + // The anchor was not replaced so we need to revert to the original setup + let Some(original) = state.original else { + return Ok(()); + }; + + let revert = original.array()[state.side.index()]; + state.set_chosen(revert, &mut edges, &mut commands)?; + + Ok(()) +} diff --git a/rmf_site_editor/src/interaction/select/select_anchor.rs b/rmf_site_editor/src/interaction/select/select_anchor.rs new file mode 100644 index 00000000..399a63d4 --- /dev/null +++ b/rmf_site_editor/src/interaction/select/select_anchor.rs @@ -0,0 +1,765 @@ +/* + * Copyright (C) 2024 Open Source Robotics Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +use bevy::prelude::*; +use bevy_impulse::*; + +use crate::{interaction::select::*, site::CurrentLevel}; +use rmf_site_format::{Fiducial, Floor, LevelElevation, Location, Path, Point}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Resource)] +pub enum AnchorScope { + Drawing, + General, + Site, +} + +impl AnchorScope { + pub fn is_site(&self) -> bool { + match self { + AnchorScope::Site => true, + _ => false, + } + } +} + +#[derive(Default)] +pub struct AnchorSelectionPlugin {} + +impl Plugin for AnchorSelectionPlugin { + fn build(&self, app: &mut App) { + let helpers = AnchorSelectionHelpers::from_app(app); + let services = AnchorSelectionServices::from_app(&helpers, app); + app.init_resource::() + .insert_resource(AnchorScope::General) + .insert_resource(helpers) + .insert_resource(services); + } +} + +#[derive(Resource, Clone, Copy)] +pub struct AnchorSelectionHelpers { + pub anchor_select_stream: Service<(), (), (Hover, Select)>, + pub anchor_cursor_transform: Service<(), ()>, + pub keyboard_just_pressed: Service<(), (), StreamOf>, + pub cleanup_anchor_selection: Service<(), ()>, +} + +impl AnchorSelectionHelpers { + pub fn from_app(app: &mut App) -> Self { + let anchor_select_stream = app.spawn_selection_service::(); + let anchor_cursor_transform = app.spawn_continuous_service( + Update, + select_anchor_cursor_transform + .configure(|config: SystemConfigs| config.in_set(SelectionServiceStages::Pick)), + ); + let cleanup_anchor_selection = app + .world + .spawn_service(cleanup_anchor_selection.into_blocking_service()); + + let keyboard_just_pressed = app + .world + .resource::() + .keyboard_just_pressed; + + Self { + anchor_select_stream, + anchor_cursor_transform, + keyboard_just_pressed, + cleanup_anchor_selection, + } + } + + pub fn spawn_anchor_selection_workflow( + &self, + anchor_setup: Service, SelectionNodeResult>, + state_setup: Service, SelectionNodeResult>, + update_preview: Service<(Hover, BufferKey), SelectionNodeResult>, + update_current: Service<(SelectionCandidate, BufferKey), SelectionNodeResult>, + handle_key_code: Service<(KeyCode, BufferKey), SelectionNodeResult>, + cleanup_state: Service, SelectionNodeResult>, + world: &mut World, + ) -> Service, ()> { + world.spawn_io_workflow(build_anchor_selection_workflow( + anchor_setup, + state_setup, + update_preview, + update_current, + handle_key_code, + cleanup_state, + self.anchor_cursor_transform, + self.anchor_select_stream, + self.keyboard_just_pressed, + self.cleanup_anchor_selection, + )) + } +} + +#[derive(Resource, Clone, Copy)] +pub struct AnchorSelectionServices { + pub create_edges: Service, ()>, + pub replace_side: Service, ()>, + pub create_path: Service, ()>, + pub create_point: Service, ()>, + pub replace_point: Service, ()>, +} + +impl AnchorSelectionServices { + pub fn from_app(helpers: &AnchorSelectionHelpers, app: &mut App) -> Self { + let create_edges = spawn_create_edges_service(helpers, app); + let replace_side = spawn_replace_side_service(helpers, app); + let create_path = spawn_create_path_service(helpers, app); + let create_point = spawn_create_point_service(helpers, app); + let replace_point = spawn_replace_point_service(helpers, app); + Self { + create_edges, + replace_side, + create_path, + create_point, + replace_point, + } + } +} + +#[derive(SystemParam)] +pub struct AnchorSelection<'w, 's> { + pub services: Res<'w, AnchorSelectionServices>, + pub commands: Commands<'w, 's>, +} + +impl<'w, 's> AnchorSelection<'w, 's> { + pub fn create_lanes(&mut self) { + self.create_edges::>(EdgeContinuity::Continuous, AnchorScope::General); + } + + pub fn create_measurements(&mut self) { + self.create_edges::>(EdgeContinuity::Separate, AnchorScope::Drawing) + } + + pub fn create_walls(&mut self) { + self.create_edges_with_texture::>( + EdgeContinuity::Continuous, + AnchorScope::General, + ); + } + + pub fn create_door(&mut self) { + self.create_edges::>(EdgeContinuity::Single, AnchorScope::General) + } + + pub fn create_lift(&mut self) { + self.create_edges::>(EdgeContinuity::Single, AnchorScope::Site) + } + + pub fn create_floor(&mut self) { + self.create_path::>( + create_path_with_texture::>, + 3, + false, + true, + AnchorScope::General, + ); + } + + pub fn create_location(&mut self) { + self.create_point::>(false, AnchorScope::General); + } + + pub fn create_site_fiducial(&mut self) { + self.create_point::>(false, AnchorScope::Site); + } + + pub fn create_drawing_fiducial(&mut self) { + self.create_point::>(false, AnchorScope::Drawing); + } + + pub fn create_edges>>( + &mut self, + continuity: EdgeContinuity, + scope: AnchorScope, + ) { + let state = self + .commands + .spawn(SelectorInput(CreateEdges::new::(continuity, scope))) + .id(); + + self.send(RunSelector { + selector: self.services.create_edges, + input: Some(state), + }); + } + + pub fn create_edges_with_texture>>( + &mut self, + continuity: EdgeContinuity, + scope: AnchorScope, + ) { + let state = self + .commands + .spawn(SelectorInput(CreateEdges::new_with_texture::( + continuity, scope, + ))) + .id(); + + self.send(RunSelector { + selector: self.services.create_edges, + input: Some(state), + }); + } + + pub fn replace_side(&mut self, edge: Entity, side: Side, category: Category) -> bool { + let scope = match category { + Category::Lane | Category::Wall | Category::Door => AnchorScope::General, + Category::Measurement => AnchorScope::Drawing, + Category::Lift => AnchorScope::Site, + _ => return false, + }; + let state = self + .commands + .spawn(SelectorInput(ReplaceSide::new(edge, side, scope))) + .id(); + + self.send(RunSelector { + selector: self.services.replace_side, + input: Some(state), + }); + + true + } + + pub fn create_path>>( + &mut self, + spawn_path: fn(Path, &mut Commands) -> Entity, + minimum_points: usize, + allow_inner_loops: bool, + implied_complete_loop: bool, + scope: AnchorScope, + ) { + let state = self + .commands + .spawn(SelectorInput(CreatePath::new( + spawn_path, + minimum_points, + allow_inner_loops, + implied_complete_loop, + scope, + ))) + .id(); + + self.send(RunSelector { + selector: self.services.create_path, + input: Some(state), + }); + } + + pub fn create_point>>( + &mut self, + repeating: bool, + scope: AnchorScope, + ) { + let state = self + .commands + .spawn(SelectorInput(CreatePoint::new::(repeating, scope))) + .id(); + + self.send(RunSelector { + selector: self.services.create_point, + input: Some(state), + }); + } + + pub fn replace_point(&mut self, point: Entity, scope: AnchorScope) { + let state = self + .commands + .spawn(SelectorInput(ReplacePoint::new(point, scope))) + .id(); + + self.send(RunSelector { + selector: self.services.replace_point, + input: Some(state), + }); + } + + fn send(&mut self, run: RunSelector) { + self.commands.add(move |world: &mut World| { + world.send_event(run); + }); + } +} + +#[derive(Resource, Default)] +pub struct HiddenSelectAnchorEntities { + /// All drawing anchors, hidden when users draw level entities such as walls, lanes, floors to + /// make sure they don't connect to drawing anchors + pub drawing_anchors: HashSet, +} + +/// The first five services should be customized for the State data. The services +/// that return [`SelectionNodeResult`] should return `Ok(())` if it is okay for the +/// workflow to continue as normal, and they should return `Err(None)` if it's +/// time for the workflow to terminate as normal. If the workflow needs to +/// terminate because of an error, return `Err(Some(_))`. +/// +/// In most cases you should use [`AnchorSelectionHelpers::spawn_anchor_selection_workflow`] +/// instead of running this function yourself directly, unless you know that you +/// need to customize the last four services. +/// +/// * `anchor_setup`: This is run once at the start of the workflow to prepare the +/// world to select anchors from the right kind of scope for the request. This +/// is usually just [`anchor_selection_setup`] instantiated for the right type +/// of state. +/// * `state_setup`: This is for any additional custom setup that is relevant to +/// the state information for your selection workflow. This gets run exactly once +/// immediately after `anchor_setup` +/// * `update_preview`: This is run each time a [`Hover`] signal arrives. This +/// is where you should put the logic to update the preview that's being displayed +/// for users. +/// * `update_current`: This is run each time a [`Select`] signal containing `Some` +/// value is sent. This is where you should put the logic to make a persistent +/// (rather than just a preview) modification to the world. +/// * `handle_key_code`: This is where you should put the logic for how your +/// workflow responds to various key codes. For example, should the workflow +/// exit? +/// * `cleanup_state`: This is where you should run anything that's needed to +/// clean up the state of the world after your workflow is finished running. +/// This will be run no matter whether your workflow terminates with a success, +/// terminates with a failure, or cancels prematurely. +/// +/// ### The remaining parameters can all be provided by [`AnchorSelectionHelpers`] in most cases: +/// +/// * `anchor_cursor_transform`: This service should update the 3D cursor transform. +/// A suitable service for this is available from [`AnchorSelectionHelpers`]. +/// * `anchor_select_stream`: This service should produce the [`Hover`] and [`Select`] +/// streams that hook into `update_preview` and `update_current` respectively. +/// A suitable service for this is provided by [`AnchorSelectionHelpers`]. +/// * `keyobard_just_pressed`: This service should produce [`KeyCode`] streams +/// when the keyboard gets pressed. A suitable service for this is provided by +/// [`AnchorSelectionHelpers`]. +/// * `cleanup_anchor_selection`: This service will run during the cleanup phase +/// and should cleanup any anchor-related modifications to the world. A suitable +/// service for this is provided by [`AnchorSelectionHelpers`]. +pub fn build_anchor_selection_workflow( + anchor_setup: Service, SelectionNodeResult>, + state_setup: Service, SelectionNodeResult>, + update_preview: Service<(Hover, BufferKey), SelectionNodeResult>, + update_current: Service<(SelectionCandidate, BufferKey), SelectionNodeResult>, + handle_key_code: Service<(KeyCode, BufferKey), SelectionNodeResult>, + cleanup_state: Service, SelectionNodeResult>, + anchor_cursor_transform: Service<(), ()>, + anchor_select_stream: Service<(), (), (Hover, Select)>, + keyboard_just_pressed: Service<(), (), StreamOf>, + cleanup_anchor_selection: Service<(), ()>, +) -> impl FnOnce(Scope, ()>, &mut Builder) { + move |scope, builder| { + let buffer = builder.create_buffer::(BufferSettings::keep_last(1)); + + let setup_node = builder.create_buffer_access(buffer); + scope + .input + .chain(builder) + .then(extract_selector_input.into_blocking_callback()) + // If the setup failed, then terminate right away. + .branch_for_err(|chain: Chain<_>| chain.connect(scope.terminate)) + .fork_option( + |some: Chain<_>| some.then_push(buffer).connect(setup_node.input), + |none: Chain<_>| none.connect(setup_node.input), + ); + + let begin_input_services = setup_node + .output + .chain(builder) + .map_block(|(_, key)| key) + .then(anchor_setup) + .branch_for_err(|err| err.map_block(print_if_err).connect(scope.terminate)) + .with_access(buffer) + .map_block(|(_, key)| key) + .then(state_setup) + .branch_for_err(|err| err.map_block(print_if_err).connect(scope.terminate)) + .output() + .fork_clone(builder); + + begin_input_services + .clone_chain(builder) + .then(anchor_cursor_transform) + .unused(); + + let select = begin_input_services + .clone_chain(builder) + .then_node(anchor_select_stream); + select + .streams + .0 + .chain(builder) + .with_access(buffer) + .then(update_preview) + .dispose_on_ok() + .map_block(print_if_err) + .connect(scope.terminate); + + select + .streams + .1 + .chain(builder) + .map_block(|s| s.0) + .dispose_on_none() + .with_access(buffer) + .then(update_current) + .dispose_on_ok() + .map_block(print_if_err) + .connect(scope.terminate); + + let keyboard = begin_input_services + .clone_chain(builder) + .then_node(keyboard_just_pressed); + keyboard + .streams + .chain(builder) + .inner() + .with_access(buffer) + .then(handle_key_code) + .dispose_on_ok() + .map_block(print_if_err) + .connect(scope.terminate); + + builder.on_cleanup(buffer, move |scope, builder| { + let state_node = builder.create_node(cleanup_state); + let anchor_node = builder.create_node(cleanup_anchor_selection); + + builder.connect(scope.input, state_node.input); + state_node.output.chain(builder).fork_result( + |ok| ok.connect(anchor_node.input), + |err| err.map_block(print_if_err).connect(anchor_node.input), + ); + + builder.connect(anchor_node.output, scope.terminate); + }); + } +} + +pub fn print_if_err(err: Option) { + if let Some(err) = err { + error!("{err}"); + } +} + +pub fn anchor_selection_setup>( + In(key): In>, + access: BufferAccess, + anchors: Query>, + drawings: Query<(), With>, + parents: Query<&'static Parent>, + mut visibility: Query<&'static mut Visibility>, + mut hidden_anchors: ResMut, + mut current_anchor_scope: ResMut, + mut cursor: ResMut, + mut highlight: ResMut, + mut gizmo_blockers: ResMut, +) -> SelectionNodeResult +where + State: 'static + Send + Sync, +{ + let access = access.get(&key).or_broken_buffer()?; + let state = access.newest().or_broken_state()?; + let scope: &AnchorScope = (&*state).borrow(); + match scope { + AnchorScope::General | AnchorScope::Site => { + // If we are working with normal level or site requests, hide all drawing anchors + for e in anchors + .iter() + .filter(|e| parents.get(*e).is_ok_and(|p| drawings.get(p.get()).is_ok())) + { + set_visibility(e, &mut visibility, false); + hidden_anchors.drawing_anchors.insert(e); + } + } + // Nothing to hide, it's done by the drawing editor plugin + AnchorScope::Drawing => {} + } + + if scope.is_site() { + set_visibility(cursor.site_anchor_placement, &mut visibility, true); + } else { + set_visibility(cursor.level_anchor_placement, &mut visibility, true); + } + + highlight.0 = true; + gizmo_blockers.selecting = true; + + *current_anchor_scope = *scope; + + cursor.add_mode(SELECT_ANCHOR_MODE_LABEL, &mut visibility); + set_visibility(cursor.dagger, &mut visibility, true); + set_visibility(cursor.halo, &mut visibility, true); + + Ok(()) +} + +pub fn cleanup_anchor_selection( + In(_): In<()>, + mut cursor: ResMut, + mut visibility: Query<&mut Visibility>, + mut hidden_anchors: ResMut, + mut anchor_scope: ResMut, + mut highlight: ResMut, + mut gizmo_blockers: ResMut, +) { + cursor.remove_mode(SELECT_ANCHOR_MODE_LABEL, &mut visibility); + set_visibility(cursor.site_anchor_placement, &mut visibility, false); + set_visibility(cursor.level_anchor_placement, &mut visibility, false); + for e in hidden_anchors.drawing_anchors.drain() { + set_visibility(e, &mut visibility, true); + } + + highlight.0 = false; + gizmo_blockers.selecting = false; + + *anchor_scope = AnchorScope::General; +} + +pub fn extract_selector_input( + In(e): In>, + world: &mut World, +) -> Result, ()> { + let Some(e) = e else { + // There is no input to provide, so move ahead with the workflow + return Ok(None); + }; + + let Some(mut e_mut) = world.get_entity_mut(e) else { + error!( + "Could not begin selector service because the input entity {e:?} \ + does not exist.", + ); + return Err(()); + }; + + let Some(input) = e_mut.take::>() else { + error!( + "Could not begin selector service because the input entity {e:?} \ + did not contain a value {:?}. This is a bug, please report it.", + std::any::type_name::>(), + ); + return Err(()); + }; + + e_mut.despawn_recursive(); + + Ok(Some(input.0)) +} + +#[derive(SystemParam)] +pub struct AnchorFilter<'w, 's> { + inspect: InspectorFilter<'w, 's>, + anchors: Query<'w, 's, (), With>, + cursor: Res<'w, Cursor>, + anchor_scope: Res<'w, AnchorScope>, + workspace: Res<'w, CurrentWorkspace>, + open_sites: Query<'w, 's, Entity, With>, + transforms: Query<'w, 's, &'static GlobalTransform>, + commands: Commands<'w, 's>, + current_drawing: Res<'w, CurrentEditDrawing>, + drawings: Query<'w, 's, &'static PixelsPerMeter, With>, + parents: Query<'w, 's, &'static Parent>, + levels: Query<'w, 's, (), With>, + current_level: Res<'w, CurrentLevel>, +} + +impl<'w, 's> SelectionFilter for AnchorFilter<'w, 's> { + fn filter_pick(&mut self, select: Entity) -> Option { + self.inspect + .filter_pick(select) + .and_then(|e| self.filter_target(e)) + } + + fn filter_select(&mut self, target: Entity) -> Option { + self.filter_target(target) + } + + fn on_click(&mut self, hovered: Hover) -> Option, - mut hover: EventWriter, - blockers: Option>, - workspace: Res, - open_sites: Query>, - current_drawing: Res, -) { - let mut request = match &*mode { - InteractionMode::SelectAnchor(request) => request.clone(), - _ => { - return; - } - }; - - if mode.is_changed() { - // The mode was changed to this one on this update cycle. We should - // check if something besides an anchor is being hovered, and clear it - // out if it is. - if let Some(hovering) = hovering.0 { - if anchors.contains(hovering) { - params - .cursor - .remove_mode(SELECT_ANCHOR_MODE_LABEL, &mut params.visibility); - } else { - hover.send(Hover(None)); - params - .cursor - .add_mode(SELECT_ANCHOR_MODE_LABEL, &mut params.visibility); - } - } else { - params - .cursor - .add_mode(SELECT_ANCHOR_MODE_LABEL, &mut params.visibility); - } - - // Make the anchor placement component of the cursor visible - if request.site_scope() { - set_visibility( - params.cursor.site_anchor_placement, - &mut params.visibility, - true, - ); - } else { - set_visibility( - params.cursor.level_anchor_placement, - &mut params.visibility, - true, - ); - } - - match request.scope { - Scope::General | Scope::Site => { - // If we are working with normal level or site requests, hide all drawing anchors - for anchor in params.anchors.iter().filter(|(e, _)| { - params - .parents - .get(*e) - .is_ok_and(|p| params.drawings.get(**p).is_ok()) - }) { - set_visibility(anchor.0, &mut params.visibility, false); - params.hidden_entities.drawing_anchors.insert(anchor.0); - } - } - // Nothing to hide, it's done by the drawing editor plugin - Scope::Drawing => {} - } - - // If we are creating a new object, then we should deselect anything - // that might be currently selected. - if request.begin_creating() { - if let Some(previous_selection) = selection.0 { - if let Ok(mut selected) = selected.get_mut(previous_selection) { - selected.is_selected = false; - } - selection.0 = None; - } - } - - if request.continuity.needs_original() { - // Keep track of the original anchor that we intend to replace so - // that we can revert any previews. - let for_element = match request.target { - Some(for_element) => for_element, - None => { - error!( - "for_element must be Some for ReplaceAnchor. \ - Reverting to Inspect Mode." - ); - params.cleanup(); - *mode = InteractionMode::Inspect; - return; - } - }; - - let original = match request.placement.save_original(for_element, &mut params) { - Some(original) => original, - None => { - error!( - "cannot locate an original anchor for \ - entity {:?}. Reverting to Inspect Mode.", - for_element, - ); - params.cleanup(); - *mode = InteractionMode::Inspect; - return; - } - }; - - request.continuity = SelectAnchorContinuity::ReplaceAnchor { - original_anchor: Some(original), - }; - // Save the new mode here in case it doesn't get saved by any - // branches in the rest of this system function. - *mode = InteractionMode::SelectAnchor(request.clone()); - } - } - - if hovering.is_changed() { - if hovering.0.is_none() { - params - .cursor - .add_mode(SELECT_ANCHOR_MODE_LABEL, &mut params.visibility); - } else { - params - .cursor - .remove_mode(SELECT_ANCHOR_MODE_LABEL, &mut params.visibility); - } - } - - if select.is_empty() { - let clicked = mouse_button_input.just_pressed(MouseButton::Left) - || touch_input.iter_just_pressed().next().is_some(); - let blocked = blockers.filter(|x| x.blocking()).is_some(); - - if clicked && !blocked { - // Since the user clicked but there are no actual selections, the - // user is effectively asking to create a new anchor at the current - // cursor location. We will create that anchor and treat it as if it - // were selected. - let tf = match transforms.get(params.cursor.frame) { - Ok(tf) => tf, - Err(_) => { - error!( - "Could not get transform for cursor frame \ - {:?} in SelectAnchor mode.", - params.cursor.frame, - ); - // TODO(MXG): Put in backout behavior here. - return; - } - }; - - let new_anchor = match request.scope { - Scope::Site => { - let site = workspace.to_site(&open_sites).expect("No current site??"); - let new_anchor = params.commands.spawn(AnchorBundle::at_transform(tf)).id(); - params.commands.entity(site).add_child(new_anchor); - new_anchor - } - Scope::Drawing => { - let drawing_entity = current_drawing - .target() - .expect("No drawing while spawning drawing anchor") - .drawing; - let (parent, ppm) = params - .drawings - .get(drawing_entity) - .expect("Entity being edited is not a drawing"); - // We also need to have a transform such that the anchor will spawn in the - // right spot - let pose = compute_parent_inverse_pose(&tf, &transforms, parent); - let ppm = ppm.0; - let new_anchor = params - .commands - .spawn(AnchorBundle::new([pose.trans[0], pose.trans[1]].into())) - .insert(Transform::from_scale(Vec3::new(ppm, ppm, 1.0))) - .set_parent(parent) - .id(); - new_anchor - } - Scope::General => params.commands.spawn(AnchorBundle::at_transform(tf)).id(), - }; - - request = match request.next(AnchorSelection::new(new_anchor), &mut params) { - Some(next_mode) => next_mode, - None => { - params.cleanup(); - *mode = InteractionMode::Inspect; - return; - } - }; - - *mode = InteractionMode::SelectAnchor(request); - } else { - // Offer a preview based on the current hovering status - let hovered = hovering.0.unwrap_or(params.cursor.level_anchor_placement); - let current = request - .target - .map(|target| request.placement.current(target, ¶ms)) - .flatten(); - - if Some(hovered) != current { - // We should only call this function if the current hovered - // anchor is not the one currently assigned. Otherwise we - // are wasting query+command effort. - match request.preview(hovered, &mut params) { - PreviewResult::Updated(next) => { - *mode = InteractionMode::SelectAnchor(next); - } - PreviewResult::Updated3D(next) => { - *mode = InteractionMode::SelectAnchor3D(next); - } - PreviewResult::Unchanged => { - // Do nothing, the mode has not changed - } - PreviewResult::Invalid => { - // Something was invalid about the request, so we - // will exit back to Inspect mode. - params.cleanup(); - *mode = InteractionMode::Inspect; - } - }; - } - } - } else { - for new_selection in select - .read() - .filter_map(|s| s.0) - .filter(|s| anchors.contains(*s)) - { - request = match request.next(AnchorSelection::existing(new_selection), &mut params) { - Some(next_mode) => next_mode, - None => { - params.cleanup(); - *mode = InteractionMode::Inspect; - return; - } - }; - } - - *mode = InteractionMode::SelectAnchor(request); - } -} - -fn compute_parent_inverse_pose( - tf: &GlobalTransform, - transforms: &Query<&GlobalTransform>, - parent: Entity, -) -> Pose { - let parent_tf = transforms - .get(parent) - .expect("Failed in fetching parent transform"); - - let inv_tf = parent_tf.affine().inverse(); - let goal_tf = tf.affine(); - let mut pose = Pose::default(); - pose.rot = pose.rot.as_euler_extrinsic_xyz(); - pose.align_with(&Transform::from_matrix((inv_tf * goal_tf).into())) -} - -pub fn handle_select_anchor_3d_mode( - mut mode: ResMut, - anchors: Query<(), With>, - transforms: Query<&GlobalTransform>, - hovering: Res, - mouse_button_input: Res>, - touch_input: Res, - mut params: SelectAnchorPlacementParams, - selection: Res, - mut select: EventReader