diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b4f6643a..327fed0a 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -35,7 +35,7 @@ jobs: shared-key: ci save-if: false - run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev - - run: cargo check --workspace --no-default-features + - run: cargo check --workspace --no-default-features --features libm clippy: runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index 63ff0b28..b6343e4b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -110,7 +110,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" dependencies = [ "alsa-sys", - "bitflags 2.11.0", + "bitflags 2.11.1", "cfg-if", "libc", ] @@ -127,23 +127,22 @@ dependencies = [ [[package]] name = "android-activity" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" +checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" dependencies = [ "android-properties", - "bitflags 2.11.0", + "bitflags 2.11.1", "cc", - "cesu8", - "jni", - "jni-sys", + "jni 0.22.4", "libc", "log", "ndk 0.9.0", "ndk-context", "ndk-sys 0.6.0+11769913", "num_enum", - "thiserror 1.0.69", + "simd_cesu8", + "thiserror 2.0.18", ] [[package]] @@ -318,9 +317,9 @@ dependencies = [ [[package]] name = "atomicow" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52e8890bb9844440d0c412fa74b67fd2f14e85248b6e00708059b6da9e5f8bf" +checksum = "301801c08259e328a1c7da556608c0c22687708831b22024dbd3a57ea741e6de" dependencies = [ "portable-atomic", "portable-atomic-util", @@ -479,7 +478,7 @@ dependencies = [ "bevy_reflect", "bevy_tasks", "bevy_utils", - "bitflags 2.11.0", + "bitflags 2.11.1", "blake3", "crossbeam-channel", "derive_more", @@ -595,7 +594,7 @@ dependencies = [ "bevy_transform", "bevy_utils", "bevy_window", - "bitflags 2.11.0", + "bitflags 2.11.1", "nonmax", "radsort", "smallvec", @@ -674,7 +673,7 @@ dependencies = [ "bevy_reflect", "bevy_tasks", "bevy_utils", - "bitflags 2.11.0", + "bitflags 2.11.1", "bumpalo", "concurrent-queue", "derive_more", @@ -871,7 +870,7 @@ dependencies = [ "bevy_platform", "bevy_reflect", "bevy_utils", - "bitflags 2.11.0", + "bitflags 2.11.1", "bytemuck", "futures-lite", "guillotiere", @@ -1062,7 +1061,7 @@ dependencies = [ "bevy_platform", "bevy_reflect", "bevy_transform", - "bitflags 2.11.0", + "bitflags 2.11.1", "bytemuck", "derive_more", "hexasphere", @@ -1088,9 +1087,7 @@ dependencies = [ "bevy_derive", "bevy_ecs", "bevy_math", - "bevy_pbr", "bevy_platform", - "bevy_sprite", "bevy_time", "bevy_transform", "motiongfx", @@ -1121,7 +1118,7 @@ dependencies = [ "bevy_shader", "bevy_transform", "bevy_utils", - "bitflags 2.11.0", + "bitflags 2.11.1", "bytemuck", "derive_more", "fixedbitset", @@ -1199,7 +1196,7 @@ dependencies = [ "bevy_transform", "bevy_utils", "bevy_window", - "bitflags 2.11.0", + "bitflags 2.11.1", "nonmax", "radsort", "smallvec", @@ -1283,7 +1280,7 @@ dependencies = [ "bevy_transform", "bevy_utils", "bevy_window", - "bitflags 2.11.0", + "bitflags 2.11.1", "bytemuck", "derive_more", "downcast-rs 2.0.2", @@ -1406,7 +1403,7 @@ dependencies = [ "bevy_text", "bevy_transform", "bevy_utils", - "bitflags 2.11.0", + "bitflags 2.11.1", "bytemuck", "derive_more", "fixedbitset", @@ -1674,14 +1671,14 @@ version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "cexpr", "clang-sys", "itertools 0.13.0", "proc-macro2", "quote", "regex", - "rustc-hash 2.1.1", + "rustc-hash 2.1.2", "shlex", "syn", ] @@ -1709,9 +1706,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" dependencies = [ "bytemuck", "serde_core", @@ -1719,9 +1716,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.8.3" +version = "1.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" +checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce" dependencies = [ "arrayref", "arrayvec", @@ -1818,7 +1815,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "log", "polling", "rustix 0.38.44", @@ -1840,9 +1837,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.56" +version = "1.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" dependencies = [ "find-msvc-tools", "jobserver", @@ -1899,6 +1896,15 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "color" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ec7c5eb7a16992b1904d76c517d170ab353b0e0b3d5a0c81a8a0cd1037893cf" +dependencies = [ + "libm", +] + [[package]] name = "combine" version = "4.6.7" @@ -2030,7 +2036,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "core-foundation 0.10.1", "libc", ] @@ -2070,7 +2076,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cadaea21e24c49c0c82116f2b465ae6a49d63c90e428b0f8d9ae1f638ac91f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "fontdb", "harfrust", "linebender_resource_handle", @@ -2098,7 +2104,7 @@ dependencies = [ "core-foundation-sys", "coreaudio-rs", "dasp_sample", - "jni", + "jni 0.21.1", "js-sys", "libc", "mach2", @@ -2113,9 +2119,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.17" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" dependencies = [ "libc", ] @@ -2172,7 +2178,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162" dependencies = [ "dispatch2", - "nix 0.31.2", + "nix 0.31.3", "windows-sys 0.61.2", ] @@ -2190,9 +2196,9 @@ checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" [[package]] name = "data-encoding" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" +checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" [[package]] name = "derive_more" @@ -2229,7 +2235,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2 0.6.2", "libc", "objc2 0.6.4", @@ -2343,9 +2349,9 @@ dependencies = [ [[package]] name = "euclid" -version = "0.22.13" +version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df61bf483e837f88d5c2291dcf55c67be7e676b3a51acc48db3a7b163b91ed63" +checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06" dependencies = [ "num-traits", ] @@ -2373,9 +2379,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "fdeflate" @@ -2441,6 +2447,15 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "font-types" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b38ad915f6dadd993ced50848a8291a543bd41ca62bc10740d5e64e2ab4cfd7" +dependencies = [ + "bytemuck", +] + [[package]] name = "fontconfig-parser" version = "0.5.8" @@ -2506,6 +2521,17 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + [[package]] name = "futures-io" version = "0.3.32" @@ -2717,7 +2743,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "gpu-alloc-types", ] @@ -2727,7 +2753,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] @@ -2748,7 +2774,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "gpu-descriptor-types", "hashbrown 0.15.5", ] @@ -2759,14 +2785,14 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] name = "grid" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e2d4c0a8296178d8802098410ca05d86b17a10bb5ab559b3fb404c1f948220" +checksum = "b40ca9252762c466af32d0b1002e91e4e1bc5398f77455e55474deb466355ff5" [[package]] name = "guillotiere" @@ -2796,7 +2822,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0caaee032384c10dd597af4579c67dee16650d862a9ccbe1233ff1a379abc07" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "bytemuck", "core_maths", "read-fonts 0.36.0", @@ -2833,11 +2859,17 @@ dependencies = [ "serde_core", ] +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + [[package]] name = "heapless" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" +checksum = "25ba4bd83f9415b58b4ed8dc5714c76e626a105be4646c02630ad730ad3b5aa4" dependencies = [ "hash32", "portable-atomic", @@ -2881,25 +2913,25 @@ checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" [[package]] name = "image" -version = "0.25.9" +version = "0.25.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" dependencies = [ "bytemuck", "byteorder-lite", "moxcms", "num-traits", - "png", + "png 0.18.1", ] [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "serde", "serde_core", ] @@ -2916,7 +2948,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "inotify-sys", "libc", ] @@ -2932,9 +2964,9 @@ dependencies = [ [[package]] name = "inventory" -version = "0.3.22" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "009ae045c87e7082cb72dab0ccd01ae075dd00141ddc108f43a0ea150a9e7227" +checksum = "a4f0c30c76f2f4ccee3fe55a2435f691ca00c0e4bd87abe4f4a851b1d4dac39b" dependencies = [ "rustversion", ] @@ -2959,9 +2991,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jni" @@ -2972,18 +3004,70 @@ dependencies = [ "cesu8", "cfg-if", "combine", - "jni-sys", + "jni-sys 0.3.1", "log", "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link 0.2.1", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn", +] + [[package]] name = "jni-sys" -version = "0.3.0" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] [[package]] name = "jobserver" @@ -2997,10 +3081,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.91" +version = "0.3.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] @@ -3028,7 +3114,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff7f53bdf698e7aa7ec916411bbdc8078135da11b66db5182675b2227f6c0d07" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", +] + +[[package]] +name = "kurbo" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b60dfc32f652b926df6192e55525b16d186c69d47876c3ead4da5cc9f8450e2" +dependencies = [ + "arrayvec", + "euclid", + "libm", + "polycool", + "smallvec", ] [[package]] @@ -3056,9 +3155,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.182" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libloading" @@ -3078,14 +3177,14 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.14" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "libc", "plain", - "redox_syscall 0.7.3", + "redox_syscall 0.7.5", ] [[package]] @@ -3185,7 +3284,7 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00c15a6f673ff72ddcc22394663290f870fb224c1bfce55734a75c414150e605" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block", "core-graphics-types 0.2.0", "foreign-types", @@ -3223,9 +3322,9 @@ dependencies = [ [[package]] name = "moxcms" -version = "0.7.11" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" dependencies = [ "num-traits", "pxfm", @@ -3239,7 +3338,7 @@ checksum = "066cf25f0e8b11ee0df221219010f213ad429855f57c494f995590c861a9a7d8" dependencies = [ "arrayvec", "bit-set", - "bitflags 2.11.0", + "bitflags 2.11.1", "cfg-if", "cfg_aliases", "codespan-reporting", @@ -3281,8 +3380,8 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" dependencies = [ - "bitflags 2.11.0", - "jni-sys", + "bitflags 2.11.1", + "jni-sys 0.3.1", "log", "ndk-sys 0.5.0+25.2.9519653", "num_enum", @@ -3295,8 +3394,8 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.11.0", - "jni-sys", + "bitflags 2.11.1", + "jni-sys 0.3.1", "log", "ndk-sys 0.6.0+11769913", "num_enum", @@ -3316,7 +3415,7 @@ version = "0.5.0+25.2.9519653" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" dependencies = [ - "jni-sys", + "jni-sys 0.3.1", ] [[package]] @@ -3325,7 +3424,7 @@ version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ - "jni-sys", + "jni-sys 0.3.1", ] [[package]] @@ -3334,7 +3433,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "cfg-if", "cfg_aliases", "libc", @@ -3342,11 +3441,11 @@ dependencies = [ [[package]] name = "nix" -version = "0.31.2" +version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "cfg-if", "cfg_aliases", "libc", @@ -3415,9 +3514,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" dependencies = [ "num_enum_derive", "rustversion", @@ -3425,9 +3524,9 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3475,7 +3574,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -3491,7 +3590,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2 0.5.1", "objc2 0.5.2", "objc2-core-location", @@ -3515,7 +3614,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation", @@ -3527,7 +3626,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] @@ -3566,7 +3665,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2 0.5.1", "dispatch", "libc", @@ -3579,7 +3678,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "libc", "objc2-core-foundation", ] @@ -3602,7 +3701,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation", @@ -3614,7 +3713,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation", @@ -3637,7 +3736,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2 0.5.1", "objc2 0.5.2", "objc2-cloud-kit", @@ -3669,7 +3768,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "block2 0.5.1", "objc2 0.5.2", "objc2-core-location", @@ -3682,7 +3781,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" dependencies = [ - "jni", + "jni 0.21.1", "ndk 0.8.0", "ndk-context", "num-derive", @@ -3720,15 +3819,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "orbclient" -version = "0.3.50" +version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ad2c6bae700b7aa5d1cc30c59bdd3a1c180b09dbaea51e2ae2b8e1cf211fdd" +checksum = "a570f6bca41d29acb2139229a7c873ec99bc9a313bd10804081d89bfac8ff329" dependencies = [ "libc", "libredox", @@ -3736,9 +3835,9 @@ dependencies = [ [[package]] name = "ordered-float" -version = "5.1.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d" +checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" dependencies = [ "num-traits", ] @@ -3787,6 +3886,26 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "peniko" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "839c8299360d2e998bdb106dc0a6cd71dcc5f4df51df1b620361bf50e283cca6" +dependencies = [ + "color", + "kurbo", + "linebender_resource_handle", + "smallvec", +] + +[[package]] +name = "peniko_motiongfx" +version = "0.3.0" +dependencies = [ + "motiongfx", + "peniko", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -3808,18 +3927,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.11" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.11" +version = "1.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", @@ -3845,9 +3964,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "plain" @@ -3855,13 +3974,26 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "png" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "crc32fast", "fdeflate", "flate2", @@ -3882,6 +4014,22 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "pollster" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" + +[[package]] +name = "polycool" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50596ddc09eb5ad5f75cacd40209568e66df71baf86e1499a0e99c4cff12a5a6" +dependencies = [ + "arrayvec", + "libm", +] + [[package]] name = "portable-atomic" version = "1.13.1" @@ -3890,9 +4038,9 @@ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" dependencies = [ "portable-atomic", ] @@ -3937,7 +4085,7 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.25.4+spec-1.1.0", + "toml_edit 0.25.11+spec-1.1.0", ] [[package]] @@ -3951,21 +4099,21 @@ dependencies = [ [[package]] name = "profiling" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" [[package]] name = "pxfm" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" +checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f" [[package]] name = "quick-xml" -version = "0.39.2" +version = "0.39.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" +checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" dependencies = [ "memchr", ] @@ -3999,9 +4147,9 @@ checksum = "019b4b213425016d7d84a153c4c73afb0946fbb4840e4eece7ba8848b9d6da22" [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha", "rand_core", @@ -4056,23 +4204,23 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "read-fonts" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717cf23b488adf64b9d711329542ba34de147df262370221940dfabc2c91358" +checksum = "5eaa2941a4c05443ee3a7b26ab076a553c343ad5995230cc2b1d3e993bdc6345" dependencies = [ "bytemuck", - "font-types", + "core_maths", + "font-types 0.10.1", ] [[package]] name = "read-fonts" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eaa2941a4c05443ee3a7b26ab076a553c343ad5995230cc2b1d3e993bdc6345" +checksum = "7b634fabf032fab15307ffd272149b622260f55974d9fad689292a5d33df02e5" dependencies = [ "bytemuck", - "core_maths", - "font-types", + "font-types 0.11.3", ] [[package]] @@ -4096,16 +4244,16 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] name = "redox_syscall" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +checksum = "4666a1a60d8412eab19d94f6d13dcc9cea0a5ef4fdf6a5db306537413c661b1b" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] @@ -4155,11 +4303,11 @@ dependencies = [ [[package]] name = "ron" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd490c5b18261893f14449cbd28cb9c0b637aebf161cd77900bfdedaff21ec32" +checksum = "4147b952f3f819eca0e99527022f7d6a8d05f111aeb0a62960c74eb283bec8fc" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "once_cell", "serde", "serde_derive", @@ -4181,9 +4329,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "rustc_version" @@ -4200,7 +4348,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "errno", "libc", "linux-raw-sys 0.4.15", @@ -4213,7 +4361,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "errno", "libc", "linux-raw-sys 0.12.1", @@ -4228,9 +4376,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ruzstd" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01" +checksum = "a7c1c839d570d835527c9a5e4db7cb2198683a988cb9d7293fc8674e6bd58fc8" dependencies = [ "twox-hash", ] @@ -4277,9 +4425,9 @@ checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "send_wrapper" @@ -4347,20 +4495,26 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" [[package]] -name = "skrifa" -version = "0.37.0" +name = "simd_cesu8" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c31071dedf532758ecf3fed987cdb4bd9509f900e026ab684b4ecb81ea49841" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" dependencies = [ - "bytemuck", - "read-fonts 0.35.0", + "rustc_version", + "simdutf8", ] +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "skrifa" version = "0.39.0" @@ -4371,6 +4525,16 @@ dependencies = [ "read-fonts 0.36.0", ] +[[package]] +name = "skrifa" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fbdfe3d2475fbd7ddd1f3e5cf8288a30eb3e5f95832829570cd88115a7434ac" +dependencies = [ + "bytemuck", + "read-fonts 0.37.0", +] + [[package]] name = "slab" version = "0.4.12" @@ -4398,7 +4562,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "calloop", "calloop-wayland-source", "cursor-icon", @@ -4441,7 +4605,7 @@ version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] @@ -4479,11 +4643,11 @@ checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb" [[package]] name = "swash" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47846491253e976bdd07d0f9cc24b7daf24720d11309302ccbbc6e6b6e53550a" +checksum = "842f3cd369c2ba38966204f983eaa5e54a8e84a7d7159ed36ade2b6c335aae64" dependencies = [ - "skrifa 0.37.0", + "skrifa 0.40.0", "yazi", "zeno", ] @@ -4619,9 +4783,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -4643,9 +4807,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "1.0.0+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] @@ -4659,28 +4823,28 @@ dependencies = [ "indexmap", "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", - "winnow", + "winnow 0.7.15", ] [[package]] name = "toml_edit" -version = "0.25.4+spec-1.1.0" +version = "0.25.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" +checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" dependencies = [ "indexmap", - "toml_datetime 1.0.0+spec-1.1.0", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", - "winnow", + "winnow 1.0.3", ] [[package]] name = "toml_parser" -version = "1.0.9+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow", + "winnow 1.0.3", ] [[package]] @@ -4740,9 +4904,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "matchers", "nu-ansi-term", @@ -4790,9 +4954,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typewit" -version = "1.14.2" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c1ae7cc0fdb8b842d65d127cb981574b0d2b249b74d1c7a2986863dc134f71" +checksum = "214ca0b2191785cbc06209b9ca1861e048e39b5ba33574b3cedd58363d5bb5f6" [[package]] name = "unicode-bidi" @@ -4820,9 +4984,9 @@ checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" [[package]] name = "unicode-width" @@ -4838,9 +5002,9 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "uuid" -version = "1.22.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" +checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" dependencies = [ "getrandom 0.4.2", "js-sys", @@ -4871,6 +5035,62 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +[[package]] +name = "vello" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72fef40773530322d5c2ffe3c1107e9874bd8239ac137d1c2b6c1edad695146e" +dependencies = [ + "bytemuck", + "futures-intrusive", + "log", + "peniko", + "png 0.17.16", + "skrifa 0.40.0", + "static_assertions", + "thiserror 2.0.18", + "vello_encoding", + "vello_shaders", + "wgpu", +] + +[[package]] +name = "vello_encoding" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24c91203ec4b483440614a9a5c7c2d991932af72c5349659a63ec49476f0b79c" +dependencies = [ + "bytemuck", + "guillotiere", + "peniko", + "skrifa 0.40.0", + "smallvec", +] + +[[package]] +name = "vello_shaders" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a765d44d4bd354146e44f9a860f4e92effd91a97302549be9e47f0a18d8128c" +dependencies = [ + "bytemuck", + "log", + "naga", + "thiserror 2.0.18", + "vello_encoding", +] + +[[package]] +name = "vello_winit_example" +version = "0.3.0" +dependencies = [ + "motiongfx", + "peniko_motiongfx", + "pollster", + "vello", + "winit", +] + [[package]] name = "version_check" version = "0.9.5" @@ -4889,11 +5109,11 @@ dependencies = [ [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.57.1", ] [[package]] @@ -4902,14 +5122,14 @@ version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.51.0", ] [[package]] name = "wasm-bindgen" -version = "0.2.114" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" dependencies = [ "cfg-if", "once_cell", @@ -4920,23 +5140,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.64" +version = "0.4.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" +checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8" dependencies = [ - "cfg-if", - "futures-util", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.114" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4944,9 +5160,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.114" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" dependencies = [ "bumpalo", "proc-macro2", @@ -4957,9 +5173,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.114" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" dependencies = [ "unicode-ident", ] @@ -4992,7 +5208,7 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "hashbrown 0.15.5", "indexmap", "semver", @@ -5000,9 +5216,9 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa75f400b7f719bcd68b3f47cd939ba654cedeef690f486db71331eec4c6a406" +checksum = "2857dd20b54e916ec7253b3d6b4d5c4d7d4ca2c33c2e11c6c76a99bd8744755d" dependencies = [ "cc", "downcast-rs 1.2.1", @@ -5014,11 +5230,11 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.13" +version = "0.31.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab51d9f7c071abeee76007e2b742499e535148035bb835f97aaed1338cf516c3" +checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "rustix 1.1.4", "wayland-backend", "wayland-scanner", @@ -5030,16 +5246,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "cursor-icon", "wayland-backend", ] [[package]] name = "wayland-cursor" -version = "0.31.13" +version = "0.31.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b3298683470fbdc6ca40151dfc48c8f2fd4c41a26e13042f801f85002384091" +checksum = "4a52d18780be9b1314328a3de5f930b73d2200112e3849ca6cb11822793fb34d" dependencies = [ "rustix 1.1.4", "wayland-client", @@ -5048,11 +5264,11 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.32.11" +version = "0.32.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b23b5df31ceff1328f06ac607591d5ba360cf58f90c8fad4ac8d3a55a3c4aec7" +checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "wayland-backend", "wayland-client", "wayland-scanner", @@ -5060,11 +5276,11 @@ dependencies = [ [[package]] name = "wayland-protocols-plasma" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d392fc283a87774afc9beefcd6f931582bb97fe0e6ced0b306a62cb1d026527c" +checksum = "2b6d8cf1eb2c1c31ed1f5643c88a6e53538129d4af80030c8cabd1f9fa884d91" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -5073,11 +5289,11 @@ dependencies = [ [[package]] name = "wayland-protocols-wlr" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78248e4cc0eff8163370ba5c158630dcae1f3497a586b826eca2ef5f348d6235" +checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -5086,9 +5302,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.9" +version = "0.31.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86287151a309799b821ca709b7345a048a2956af05957c89cb824ab919fa4e3" +checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a" dependencies = [ "proc-macro2", "quick-xml", @@ -5097,20 +5313,21 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.31.10" +version = "0.31.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374f6b70e8e0d6bf9461a32988fd553b59ff630964924dad6e4a4eb6bd538d17" +checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be" dependencies = [ "dlib", "log", + "once_cell", "pkg-config", ] [[package]] name = "web-sys" -version = "0.3.91" +version = "0.3.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa" dependencies = [ "js-sys", "wasm-bindgen", @@ -5133,7 +5350,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfe68bac7cde125de7a731c3400723cadaaf1703795ad3f4805f187459cd7a77" dependencies = [ "arrayvec", - "bitflags 2.11.0", + "bitflags 2.11.1", "cfg-if", "cfg_aliases", "document-features", @@ -5141,12 +5358,14 @@ dependencies = [ "js-sys", "log", "naga", + "parking_lot", "portable-atomic", "profiling", "raw-window-handle", "smallvec", "static_assertions", "wasm-bindgen", + "wasm-bindgen-futures", "web-sys", "wgpu-core", "wgpu-hal", @@ -5162,7 +5381,7 @@ dependencies = [ "arrayvec", "bit-set", "bit-vec", - "bitflags 2.11.0", + "bitflags 2.11.1", "bytemuck", "cfg_aliases", "document-features", @@ -5179,6 +5398,7 @@ dependencies = [ "smallvec", "thiserror 2.0.18", "wgpu-core-deps-apple", + "wgpu-core-deps-emscripten", "wgpu-core-deps-wasm", "wgpu-core-deps-windows-linux-android", "wgpu-hal", @@ -5194,6 +5414,15 @@ dependencies = [ "wgpu-hal", ] +[[package]] +name = "wgpu-core-deps-emscripten" +version = "27.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06ac3444a95b0813ecfd81ddb2774b66220b264b3e2031152a4a29fda4da6b5" +dependencies = [ + "wgpu-hal", +] + [[package]] name = "wgpu-core-deps-wasm" version = "27.0.0" @@ -5222,7 +5451,7 @@ dependencies = [ "arrayvec", "ash", "bit-set", - "bitflags 2.11.0", + "bitflags 2.11.1", "block", "bytemuck", "cfg-if", @@ -5267,7 +5496,7 @@ version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afdcf84c395990db737f2dd91628706cb31e86d72e53482320d368e52b5da5eb" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "bytemuck", "js-sys", "log", @@ -5765,7 +5994,7 @@ dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.11.0", + "bitflags 2.11.1", "block2 0.5.1", "bytemuck", "calloop", @@ -5817,6 +6046,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +dependencies = [ + "memchr", +] + [[package]] name = "wit-bindgen" version = "0.51.0" @@ -5826,6 +6064,12 @@ dependencies = [ "wit-bindgen-rust-macro", ] +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + [[package]] name = "wit-bindgen-core" version = "0.51.0" @@ -5875,7 +6119,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.0", + "bitflags 2.11.1", "indexmap", "log", "serde", @@ -5949,7 +6193,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "dlib", "log", "once_cell", @@ -5982,18 +6226,18 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" [[package]] name = "zerocopy" -version = "0.8.40" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.40" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 23ab5999..7453828e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ repository = "https://github.com/voxell-tech/motiongfx" # motiongfx motiongfx = { version = "0.3.0", path = "crates/motiongfx" } bevy_motiongfx = { version = "0.3.0", path = "crates/bevy_motiongfx" } +peniko_motiongfx = { version = "0.3.0", path = "crates/peniko_motiongfx" } # bevy bevy = { version = "0.18.1", default-features = false } @@ -24,16 +25,17 @@ bevy_asset = { version = "0.18.1", default-features = false } bevy_time = { version = "0.18.1", default-features = false } bevy_transform = { version = "0.18.1", default-features = false, features = ["bevy-support"] } bevy_color = { version = "0.18.1", default-features = false } -bevy_sprite = { version = "0.18.1", default-features = false } -bevy_pbr = { version = "0.18.1", default-features = false } # other field_path = "0.4.1" nonempty = { version = "0.12", default-features = false } +peniko = { version = "0.6", default-features = false } +vello = "0.7.0" +winit = "0.30" +pollster = "0.4" [workspace.lints.clippy] redundant_type_annotations = "warn" -bool_comparison = "allow" # Enable a small amount of optimization in the dev profile. [profile.dev] diff --git a/crates/bevy_motiongfx/Cargo.toml b/crates/bevy_motiongfx/Cargo.toml index 1abe34f4..46217eb8 100644 --- a/crates/bevy_motiongfx/Cargo.toml +++ b/crates/bevy_motiongfx/Cargo.toml @@ -24,8 +24,6 @@ bevy_time = { workspace = true } bevy_asset = { workspace = true, optional = true } bevy_transform = { workspace = true, optional = true } bevy_color = { workspace = true, optional = true } -bevy_sprite = { workspace = true, optional = true } -bevy_pbr = { workspace = true, optional = true } [dev-dependencies] bevy = { workspace = true, features = ["bevy_pbr"] } @@ -34,9 +32,8 @@ bevy = { workspace = true, features = ["bevy_pbr"] } workspace = true [features] -default = ["asset", "transform", "color", "sprite", "pbr"] +default = ["std", "asset", "transform", "color"] +std = ["motiongfx/std", "bevy_ecs/std", "bevy_app/std", "bevy_platform/std", "bevy_time/std"] asset = ["dep:bevy_asset"] transform = ["dep:bevy_transform"] color = ["dep:bevy_color"] -sprite = ["dep:bevy_sprite", "asset"] -pbr = ["dep:bevy_pbr", "asset"] diff --git a/crates/bevy_motiongfx/README.md b/crates/bevy_motiongfx/README.md index 08362a60..56a373c7 100644 --- a/crates/bevy_motiongfx/README.md +++ b/crates/bevy_motiongfx/README.md @@ -50,7 +50,7 @@ fn build_timeline( // Build the timeline. let mut b = motiongfx.create_builder(); let track = b - .act_interp(entity, path!(::translation::x), |x| { + .act(entity, path!(::translation::x), |x| { x + 6.0 }) .play(1.0) @@ -84,7 +84,7 @@ fn build_timeline( // Build the timeline. let mut b = motiongfx.create_builder(); let track = b - .act_interp( + .act( // AssetIds must be type-erased. material.untyped().id(), path!(::base_color), diff --git a/crates/bevy_motiongfx/src/interpolation.rs b/crates/bevy_motiongfx/src/interpolation.rs index c94cd92d..9229c2f3 100644 --- a/crates/bevy_motiongfx/src/interpolation.rs +++ b/crates/bevy_motiongfx/src/interpolation.rs @@ -1,64 +1,17 @@ use bevy_math::*; +use motiongfx::impl_float_interpolation; use motiongfx::prelude::*; -use motiongfx::subject::SubjectId; -pub trait ActionInterpTimelineExt { - fn act_interp( - &mut self, - target: I, - field_acc: FieldAccessor, - action: impl Action, - ) -> InterpActionBuilder<'_, T> - where - W: SubjectSource, - I: SubjectId, - S: 'static, - T: Interpolation + Clone + ThreadSafe; -} - -impl ActionInterpTimelineExt - for TimelineBuilder<'_, W> -{ - /// Add an [`Action`] with interpolation using - /// [`Interpolation::interp`]. - fn act_interp( - &mut self, - target: I, - field_acc: FieldAccessor, - action: impl Action, - ) -> InterpActionBuilder<'_, T> - where - W: SubjectSource, - I: SubjectId, - S: 'static, - T: Interpolation + Clone + ThreadSafe, - { - self.act(target, field_acc, action).with_interp(T::interp) - } -} - -/// Trait for interpolating between 2 values based on a f32 `t` value. -pub trait Interpolation { - /// Linearly interpolate between 2 values based on a f32 `t` value. - fn interp(a: &Self, b: &T, t: f32) -> U; -} - -#[macro_export] -macro_rules! impl_float_interpolation { - ($ty:ty, $base:ty) => { - impl $crate::interpolation::Interpolation for $ty { - #[inline] - fn interp(a: &Self, b: &Self, t: f32) -> Self { - let t = <$base>::from(t); - (*a) * (1.0 - t) + (*b) * t - } - } - }; -} +#[derive(Debug)] +pub struct Bevy; macro_rules! impl_slerp_interpolation { ($ty: ty, $base: ty) => { - impl $crate::interpolation::Interpolation for $ty { + impl + ::motiongfx::interpolation::Interpolation< + $crate::interpolation::Bevy, + > for $ty + { #[inline] fn interp(a: &Self, b: &Self, t: f32) -> Self { let t = <$base>::from(t); @@ -68,16 +21,14 @@ macro_rules! impl_slerp_interpolation { }; } -impl_float_interpolation!(f32, f32); -impl_float_interpolation!(Vec2, f32); -impl_float_interpolation!(Vec3, f32); -impl_float_interpolation!(Vec3A, f32); -impl_float_interpolation!(Vec4, f32); +impl_float_interpolation!(Vec2, f32, Bevy); +impl_float_interpolation!(Vec3, f32, Bevy); +impl_float_interpolation!(Vec3A, f32, Bevy); +impl_float_interpolation!(Vec4, f32, Bevy); -impl_float_interpolation!(f64, f64); -impl_float_interpolation!(DVec2, f64); -impl_float_interpolation!(DVec3, f64); -impl_float_interpolation!(DVec4, f64); +impl_float_interpolation!(DVec2, f64, Bevy); +impl_float_interpolation!(DVec3, f64, Bevy); +impl_float_interpolation!(DVec4, f64, Bevy); impl_slerp_interpolation!(Quat, f32); impl_slerp_interpolation!(DQuat, f64); @@ -86,7 +37,7 @@ impl_slerp_interpolation!(Dir2, f32); impl_slerp_interpolation!(Dir3, f32); impl_slerp_interpolation!(Dir3A, f32); -impl Interpolation for u8 { +impl Interpolation for u8 { fn interp(a: &Self, b: &Self, t: f32) -> Self { let a = *a as f32; let b = *b as f32; @@ -99,11 +50,11 @@ impl Interpolation for u8 { pub mod color { use bevy_color::prelude::*; - use super::Interpolation; + use super::*; macro_rules! impl_color_interpolation { ($ty:ty) => { - impl $crate::interpolation::Interpolation for $ty { + impl Interpolation<$crate::interpolation::Bevy> for $ty { #[inline] fn interp(a: &Self, b: &Self, t: f32) -> Self { (*a) * (1.0 - t) + (*b) * t @@ -118,7 +69,7 @@ pub mod color { impl_color_interpolation!(Srgba); impl_color_interpolation!(Xyza); - impl Interpolation for Color { + impl Interpolation for Color { #[inline] fn interp(a: &Self, b: &Self, t: f32) -> Self { Color::mix(a, b, t) @@ -130,22 +81,24 @@ pub mod color { pub mod transform { use bevy_transform::components::Transform; - use super::Interpolation; + use super::*; - impl Interpolation for Transform { + impl Interpolation for Transform { fn interp(a: &Self, b: &Self, t: f32) -> Self { Self { - translation: Interpolation::interp( + translation: <_ as Interpolation>::interp( &a.translation, &b.translation, t, ), - rotation: Interpolation::interp( + rotation: <_ as Interpolation>::interp( &a.rotation, &b.rotation, t, ), - scale: Interpolation::interp(&a.scale, &b.scale, t), + scale: <_ as Interpolation>::interp( + &a.scale, &b.scale, t, + ), } } } diff --git a/crates/bevy_motiongfx/src/lib.rs b/crates/bevy_motiongfx/src/lib.rs index 7c210a90..388ec39f 100644 --- a/crates/bevy_motiongfx/src/lib.rs +++ b/crates/bevy_motiongfx/src/lib.rs @@ -16,9 +16,6 @@ pub mod prelude { pub use motiongfx::prelude::*; pub use crate::controller::{FixedRatePlayer, RealtimePlayer}; - pub use crate::interpolation::{ - ActionInterpTimelineExt, Interpolation, - }; pub use crate::manager::{MotionGfxManager, TimelineId}; pub use crate::world::{BevyTimeline, BevyTimelineBuilder}; } diff --git a/crates/bevy_motiongfx/src/manager.rs b/crates/bevy_motiongfx/src/manager.rs index aee0f022..a05f2f07 100644 --- a/crates/bevy_motiongfx/src/manager.rs +++ b/crates/bevy_motiongfx/src/manager.rs @@ -53,7 +53,7 @@ pub struct TimelineId(u64); #[derive(Component)] pub struct TimelineComplete; -#[allow(clippy::type_complexity)] +#[expect(clippy::type_complexity)] fn complete_timelines( mut commands: Commands, motiongfx: Res, diff --git a/crates/motiongfx/Cargo.toml b/crates/motiongfx/Cargo.toml index df37f75c..51cea185 100644 --- a/crates/motiongfx/Cargo.toml +++ b/crates/motiongfx/Cargo.toml @@ -22,3 +22,7 @@ nonempty = { workspace = true } [lints] workspace = true + +[features] +default = ["std"] +std = ["bevy_ecs/std", "bevy_platform/std", "bevy_math/std"] diff --git a/crates/motiongfx/README.md b/crates/motiongfx/README.md index e1a65d56..2af8b40e 100644 --- a/crates/motiongfx/README.md +++ b/crates/motiongfx/README.md @@ -56,11 +56,8 @@ let mut b = registry.create_builder::(); let id = 0; // Create an action with: id, field path, action fn. -let action = b - // Animate subject 0 from its current value to +10.0. - .act(id, path!(), |x| x + 10.0) - // Every action needs an interpolation function. - .with_interp(|a, b, t| a + (b - a) * t); +// Animate subject 0 from its current value to +10.0. +let action = b.act(id, path!(), |x| x + 10.0); // "Play" the action into a `TrackFragment` with a duration. let frag = action.play(1.0); @@ -164,8 +161,6 @@ let id = 0; // Act: animate subject 0 from its current value to +10.0. let action = b .act(id, path!(), |x| x + 10.0) - // Every action needs an interpolation function. - .with_interp(|a: &f32, b: &f32, t| a + (b - a) * t) // An optional easing function can be added. .with_ease(ease::cubic::ease_in_out); diff --git a/crates/motiongfx/docs/world.rs b/crates/motiongfx/docs/world.rs index 09558a57..e97fb0e0 100644 --- a/crates/motiongfx/docs/world.rs +++ b/crates/motiongfx/docs/world.rs @@ -20,7 +20,7 @@ pub fn timeline() -> (Registry, Timeline) { let mut registry = Registry::new(); let mut b = registry.create_builder::(); let track = b - .act(0usize, path!(), |x| x + 10.0) + .act_builder(0usize, path!(), |x| x + 10.0) .with_interp(|a: &f32, b: &f32, t| a + (b - a) * t) .play(1.0) .compile(); diff --git a/crates/motiongfx/examples/custom_world.rs b/crates/motiongfx/examples/custom_world.rs index 0ccf9079..fec2eb21 100644 --- a/crates/motiongfx/examples/custom_world.rs +++ b/crates/motiongfx/examples/custom_world.rs @@ -66,16 +66,18 @@ fn main() { // Create the track. let track = [ builder - .act(Id(0), path!(::x), |x| x + 72.0) + .act_builder(Id(0), path!(::x), |x| x + 72.0) .with_interp(linear_f32) .play(1.0), [ builder - .act(Id(1), path!(::p0::y), |y| y + 42.0) + .act_builder(Id(1), path!(::p0::y), |y| { + y + 42.0 + }) .with_interp(linear_f32) .play(2.0), builder - .act(Id(1), path!(::p1), |_| Point { + .act_builder(Id(1), path!(::p1), |_| Point { x: 6.0, y: 6.0, }) diff --git a/crates/motiongfx/src/interpolation.rs b/crates/motiongfx/src/interpolation.rs new file mode 100644 index 00000000..fcc88f71 --- /dev/null +++ b/crates/motiongfx/src/interpolation.rs @@ -0,0 +1,28 @@ +/// Trait for interpolating between two values. +/// +/// The `M` marker parameter exists solely to satisfy the orphan rule: +/// downstream crates can provide a local marker type to implement +/// this trait for foreign `Self` types. +pub trait Interpolation { + fn interp(a: &Self, b: &Self, t: f32) -> Self; +} + +#[macro_export] +macro_rules! impl_float_interpolation { + ($ty:ty, $base:ty) => { + $crate::impl_float_interpolation!($ty, $base, ()); + }; + + ($ty:ty, $base:ty, $marker:ty) => { + impl $crate::interpolation::Interpolation<$marker> for $ty { + #[inline] + fn interp(a: &Self, b: &Self, t: f32) -> Self { + let t = <$base>::from(t); + (*a) + (*b - *a) * t + } + } + }; +} + +impl_float_interpolation!(f32, f32); +impl_float_interpolation!(f64, f64); diff --git a/crates/motiongfx/src/lib.rs b/crates/motiongfx/src/lib.rs index f98d59de..56e19aa9 100644 --- a/crates/motiongfx/src/lib.rs +++ b/crates/motiongfx/src/lib.rs @@ -5,6 +5,7 @@ extern crate alloc; pub mod action; pub mod ease; +pub mod interpolation; pub mod pipeline; pub mod registry; pub mod sequence; @@ -25,6 +26,7 @@ pub mod prelude { InterpFn, }; pub use crate::ease; + pub use crate::interpolation::Interpolation; pub use crate::path; pub use crate::pipeline::PipelineKey; pub use crate::registry::{ diff --git a/crates/motiongfx/src/timeline.rs b/crates/motiongfx/src/timeline.rs index 643112f2..611d30e6 100644 --- a/crates/motiongfx/src/timeline.rs +++ b/crates/motiongfx/src/timeline.rs @@ -11,6 +11,7 @@ use crate::action::{ Action, ActionBuilder, ActionId, ActionKey, ActionWorld, InterpActionBuilder, SampleMode, }; +use crate::interpolation::Interpolation; use crate::pipeline::{BakeCtx, PipelineKey, Range, SampleCtx}; use crate::registry::Registry; use crate::subject::SubjectId; @@ -200,7 +201,7 @@ impl Timeline { }; // Skip if the the animation range does not // overlap with the span range. - if time_range.overlap(&clip_range) == false { + if !time_range.overlap(&clip_range) { continue; } @@ -431,31 +432,22 @@ impl<'a, W: 'static> TimelineBuilder<'a, W> { } } - /// Add an [`Action`] without interpolation. - pub fn act( + /// Add an [`Action`] with interpolation using + /// [`Interpolation::interp`]. + pub fn act( &mut self, target: I, field_acc: FieldAccessor, action: impl Action, - ) -> ActionBuilder<'_, T> + ) -> InterpActionBuilder<'_, T> where W: SubjectSource + 'static, I: SubjectId, S: 'static, - T: Clone + ThreadSafe, + T: Interpolation + Clone + ThreadSafe, { - let field = field_acc.field; - self.registry.register::(field_acc); - let key = PipelineKey::new::(); - - match self.pipeline_counts.get_mut(&key) { - Some(count) => *count += 1, - None => { - self.pipeline_counts.insert(key, 1); - } - } - - self.action_world.add(target, field, action) + self.act_builder(target, field_acc, action) + .with_interp(T::interp) } /// Add an [`Action`] using step interpolation. @@ -471,9 +463,39 @@ impl<'a, W: 'static> TimelineBuilder<'a, W> { S: 'static, T: Clone + ThreadSafe, { - self.act(target, field_acc, action).with_interp(|a, b, t| { - if t < 1.0 { a.clone() } else { b.clone() } - }) + self.act_builder(target, field_acc, action).with_interp( + |a, b, t| { + if t < 1.0 { a.clone() } else { b.clone() } + }, + ) + } + + /// Add an [`Action`] without interpolation, returning an + /// [`ActionBuilder`] for manual configuration. + pub fn act_builder( + &mut self, + target: I, + field_acc: FieldAccessor, + action: impl Action, + ) -> ActionBuilder<'_, T> + where + W: SubjectSource + 'static, + I: SubjectId, + S: 'static, + T: Clone + ThreadSafe, + { + let field = field_acc.field; + self.registry.register::(field_acc); + let key = PipelineKey::new::(); + + match self.pipeline_counts.get_mut(&key) { + Some(count) => *count += 1, + None => { + self.pipeline_counts.insert(key, 1); + } + } + + self.action_world.add(target, field, action) } /// Remove an [`Action`]. diff --git a/crates/peniko_motiongfx/Cargo.toml b/crates/peniko_motiongfx/Cargo.toml new file mode 100644 index 00000000..a89c81ee --- /dev/null +++ b/crates/peniko_motiongfx/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "peniko_motiongfx" +description = "Peniko 2d graphics support for the MotionGfx framework." +keywords = ["motion", "animation", "procedural", "kurbo"] +categories = ["no-std", "multimedia", "graphics", "visualization"] +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +motiongfx = { workspace = true } +peniko = { workspace = true } + +[lints] +workspace = true + +[features] +default = ["std"] +std = ["motiongfx/std", "peniko/std"] +libm = ["peniko/libm"] diff --git a/crates/peniko_motiongfx/src/interpolation.rs b/crates/peniko_motiongfx/src/interpolation.rs new file mode 100644 index 00000000..56bcaeed --- /dev/null +++ b/crates/peniko_motiongfx/src/interpolation.rs @@ -0,0 +1,146 @@ +use motiongfx::prelude::Interpolation; +use peniko::Color; +use peniko::kurbo::{ + Circle, CubicBez, Line, Point, QuadBez, Rect, RoundedRect, + RoundedRectRadii, Size, Vec2, +}; + +use crate::Peniko; + +/// Linearly interpolates between two `f64` values. +#[inline] +pub(crate) const fn lerp_f64(a: f64, b: f64, t: f32) -> f64 { + let t = t as f64; + a * (1.0 - t) + b * t +} + +/// Linearly interpolates between two [`Point`]s. +#[inline] +pub(crate) const fn interp_point( + a: &Point, + b: &Point, + t: f32, +) -> Point { + Point::new(lerp_f64(a.x, b.x, t), lerp_f64(a.y, b.y, t)) +} + +impl Interpolation for Point { + /// Linearly interpolates between two [`Point`]s. + #[inline] + fn interp(a: &Self, b: &Self, t: f32) -> Self { + interp_point(a, b, t) + } +} + +impl Interpolation for Vec2 { + /// Linearly interpolates between two [`Vec2`]s. + #[inline] + fn interp(a: &Self, b: &Self, t: f32) -> Self { + Vec2::new(lerp_f64(a.x, b.x, t), lerp_f64(a.y, b.y, t)) + } +} + +impl Interpolation for Size { + /// Linearly interpolates between two [`Size`]s. + #[inline] + fn interp(a: &Self, b: &Self, t: f32) -> Self { + Size::new( + lerp_f64(a.width, b.width, t), + lerp_f64(a.height, b.height, t), + ) + } +} + +impl Interpolation for Rect { + /// Linearly interpolates between two [`Rect`]s. + /// + /// Each corner coordinate is interpolated independently. + #[inline] + fn interp(a: &Self, b: &Self, t: f32) -> Self { + Rect { + x0: lerp_f64(a.x0, b.x0, t), + y0: lerp_f64(a.y0, b.y0, t), + x1: lerp_f64(a.x1, b.x1, t), + y1: lerp_f64(a.y1, b.y1, t), + } + } +} + +impl Interpolation for Circle { + /// Linearly interpolates between two [`Circle`]s. + /// + /// Both the center position and radius are interpolated. + #[inline] + fn interp(a: &Self, b: &Self, t: f32) -> Self { + Circle { + center: interp_point(&a.center, &b.center, t), + radius: lerp_f64(a.radius, b.radius, t), + } + } +} + +impl Interpolation for Line { + /// Linearly interpolates between two [`Line`]s. + #[inline] + fn interp(a: &Self, b: &Self, t: f32) -> Self { + Line { + p0: interp_point(&a.p0, &b.p0, t), + p1: interp_point(&a.p1, &b.p1, t), + } + } +} + +impl Interpolation for CubicBez { + /// Linearly interpolates between two [`CubicBez`] curves. + /// + /// Each of the four control points is interpolated independently. + #[inline] + fn interp(a: &Self, b: &Self, t: f32) -> Self { + CubicBez::new( + interp_point(&a.p0, &b.p0, t), + interp_point(&a.p1, &b.p1, t), + interp_point(&a.p2, &b.p2, t), + interp_point(&a.p3, &b.p3, t), + ) + } +} + +impl Interpolation for QuadBez { + /// Linearly interpolates between two [`QuadBez`] curves. + /// + /// Each of the three control points is interpolated independently. + #[inline] + fn interp(a: &Self, b: &Self, t: f32) -> Self { + QuadBez::new( + interp_point(&a.p0, &b.p0, t), + interp_point(&a.p1, &b.p1, t), + interp_point(&a.p2, &b.p2, t), + ) + } +} + +impl Interpolation for RoundedRect { + /// Linearly interpolates between two [`RoundedRect`]s. + /// + /// Both the bounding rect and each of the four corner radii are + /// interpolated independently. + #[inline] + fn interp(a: &Self, b: &Self, t: f32) -> Self { + let rect = Rect::interp(&a.rect(), &b.rect(), t); + let ra = a.radii(); + let rb = b.radii(); + let radii = RoundedRectRadii::new( + lerp_f64(ra.top_left, rb.top_left, t), + lerp_f64(ra.top_right, rb.top_right, t), + lerp_f64(ra.bottom_right, rb.bottom_right, t), + lerp_f64(ra.bottom_left, rb.bottom_left, t), + ); + RoundedRect::from_rect(rect, radii) + } +} + +impl Interpolation for Color { + fn interp(a: &Self, b: &Self, t: f32) -> Self { + a.lerp_rect(*b, t) + } +} diff --git a/crates/peniko_motiongfx/src/lib.rs b/crates/peniko_motiongfx/src/lib.rs new file mode 100644 index 00000000..a6dbea9a --- /dev/null +++ b/crates/peniko_motiongfx/src/lib.rs @@ -0,0 +1,22 @@ +#![no_std] + +pub mod interpolation; +pub mod trace; + +pub mod prelude { + pub use peniko; + pub use peniko::kurbo; + + pub use crate::Peniko; + pub use crate::trace::{ + CubicTracer, LineTracer, PathTracer, QuadTracer, Trace, + }; +} + +pub use motiongfx; +pub use peniko; + +/// Marker for [`Interpolation`] impls on [`peniko`] types. +/// +/// [`Interpolation`]: motiongfx::interpolation::Interpolation +pub struct Peniko; diff --git a/crates/peniko_motiongfx/src/trace.rs b/crates/peniko_motiongfx/src/trace.rs new file mode 100644 index 00000000..e3bb4245 --- /dev/null +++ b/crates/peniko_motiongfx/src/trace.rs @@ -0,0 +1,122 @@ +use peniko::kurbo::{BezPath, CubicBez, Line, ParamCurve, QuadBez}; + +pub type LineTracer = Tracer; +pub type QuadTracer = Tracer; +pub type CubicTracer = Tracer; +pub type PathTracer = Tracer; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Tracer { + /// The original full path. + pub path: T, + /// Normalized start of the visible range (0..1). + pub t_start: f32, + /// Normalized end of the visible range (0..1). + pub t_end: f32, +} + +impl Tracer { + pub fn trace(&self) -> T { + self.path.trace_range(self.t_start, self.t_end) + } +} + +pub trait Trace { + /// Returns the slice of `self` from `t_start` to `t_end` (both in 0..1). + fn trace_range(&self, t_start: f32, t_end: f32) -> Self; + + /// Returns the prefix of `self` from 0 to `t`. + fn trace(&self, t: f32) -> Self + where + Self: Sized, + { + self.trace_range(0.0, t) + } +} + +impl Trace for Line { + #[inline] + fn trace_range(&self, t_start: f32, t_end: f32) -> Self { + let t_start = t_start.clamp(0.0, 1.0) as f64; + let t_end = t_end.clamp(0.0, 1.0) as f64; + self.subsegment(t_start..t_end) + } +} + +impl Trace for QuadBez { + #[inline] + fn trace_range(&self, t_start: f32, t_end: f32) -> Self { + let t_start = t_start.clamp(0.0, 1.0) as f64; + let t_end = t_end.clamp(0.0, 1.0) as f64; + self.subsegment(t_start..t_end) + } +} + +impl Trace for CubicBez { + #[inline] + fn trace_range(&self, t_start: f32, t_end: f32) -> Self { + let t_start = t_start.clamp(0.0, 1.0) as f64; + let t_end = t_end.clamp(0.0, 1.0) as f64; + self.subsegment(t_start..t_end) + } +} + +impl Trace for BezPath { + #[inline] + fn trace_range(&self, t_start: f32, t_end: f32) -> Self { + trace_bez_path_range(self, t_start, t_end) + } +} + +fn trace_bez_path_range( + path: &BezPath, + t_start: f32, + t_end: f32, +) -> BezPath { + let t_start = t_start.clamp(0.0, 1.0) as f64; + let t_end = t_end.clamp(0.0, 1.0) as f64; + + if t_start >= t_end { + return BezPath::new(); + } + if t_start <= 0.0 && t_end >= 1.0 { + return path.clone(); + } + + let n = path.segments().count(); + if n == 0 { + return BezPath::new(); + } + + let start_scaled = t_start * n as f64; + let end_scaled = t_end * n as f64; + let start_seg = start_scaled.floor() as usize; + let start_frac = start_scaled - start_seg as f64; + let end_seg = end_scaled.floor() as usize; + let end_frac = end_scaled - end_seg as f64; + + let mut result = BezPath::new(); + for (i, seg) in path.segments().enumerate() { + if i < start_seg { + continue; + } + if i > end_seg { + break; + } + let lo = if i == start_seg { start_frac } else { 0.0 }; + let hi = if i == end_seg { + if end_frac == 0.0 { + break; + } + end_frac + } else { + 1.0 + }; + let sub = seg.subsegment(lo..hi); + if result.is_empty() { + result.move_to(sub.start()); + } + result.push(sub.as_path_el()); + } + result +} diff --git a/examples/bevy_examples/Cargo.toml b/examples/bevy_examples/Cargo.toml index a843bff3..7d05f631 100644 --- a/examples/bevy_examples/Cargo.toml +++ b/examples/bevy_examples/Cargo.toml @@ -9,9 +9,6 @@ publish = false [dependencies] bevy_motiongfx = { workspace = true } -bevy = { workspace = true } - -[dev-dependencies] bevy = { workspace = true, default-features = true } [lints] diff --git a/examples/bevy_examples/examples/custom_ease.rs b/examples/bevy_examples/examples/custom_ease.rs index 1bb9468a..3d2c97bb 100644 --- a/examples/bevy_examples/examples/custom_ease.rs +++ b/examples/bevy_examples/examples/custom_ease.rs @@ -35,11 +35,9 @@ fn spawn_timeline( let mut b = motiongfx.create_builder(); let track = b - .act_interp( - cube_id, - path!(::translation::x), - |x| x + 10.0, - ) + .act(cube_id, path!(::translation::x), |x| { + x + 10.0 + }) // A custom 10 step easing. .with_ease(|t| ((t * 10.0) as u32) as f32 / 10.0) .play(1.0) diff --git a/examples/bevy_examples/examples/custom_interp.rs b/examples/bevy_examples/examples/custom_interp.rs index 60b975eb..57bddcaf 100644 --- a/examples/bevy_examples/examples/custom_interp.rs +++ b/examples/bevy_examples/examples/custom_interp.rs @@ -37,7 +37,7 @@ fn spawn_timeline( let mut b = motiongfx.create_builder(); let track = b - .act(cube_id, path!(::translation), |x| { + .act_builder(cube_id, path!(::translation), |x| { x + Vec3::ZERO.with_x(10.0).with_z(1.0) }) .with_interp(|start, end, t| arc_lerp_3d(*start, *end, t)) diff --git a/examples/bevy_examples/examples/easings.rs b/examples/bevy_examples/examples/easings.rs index 177a6eb2..c4dfd140 100644 --- a/examples/bevy_examples/examples/easings.rs +++ b/examples/bevy_examples/examples/easings.rs @@ -79,14 +79,14 @@ fn spawn_timeline( .enumerate() .map(|(i, ease_fn)| { [ - b.act_interp( + b.act( sphere_ids[i], path!(::translation::x), |x| x + 10.0, ) .with_ease(ease_fn) .play(1.0), - b.act_interp( + b.act( sphere_mat_ids[i], path!(::emissive), move |_| red, diff --git a/examples/bevy_examples/examples/hello_world.rs b/examples/bevy_examples/examples/hello_world.rs index 90001eae..3d8dd622 100644 --- a/examples/bevy_examples/examples/hello_world.rs +++ b/examples/bevy_examples/examples/hello_world.rs @@ -63,32 +63,26 @@ fn spawn_timeline( let circ_ease = ease::circ::ease_in_out; let track = [ - b.act_interp( - cube_id, - path!(::scale), - |_| Vec3::splat(0.9), - ) + b.act(cube_id, path!(::scale), |_| { + Vec3::splat(0.9) + }) .with_ease(circ_ease) .play(1.0), - b.act_interp( + b.act( cube_id, path!(::translation::x), |x| x + 1.0, ) .with_ease(circ_ease) .play(1.0), - b.act_interp( - cube_id, - path!(::rotation), - |_| { - Quat::from_euler( - EulerRot::XYZ, - 0.0, - f32::to_radians(90.0), - 0.0, - ) - }, - ) + b.act(cube_id, path!(::rotation), |_| { + Quat::from_euler( + EulerRot::XYZ, + 0.0, + f32::to_radians(90.0), + 0.0, + ) + }) .with_ease(circ_ease) .play(1.0), ] diff --git a/examples/bevy_examples/examples/minimal.rs b/examples/bevy_examples/examples/minimal.rs index 7b36056f..e0ccb2e7 100644 --- a/examples/bevy_examples/examples/minimal.rs +++ b/examples/bevy_examples/examples/minimal.rs @@ -51,13 +51,11 @@ fn build_timeline( // Build the timeline. let mut b = motiongfx.create_builder(); let track = [ - b.act_interp( - cube_id, - path!(::translation::x), - |x| x + 6.0, - ) + b.act(cube_id, path!(::translation::x), |x| { + x + 6.0 + }) .play(1.0), - b.act_interp( + b.act( cube_mat_id, path!(::base_color), |_| Srgba::RED.into(), diff --git a/examples/bevy_examples/examples/recording.rs b/examples/bevy_examples/examples/recording.rs index b767b439..d3c7e77e 100644 --- a/examples/bevy_examples/examples/recording.rs +++ b/examples/bevy_examples/examples/recording.rs @@ -108,7 +108,7 @@ fn spawn_timeline( let mut b = motiongfx.create_builder(); let track = b - .act(cube_id, path!(::translation), |x| { + .act_builder(cube_id, path!(::translation), |x| { x + Vec3::ZERO.with_x(10.0).with_z(1.0) }) .with_interp(|start, end, t| arc_lerp_3d(*start, *end, t)) diff --git a/examples/bevy_examples/examples/slide_basic.rs b/examples/bevy_examples/examples/slide_basic.rs index b81c514e..18108a60 100644 --- a/examples/bevy_examples/examples/slide_basic.rs +++ b/examples/bevy_examples/examples/slide_basic.rs @@ -51,21 +51,21 @@ fn spawn_timeline( // Generate slide sequences. let slide0 = b - .act_interp(cube, path!(::scale), |_| Vec3::ONE) + .act(cube, path!(::scale), |_| Vec3::ONE) .with_ease(ease::cubic::ease_out) .play(1.0) .compile(); let slide1 = [ [ - b.act_interp( + b.act( cube, path!(::translation::x), move |_| -X_OFFSET, ) .with_ease(ease::cubic::ease_out) .play(1.0), - b.act_interp( + b.act( cube_mat_id, path!(::base_color), move |_| palettes::tailwind::ZINC_700.into(), @@ -74,11 +74,9 @@ fn spawn_timeline( .play(1.0), ] .ord_all(), - b.act_interp(sphere, path!(::scale), |_| { - Vec3::ONE - }) - .with_ease(ease::cubic::ease_out) - .play(1.0), + b.act(sphere, path!(::scale), |_| Vec3::ONE) + .with_ease(ease::cubic::ease_out) + .play(1.0), ] .ord_flow(0.1) .compile(); diff --git a/examples/vello_winit_example/Cargo.toml b/examples/vello_winit_example/Cargo.toml new file mode 100644 index 00000000..bdc438b0 --- /dev/null +++ b/examples/vello_winit_example/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "vello_winit_example" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +publish = false + +[dependencies] +motiongfx = { workspace = true } +peniko_motiongfx = { workspace = true } +vello = { workspace = true } +winit = { workspace = true } +pollster = { workspace = true } diff --git a/examples/vello_winit_example/examples/lissajous.rs b/examples/vello_winit_example/examples/lissajous.rs new file mode 100644 index 00000000..11173e12 --- /dev/null +++ b/examples/vello_winit_example/examples/lissajous.rs @@ -0,0 +1,426 @@ +use core::f64; +use std::time::Instant; + +use kurbo::{Affine, BezPath, Vec2}; +use motiongfx::prelude::*; +use peniko::{Color, Fill}; +use peniko_motiongfx::prelude::*; +use vello::peniko::color::palette::css; +use vello_winit_example::{VelloDemo, VelloWinitApp}; +use winit::event_loop::EventLoop; + +const N_X: usize = 12; +const N_Y: usize = 6; +const CELL_W: f64 = 110.0; +const CELL_H: f64 = 113.0; +const CURVE_R: f64 = 42.0; +const REF_R: f64 = 36.0; +const DELTA: f64 = f64::consts::PI / 4.0; +const DRAW_DUR: f32 = 1.5; +const HOLD_DUR: f32 = 0.8; +const STAGGER: f32 = 0.08; // per diagonal + +fn curve_color(c: usize) -> Color { + let t = (c - 1) as f64 / (N_X - 1) as f64; + Color::from_rgba8(220, (t * 130.0) as u8, 0, 255) +} + +fn lissajous_pt( + a: f64, + b: f64, + t: f64, + cx: f64, + cy: f64, +) -> (f64, f64) { + ( + cx + CURVE_R * (a * t + DELTA).sin(), + cy + CURVE_R * (b * t).sin(), + ) +} + +struct GridLine { + line: kurbo::Line, + width: f64, + color: Color, +} + +struct CurveState { + tracer: PathTracer, +} + +struct TableWorld { + grid_lines: Vec, + curves: Vec, +} + +impl SubjectSource for TableWorld { + fn get_source(&self, id: usize) -> Option<&GridLine> { + self.grid_lines.get(id) + } + + fn apply_source( + &mut self, + id: usize, + f: impl FnOnce(&mut GridLine) -> R, + ) -> Option { + self.grid_lines.get_mut(id).map(f) + } +} + +impl SubjectSource for TableWorld { + fn get_source(&self, id: usize) -> Option<&CurveState> { + self.curves.get(id) + } + + fn apply_source( + &mut self, + id: usize, + f: impl FnOnce(&mut CurveState) -> R, + ) -> Option { + self.curves.get_mut(id).map(f) + } +} + +fn curve_id(c: usize, r: usize) -> usize { + (r - 1) * N_X + (c - 1) +} + +struct LissajousTableDemo { + registry: Registry, + world: TableWorld, + start: Instant, + timeline: Timeline, + grid_duration: f32, + curve_duration: f32, + window_size: kurbo::Size, +} + +impl LissajousTableDemo { + pub fn new() -> Self { + let table_w = (N_X + 1) as f64 * CELL_W; + let table_h = (N_Y + 1) as f64 * CELL_H; + + let mut registry = Registry::new(); + let mut world = TableWorld { + grid_lines: Vec::new(), + curves: (0..N_X * N_Y) + .map(|id| { + let c = id % N_X + 1; + let r = id / N_X + 1; + let a = c as f64; + let b = r as f64; + let cx = c as f64 * CELL_W + CELL_W / 2.0; + let cy = r as f64 * CELL_H + CELL_H / 2.0; + let samples = a.max(b) as usize * 80 + 2; + let mut path = BezPath::new(); + let (px, py) = lissajous_pt(a, b, 0.0, cx, cy); + path.move_to((px, py)); + for i in 1..=samples { + let t = i as f64 / samples as f64 + * f64::consts::TAU; + let (px, py) = lissajous_pt(a, b, t, cx, cy); + path.line_to((px, py)); + } + CurveState { + tracer: PathTracer { + path, + t_start: 0.0, + t_end: 0.0, + }, + } + }) + .collect(), + }; + + // Grid lines: p1 starts at p0 (zero length) so they draw in. + let grid_col = Color::from_rgba8(105, 105, 140, 255); + let mut vert_entries: Vec<(usize, kurbo::Point)> = Vec::new(); + let mut horiz_entries: Vec<(usize, kurbo::Point)> = + Vec::new(); + for c in 0..=(N_X + 1) { + let x = c as f64 * CELL_W; + let p0 = kurbo::Point::new(x, 0.0); + let id = world.grid_lines.len(); + world.grid_lines.push(GridLine { + line: kurbo::Line::new(p0, p0), + width: 0.5, + color: grid_col, + }); + vert_entries.push((id, kurbo::Point::new(x, table_h))); + } + for r in 0..=(N_Y + 1) { + let y = r as f64 * CELL_H; + let p0 = kurbo::Point::new(0.0, y); + let id = world.grid_lines.len(); + world.grid_lines.push(GridLine { + line: kurbo::Line::new(p0, p0), + width: 0.5, + color: grid_col, + }); + horiz_entries.push((id, kurbo::Point::new(table_w, y))); + } + + let mut b = registry.create_builder::(); + + // Track 0: one column + one row draw in simultaneously per step. + let n_steps = vert_entries.len().max(horiz_entries.len()); + let mut pair_tracks = Vec::with_capacity(n_steps); + for i in 0..n_steps { + let v = vert_entries.get(i).map(|&(id, p1)| { + b.act(id, path!(::line::p1), move |_| p1) + .with_ease(ease::cubic::ease_in_out) + .play(0.6) + }); + let h = horiz_entries.get(i).map(|&(id, p1)| { + b.act(id, path!(::line::p1), move |_| p1) + .with_ease(ease::cubic::ease_in_out) + .play(0.6) + }); + pair_tracks.push(match (v, h) { + (Some(v), Some(h)) => [v, h].ord_flow(0.025), + (Some(v), None) => v, + (None, Some(h)) => h, + (None, None) => unreachable!(), + }); + } + let grid_track = + pair_tracks.into_iter().ord_flow(0.05).compile(); + b.add_tracks(grid_track); + + // Track 1: curves draw in and out, looped by the caller. + let max_diag = N_X + N_Y; + let curve_track = (2..=max_diag) + .map(|d| { + (1..=N_X) + .filter_map(|c| { + let r = d.checked_sub(c)?; + if !(1..=N_Y).contains(&r) { + return None; + } + let id = curve_id(c, r); + let draw_in = b + .act( + id, + path!(::tracer::t_end), + |_| 1.0f32, + ) + .with_ease(ease::cubic::ease_in_out) + .play(DRAW_DUR); + let draw_out = b + .act( + id, + path!(::tracer::t_start), + |_| 1.0f32, + ) + .with_ease(ease::cubic::ease_in_out) + .play(DRAW_DUR); + Some( + [draw_in, draw_out] + .ord_flow(DRAW_DUR + HOLD_DUR), + ) + }) + .ord_all() + }) + .ord_flow(STAGGER) + .compile(); + b.add_tracks(curve_track); + + let mut timeline = b.compile(); + timeline.bake_actions(®istry, &world); + let grid_duration = timeline.tracks()[0].duration(); + let curve_duration = timeline.tracks()[1].duration(); + + Self { + registry, + world, + start: Instant::now(), + timeline, + grid_duration, + curve_duration, + window_size: kurbo::Size::new( + (N_X + 1) as f64 * CELL_W, + (N_Y + 1) as f64 * CELL_H, + ), + } + } +} + +impl VelloDemo for LissajousTableDemo { + fn window_title(&self) -> &'static str { + "Lissajous Table" + } + + fn initial_logical_size(&self) -> (f64, f64) { + ((N_X + 1) as f64 * CELL_W, (N_Y + 1) as f64 * CELL_H) + } + + fn size_changed(&mut self, size: kurbo::Size) { + self.window_size = size; + } + + fn rebuild_scene( + &mut self, + scene: &mut vello::Scene, + scale_factor: f64, + ) { + let elapsed = self.start.elapsed().as_secs_f32(); + + // Track 0 plays once; once done we lock to track 1 and loop it. + if elapsed < self.grid_duration { + self.timeline.set_target_track(0); + self.timeline.set_target_time(elapsed); + } else { + self.timeline.set_target_track(1); + self.timeline.set_target_time( + (elapsed - self.grid_duration) % self.curve_duration, + ); + } + self.timeline.queue_actions(); + self.timeline + .sample_queued_actions(&self.registry, &mut self.world); + + // Centre the table in the window. + let table_w = (N_X + 1) as f64 * CELL_W; + let table_h = (N_Y + 1) as f64 * CELL_H; + let ox = (self.window_size.width - table_w).max(0.0) / 2.0; + let oy = (self.window_size.height - table_h).max(0.0) / 2.0; + let xf = Affine::scale(scale_factor) + .pre_translate(Vec2::new(ox, oy)); + + // Grid lines + for line in &self.world.grid_lines { + scene.stroke( + &kurbo::Stroke::new(line.width), + xf, + line.color, + None, + &line.line, + ); + } + + // Reference circles: dot tracks the curve tip of row 1 / col 1. + let xhair_col = Color::from_rgba8(90, 90, 110, 255); + let xhair_st = kurbo::Stroke::new(0.5); + let ref_st = kurbo::Stroke::new(1.0); + + for c in 1..=N_X { + let a = c as f64; + let cx = c as f64 * CELL_W + CELL_W / 2.0; + let cy = CELL_H / 2.0; + scene.stroke( + &ref_st, + xf, + css::GAINSBORO, + None, + &kurbo::Circle::new((cx, cy), REF_R), + ); + scene.stroke( + &xhair_st, + xf, + xhair_col, + None, + &kurbo::Line::new((cx, cy - REF_R), (cx, cy + REF_R)), + ); + scene.stroke( + &xhair_st, + xf, + xhair_col, + None, + &kurbo::Line::new((cx - REF_R, cy), (cx + REF_R, cy)), + ); + // x-component of curve tip: sin(a * t_end + DELTA) + let t_end = self.world.curves[curve_id(c, 1)].tracer.t_end + as f64 + * f64::consts::TAU; + let angle = a * t_end + DELTA - f64::consts::FRAC_PI_2; + scene.fill( + Fill::NonZero, + xf, + css::WHITE, + None, + &kurbo::Circle::new( + ( + cx + REF_R * angle.cos(), + cy + REF_R * angle.sin(), + ), + 3.5, + ), + ); + } + + for r in 1..=N_Y { + let b = r as f64; + let cx = CELL_W / 2.0; + let cy = r as f64 * CELL_H + CELL_H / 2.0; + scene.stroke( + &ref_st, + xf, + css::GAINSBORO, + None, + &kurbo::Circle::new((cx, cy), REF_R), + ); + scene.stroke( + &xhair_st, + xf, + xhair_col, + None, + &kurbo::Line::new((cx, cy - REF_R), (cx, cy + REF_R)), + ); + scene.stroke( + &xhair_st, + xf, + xhair_col, + None, + &kurbo::Line::new((cx - REF_R, cy), (cx + REF_R, cy)), + ); + // y-component of curve tip: sin(b * t_end) + let t_end = self.world.curves[curve_id(1, r)].tracer.t_end + as f64 + * f64::consts::TAU; + let angle = b * t_end - f64::consts::FRAC_PI_2; + scene.fill( + Fill::NonZero, + xf, + css::WHITE, + None, + &kurbo::Circle::new( + ( + cx + REF_R * angle.cos(), + cy + REF_R * angle.sin(), + ), + 3.5, + ), + ); + } + + // Lissajous curves driven by timeline world state + for r in 1..=N_Y { + for c in 1..=N_X { + let id = curve_id(c, r); + let state = &self.world.curves[id]; + + const MIN_ARC: f32 = 0.01; + if state.tracer.t_end - state.tracer.t_start < MIN_ARC + || 1.0 - state.tracer.t_start < MIN_ARC + { + continue; + } + + let visible = state.tracer.trace(); + scene.stroke( + &kurbo::Stroke::new(2.0), + xf, + curve_color(c), + None, + &visible, + ); + } + } + } +} + +fn main() { + let event_loop = EventLoop::new().unwrap(); + let mut app = VelloWinitApp::new(LissajousTableDemo::new()); + event_loop.run_app(&mut app).unwrap(); +} diff --git a/examples/vello_winit_example/src/lib.rs b/examples/vello_winit_example/src/lib.rs new file mode 100644 index 00000000..940f91f2 --- /dev/null +++ b/examples/vello_winit_example/src/lib.rs @@ -0,0 +1,238 @@ +use std::num::NonZeroUsize; +use std::sync::Arc; +use vello::kurbo::Size; +use vello::peniko::Color; +use vello::util::{RenderContext, RenderSurface}; +use vello::wgpu; +use vello::{ + AaConfig, RenderParams, Renderer, RendererOptions, Scene, +}; +use winit::application::ApplicationHandler; +use winit::dpi::{LogicalSize, PhysicalSize}; +use winit::event::WindowEvent; +use winit::event_loop::ActiveEventLoop; +use winit::window::Window; + +pub trait VelloDemo { + fn window_title(&self) -> &'static str; + fn initial_logical_size(&self) -> (f64, f64); + fn size_changed(&mut self, size: Size); + fn rebuild_scene(&mut self, scene: &mut Scene, scale_factor: f64); +} + +pub struct VelloWinitApp<'s, D: VelloDemo> { + pub context: RenderContext, + pub renderer: Option, + pub state: RenderState<'s>, + pub scene: Scene, + pub demo: D, +} + +pub enum RenderState<'s> { + Suspended(Option>), + Active { + surface: Box>, + window: Arc, + }, +} + +impl<'s, D: VelloDemo> VelloWinitApp<'s, D> { + pub fn new(demo: D) -> Self { + Self { + context: RenderContext::new(), + renderer: None, + state: RenderState::Suspended(None), + scene: Scene::new(), + demo, + } + } + + fn render(&mut self) { + let (surface, window) = match &mut self.state { + RenderState::Active { surface, window } => { + (surface, window) + } + _ => return, + }; + + self.scene.reset(); + + let size = window.inner_size(); + let scale_factor = window.scale_factor(); + + if size.width == 0 || size.height == 0 { + return; + } + + if surface.config.width != size.width + || surface.config.height != size.height + { + self.context.resize_surface( + surface, + size.width, + size.height, + ); + } + + self.demo.rebuild_scene(&mut self.scene, scale_factor); + + let dev = &self.context.devices[surface.dev_id]; + let texture = match surface.surface.get_current_texture() { + Ok(t) => t, + Err( + wgpu::SurfaceError::Lost + | wgpu::SurfaceError::Outdated, + ) => { + self.context.resize_surface( + surface, + size.width, + size.height, + ); + return; + } + Err(wgpu::SurfaceError::Timeout) => return, + Err(wgpu::SurfaceError::OutOfMemory) => { + panic!("GPU out of memory") + } + Err(wgpu::SurfaceError::Other) => return, + }; + + self.renderer + .as_mut() + .unwrap() + .render_to_texture( + &dev.device, + &dev.queue, + &self.scene, + &surface.target_view, + &RenderParams { + base_color: Color::from_rgb8(28, 28, 46), + width: surface.config.width, + height: surface.config.height, + antialiasing_method: AaConfig::Area, + }, + ) + .unwrap(); + + let mut enc = dev.device.create_command_encoder( + &wgpu::CommandEncoderDescriptor { label: None }, + ); + + surface.blitter.copy( + &dev.device, + &mut enc, + &surface.target_view, + &texture + .texture + .create_view(&wgpu::TextureViewDescriptor::default()), + ); + + dev.queue.submit([enc.finish()]); + texture.present(); + } + + fn handle_resize( + &mut self, + scale_factor: f64, + size: PhysicalSize, + ) { + let logical_width = size.width as f64 / scale_factor; + let logical_height = size.height as f64 / scale_factor; + self.demo + .size_changed(Size::new(logical_width, logical_height)); + } +} + +impl ApplicationHandler for VelloWinitApp<'_, D> { + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + let RenderState::Suspended(cached_window) = &mut self.state + else { + return; + }; + + let window = cached_window.take().unwrap_or_else(|| { + let (w, h) = self.demo.initial_logical_size(); + let attr = Window::default_attributes() + .with_inner_size(LogicalSize::new(w, h)) + .with_title(self.demo.window_title()); + Arc::new(event_loop.create_window(attr).unwrap()) + }); + + self.handle_resize( + window.scale_factor(), + window.inner_size(), + ); + + let size = window.inner_size(); + let surface_future = self.context.create_surface( + window.clone(), + size.width, + size.height, + wgpu::PresentMode::AutoVsync, + ); + let surface = + pollster::block_on(surface_future).expect("surface"); + + let device_handle = &self.context.devices[surface.dev_id]; + surface + .surface + .configure(&device_handle.device, &surface.config); + + if self.renderer.is_none() { + self.renderer = Some( + Renderer::new( + &device_handle.device, + RendererOptions { + use_cpu: false, + antialiasing_support: + vello::AaSupport::area_only(), + num_init_threads: NonZeroUsize::new(1), + pipeline_cache: None, + }, + ) + .unwrap(), + ); + } + + self.state = RenderState::Active { + surface: Box::new(surface), + window, + }; + } + + fn suspended(&mut self, _el: &ActiveEventLoop) { + if let RenderState::Active { window, .. } = &self.state { + self.state = RenderState::Suspended(Some(window.clone())); + } + } + + fn window_event( + &mut self, + el: &ActiveEventLoop, + _id: winit::window::WindowId, + event: WindowEvent, + ) { + match event { + WindowEvent::CloseRequested => el.exit(), + WindowEvent::Resized(size) => { + let scale_factor = match &self.state { + RenderState::Active { window, .. } => { + window.scale_factor() + } + _ => return, + }; + self.handle_resize(scale_factor, size); + self.render(); + } + WindowEvent::RedrawRequested => { + self.render(); + if let RenderState::Active { window, .. } = + &self.state + { + window.request_redraw(); + } + } + _ => {} + } + } +}