diff --git a/Cargo.lock b/Cargo.lock index 2a2e86c440..b4b8de3d1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,59 +18,6 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" -[[package]] -name = "accesskit" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76eb1adf08c5bcaa8490b9851fd53cca27fa9880076f178ea9d29f05196728a8" - -[[package]] -name = "accesskit_consumer" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04bb4d9e4772fe0d47df57d0d5dbe5d85dd05e2f37ae1ddb6b105e76be58fb00" -dependencies = [ - "accesskit", -] - -[[package]] -name = "accesskit_macos" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134d0acf6acb667c89d3332999b1a5df4edbc8d6113910f392ebb73f2b03bb56" -dependencies = [ - "accesskit", - "accesskit_consumer", - "objc2 0.3.0-beta.3.patch-leaks.3", - "once_cell", -] - -[[package]] -name = "accesskit_windows" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eac0a7f2d7cd7a93b938af401d3d8e8b7094217989a7c25c55a953023436e31" -dependencies = [ - "accesskit", - "accesskit_consumer", - "arrayvec", - "once_cell", - "paste", - "windows 0.48.0", -] - -[[package]] -name = "accesskit_winit" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "825d23acee1bd6d25cbaa3ca6ed6e73faf24122a774ec33d52c5c86c6ab423c0" -dependencies = [ - "accesskit", - "accesskit_macos", - "accesskit_windows", - "winit", -] - [[package]] name = "acto" version = "0.7.1" @@ -152,7 +99,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" dependencies = [ "alsa-sys", - "bitflags 2.6.0", + "bitflags 2.9.1", "cfg-if", "libc", ] @@ -169,20 +116,23 @@ dependencies = [ [[package]] name = "android-activity" -version = "0.4.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64529721f27c2314ced0890ce45e469574a73e5e6fdd6e9da1860eb29285f5e0" +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", - "bitflags 1.3.2", + "bitflags 2.9.1", "cc", + "cesu8", + "jni 0.21.1", "jni-sys", "libc", "log", - "ndk 0.7.0", + "ndk 0.9.0", "ndk-context", - "ndk-sys 0.4.1+23.1.7779620", - "num_enum 0.6.1", + "ndk-sys 0.6.0+11769913", + "num_enum", + "thiserror 1.0.69", ] [[package]] @@ -197,12 +147,6 @@ 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" @@ -263,9 +207,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.87" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "append-only-vec" @@ -273,15 +217,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74d9f7083455f1a474276ccd32374958d2cb591024aac45101c7623b10271347" -[[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.0" @@ -289,10 +224,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fb4009533e8ff8f1450a5bcbc30f4242a1d34442221f72314bea1f5dc9c7f89" dependencies = [ "clipboard-win", - "core-graphics 0.23.2", - "image 0.25.2", + "core-graphics", + "image 0.25.6", "log", - "objc2 0.5.2", + "objc2", "objc2-app-kit", "objc2-foundation", "parking_lot", @@ -312,13 +247,19 @@ 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" +version = "0.38.0+1.3.281" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" dependencies = [ - "libloading 0.7.4", + "libloading", ] [[package]] @@ -333,7 +274,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 1.0.63", + "thiserror 1.0.69", "time", ] @@ -345,7 +286,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", "synstructure", ] @@ -357,7 +298,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -392,7 +333,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -409,7 +350,7 @@ checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -482,12 +423,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[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" @@ -500,154 +435,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "bevy" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91c6d3ec4f89e85294dc97334c5b271ddc301fdf67ac9bb994fe44d9273e6ed7" -dependencies = [ - "bevy_internal", -] - -[[package]] -name = "bevy_a11y" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "132c9e35a77c5395951f6d25fa2c52ee92296353426df4f961e60f3ff47e2e42" -dependencies = [ - "accesskit", - "bevy_app", - "bevy_derive", - "bevy_ecs 0.11.3", -] - -[[package]] -name = "bevy_app" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f557a7d59e1e16892d7544fc37316506ee598cb5310ef0365125a30783c11531" -dependencies = [ - "bevy_derive", - "bevy_ecs 0.11.3", - "bevy_reflect 0.11.3", - "bevy_tasks 0.11.3", - "bevy_utils 0.11.3", - "downcast-rs", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "bevy_asset" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9714af523da4cdf58c42a317e5ed40349708ad954a18533991fd64c8ae0a6f68" -dependencies = [ - "anyhow", - "async-channel", - "bevy_app", - "bevy_diagnostic", - "bevy_ecs 0.11.3", - "bevy_log", - "bevy_reflect 0.11.3", - "bevy_tasks 0.11.3", - "bevy_utils 0.11.3", - "bevy_winit", - "crossbeam-channel", - "downcast-rs", - "fastrand 1.9.0", - "js-sys", - "parking_lot", - "serde", - "thiserror 1.0.63", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "bevy_core" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d5272321be5fcf5ce2fb16023bc825bb10dfcb71611117296537181ce950f48" -dependencies = [ - "bevy_app", - "bevy_ecs 0.11.3", - "bevy_math", - "bevy_reflect 0.11.3", - "bevy_tasks 0.11.3", - "bevy_utils 0.11.3", - "bytemuck", -] - -[[package]] -name = "bevy_core_pipeline" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67382fa9c96ce4f4e5833ed7cedd9886844a8f3284b4a717bd4ac738dcdea0c3" -dependencies = [ - "bevy_app", - "bevy_asset", - "bevy_core", - "bevy_derive", - "bevy_ecs 0.11.3", - "bevy_math", - "bevy_reflect 0.11.3", - "bevy_render", - "bevy_transform", - "bevy_utils 0.11.3", - "bitflags 2.6.0", - "radsort", - "serde", -] - -[[package]] -name = "bevy_derive" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44e4e2784a81430199e4157e02903a987a32127c773985506f020e7d501b62e" -dependencies = [ - "bevy_macro_utils 0.11.3", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "bevy_diagnostic" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6babb230dc383c98fdfc9603e3a7a2a49e1e2879dbe8291059ef37dca897932e" -dependencies = [ - "bevy_app", - "bevy_core", - "bevy_ecs 0.11.3", - "bevy_log", - "bevy_time", - "bevy_utils 0.11.3", - "sysinfo", -] - -[[package]] -name = "bevy_ecs" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266144b36df7e834d5198049e037ecdf2a2310a76ce39ed937d1b0a6a2c4e8c6" -dependencies = [ - "async-channel", - "bevy_ecs_macros 0.11.3", - "bevy_ptr 0.11.3", - "bevy_reflect 0.11.3", - "bevy_tasks 0.11.3", - "bevy_utils 0.11.3", - "downcast-rs", - "event-listener 2.5.3", - "fixedbitset", - "rustc-hash 1.1.0", - "serde", - "thiserror 1.0.63", - "thread_local", -] - [[package]] name = "bevy_ecs" version = "0.12.1" @@ -655,423 +442,77 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7709fbd22f81fb681534cd913c41e1cd18b17143368743281195d7f024b61aea" dependencies = [ "async-channel", - "bevy_ecs_macros 0.12.1", - "bevy_ptr 0.12.1", - "bevy_reflect 0.12.1", + "bevy_ecs_macros", + "bevy_ptr", + "bevy_reflect", "bevy_tasks 0.12.1", - "bevy_utils 0.12.1", - "downcast-rs", - "event-listener 2.5.3", - "fixedbitset", - "rustc-hash 1.1.0", - "serde", - "thiserror 1.0.63", - "thread_local", -] - -[[package]] -name = "bevy_ecs_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7157a9c3be038d5008ee3f114feb6cf6b39c1d3d32ee21a7cacb8f81fccdfa80" -dependencies = [ - "bevy_macro_utils 0.11.3", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "bevy_ecs_macros" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8843aa489f159f25cdcd9fee75cd7d221a7098a71eaa72cb2d6b40ac4e3f1ba" -dependencies = [ - "bevy_macro_utils 0.12.1", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "bevy_egui" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb1c1f6ad293c60fd8559c4502cda5e832e92b0e0f3d994929b33f24d4352d70" -dependencies = [ - "arboard", - "bevy", - "egui", - "thread_local", - "webbrowser", -] - -[[package]] -name = "bevy_encase_derive" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ac0f55ad6bca1be7b0f35bbd5fc95ed3d31e4e9db158fee8e5327f59006001" -dependencies = [ - "bevy_macro_utils 0.11.3", - "encase_derive_impl", -] - -[[package]] -name = "bevy_gizmos" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e286a3e7276431963f4aa29165ea5429fa7dbbc6d5c5ba0c531e7dd44ecc88a2" -dependencies = [ - "bevy_app", - "bevy_asset", - "bevy_core", - "bevy_core_pipeline", - "bevy_ecs 0.11.3", - "bevy_math", - "bevy_reflect 0.11.3", - "bevy_render", - "bevy_sprite", - "bevy_transform", - "bevy_utils 0.11.3", -] - -[[package]] -name = "bevy_hierarchy" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "103f8f58416ac6799b8c7f0b418f1fac9eba44fa924df3b0e16b09256b897e3d" -dependencies = [ - "bevy_app", - "bevy_core", - "bevy_ecs 0.11.3", - "bevy_log", - "bevy_reflect 0.11.3", - "bevy_utils 0.11.3", - "smallvec", -] - -[[package]] -name = "bevy_input" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbd935401101ac8003f3c3aea70788c65ad03f7a32716a10608bedda7a648bc" -dependencies = [ - "bevy_app", - "bevy_ecs 0.11.3", - "bevy_math", - "bevy_reflect 0.11.3", - "bevy_utils 0.11.3", - "thiserror 1.0.63", -] - -[[package]] -name = "bevy_internal" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0e35a9b2bd29aa784b3cc416bcbf2a298f69f00ca51fd042ea39d9af7fad37e" -dependencies = [ - "bevy_a11y", - "bevy_app", - "bevy_asset", - "bevy_core", - "bevy_core_pipeline", - "bevy_derive", - "bevy_diagnostic", - "bevy_ecs 0.11.3", - "bevy_gizmos", - "bevy_hierarchy", - "bevy_input", - "bevy_log", - "bevy_math", - "bevy_pbr", - "bevy_ptr 0.11.3", - "bevy_reflect 0.11.3", - "bevy_render", - "bevy_scene", - "bevy_sprite", - "bevy_tasks 0.11.3", - "bevy_time", - "bevy_transform", - "bevy_utils 0.11.3", - "bevy_window", - "bevy_winit", -] - -[[package]] -name = "bevy_log" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07dcc615ff4f617b06c3f9522fca3c55d56f9644db293318f8ab68fcdea5d4fe" -dependencies = [ - "android_log-sys", - "bevy_app", - "bevy_ecs 0.11.3", - "bevy_utils 0.11.3", - "console_error_panic_hook", - "tracing-log 0.1.4", - "tracing-subscriber", - "tracing-wasm", -] - -[[package]] -name = "bevy_macro_utils" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23ddc18d489b4e57832d4958cde7cd2f349f0ad91e5892ac9e2f2ee16546b981" -dependencies = [ - "quote", - "rustc-hash 1.1.0", - "syn 2.0.90", - "toml_edit 0.19.15", -] - -[[package]] -name = "bevy_macro_utils" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e566640c6b6dced73d2006c764c2cffebe1a82be4809486c4a5d7b4b50efed4d" -dependencies = [ - "proc-macro2", - "quote", - "rustc-hash 1.1.0", - "syn 2.0.90", - "toml_edit 0.20.7", -] - -[[package]] -name = "bevy_math" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78286a81fead796dc4b45ab14f4f02fe29a94423d3587bcfef872b2a8e0a474b" -dependencies = [ - "glam 0.24.2", - "serde", -] - -[[package]] -name = "bevy_mikktspace" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cfc2a21ea47970a9b1f0f4735af3256a8f204815bd756110051d10f9d909497" -dependencies = [ - "glam 0.24.2", -] - -[[package]] -name = "bevy_pbr" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63ca796a619e61cd43a0a3b11fde54644f7f0732a1fba1eef5d406248c6eba85" -dependencies = [ - "bevy_app", - "bevy_asset", - "bevy_core_pipeline", - "bevy_derive", - "bevy_ecs 0.11.3", - "bevy_math", - "bevy_reflect 0.11.3", - "bevy_render", - "bevy_transform", - "bevy_utils 0.11.3", - "bevy_window", - "bitflags 2.6.0", - "bytemuck", - "naga_oil", - "radsort", -] - -[[package]] -name = "bevy_prototype_lyon" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e347c16caede05dc5f774ba388cefeef0ab558a5601fc6b5ffd6606bef77308" -dependencies = [ - "bevy", - "lyon_algorithms", - "lyon_tessellation", - "svgtypes", -] - -[[package]] -name = "bevy_ptr" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c7586401a46f7d8e436028225c1df5288f2e0082d066b247a82466fea155c6" - -[[package]] -name = "bevy_ptr" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77ec20c8fafcdc196508ef5ccb4f0400a8d193cb61f7b14a36ed9a25ad423cf" - -[[package]] -name = "bevy_reflect" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0778197a1eb3e095a71417c74b7152ede02975cdc95b5ea4ddc5251ed00a2eb5" -dependencies = [ - "bevy_math", - "bevy_ptr 0.11.3", - "bevy_reflect_derive 0.11.3", - "bevy_utils 0.11.3", - "downcast-rs", - "erased-serde 0.3.31", - "glam 0.24.2", - "once_cell", - "parking_lot", - "serde", - "smallvec", - "smol_str 0.2.2", - "thiserror 1.0.63", -] - -[[package]] -name = "bevy_reflect" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7921f15fc944c9c8ad01d7dbcea6505b8909c6655cd9382bab1407181556038" -dependencies = [ - "bevy_ptr 0.12.1", - "bevy_reflect_derive 0.12.1", - "bevy_utils 0.12.1", + "bevy_utils", "downcast-rs", - "erased-serde 0.3.31", - "serde", - "thiserror 1.0.63", -] - -[[package]] -name = "bevy_reflect_derive" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342a4b2d09db22c48607d23ad59a056aff1ee004549050a51d490d375ba29528" -dependencies = [ - "bevy_macro_utils 0.11.3", - "bit-set", - "proc-macro2", - "quote", - "syn 2.0.90", - "uuid", -] - -[[package]] -name = "bevy_reflect_derive" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a8c5475f216e751ef4452a1306b00711f33d2d04d9f149e4c845dfeb6753a0" -dependencies = [ - "bevy_macro_utils 0.12.1", - "proc-macro2", - "quote", - "syn 2.0.90", - "uuid", -] - -[[package]] -name = "bevy_render" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39df4824b760928c27afc7b00fb649c7a63c9d76661ab014ff5c86537ee906cb" -dependencies = [ - "anyhow", - "async-channel", - "bevy_app", - "bevy_asset", - "bevy_core", - "bevy_derive", - "bevy_ecs 0.11.3", - "bevy_encase_derive", - "bevy_hierarchy", - "bevy_log", - "bevy_math", - "bevy_mikktspace", - "bevy_reflect 0.11.3", - "bevy_render_macros", - "bevy_tasks 0.11.3", - "bevy_time", - "bevy_transform", - "bevy_utils 0.11.3", - "bevy_window", - "bitflags 2.6.0", - "bytemuck", - "codespan-reporting", - "downcast-rs", - "encase", - "futures-lite 1.13.0", - "hexasphere", - "image 0.24.9", - "js-sys", - "naga", - "naga_oil", - "parking_lot", - "regex", + "event-listener 2.5.3", + "fixedbitset", + "rustc-hash 1.1.0", "serde", - "smallvec", - "thiserror 1.0.63", + "thiserror 1.0.69", "thread_local", - "wasm-bindgen", - "web-sys", - "wgpu", - "wgpu-hal", ] [[package]] -name = "bevy_render_macros" -version = "0.11.3" +name = "bevy_ecs_macros" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd08c740aac73363e32fb45af869b10cec65bcb76fe3e6cd0f8f7eebf4c36c9" +checksum = "a8843aa489f159f25cdcd9fee75cd7d221a7098a71eaa72cb2d6b40ac4e3f1ba" dependencies = [ - "bevy_macro_utils 0.11.3", + "bevy_macro_utils", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] -name = "bevy_scene" -version = "0.11.3" +name = "bevy_macro_utils" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd47e1263506153bef3a8be97fe2d856f206d315668c4f97510ca6cc181d9681" +checksum = "e566640c6b6dced73d2006c764c2cffebe1a82be4809486c4a5d7b4b50efed4d" dependencies = [ - "anyhow", - "bevy_app", - "bevy_asset", - "bevy_derive", - "bevy_ecs 0.11.3", - "bevy_hierarchy", - "bevy_reflect 0.11.3", - "bevy_render", - "bevy_transform", - "bevy_utils 0.11.3", - "ron", + "proc-macro2", + "quote", + "rustc-hash 1.1.0", + "syn 2.0.104", + "toml_edit 0.20.7", +] + +[[package]] +name = "bevy_ptr" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77ec20c8fafcdc196508ef5ccb4f0400a8d193cb61f7b14a36ed9a25ad423cf" + +[[package]] +name = "bevy_reflect" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7921f15fc944c9c8ad01d7dbcea6505b8909c6655cd9382bab1407181556038" +dependencies = [ + "bevy_ptr", + "bevy_reflect_derive", + "bevy_utils", + "downcast-rs", + "erased-serde 0.3.31", "serde", - "thiserror 1.0.63", - "uuid", + "thiserror 1.0.69", ] [[package]] -name = "bevy_sprite" -version = "0.11.3" +name = "bevy_reflect_derive" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a8ca824fad75c6ef74cfbbba0a4ce3ccc435fa23d6bf3f003f260548813397" -dependencies = [ - "bevy_app", - "bevy_asset", - "bevy_core_pipeline", - "bevy_derive", - "bevy_ecs 0.11.3", - "bevy_log", - "bevy_math", - "bevy_reflect 0.11.3", - "bevy_render", - "bevy_transform", - "bevy_utils 0.11.3", - "bitflags 2.6.0", - "bytemuck", - "fixedbitset", - "guillotiere", - "rectangle-pack", - "thiserror 1.0.63", +checksum = "b4a8c5475f216e751ef4452a1306b00711f33d2d04d9f149e4c845dfeb6753a0" +dependencies = [ + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn 2.0.104", + "uuid", ] [[package]] @@ -1102,50 +543,6 @@ dependencies = [ "wasm-bindgen-futures", ] -[[package]] -name = "bevy_time" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d58d6dbae9c8225d8c0e0f04d2c5dbb71d22adc01ecd5ab3cebc364139e4a6d" -dependencies = [ - "bevy_app", - "bevy_ecs 0.11.3", - "bevy_reflect 0.11.3", - "bevy_utils 0.11.3", - "crossbeam-channel", - "thiserror 1.0.63", -] - -[[package]] -name = "bevy_transform" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9b0ac0149a57cd846cb357a35fc99286f9848e53d4481954608ac9552ed2d4" -dependencies = [ - "bevy_app", - "bevy_ecs 0.11.3", - "bevy_hierarchy", - "bevy_math", - "bevy_reflect 0.11.3", -] - -[[package]] -name = "bevy_utils" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d9484e32434ea84dc548cff246ce0c6f756c1336f5ea03f24ac120a48595c7" -dependencies = [ - "ahash", - "bevy_utils_proc_macros 0.11.3", - "getrandom", - "hashbrown 0.14.5", - "instant", - "petgraph", - "thiserror 1.0.63", - "tracing", - "uuid", -] - [[package]] name = "bevy_utils" version = "0.12.1" @@ -1153,28 +550,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7915222f4a08ccc782e08d10b751b42e5f9d786e697d0cb3fd09333cb7e8b6ea" dependencies = [ "ahash", - "bevy_utils_proc_macros 0.12.1", + "bevy_utils_proc_macros", "getrandom", "hashbrown 0.14.5", "instant", "nonmax", "petgraph", - "thiserror 1.0.63", + "thiserror 1.0.69", "tracing", "uuid", ] -[[package]] -name = "bevy_utils_proc_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5391b242c36f556db01d5891444730c83aa9dd648b6a8fd2b755d22cb3bddb57" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - [[package]] name = "bevy_utils_proc_macros" version = "0.12.1" @@ -1183,47 +569,7 @@ checksum = "7aafecc952b6b8eb1a93c12590bd867d25df2f4ae1033a01dfdfc3c35ebccfff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", -] - -[[package]] -name = "bevy_window" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd584c0da7c4ada6557b09f57f30fb7cff21ccedc641473fc391574b4c9b7944" -dependencies = [ - "bevy_app", - "bevy_ecs 0.11.3", - "bevy_input", - "bevy_math", - "bevy_reflect 0.11.3", - "bevy_utils 0.11.3", - "raw-window-handle", -] - -[[package]] -name = "bevy_winit" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdc044abdb95790c20053e6326760f0a2985f0dcd78613d397bf35f16039d53" -dependencies = [ - "accesskit_winit", - "approx", - "bevy_a11y", - "bevy_app", - "bevy_derive", - "bevy_ecs 0.11.3", - "bevy_hierarchy", - "bevy_input", - "bevy_math", - "bevy_tasks 0.11.3", - "bevy_utils 0.11.3", - "bevy_window", - "crossbeam-channel", - "raw-window-handle", - "wasm-bindgen", - "web-sys", - "winit", + "syn 2.0.104", ] [[package]] @@ -1241,7 +587,7 @@ version = "0.69.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "cexpr", "clang-sys", "itertools", @@ -1252,23 +598,29 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] name = "bit-set" -version = "0.5.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" -version = "0.6.3" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bit_field" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" [[package]] name = "bitfield-rle" @@ -1288,9 +640,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" dependencies = [ "serde", ] @@ -1341,32 +693,13 @@ 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 = "block2" -version = "0.2.0-alpha.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42" -dependencies = [ - "block-sys", - "objc2-encode 2.0.0-pre.2", -] - [[package]] name = "block2" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" dependencies = [ - "objc2 0.5.2", + "objc2", ] [[package]] @@ -1403,22 +736,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "bones_bevy_renderer" -version = "0.4.0" -dependencies = [ - "anyhow", - "bevy", - "bevy_egui", - "bevy_prototype_lyon", - "bones_framework", - "directories", - "glam 0.24.2", - "serde", - "serde_yaml", - "web-sys", -] - [[package]] name = "bones_ecs" version = "0.4.0" @@ -1434,7 +751,7 @@ dependencies = [ "once_map", "paste", "serde", - "thiserror 1.0.63", + "thiserror 1.0.69", "tracing", ] @@ -1442,7 +759,7 @@ dependencies = [ name = "bones_ecs_macros" version = "0.4.0" dependencies = [ - "bevy_ecs 0.12.1", + "bevy_ecs", "bones_ecs", "bones_ecs_macros_core", "bones_schema", @@ -1456,7 +773,7 @@ dependencies = [ "pretty_assertions", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -1504,7 +821,7 @@ dependencies = [ "serde_yaml", "smallvec", "sys-locale", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", "tracing", "tracing-appender", @@ -1627,6 +944,33 @@ dependencies = [ "venial", ] +[[package]] +name = "bones_wgpu_renderer" +version = "0.4.0" +dependencies = [ + "anyhow", + "bevy_tasks 0.11.3", + "bones_framework", + "bones_schema", + "bytemuck", + "crossbeam-channel", + "directories", + "egui", + "egui-wgpu", + "egui-winit", + "env_logger", + "guillotiere", + "image 0.24.9", + "log", + "lyon", + "pollster", + "profiling", + "serde", + "serde_yaml", + "wgpu", + "winit", +] + [[package]] name = "bounded-integer" version = "0.5.7" @@ -1656,9 +1000,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.18.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" dependencies = [ "bytemuck_derive", ] @@ -1671,7 +1015,7 @@ checksum = "0cc8b54b395f2fcfbb3d90c47b01c7f444d94d05bdeb775811dec868ac3bbc26" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -1692,6 +1036,32 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +[[package]] +name = "calloop" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" +dependencies = [ + "bitflags 2.9.1", + "log", + "polling 3.9.0", + "rustix 0.38.36", + "slab", + "thiserror 1.0.69", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" +dependencies = [ + "calloop", + "rustix 0.38.36", + "wayland-backend", + "wayland-client", +] + [[package]] name = "cc" version = "1.1.18" @@ -1724,12 +1094,6 @@ 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" @@ -1779,7 +1143,7 @@ checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", - "libloading 0.8.5", + "libloading", ] [[package]] @@ -1813,7 +1177,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -1859,12 +1223,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" -[[package]] -name = "com-rs" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf43edc576402991846b093a7ca18a3477e0ef9c588cde84964b5d3e43016642" - [[package]] name = "combine" version = "4.6.7" @@ -1884,49 +1242,18 @@ 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 = "const-oid" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[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 = "cordyceps" version = "0.3.2" @@ -1963,19 +1290,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "core-graphics" -version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.4", - "core-graphics-types", - "foreign-types 0.3.2", - "libc", -] - [[package]] name = "core-graphics" version = "0.23.2" @@ -1985,7 +1299,7 @@ dependencies = [ "bitflags 1.3.2", "core-foundation 0.9.4", "core-graphics-types", - "foreign-types 0.5.0", + "foreign-types", "libc", ] @@ -2084,9 +1398,28 @@ checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242" [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] @@ -2097,6 +1430,12 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -2161,6 +1500,12 @@ dependencies = [ "phf", ] +[[package]] +name = "cursor-icon" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" + [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -2185,18 +1530,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", -] - -[[package]] -name = "d3d12" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8f0de2f5a8e7bd4a9eec0e3c781992a4ce1724f68aec7d7a3715344de8b39da" -dependencies = [ - "bitflags 1.3.2", - "libloading 0.7.4", - "winapi", + "syn 2.0.104", ] [[package]] @@ -2242,40 +1576,48 @@ checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" name = "demo_asset_packs" version = "0.4.0" dependencies = [ - "bones_bevy_renderer", "bones_framework", + "bones_wgpu_renderer", ] [[package]] name = "demo_assets_minimal" version = "0.4.0" dependencies = [ - "bones_bevy_renderer", "bones_framework", + "bones_wgpu_renderer", ] [[package]] name = "demo_features" version = "0.4.0" dependencies = [ - "bones_bevy_renderer", "bones_framework", + "bones_wgpu_renderer", ] [[package]] name = "demo_hello_world" version = "0.4.0" dependencies = [ - "bones_bevy_renderer", "bones_framework", + "bones_wgpu_renderer", +] + +[[package]] +name = "demo_hello_world_wgpu" +version = "0.4.0" +dependencies = [ + "bones_framework", + "bones_wgpu_renderer", ] [[package]] name = "demo_scripting" version = "0.4.0" dependencies = [ - "bones_bevy_renderer", "bones_framework", + "bones_wgpu_renderer", ] [[package]] @@ -2311,7 +1653,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -2341,7 +1683,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", "unicode-xid", ] @@ -2404,7 +1746,16 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", +] + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", ] [[package]] @@ -2431,7 +1782,13 @@ dependencies = [ name = "downcast-rs" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" [[package]] name = "dtoa" @@ -2461,11 +1818,12 @@ dependencies = [ [[package]] name = "ecolor" -version = "0.23.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfdf4e52dbbb615cfd30cf5a5265335c217b5fd8d669593cea74a517d9c605af" +checksum = "bc4feb366740ded31a004a0e4452fbf84e80ef432ecf8314c485210229672fd1" dependencies = [ "bytemuck", + "emath", ] [[package]] @@ -2496,22 +1854,66 @@ dependencies = [ [[package]] name = "egui" -version = "0.23.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd69fed5fcf4fbb8225b24e80ea6193b61e17a625db105ef0c4d71dde6eb8b7" +checksum = "25dd34cec49ab55d85ebf70139cb1ccd29c977ef6b6ba4fe85489d6877ee9ef3" dependencies = [ "ahash", + "bitflags 2.9.1", + "emath", "epaint", + "log", "nohash-hasher", + "profiling", +] + +[[package]] +name = "egui-wgpu" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d319dfef570f699b6e9114e235e862a2ddcf75f0d1a061de9e1328d92146d820" +dependencies = [ + "ahash", + "bytemuck", + "document-features", + "egui", + "epaint", + "log", + "profiling", + "thiserror 1.0.69", + "type-map", + "web-time", + "wgpu", +] + +[[package]] +name = "egui-winit" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d9dfbb78fe4eb9c3a39ad528b90ee5915c252e77bbab9d4ebc576541ab67e13" +dependencies = [ + "ahash", + "arboard", + "bytemuck", + "egui", + "log", + "profiling", + "raw-window-handle", + "smithay-clipboard", + "web-time", + "webbrowser", + "winit", ] [[package]] name = "egui_plot" -version = "0.23.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f33a00fe8eb1ba56535b3dbacdecc7a1365a328908a97c5f3c81bb466be72b" +checksum = "1794c66fb727dac28dffed2e4b548e5118d1cccc331d368a35411d68725dde71" dependencies = [ + "ahash", "egui", + "emath", ] [[package]] @@ -2564,9 +1966,9 @@ dependencies = [ [[package]] name = "emath" -version = "0.23.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ef2b29de53074e575c18b694167ccbe6e5191f7b25fe65175a0d905a32eeec0" +checksum = "9e4cadcff7a5353ba72b7fea76bf2122b5ebdbc68e8155aa56dfdea90083fe1b" dependencies = [ "bytemuck", ] @@ -2583,38 +1985,6 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" -[[package]] -name = "encase" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fce2eeef77fd4a293a54b62aa00ac9daebfbcda4bf8998c5a815635b004aa1c" -dependencies = [ - "const_panic", - "encase_derive", - "glam 0.24.2", - "thiserror 1.0.63", -] - -[[package]] -name = "encase_derive" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e520cde08cbf4f7cc097f61573ec06ce467019803de8ae82fb2823fa1554a0e" -dependencies = [ - "encase_derive_impl", -] - -[[package]] -name = "encase_derive_impl" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fe2568f851fd6144a45fa91cfed8fe5ca8fc0b56ba6797bfc1ed2771b90e37c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - [[package]] name = "encoding_rs" version = "0.8.34" @@ -2633,7 +2003,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -2653,24 +2023,56 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", +] + +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", ] [[package]] name = "epaint" -version = "0.23.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58067b840d009143934d91d8dcb8ded054d8301d7c11a517ace0a99bb1e1595e" +checksum = "41fcc0f5a7c613afd2dee5e4b30c3e6acafb8ad6f0edb06068811f708a67c562" dependencies = [ "ab_glyph", "ahash", "bytemuck", "ecolor", "emath", + "epaint_default_fonts", + "log", "nohash-hasher", "parking_lot", + "profiling", ] +[[package]] +name = "epaint_default_fonts" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7e7a64c02cf7a5b51e745a9e45f60660a286f151c238b9d397b3e923f5082f" + [[package]] name = "equivalent" version = "1.0.1" @@ -2704,12 +2106,12 @@ checksum = "a02a5d186d7bf1cb21f1f95e1a9cfa5c1f2dcd803a47aad454423ceec13525c5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -2744,6 +2146,21 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "exr" +version = "1.73.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide 0.8.0", + "rayon-core", + "smallvec", + "zune-inflate", +] + [[package]] name = "extended" version = "0.1.0" @@ -2871,7 +2288,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" dependencies = [ - "thiserror 1.0.63", + "thiserror 1.0.69", ] [[package]] @@ -2893,13 +2310,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "foreign-types" -version = "0.3.2" +name = "foldhash" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared 0.1.1", -] +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "foreign-types" @@ -2908,7 +2322,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared 0.3.1", + "foreign-types-shared", ] [[package]] @@ -2919,15 +2333,9 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -3069,7 +2477,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -3137,7 +2545,7 @@ checksum = "c612a69f5557a11046b77a7408d2836fe77077f842171cd211c5ef504bd3cddd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", "synstructure", ] @@ -3298,6 +2706,17 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +[[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.24.2" @@ -3326,9 +2745,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "glow" -version = "0.12.3" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0fe580e4b60a8ab24a868bc08e2f03cbcb20d3d676601fa909386713333728" +checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" dependencies = [ "js-sys", "slotmap", @@ -3336,6 +2755,15 @@ dependencies = [ "web-sys", ] +[[package]] +name = "glutin_wgl_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +dependencies = [ + "gl_generator", +] + [[package]] name = "governor" version = "0.7.0" @@ -3359,54 +2787,53 @@ dependencies = [ [[package]] name = "gpu-alloc" -version = "0.5.4" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22beaafc29b38204457ea030f6fb7a84c9e4dd1b86e311ba0542533453d87f62" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "gpu-alloc-types", ] [[package]] name = "gpu-alloc-types" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", ] [[package]] name = "gpu-allocator" -version = "0.22.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce95f9e2e11c2c6fadfce42b5af60005db06576f231f5c92550fdded43c423e8" +checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" dependencies = [ - "backtrace", "log", - "thiserror 1.0.63", - "winapi", - "windows 0.44.0", + "presser", + "thiserror 1.0.69", + "windows 0.58.0", ] [[package]] name = "gpu-descriptor" -version = "0.2.4" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "gpu-descriptor-types", - "hashbrown 0.14.5", + "hashbrown 0.15.4", ] [[package]] name = "gpu-descriptor-types" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", ] [[package]] @@ -3442,13 +2869,23 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.5.0", + "indexmap", "slab", "tokio", "tokio-util", "tracing", ] +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hash32" version = "0.2.1" @@ -3458,12 +2895,6 @@ 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" @@ -3476,18 +2907,12 @@ dependencies = [ ] [[package]] -name = "hassle-rs" -version = "0.10.0" +name = "hashbrown" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1397650ee315e8891a0df210707f0fc61771b0cc518c3023896064c5407cb3b0" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ - "bitflags 1.3.2", - "com-rs", - "libc", - "libloading 0.7.4", - "thiserror 1.0.63", - "widestring", - "winapi", + "foldhash", ] [[package]] @@ -3517,20 +2942,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] -name = "hex" -version = "0.4.3" +name = "hermit-abi" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] -name = "hexasphere" -version = "9.1.0" +name = "hex" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cb3df16a7bcb1b5bc092abd55e14f77ca70aea14445026e264586fc62889a10" -dependencies = [ - "constgebra", - "glam 0.24.2", -] +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hexf-parse" @@ -3555,7 +2976,7 @@ dependencies = [ "ipnet", "once_cell", "rand", - "thiserror 1.0.63", + "thiserror 1.0.69", "tinyvec", "tokio", "tracing", @@ -3580,7 +3001,7 @@ dependencies = [ "ipnet", "once_cell", "rand", - "thiserror 1.0.63", + "thiserror 1.0.69", "time", "tinyvec", "tokio", @@ -3604,7 +3025,7 @@ dependencies = [ "rand", "resolv-conf", "smallvec", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -3876,18 +3297,20 @@ dependencies = [ "bytemuck", "byteorder", "color_quant", + "exr", "gif", "jpeg-decoder", "num-traits", "png", + "qoi", "tiff", ] [[package]] name = "image" -version = "0.25.2" +version = "0.25.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" dependencies = [ "bytemuck", "byteorder-lite", @@ -3896,16 +3319,6 @@ dependencies = [ "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" @@ -3933,7 +3346,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "inotify-sys", "libc", ] @@ -4023,7 +3436,7 @@ checksum = "80b15215aea8d0367fefb9264521e4a251dc4e113896a3d765f530378518188f" dependencies = [ "anyhow", "backoff", - "base64 0.22.1", + "base64", "bytes", "der", "derive_more", @@ -4057,7 +3470,7 @@ dependencies = [ "netlink-packet-route 0.21.0", "netlink-sys", "netwatch", - "num_enum 0.7.3", + "num_enum", "once_cell", "parking_lot", "pin-project", @@ -4179,7 +3592,7 @@ dependencies = [ "reqwest", "rustls 0.23.12", "surge-ping", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", "tokio-util", "tracing", @@ -4199,7 +3612,7 @@ dependencies = [ "rustc-hash 2.0.0", "rustls 0.23.12", "socket2 0.5.7", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -4217,7 +3630,7 @@ dependencies = [ "rustls 0.23.12", "rustls-platform-verifier", "slab", - "thiserror 1.0.63", + "thiserror 1.0.69", "tinyvec", "tracing", ] @@ -4242,7 +3655,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28a0d0d7317795a01caa47ffdaeec84211d1b394530bdb31dbe15f642e58bcff" dependencies = [ "anyhow", - "base64 0.22.1", + "base64", "bytes", "clap", "derive_more", @@ -4264,7 +3677,7 @@ dependencies = [ "iroh-quinn", "iroh-quinn-proto", "libc", - "num_enum 0.7.3", + "num_enum", "once_cell", "parking_lot", "pin-project", @@ -4317,6 +3730,30 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "jni" version = "0.19.0" @@ -4327,7 +3764,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror 1.0.63", + "thiserror 1.0.69", "walkdir", ] @@ -4342,7 +3779,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror 1.0.63", + "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] @@ -4367,27 +3804,37 @@ 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" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "khronos-egl" -version = "4.1.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "libloading 0.7.4", + "libloading", "pkg-config", ] +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + [[package]] name = "kira" version = "0.9.5" @@ -4440,20 +3887,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] -name = "libc" -version = "0.2.158" +name = "lebe" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] -name = "libloading" -version = "0.7.4" +name = "libc" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libloading" @@ -4477,7 +3920,7 @@ version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "libc", "redox_syscall 0.4.1", ] @@ -4488,7 +3931,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "libc", "redox_syscall 0.5.3", ] @@ -4515,6 +3958,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + [[package]] name = "litrs" version = "0.4.1" @@ -4578,6 +4027,16 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "lyon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7f9cda98b5430809e63ca5197b06c7d191bf7e26dfc467d5a3f0290e2a74f" +dependencies = [ + "lyon_algorithms", + "lyon_tessellation", +] + [[package]] name = "lyon_algorithms" version = "1.0.4" @@ -4645,7 +4104,7 @@ dependencies = [ "serde_bencode", "serde_bytes", "sha1_smol", - "thiserror 1.0.63", + "thiserror 1.0.69", "tracing", ] @@ -4687,7 +4146,7 @@ checksum = "d8031297470465389c1349c399b927505d0cc4503be7a997c3541765bca82b4d" dependencies = [ "flume", "if-addrs", - "polling", + "polling 2.8.0", "socket2 0.5.7", ] @@ -4697,18 +4156,28 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "memmap2" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "483758ad303d734cec05e5c12b41d7e93e6a6390c5e9dae6bdeb7c1259012d28" +dependencies = [ + "libc", +] + [[package]] name = "metal" -version = "0.24.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de11355d1f6781482d027a3b4d4de7825dcedb197bf573e0596d00008402d060" +checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "block", "core-graphics-types", - "foreign-types 0.3.2", + "foreign-types", "log", "objc", + "paste", ] [[package]] @@ -4766,7 +4235,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "wasi", "windows-sys 0.52.0", @@ -4774,45 +4243,26 @@ dependencies = [ [[package]] name = "naga" -version = "0.12.3" +version = "24.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbcc2e0513220fd2b598e6068608d4462db20322c0e77e47f6f488dfcfc279cb" +checksum = "e380993072e52eef724eddfcde0ed013b0c023c3f0417336ed041aa9f076994e" dependencies = [ + "arrayvec", "bit-set", - "bitflags 1.3.2", + "bitflags 2.9.1", + "cfg_aliases", "codespan-reporting", "hexf-parse", - "indexmap 1.9.3", + "indexmap", "log", - "num-traits", - "pp-rs", "rustc-hash 1.1.0", "spirv", + "strum", "termcolor", - "thiserror 1.0.63", + "thiserror 2.0.4", "unicode-xid", ] -[[package]] -name = "naga_oil" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be942a5c21c58b9b0bf4d9b99db3634ddb7a916f8e1d1d0b71820cc4150e56b" -dependencies = [ - "bit-set", - "codespan-reporting", - "data-encoding", - "indexmap 1.9.3", - "naga", - "once_cell", - "regex", - "regex-syntax 0.6.29", - "rustc-hash 1.1.0", - "thiserror 1.0.63", - "tracing", - "unicode-ident", -] - [[package]] name = "nanorand" version = "0.7.0" @@ -4824,30 +4274,31 @@ dependencies = [ [[package]] name = "ndk" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "jni-sys", - "ndk-sys 0.4.1+23.1.7779620", - "num_enum 0.5.11", - "raw-window-handle", - "thiserror 1.0.63", + "log", + "ndk-sys 0.5.0+25.2.9519653", + "num_enum", + "thiserror 1.0.69", ] [[package]] name = "ndk" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "jni-sys", "log", - "ndk-sys 0.5.0+25.2.9519653", - "num_enum 0.7.3", - "thiserror 1.0.63", + "ndk-sys 0.6.0+11769913", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", ] [[package]] @@ -4858,18 +4309,18 @@ checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "ndk-sys" -version = "0.4.1+23.1.7779620" +version = "0.5.0+25.2.9519653" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" dependencies = [ "jni-sys", ] [[package]] name = "ndk-sys" -version = "0.5.0+25.2.9519653" +version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ "jni-sys", ] @@ -4937,7 +4388,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "483325d4bfef65699214858f097d504eb812c38ce7077d165f301ec406c3066e" dependencies = [ "anyhow", - "bitflags 2.6.0", + "bitflags 2.9.1", "byteorder", "libc", "log", @@ -4954,7 +4405,7 @@ dependencies = [ "anyhow", "byteorder", "paste", - "thiserror 1.0.63", + "thiserror 1.0.69", ] [[package]] @@ -4968,7 +4419,7 @@ dependencies = [ "log", "netlink-packet-core", "netlink-sys", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", ] @@ -5035,7 +4486,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "cfg-if", "libc", ] @@ -5046,9 +4497,9 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "cfg-if", - "cfg_aliases 0.2.1", + "cfg_aliases", "libc", ] @@ -5109,7 +4560,7 @@ version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "crossbeam-channel", "filetime", "fsevent-sys", @@ -5122,15 +4573,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[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" @@ -5182,7 +4624,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -5215,55 +4657,13 @@ dependencies = [ "libm", ] -[[package]] -name = "num_enum" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" -dependencies = [ - "num_enum_derive 0.5.11", -] - -[[package]] -name = "num_enum" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" -dependencies = [ - "num_enum_derive 0.6.1", -] - [[package]] name = "num_enum" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ - "num_enum_derive 0.7.3", -] - -[[package]] -name = "num_enum_derive" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "num_enum_derive" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 2.0.90", + "num_enum_derive", ] [[package]] @@ -5272,10 +4672,10 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -5291,40 +4691,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" dependencies = [ "malloc_buf", - "objc_exception", ] -[[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.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", + "objc-sys", + "objc2-encode", ] [[package]] @@ -5333,25 +4715,49 @@ 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", + "bitflags 2.9.1", + "block2", "libc", - "objc2 0.5.2", + "objc2", "objc2-core-data", "objc2-core-image", "objc2-foundation", "objc2-quartz-core", ] +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.9.1", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + [[package]] name = "objc2-core-data" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.6.0", - "block2 0.5.1", - "objc2 0.5.2", + "bitflags 2.9.1", + "block2", + "objc2", "objc2-foundation", ] @@ -5361,19 +4767,22 @@ 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", + "block2", + "objc2", "objc2-foundation", "objc2-metal", ] [[package]] -name = "objc2-encode" -version = "2.0.0-pre.2" +name = "objc2-core-location" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ - "objc-sys 0.2.0-beta.2", + "block2", + "objc2", + "objc2-contacts", + "objc2-foundation", ] [[package]] @@ -5388,10 +4797,23 @@ 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", + "bitflags 2.9.1", + "block2", + "dispatch", "libc", - "objc2 0.5.2", + "objc2", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", ] [[package]] @@ -5400,9 +4822,9 @@ 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", + "bitflags 2.9.1", + "block2", + "objc2", "objc2-foundation", ] @@ -5412,20 +4834,66 @@ 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", + "bitflags 2.9.1", + "block2", + "objc2", "objc2-foundation", "objc2-metal", ] [[package]] -name = "objc_exception" -version = "0.1.2" +name = "objc2-symbols" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" dependencies = [ - "cc", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.9.1", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.9.1", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", ] [[package]] @@ -5471,9 +4939,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_map" @@ -5514,6 +4982,15 @@ dependencies = [ "libredox 0.0.2", ] +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + [[package]] name = "overload" version = "0.1.1" @@ -5626,7 +5103,7 @@ version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" dependencies = [ - "base64 0.22.1", + "base64", "serde", ] @@ -5652,7 +5129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c73c26c01b8c87956cea613c907c9d6ecffd8d18a2a5908e5de0adfaa185cea" dependencies = [ "memchr", - "thiserror 1.0.63", + "thiserror 1.0.69", "ucd-trie", ] @@ -5676,7 +5153,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -5697,7 +5174,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.5.0", + "indexmap", ] [[package]] @@ -5730,7 +5207,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -5754,7 +5231,7 @@ dependencies = [ "gc-arena", "hashbrown 0.14.5", "rand", - "thiserror 1.0.63", + "thiserror 1.0.69", ] [[package]] @@ -5774,7 +5251,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -5819,7 +5296,7 @@ dependencies = [ "mainline", "self_cell 1.0.4", "simple-dns", - "thiserror 1.0.63", + "thiserror 1.0.69", "tracing", "ureq", "wasm-bindgen", @@ -5873,7 +5350,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -5926,6 +5403,26 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "polling" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee9b2fa7a4517d2c91ff5bc6c297a427a96749d15f98fcdbb22c05571a4d4b7" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.5.2", + "pin-project-lite", + "rustix 1.0.8", + "windows-sys 0.60.2", +] + +[[package]] +name = "pollster" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" + [[package]] name = "poly1305" version = "0.8.0" @@ -5939,9 +5436,18 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] [[package]] name = "portmapper" @@ -5950,7 +5456,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ea24e7552a28ee4a3478ae116c89080957d6816526d0a533bee6cd67048279" dependencies = [ "anyhow", - "base64 0.22.1", + "base64", "bytes", "derive_more", "futures-lite 2.5.0", @@ -5959,7 +5465,7 @@ dependencies = [ "iroh-metrics", "libc", "netwatch", - "num_enum 0.7.3", + "num_enum", "rand", "serde", "smallvec", @@ -6003,15 +5509,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" -[[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" @@ -6055,6 +5552,12 @@ dependencies = [ "ucd-parse", ] +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + [[package]] name = "pretty_assertions" version = "1.4.0" @@ -6074,16 +5577,6 @@ dependencies = [ "elliptic-curve", ] -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - [[package]] name = "proc-macro-crate" version = "3.2.0" @@ -6127,18 +5620,31 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "profiling" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" +dependencies = [ + "quote", + "syn 2.0.104", +] [[package]] name = "prometheus-client" @@ -6160,7 +5666,16 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", ] [[package]] @@ -6184,6 +5699,15 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quick-xml" +version = "0.37.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" +dependencies = [ + "memchr", +] + [[package]] name = "quinn" version = "0.11.5" @@ -6197,7 +5721,7 @@ dependencies = [ "rustc-hash 2.0.0", "rustls 0.23.12", "socket2 0.5.7", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -6214,7 +5738,7 @@ dependencies = [ "rustc-hash 2.0.0", "rustls 0.23.12", "slab", - "thiserror 1.0.63", + "thiserror 1.0.69", "tinyvec", "tracing", ] @@ -6234,9 +5758,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -6257,12 +5781,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[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" @@ -6314,14 +5832,34 @@ version = "11.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb9ee317cfe3fbd54b36a511efc1edd42e216903c9cd575e686dd68a2ba90d8d" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", ] [[package]] name = "raw-window-handle" -version = "0.5.2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "rayon" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" +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 = "rcgen" @@ -6348,21 +5886,6 @@ dependencies = [ "yasna", ] -[[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" @@ -6378,7 +5901,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", ] [[package]] @@ -6389,7 +5912,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox 0.1.3", - "thiserror 1.0.63", + "thiserror 1.0.69", ] [[package]] @@ -6454,7 +5977,7 @@ version = "0.12.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "futures-core", "futures-util", @@ -6534,18 +6057,6 @@ dependencies = [ "crossbeam-utils", ] -[[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 = "rsa" version = "0.9.6" @@ -6581,7 +6092,7 @@ dependencies = [ "netlink-proto", "netlink-sys", "nix 0.26.4", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", ] @@ -6599,7 +6110,7 @@ dependencies = [ "netlink-proto", "netlink-sys", "nix 0.27.1", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", ] @@ -6645,13 +6156,26 @@ version = "0.38.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.14", "windows-sys 0.52.0", ] +[[package]] +name = "rustix" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +dependencies = [ + "bitflags 2.9.1", + "errno", + "libc", + "linux-raw-sys 0.9.4", + "windows-sys 0.60.2", +] + [[package]] name = "rustls" version = "0.21.12" @@ -6698,7 +6222,7 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" dependencies = [ - "base64 0.22.1", + "base64", "rustls-pki-types", ] @@ -6823,6 +6347,19 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sctk-adwaita" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit", + "tiny-skia", +] + [[package]] name = "sec1" version = "0.7.3" @@ -6843,7 +6380,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -6927,7 +6464,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -6969,7 +6506,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.5.0", + "indexmap", "itoa", "ryu", "serde", @@ -7060,7 +6597,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01607fe2e61894468c6dc0b26103abb073fb08b79a3d9e4b6d76a1a341549958" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", ] [[package]] @@ -7092,8 +6629,41 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "smithay-client-toolkit" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "serde", + "bitflags 2.9.1", + "calloop", + "calloop-wayland-source", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix 0.38.36", + "thiserror 1.0.69", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smithay-clipboard" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc8216eec463674a0e90f29e0ae41a4db573ec5b56b1c6c1c71615d249b6d846" +dependencies = [ + "libc", + "smithay-client-toolkit", + "wayland-backend", ] [[package]] @@ -7151,12 +6721,11 @@ dependencies = [ [[package]] name = "spirv" -version = "0.2.0+1.5.4" +version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 1.3.2", - "num-traits", + "bitflags 2.9.1", ] [[package]] @@ -7229,6 +6798,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + [[package]] name = "strsim" version = "0.11.1" @@ -7255,7 +6830,7 @@ dependencies = [ "proc-macro2", "quote", "struct_iterable_internal", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -7283,7 +6858,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -7292,7 +6867,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0adebf9fb8fba5c39ee34092b0383f247e4d1255b98fcffec94b4b797b85b677" dependencies = [ - "base64 0.22.1", + "base64", "bounded-integer", "byteorder", "crc", @@ -7327,25 +6902,16 @@ dependencies = [ "pnet_packet", "rand", "socket2 0.5.7", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", "tracing", ] [[package]] name = "svg_fmt" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20e16a0f46cf5fd675563ef54f26e83e20f2366bcf027bcb3cc3ed2b98aaf2ca" - -[[package]] -name = "svgtypes" -version = "0.8.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22975e8a2bac6a76bb54f898a6b18764633b00e780330f0b689f65afb3975564" -dependencies = [ - "siphasher", -] +checksum = "20e16a0f46cf5fd675563ef54f26e83e20f2366bcf027bcb3cc3ed2b98aaf2ca" [[package]] name = "swarm-discovery" @@ -7496,9 +7062,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -7533,7 +7099,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -7545,27 +7111,13 @@ dependencies = [ "libc", ] -[[package]] -name = "sysinfo" -version = "0.29.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd727fc423c2060f6c92d9534cef765c65a6ed3f428a03d7def74a8c4348e666" -dependencies = [ - "cfg-if", - "core-foundation-sys", - "libc", - "ntapi", - "once_cell", - "winapi", -] - [[package]] name = "system-configuration" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -7597,11 +7149,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl 1.0.63", + "thiserror-impl 1.0.69", ] [[package]] @@ -7615,13 +7167,13 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -7632,7 +7184,7 @@ checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -7687,6 +7239,31 @@ dependencies = [ "time-core", ] +[[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 = "tinystr" version = "0.7.6" @@ -7736,7 +7313,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -7757,7 +7334,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3184e8e292a828dd4bca5b2a60aba830ec5ed873a66c9ebb6e65038fa649e827" dependencies = [ "async-trait", - "base64 0.22.1", + "base64", "chrono", "futures", "log", @@ -7824,7 +7401,7 @@ dependencies = [ "http 1.1.0", "httparse", "js-sys", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", "tokio-tungstenite 0.21.0", "wasm-bindgen", @@ -7867,24 +7444,13 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.5.0", - "toml_datetime", - "winnow 0.5.40", -] - [[package]] name = "toml_edit" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.5.0", + "indexmap", "toml_datetime", "winnow 0.5.40", ] @@ -7895,7 +7461,7 @@ version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.5.0", + "indexmap", "serde", "serde_spanned", "toml_datetime", @@ -7949,7 +7515,7 @@ checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" dependencies = [ "crossbeam-channel", "parking_lot", - "thiserror 1.0.63", + "thiserror 1.0.69", "time", "tracing-subscriber", ] @@ -7962,7 +7528,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -7975,17 +7541,6 @@ dependencies = [ "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" @@ -8012,7 +7567,7 @@ dependencies = [ "thread_local", "tracing", "tracing-core", - "tracing-log 0.2.0", + "tracing-log", ] [[package]] @@ -8101,7 +7656,7 @@ dependencies = [ "log", "rand", "sha1", - "thiserror 1.0.63", + "thiserror 1.0.69", "url", "utf-8", ] @@ -8120,7 +7675,7 @@ dependencies = [ "log", "rand", "sha1", - "thiserror 1.0.63", + "thiserror 1.0.69", "utf-8", ] @@ -8239,6 +7794,12 @@ 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" @@ -8247,9 +7808,9 @@ checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" @@ -8279,7 +7840,7 @@ version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" dependencies = [ - "base64 0.22.1", + "base64", "flate2", "log", "once_cell", @@ -8402,47 +7963,48 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -8450,22 +8012,25 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "watchable" @@ -8476,25 +8041,123 @@ dependencies = [ "event-listener 4.0.3", "futures-util", "parking_lot", - "thiserror 1.0.63", + "thiserror 1.0.69", +] + +[[package]] +name = "wayland-backend" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35" +dependencies = [ + "cc", + "downcast-rs", + "rustix 1.0.8", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" +dependencies = [ + "bitflags 2.9.1", + "rustix 1.0.8", + "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.9.1", + "cursor-icon", + "wayland-backend", +] + +[[package]] +name = "wayland-cursor" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447ccc440a881271b19e9989f75726d60faa09b95b0200a9b7eb5cc47c3eeb29" +dependencies = [ + "rustix 1.0.8", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901" +dependencies = [ + "bitflags 2.9.1", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a07a14257c077ab3279987c4f8bb987851bf57081b93710381daea94f2c2c032" +dependencies = [ + "bitflags 2.9.1", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec" +dependencies = [ + "bitflags 2.9.1", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", ] [[package]] name = "wayland-scanner" -version = "0.29.5" +version = "0.31.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" +checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3" dependencies = [ "proc-macro2", + "quick-xml", "quote", - "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.31.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", ] [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -8512,17 +8175,18 @@ dependencies = [ [[package]] name = "webbrowser" -version = "0.8.15" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db67ae75a9405634f5882791678772c94ff5f16a66535aae186e26aa0841fc8b" +checksum = "ea9fe1ebb156110ff855242c1101df158b822487e4957b0556d9ffce9db0f535" dependencies = [ - "core-foundation 0.9.4", + "block2", + "core-foundation 0.10.0", "home", "jni 0.21.1", "log", "ndk-context", - "objc", - "raw-window-handle", + "objc2", + "objc2-foundation", "url", "web-sys", ] @@ -8544,12 +8208,14 @@ checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" [[package]] name = "wgpu" -version = "0.16.3" +version = "24.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "480c965c9306872eb6255fa55e4b4953be55a8b64d57e61d7ff840d3dcc051cd" +checksum = "6b0b3436f0729f6cdf2e6e9201f3d39dc95813fad61d826c1ed07918b4539353" dependencies = [ "arrayvec", - "cfg-if", + "bitflags 2.9.1", + "cfg_aliases", + "document-features", "js-sys", "log", "naga", @@ -8568,55 +8234,60 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "0.16.1" +version = "24.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f478237b4bf0d5b70a39898a66fa67ca3a007d79f2520485b8b0c3dfc46f8c2" +checksum = "7f0aa306497a238d169b9dc70659105b4a096859a34894544ca81719242e1499" dependencies = [ "arrayvec", "bit-vec", - "bitflags 2.6.0", - "codespan-reporting", + "bitflags 2.9.1", + "cfg_aliases", + "document-features", + "indexmap", "log", "naga", + "once_cell", "parking_lot", "profiling", "raw-window-handle", "rustc-hash 1.1.0", "smallvec", - "thiserror 1.0.63", - "web-sys", + "thiserror 2.0.4", "wgpu-hal", "wgpu-types", ] [[package]] name = "wgpu-hal" -version = "0.16.2" +version = "24.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecb3258078e936deee14fd4e0febe1cfe9bbb5ffef165cb60218d2ee5eb4448" +checksum = "f112f464674ca69f3533248508ee30cb84c67cf06c25ff6800685f5e0294e259" dependencies = [ "android_system_properties", "arrayvec", "ash", "bit-set", - "bitflags 2.6.0", + "bitflags 2.9.1", "block", + "bytemuck", + "cfg_aliases", "core-graphics-types", - "d3d12", - "foreign-types 0.3.2", "glow", + "glutin_wgl_sys", "gpu-alloc", "gpu-allocator", "gpu-descriptor", - "hassle-rs", "js-sys", "khronos-egl", "libc", - "libloading 0.8.5", + "libloading", "log", "metal", "naga", + "ndk-sys 0.5.0+25.2.9519653", "objc", + "once_cell", + "ordered-float", "parking_lot", "profiling", "range-alloc", @@ -8624,21 +8295,23 @@ dependencies = [ "renderdoc-sys", "rustc-hash 1.1.0", "smallvec", - "thiserror 1.0.63", + "thiserror 2.0.4", "wasm-bindgen", "web-sys", "wgpu-types", - "winapi", + "windows 0.58.0", + "windows-core 0.58.0", ] [[package]] name = "wgpu-types" -version = "0.16.1" +version = "24.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c153280bb108c2979eb5c7391cb18c56642dd3c072e55f52065e13e2a1252a" +checksum = "50ac044c0e76c03a0378e7786ac505d010a873665e2d51383dcff8dd227dc69c" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "js-sys", + "log", "web-sys", ] @@ -8694,23 +8367,12 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows" -version = "0.44.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" -dependencies = [ - "windows-targets 0.42.2", -] - [[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", ] @@ -8769,24 +8431,13 @@ 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-implement", + "windows-interface", "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" @@ -8795,30 +8446,25 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] name = "windows-interface" -version = "0.48.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6fb8df20c9bcaa8ad6ab513f7b40104840c8867d5751126e4df3b08388d0cc7" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.104", ] [[package]] -name = "windows-interface" -version = "0.58.0" +name = "windows-link" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-registry" @@ -8895,6 +8541,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -8934,13 +8589,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "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-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -8959,6 +8631,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -8977,6 +8655,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -8995,12 +8679,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[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_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -9019,6 +8715,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -9037,6 +8739,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -9055,6 +8763,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -9073,34 +8787,62 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winit" -version = "0.28.7" +version = "0.30.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9596d90b45384f5281384ab204224876e8e8bf7d58366d9b795ad99aa9894b94" +checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732" dependencies = [ + "ahash", "android-activity", - "bitflags 1.3.2", - "cfg_aliases 0.1.1", + "atomic-waker", + "bitflags 2.9.1", + "block2", + "bytemuck", + "calloop", + "cfg_aliases", + "concurrent-queue", "core-foundation 0.9.4", - "core-graphics 0.22.3", - "dispatch", - "instant", + "core-graphics", + "cursor-icon", + "dpi", + "js-sys", "libc", - "log", - "mio 0.8.11", - "ndk 0.7.0", - "objc2 0.3.0-beta.3.patch-leaks.3", - "once_cell", + "memmap2", + "ndk 0.9.0", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", "orbclient", "percent-encoding", + "pin-project", "raw-window-handle", - "redox_syscall 0.3.5", + "redox_syscall 0.4.1", + "rustix 0.38.36", + "sctk-adwaita", + "smithay-client-toolkit", + "smol_str 0.2.2", + "tracing", + "unicode-segmentation", "wasm-bindgen", - "wayland-scanner", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", "web-sys", - "windows-sys 0.45.0", + "web-time", + "windows-sys 0.52.0", "x11-dl", + "x11rb", + "xkbcommon-dl", ] [[package]] @@ -9172,8 +8914,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" dependencies = [ + "as-raw-xcb-connection", "gethostname", - "rustix", + "libc", + "libloading", + "once_cell", + "rustix 0.38.36", "x11rb-protocol", ] @@ -9196,10 +8942,35 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror 1.0.63", + "thiserror 1.0.69", "time", ] +[[package]] +name = "xcursor" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.9.1", + "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.21" @@ -9254,7 +9025,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.104", ] [[package]] @@ -9262,3 +9033,12 @@ 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/framework_crates/bones_bevy_renderer/CHANGELOG.md b/bones_bevy_renderer/CHANGELOG.md similarity index 100% rename from framework_crates/bones_bevy_renderer/CHANGELOG.md rename to bones_bevy_renderer/CHANGELOG.md diff --git a/framework_crates/bones_bevy_renderer/Cargo.toml b/bones_bevy_renderer/Cargo.toml similarity index 100% rename from framework_crates/bones_bevy_renderer/Cargo.toml rename to bones_bevy_renderer/Cargo.toml diff --git a/framework_crates/bones_bevy_renderer/src/convert.rs b/bones_bevy_renderer/src/convert.rs similarity index 100% rename from framework_crates/bones_bevy_renderer/src/convert.rs rename to bones_bevy_renderer/src/convert.rs diff --git a/framework_crates/bones_bevy_renderer/src/debug.rs b/bones_bevy_renderer/src/debug.rs similarity index 100% rename from framework_crates/bones_bevy_renderer/src/debug.rs rename to bones_bevy_renderer/src/debug.rs diff --git a/framework_crates/bones_bevy_renderer/src/input.rs b/bones_bevy_renderer/src/input.rs similarity index 98% rename from framework_crates/bones_bevy_renderer/src/input.rs rename to bones_bevy_renderer/src/input.rs index 77b28b1e59..4259a259b5 100644 --- a/framework_crates/bones_bevy_renderer/src/input.rs +++ b/bones_bevy_renderer/src/input.rs @@ -60,7 +60,7 @@ pub fn get_bones_input( key_events: keyboard_events .iter() .map(|event| bones::KeyboardEvent { - scan_code: event.scan_code, + scan_code: bones::Set(event.scan_code), key_code: event.key_code.map(|x| x.into_bones()).into(), button_state: event.state.into_bones(), }) diff --git a/framework_crates/bones_bevy_renderer/src/lib.rs b/bones_bevy_renderer/src/lib.rs similarity index 100% rename from framework_crates/bones_bevy_renderer/src/lib.rs rename to bones_bevy_renderer/src/lib.rs diff --git a/framework_crates/bones_bevy_renderer/src/render.rs b/bones_bevy_renderer/src/render.rs similarity index 99% rename from framework_crates/bones_bevy_renderer/src/render.rs rename to bones_bevy_renderer/src/render.rs index c31cc38e28..f1c96be422 100644 --- a/framework_crates/bones_bevy_renderer/src/render.rs +++ b/bones_bevy_renderer/src/render.rs @@ -47,7 +47,7 @@ impl BonesImageIds { bevy_egui_textures: &mut bevy_egui::EguiUserTextures, ) { for entry in bones_assets.store.asset_ids.iter() { - let handle = entry.key(); + let handle: &bones::UntypedHandle = entry.key(); let cid = entry.value(); let mut asset = bones_assets.store.assets.get_mut(cid).unwrap(); if let Ok(image) = asset.data.try_cast_mut::() { @@ -77,7 +77,8 @@ impl BonesImageIds { if let bones::Image::Data(data) = taken_image { let handle = bevy_images.add(Image::from_dynamic(data, true)); let egui_texture = bevy_egui_textures.add_image(handle.clone()); - bones_egui_textures.insert(bones_handle, egui_texture); + // Broke when updating bones egui to 0.30 + //bones_egui_textures.insert(bones_handle, egui_texture); map.insert(*next_id, handle); *image = bones::Image::External(*next_id); *next_id += 1; diff --git a/framework_crates/bones_bevy_renderer/src/rumble.rs b/bones_bevy_renderer/src/rumble.rs similarity index 100% rename from framework_crates/bones_bevy_renderer/src/rumble.rs rename to bones_bevy_renderer/src/rumble.rs diff --git a/framework_crates/bones_bevy_renderer/src/storage.rs b/bones_bevy_renderer/src/storage.rs similarity index 100% rename from framework_crates/bones_bevy_renderer/src/storage.rs rename to bones_bevy_renderer/src/storage.rs diff --git a/framework_crates/bones_bevy_renderer/src/ui.rs b/bones_bevy_renderer/src/ui.rs similarity index 93% rename from framework_crates/bones_bevy_renderer/src/ui.rs rename to bones_bevy_renderer/src/ui.rs index c44d85d991..85029b6441 100644 --- a/framework_crates/bones_bevy_renderer/src/ui.rs +++ b/bones_bevy_renderer/src/ui.rs @@ -11,7 +11,8 @@ pub fn setup_egui(world: &mut World) { }; // Insert the egui context as a shared resource - game.insert_shared_resource(bones::EguiCtx(ctx.clone())); + // Broke when updating bones egui to 0.30 + //game.insert_shared_resource(bones::EguiCtx(ctx.clone())); if let Some(bones_assets) = &game.asset_server() { update_egui_fonts(&ctx, bones_assets); @@ -34,7 +35,8 @@ pub fn egui_input_hook( if let Some(hook) = game.shared_resource_cell::() { let hook = hook.borrow().unwrap(); let mut egui_input = egui_query.get_single_mut().unwrap(); - (hook.0)(&mut game, &mut egui_input); + // Broke when updating bones egui to 0.30 + //(hook.0)(&mut game, &mut egui_input); } } @@ -57,6 +59,7 @@ pub fn update_egui_fonts(ctx: &bevy_egui::egui::Context, bones_assets: &bones::A let mut fonts = egui::FontDefinitions::default(); for entry in bones_assets.store.assets.iter() { + /*Broke when updating bones egui to 0.30 let asset = entry.value(); if let Ok(font) = asset.try_cast_ref::() { let previous = fonts @@ -75,6 +78,7 @@ pub fn update_egui_fonts(ctx: &bevy_egui::egui::Context, bones_assets: &bones::A .or_default() .push(font.family_name.to_string()); } + */ } ctx.set_fonts(fonts); diff --git a/demos/asset_packs/Cargo.toml b/demos/asset_packs/Cargo.toml index c4b250027d..dc79658264 100644 --- a/demos/asset_packs/Cargo.toml +++ b/demos/asset_packs/Cargo.toml @@ -7,4 +7,4 @@ publish = false [dependencies] bones_framework = { path = "../../framework_crates/bones_framework" } -bones_bevy_renderer = { path = "../../framework_crates/bones_bevy_renderer" } +bones_wgpu_renderer = { path = "../../framework_crates/bones_wgpu_renderer" } diff --git a/demos/asset_packs/src/main.rs b/demos/asset_packs/src/main.rs index 8bb247882a..b95fe50cee 100644 --- a/demos/asset_packs/src/main.rs +++ b/demos/asset_packs/src/main.rs @@ -1,4 +1,4 @@ -use bones_bevy_renderer::BonesBevyRenderer; +use bones_wgpu_renderer::BonesWgpuRenderer; use bones_framework::prelude::*; // @@ -55,7 +55,7 @@ fn main() { .add_system_to_stage(Update, menu_system); }); - BonesBevyRenderer::new(game).app().run(); + BonesWgpuRenderer::new(game).run(); } /// System to render the home menu. @@ -65,7 +65,7 @@ fn menu_system( all_packs: AllPacksData, ) { egui::CentralPanel::default() - .frame(egui::Frame::none().outer_margin(egui::Margin::same(32.0))) + .frame(egui::Frame::new().outer_margin(egui::epaint::Marginf::same(32.0))) .show(&egui_ctx, |ui| { // Use the title that has been loaded from the asset ui.heading(&core_meta.title); diff --git a/demos/assets_minimal/Cargo.toml b/demos/assets_minimal/Cargo.toml index df333a9573..a60d02dd96 100644 --- a/demos/assets_minimal/Cargo.toml +++ b/demos/assets_minimal/Cargo.toml @@ -7,4 +7,4 @@ publish = false [dependencies] bones_framework = { path = "../../framework_crates/bones_framework" } -bones_bevy_renderer = { path = "../../framework_crates/bones_bevy_renderer" } +bones_wgpu_renderer = { path = "../../framework_crates/bones_wgpu_renderer" } diff --git a/demos/assets_minimal/src/main.rs b/demos/assets_minimal/src/main.rs index b49b7c0a01..a4b883ac62 100644 --- a/demos/assets_minimal/src/main.rs +++ b/demos/assets_minimal/src/main.rs @@ -1,4 +1,4 @@ -use bones_bevy_renderer::BonesBevyRenderer; +use bones_wgpu_renderer::BonesWgpuRenderer; use bones_framework::prelude::*; // @@ -44,10 +44,7 @@ fn main() { // Add our menu system to the update stage .add_system_to_stage(Update, menu_system); - // Finalize session and register with game sessions. - menu_session_builder.finish_and_add(&mut game.sessions); - - BonesBevyRenderer::new(game).app().run(); + BonesWgpuRenderer::new(game).run(); } /// System to render the home menu. @@ -57,7 +54,7 @@ fn menu_system( meta: Root, ) { egui::CentralPanel::default() - .frame(egui::Frame::none()) + .frame(egui::Frame::new()) .show(&egui_ctx, |ui| { // Use the title that has been loaded from the asset ui.heading(&meta.title); diff --git a/demos/features/Cargo.toml b/demos/features/Cargo.toml index ec3e4425f7..85c3d4b044 100644 --- a/demos/features/Cargo.toml +++ b/demos/features/Cargo.toml @@ -7,4 +7,4 @@ publish = false [dependencies] bones_framework = { path = "../../framework_crates/bones_framework" } -bones_bevy_renderer = { path = "../../framework_crates/bones_bevy_renderer" } +bones_wgpu_renderer = { path = "../../framework_crates/bones_wgpu_renderer" } diff --git a/demos/features/src/main.rs b/demos/features/src/main.rs index 51e4380b9d..688b36b247 100644 --- a/demos/features/src/main.rs +++ b/demos/features/src/main.rs @@ -1,6 +1,6 @@ #![allow(clippy::too_many_arguments)] -use bones_bevy_renderer::{bevy::diagnostic::LogDiagnosticsPlugin, BonesBevyRenderer}; +use bones_wgpu_renderer::BonesWgpuRenderer; use bones_framework::prelude::*; /// Create our root asset type. @@ -91,7 +91,7 @@ fn main() { PersistedTextData::register_schema(); // Create a bones bevy renderer from our bones game - let mut renderer = BonesBevyRenderer::new(create_game()); + let mut renderer = BonesWgpuRenderer::new(create_game()); // Set the app namespace which will be used by the renderer to decide where to put // persistent storage files. renderer.app_namespace = ( @@ -101,9 +101,9 @@ fn main() { ); // Get a bevy app for running our game renderer - .app() + //.app() // We can add our own bevy plugins now - .add_plugins(LogDiagnosticsPlugin::default()) + //.add_plugins(LogDiagnosticsPlugin::default()) // And run the bevy app .run() } @@ -181,7 +181,7 @@ fn menu_system( // Render the menu. egui::CentralPanel::default() - .frame(egui::Frame::none()) + .frame(egui::Frame::new()) .show(&ctx, |ui| { BorderedFrame::new(&meta.menu_border).show(ui, |ui| { ui.vertical_centered(|ui| { @@ -317,7 +317,7 @@ fn move_sprite( ctx: Res, ) { egui::CentralPanel::default() - .frame(egui::Frame::none()) + .frame(egui::Frame::new()) .show(&ctx, |ui| { ui.label("Press left and right arrow keys to move sprite"); }); @@ -453,7 +453,7 @@ fn audio_demo_ui( assets: Res, ) { egui::CentralPanel::default() - .frame(egui::Frame::none()) + .frame(egui::Frame::new()) .show(&ctx, |ui| { ui.vertical_centered(|ui| { ui.add_space(50.0); @@ -538,7 +538,7 @@ fn back_to_menu_ui( localization: Localization, ) { egui::TopBottomPanel::bottom("back-to-menu") - .frame(egui::Frame::none()) + .frame(egui::Frame::new()) .show_separator_line(false) .show(&ctx, |ui| { ui.with_layout(egui::Layout::bottom_up(egui::Align::Center), |ui| { diff --git a/demos/hello_world/Cargo.toml b/demos/hello_world/Cargo.toml index 947524c651..5763fdf58f 100644 --- a/demos/hello_world/Cargo.toml +++ b/demos/hello_world/Cargo.toml @@ -7,4 +7,4 @@ publish = false [dependencies] bones_framework = { path = "../../framework_crates/bones_framework" } -bones_bevy_renderer = { path = "../../framework_crates/bones_bevy_renderer" } +bones_wgpu_renderer = { path = "../../framework_crates/bones_wgpu_renderer" } diff --git a/demos/hello_world/src/main.rs b/demos/hello_world/src/main.rs index b2931bfa4d..2509710f0d 100644 --- a/demos/hello_world/src/main.rs +++ b/demos/hello_world/src/main.rs @@ -1,4 +1,4 @@ -use bones_bevy_renderer::BonesBevyRenderer; +use bones_wgpu_renderer::BonesWgpuRenderer; use bones_framework::prelude::*; fn main() { @@ -19,7 +19,7 @@ fn main() { .add_system_to_stage(Update, menu_system); }); - BonesBevyRenderer::new(game).app().run(); + BonesWgpuRenderer::new(game).run(); } /// System to render the home menu. diff --git a/demos/hello_world_wgpu/Cargo.toml b/demos/hello_world_wgpu/Cargo.toml new file mode 100644 index 0000000000..38f0af244e --- /dev/null +++ b/demos/hello_world_wgpu/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "demo_hello_world_wgpu" +edition.workspace = true +version.workspace = true +license.workspace = true +publish = false + +[dependencies] +bones_framework = { path = "../../framework_crates/bones_framework" } +bones_wgpu_renderer = { path = "../../framework_crates/bones_wgpu_renderer" } diff --git a/demos/hello_world_wgpu/assets/atlas/fishy-body(2).png b/demos/hello_world_wgpu/assets/atlas/fishy-body(2).png new file mode 100755 index 0000000000..b092cf8d3d Binary files /dev/null and b/demos/hello_world_wgpu/assets/atlas/fishy-body(2).png differ diff --git a/demos/hello_world_wgpu/assets/atlas/fishy-body.atlas.yaml b/demos/hello_world_wgpu/assets/atlas/fishy-body.atlas.yaml new file mode 100644 index 0000000000..833d869160 --- /dev/null +++ b/demos/hello_world_wgpu/assets/atlas/fishy-body.atlas.yaml @@ -0,0 +1,4 @@ +image: ./fishy-body.png +tile_size: [96, 80] +columns: 14 +rows: 7 diff --git a/demos/hello_world_wgpu/assets/atlas/fishy-body.png b/demos/hello_world_wgpu/assets/atlas/fishy-body.png new file mode 100644 index 0000000000..471ad6ee00 Binary files /dev/null and b/demos/hello_world_wgpu/assets/atlas/fishy-body.png differ diff --git a/demos/hello_world_wgpu/assets/game.yaml b/demos/hello_world_wgpu/assets/game.yaml new file mode 100644 index 0000000000..1ed6245d4d --- /dev/null +++ b/demos/hello_world_wgpu/assets/game.yaml @@ -0,0 +1,6 @@ +# This is our root asset file, which corresponds to our `GameMeta` struct. + +title: Assets Minimal +sprite: ./sprite/fractal.png +sprite2: ./sprite/example.png +atlas: ./atlas/fishy-body.atlas.yaml \ No newline at end of file diff --git a/demos/hello_world_wgpu/assets/pack.yaml b/demos/hello_world_wgpu/assets/pack.yaml new file mode 100644 index 0000000000..b5c73f5291 --- /dev/null +++ b/demos/hello_world_wgpu/assets/pack.yaml @@ -0,0 +1,3 @@ +# This is the core asset pack file. It's only job is to specify +# the path to the root asset. +root: ./game.yaml diff --git a/demos/hello_world_wgpu/assets/sprite/example.png b/demos/hello_world_wgpu/assets/sprite/example.png new file mode 100644 index 0000000000..35054de3e2 Binary files /dev/null and b/demos/hello_world_wgpu/assets/sprite/example.png differ diff --git a/demos/hello_world_wgpu/assets/sprite/fractal.png b/demos/hello_world_wgpu/assets/sprite/fractal.png new file mode 100644 index 0000000000..a96df3d53d Binary files /dev/null and b/demos/hello_world_wgpu/assets/sprite/fractal.png differ diff --git a/demos/hello_world_wgpu/src/main.rs b/demos/hello_world_wgpu/src/main.rs new file mode 100644 index 0000000000..87c14910be --- /dev/null +++ b/demos/hello_world_wgpu/src/main.rs @@ -0,0 +1,283 @@ +use bones_framework::prelude::*; +use bones_wgpu_renderer::BonesWgpuRenderer; + +// +// NOTE: You must run this example from within the `demos/hello_world_wgpu` folder. Also, be sure to +// look at the `demos/hello_world_wgpu` folder to see the asset files for this example. +// + +/// Create our "root" asset type. +#[derive(HasSchema, Clone, Default)] +#[repr(C)] +// We must mark this as a metadata asset, and we set the type to "game". +// +// This means that any files with names like `game.yaml`, `game.yml`, `game.json`, `name.game.yaml`, +// etc. will be loaded as a `GameMeta` asset. +#[type_data(metadata_asset("game"))] +struct GameMeta { + title: String, + sprite: Handle, + sprite2: Handle, + atlas: Handle, +} + +fn main() { + // Setup logging + setup_logs!(); + + // First create bones game. + let mut game = Game::new(); + + game + // We initialize the asset server. + .init_shared_resource::(); + + // We must register all of our asset types before they can be loaded by the asset server. This + // may be done by calling schema() on each of our types, to register them with the schema + // registry. + GameMeta::register_schema(); + + // Create a new session for the game world. Each session is it's own bones world with it's own + // plugins, systems, and entities. + game + .sessions + .create_with("world", |session: &mut SessionBuilder| { + session.install_plugin(sprite_demo_plugin); + session.add_system_to_stage(Update, test); + //session.add_system_to_stage(Update, menu_system); + }); + + BonesWgpuRenderer::new(game).run(); +} + +/// Plugin for running the sprite demo. +fn sprite_demo_plugin(session: &mut SessionBuilder) { + session + .install_plugin(DefaultSessionPlugin) + .add_startup_system(sprite_demo_startup) + .add_system_to_stage(Update, move_sprite); +} + +/// System that spawns the sprite demo. +fn sprite_demo_startup( + mut entities: ResMut, + mut sprites: CompMut, + mut atlas_sprites: CompMut, + mut transforms: CompMut, + mut cameras: CompMut, + meta: Root, +) { + spawn_default_camera(&mut entities, &mut transforms, &mut cameras); + let second_camera = Camera { + priority: 1, + viewport: Maybe::Set(Viewport { + position: UVec2::new(10, 10), + size: UVec2::new(100, 100), + ..Default::default() + }), + //background_color: Set(Color::ORANGE), + ..Default::default() + }; + let camera_ent = entities.create(); + transforms.insert(camera_ent, default()); + cameras.insert(camera_ent, second_camera); + + let sprite_ent = entities.create(); + transforms.insert(sprite_ent, default()); + sprites.insert( + sprite_ent, + Sprite { + image: meta.sprite, + ..default() + }, + ); + let sprite_ent = entities.create(); + transforms.insert( + sprite_ent, + Transform::from_translation(Vec3::new(0.5, 0.5, 0.0)), + ); + sprites.insert( + sprite_ent, + Sprite { + image: meta.sprite2, + flip_x: true, + ..default() + }, + ); + + let atlas_ent = entities.create(); + transforms.insert( + atlas_ent, + Transform::from_translation(Vec3::new(1.5, 1.5, 0.0)), + ); + atlas_sprites.insert( + atlas_ent, + AtlasSprite { + atlas: meta.atlas, + index: 0, + flip_x: false, + flip_y: false, + ..default() + }, + ); +} + +fn move_sprite( + entities: Res, + mut atlases: CompMut, + mut sprites: CompMut, + mut transforms: CompMut, + input: Res, + input_mouse: Res, + gamepad: Res, + camera: Comp, + //mouse_position: Res +) { + let mut left = false; + let mut right = false; + let mut up = false; + let mut down = false; + let mut rotate_left = false; + let mut rotate_right = false; + let mut idx_up = false; + let mut idx_down = false; + let mut flip_x = false; + let mut flip_y = false; + + for input in &input.key_events { + match input.key_code { + Set(KeyCode::D) => right = true, + Set(KeyCode::A) => left = true, + Set(KeyCode::W) => up = true, + Set(KeyCode::S) => down = true, + Set(KeyCode::Q) => rotate_left = true, + Set(KeyCode::E) => rotate_right = true, + Set(KeyCode::P) => idx_up = true, + Set(KeyCode::O) => idx_down = true, + Set(KeyCode::L) => flip_y = true, + Set(KeyCode::K) => flip_x = true, + _ => (), + } + } + + for (_, atlas) in entities.iter_with(&mut atlases) { + if idx_up { + atlas.index += 1; + } + if idx_down { + atlas.index -= 1; + } + if flip_x { + atlas.flip_x = !atlas.flip_x; + } + if flip_y { + atlas.flip_y = !atlas.flip_y; + } + } + + for (_, sprite) in entities.iter_with(&mut sprites) { + if flip_x { + sprite.flip_x = !sprite.flip_x; + } + if flip_y { + sprite.flip_y = !sprite.flip_y; + } + } + + let mut i = 0; + for (_ent, (_sprite, transform)) in entities.iter_with((&camera, &mut transforms)) { + if i == 0 { + //mouse and keyboard + if left { + transform.translation.x -= 0.1; + } + if right { + transform.translation.x += 0.1; + } + if up { + transform.translation.y += 0.1; + } + if down { + transform.translation.y -= 0.1; + } + if rotate_left { + transform.rotation.z -= 0.1; + } + if rotate_right { + transform.rotation.z += 0.1; + } + + for event in &input_mouse.wheel_events { + transform.scale += event.movement.y * 0.1; + } + i += 1; + continue; + } + //gamepad + for event in gamepad.gamepad_events.iter() { + match event { + GamepadEvent::Axis(axis) => match axis.axis { + GamepadAxis::LeftStickX => { + transform.translation.x += axis.value * 0.1; + } + GamepadAxis::LeftStickY => { + transform.translation.y += axis.value * 0.1; + } + GamepadAxis::RightStickX => { + transform.translation.x += axis.value * 0.1; + } + GamepadAxis::RightStickY => { + transform.translation.y += axis.value * 0.1; + } + _ => (), + }, + GamepadEvent::Button(button) => { + if button.button == GamepadButton::LeftTrigger { + transform.rotation.z += 0.1; + } + if button.button == GamepadButton::RightTrigger { + transform.rotation.z -= 0.1; + } + if button.button == GamepadButton::LeftTrigger2 { + transform.scale -= button.value * 0.05; + } + if button.button == GamepadButton::RightTrigger2 { + transform.scale += button.value * 0.05; + } + } + _ => (), + } + } + } +} + +/// System to render the home menu. +fn _menu_system(ctx: Res) { + egui::CentralPanel::default().show(&ctx, |ui| { + ui.label("Hello World"); + }); +} + +fn test(ctx: Res) { + egui::Window::new("winit + egui + wgpu + bones :0") + .resizable(true) + .vscroll(true) + .default_open(false) + .show(&ctx, |ui| { + ui.label("Label!"); + + if ui.button("Button!").clicked() { + println!("boom!") + } + + ui.separator(); + ui.horizontal(|ui| { + if ui.button("-").clicked() { + println!("Sei la"); + } + if ui.button("+").clicked() { + println!("Sei la"); + } + }); + }); +} diff --git a/demos/scripting/Cargo.toml b/demos/scripting/Cargo.toml index 64a4142881..bc57e7a6e3 100644 --- a/demos/scripting/Cargo.toml +++ b/demos/scripting/Cargo.toml @@ -7,4 +7,4 @@ publish = false [dependencies] bones_framework = { path = "../../framework_crates/bones_framework" } -bones_bevy_renderer = { path = "../../framework_crates/bones_bevy_renderer" } +bones_wgpu_renderer = { path = "../../framework_crates/bones_wgpu_renderer" } diff --git a/demos/scripting/src/main.rs b/demos/scripting/src/main.rs index ee14e227b0..9e44333dc5 100644 --- a/demos/scripting/src/main.rs +++ b/demos/scripting/src/main.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use bones_bevy_renderer::BonesBevyRenderer; +use bones_wgpu_renderer::BonesWgpuRenderer; use bones_framework::prelude::*; #[derive(HasSchema, Default, Clone)] @@ -27,13 +27,13 @@ fn main() { builder.add_startup_system(launch_game_session); }); - let mut renderer = BonesBevyRenderer::new(game); + let mut renderer = BonesWgpuRenderer::new(game); renderer.app_namespace = ( "org".into(), "fishfolk".into(), "bones.demo_scripting".into(), ); - renderer.app().run(); + renderer.run(); } fn launch_game_session( diff --git a/framework_crates/bones_framework/Cargo.toml b/framework_crates/bones_framework/Cargo.toml index 7c266dd720..e09f86f0d6 100644 --- a/framework_crates/bones_framework/Cargo.toml +++ b/framework_crates/bones_framework/Cargo.toml @@ -122,8 +122,8 @@ serde = { version = "1.0", features = ["derive"] } image = { version = "0.24", default-features = false } # Gui -egui = { version = "0.23", optional = true } -egui_plot = "0.23" +egui = { version = "0.31", optional = true } +egui_plot = "0.31" ttf-parser = { version = "0.24", default-features = false, optional = true } # Audio diff --git a/framework_crates/bones_framework/src/input/keyboard.rs b/framework_crates/bones_framework/src/input/keyboard.rs index 6e055f193e..0f35e40c95 100644 --- a/framework_crates/bones_framework/src/input/keyboard.rs +++ b/framework_crates/bones_framework/src/input/keyboard.rs @@ -15,7 +15,7 @@ pub struct KeyboardInputs { #[repr(C)] pub struct KeyboardEvent { /// The scan code of the pressed key. - pub scan_code: u32, + pub scan_code: Maybe, /// The key code of the pressed key, if applicable. pub key_code: Maybe, /// The state of the keyboard button. diff --git a/framework_crates/bones_framework/src/input/mouse.rs b/framework_crates/bones_framework/src/input/mouse.rs index 76c99e9c6b..029d1d1148 100644 --- a/framework_crates/bones_framework/src/input/mouse.rs +++ b/framework_crates/bones_framework/src/input/mouse.rs @@ -52,6 +52,10 @@ pub enum MouseButton { Right, /// The middle mouse button. Middle, + /// The first extra mouse button. + Back, + /// The second extra mouse button. + Forward, /// Another mouse button with the associated number. Other(u16), } diff --git a/framework_crates/bones_framework/src/render/camera.rs b/framework_crates/bones_framework/src/render/camera.rs index 90be8e37b6..02878bcc0e 100644 --- a/framework_crates/bones_framework/src/render/camera.rs +++ b/framework_crates/bones_framework/src/render/camera.rs @@ -11,6 +11,8 @@ use crate::prelude::*; // TODO: make repr(C) when `Option`s are supported. // We don't have `Option` support in `bones_schema` right now. // Once we do, we can make this type `#[repr(C)]` instead of `#[schema(opaque)]`. +// TODO: Support different Render Targets, for example, multiple windows, +// for now the camera will always render to the main window. #[repr(C)] pub struct Camera { /// The height of the camera in in-game pixels. @@ -27,6 +29,12 @@ pub struct Camera { pub viewport: Maybe, /// Cameras with a higher priority will be rendered on top of cameras with a lower priority. pub priority: i32, + /// The color to clear the screen to before rendering. + /// If None and the camera is set to draw the background, we will try to use the global ClearColor, + /// If not available, we will use Black + pub background_color: Maybe, + /// Whether or not the camera should draw the background color. + pub draw_background_color: bool, } /// A size setting for a camera. @@ -68,11 +76,13 @@ impl Default for Camera { viewport: Unset, priority: 0, size: default(), + background_color: Maybe::Unset, + draw_background_color: true, } } } -/// Resource for controlling the clear color. +/// Resource for controlling the global clear color. #[derive(Deref, DerefMut, Clone, Copy, HasSchema, Default)] pub struct ClearColor(pub Color); @@ -87,7 +97,14 @@ pub fn spawn_default_camera( ) -> Entity { let ent = entities.create(); cameras.insert(ent, default()); - transforms.insert(ent, Transform::from_translation(Vec3::new(0., 0., 1000.))); + transforms.insert( + ent, + Transform { + translation: Vec3::new(0.0, 0.0, 1000.0), + scale: Vec3::new(40., 40., 1.0), + ..default() + }, + ); ent } diff --git a/framework_crates/bones_framework/src/render/color.rs b/framework_crates/bones_framework/src/render/color.rs index 3daf4f6fd8..5be187c2d6 100644 --- a/framework_crates/bones_framework/src/render/color.rs +++ b/framework_crates/bones_framework/src/render/color.rs @@ -300,6 +300,35 @@ impl Color { } => [red, green, blue, alpha], } } + + /// Converts a `Color` to a `[f64; 4]` from sRGB colorspace + pub fn as_rgba_f64(self: Color) -> [f64; 4] { + match self { + Color::Rgba { + red, + green, + blue, + alpha, + } => [red as f64, green as f64, blue as f64, alpha as f64], + } + } + + /// Converts a `Color` to a `[u8; 4]` from sRGB colorspace + pub fn as_rgba_u8(self: Color) -> [u8; 4] { + match self { + Color::Rgba { + red, + green, + blue, + alpha, + } => [ + (red * 255.0) as u8, + (green * 255.0) as u8, + (blue * 255.0) as u8, + (alpha * 255.0) as u8, + ], + } + } } impl Default for Color { diff --git a/framework_crates/bones_framework/src/render/tilemap.rs b/framework_crates/bones_framework/src/render/tilemap.rs index 2da156303b..74e0aa6db2 100644 --- a/framework_crates/bones_framework/src/render/tilemap.rs +++ b/framework_crates/bones_framework/src/render/tilemap.rs @@ -25,6 +25,8 @@ pub struct Tile { pub flip_x: bool, /// Whether or not to flip tile vertically. pub flip_y: bool, + /// The tile's color tint + pub color: Color, } impl TileLayer { diff --git a/framework_crates/bones_framework/src/render/transform.rs b/framework_crates/bones_framework/src/render/transform.rs index c42c17a196..428587f6ea 100644 --- a/framework_crates/bones_framework/src/render/transform.rs +++ b/framework_crates/bones_framework/src/render/transform.rs @@ -1,6 +1,7 @@ //! Transform component. use crate::prelude::*; +use std::f32::consts::PI; /// The main transform component. /// @@ -47,4 +48,58 @@ impl Transform { pub fn from_scale(scale: Vec3) -> Self { Self { scale, ..default() } } + + /// Create a transform from a transformation matrix. + pub fn from_matrix(matrix: Mat4) -> Self { + let (scale, rotation, translation) = matrix.to_scale_rotation_translation(); + + Self { + translation, + rotation, + scale, + } + } + + /// Converts the transform to a 4x4 matrix for rendering + pub fn to_matrix(&self, translation_scale: Vec3) -> Mat4 { + let angle = self.rotation.z.rem_euclid(2.0 * PI); + let rotation = Mat4::from_rotation_z(angle); + + let scale_rotation = rotation * Mat4::from_scale(self.scale); + Mat4::from_translation(self.translation * translation_scale) * scale_rotation + } + + /// Converts to a matrix without translation scale + pub fn to_matrix_none(&self) -> Mat4 { + Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation) + } + + /// Converts the transform to a 4x4 matrix for rendering, + /// scaling off from the given pivot (for example, the center of the screen). + pub fn to_matrix_with_pivot(&self, pivot: Vec3) -> Mat4 { + let angle = self.rotation.z.rem_euclid(2.0 * PI); + let rotation = Mat4::from_rotation_z(angle); + + let scale_offset = Mat4::from_translation(pivot) + * Mat4::from_scale(self.scale) + * Mat4::from_translation(-pivot); + + Mat4::from_translation(self.translation) * rotation * scale_offset + } + + /// Converts the transform to a 4x4 matrix for rendering, + /// using a separate pivot for scaling and for rotation. + pub fn to_matrix_with_pivots(&self, pivot_scale: Vec3, pivot_rot: Vec3) -> Mat4 { + let scale_transform = Mat4::from_translation(pivot_scale) + * Mat4::from_scale(self.scale) + * Mat4::from_translation(-pivot_scale); + + let angle = self.rotation.z.rem_euclid(2.0 * std::f32::consts::PI); + let rotation = Mat4::from_rotation_z(angle); + + let rotation_transform = + Mat4::from_translation(pivot_rot) * rotation * Mat4::from_translation(-pivot_rot); + + Mat4::from_translation(self.translation) * rotation_transform * scale_transform + } } diff --git a/framework_crates/bones_framework/src/render/ui.rs b/framework_crates/bones_framework/src/render/ui.rs index d47dd770e8..a3610d1c13 100644 --- a/framework_crates/bones_framework/src/render/ui.rs +++ b/framework_crates/bones_framework/src/render/ui.rs @@ -35,14 +35,14 @@ impl EguiInputHook { } /// Resource that maps image handles to their associated egui textures. -#[derive(HasSchema, Clone, Debug, Default, Deref, DerefMut)] -pub struct EguiTextures(pub HashMap, egui::TextureId>); +#[derive(HasSchema, Clone, Default, Deref, DerefMut)] +pub struct EguiTextures(pub HashMap, egui::TextureHandle>); impl EguiTextures { /// Get the [`egui::TextureId`] for the given bones [`Handle`]. #[track_caller] pub fn get(&self, handle: Handle) -> egui::TextureId { - *self.0.get(&handle).unwrap() + self.0.get(&handle).unwrap().id() } } @@ -180,13 +180,13 @@ pub trait EguiContextExt { impl EguiContextExt for &egui::Context { fn clear_focus(self) { - self.memory_mut(|r| r.request_focus(egui::Id::null())); + self.memory_mut(|r| r.request_focus(egui::Id::NULL)); } fn get_state(self) -> T { - self.data_mut(|data| data.get_temp_mut_or_default::(egui::Id::null()).clone()) + self.data_mut(|data| data.get_temp_mut_or_default::(egui::Id::NULL).clone()) } fn set_state(self, value: T) { - self.data_mut(|data| *data.get_temp_mut_or_default::(egui::Id::null()) = value); + self.data_mut(|data| *data.get_temp_mut_or_default::(egui::Id::NULL) = value); } } @@ -198,7 +198,7 @@ pub trait EguiResponseExt { impl EguiResponseExt for egui::Response { fn focus_by_default(self, ui: &mut egui::Ui) -> egui::Response { - if ui.ctx().memory(|r| r.focus().is_none()) { + if ui.ctx().memory(|r| r.focused().is_none()) { ui.ctx().memory_mut(|r| r.request_focus(self.id)); self diff --git a/framework_crates/bones_framework/src/render/ui/widgets.rs b/framework_crates/bones_framework/src/render/ui/widgets.rs index 8d4aaf3eb5..9404589711 100644 --- a/framework_crates/bones_framework/src/render/ui/widgets.rs +++ b/framework_crates/bones_framework/src/render/ui/widgets.rs @@ -75,7 +75,7 @@ pub struct MarginMeta { pub right: f32, } -impl From for egui::style::Margin { +impl From for egui::epaint::Marginf { fn from(m: MarginMeta) -> Self { Self { left: m.left, diff --git a/framework_crates/bones_framework/src/render/ui/widgets/bordered_button.rs b/framework_crates/bones_framework/src/render/ui/widgets/bordered_button.rs index 42df4fbd7d..64ec17a062 100644 --- a/framework_crates/bones_framework/src/render/ui/widgets/bordered_button.rs +++ b/framework_crates/bones_framework/src/render/ui/widgets/bordered_button.rs @@ -16,8 +16,8 @@ pub struct BorderedButton<'a> { default_border: Option<&'a BorderImageMeta>, on_focus_border: Option<&'a BorderImageMeta>, on_click_border: Option<&'a BorderImageMeta>, - margin: egui::style::Margin, - padding: egui::style::Margin, + margin: egui::epaint::Marginf, + padding: egui::epaint::Marginf, } impl<'a> BorderedButton<'a> { @@ -78,7 +78,7 @@ impl<'a> BorderedButton<'a> { /// Set the margin. This will be applied on the outside of the border. #[must_use = "You must call .show() to render the button"] - pub fn margin(mut self, margin: impl Into) -> Self { + pub fn margin(mut self, margin: impl Into) -> Self { self.margin = margin.into(); self @@ -86,7 +86,7 @@ impl<'a> BorderedButton<'a> { /// Set the padding. This will be applied on the inside of the border. #[must_use = "You must call .show() to render the button"] - pub fn padding(mut self, padding: impl Into) -> Self { + pub fn padding(mut self, padding: impl Into) -> Self { self.padding = padding.into(); self @@ -153,13 +153,26 @@ impl<'a> Widget for BorderedButton<'a> { let total_extra = padding.sum() + margin.sum(); let wrap_width = ui.available_width() - total_extra.x; - let text = text.into_galley(ui, wrap, wrap_width, TextStyle::Button); + let text = text.into_galley( + ui, + if let Some(wrap) = wrap { + if wrap { + Some(egui::TextWrapMode::Wrap) + } else { + None + } + } else { + None + }, + wrap_width, + TextStyle::Button, + ); let mut desired_size = text.size() + total_extra; desired_size = desired_size.at_least(egui::vec2(min_size.x, min_size.y)); let (rect, response) = ui.allocate_at_least(desired_size, sense); - response.widget_info(|| WidgetInfo::labeled(WidgetType::Button, text.text())); + response.widget_info(|| WidgetInfo::labeled(WidgetType::Button, true, text.text())); // Focus the button automatically when it is hovered and the mouse is moving if response.hovered() @@ -199,7 +212,7 @@ impl<'a> Widget for BorderedButton<'a> { if let Some(border) = border { let texture = ui.data(|map| { - map.get_temp::>(egui::Id::null()) + map.get_temp::>(egui::Id::NULL) .unwrap() .borrow() .unwrap() @@ -209,7 +222,10 @@ impl<'a> Widget for BorderedButton<'a> { .add(BorderedFrame::new(border).paint(texture, border_rect)); } - text.paint_with_visuals(ui.painter(), label_pos, visuals); + // OLD + //text.paint_with_visuals(ui.painter(), label_pos, visuals); + + ui.painter().galley(label_pos, text, visuals.text_color()); } response diff --git a/framework_crates/bones_framework/src/render/ui/widgets/bordered_frame.rs b/framework_crates/bones_framework/src/render/ui/widgets/bordered_frame.rs index d34f56135a..7b98fa242d 100644 --- a/framework_crates/bones_framework/src/render/ui/widgets/bordered_frame.rs +++ b/framework_crates/bones_framework/src/render/ui/widgets/bordered_frame.rs @@ -5,9 +5,9 @@ pub struct BorderedFrame { bg_handle: Handle, border_scale: f32, texture_size: egui::Vec2, - texture_border_size: egui::style::Margin, - padding: egui::style::Margin, - margin: egui::style::Margin, + texture_border_size: egui::epaint::Marginf, + padding: egui::epaint::Marginf, + margin: egui::epaint::Marginf, border_only: bool, } @@ -29,7 +29,7 @@ impl BorderedFrame { /// Set the padding. This will be applied on the inside of the border. #[must_use = "You must call .show() to render the frame"] - pub fn padding(mut self, margin: impl Into) -> Self { + pub fn padding(mut self, margin: impl Into) -> Self { self.padding = margin.into(); self @@ -37,7 +37,7 @@ impl BorderedFrame { /// Set the margin. This will be applied on the outside of the border. #[must_use = "You must call .show() to render the frame"] - pub fn margin(mut self, margin: egui::style::Margin) -> Self { + pub fn margin(mut self, margin: egui::epaint::Marginf) -> Self { self.margin = margin; self @@ -97,7 +97,11 @@ impl BorderedFrame { content_rect.max.x = content_rect.max.x.max(content_rect.min.x); content_rect.max.y = content_rect.max.y.max(content_rect.min.y); - let content_ui = ui.child_ui(content_rect, *ui.layout()); + let content_ui = ui.new_child(egui::UiBuilder { + layout: Some(*ui.layout()), + max_rect: Some(content_rect), + ..Default::default() + }); BorderedFramePrepared { frame: self, @@ -120,13 +124,13 @@ impl BorderedFrame { let b = self.texture_border_size; let pr = paint_rect; // UV border - let buv = egui::style::Margin { + let buv = egui::epaint::Marginf { left: b.left / s.x, right: b.right / s.x, top: b.top / s.y, bottom: b.bottom / s.y, }; - let b = egui::style::Margin { + let b = egui::epaint::Marginf { left: b.left * self.border_scale, right: b.right * self.border_scale, top: b.top * self.border_scale, @@ -243,7 +247,7 @@ impl BorderedFrame { white, ); - egui::Shape::Mesh(mesh) + egui::Shape::Mesh(mesh.into()) } } @@ -266,7 +270,7 @@ impl BorderedFramePrepared { }; if ui.is_rect_visible(paint_rect) { let texture = ui.data(|map| { - map.get_temp::>(egui::Id::null()) + map.get_temp::>(egui::Id::NULL) .unwrap() .borrow() .unwrap() diff --git a/framework_crates/bones_wgpu_renderer/Cargo.toml b/framework_crates/bones_wgpu_renderer/Cargo.toml new file mode 100644 index 0000000000..fef4aaa9d2 --- /dev/null +++ b/framework_crates/bones_wgpu_renderer/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "bones_wgpu_renderer" +description = "WGPU rendering implementation for the bones_framework." +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +documentation.workspace = true +categories.workspace = true +keywords.workspace = true + +[dependencies] +bones_framework = { version = "0.4.0", path = "../bones_framework" } +bones_schema = { path = "../bones_schema" } +winit = "0.30.9" +wgpu = "24" +profiling = "1.0.16" +pollster = "0.4.0" +env_logger = "0.11.6" +log = "0.4" +bevy_tasks = "0.11.3" +image = "0.24.9" +crossbeam-channel = "0.5.14" +bytemuck = "1.22" +lyon = "1.0.1" + +guillotiere = "0.6.2" +anyhow = "1.0.98" + +egui = "0.31" +egui-wgpu = "0.31" +egui-winit = "0.31" + +serde = "1.0.188" +serde_yaml = "0.9" + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +directories = "5.0" diff --git a/framework_crates/bones_wgpu_renderer/src/atlas_pool.rs b/framework_crates/bones_wgpu_renderer/src/atlas_pool.rs new file mode 100644 index 0000000000..c4ad965aba --- /dev/null +++ b/framework_crates/bones_wgpu_renderer/src/atlas_pool.rs @@ -0,0 +1,188 @@ +use bones_framework::prelude::Entity; +use crossbeam_channel::bounded; +use guillotiere::{size2, AllocId, Allocation, AtlasAllocator}; +use std::sync::Arc; + +/// Code for the AtlasPool and the TextureAtlas. +/// A pool of texture atlases, each capable of holding multiple sprites. + +pub struct AtlasPool { + device: Arc, + layout: Arc, + pub atlases: Vec, + next_id: usize, + max_atlases: usize, + pub atlas_size: (u32, u32), + pixel_art: bool, + //Used to remove deleted textures + pub sender: crossbeam_channel::Sender<(Entity, usize, Allocation)>, + pub receiver: crossbeam_channel::Receiver<(Entity, usize, Allocation)>, +} + +impl AtlasPool { + pub fn new( + device: &Arc, + layout: &Arc, + atlas_size: (u32, u32), + max_atlases: usize, + pixel_art: bool, + ) -> Self { + // I think 100 is a good number? + let (sender, receiver) = bounded(1000); + + AtlasPool { + device: device.clone(), + layout: layout.clone(), + atlases: Vec::new(), + next_id: 0, + max_atlases, + atlas_size, + pixel_art, + sender, + receiver, + } + } + + /// Allocate a rectangle of `size` in one of the atlases. + /// If none has room and we’re under `max_atlases`, we create a new atlas. + /// If at capacity and no atlas has space, returns an error. + pub fn allocate(&mut self, size: (i32, i32)) -> Result<(usize, Allocation), String> { + // 1) Try existing atlases + if let Some((idx, alloc)) = self + .atlases + .iter_mut() + .enumerate() + .filter_map(|(i, a)| a.allocate(size).map(|alloc| (i, alloc))) + .next() + { + return Ok((self.atlases[idx].id, alloc)); + } + + // 2) Need a new atlas? + if self.atlases.len() < self.max_atlases { + let id = self.next_id; + self.next_id += 1; + + let mut atlas = TextureAtlas::new( + &self.device, + &self.layout, + id, + self.atlas_size, + self.pixel_art, + ); + let alloc = atlas + .allocate(size) + .expect("Newly-created atlas must fit the requested sprite size"); + self.atlases.push(atlas); + return Ok((id, alloc)); + } + + // 3) All atlases full + Err(format!( + "AtlasPool: all {} atlases are full, cannot allocate size {:?}", + self.max_atlases, size + )) + } + + /// Frees the given allocation back into its atlas, making space reusable. + pub fn deallocate(&mut self, atlas_id: usize, alloc: Allocation) -> bool { + if let Some(atlas) = self.atlases.iter_mut().find(|a| a.id == atlas_id) { + atlas.deallocate(alloc.id); + true + } else { + false + } + } +} + +pub struct TextureAtlas { + pub id: usize, + pub allocator: AtlasAllocator, // guillotiere packing + pub texture: wgpu::Texture, // the GPU texture + pub view: wgpu::TextureView, + pub bind_group: wgpu::BindGroup, // for sampling it in shaders + pub allocated: usize, +} + +impl TextureAtlas { + pub fn new( + device: &wgpu::Device, + layout: &wgpu::BindGroupLayout, + id: usize, + size: (u32, u32), + pixel_art: bool, + ) -> Self { + // initialize allocator + let allocator = AtlasAllocator::new(size2(size.0 as i32, size.1 as i32)); + + // create GPU texture + let texture = device.create_texture(&wgpu::TextureDescriptor { + label: Some(&format!("Atlas #{}", id)), + size: wgpu::Extent3d { + width: size.0, + height: size.1, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8UnormSrgb, + usage: wgpu::TextureUsages::TEXTURE_BINDING + | wgpu::TextureUsages::COPY_DST + | wgpu::TextureUsages::COPY_SRC, + view_formats: &[], + }); + + let view = texture.create_view(&Default::default()); + let sampler = device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: if pixel_art { + wgpu::FilterMode::Nearest + } else { + wgpu::FilterMode::Linear + }, + min_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::FilterMode::Nearest, + ..Default::default() + }); + + // create bind group + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&sampler), + }, + ], + label: Some(&format!("Atlas BG #{}", id)), + }); + + TextureAtlas { + id, + allocator, + texture, + view, + bind_group, + allocated: 0, + } + } + + /// Attempt to allocate; returns None if sprite doesn't fit + pub fn allocate(&mut self, size: (i32, i32)) -> Option { + self.allocated += 1; + self.allocator.allocate(size.into()) + } + + /// Free a single rectangle back into this atlas’s free-list + pub fn deallocate(&mut self, alloc_id: AllocId) { + self.allocated -= 1; + self.allocator.deallocate(alloc_id); + } +} diff --git a/framework_crates/bones_wgpu_renderer/src/atlas_sprite.wgsl b/framework_crates/bones_wgpu_renderer/src/atlas_sprite.wgsl new file mode 100644 index 0000000000..3e0915b0e7 --- /dev/null +++ b/framework_crates/bones_wgpu_renderer/src/atlas_sprite.wgsl @@ -0,0 +1,181 @@ +// Must match the Rust layout +struct AtlasSpriteUniform { + entity_type: u32, + camera_index: u32, + _pad0: u32, + _pad1: u32, + transform: mat4x4, + color_tint: vec4, + + flip_x: u32, + flip_y: u32, + uv_min: vec2, + uv_max: vec2, + + tile_size: vec2, + image_size: vec2, + padding: vec2, + offset: vec2, + + columns: u32, + index: u32, +}; + +// Camera uniform, one per render pass +struct CameraUniform { + transform: mat4x4, + screen_size: vec2, + _pad0: u32, + _pad1: u32, // Padding to ensure 16-byte alignment +} + +// Bindings +@group(0) @binding(0) var diffuseTex: texture_2d; +@group(0) @binding(1) var texSampler: sampler; + +// All per-instance data lives here +@group(1) @binding(0) +var sprite_data: array; + +@group(2) @binding(0) +var cameras: array; + +// Quad vertex input +struct VertexInput { + @location(0) position: vec3, + @location(1) uv: vec2, +}; + +// Data we pass to the fragment stage +struct VertexOutput { + @builtin(position) clipPos: vec4, + @location(0) atlas_uv: vec2, + @location(1) inst_index: u32, +}; + +// Vertex Shader +@vertex +fn vs_main( + vert: VertexInput, + @builtin(instance_index) idx: u32 +) -> VertexOutput { + let inst = sprite_data[idx]; + var out: VertexOutput; + + var uv_size: vec2; + if inst.entity_type == 1u { + // For atlas/tiles: use tile_size directly + uv_size = inst.tile_size; + } else { + // For sprites: use calculated UV size multiplied by 4096 (atlas pool size) + uv_size = (inst.uv_max - inst.uv_min) * 4096.0; + } + + // Convert UV size to world size: use a fixed scale factor instead of screen size + // This prevents distortion when window is resized + let pixel_scale = 0.001; // Adjust this value to control sprite size (smaller = smaller sprites) + uv_size = uv_size * pixel_scale; + + let aspect_ratio = uv_size.x / uv_size.y; + + // Scale position by UV size (not just aspect ratio) + let scaled_position = vec3( + vert.position.x * uv_size.x, + vert.position.y * uv_size.y, + vert.position.z + ); + + // load the camera uniform + let camera = cameras[inst.camera_index]; + + // 1) Transform should use the same pixel_scale so 1 unit = 1 pixel + // Scale transform by pixel_scale to match sprite scaling + let transform_scale = vec3(pixel_scale, pixel_scale, 1.0); + let inst_mat = scale_translation(inst.transform, transform_scale); + + // 2) apply camera→clip transform + out.clipPos = camera.transform * inst_mat * vec4(scaled_position, 1.0); + + // 2) Apply per‑instance flip + var base_uv = vert.uv; + if inst.flip_x == 1u { base_uv.x = 1.0 - base_uv.x; } + if inst.flip_y == 1u { base_uv.y = 1.0 - base_uv.y; } + + // 3) Remap [0,1] → [uv_min,uv_max] of the atlas + out.atlas_uv = mix(inst.uv_min, inst.uv_max, base_uv); + + // 4) Pass instance index along + out.inst_index = idx; + return out; +} + +// Fragment Shader +@fragment +fn fs_main( + in: VertexOutput +) -> @location(0) vec4 { + let inst = sprite_data[in.inst_index]; + + // Start with the quad’s atlas-mapped UV + var uv = in.atlas_uv; + + //If this is a tiled sheet sprite, compute the sub‐cell + if inst.entity_type == 1u { + // Normalize dimensions by image size + let ts = inst.tile_size / inst.image_size; + let ps = inst.padding / inst.image_size; + let os = inst.offset / inst.image_size; + + // Calculate tile position + let col = inst.index % inst.columns; + let row = inst.index / inst.columns; + + // Calculate step size (tile + padding) + let step = ts + ps; + + // Calculate top-left corner of tile + let tile_min = os + vec2(f32(col), f32(row)) * step; + + // Calculate bottom-right corner of tile (exclude padding) + let tile_max = tile_min + ts; + // Map UV from [0,1] to [tile_min, tile_max] (only tile area, not padding) + uv = mix(tile_min, tile_max, uv); + } + + // Sample the atlas at the correct UV and apply tint + let tex_col = textureSample(diffuseTex, texSampler, uv); + return tex_col * inst.color_tint; + //return inst.color_tint; +} + +fn scale_translation(matrix: mat4x4, translation_scale: vec3) -> mat4x4 { + // Extract translation from last column + let translation = matrix[3].xyz; + + // Extract scale from basis vector lengths + let scale = vec3( + length(matrix[0].xyz), + length(matrix[1].xyz), + length(matrix[2].xyz) + ); + + // Extract Z-rotation from first column + let angle = atan2(matrix[0].y, matrix[0].x); + + // Compute sin/cos once + let c = cos(angle); + let s = sin(angle); + + // Scale translation components + let tx = translation.x * translation_scale.x; + let ty = translation.y * translation_scale.y; + let tz = translation.z * translation_scale.z; + + // Rebuild matrix in column-major order + return mat4x4( + vec4(c * scale.x, s * scale.x, 0.0, 0.0), // Column 0 + vec4(-s * scale.y, c * scale.y, 0.0, 0.0), // Column 1 + vec4(0.0, 0.0, scale.z, 0.0), // Column 2 + vec4(tx, ty, tz, 1.0) // Column 3 + ); +} diff --git a/framework_crates/bones_wgpu_renderer/src/convert.rs b/framework_crates/bones_wgpu_renderer/src/convert.rs new file mode 100644 index 0000000000..6397985dde --- /dev/null +++ b/framework_crates/bones_wgpu_renderer/src/convert.rs @@ -0,0 +1,235 @@ +use bones_framework::glam::Vec2; +use bones_framework::prelude::{self as bones}; +use winit::event::{MouseButton, MouseScrollDelta}; +use winit::{event::ElementState, keyboard::KeyCode}; + +pub trait IntoBones { + fn into_bones(self) -> T; +} + +impl IntoBones for MouseScrollDelta { + fn into_bones(self) -> bones::MouseScrollEvent { + match self { + MouseScrollDelta::LineDelta(x, y) => bones::MouseScrollEvent { + movement: Vec2::new(x, y), + unit: bones::MouseScrollUnit::Lines, + }, + MouseScrollDelta::PixelDelta(physical_position) => bones::MouseScrollEvent { + movement: Vec2::new(physical_position.x as f32, physical_position.y as f32), + unit: bones::MouseScrollUnit::Pixels, + }, + } + } +} + +impl IntoBones for ElementState { + fn into_bones(self) -> bones::ButtonState { + match self { + ElementState::Pressed => bones::ButtonState::Pressed, + ElementState::Released => bones::ButtonState::Released, + } + } +} + +impl IntoBones for MouseButton { + fn into_bones(self) -> bones::MouseButton { + match self { + MouseButton::Left => bones::MouseButton::Left, + MouseButton::Right => bones::MouseButton::Right, + MouseButton::Middle => bones::MouseButton::Middle, + MouseButton::Back => bones::MouseButton::Back, + MouseButton::Forward => bones::MouseButton::Forward, + MouseButton::Other(i) => bones::MouseButton::Other(i), + } + } +} + +impl IntoBones for winit::keyboard::KeyCode { + fn into_bones(self) -> bones::KeyCode { + match self { + KeyCode::Digit1 => bones::KeyCode::Key1, + KeyCode::Digit2 => bones::KeyCode::Key2, + KeyCode::Digit3 => bones::KeyCode::Key3, + KeyCode::Digit4 => bones::KeyCode::Key4, + KeyCode::Digit5 => bones::KeyCode::Key5, + KeyCode::Digit6 => bones::KeyCode::Key6, + KeyCode::Digit7 => bones::KeyCode::Key7, + KeyCode::Digit8 => bones::KeyCode::Key8, + KeyCode::Digit9 => bones::KeyCode::Key9, + KeyCode::Digit0 => bones::KeyCode::Key0, + KeyCode::KeyA => bones::KeyCode::A, + KeyCode::KeyB => bones::KeyCode::B, + KeyCode::KeyC => bones::KeyCode::C, + KeyCode::KeyD => bones::KeyCode::D, + KeyCode::KeyE => bones::KeyCode::E, + KeyCode::KeyF => bones::KeyCode::F, + KeyCode::KeyG => bones::KeyCode::G, + KeyCode::KeyH => bones::KeyCode::H, + KeyCode::KeyI => bones::KeyCode::I, + KeyCode::KeyJ => bones::KeyCode::J, + KeyCode::KeyK => bones::KeyCode::K, + KeyCode::KeyL => bones::KeyCode::L, + KeyCode::KeyM => bones::KeyCode::M, + KeyCode::KeyN => bones::KeyCode::N, + KeyCode::KeyO => bones::KeyCode::O, + KeyCode::KeyP => bones::KeyCode::P, + KeyCode::KeyQ => bones::KeyCode::Q, + KeyCode::KeyR => bones::KeyCode::R, + KeyCode::KeyS => bones::KeyCode::S, + KeyCode::KeyT => bones::KeyCode::T, + KeyCode::KeyU => bones::KeyCode::U, + KeyCode::KeyV => bones::KeyCode::V, + KeyCode::KeyW => bones::KeyCode::W, + KeyCode::KeyX => bones::KeyCode::X, + KeyCode::KeyY => bones::KeyCode::Y, + KeyCode::KeyZ => bones::KeyCode::Z, + KeyCode::Escape => bones::KeyCode::Escape, + KeyCode::F1 => bones::KeyCode::F1, + KeyCode::F2 => bones::KeyCode::F2, + KeyCode::F3 => bones::KeyCode::F3, + KeyCode::F4 => bones::KeyCode::F4, + KeyCode::F5 => bones::KeyCode::F5, + KeyCode::F6 => bones::KeyCode::F6, + KeyCode::F7 => bones::KeyCode::F7, + KeyCode::F8 => bones::KeyCode::F8, + KeyCode::F9 => bones::KeyCode::F9, + KeyCode::F10 => bones::KeyCode::F10, + KeyCode::F11 => bones::KeyCode::F11, + KeyCode::F12 => bones::KeyCode::F12, + KeyCode::F13 => bones::KeyCode::F13, + KeyCode::F14 => bones::KeyCode::F14, + KeyCode::F15 => bones::KeyCode::F15, + KeyCode::F16 => bones::KeyCode::F16, + KeyCode::F17 => bones::KeyCode::F17, + KeyCode::F18 => bones::KeyCode::F18, + KeyCode::F19 => bones::KeyCode::F19, + KeyCode::F20 => bones::KeyCode::F20, + KeyCode::F21 => bones::KeyCode::F21, + KeyCode::F22 => bones::KeyCode::F22, + KeyCode::F23 => bones::KeyCode::F23, + KeyCode::F24 => bones::KeyCode::F24, + KeyCode::PrintScreen => bones::KeyCode::Snapshot, + // Normally on the same key as PrintScreen, and we are already mapping it + //KeyCode::PrintScreen => bones::KeyCode::Sysrq, + KeyCode::ScrollLock => bones::KeyCode::Scroll, + KeyCode::Pause => bones::KeyCode::Pause, + KeyCode::Insert => bones::KeyCode::Insert, + KeyCode::Home => bones::KeyCode::Home, + KeyCode::Delete => bones::KeyCode::Delete, + KeyCode::End => bones::KeyCode::End, + KeyCode::PageDown => bones::KeyCode::PageDown, + KeyCode::PageUp => bones::KeyCode::PageUp, + KeyCode::ArrowLeft => bones::KeyCode::Left, + KeyCode::ArrowUp => bones::KeyCode::Up, + KeyCode::ArrowRight => bones::KeyCode::Right, + KeyCode::ArrowDown => bones::KeyCode::Down, + KeyCode::Backspace => bones::KeyCode::Back, + KeyCode::Enter => bones::KeyCode::Return, + KeyCode::Space => bones::KeyCode::Space, + KeyCode::NumLock => bones::KeyCode::Numlock, + KeyCode::Numpad0 => bones::KeyCode::Numpad0, + KeyCode::Numpad1 => bones::KeyCode::Numpad1, + KeyCode::Numpad2 => bones::KeyCode::Numpad2, + KeyCode::Numpad3 => bones::KeyCode::Numpad3, + KeyCode::Numpad4 => bones::KeyCode::Numpad4, + KeyCode::Numpad5 => bones::KeyCode::Numpad5, + KeyCode::Numpad6 => bones::KeyCode::Numpad6, + KeyCode::Numpad7 => bones::KeyCode::Numpad7, + KeyCode::Numpad8 => bones::KeyCode::Numpad8, + KeyCode::Numpad9 => bones::KeyCode::Numpad9, + KeyCode::NumpadAdd => bones::KeyCode::NumpadAdd, + KeyCode::Equal => bones::KeyCode::Equals, + // Winit doesn't differentiate both '+' and '=', considering they are usually + // on the same physical key, and we are already mapping it + //KeyCode::Equal => bones::KeyCode::Plus, + KeyCode::Backslash => bones::KeyCode::Backslash, + // LaunchApp2 is sometimes named Calculator + KeyCode::LaunchApp2 => bones::KeyCode::Calculator, + KeyCode::CapsLock => bones::KeyCode::Capital, + KeyCode::Comma => bones::KeyCode::Comma, + KeyCode::Convert => bones::KeyCode::Convert, + KeyCode::NumpadDecimal => bones::KeyCode::NumpadDecimal, + KeyCode::NumpadDivide => bones::KeyCode::NumpadDivide, + KeyCode::Backquote => bones::KeyCode::Grave, + KeyCode::AltLeft => bones::KeyCode::AltLeft, + KeyCode::BracketLeft => bones::KeyCode::BracketLeft, + KeyCode::ControlLeft => bones::KeyCode::ControlLeft, + KeyCode::ShiftLeft => bones::KeyCode::ShiftLeft, + KeyCode::SuperLeft => bones::KeyCode::SuperLeft, + KeyCode::LaunchMail => bones::KeyCode::Mail, + KeyCode::MediaSelect => bones::KeyCode::MediaSelect, + KeyCode::MediaStop => bones::KeyCode::MediaStop, + KeyCode::Minus => bones::KeyCode::Minus, + KeyCode::NumpadMultiply => bones::KeyCode::NumpadMultiply, + KeyCode::AudioVolumeMute => bones::KeyCode::Mute, + // LaunchApp1 is sometimes named MyComputer + KeyCode::LaunchApp1 => bones::KeyCode::MyComputer, + KeyCode::MediaTrackNext => bones::KeyCode::NextTrack, + KeyCode::NumpadComma => bones::KeyCode::NumpadComma, + KeyCode::NumpadEnter => bones::KeyCode::NumpadEnter, + KeyCode::NumpadEqual => bones::KeyCode::NumpadEquals, + KeyCode::Period => bones::KeyCode::Period, + KeyCode::MediaPlayPause => bones::KeyCode::PlayPause, + KeyCode::Power => bones::KeyCode::Power, + KeyCode::MediaTrackPrevious => bones::KeyCode::PrevTrack, + KeyCode::AltRight => bones::KeyCode::AltRight, + KeyCode::BracketRight => bones::KeyCode::BracketRight, + KeyCode::ControlRight => bones::KeyCode::ControlRight, + KeyCode::ShiftRight => bones::KeyCode::ShiftRight, + KeyCode::SuperRight => bones::KeyCode::SuperRight, + KeyCode::Semicolon => bones::KeyCode::Semicolon, + KeyCode::Slash => bones::KeyCode::Slash, + KeyCode::Sleep => bones::KeyCode::Sleep, + KeyCode::NumpadSubtract => bones::KeyCode::NumpadSubtract, + KeyCode::Tab => bones::KeyCode::Tab, + KeyCode::AudioVolumeDown => bones::KeyCode::VolumeDown, + KeyCode::AudioVolumeUp => bones::KeyCode::VolumeUp, + KeyCode::WakeUp => bones::KeyCode::Wake, + KeyCode::BrowserBack => bones::KeyCode::WebBack, + KeyCode::BrowserFavorites => bones::KeyCode::WebFavorites, + KeyCode::BrowserForward => bones::KeyCode::WebForward, + KeyCode::BrowserHome => bones::KeyCode::WebHome, + KeyCode::BrowserRefresh => bones::KeyCode::WebRefresh, + KeyCode::BrowserSearch => bones::KeyCode::WebSearch, + KeyCode::BrowserStop => bones::KeyCode::WebStop, + KeyCode::IntlYen => bones::KeyCode::Yen, + KeyCode::Copy => bones::KeyCode::Copy, + KeyCode::Paste => bones::KeyCode::Paste, + KeyCode::Cut => bones::KeyCode::Cut, + // These are not on the latest winit version, + // need to figure out how to handle them. + //KeyCode:: => bones::KeyCode::AbntC1, + //KeyCode:: => bones::KeyCode::AbntC2, + //KeyCode:: => bones::KeyCode::Apostrophe, + //KeyCode:: => bones::KeyCode::Asterisk, + + // Not sure how to implement this, maybe NonConvert? + //KeyCode::NonConvert => bones::KeyCode::NoConvert, + + // Not sure how to implement this + //KeyCode:: => bones::KeyCode::At, + //KeyCode:: => bones::KeyCode::Ax, + //KeyCode:: => bones::KeyCode::Colon, + //KeyCode:: => bones::KeyCode::Kana, + //KeyCode:: => bones::KeyCode::Kanji, + //KeyCode:: => bones::KeyCode::Unlabeled, + //KeyCode:: => bones::KeyCode::Oem102, + //KeyCode:: => bones::KeyCode::Underline, + //KeyCode:: => bones::KeyCode::Stop, + + // I think this is the same as PageUp and PageDown keys, but not sure. + // tho they are already mapped + //KeyCode::PageUp => bones::KeyCode::NavigateForward, + //KeyCode::PageDown => bones::KeyCode::NavigateBackward, + + // These are named keys now on winit, need to + // figure out how to handle them. + //NamedKey::Compose => bones::KeyCode::Compose, + //NamedKey::Caret => bones::KeyCode::Caret, + + // Not sure what this is, could be MediaApps or ContextMenu, or both + //KeyCode::MediaApps | KeyCode::ContextMenu => bones::KeyCode::Apps, + _ => unimplemented!(), + } + } +} diff --git a/framework_crates/bones_wgpu_renderer/src/dynamic_storage.rs b/framework_crates/bones_wgpu_renderer/src/dynamic_storage.rs new file mode 100644 index 0000000000..505ba970d7 --- /dev/null +++ b/framework_crates/bones_wgpu_renderer/src/dynamic_storage.rs @@ -0,0 +1,84 @@ +use std::sync::Arc; + +pub struct DynamicBuffer { + pub layout: Arc, + pub buffer: wgpu::Buffer, + bind_group: wgpu::BindGroup, + pub capacity: u64, // in bytes + buffer_usage: wgpu::BufferUsages, +} + +impl DynamicBuffer { + /// Create with an initial capacity (in bytes). + pub fn new( + device: &wgpu::Device, + layout: Arc, + initial_capacity: u64, + buffer_usage: wgpu::BufferUsages, + ) -> Self { + let buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("dynamic_storage_buffer"), + size: initial_capacity, + usage: buffer_usage | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &*layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: buffer.as_entire_binding(), + }], + label: Some("dynamic_storage_bind_group"), + }); + Self { + layout, + buffer, + bind_group, + capacity: initial_capacity, + buffer_usage, + } + } + + /// Ensure we have at least `needed` bytes; if not, reallocate & rebind. + fn ensure_capacity(&mut self, device: &wgpu::Device, needed: u64) { + if needed <= self.capacity { + return; + } + // double up (or at least `needed`) + let new_capacity = (self.capacity.max(needed)) * 2; + self.buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("dynamic_storage_buffer (resized)"), + size: new_capacity, + usage: self.buffer_usage | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + self.bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &*self.layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: self.buffer.as_entire_binding(), + }], + label: Some("dynamic_storage_bind_group (resized)"), + }); + self.capacity = new_capacity; + } + + /// Write your Pod‐slice into the buffer, growing if necessary. + pub fn write_pods( + &mut self, + device: &wgpu::Device, + queue: &wgpu::Queue, + data: &[T], + ) { + let needed_bytes = (data.len() * std::mem::size_of::()) as u64; + self.ensure_capacity(device, needed_bytes); + queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(data)); + + println!("DynamicBuffer: Wrote {} bytes", needed_bytes); + } + + /// Access the bind group for binding in your render pass. + pub fn get_bind_group(&self) -> &wgpu::BindGroup { + &self.bind_group + } +} diff --git a/framework_crates/bones_wgpu_renderer/src/lib.rs b/framework_crates/bones_wgpu_renderer/src/lib.rs new file mode 100644 index 0000000000..6bad8c8672 --- /dev/null +++ b/framework_crates/bones_wgpu_renderer/src/lib.rs @@ -0,0 +1,1189 @@ +use bevy_tasks::{IoTaskPool, TaskPool}; +use convert::IntoBones; +use image::RgbaImage; +use pollster::FutureExt; +use std::{ + path::{Path, PathBuf}, + sync::Arc, + time::Instant, +}; +use wgpu::util::DeviceExt; +use winit::{ + application::ApplicationHandler, + event::WindowEvent, + event_loop::{ActiveEventLoop, ControlFlow, EventLoop}, + window::{Window, WindowId}, +}; + +use bones_framework::{ + glam::*, + input::gilrs::process_gamepad_events, + prelude::{self as bones}, +}; + +use egui_wgpu::ScreenDescriptor; + +mod atlas_pool; +mod convert; +mod dynamic_storage; +mod line; +mod sprite; +mod storage; +mod texture; +mod texture_file; +mod ui; + +use dynamic_storage::DynamicBuffer; +use sprite::*; +use ui::{default_load_progress, EguiRenderer}; + +/// The prelude +pub mod prelude { + pub use crate::*; +} + +//Wgpu utils Bones types + +#[derive(bones_schema::HasSchema, Default, Clone)] +#[repr(C)] +#[schema(opaque)] +struct WgpuDevice(Option>); + +impl WgpuDevice { + fn get(&self) -> &wgpu::Device { + self.0.as_ref().unwrap() + } +} + +#[derive(bones_schema::HasSchema, Default, Clone)] +#[repr(C)] +#[schema(opaque)] +struct WgpuQueue(Option>); + +impl WgpuQueue { + fn get(&self) -> &wgpu::Queue { + self.0.as_ref().unwrap() + } +} + +#[derive(bones_schema::HasSchema, Default, Clone)] +#[repr(C)] +struct PixelArt(bool); + +#[derive(bones_schema::HasSchema, Default, bones::Deref, bones::DerefMut)] +#[schema(no_clone)] +struct LoadingContext(pub Option); +type LoadingFunction = Box; + +/// Renderer for [`bones_framework`] [`Game`][bones::Game]s using wgpu. +pub struct BonesWgpuRenderer { + /// Whether or not to load all assets on startup with a loading screen, + /// or skip straight to running the bones game immedietally. + pub preload: bool, + /// Optional field to implement your own loading screen. Does nothing if [`Self::preload`] = false + pub custom_load_progress: Option, + /// Whether or not to use nearest-neighbor sampling for textures. + pub pixel_art: bool, + /// The bones game to run. + pub game: bones::Game, + /// The version of the game, used for the asset loader. + pub game_version: bones::Version, + /// The (qualifier, organization, application) that will be used to pick a persistent storage + /// location for the game. + /// + /// For example: `("org", "fishfolk", "jumpy")` + pub app_namespace: (String, String, String), + /// The path to load assets from. + pub asset_dir: PathBuf, + /// The path to load asset packs from. + pub packs_dir: PathBuf, +} + +impl BonesWgpuRenderer { + pub fn new(game: bones::Game) -> Self { + BonesWgpuRenderer { + preload: true, + custom_load_progress: None, + pixel_art: true, + game, + game_version: bones::Version::new(0, 1, 0), + app_namespace: ("local".into(), "developer".into(), "bones_demo_game".into()), + asset_dir: PathBuf::from("assets"), + packs_dir: PathBuf::from("packs"), + } + } + + pub fn run(mut self) { + //Start wgpu + let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default()); + let (adapter, device, queue) = async { + let adapter = instance + .request_adapter(&wgpu::RequestAdapterOptions::default()) + .await + .unwrap(); + + let (device, queue) = adapter + .request_device( + &wgpu::DeviceDescriptor::default(), + None, // Trace path + ) + .await + .unwrap(); + (Arc::new(adapter), Arc::new(device), Arc::new(queue)) + } + .block_on(); + + // Texture bind group layout (matches @group(0) in WGSL) + let texture_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + multisampled: false, + view_dimension: wgpu::TextureViewDimension::D2, + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + // This should match the filterable field of the textures + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, + ], + label: Some("texture_bind_group_layout"), + }); + + // Storage buffer bind group layout (matches @group(1) in WGSL) + let storage_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("storage_bind_group_layout"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: true }, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + }); + + let camera_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("camera_bind_group_layout"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: true }, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + }); + + let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Index Buffer"), + contents: bytemuck::cast_slice(INDICES), + usage: wgpu::BufferUsages::INDEX, + }); + let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Vertex Buffer"), + contents: bytemuck::cast_slice(VERTICES), + usage: wgpu::BufferUsages::VERTEX, + }); + + let instance = Arc::new(instance); + let texture_layout = Arc::new(texture_layout); + let storage_layout = Arc::new(storage_layout); + let camera_layout = Arc::new(camera_layout); + let vertex_buffer = Arc::new(vertex_buffer); + let index_buffer = Arc::new(index_buffer); + + //This is used to store dynamically some rendering data, like transform, flip, etc + let dynamic_storage = + DynamicBuffer::new(&device, storage_layout, 1024, wgpu::BufferUsages::STORAGE); + let camera_dynamic_uniform = + DynamicBuffer::new(&device, camera_layout, 1024, wgpu::BufferUsages::STORAGE); + + //Insert wgpu resources + self.game + .insert_shared_resource(WgpuDevice(Some(device.clone()))); + self.game + .insert_shared_resource(WgpuQueue(Some(queue.clone()))); + self.game.insert_shared_resource(PixelArt(self.pixel_art)); + self.game + .insert_shared_resource(LoadingContext(self.custom_load_progress)); + self.game.insert_shared_resource(Cameras(Vec::new())); + + //Deal with asset server + IoTaskPool::init(TaskPool::default); + if let Some(mut asset_server) = self.game.shared_resource_mut::() { + asset_server.set_game_version(self.game_version.clone()); + asset_server.set_io(asset_io(&self.asset_dir, &self.packs_dir)); + + if self.preload { + // Load assets + let s = asset_server.clone(); + println!("Loading Assets..."); + + // Spawn a task to load the assets + IoTaskPool::get() + .spawn(async move { + s.load_assets().await.unwrap(); + }) + .detach(); + } + + // Enable asset hot reload. + asset_server.watch_for_changes(); + } + + // Configure and load the persitent storage + let mut storage = bones::Storage::with_backend(Box::new(storage::StorageBackend::new( + &self.app_namespace.0, + &self.app_namespace.1, + &self.app_namespace.2, + ))); + storage.load(); + self.game.insert_shared_resource(storage); + + self.game + .insert_shared_resource(bones::EguiTextures::default()); + self.game.insert_shared_resource(bones::ExitBones(false)); + + // Insert empty inputs that will be updated by the `insert_bones_input` system later. + self.game.init_shared_resource::(); + self.game.init_shared_resource::(); + self.game.init_shared_resource::(); + self.game + .init_shared_resource::(); + self.game + .init_shared_resource::(); + + //Insert needed systems + self.game.systems.add_startup_system(load_egui_textures); + self.game.systems.add_startup_system(asset_load_status); + + // wgpu uses `log` for all of our logging, so we initialize a logger with the `env_logger` crate. + env_logger::init(); + + let event_loop = EventLoop::builder().build().unwrap(); + + // When the current loop iteration finishes, immediately begin a new + // iteration regardless of whether or not new events are available to + // process. + event_loop.set_control_flow(ControlFlow::Poll); + + let bind_group_clone = texture_layout.clone(); + let device_clone = device.clone(); + + let mut app = App { + state: None, + instance, + adapter, + device, + queue, + texture_layout, + storage_layout: dynamic_storage.layout.clone(), + dynamic_storage: Some(dynamic_storage), + camera_layout: camera_dynamic_uniform.layout.clone(), + camera_dynamic_uniform: Some(camera_dynamic_uniform), + game: self.game, + vertex_buffer, + index_buffer, + _now: Instant::now(), + atlas_pool: atlas_pool::AtlasPool::new( + &device_clone, + &bind_group_clone, + (4096, 4096), + 8, + self.pixel_art, + ), + }; + event_loop.run_app(&mut app).unwrap(); + + app.device.poll(wgpu::Maintain::Wait); + } +} + +fn asset_load_status(game: &mut bones::Game) { + let asset_server = game.shared_resource::().unwrap(); + let ctx = game.shared_resource::().unwrap(); + let mut function = game.shared_resource_mut::().unwrap(); + + if asset_server.load_progress.is_finished() { + return; + } + + if let Some(function) = &mut function.0 { + (function)(&asset_server, &ctx); + } else { + default_load_progress(&asset_server, &ctx); + } +} + +/// Startup system to load egui fonts and textures. +pub fn setup_egui(game: &mut bones::Game, ctx: &egui::Context) { + // Insert the egui context as a shared resource + game.insert_shared_resource(bones::EguiCtx(ctx.clone())); + + let asset_server = game.shared_resource::(); + + if let Some(bones_assets) = asset_server { + update_egui_fonts(ctx, &bones_assets); + + // Insert the bones egui textures + ctx.data_mut(|map| { + map.insert_temp( + egui::Id::NULL, + game.shared_resource_cell::().unwrap(), + ); + }); + } +} + +pub fn update_egui_fonts(ctx: &egui::Context, bones_assets: &bones::AssetServer) { + let mut fonts = egui::FontDefinitions::default(); + + for entry in bones_assets.store.assets.iter() { + let asset = entry.value(); + if let Ok(font) = asset.try_cast_ref::() { + let previous = fonts + .font_data + .insert(font.family_name.to_string(), font.data.clone().into()); + if previous.is_some() { + log::warn!( + "{} Found two fonts with the same family name, using \ + only the latest one", + font.family_name + ); + } + fonts + .families + .entry(egui::FontFamily::Name(font.family_name.clone())) + .or_default() + .push(font.family_name.to_string()); + } + } + + ctx.set_fonts(fonts); +} + +//TODO Handle asset changes +fn load_egui_textures(game: &mut bones::Game) { + let asset_server = game.shared_resource::().unwrap(); + let ctx = game.shared_resource::().unwrap(); + let mut egui_textures = game.shared_resource_mut::().unwrap(); + let pixel_art = game.shared_resource::().unwrap(); + + for entry in asset_server.store.asset_ids.iter() { + let id = entry.key().typed(); + if egui_textures.contains_key(&id) { + // we already loaded this one + continue; + } + + let asset = asset_server.store.assets.get_mut(entry.value()).unwrap(); + if let Ok(bones::Image::Data(data)) = asset.data.try_cast_ref::() { + let rgba: RgbaImage = data.to_rgba8(); + let (w, h) = (rgba.width() as usize, rgba.height() as usize); + let raw = rgba.into_raw(); + + let handle = ctx.load_texture( + format!("Texture {:?}", entry.key()), + egui::ColorImage::from_rgba_unmultiplied([w, h], &raw), + egui::TextureOptions { + magnification: if pixel_art.0 { + egui::TextureFilter::Nearest + } else { + egui::TextureFilter::Linear + }, + minification: if pixel_art.0 { + egui::TextureFilter::Nearest + } else { + egui::TextureFilter::Linear + }, + ..Default::default() + }, + ); + egui_textures.insert(id, handle); + } + } +} + +//TODO Implement proper Drop for the app +struct App { + state: Option, + atlas_pool: atlas_pool::AtlasPool, + instance: Arc, + adapter: Arc, + device: Arc, + queue: Arc, + texture_layout: Arc, + storage_layout: Arc, + dynamic_storage: Option, + camera_layout: Arc, + camera_dynamic_uniform: Option, + vertex_buffer: Arc, + index_buffer: Arc, + game: bones::Game, + _now: Instant, +} + +impl ApplicationHandler for App { + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + // Create window object + let window = Arc::new( + event_loop + .create_window(Window::default_attributes()) + .unwrap(), + ); + + if let Some(state) = &mut self.state { + state.window = window.clone(); + state.size = window.inner_size(); + + state.surface = self.instance.create_surface(window.clone()).unwrap(); + let cap = state.surface.get_capabilities(&self.adapter); + state.surface_format = cap.formats[0]; + + state.configure_surface(); + } else { + let state = State::new( + window.clone(), + self.device.clone(), + self.queue.clone(), + &self.instance, + &self.adapter, + self.texture_layout.clone(), + self.vertex_buffer.clone(), + self.index_buffer.clone(), + self.dynamic_storage.take().unwrap_or(DynamicBuffer::new( + &self.device, + self.storage_layout.clone(), + 1024, + wgpu::BufferUsages::STORAGE, + )), + self.camera_dynamic_uniform + .take() + .unwrap_or(DynamicBuffer::new( + &self.device, + self.camera_layout.clone(), + 1024, + wgpu::BufferUsages::STORAGE, + )), + ); + + setup_egui(&mut self.game, &state.egui_renderer.context().clone()); + + self.state = Some(state); + } + + window.request_redraw(); + } + + fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { + let state = self.state.as_mut().unwrap(); + // TODO: investigate possible ways to avoid allocating vectors every frame for event lists. + // TODO: Maybe add some multithreading for the diferent fors in the function? + let mut keyboard_inputs = bones::KeyboardInputs::default(); + let mut wheel_events = Vec::new(); + let mut button_events = Vec::new(); + + // Egui input handling + state + .egui_renderer + .handle_input(&state.get_window(), &event); + + match event { + WindowEvent::CloseRequested => { + //Close window + event_loop.exit(); + } + WindowEvent::RedrawRequested => { + //println!("{}", self.now.elapsed().as_secs_f32()); + //self.now = Instant::now(); + + if self.game.shared_resource::().unwrap().0 { + event_loop.exit(); + } + + state.render(&mut self.game, &mut self.atlas_pool); + // Emits a new redraw requested event. + state.get_window().request_redraw(); + } + WindowEvent::Resized(size) => { + // Reconfigures the size of the surface. We do not re-render + // here as this event is always followed up by redraw request. + state.resize(size); + } + WindowEvent::KeyboardInput { event, .. } => { + let ev = match event.physical_key { + winit::keyboard::PhysicalKey::Code(code) => bones::KeyboardEvent { + scan_code: bones::Unset, + key_code: bones::Set(code.into_bones()), + button_state: event.state.into_bones(), + }, + winit::keyboard::PhysicalKey::Unidentified(native_key_code) => { + let scan_code = match native_key_code { + winit::keyboard::NativeKeyCode::Android(u) => bones::Set(u), + winit::keyboard::NativeKeyCode::MacOS(u) => bones::Set(u as u32), + winit::keyboard::NativeKeyCode::Windows(u) => bones::Set(u as u32), + winit::keyboard::NativeKeyCode::Xkb(u) => bones::Set(u), + winit::keyboard::NativeKeyCode::Unidentified => bones::Unset, + }; + bones::KeyboardEvent { + scan_code, + key_code: bones::Unset, + button_state: event.state.into_bones(), + } + } + }; + keyboard_inputs.key_events.push(ev); + } + WindowEvent::MouseWheel { delta, .. } => { + let ev: bones::MouseScrollEvent = delta.into_bones(); + wheel_events.push(ev); + } + WindowEvent::MouseInput { state, button, .. } => { + let ev = bones::MouseButtonEvent { + button: button.into_bones(), + state: state.into_bones(), + }; + button_events.push(ev); + } + WindowEvent::CursorMoved { position, .. } => { + let screen_pos = Some(Vec2::new(position.x as f32, position.y as f32)); + self.game + .insert_shared_resource(bones::MouseScreenPosition(screen_pos)); + } + WindowEvent::CursorLeft { .. } => { + self.game + .insert_shared_resource(bones::MouseScreenPosition(None)); + } + _ => (), + } + + // Add the game inputs + //TODO: Add world position + //self.game.insert_shared_resource(MouseWorldPosition(world_pos)); + self.game + .shared_resource_mut::() + .unwrap() + .wheel_events = wheel_events; + self.game + .shared_resource_mut::() + .unwrap() + .button_events = button_events; + self.game.insert_shared_resource(keyboard_inputs); + self.game.insert_shared_resource(process_gamepad_events()); + } + + fn device_event( + &mut self, + _event_loop: &ActiveEventLoop, + _device_id: winit::event::DeviceId, + event: winit::event::DeviceEvent, + ) { + let mut movement = Vec2::default(); + + if let winit::event::DeviceEvent::MouseMotion { delta } = event { + let delta = Vec2::new(delta.0 as f32, delta.1 as f32); + movement += delta; + }; + + self.game + .shared_resource_mut::() + .unwrap() + .movement = movement; + } +} + +struct State { + window: Arc, + device: Arc, + queue: Arc, + size: winit::dpi::PhysicalSize, + surface: wgpu::Surface<'static>, + surface_format: wgpu::TextureFormat, + opaque_render_pipeline: wgpu::RenderPipeline, + transparent_render_pipeline: wgpu::RenderPipeline, + vertex_buffer: Arc, + index_buffer: Arc, + dynamic_storage: DynamicBuffer, + camera_dynamic_uniform: DynamicBuffer, + egui_renderer: EguiRenderer, + egui_scale_factor: f32, +} + +impl State { + fn new( + window: Arc, + device: Arc, + queue: Arc, + instance: &wgpu::Instance, + adapter: &wgpu::Adapter, + texture_layout: Arc, + vertex_buffer: Arc, + index_buffer: Arc, + dynamic_storage: DynamicBuffer, + camera_dynamic_uniform: DynamicBuffer, + ) -> Self { + let size = window.inner_size(); + let surface = instance.create_surface(window.clone()).unwrap(); + let cap = surface.get_capabilities(adapter); + let surface_format = cap.formats[0]; + + // Configure surface for the first time + let surface_config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: surface_format, + // Request compatibility with the sRGB-format texture view we‘re going to create later. + view_formats: vec![surface_format.add_srgb_suffix()], + alpha_mode: wgpu::CompositeAlphaMode::Auto, + width: size.width, + height: size.height, + desired_maximum_frame_latency: 2, + present_mode: wgpu::PresentMode::AutoVsync, + }; + surface.configure(&device, &surface_config); + + let surface_caps = surface.get_capabilities(adapter); + // This accounts only for Srgb surfaces + let surface_format = surface_caps + .formats + .iter() + .copied() + .find(|f| f.is_srgb()) + .unwrap_or(surface_caps.formats[0]); + let config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: surface_format, + width: size.width, + height: size.height, + present_mode: surface_caps.present_modes[0], + alpha_mode: surface_caps.alpha_modes[0], + view_formats: vec![], + desired_maximum_frame_latency: 2, + }; + + let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some("Shader"), + source: wgpu::ShaderSource::Wgsl(include_str!("atlas_sprite.wgsl").into()), + }); + + let render_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("Render Pipeline Layout"), + bind_group_layouts: &[ + &texture_layout, + &dynamic_storage.layout, + &camera_dynamic_uniform.layout, + ], + push_constant_ranges: &[], + }); + + let opaque_render_pipeline = + device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("Render Pipeline"), + layout: Some(&render_pipeline_layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: Some("vs_main"), + buffers: &[Vertex::desc()], + compilation_options: Default::default(), + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: Some("fs_main"), + targets: &[Some(wgpu::ColorTargetState { + format: config.format, + blend: None, //For opaque + write_mask: wgpu::ColorWrites::ALL, + })], + compilation_options: Default::default(), + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: Some(wgpu::Face::Back), + // Setting this to anything other than Fill requires Features::POLYGON_MODE_LINE + // or Features::POLYGON_MODE_POINT + polygon_mode: wgpu::PolygonMode::Fill, + // Requires Features::DEPTH_CLIP_CONTROL + unclipped_depth: false, + // Requires Features::CONSERVATIVE_RASTERIZATION + conservative: false, + }, + depth_stencil: None, + + /*Some(wgpu::DepthStencilState { + format: wgpu::TextureFormat::Rgba8UnormSrgb, + depth_write_enabled: true, //For opaque + depth_compare: wgpu::CompareFunction::LessEqual, + stencil: Default::default(), + bias: Default::default(), + }),*/ + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + // If the pipeline will be used with a multiview render pass, this + // indicates how many array layers the attachments will have. + multiview: None, + // Useful for optimizing shader compilation on Android + cache: None, + }); + + let transparent_render_pipeline = + device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("Render Pipeline"), + layout: Some(&render_pipeline_layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: Some("vs_main"), + buffers: &[Vertex::desc()], + compilation_options: Default::default(), + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: Some("fs_main"), + targets: &[Some(wgpu::ColorTargetState { + format: config.format, + blend: Some(wgpu::BlendState::ALPHA_BLENDING), //For transparent + write_mask: wgpu::ColorWrites::ALL, + })], + compilation_options: Default::default(), + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: Some(wgpu::Face::Back), + // Setting this to anything other than Fill requires Features::POLYGON_MODE_LINE + // or Features::POLYGON_MODE_POINT + polygon_mode: wgpu::PolygonMode::Fill, + // Requires Features::DEPTH_CLIP_CONTROL + unclipped_depth: false, + // Requires Features::CONSERVATIVE_RASTERIZATION + conservative: false, + }, + depth_stencil: None, + + /*Some(wgpu::DepthStencilState { + format: wgpu::TextureFormat::Rgba8UnormSrgb, + depth_write_enabled: false, //For transparent + depth_compare: wgpu::CompareFunction::LessEqual, + stencil: Default::default(), + bias: Default::default(), + }),*/ + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + // If the pipeline will be used with a multiview render pass, this + // indicates how many array layers the attachments will have. + multiview: None, + // Useful for optimizing shader compilation on Android + cache: None, + }); + + let egui_renderer = EguiRenderer::new(&device, surface_config.format, None, 1, &window); + + State { + window, + device: device.clone(), + queue, + size, + surface, + surface_format, + opaque_render_pipeline, + transparent_render_pipeline, + egui_renderer, + dynamic_storage, + camera_dynamic_uniform, + egui_scale_factor: 1.0, + vertex_buffer, + index_buffer, + } + } + + fn get_window(&self) -> Arc { + self.window.clone() + } + + fn configure_surface(&self) { + let surface_config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: self.surface_format, + // Request compatibility with the sRGB-format texture view we‘re going to create later. + view_formats: vec![self.surface_format.add_srgb_suffix()], + alpha_mode: wgpu::CompositeAlphaMode::Auto, + width: self.size.width, + height: self.size.height, + desired_maximum_frame_latency: 2, + present_mode: wgpu::PresentMode::AutoVsync, + }; + self.surface.configure(&self.device, &surface_config); + } + + fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { + self.size = new_size; + + // reconfigure the surface + self.configure_surface(); + } + + fn render(&mut self, game: &mut bones::Game, atlas_pool: &mut atlas_pool::AtlasPool) { + // Create the command encoder. + let mut encoder = self.device.create_command_encoder(&Default::default()); + + //Run needed egui related function, needs to run before step + self.egui_renderer.begin_frame(&self.window); + + //Step bones + game.step(Instant::now()); + + update_atlas_pool(game, atlas_pool); + sort_sprites(game); + update_uniforms(game, &mut self.dynamic_storage); + update_cameras_uniform( + game, + &mut self.camera_dynamic_uniform, + IVec2::new(self.size.width as i32, self.size.height as i32), + ); + + let cameras_sorted = game.shared_resource::().unwrap(); + + // Create texture view + let surface_texture = self + .surface + .get_current_texture() + .expect("failed to acquire next swapchain texture"); + let texture_view = surface_texture + .texture + .create_view(&wgpu::TextureViewDescriptor { + // Without add_srgb_suffix() the image we will be working with + // might not be "gamma correct". + format: Some(self.surface_format.add_srgb_suffix()), + ..Default::default() + }); + + let mut camera_index = 0; + for (session_name, camera_vec) in cameras_sorted.0.iter() { + let session = game.sessions.get(*session_name).unwrap(); + + let sprite_lists = session.world.resource::(); + let atlas_handles = session.world.component::(); + let cameras = session.world.component::(); + + for (camera_ent, camera_size) in camera_vec { + // Create render passes for each camera + let camera = cameras.get(*camera_ent).unwrap(); + + // Set the camera for the sprites + let n = self.dynamic_storage.capacity / size_of::() as u64; + for i in 0..n { + self.queue.write_buffer( + &self.dynamic_storage.buffer, + 4 + i * size_of::() as u64, + bytemuck::cast_slice(&[(camera_index as u32)]), + ); + } + + let clear_color = session.world.get_resource::(); + + let load = if camera.draw_background_color { + let color: bones_framework::render::prelude::Color = + match (camera.background_color.option(), clear_color) { + (Some(color), _) => color, + (None, Some(color)) => color.0, + (None, None) => bones::Color::BLACK, + }; + let color = color.as_rgba_f64(); + + let color = wgpu::Color { + r: color[0], + g: color[1], + b: color[2], + a: color[3], + }; + + wgpu::LoadOp::Clear(color) + } else { + wgpu::LoadOp::Load + }; + + let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &texture_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + + if let Some(viewport) = camera.viewport.option() { + pass.set_viewport( + viewport.position.x as f32, + viewport.position.y as f32, + camera_size.x, + camera_size.y, + viewport.depth_min, + viewport.depth_max, + ); + } + + // set the quad vertex buffer (slot 0) + pass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); + // Before your draw loops, once: + pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16); + pass.set_bind_group(1, &*self.dynamic_storage.get_bind_group(), &[]); + pass.set_bind_group(2, &*self.camera_dynamic_uniform.get_bind_group(), &[]); + + // === OPAQUE PASS === + pass.set_pipeline(&self.opaque_render_pipeline); + + // Debug bind: use atlas 0 and instance 0 for a single test quad + + //pass.set_bind_group(0, &atlas_pool.atlases[0].bind_group, &[]); + //pass.set_bind_group(1, self.dynamic_storage.get_bind_group(), &[]); + //pass.draw_indexed(0..6, 0, 0..1); // should draw the first sprite once + + let opaque_list = &sprite_lists.opaque_list; + let transparent_list = &sprite_lists.transparent_list; + let index_of = &sprite_lists.index_of; + + // iterate through opaque_list and batch by atlas_id + let mut i = 0; + while i < opaque_list.len() { + let atlas_pool_handle = + atlas_handles.get(opaque_list[i]).unwrap_or_else(|| { + atlas_handles + .get(sprite_lists.tile_layer.get(&opaque_list[i]).unwrap().0) + .unwrap() + }); + let current_atlas = atlas_pool_handle.atlas_id; + + // find how many consecutive entries share this atlas + let start = i; + while i < opaque_list.len() + && atlas_handles + .get(opaque_list[i]) + .unwrap_or_else(|| { + atlas_handles + .get(sprite_lists.tile_layer.get(&opaque_list[i]).unwrap().0) + .unwrap() + }) + .atlas_id + == current_atlas + { + i += 1; + } + let count = (i - start) as u32; + let first_instance = index_of[&opaque_list[start]]; + + // bind this atlas’s bind group (group 0) + let atlas_bg = &atlas_pool.atlases[current_atlas].bind_group; + pass.set_bind_group(0, atlas_bg, &[]); + + // draw a quad instanced `count` times, indexing into your storage arrays + pass.draw_indexed(0..6, 0, first_instance..first_instance + count); + } + + // === TRANSPARENT PASS === + pass.set_pipeline(&self.transparent_render_pipeline); + + let mut j = 0; + while j < transparent_list.len() { + let atlas_pool_handle = atlas_handles.get(transparent_list[i]).unwrap_or( + atlas_handles + .get(sprite_lists.tile_layer.get(&transparent_list[i]).unwrap().0) + .unwrap(), + ); + let current_atlas = atlas_pool_handle.atlas_id; + + let start = j; + while j < transparent_list.len() + && atlas_handles + .get(transparent_list[i]) + .unwrap_or( + atlas_handles + .get( + sprite_lists + .tile_layer + .get(&transparent_list[i]) + .unwrap() + .0, + ) + .unwrap(), + ) + .atlas_id + == current_atlas + { + j += 1; + } + let count = (j - start) as u32; + let first_instance = index_of[&transparent_list[start]]; + + let atlas_bg = &atlas_pool.atlases[current_atlas].bind_group; + pass.set_bind_group(0, atlas_bg, &[]); + + pass.draw_indexed(0..6, 0, first_instance..first_instance + count); + } + camera_index += 1; + } + } + + // Draw the egui UI + { + let screen_descriptor = ScreenDescriptor { + size_in_pixels: [self.size.width, self.size.height], + pixels_per_point: self.window.as_ref().scale_factor() as f32 + * self.egui_scale_factor, + }; + + self.egui_renderer.end_frame_and_draw( + &self.device, + &self.queue, + &mut encoder, + &self.window, + &texture_view, + screen_descriptor, + ); + } + + // Submit the command queue. + self.queue.submit([encoder.finish()]); + self.window.pre_present_notify(); + surface_texture.present(); + + /*Write atlas pool textures to png files for debugging + if !time_since_start().as_secs() < 10 { + for atlas in atlas_pool.atlases.iter() { + let path = String::from("atlas_") + &atlas.id.to_string() + ".png"; + + let result = crate::texture_file::dump_texture_to_png( + &self.device, + &self.queue, + &atlas.texture, + (atlas.texture.width(), atlas.texture.height()), + std::path::Path::new(&path), + ); + result.unwrap(); + } + std::process::exit(1); + }*/ + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] +struct Vertex { + position: [f32; 3], + tex_coords: [f32; 2], +} + +impl Vertex { + fn desc() -> wgpu::VertexBufferLayout<'static> { + use std::mem; + wgpu::VertexBufferLayout { + array_stride: mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &[ + wgpu::VertexAttribute { + offset: 0, + shader_location: 0, + format: wgpu::VertexFormat::Float32x3, + }, + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress, + shader_location: 1, + format: wgpu::VertexFormat::Float32x2, + }, + ], + } + } +} + +const VERTICES: &[Vertex] = &[ + // Top-left vertex + Vertex { + position: [-0.5, 0.5, 0.0], + tex_coords: [0.0, 0.0], + }, + // Bottom-left vertex + Vertex { + position: [-0.5, -0.5, 0.0], + tex_coords: [0.0, 1.0], + }, + // Bottom-right vertex + Vertex { + position: [0.5, -0.5, 0.0], + tex_coords: [1.0, 1.0], + }, + // Top-right vertex + Vertex { + position: [0.5, 0.5, 0.0], + tex_coords: [1.0, 0.0], + }, +]; + +const VERTICES_FULL: &[Vertex] = &[ + // Top-left vertex + Vertex { + position: [-1.0, 1.0, 0.0], + tex_coords: [0.0, 0.0], + }, + // Bottom-left vertex + Vertex { + position: [-1.0, -1.0, 0.0], + tex_coords: [0.0, 1.0], + }, + // Bottom-right vertex + Vertex { + position: [1.0, -1.0, 0.0], + tex_coords: [1.0, 1.0], + }, + // Top-right vertex + Vertex { + position: [1.0, 1.0, 0.0], + tex_coords: [1.0, 0.0], + }, +]; + +const INDICES: &[u16] = &[ + 0, 1, 2, // first triangle + 0, 2, 3, // second triangle +]; + +/// A [`bones::AssetIo`] configured for web and local file access +pub fn asset_io(asset_dir: &Path, packs_dir: &Path) -> impl bones::AssetIo + 'static { + #[cfg(not(target_arch = "wasm32"))] + { + bones::FileAssetIo::new(asset_dir, packs_dir) + } + #[cfg(target_arch = "wasm32")] + { + let _ = asset_dir; + let _ = packs_dir; + let window = web_sys::window().unwrap(); + let path = window.location().pathname().unwrap(); + let base = path.rsplit_once('/').map(|x| x.0).unwrap_or(&path); + bones::WebAssetIo::new(&format!("{base}/assets")) + } +} diff --git a/framework_crates/bones_wgpu_renderer/src/line.rs b/framework_crates/bones_wgpu_renderer/src/line.rs new file mode 100644 index 0000000000..cf3d8db723 --- /dev/null +++ b/framework_crates/bones_wgpu_renderer/src/line.rs @@ -0,0 +1,100 @@ +use bones_framework::glam::Vec2; +use lyon::math::Point; +use lyon::path::Path; +use lyon::tessellation::{ + BuffersBuilder, StrokeOptions, StrokeTessellator, StrokeVertex, VertexBuffers, +}; + +use crate::bones::Path2d; + +#[repr(C)] +#[derive(Clone, Copy, Debug, bytemuck::Pod, bytemuck::Zeroable)] +struct Vertex { + position: [f32; 2], + color: [f32; 4], +} + +impl Vertex { + fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { + use std::mem; + wgpu::VertexBufferLayout { + array_stride: mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &[ + wgpu::VertexAttribute { + offset: 0, + shader_location: 0, + format: wgpu::VertexFormat::Float32x2, + }, + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 2]>() as wgpu::BufferAddress, + shader_location: 1, + format: wgpu::VertexFormat::Float32x4, + }, + ], + } + } +} + +// Helper function to process line breaks +fn process_segments(path: &Path2d) -> Vec<&[Vec2]> { + let mut segments = Vec::new(); + let mut line_breaks = path.line_breaks.clone(); + line_breaks.sort_unstable(); + line_breaks.dedup(); + + let mut start = 0; + for &break_point in &line_breaks { + let end = break_point; + if start <= end && end < path.points.len() { + let segment = &path.points[start..=end]; + if segment.len() >= 2 { + segments.push(segment); + } + } + start = end + 1; + } + + if start < path.points.len() { + let segment = &path.points[start..]; + if segment.len() >= 2 { + segments.push(segment); + } + } + + segments +} + +// Tessellate path into vertex/index buffers +fn tessellate_path(path: &Path2d) -> VertexBuffers { + let segments = process_segments(path); + let mut lyon_path_builder = Path::builder(); + + for segment in segments { + let mut points = segment.iter(); + if let Some(first) = points.next() { + lyon_path_builder.begin(Point::new(first.x, first.y)); + for point in points { + lyon_path_builder.line_to(Point::new(point.x, point.y)); + } + lyon_path_builder.end(false); + } + } + + let lyon_path = lyon_path_builder.build(); + let options = StrokeOptions::default().with_line_width(path.thickness); + let mut geometry = VertexBuffers::new(); + + StrokeTessellator::new() + .tessellate_path( + &lyon_path, + &options, + &mut BuffersBuilder::new(&mut geometry, |vertex: StrokeVertex| Vertex { + position: vertex.position().to_array(), + color: path.color.as_rgba_f32(), + }), + ) + .expect("Path tessellation failed"); + + geometry +} diff --git a/framework_crates/bones_wgpu_renderer/src/sprite.rs b/framework_crates/bones_wgpu_renderer/src/sprite.rs new file mode 100644 index 0000000000..3802358248 --- /dev/null +++ b/framework_crates/bones_wgpu_renderer/src/sprite.rs @@ -0,0 +1,1072 @@ +use crate::{atlas_pool::AtlasPool, *}; +use bones_framework::{ + prelude::{self as bones, BitSet, ComponentIterBitset, Ustr}, +}; +use guillotiere::Allocation; +use std::collections::HashMap; + +// Functions used to load sprites, atlas sprites and tile sprites, and update them. + +#[repr(C, align(16))] +#[derive(Debug, Clone, Copy, Default, bytemuck::Pod, bytemuck::Zeroable)] +pub struct CameraTransform { + transform: [[f32; 4]; 4], + screen_size: [f32; 2], + _pad0: u32, + _pad1: u32, +} + +#[repr(C, align(16))] +#[derive(Debug, Clone, Copy, Default, bytemuck::Pod, bytemuck::Zeroable)] +pub struct AtlasSpriteUniform { + // Base parameters + pub entity_type: u32, + pub camera_index: u32, + pub _pad0: u32, + pub _pad1: u32, + pub transform: [[f32; 4]; 4], + pub color_tint: [f32; 4], + + // Sprite and Atlas parameters + pub flip_x: u32, + pub flip_y: u32, + pub uv_min: [f32; 2], + pub uv_max: [f32; 2], + + // Atlas parameters + pub tile_size: [f32; 2], + pub image_size: [f32; 2], + pub padding: [f32; 2], + pub offset: [f32; 2], + + pub columns: u32, + pub index: u32, +} + +impl AtlasSpriteUniform { + pub fn from_atlas_sprite( + atlas_sprite: &bones::AtlasSprite, + atlas: &bones::Atlas, + transform: &bones::Transform, + uvs: ([f32; 2], [f32; 2]), + ) -> Self { + let image_size = [ + atlas.offset.x + ((atlas.tile_size.x + atlas.padding.x) * atlas.columns as f32), + atlas.offset.y + ((atlas.tile_size.y + atlas.padding.y) * atlas.rows as f32), + ]; + + if atlas_sprite.flip_x { + println!("Flipping X for sprite: {:?}", atlas_sprite.index); + } else { + println!("Not flipping X for sprite: {:?}", atlas_sprite.index); + } + + Self { + tile_size: atlas.tile_size.into(), + columns: atlas.columns, + padding: atlas.padding.into(), + offset: atlas.offset.into(), + index: atlas_sprite.index, + image_size, + entity_type: 1, + flip_x: atlas_sprite.flip_x as u32, + flip_y: atlas_sprite.flip_y as u32, + color_tint: atlas_sprite.color.as_rgba_f32(), + transform: transform.to_matrix_none().to_cols_array_2d(), + uv_min: uvs.0, + uv_max: uvs.1, + ..Default::default() + } + } + + //DONE I need to spawn sprite in a place based on its position on the tile layer array + pub fn from_tile( + tile: &bones::Tile, + atlas: &bones::Atlas, + transform: &bones::Transform, + uvs: ([f32; 2], [f32; 2]), + index: usize, + tile_layer: &bones::TileLayer, + ) -> Self { + let image_size = [ + atlas.offset.x + ((atlas.tile_size.x + atlas.padding.x) * atlas.columns as f32), + atlas.offset.y + ((atlas.tile_size.y + atlas.padding.y) * atlas.rows as f32), + ]; + let mut transform = transform.clone(); + transform.translation.x += + tile_layer.tile_size.x * (index as u32 % tile_layer.grid_size.x) as f32; + transform.translation.y += + tile_layer.tile_size.y * (index as u32 / tile_layer.grid_size.x) as f32; + + Self { + tile_size: atlas.tile_size.into(), + columns: atlas.columns, + padding: atlas.padding.into(), + offset: atlas.offset.into(), + index: tile.idx, + image_size, + entity_type: 1, + flip_x: tile.flip_x as u32, + flip_y: tile.flip_y as u32, + color_tint: tile.color.as_rgba_f32(), + transform: transform.to_matrix_none().to_cols_array_2d(), + uv_min: uvs.0, + uv_max: uvs.1, + ..Default::default() + } + } + + pub fn from_sprite( + sprite: &bones::Sprite, + transform: &bones::Transform, + uvs: ([f32; 2], [f32; 2]), + image_size: Vec2, + ) -> Self { + if sprite.flip_x { + println!("Flipping X for sprite: {:?}", sprite); + } else { + println!("Not flipping X for sprite: {:?}", sprite); + } + + Self { + color_tint: sprite.color.as_rgba_f32(), + flip_x: sprite.flip_x as u32, + flip_y: sprite.flip_y as u32, + entity_type: 0, + transform: transform.to_matrix_none().to_cols_array_2d(), + uv_min: uvs.0, + uv_max: uvs.1, + tile_size: image_size.into(), + ..Default::default() + } + } +} + +#[derive(bones_schema::HasSchema, Clone)] +#[schema(no_default)] +/// Points to the atlas and rectangle this sprite lives in. +pub struct AtlasPoolHandle { + pub atlas_id: usize, + pub alloc: Allocation, + pub uv_min: [f32; 2], // Atlas UV coordinates (min_x, min_y) + pub uv_max: [f32; 2], // Atlas UV coordinates (max_x, max_y) + pub image_size: [f32; 2], // Original image size (width, height) + + sender: crossbeam_channel::Sender<(bones::Entity, usize, Allocation)>, + entity: bones::Entity, +} + +impl Drop for AtlasPoolHandle { + fn drop(&mut self) { + // Send the entity to the atlas pool for deallocation + if let Err(e) = self.sender.send((self.entity, self.atlas_id, self.alloc)) { + eprintln!("Failed to send entity for deallocation: {:?}", e); + } + } +} + +//TODO Add tiles +pub fn update_atlas_pool(game: &mut bones::Game, atlas_pool: &mut AtlasPool) { + let assets = game.shared_resource_cell::().unwrap(); + let queue = game.shared_resource_cell::().unwrap(); + + for (_, session) in game.sessions.iter_mut() { + if !session.active { + continue; + } + + let entities = session.world.resource::(); + let sprites = session.world.component::(); + let atlases = session.world.component::(); + let tile_layers = session.world.component::(); + let mut atlas_pool_handles = session.world.component_mut::(); + + let mut bitset = sprites.bitset().clone(); + bitset.bit_or(atlases.bitset()); + bitset.bit_or(tile_layers.bitset()); + + let mut not_atlas_handle_bitset = atlas_pool_handles.bitset().clone(); + not_atlas_handle_bitset.bit_not(); + + let mut without_handle = bitset.clone(); + without_handle.bit_and(¬_atlas_handle_bitset); + + for ent in entities.iter_with_bitset(&without_handle) { + println!("Adding sprite to atlas pool: {:?}", ent); + + let image; + if let Some(sprite) = sprites.get(ent) { + image = sprite.image; + } else if let Some(atlas_sprite) = atlases.get(ent) { + let assets = assets.borrow().unwrap(); + let atlas = assets.get(atlas_sprite.atlas); + image = atlas.image.clone(); + } else { + let tile_layer = tile_layers.get(ent).unwrap(); + let assets = assets.borrow().unwrap(); + let atlas = assets.get(tile_layer.atlas); + image = atlas.image.clone(); + } + let assets = assets.borrow().unwrap(); + let image = assets.get(image); + + if let bones::Image::Data(img) = &*image { + //Allocate in the atlas pool guiliotiere + let (atlas_id, alloc) = atlas_pool + .allocate((img.width() as i32, img.height() as i32)) + .unwrap_or_else(|_| { + panic!("Failed to allocate space for sprite image: {:?}", image); + }); + + // 5) Compute and store UVs for your sprite + let rect: guillotiere::euclid::Box2D = + alloc.rectangle; + let (atlas_w, atlas_h) = ( + atlas_pool.atlas_size.0 as f32, + atlas_pool.atlas_size.1 as f32, + ); + let uv_min = [rect.min.x as f32 / atlas_w, rect.min.y as f32 / atlas_h]; + let uv_max = [rect.max.x as f32 / atlas_w, rect.max.y as f32 / atlas_h]; + + println!("{} {}", uv_min[0], uv_min[1]); + println!("{} {}", uv_max[0], uv_max[1]); + + atlas_pool_handles.insert( + ent, + AtlasPoolHandle { + atlas_id, + alloc, + uv_min, + uv_max, + image_size: [img.width() as f32, img.height() as f32], + entity: ent, + sender: atlas_pool.sender.clone(), + }, + ); + + // 1) Convert to RGBA8 and grab the raw bytes + let rgba = img.to_rgba8(); // image::RgbaImage (Vec under the hood) + let (w, h) = (rgba.width(), rgba.height()); + let raw = rgba.into_raw(); // Vec, length = w*h*4 + + // 2) Compute the origin in the atlas texture + let origin = wgpu::Origin3d { + x: rect.min.x as u32, + y: rect.min.y as u32, + z: 0, + }; + + let unpadded_stride = (4 * w) as usize; + let padded_stride = ((unpadded_stride + 255) / 256) * 256; + let mut padded_data = vec![0u8; padded_stride * h as usize]; + + // copy each scanline into the padded buffer + for row in 0..(h as usize) { + let src_offset = row * unpadded_stride; + let dst_offset = row * padded_stride; + padded_data[dst_offset..dst_offset + unpadded_stride] + .copy_from_slice(&raw[src_offset..src_offset + unpadded_stride]); + } + + println!("Texture {:?}", atlas_pool.atlases[atlas_id].texture); + + let data_layout = wgpu::TexelCopyBufferLayout { + offset: 0, + bytes_per_row: Some(padded_stride as u32), + rows_per_image: Some(h), + }; + let queue = queue.borrow().unwrap(); + queue.get().write_texture( + wgpu::TexelCopyTextureInfo { + texture: &atlas_pool.atlases[atlas_id].texture, + mip_level: 0, + origin, + aspect: wgpu::TextureAspect::All, + }, + &padded_data, + data_layout, + wgpu::Extent3d { + width: w, + height: h, + depth_or_array_layers: 1, + }, + ); + queue.get().submit([]); + } + } + + // Deallocate sprites that were removed + let removed: Vec<_> = atlas_pool.receiver.try_iter().collect(); + for (ent, atlas_id, alloc) in removed { + println!("Removing sprite from atlas pool: {:?}", ent); + atlas_pool.deallocate(atlas_id, alloc); + atlas_pool_handles.remove(ent); + } + } +} + +pub fn update_uniforms(game: &mut bones::Game, dynamic_storage: &mut DynamicBuffer) { + // Prepare instance data + //TODO put lenght + let mut instances = Vec::new(); + + let queue = game.shared_resource_cell::().unwrap(); + let device = game.shared_resource_cell::().unwrap(); + let assets = game.shared_resource_cell::().unwrap(); + + for (_, session) in game.sessions.iter_mut() { + if !session.visible { + continue; + } + + let entities = session.world.resource::(); + let sprite_lists = session.world.resource::(); + + let transforms = session.world.component::(); + let sprites = session.world.component::(); + let atlases = session.world.component::(); + let tile_layers = session.world.component::(); + let tiles = session.world.component::(); + let paths = session.world.component::(); + let atlas_handles = session.world.component::(); + + for entity in sprite_lists + .opaque_list + .iter() + .chain(&sprite_lists.transparent_list) + { + let transform = transforms.get(*entity).unwrap_or_else(|| { + transforms + .get(sprite_lists.tile_layer.get(entity).unwrap().0) + .unwrap() + }); + + if let Some(sprite) = sprites.get(*entity) { + let Some(atlas_handle) = atlas_handles.get(*entity) else { + panic!("Texture not loaded in atlas pool!") + }; + let (uv_min, uv_max) = (atlas_handle.uv_min, atlas_handle.uv_max); + + // Get dynamic image size from the atlas handle (stored when the image was loaded) + let image_size = Vec2::new(atlas_handle.image_size[0], atlas_handle.image_size[1]); + + let atlas_sprite = + AtlasSpriteUniform::from_sprite(sprite, &transform, (uv_min, uv_max), image_size); + + println!("Adding atlas sprite: {:?}", atlas_sprite); + + instances.push(atlas_sprite); + } else if let Some(atlas_sprite) = atlases.get(*entity) { + let assets = assets.borrow().unwrap(); + let atlas = assets.get(atlas_sprite.atlas).clone(); + + let Some(atlas_handle) = atlas_handles.get(*entity) else { + panic!("Texture not loaded in atlas pool!") + }; + let (uv_min, uv_max) = (atlas_handle.uv_min, atlas_handle.uv_max); + + let atlas_sprite = AtlasSpriteUniform::from_atlas_sprite( + atlas_sprite, + &atlas, + &transform, + (uv_min, uv_max), + ); + + println!("Adding atlas sprite: {:?}", atlas_sprite); + + instances.push(atlas_sprite); + } else if let Some(tile) = tiles.get(*entity) { + let tile_layer_ent = sprite_lists.tile_layer.get(&entity).unwrap(); + let tile_layer = tile_layers.get(tile_layer_ent.0).unwrap(); + let assets = assets.borrow().unwrap(); + let atlas = assets.get(tile_layer.atlas).clone(); + + let Some(atlas_handle) = atlas_handles.get(tile_layer_ent.0) else { + panic!("Texture not loaded in atlas pool!") + }; + let (uv_min, uv_max) = (atlas_handle.uv_min, atlas_handle.uv_max); + + let tile_sprite = AtlasSpriteUniform::from_tile( + tile, + &atlas, + &transform, + (uv_min, uv_max), + tile_layer_ent.1, + tile_layer, + ); + + instances.push(tile_sprite); + } else { + unreachable!() + } + } + + for (entity, path) in entities.iter_with(&paths) { + let Some(transform) = transforms.get(entity) else { + unreachable!() + }; + + instances.push(AtlasSpriteUniform { + entity_type: 2, + transform: transform.to_matrix_none().to_cols_array_2d(), + color_tint: path.color.as_rgba_f32(), + ..Default::default() + }); + } + } + + let device = device.borrow().unwrap(); + let queue = queue.borrow().unwrap(); + + println!("{}: {:?}", instances.len(), instances); + + // Update buffers (with dynamic resizing) + dynamic_storage.write_pods(&device.get(), queue.get(), &instances); +} + +#[derive(bones_schema::HasSchema, Default, Clone)] +/// Holds sorted sprite indices grouped by transparency for rendering order: +pub struct SpriteLists { + pub transparent_list: Vec, + pub opaque_list: Vec, + pub index_of: HashMap, + pub tile_layer: HashMap, +} + +pub fn sort_sprites(game: &mut bones::Game) { + for (_, session) in game.sessions.iter_mut() { + if !session.visible { + continue; + } + + { + let mut sprite_lists = session.world.init_resource::(); + + sprite_lists.transparent_list.clear(); + sprite_lists.opaque_list.clear(); + } + + // Now safe to borrow entities immutably + let entities = session.world.resource::(); + + let atlas_handles = session.world.component::(); + let transforms = session.world.component::(); + + let sprites = session.world.component::(); + let atlases = session.world.component::(); + let tile_layers = session.world.component::(); + let tiles = session.world.component::(); + + //Get entities with atlas handle, and that have sprite or atlas sprite + let mut sprites_atlases = sprites.bitset().clone(); + sprites_atlases.bit_or(atlases.bitset()); + sprites_atlases.bit_or(tile_layers.bitset()); + let mut bitset = atlas_handles.bitset().clone(); + bitset.bit_and(&sprites_atlases); + + // Pre‐frame (CPU) work: + let mut opaque_list: Vec = Vec::new(); + let mut transparent_list: Vec = Vec::new(); + + let mut tile_layer_hash = HashMap::with_capacity(tiles.bitset().len()); + + //TODO This is wrong! When adding sprite we should also check if we find a transparent pixel! + //And add a flag, but its fine for now i guess + for ent in entities.iter_with_bitset(&bitset) { + println!("Sorting sprite: {:?}", ent); + + if let Some(sprite) = sprites.get(ent) { + let color = sprite.color; + + if color.a() != 1.0 { + transparent_list.push(ent); + } else { + opaque_list.push(ent); + } + } else if let Some(atlas_sprite) = atlases.get(ent) { + let color = atlas_sprite.color; + + if color.a() != 1.0 { + transparent_list.push(ent); + } else { + opaque_list.push(ent); + } + } else if let Some(tile_layer) = tile_layers.get(ent) { + for (i, tile) in tile_layer.tiles.iter().enumerate() { + if let Some(tile_ent) = tile { + let tile = tiles.get(*tile_ent).unwrap(); + if tile.color.a() != 1.0 { + transparent_list.push(*tile_ent); + } else { + opaque_list.push(*tile_ent); + } + tile_layer_hash.insert(*tile_ent, (ent, i)); + } + } + } + } + + // sort opaque front‐to‐back by layer, then atlas + opaque_list.sort_by_key(|ent| { + let atlas_handle = atlas_handles.get(*ent).unwrap_or_else(|| { + atlas_handles + .get(tile_layer_hash.get(ent).unwrap().0) + .unwrap() + }); + + let layer = transforms + .get(*ent) + .unwrap_or_else(|| transforms.get(tile_layer_hash.get(ent).unwrap().0).unwrap()) + .translation + .z; + + (layer.to_bits(), atlas_handle.atlas_id) + }); + // sort transparent back‐to‐front, then atlas + transparent_list.sort_by_key(|ent| { + let atlas_handle = atlas_handles.get(*ent).unwrap_or_else(|| { + atlas_handles + .get(tile_layer_hash.get(ent).unwrap().0) + .unwrap() + }); + + let layer = transforms + .get(*ent) + .unwrap_or_else(|| transforms.get(tile_layer_hash.get(ent).unwrap().0).unwrap()) + .translation + .z; + + (!layer.to_bits(), atlas_handle.atlas_id) + }); + + /* + println!( + "Opaque sprites: {}, Transparent sprites: {}", + opaque_list.len(), + transparent_list.len() + ); + */ + + // Create index map for fast lookup + let mut index_of = HashMap::with_capacity(opaque_list.len() + transparent_list.len()); + for (i, &e) in opaque_list.iter().chain(&transparent_list).enumerate() { + index_of.insert(e, i as u32); + } + + let mut sprite_lists = session.world.resource_mut::(); + sprite_lists.index_of = index_of; + + sprite_lists.opaque_list = opaque_list; + sprite_lists.transparent_list = transparent_list; + sprite_lists.tile_layer = tile_layer_hash; + } +} + +pub fn update_cameras_uniform( + game: &mut bones::Game, + dynamic_uniform: &mut DynamicBuffer, + mut window_size: IVec2, +) { + let mut instances: Vec<(&Ustr, Vec<(i32, CameraTransform, bones::Entity, Vec2)>)> = Vec::new(); + + let queue = game.shared_resource_cell::().unwrap(); + let device = game.shared_resource_cell::().unwrap(); + + for (session_name, session) in game.sessions.iter() { + if !session.visible { + continue; + } + + let mut session_instances = Vec::new(); + + let entities = session.world.resource::(); + let cameras = session.world.component::(); + let transforms = session.world.component::(); + + let mut bitset = cameras.bitset().clone(); + bitset.bit_and(transforms.bitset()); + + for ent in entities.iter_with_bitset(&bitset) { + let Some(transform) = transforms.get(ent) else { + unreachable!() + }; + + let Some(camera) = cameras.get(ent) else { + unreachable!() + }; + + if !camera.active { + continue; + } + + let scale_ratio; + if let Some(viewport) = camera.viewport.option() { + //Get the viewport size, cropping it if needed + window_size -= viewport.position.as_ivec2(); + window_size = IVec2::new( + (viewport.size.x as i32).min(window_size.x), + (viewport.size.y as i32).min(window_size.y), + ); + + if window_size.x <= 0 || window_size.y <= 0 { + continue; + } + + if viewport.size.y <= viewport.size.x { + scale_ratio = Mat4::from_scale(Vec3::new( + window_size.x as f32 / viewport.size.x as f32, + viewport.size.y as f32 / viewport.size.x as f32 * window_size.y as f32 + / viewport.size.y as f32, + 1., + )) + .inverse(); + } else { + scale_ratio = Mat4::from_scale(Vec3::new( + viewport.size.x as f32 / viewport.size.y as f32 * window_size.x as f32 + / viewport.size.x as f32, + window_size.y as f32 / viewport.size.y as f32, + 1., + )) + .inverse(); + } + } else if window_size.x <= 0 || window_size.y <= 0 { + continue; + } else if window_size.y <= window_size.x { + scale_ratio = Mat4::from_scale(Vec3::new( + 1., + window_size.y as f32 / window_size.x as f32, + 1., + )) + .inverse(); + } else { + scale_ratio = Mat4::from_scale(Vec3::new( + window_size.x as f32 / window_size.y as f32, + 1., + 1., + )) + .inverse(); + } + + let pixel_to_clip_space = Mat4::from_scale(Vec3::new( + 2.0 / window_size.x as f32, + -2.0 / window_size.y as f32, + 1.0, + )) * Mat4::from_translation(Vec3::new(-1.0, 1.0, 0.0)); + + session_instances.push(( + camera.priority, + CameraTransform{ + transform: (/*Mat4::IDENTITYtransform.to_matrix((1.0 / window_size.as_vec2()).extend(1.0)) */ scale_ratio) + .to_cols_array_2d(), + screen_size: window_size.as_vec2().into(), ..Default::default() + }, + ent, + window_size.as_vec2() + )); + } + + session_instances.sort_by(|a, b| a.0.cmp(&b.0)); + instances.push((session_name, session_instances)); + } + + instances.sort_by(|a, b| a.0.cmp(&b.0)); + + let device = device.borrow().unwrap(); + let queue = queue.borrow().unwrap(); + let mut cameras = game.shared_resource_mut::().unwrap(); + + cameras.0 = Vec::new(); + let mut transforms = Vec::new(); + instances + .iter() + .for_each(|(session_name, session_instances)| { + let mut entities = Vec::new(); + for (_, transform, entity, window_size) in session_instances { + transforms.push(transform.clone()); + entities.push((*entity, *window_size)); + } + + cameras.0.push((**session_name, entities)); + }); + + dynamic_uniform.write_pods(&device.get(), queue.get(), &transforms); +} + +#[derive(bones_schema::HasSchema, Clone)] +#[schema(no_default)] +/// Camera entities sorted by `update_cameras_uniform` with their respective sizes. +pub struct Cameras(pub Vec<(Ustr, Vec<(bones::Entity, Vec2)>)>); + +/* OLD +pub fn load_sprite(game: &mut bones::Game) { + let assets = game.shared_resource_cell::().unwrap(); + let device = game.shared_resource_cell::().unwrap(); + let queue = game.shared_resource_cell::().unwrap(); + let texture_sender = game.shared_resource_cell::().unwrap(); + let pixel_art = game.shared_resource_cell::().unwrap(); + + for (session_name, session) in game.sessions.iter_mut() { + if !session.visible { + continue; + } + + let entities = session.world.resource::(); + let sprites = session.world.component::(); + let mut buffers = session.world.component_mut::(); + let mut texture_loaded = session.world.component_mut::(); + let transforms = session.world.component::(); + + let mut not_loaded = texture_loaded.bitset().clone(); + not_loaded.bit_not(); + not_loaded.bit_and(sprites.bitset()); + + for entity in entities.iter_with_bitset(¬_loaded) { + let Some(sprite) = sprites.get(entity) else { + unreachable!(); + }; + let Some(transform) = transforms.get(entity) else { + panic!("No transform found!"); + }; + + //Load and send texture + let assets = assets.borrow().unwrap(); + let image = assets.get(sprite.image); + if let bones::Image::Data(img) = &*image { + let texture = Arc::new( + Texture::from_image( + device.borrow().unwrap().get(), + queue.borrow().unwrap().get(), + img, + None, + pixel_art.borrow().unwrap().0, + ) + .unwrap(), + ); + + let base = BaseInstance { + color: sprite.color.as_rgba_f32(), + entity_type: 0, + transform: transform.to_matrix_none().to_cols_array_2d(), + }; + let sprite_flags = SpriteFlags { + flip: [sprite.flip_x as u32, sprite.flip_y as u32] + }; + + let atlas_sprite_buffer = + Arc::new(device.borrow().unwrap().get().create_buffer_init( + &wgpu::util::BufferInitDescriptor { + label: Some("Atlas Sprite Buffer"), + contents: bytemuck::cast_slice(&[base]), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }, + )); + + //Add buffer to bones so we can update it + buffers.insert(entity, AtlasSpriteBuffer(atlas_sprite_buffer.clone())); + + texture_sender + .borrow() + .unwrap() + .0 + .send((texture, entity, atlas_sprite_buffer, *session_name)) + .unwrap(); + texture_loaded.insert(entity, TextureLoaded); + } else { + unreachable!() + }; + } + } +} + +pub fn load_atlas_sprite(game: &mut bones::Game) { + let assets = game.shared_resource_cell::().unwrap(); + let device = game.shared_resource_cell::().unwrap(); + let queue = game.shared_resource_cell::().unwrap(); + let texture_sender = game.shared_resource_cell::().unwrap(); + let pixel_art = game.shared_resource_cell::().unwrap(); + + for (session_name, session) in game.sessions.iter_mut() { + if !session.visible { + continue; + } + + let entities = session.world.resource::(); + let atlas_sprites = session.world.component::(); + let mut buffers = session.world.component_mut::(); + let mut texture_loaded = session.world.component_mut::(); + + let mut not_loaded = texture_loaded.bitset().clone(); + not_loaded.bit_not(); + not_loaded.bit_and(atlas_sprites.bitset()); + + for entity in entities.iter_with_bitset(¬_loaded) { + let Some(atlas_sprite) = atlas_sprites.get(entity) else { + unreachable!(); + }; + + //Load and send texture + let assets = assets.borrow().unwrap(); + let atlas = assets.get(atlas_sprite.atlas); + let image = assets.get(atlas.image); + if let bones::Image::Data(img) = &*image { + let texture = Arc::new( + Texture::from_image( + device.borrow().unwrap().get(), + queue.borrow().unwrap().get(), + img, + None, + pixel_art.borrow().unwrap().0, + ) + .unwrap(), + ); + // create and send the atlas sprite uniform along with the texture and entity + let uniform = AtlasSpriteUniform::from_atlas_sprite( + atlas_sprite, + &assets.get(atlas_sprite.atlas), + ); + + let atlas_sprite_buffer = + Arc::new(device.borrow().unwrap().get().create_buffer_init( + &wgpu::util::BufferInitDescriptor { + label: Some("Atlas Sprite Buffer"), + contents: bytemuck::cast_slice(&[uniform]), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }, + )); + + //Add buffer to bones so we can update it + buffers.insert(entity, AtlasSpriteBuffer(atlas_sprite_buffer.clone())); + + texture_sender + .borrow() + .unwrap() + .0 + .send((texture, entity, atlas_sprite_buffer, *session_name)) + .unwrap(); + texture_loaded.insert(entity, TextureLoaded); + } else { + unreachable!() + }; + } + } +} + +pub fn load_tile_sprite(game: &mut bones::Game) { + let assets = game.shared_resource_cell::().unwrap(); + let device = game.shared_resource_cell::().unwrap(); + let queue = game.shared_resource_cell::().unwrap(); + let texture_sender = game.shared_resource_cell::().unwrap(); + let pixel_art = game.shared_resource_cell::().unwrap(); + + for (session_name, session) in game.sessions.iter_mut() { + if !session.visible { + continue; + } + + let entities = session.world.resource::(); + let tile_layers = session.world.component::(); + let tiles = session.world.component::(); + let mut buffers = session.world.component_mut::(); + let mut texture_loaded = session.world.component_mut::(); + + let mut not_loaded = texture_loaded.bitset().clone(); + not_loaded.bit_not(); + not_loaded.bit_and(tile_layers.bitset()); + + for layer_ent in entities.iter_with_bitset(¬_loaded) { + let Some(tile_layer) = tile_layers.get(layer_ent) else { + unreachable!(); + }; + + //Load and send texture + let assets = assets.borrow().unwrap(); + let atlas = assets.get(tile_layer.atlas); + let image = assets.get(atlas.image); + if let bones::Image::Data(img) = &*image { + let texture = Arc::new( + Texture::from_image( + device.borrow().unwrap().get(), + queue.borrow().unwrap().get(), + img, + None, + pixel_art.borrow().unwrap().0, + ) + .unwrap(), + ); + + for (tile_pos_idx, tile) in tile_layer.tiles.iter().enumerate() { + let Some(tile_ent) = tile else { + continue; + }; + let Some(tile) = tiles.get(*tile_ent) else { + panic!("Couldn't find tile entity!"); + }; + let mut transforms = session.world.component_mut::(); + + let transform = if let Some(t) = transforms.get_mut(*tile_ent) { + t + } else { + transforms.insert(*tile_ent, bones::Transform::default()); + transforms.get_mut(*tile_ent).unwrap() + }; + + let tile_pos = tile_layer.pos(tile_pos_idx as u32); + let tile_offset = tile_pos.as_vec2() * tile_layer.tile_size; + + /*let sprite_idx = tile.idx; + let y = sprite_idx / atlas.columns; + let x = sprite_idx - (y * atlas.columns); + let cell = Vec2::new(x as f32, y as f32); + let current_padding = atlas.padding + * Vec2::new(if x > 0 { 1.0 } else { 0.0 }, if y > 0 { 1.0 } else { 0.0 }); + let min = (atlas.tile_size + current_padding) * cell + atlas.offset; + let rect = Rect { + min, + max: min + atlas.tile_size, + };*/ + + transform.translation += tile_offset.extend(0.0); + // Scale up slightly to avoid bleeding between tiles. + // TODO: Improve tile rendering + // Currently we do a small hack here, scaling up the tiles a little bit, to prevent + // visible gaps between tiles. This solution isn't perfect and we probably need to + // create a proper tile renderer. That can render multiple tiles on one quad instead + // of using a separate quad for each tile. + transform.scale += Vec3::new(0.01, 0.01, 0.0); + + // create and send the atlas sprite uniform along with the texture and entity + let uniform = + AtlasSpriteUniform::from_tile(tile, &assets.get(tile_layer.atlas)); + + let atlas_sprite_buffer = + Arc::new(device.borrow().unwrap().get().create_buffer_init( + &wgpu::util::BufferInitDescriptor { + label: Some("Atlas Sprite Buffer"), + contents: bytemuck::cast_slice(&[uniform]), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }, + )); + + //Add buffer to bones so we can update it + buffers.insert(*tile_ent, AtlasSpriteBuffer(atlas_sprite_buffer.clone())); + + texture_sender + .borrow() + .unwrap() + .0 + .send(( + texture.clone(), + *tile_ent, + atlas_sprite_buffer, + *session_name, + )) + .unwrap(); + } + } else { + unreachable!() + }; + texture_loaded.insert(layer_ent, TextureLoaded); + } + } +} + +// System for updating atlas uniforms +pub fn update_atlas_uniforms(game: &mut bones::Game) { + let assets = game.shared_resource_cell::().unwrap(); + let queue = game.shared_resource_cell::().unwrap(); + + for (_, session) in game.sessions.iter_mut() { + if !session.visible { + continue; + } + + let entities = session.world.resource::(); + let atlases = session.world.component::(); + let mut buffers = session.world.component_mut::(); + + for (_, (atlas_sprite, atlas_sprite_buffer)) in entities.iter_with((&atlases, &mut buffers)) + { + let assets = assets.borrow().unwrap(); + let atlas = assets.get(atlas_sprite.atlas).clone(); + let uniform = AtlasSpriteUniform::from_atlas_sprite(atlas_sprite, &atlas); + queue.borrow().unwrap().get().write_buffer( + &atlas_sprite_buffer.0, + 0, + bytemuck::bytes_of(&uniform), + ); + } + } +} + +// System for updating sprite uniforms +pub fn update_sprite_uniforms(game: &mut bones::Game) { + let queue = game.shared_resource_cell::().unwrap(); + + for (_, session) in game.sessions.iter_mut() { + if !session.visible { + continue; + } + + let entities = session.world.resource::(); + let sprites = session.world.component::(); + let mut buffers = session.world.component_mut::(); + let transform = session.world.component::(); + + for (_, (sprite, atlas_sprite_buffer)) in entities.iter_with((&sprites, &mut buffers)) { + let base = BaseInstance { + color: sprite.color.as_rgba_f32(), + entity_type: 0, + transform: transform.to_matrix_none().to_cols_array_2d(), + }; + let sprite_flags = SpriteFlags { + flip: [sprite.flip_x as u32, sprite.flip_y as u32], + }; + + queue.borrow().unwrap().get().write_buffer( + &atlas_sprite_buffer.0, + 0, + bytemuck::bytes_of(&uniform), + ); + } + } +} + +// System for updating tiles uniforms +pub fn update_tiles_uniforms(game: &mut bones::Game) { + let assets = game.shared_resource_cell::().unwrap(); + let queue = game.shared_resource_cell::().unwrap(); + + for (_, session) in game.sessions.iter_mut() { + if !session.visible { + continue; + } + + let entities = session.world.resource::(); + let tile_layers = session.world.component::(); + let tiles = session.world.component::(); + let mut buffers = session.world.component_mut::(); + + for (_, (tile_layer, atlas_sprite_buffer)) in + entities.iter_with((&tile_layers, &mut buffers)) + { + let assets = assets.borrow().unwrap(); + let atlas = assets.get(tile_layer.atlas).clone(); + for tile in &tile_layer.tiles { + let Some(tile) = tile else { + continue; + }; + let Some(tile) = tiles.get(*tile) else { + panic!("Couldn't find tile entity!"); + }; + + let uniform = AtlasSpriteUniform::from_tile(tile, &atlas); + queue.borrow().unwrap().get().write_buffer( + &atlas_sprite_buffer.0, + 0, + bytemuck::bytes_of(&uniform), + ); + } + } + } +} +*/ diff --git a/framework_crates/bones_wgpu_renderer/src/storage.rs b/framework_crates/bones_wgpu_renderer/src/storage.rs new file mode 100644 index 0000000000..e03bab9af9 --- /dev/null +++ b/framework_crates/bones_wgpu_renderer/src/storage.rs @@ -0,0 +1,178 @@ +use bones_framework::prelude::*; +use serde::{de::Visitor, Deserialize, Serialize}; + +#[cfg(target_arch = "wasm32")] +pub use wasm::StorageBackend; +#[cfg(target_arch = "wasm32")] +mod wasm { + use super::*; + pub struct StorageBackend { + storage_key: String, + } + + impl StorageBackend { + pub fn new(qualifier: &str, organization: &str, application: &str) -> Self { + Self { + storage_key: format!("{qualifier}.{organization}.{application}.storage"), + } + } + } + + impl StorageApi for StorageBackend { + fn save(&mut self, data: Vec) { + let mut buffer = Vec::new(); + let mut serializer = serde_yaml::Serializer::new(&mut buffer); + LoadedStorage(data) + .serialize(&mut serializer) + .expect("Failed to serialize to storage file."); + let data = String::from_utf8(buffer).unwrap(); + let window = web_sys::window().unwrap(); + let storage = window.local_storage().unwrap().unwrap(); + storage.set_item(&self.storage_key, &data).unwrap(); + } + + fn load(&mut self) -> Vec { + let window = web_sys::window().unwrap(); + let storage = window.local_storage().unwrap().unwrap(); + let Some(data) = storage.get_item(&self.storage_key).unwrap() else { + return default(); + }; + + let Ok(loaded) = serde_yaml::from_str::(&data) else { + return default(); + }; + loaded.0 + } + } +} + +#[cfg(not(target_arch = "wasm32"))] +pub use native::StorageBackend; +#[cfg(not(target_arch = "wasm32"))] +mod native { + use super::*; + + pub struct StorageBackend { + storage_path: std::path::PathBuf, + } + + impl StorageBackend { + pub fn new(qualifier: &str, organization: &str, application: &str) -> Self { + let project_dirs = directories::ProjectDirs::from(qualifier, organization, application) + .expect("Identify system data dir path"); + Self { + storage_path: project_dirs.data_dir().join("storage.yml"), + } + } + } + + impl StorageApi for StorageBackend { + fn save(&mut self, data: Vec) { + let file = std::fs::OpenOptions::new() + .write(true) + .truncate(true) + .create(true) + .open(&self.storage_path) + .expect("Failed to open storage file"); + let mut serializer = serde_yaml::Serializer::new(file); + LoadedStorage(data) + .serialize(&mut serializer) + .expect("Failed to serialize to storage file."); + } + + fn load(&mut self) -> Vec { + if self.storage_path.exists() { + let result: anyhow::Result = (|| { + let file = std::fs::OpenOptions::new() + .read(true) + .open(&self.storage_path) + .context("Failed to open storage file")?; + let loaded: LoadedStorage = serde_yaml::from_reader(file) + .context("Failed to deserialize storage file")?; + + anyhow::Result::Ok(loaded) + })(); + match result { + Ok(loaded) => loaded.0, + Err(e) => { + log::error!( + "Error deserializing storage file, ignoring file, \ + data will be overwritten when saved: {e:?}" + ); + default() + } + } + } else { + std::fs::create_dir_all(self.storage_path.parent().unwrap()).unwrap(); + default() + } + } + } +} + +struct LoadedStorage(Vec); +impl Serialize for LoadedStorage { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let data: HashMap = self + .0 + .iter() + .map(|x| (x.schema().full_name.to_string(), x.as_ref())) + .collect(); + + use serde::ser::SerializeMap; + let mut map = serializer.serialize_map(Some(data.len()))?; + + for (key, value) in data { + map.serialize_key(&key)?; + map.serialize_value(&SchemaSerializer(value))?; + } + + map.end() + } +} +impl<'de> Deserialize<'de> for LoadedStorage { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_map(LoadedStorageVisitor).map(Self) + } +} +struct LoadedStorageVisitor; +impl<'de> Visitor<'de> for LoadedStorageVisitor { + type Value = Vec; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "Mapping of string type names to type data.") + } + fn visit_map(self, mut map: A) -> Result + where + A: serde::de::MapAccess<'de>, + { + let mut data = Vec::new(); + while let Some(type_name) = map.next_key::()? { + let Some(schema) = SCHEMA_REGISTRY + .schemas + .iter() + .find(|schema| schema.full_name.as_ref() == type_name) + else { + log::error!( + "\n\nCannot find schema registration for `{}` while loading persisted \ + storage. This means you that you need to call \ + `{}::schema()` to register your persisted storage type before \ + creating the `BonesWgpuRenderer` or that there is data from an old \ + version of the app inside of the persistent storage file.\n\n", + type_name, + type_name, + ); + continue; + }; + + data.push(map.next_value_seed(SchemaDeserializer(schema))?); + } + + Ok(data) + } +} diff --git a/framework_crates/bones_wgpu_renderer/src/test.rs b/framework_crates/bones_wgpu_renderer/src/test.rs new file mode 100644 index 0000000000..70b9f8de1b --- /dev/null +++ b/framework_crates/bones_wgpu_renderer/src/test.rs @@ -0,0 +1,250 @@ +use wgpu::util::DeviceExt; +use guillotiere::{AtlasAllocator, size2, Allocation}; + +// Your per-sprite instance data (with layer) +#[repr(C)] +#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +struct SpriteInstance { + model: [[f32; 4]; 4], + uv_min: [f32; 2], + uv_max: [f32; 2], + color: [f32; 4], + layer: f32, +} + +// Simplified sprite struct +struct Sprite { + atlas_id: usize, + allocation: Allocation, + layer: f32, + model: [[f32; 4]; 4], + uv_min: [f32; 2], + uv_max: [f32; 2], + color: [f32; 4], + is_transparent: bool, +} + +impl Sprite { + fn to_instance(&self) -> SpriteInstance { + SpriteInstance { + model: self.model, + uv_min: self.uv_min, + uv_max: self.uv_max, + color: self.color, + layer: self.layer, + } + } +} + +// --- 1. Pipeline setup --- + +// Depth format +const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth24Plus; + +// Create two pipelines: opaque and transparent +fn create_pipelines( + device: &wgpu::Device, + layout: &wgpu::BindGroupLayout, + vs_module: &wgpu::ShaderModule, + fs_module: &wgpu::ShaderModule, + sc_format: wgpu::TextureFormat, +) -> (wgpu::RenderPipeline, wgpu::RenderPipeline) { + let common = |depth_write: bool, blend: Option| { + wgpu::RenderPipelineDescriptor { + label: None, + layout: Some(&device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[layout], + push_constant_ranges: &[], + })), + vertex: wgpu::VertexState { + module: vs_module, + entry_point: "vs_main", + buffers: &[ + // quad vertex buffer (slot 0) + wgpu::VertexBufferLayout { /* pos+uv */ ..Default::default() }, + // instance buffer (slot 1) + wgpu::VertexBufferLayout { + array_stride: std::mem::size_of::() as _, + step_mode: wgpu::VertexStepMode::Instance, + attributes: &[ + // model matrix (locations 2–5), uv_min(6), uv_max(7), color(8), layer(9) + wgpu::VertexAttribute { + offset: 16*4, // after model + shader_location: 6, + format: wgpu::VertexFormat::Float32x2, + }, + wgpu::VertexAttribute { + offset: 16*4 + 2*4, + shader_location: 7, + format: wgpu::VertexFormat::Float32x2, + }, + wgpu::VertexAttribute { + offset: 16*4 + 4*4, + shader_location: 8, + format: wgpu::VertexFormat::Float32x4, + }, + wgpu::VertexAttribute { + offset: 16*4 + 8*4, + shader_location: 9, + format: wgpu::VertexFormat::Float32, + }, + ], + }, + ], + }, + fragment: Some(wgpu::FragmentState { + module: fs_module, + entry_point: "fs_main", + targets: &[Some(wgpu::ColorTargetState { + format: sc_format, + blend, + write_mask: wgpu::ColorWrites::ALL, + })], + }), + primitive: wgpu::PrimitiveState::default(), + depth_stencil: Some(wgpu::DepthStencilState { + format: DEPTH_FORMAT, + depth_write_enabled: depth_write, + depth_compare: wgpu::CompareFunction::LessEqual, + stencil: Default::default(), + bias: Default::default(), + }), + multisample: Default::default(), + multiview: None, + } + }; + + // Opaque: depth-write ON, no blending + let opaque = device.create_render_pipeline(&common(true, None)); + + // Transparent: depth-write OFF, alpha blending + let alpha_blend = wgpu::BlendState::ALPHA_BLENDING; + let transparent = device.create_render_pipeline(&common(false, Some(alpha_blend))); + + (opaque, transparent) +} + +// --- 2. Render loop --- + +fn render( + encoder: &mut wgpu::CommandEncoder, + view: &wgpu::TextureView, + depth_view: &wgpu::TextureView, + pipeline_opaque: &wgpu::RenderPipeline, + pipeline_transparent: &wgpu::RenderPipeline, + sprites: &mut Vec, + instance_buf: &wgpu::Buffer, + atlas_pool: &AtlasPool, + queue: &wgpu::Queue, +) { + // Separate lists + let mut opaque_sprites: Vec<_> = sprites.iter_mut().filter(|s| !s.is_transparent).collect(); + let mut transparent_sprites: Vec<_> = sprites.iter_mut().filter(|s| s.is_transparent).collect(); + + // === OPAQUE PASS === + { + // sort only by layer first (secondary atlas to reduce binds if you like) + opaque_sprites.sort_by(|a, b| { + a.layer.partial_cmp(&b.layer).unwrap() + .then(a.atlas_id.cmp(&b.atlas_id)) + }); + + let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Opaque Pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view, + resolve_target: None, + ops: wgpu::Operations::default(), + })], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: depth_view, + depth_ops: Some(wgpu::Operations::default()), + stencil_ops: None, + }), + }); + pass.set_pipeline(pipeline_opaque); + pass.set_vertex_buffer(0, /* your quad VB */); + // Batch by atlas + let mut last_atlas = None; + let mut batch = Vec::new(); + for sprite in opaque_sprites { + if Some(sprite.atlas_id) != last_atlas { + if let Some(id) = last_atlas { + // flush + queue.write_buffer(instance_buf, 0, bytemuck::cast_slice(&batch)); + let atlas = atlas_pool.get(id); + pass.set_bind_group(0, &atlas.bind_group, &[]); + pass.set_vertex_buffer(1, instance_buf.slice(..)); + pass.draw_indexed(0..6, 0, 0..batch.len() as u32); + } + batch.clear(); + last_atlas = Some(sprite.atlas_id); + } + batch.push(sprite.to_instance()); + } + // flush last + if let Some(id) = last_atlas { + queue.write_buffer(instance_buf, 0, bytemuck::cast_slice(&batch)); + let atlas = atlas_pool.get(id); + pass.set_bind_group(0, &atlas.bind_group, &[]); + pass.set_vertex_buffer(1, instance_buf.slice(..)); + pass.draw_indexed(0..6, 0, 0..batch.len() as u32); + } + } + + // === TRANSPARENT PASS === + { + // sort back-to-front: higher layer first + transparent_sprites.sort_by(|a, b| { + b.layer.partial_cmp(&a.layer).unwrap() + .then(a.atlas_id.cmp(&b.atlas_id)) + }); + + let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Transparent Pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: true, + }, + })], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: depth_view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Load, + store: false, // important: no depth write + }), + stencil_ops: None, + }), + }); + pass.set_pipeline(pipeline_transparent); + pass.set_vertex_buffer(0, /* your quad VB */); + + let mut last_atlas = None; + let mut batch = Vec::new(); + for sprite in transparent_sprites { + if Some(sprite.atlas_id) != last_atlas { + if let Some(id) = last_atlas { + queue.write_buffer(instance_buf, 0, bytemuck::cast_slice(&batch)); + let atlas = atlas_pool.get(id); + pass.set_bind_group(0, &atlas.bind_group, &[]); + pass.set_vertex_buffer(1, instance_buf.slice(..)); + pass.draw_indexed(0..6, 0, 0..batch.len() as u32); + } + batch.clear(); + last_atlas = Some(sprite.atlas_id); + } + batch.push(sprite.to_instance()); + } + if let Some(id) = last_atlas { + queue.write_buffer(instance_buf, 0, bytemuck::cast_slice(&batch)); + let atlas = atlas_pool.get(id); + pass.set_bind_group(0, &atlas.bind_group, &[]); + pass.set_vertex_buffer(1, instance_buf.slice(..)); + pass.draw_indexed(0..6, 0, 0..batch.len() as u32); + } + } +} diff --git a/framework_crates/bones_wgpu_renderer/src/texture.rs b/framework_crates/bones_wgpu_renderer/src/texture.rs new file mode 100644 index 0000000000..2998d6dc56 --- /dev/null +++ b/framework_crates/bones_wgpu_renderer/src/texture.rs @@ -0,0 +1,88 @@ +use image::{GenericImageView, ImageError}; + +pub struct Texture { + #[allow(unused)] + pub texture: wgpu::Texture, + pub view: wgpu::TextureView, + pub sampler: wgpu::Sampler, +} + +impl Texture { + #[allow(unused)] + pub fn from_bytes( + device: &wgpu::Device, + queue: &wgpu::Queue, + bytes: &[u8], + label: &str, + pixel_art: bool, + ) -> Result { + let img = image::load_from_memory(bytes)?; + Self::from_image(device, queue, &img, Some(label), pixel_art) + } + + pub fn from_image( + device: &wgpu::Device, + queue: &wgpu::Queue, + img: &image::DynamicImage, + label: Option<&str>, + pixel_art: bool, + ) -> Result { + let rgba = img.to_rgba8(); + let dimensions = img.dimensions(); + + let size = wgpu::Extent3d { + width: dimensions.0, + height: dimensions.1, + depth_or_array_layers: 1, + }; + let texture = device.create_texture(&wgpu::TextureDescriptor { + label, + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8UnormSrgb, + usage: wgpu::TextureUsages::TEXTURE_BINDING + | wgpu::TextureUsages::COPY_DST + | wgpu::TextureUsages::COPY_SRC, + view_formats: &[], + }); + + queue.write_texture( + wgpu::TexelCopyTextureInfo { + aspect: wgpu::TextureAspect::All, + texture: &texture, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + }, + &rgba, + wgpu::TexelCopyBufferLayout { + offset: 0, + bytes_per_row: Some(4 * dimensions.0), + rows_per_image: Some(dimensions.1), + }, + size, + ); + + let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + let sampler = device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: if pixel_art { + wgpu::FilterMode::Nearest + } else { + wgpu::FilterMode::Linear + }, + min_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::FilterMode::Nearest, + ..Default::default() + }); + + Ok(Self { + texture, + view, + sampler, + }) + } +} diff --git a/framework_crates/bones_wgpu_renderer/src/texture_file.rs b/framework_crates/bones_wgpu_renderer/src/texture_file.rs new file mode 100644 index 0000000000..a5d3f6a48c --- /dev/null +++ b/framework_crates/bones_wgpu_renderer/src/texture_file.rs @@ -0,0 +1,82 @@ +use image::{ImageBuffer, Rgba}; + +#[allow(unused)] +pub fn dump_texture_to_png( + device: &wgpu::Device, + queue: &wgpu::Queue, + texture: &wgpu::Texture, + size: (u32, u32), + path: &std::path::Path, +) -> anyhow::Result<()> { + let mut encoder = device.create_command_encoder(&Default::default()); + + let (width, height) = size; + + // 1) Create a buffer large enough to hold the RGBA8 data, + // with COPY_DST so we can copy into it + let pixel_size = 4; // RGBA8 + let padded_bytes_per_row = { + // GPU requires rows aligned to 256 bytes: + let unpadded = pixel_size * width as usize; + ((unpadded + 255) / 256) * 256 + }; + let output_buffer_size = (padded_bytes_per_row * height as usize) as u64; + + let dst_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("texture-readback-buffer"), + size: output_buffer_size, + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, + mapped_at_creation: false, + }); + + // 2) Copy the texture to the buffer + encoder.copy_texture_to_buffer( + wgpu::TexelCopyTextureInfo { + texture, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + aspect: wgpu::TextureAspect::All, + }, + wgpu::TexelCopyBufferInfo { + buffer: &dst_buffer, + layout: wgpu::TexelCopyBufferLayout { + offset: 0, + bytes_per_row: Some(padded_bytes_per_row as u32), + rows_per_image: Some(height), + }, + }, + wgpu::Extent3d { + width, + height, + depth_or_array_layers: 1, + }, + ); + + // 3) Submit the copy command and wait for it to finish + queue.submit(Some(encoder.finish())); + device.poll(wgpu::Maintain::Wait); + + // 4) Map the buffer and read its contents + let slice = dst_buffer.slice(..); + slice.map_async(wgpu::MapMode::Read, |res| res.unwrap()); + // wait for the mapping to finish + device.poll(wgpu::Maintain::Wait); + let data = slice.get_mapped_range(); + + // 5) Demultiplex rows (drop the padding) into a contiguous Vec + let mut pixels = Vec::with_capacity((pixel_size * width as usize * height as usize) as usize); + for row in 0..height as usize { + let offset = row * padded_bytes_per_row; + pixels.extend_from_slice(&data[offset..offset + (pixel_size * width as usize)]); + } + // Unmap so the buffer can be reused/dropped + drop(data); + dst_buffer.unmap(); + + // 6) Encode & save with the `image` crate + let img: ImageBuffer, _> = ImageBuffer::from_raw(width, height, pixels) + .expect("buffer size should match width*height*4"); + img.save(path)?; + + Ok(()) +} diff --git a/framework_crates/bones_wgpu_renderer/src/ui.rs b/framework_crates/bones_wgpu_renderer/src/ui.rs new file mode 100644 index 0000000000..b42e98ac9c --- /dev/null +++ b/framework_crates/bones_wgpu_renderer/src/ui.rs @@ -0,0 +1,161 @@ +use egui::Context; +use egui_wgpu::wgpu::{CommandEncoder, Device, Queue, StoreOp, TextureFormat, TextureView}; +use egui_wgpu::{wgpu, Renderer, ScreenDescriptor}; +use egui_winit::State; +use winit::event::WindowEvent; +use winit::window::Window; + +use crate::bones; + +pub struct EguiRenderer { + state: State, + renderer: Renderer, + frame_started: bool, +} + +impl EguiRenderer { + pub fn context(&self) -> &Context { + self.state.egui_ctx() + } + + pub fn new( + device: &Device, + output_color_format: TextureFormat, + output_depth_format: Option, + msaa_samples: u32, + window: &Window, + ) -> EguiRenderer { + let egui_context = Context::default(); + + let egui_state = egui_winit::State::new( + egui_context, + egui::viewport::ViewportId::ROOT, + &window, + Some(window.scale_factor() as f32), + None, + Some(2 * 1024), // default dimension is 2048 + ); + let egui_renderer = Renderer::new( + device, + output_color_format, + output_depth_format, + msaa_samples, + true, + ); + + EguiRenderer { + state: egui_state, + renderer: egui_renderer, + frame_started: false, + } + } + + pub fn handle_input(&mut self, window: &Window, event: &WindowEvent) { + let _ = self.state.on_window_event(window, event); + } + + pub fn ppp(&mut self, v: f32) { + self.context().set_pixels_per_point(v); + } + + pub fn begin_frame(&mut self, window: &Window) { + let raw_input = self.state.take_egui_input(window); + self.state.egui_ctx().begin_pass(raw_input); + self.frame_started = true; + } + + pub fn end_frame_and_draw( + &mut self, + device: &Device, + queue: &Queue, + encoder: &mut CommandEncoder, + window: &Window, + window_surface_view: &TextureView, + screen_descriptor: ScreenDescriptor, + ) { + if !self.frame_started { + panic!("begin_frame must be called before end_frame_and_draw can be called!"); + } + + self.ppp(screen_descriptor.pixels_per_point); + + let full_output = self.state.egui_ctx().end_pass(); + + self.state + .handle_platform_output(window, full_output.platform_output); + + let tris = self + .state + .egui_ctx() + .tessellate(full_output.shapes, self.state.egui_ctx().pixels_per_point()); + for (id, image_delta) in &full_output.textures_delta.set { + self.renderer + .update_texture(device, queue, *id, image_delta); + } + self.renderer + .update_buffers(device, queue, encoder, &tris, &screen_descriptor); + let rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: window_surface_view, + resolve_target: None, + ops: egui_wgpu::wgpu::Operations { + load: egui_wgpu::wgpu::LoadOp::Load, + store: StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + label: Some("egui main render pass"), + occlusion_query_set: None, + }); + + self.renderer + .render(&mut rpass.forget_lifetime(), &tris, &screen_descriptor); + for x in &full_output.textures_delta.free { + self.renderer.free_texture(x) + } + + self.frame_started = false; + } +} + +pub fn default_load_progress(asset_server: &bones::AssetServer, ctx: &egui::Context) { + let errored = asset_server.load_progress.errored(); + + egui::CentralPanel::default().show(ctx, |ui| { + let height = ui.available_height(); + let ctx = ui.ctx().clone(); + + let space_size = 0.03; + let spinner_size = 0.07; + let text_size = 0.034; + ui.vertical_centered(|ui| { + ui.add_space(height * 0.3); + + if errored > 0 { + ui.label( + egui::RichText::new("⚠") + .color(egui::Color32::RED) + .size(height * spinner_size), + ); + ui.add_space(height * space_size); + ui.label( + egui::RichText::new(format!( + "Error loading {errored} asset{}.", + if errored > 1 { "s" } else { "" } + )) + .color(egui::Color32::RED) + .size(height * text_size * 0.75), + ); + } else { + ui.add(egui::Spinner::new().size(height * spinner_size)); + ui.add_space(height * space_size); + ui.label(egui::RichText::new("Loading").size(height * text_size)); + } + }); + + ctx.data_mut(|d| { + d.insert_temp(ui.id(), (spinner_size, space_size, text_size)); + }) + }); +} diff --git a/framework_crates/bones_wgpu_renderer/src/uniforms.rs b/framework_crates/bones_wgpu_renderer/src/uniforms.rs new file mode 100644 index 0000000000..40e70c1617 --- /dev/null +++ b/framework_crates/bones_wgpu_renderer/src/uniforms.rs @@ -0,0 +1,64 @@ +#[derive(bones_schema::HasSchema)] +#[repr(C)] +#[schema(opaque, no_default, no_clone)] +pub struct RenderBuffers { + // Instance data (updated per entity) + pub base: wgpu::Buffer, + pub sprite_flags: wgpu::Buffer, + pub atlas_data: wgpu::Buffer, +} + +impl RenderBuffers { + pub fn new(device: &wgpu::Device) -> Self { + // Initialize with empty data + let initial_size = 1024; // Starting capacity + let buffer_desc = |usage| wgpu::BufferDescriptor { + label: None, + size: initial_size as u64, + usage, + mapped_at_creation: false, + }; + + Self { + base: device.create_buffer(&buffer_desc( + wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, + )), + sprite_flags: device.create_buffer(&buffer_desc( + wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, + )), + atlas_data: device.create_buffer(&buffer_desc( + wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, + )), + } + } +} + +// Common to ALL renderable types +#[repr(C)] +#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +pub struct BaseInstance { + pub transform: [[f32; 4]; 4], // Mat4 + pub entity_type: u32, // 0 = sprite, 1 = atlas, 2 = path2d + pub color: [f32; 4], +} + +// Sprite/Atlas-specific extensions +#[repr(C)] +#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +pub struct SpriteFlags { + pub flip: [u32; 2], // Packed as bits: 0x1 = flip_x, 0x2 = flip_y + pub uv_min: [f32; 2], // Atlas UV coordinates (min_x, min_y) + pub uv_max: [f32; 2], // Atlas UV coordinates (max_x, max_y) +} + +// Atlas-specific data +#[repr(C)] +#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +pub struct AtlasData { + pub tile_size: [f32; 2], + pub image_size: [f32; 2], + pub padding: [f32; 2], + pub offset: [f32; 2], + pub columns: u32, + pub index: u32, +}