From 75d7490c588028481fd4410544ef418e319ebf16 Mon Sep 17 00:00:00 2001 From: Moon Date: Sun, 5 Apr 2026 18:06:05 -0400 Subject: [PATCH 01/15] Adding mewnala install instructions --- README.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ae0fc95b..7af2d326 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,29 @@ libprocessing is an experimental native library with the goal of supporting the ## Getting started +### mewnala (the python library) + +Inside of our `processing_pyo3` crate we have created a python package that you can easily install with pip. +Again, we are still very nascent, but let us know what kinds of snags you may run into while getting this set up. +Try running the examples in the [processing_pyo3 examples directory](crates/processing_pyo3/examples). + +```bash +# have python3 installed on your system + +# create a sketch folder and go inside +mkdir my-sketch-folder && cd my-sketch-folder + +# create a virtual env +python -m venv .venv + +# activate virtual env +source .venv/bin/activate + +pip install mewnala + +python my_sketch.py +``` + ### Rust You'll need to install the Rust toolchain to work on this project. Most users will want to install Rust via [`rustup`](https://rustup.rs/), which helps manage Rust toolchain versions. @@ -49,4 +72,4 @@ just wasm-serve We want your help building this library! You can see a list of outstanding tasks in our [issues](https://github.com/processing/libprocessing). However, while we're still in the early phases, consider checking in with us first in the `#devs-chat` channel on [Discord](https://discord.gg/h99u95nU7q) to coordinate our efforts. -You can read our project design principles [here](./docs/principles.md). \ No newline at end of file +You can read our project design principles [here](./docs/principles.md). From 3046320aaa58c5d95ec7055d557312fa5fa3c078 Mon Sep 17 00:00:00 2001 From: charlotte Date: Mon, 6 Apr 2026 23:45:22 -0700 Subject: [PATCH 02/15] Upgrade Bevy. --- Cargo.lock | 1217 +++++++++++------ Cargo.toml | 2 +- crates/processing_render/src/gltf.rs | 14 +- .../processing_render/src/material/custom.rs | 5 +- 4 files changed, 798 insertions(+), 440 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5bfa7b06..54626b33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -142,6 +142,18 @@ dependencies = [ "libc", ] +[[package]] +name = "alsa" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c88dbbce13b232b26250e1e2e6ac18b6a891a646b8148285036ebce260ac5c3" +dependencies = [ + "alsa-sys", + "bitflags 2.11.0", + "cfg-if 1.0.4", + "libc", +] + [[package]] name = "alsa-sys" version = "0.3.1" @@ -154,23 +166,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", "cc", - "cesu8", - "jni", - "jni-sys", + "jni 0.22.4", "libc", "log", - "ndk 0.9.0", + "ndk", "ndk-context", - "ndk-sys 0.6.0+11769913", + "ndk-sys", "num_enum", - "thiserror 1.0.69", + "simd_cesu8", + "thiserror 2.0.18", ] [[package]] @@ -196,9 +207,9 @@ dependencies = [ [[package]] name = "annotate-snippets" -version = "0.12.13" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74fc7650eedcb2fee505aad48491529e408f0e854c2d9f63eb86c1361b9b3f93" +checksum = "92570a3f9c98e7e84df84b71d0965ac99b1871fcd75a3773a3bd1bad13f64cf7" dependencies = [ "anstyle", "memchr", @@ -507,7 +518,7 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bevy" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_internal", ] @@ -515,7 +526,7 @@ dependencies = [ [[package]] name = "bevy_a11y" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "accesskit", "bevy_app", @@ -527,7 +538,7 @@ dependencies = [ [[package]] name = "bevy_android" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "android-activity", ] @@ -535,7 +546,7 @@ dependencies = [ [[package]] name = "bevy_animation" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_animation_macros", "bevy_app", @@ -567,7 +578,7 @@ dependencies = [ [[package]] name = "bevy_animation_macros" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_macro_utils", "quote", @@ -577,7 +588,7 @@ dependencies = [ [[package]] name = "bevy_anti_alias" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -598,7 +609,7 @@ dependencies = [ [[package]] name = "bevy_app" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_derive", "bevy_ecs", @@ -620,7 +631,7 @@ dependencies = [ [[package]] name = "bevy_asset" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "async-broadcast", "async-channel", @@ -663,7 +674,7 @@ dependencies = [ [[package]] name = "bevy_asset_macros" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_macro_utils", "proc-macro2", @@ -674,7 +685,7 @@ dependencies = [ [[package]] name = "bevy_audio" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -682,8 +693,6 @@ dependencies = [ "bevy_math", "bevy_reflect", "bevy_transform", - "coreaudio-sys", - "cpal", "rodio", "tracing", ] @@ -691,7 +700,7 @@ dependencies = [ [[package]] name = "bevy_camera" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -716,7 +725,7 @@ dependencies = [ [[package]] name = "bevy_camera_controller" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_camera", @@ -732,7 +741,7 @@ dependencies = [ [[package]] name = "bevy_color" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_math", "bevy_reflect", @@ -747,7 +756,7 @@ dependencies = [ [[package]] name = "bevy_core_pipeline" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -775,7 +784,7 @@ dependencies = [ [[package]] name = "bevy_derive" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_macro_utils", "quote", @@ -785,7 +794,7 @@ dependencies = [ [[package]] name = "bevy_dev_tools" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -816,7 +825,7 @@ dependencies = [ [[package]] name = "bevy_diagnostic" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "atomic-waker", "bevy_app", @@ -833,7 +842,7 @@ dependencies = [ [[package]] name = "bevy_ecs" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "arrayvec", "bevy_ecs_macros", @@ -846,6 +855,7 @@ dependencies = [ "bumpalo", "concurrent-queue", "derive_more", + "downcast-rs 2.0.2", "fixedbitset", "indexmap", "log", @@ -860,7 +870,7 @@ dependencies = [ [[package]] name = "bevy_ecs_macros" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_macro_utils", "proc-macro2", @@ -871,7 +881,7 @@ dependencies = [ [[package]] name = "bevy_encase_derive" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_macro_utils", "encase_derive_impl", @@ -880,7 +890,7 @@ dependencies = [ [[package]] name = "bevy_feathers" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "accesskit", "bevy_a11y", @@ -897,6 +907,7 @@ dependencies = [ "bevy_platform", "bevy_reflect", "bevy_render", + "bevy_scene", "bevy_shader", "bevy_text", "bevy_ui", @@ -909,7 +920,7 @@ dependencies = [ [[package]] name = "bevy_gilrs" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_ecs", @@ -924,7 +935,7 @@ dependencies = [ [[package]] name = "bevy_gizmos" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -932,18 +943,21 @@ dependencies = [ "bevy_color", "bevy_ecs", "bevy_gizmos_macros", + "bevy_input", + "bevy_log", "bevy_math", "bevy_mesh", "bevy_reflect", "bevy_time", "bevy_transform", "bevy_utils", + "bevy_window", ] [[package]] name = "bevy_gizmos_macros" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_macro_utils", "quote", @@ -953,15 +967,18 @@ dependencies = [ [[package]] name = "bevy_gizmos_render" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", "bevy_camera", + "bevy_color", "bevy_core_pipeline", "bevy_ecs", "bevy_gizmos", "bevy_image", + "bevy_log", + "bevy_material", "bevy_math", "bevy_mesh", "bevy_pbr", @@ -978,7 +995,7 @@ dependencies = [ [[package]] name = "bevy_gltf" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "async-lock", "base64", @@ -995,12 +1012,12 @@ dependencies = [ "bevy_mesh", "bevy_platform", "bevy_reflect", - "bevy_scene", "bevy_tasks", "bevy_transform", + "bevy_world_serialization", "fixedbitset", "gltf", - "itertools 0.14.0", + "itertools", "percent-encoding", "serde", "serde_json", @@ -1013,7 +1030,7 @@ dependencies = [ [[package]] name = "bevy_image" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -1041,7 +1058,7 @@ dependencies = [ [[package]] name = "bevy_input" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_ecs", @@ -1057,7 +1074,7 @@ dependencies = [ [[package]] name = "bevy_input_focus" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_ecs", @@ -1073,7 +1090,7 @@ dependencies = [ [[package]] name = "bevy_internal" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_a11y", "bevy_android", @@ -1125,12 +1142,13 @@ dependencies = [ "bevy_utils", "bevy_window", "bevy_winit", + "bevy_world_serialization", ] [[package]] name = "bevy_light" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -1154,7 +1172,7 @@ dependencies = [ [[package]] name = "bevy_log" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "android_log-sys", "bevy_app", @@ -1171,18 +1189,18 @@ dependencies = [ [[package]] name = "bevy_macro_utils" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "proc-macro2", "quote", "syn", - "toml_edit 0.24.1+spec-1.1.0", + "toml_edit", ] [[package]] name = "bevy_material" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_asset", "bevy_derive", @@ -1204,7 +1222,7 @@ dependencies = [ [[package]] name = "bevy_material_macros" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_macro_utils", "quote", @@ -1214,14 +1232,14 @@ dependencies = [ [[package]] name = "bevy_math" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "approx", "arrayvec", "bevy_reflect", "derive_more", "glam", - "itertools 0.14.0", + "itertools", "libm", "rand 0.10.0", "rand_distr", @@ -1233,7 +1251,7 @@ dependencies = [ [[package]] name = "bevy_mesh" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -1282,7 +1300,7 @@ checksum = "bff34eb29ff4b8a8688bc7299f14fb6b597461ca80fec03ed7d22939ab33e48f" [[package]] name = "bevy_naga_reflect" version = "0.1.0" -source = "git+https://github.com/tychedelia/bevy_naga_reflect#98612a63a847401da144150d786e7455a32cd7e1" +source = "git+https://github.com/tychedelia/bevy_naga_reflect#bcede929195ed5ae67d398f26b0872e879a0aeb0" dependencies = [ "bevy", "naga", @@ -1291,7 +1309,7 @@ dependencies = [ [[package]] name = "bevy_pbr" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "arrayvec", "bevy_app", @@ -1327,12 +1345,13 @@ dependencies = [ "static_assertions", "thiserror 2.0.18", "tracing", + "wgpu-types", ] [[package]] name = "bevy_picking" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -1355,7 +1374,7 @@ dependencies = [ [[package]] name = "bevy_platform" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "critical-section", "foldhash 0.2.0", @@ -1376,7 +1395,7 @@ dependencies = [ [[package]] name = "bevy_post_process" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -1400,12 +1419,12 @@ dependencies = [ [[package]] name = "bevy_ptr" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" [[package]] name = "bevy_reflect" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "assert_type_match", "bevy_platform", @@ -1433,7 +1452,7 @@ dependencies = [ [[package]] name = "bevy_reflect_derive" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_macro_utils", "indexmap", @@ -1446,7 +1465,7 @@ dependencies = [ [[package]] name = "bevy_render" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "async-channel", "bevy_app", @@ -1480,7 +1499,7 @@ dependencies = [ "glam", "image", "indexmap", - "itertools 0.14.0", + "itertools", "js-sys", "naga", "nonmax", @@ -1499,7 +1518,7 @@ dependencies = [ [[package]] name = "bevy_render_macros" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_macro_utils", "proc-macro2", @@ -1510,28 +1529,37 @@ dependencies = [ [[package]] name = "bevy_scene" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", - "bevy_camera", "bevy_derive", "bevy_ecs", + "bevy_log", "bevy_platform", "bevy_reflect", - "bevy_transform", + "bevy_scene_macros", "bevy_utils", - "derive_more", - "ron", - "serde", "thiserror 2.0.18", - "uuid", + "tracing", + "variadics_please", +] + +[[package]] +name = "bevy_scene_macros" +version = "0.19.0-dev" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" +dependencies = [ + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "bevy_shader" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_asset", "bevy_platform", @@ -1543,13 +1571,14 @@ dependencies = [ "thiserror 2.0.18", "tracing", "wesl", + "wgpu-naga-bridge", "wgpu-types", ] [[package]] name = "bevy_sprite" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -1574,7 +1603,7 @@ dependencies = [ [[package]] name = "bevy_sprite_render" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -1606,7 +1635,7 @@ dependencies = [ [[package]] name = "bevy_state" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_ecs", @@ -1621,7 +1650,7 @@ dependencies = [ [[package]] name = "bevy_state_macros" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_macro_utils", "quote", @@ -1631,7 +1660,7 @@ dependencies = [ [[package]] name = "bevy_tasks" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "async-channel", "async-executor", @@ -1643,13 +1672,13 @@ dependencies = [ "derive_more", "futures-lite", "heapless", - "pin-project", + "web-task", ] [[package]] name = "bevy_text" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -1676,7 +1705,7 @@ dependencies = [ [[package]] name = "bevy_time" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_ecs", @@ -1690,7 +1719,7 @@ dependencies = [ [[package]] name = "bevy_transform" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_ecs", @@ -1707,7 +1736,7 @@ dependencies = [ [[package]] name = "bevy_ui" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "accesskit", "bevy_a11y", @@ -1727,11 +1756,14 @@ dependencies = [ "bevy_reflect", "bevy_sprite", "bevy_text", + "bevy_time", "bevy_transform", "bevy_utils", "bevy_window", "derive_more", + "parley", "smallvec", + "swash", "taffy", "thiserror 2.0.18", "tracing", @@ -1741,7 +1773,7 @@ dependencies = [ [[package]] name = "bevy_ui_render" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -1772,7 +1804,7 @@ dependencies = [ [[package]] name = "bevy_ui_widgets" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "accesskit", "bevy_a11y", @@ -1785,13 +1817,16 @@ dependencies = [ "bevy_math", "bevy_picking", "bevy_reflect", + "bevy_text", "bevy_ui", + "parley", + "smol_str", ] [[package]] name = "bevy_utils" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "async-channel", "bevy_platform", @@ -1802,7 +1837,7 @@ dependencies = [ [[package]] name = "bevy_window" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "bevy_app", "bevy_asset", @@ -1820,7 +1855,7 @@ dependencies = [ [[package]] name = "bevy_winit" version = "0.19.0-dev" -source = "git+https://github.com/bevyengine/bevy?branch=main#26ee545b87cdfa36aeb4ca83738240063e691a07" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" dependencies = [ "accesskit", "accesskit_winit", @@ -1850,6 +1885,27 @@ dependencies = [ "winit", ] +[[package]] +name = "bevy_world_serialization" +version = "0.19.0-dev" +source = "git+https://github.com/bevyengine/bevy?branch=main#104a8c35f8c4eee092be656cf62784d6eae0841d" +dependencies = [ + "bevy_app", + "bevy_asset", + "bevy_camera", + "bevy_derive", + "bevy_ecs", + "bevy_platform", + "bevy_reflect", + "bevy_transform", + "bevy_utils", + "derive_more", + "ron", + "serde", + "thiserror 2.0.18", + "uuid", +] + [[package]] name = "bindgen" version = "0.65.1" @@ -1867,37 +1923,28 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash 1.1.0", + "rustc-hash", "shlex", "syn", "which", ] [[package]] -name = "bindgen" -version = "0.72.1" +name = "bit-set" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "bitflags 2.11.0", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "proc-macro2", - "quote", - "regex", - "rustc-hash 2.1.1", - "shlex", - "syn", + "bit-vec 0.8.0", ] [[package]] name = "bit-set" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +checksum = "34ddef2995421ab6a5c779542c81ee77c115206f4ad9d5a8e05f4ff49716a3dd" dependencies = [ - "bit-vec", + "bit-vec 0.9.1", ] [[package]] @@ -1906,6 +1953,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" + [[package]] name = "bit_field" version = "0.10.3" @@ -1939,16 +1992,16 @@ dependencies = [ [[package]] name = "blake3" -version = "1.8.3" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" +checksum = "4d2d5991425dfd0785aed03aedcf0b321d61975c9b5b3689c774a2610ae0b51e" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if 1.0.4", "constant_time_eq", - "cpufeatures 0.2.17", + "cpufeatures 0.3.0", ] [[package]] @@ -2094,9 +2147,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.57" +version = "1.2.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" +checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" dependencies = [ "find-msvc-tools", "jobserver", @@ -2225,6 +2278,17 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "codespan-reporting" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681" +dependencies = [ + "serde", + "termcolor", + "unicode-width", +] + [[package]] name = "color_quant" version = "1.1.0" @@ -2422,7 +2486,7 @@ dependencies = [ "core-foundation-sys 0.7.0", "core-graphics 0.19.2", "libc", - "metal 0.18.0", + "metal", "objc", ] @@ -2446,22 +2510,16 @@ dependencies = [ [[package]] name = "coreaudio-rs" -version = "0.11.3" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" +checksum = "1aae284fbaf7d27aa0e292f7677dfbe26503b0d555026f702940805a630eac17" dependencies = [ "bitflags 1.3.2", - "core-foundation-sys 0.8.7", - "coreaudio-sys", -] - -[[package]] -name = "coreaudio-sys" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceec7a6067e62d6f931a2baf6f3a751f4a892595bcec1461a3c94ef9949864b6" -dependencies = [ - "bindgen 0.72.1", + "libc", + "objc2-audio-toolbox", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", ] [[package]] @@ -2487,25 +2545,32 @@ dependencies = [ [[package]] name = "cpal" -version = "0.15.3" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" +checksum = "5b1f9c7312f19fc2fa12fd7acaf38de54e8320ba10d1a02dcbe21038def51ccb" dependencies = [ - "alsa", - "core-foundation-sys 0.8.7", + "alsa 0.10.0", "coreaudio-rs", "dasp_sample", - "jni", + "jni 0.21.1", "js-sys", "libc", "mach2", - "ndk 0.8.0", + "ndk", "ndk-context", - "oboe", + "num-derive", + "num-traits", + "objc2 0.6.4", + "objc2-audio-toolbox", + "objc2-avf-audio", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", + "objc2-foundation 0.3.2", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows 0.54.0", + "windows 0.62.2", ] [[package]] @@ -2834,9 +2899,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", ] @@ -2879,9 +2944,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 = "fax" @@ -2981,24 +3046,23 @@ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "font-types" -version = "0.10.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39a654f404bbcbd48ea58c617c2993ee91d1cb63727a37bf2323a4edeed1b8c5" +checksum = "2d9237c6d82152100c691fb77ea18037b402bcc7257d2c876a4ffac81bc22a1c" dependencies = [ "bytemuck", ] [[package]] name = "fontique" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bbc252c93499b6d3635d692f892a637db0dbb130ce9b32bf20b28e0dcc470b" +checksum = "23358480a54a886d51b306718d5ca743fdfe238e5df38ef650f4e72f29c5d9e9" dependencies = [ - "bytemuck", "hashbrown 0.16.1", - "icu_locale_core", "linebender_resource_handle", "memmap2", + "parlance", "read-fonts", "smallvec", ] @@ -3292,9 +3356,9 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "glow" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" +checksum = "29038e1c483364cc6bb3cf78feee1816002e127c331a1eec55a4d202b9e1adb5" dependencies = [ "js-sys", "slotmap", @@ -3424,9 +3488,9 @@ dependencies = [ [[package]] name = "harfrust" -version = "0.3.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c020db12c71d8a12a3fe7607873cade3a01a6287e29d540c8723276221b9d8" +checksum = "9da2e5ae821f6e96664977bf974d6d6a2d6682f9ccee23e62ec1d134246845f9" dependencies = [ "bitflags 2.11.0", "bytemuck", @@ -3515,19 +3579,133 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5a396343c7208121dc86e35623d3dfe19814a7613cfd14964994cdc9c9a2e26" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_locale_data", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", +] + [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", "serde", "tinystr", "writeable", + "zerovec", +] + +[[package]] +name = "icu_locale_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fdcc9ac77c6d74ff5cf6e65ef3181d6af32003b16fce3a77fb451d2f695993" + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "serde", + "stable_deref_trait", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_segmenter" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c0794db0b1a86193ac9c48768d0e6c52c54448e0870ad87907d456ee0dac964" +dependencies = [ + "icu_collections", + "icu_locale", + "icu_provider", + "icu_segmenter_data", + "potential_utf", + "utf8_iter", + "zerovec", ] +[[package]] +name = "icu_segmenter_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a2c462a4d927d512f5f882a033ddd62f33a05bb9f230d98f736ac3dc85938f" + [[package]] name = "id-arena" version = "2.3.0" @@ -3576,9 +3754,9 @@ checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" [[package]] name = "indexmap" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" dependencies = [ "equivalent", "hashbrown 0.16.1", @@ -3625,9 +3803,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", ] @@ -3638,15 +3816,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.14.0" @@ -3658,9 +3827,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" @@ -3671,18 +3840,70 @@ dependencies = [ "cesu8", "cfg-if 1.0.4", "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 1.0.4", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link", +] + +[[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 = "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 = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] [[package]] name = "jobserver" @@ -3696,10 +3917,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.91" +version = "0.3.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" dependencies = [ + "cfg-if 1.0.4", + "futures-util", "once_cell", "wasm-bindgen", ] @@ -3766,9 +3989,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba4ebbd48ce411c1d10fb35185f5a51a7bfa3d8b24b4e330d30c9e3a34129501" dependencies = [ "ascii-canvas", - "bit-set", + "bit-set 0.8.0", "ena", - "itertools 0.14.0", + "itertools", "lalrpop-util", "petgraph 0.7.1", "regex", @@ -3893,9 +4116,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.183" +version = "0.2.184" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" [[package]] name = "libfuzzer-sys" @@ -3925,9 +4148,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" +checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" dependencies = [ "bitflags 2.11.0", "libc", @@ -3965,9 +4188,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "litrs" @@ -4074,9 +4297,9 @@ dependencies = [ [[package]] name = "lyon_tessellation" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05a35a7dd71b845ff317ce1834c4185506b79790294bde397df8d5c23031e357" +checksum = "8e43b7e44161571868f5c931d12583592c223c5583eef86b08aa02b7048a3552" dependencies = [ "float_next_after", "lyon_path", @@ -4085,9 +4308,9 @@ dependencies = [ [[package]] name = "mach2" -version = "0.4.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +checksum = "6a1b95cd5421ec55b445b5ae102f5ea0e768de1f82bd3001e11f426c269c3aea" dependencies = [ "libc", ] @@ -4150,28 +4373,13 @@ dependencies = [ "objc", ] -[[package]] -name = "metal" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7047791b5bc903b8cd963014b355f71dc9864a9a0b727057676c1dcae5cbc15" -dependencies = [ - "bitflags 2.11.0", - "block", - "core-graphics-types 0.2.0", - "foreign-types 0.5.0", - "log", - "objc", - "paste", -] - [[package]] name = "midir" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b73f8737248ad37b88291a2108d9df5f991dc8555103597d586b5a29d4d703c0" dependencies = [ - "alsa", + "alsa 0.9.1", "bitflags 1.3.2", "coremidi", "js-sys", @@ -4200,9 +4408,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", "log", @@ -4247,16 +4455,16 @@ dependencies = [ [[package]] name = "naga" -version = "28.0.0" +version = "29.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "618f667225063219ddfc61251087db8a9aec3c3f0950c916b614e403486f1135" +checksum = "aa2630921705b9b01dcdd0b6864b9562ca3c1951eecd0f0c4f5f04f61e412647" dependencies = [ "arrayvec", - "bit-set", + "bit-set 0.9.1", "bitflags 2.11.0", "cfg-if 1.0.4", "cfg_aliases", - "codespan-reporting", + "codespan-reporting 0.13.1", "half", "hashbrown 0.16.1", "hexf-parse", @@ -4266,7 +4474,7 @@ dependencies = [ "num-traits", "once_cell", "pp-rs", - "rustc-hash 1.1.0", + "rustc-hash", "serde", "spirv", "thiserror 2.0.18", @@ -4275,16 +4483,16 @@ dependencies = [ [[package]] name = "naga_oil" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f13ea787c55e7b2d1ab69b57847a8bfb19278da89dc5cd72701dced496314b" +checksum = "319f03062940ed85c03da020042618356bb8ca5263020322930883b05e30208e" dependencies = [ - "codespan-reporting", + "codespan-reporting 0.12.0", "data-encoding", "indexmap", "naga", "regex", - "rustc-hash 1.1.0", + "rustc-hash", "thiserror 2.0.18", "tracing", "unicode-ident", @@ -4323,20 +4531,6 @@ dependencies = [ "log", ] -[[package]] -name = "ndk" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" -dependencies = [ - "bitflags 2.11.0", - "jni-sys", - "log", - "ndk-sys 0.5.0+25.2.9519653", - "num_enum", - "thiserror 1.0.69", -] - [[package]] name = "ndk" version = "0.9.0" @@ -4344,9 +4538,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ "bitflags 2.11.0", - "jni-sys", + "jni-sys 0.3.1", "log", - "ndk-sys 0.6.0+11769913", + "ndk-sys", "num_enum", "raw-window-handle", "thiserror 1.0.69", @@ -4358,22 +4552,13 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" -[[package]] -name = "ndk-sys" -version = "0.5.0+25.2.9519653" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" -dependencies = [ - "jni-sys", -] - [[package]] name = "ndk-sys" version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ - "jni-sys", + "jni-sys 0.3.1", ] [[package]] @@ -4706,6 +4891,31 @@ dependencies = [ "objc2-quartz-core 0.3.2", ] +[[package]] +name = "objc2-audio-toolbox" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6948501a91121d6399b79abaa33a8aa4ea7857fe019f341b8c23ad6e81b79b08" +dependencies = [ + "bitflags 2.11.0", + "libc", + "objc2 0.6.4", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-avf-audio" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13a380031deed8e99db00065c45937da434ca987c034e13b87e4441f9e4090be" +dependencies = [ + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + [[package]] name = "objc2-cloud-kit" version = "0.2.2" @@ -4741,6 +4951,29 @@ dependencies = [ "objc2-foundation 0.2.2", ] +[[package]] +name = "objc2-core-audio" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1eebcea8b0dbff5f7c8504f3107c68fc061a3eb44932051c8cf8a68d969c3b2" +dependencies = [ + "dispatch2", + "objc2 0.6.4", + "objc2-core-audio-types", + "objc2-core-foundation", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-core-audio-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a89f2ec274a0cf4a32642b2991e8b351a404d290da87bb6a9a9d8632490bd1c" +dependencies = [ + "bitflags 2.11.0", + "objc2 0.6.4", +] + [[package]] name = "objc2-core-data" version = "0.2.2" @@ -4771,7 +5004,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ "bitflags 2.11.0", + "block2 0.6.2", "dispatch2", + "libc", "objc2 0.6.4", ] @@ -4797,7 +5032,7 @@ dependencies = [ "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", - "objc2-metal", + "objc2-metal 0.2.2", ] [[package]] @@ -4873,6 +5108,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.11.0", + "block2 0.6.2", + "libc", "objc2 0.6.4", "objc2-core-foundation", ] @@ -4923,6 +5160,18 @@ dependencies = [ "objc2-foundation 0.2.2", ] +[[package]] +name = "objc2-metal" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794" +dependencies = [ + "bitflags 2.11.0", + "block2 0.6.2", + "objc2 0.6.4", + "objc2-foundation 0.3.2", +] + [[package]] name = "objc2-quartz-core" version = "0.2.2" @@ -4933,7 +5182,7 @@ dependencies = [ "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", - "objc2-metal", + "objc2-metal 0.2.2", ] [[package]] @@ -4944,7 +5193,9 @@ checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ "bitflags 2.11.0", "objc2 0.6.4", + "objc2-core-foundation", "objc2-foundation 0.3.2", + "objc2-metal 0.3.2", ] [[package]] @@ -5011,29 +5262,6 @@ dependencies = [ "cc", ] -[[package]] -name = "oboe" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" -dependencies = [ - "jni", - "ndk 0.8.0", - "ndk-context", - "num-derive", - "num-traits", - "oboe-sys", -] - -[[package]] -name = "oboe-sys" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d" -dependencies = [ - "cc", -] - [[package]] name = "offset-allocator" version = "0.2.0" @@ -5077,9 +5305,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", ] @@ -5122,18 +5350,37 @@ dependencies = [ "windows-link", ] +[[package]] +name = "parlance" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6937eda350acc1a5d05872c3cbf99fe78619c269096e2be3d4a350058639d5" + [[package]] name = "parley" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ada5338c3a9794af7342e6f765b6e78740db37378aced034d7bf72c96b94ed94" +checksum = "d6c00ec192e1a402861526eff91a4b4690a2e5a17a4ae2deb772d72b49daf868" dependencies = [ "fontique", "harfrust", "hashbrown 0.16.1", + "icu_normalizer", + "icu_properties", + "icu_segmenter", "linebender_resource_handle", + "parlance", + "parley_data", "skrifa", - "swash", +] + +[[package]] +name = "parley_data" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "232313eddc02ac27f015e8f8eeb7facce8a896116df7e3eda1bfd9f600a9a39d" +dependencies = [ + "icu_properties", ] [[package]] @@ -5283,6 +5530,17 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "serde_core", + "writeable", + "zerovec", +] + [[package]] name = "pp-rs" version = "0.2.1" @@ -5329,7 +5587,7 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.25.5+spec-1.1.0", + "toml_edit", ] [[package]] @@ -5492,8 +5750,8 @@ checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" [[package]] name = "pyo3" -version = "0.28.2" -source = "git+https://github.com/PyO3/pyo3?branch=main#bd04fcd0c8decb1f7e6808a6659b508f04cf49cd" +version = "0.28.3" +source = "git+https://github.com/PyO3/pyo3?branch=main#df36c7165663ec70180d71495bd52031edd075d4" dependencies = [ "libc", "once_cell", @@ -5505,16 +5763,16 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.28.2" -source = "git+https://github.com/PyO3/pyo3?branch=main#bd04fcd0c8decb1f7e6808a6659b508f04cf49cd" +version = "0.28.3" +source = "git+https://github.com/PyO3/pyo3?branch=main#df36c7165663ec70180d71495bd52031edd075d4" dependencies = [ "target-lexicon", ] [[package]] name = "pyo3-ffi" -version = "0.28.2" -source = "git+https://github.com/PyO3/pyo3?branch=main#bd04fcd0c8decb1f7e6808a6659b508f04cf49cd" +version = "0.28.3" +source = "git+https://github.com/PyO3/pyo3?branch=main#df36c7165663ec70180d71495bd52031edd075d4" dependencies = [ "libc", "pyo3-build-config", @@ -5522,8 +5780,8 @@ dependencies = [ [[package]] name = "pyo3-introspection" -version = "0.28.2" -source = "git+https://github.com/PyO3/pyo3?branch=main#bd04fcd0c8decb1f7e6808a6659b508f04cf49cd" +version = "0.28.3" +source = "git+https://github.com/PyO3/pyo3?branch=main#df36c7165663ec70180d71495bd52031edd075d4" dependencies = [ "anyhow", "goblin", @@ -5533,8 +5791,8 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.28.2" -source = "git+https://github.com/PyO3/pyo3?branch=main#bd04fcd0c8decb1f7e6808a6659b508f04cf49cd" +version = "0.28.3" +source = "git+https://github.com/PyO3/pyo3?branch=main#df36c7165663ec70180d71495bd52031edd075d4" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -5544,8 +5802,8 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.28.2" -source = "git+https://github.com/PyO3/pyo3?branch=main#bd04fcd0c8decb1f7e6808a6659b508f04cf49cd" +version = "0.28.3" +source = "git+https://github.com/PyO3/pyo3?branch=main#df36c7165663ec70180d71495bd52031edd075d4" dependencies = [ "heck", "proc-macro2", @@ -5682,7 +5940,7 @@ dependencies = [ "built", "cfg-if 1.0.4", "interpolate_name", - "itertools 0.14.0", + "itertools", "libc", "libfuzzer-sys", "log", @@ -5722,6 +5980,18 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" +[[package]] +name = "raw-window-metal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135" +dependencies = [ + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", +] + [[package]] name = "rayon" version = "1.11.0" @@ -5744,9 +6014,9 @@ dependencies = [ [[package]] name = "read-fonts" -version = "0.35.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717cf23b488adf64b9d711329542ba34de147df262370221940dfabc2c91358" +checksum = "7b634fabf032fab15307ffd272149b622260f55974d9fad689292a5d33df02e5" dependencies = [ "bytemuck", "core_maths", @@ -5832,19 +6102,23 @@ dependencies = [ [[package]] name = "rodio" -version = "0.20.1" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ceb6607dd738c99bc8cb28eff249b7cd5c8ec88b9db96c0608c1480d140fb1" +checksum = "d0a536bb79db59098ef71a4dd4246c02eb87b316deceb1b68e0cde7167ec01eb" dependencies = [ "cpal", + "dasp_sample", "lewton", + "num-rational", + "thiserror 2.0.18", + "tracing", ] [[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", "once_cell", @@ -5860,12 +6134,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - [[package]] name = "rustc_version" version = "0.4.1" @@ -5972,9 +6240,9 @@ dependencies = [ [[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" @@ -6027,9 +6295,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ "serde_core", ] @@ -6061,9 +6329,19 @@ 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 = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "simd_cesu8" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] [[package]] name = "simd_helpers" @@ -6074,6 +6352,12 @@ dependencies = [ "quote", ] +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "siphasher" version = "1.0.2" @@ -6082,9 +6366,9 @@ checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "skrifa" -version = "0.37.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c31071dedf532758ecf3fed987cdb4bd9509f900e026ab684b4ecb81ea49841" +checksum = "7fbdfe3d2475fbd7ddd1f3e5cf8288a30eb3e5f95832829570cd88115a7434ac" dependencies = [ "bytemuck", "read-fonts", @@ -6165,9 +6449,9 @@ dependencies = [ [[package]] name = "spirv" -version = "0.3.0+sdk-1.3.268.0" +version = "0.4.0+sdk-1.4.341.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +checksum = "d9571ea910ebd84c86af4b3ed27f9dbdc6ad06f17c5f96146b2b671e2976744f" dependencies = [ "bitflags 2.11.0", ] @@ -6225,9 +6509,9 @@ 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", "yazi", @@ -6245,6 +6529,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sys-locale" version = "0.3.2" @@ -6270,9 +6565,9 @@ dependencies = [ [[package]] name = "taffy" -version = "0.9.2" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ba83ebaf2954d31d05d67340fd46cebe99da2b7133b0dd68d70c65473a437b" +checksum = "96fb9d22ffe63c7aa8996275aa0017404b513619bb6cf6309d9f822095afb414" dependencies = [ "arrayvec", "grid", @@ -6407,9 +6702,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "serde_core", @@ -6457,51 +6752,39 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "1.0.1+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b320e741db58cac564e26c607d3cc1fdc4a88fd36c879568c07856ed83ff3e9" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.24.1+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01f2eadbbc6b377a847be05f60791ef1058d9f696ecb51d2c07fe911d8569d8e" -dependencies = [ - "indexmap", - "toml_datetime 0.7.5+spec-1.1.0", - "toml_parser", - "winnow 0.7.15", -] - -[[package]] -name = "toml_edit" -version = "0.25.5+spec-1.1.0" +version = "0.25.10+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca1a40644a28bce036923f6a431df0b34236949d111cc07cb6dca830c9ef2e1" +checksum = "a82418ca169e235e6c399a84e395ab6debeb3bc90edc959bf0f48647c6a32d1b" dependencies = [ "indexmap", - "toml_datetime 1.0.1+spec-1.1.0", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", - "winnow 1.0.0", + "winnow 1.0.1", ] [[package]] name = "toml_parser" -version = "1.0.10+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7df25b4befd31c4816df190124375d5a20c6b6921e2cad937316de3fccd63420" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow 1.0.0", + "winnow 1.0.1", ] [[package]] name = "toml_writer" -version = "1.0.7+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17aaa1c6e3dc22b1da4b6bba97d066e354c7945cac2f7852d4e4e7ca7a6b56d" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" [[package]] name = "tracing" @@ -6613,9 +6896,9 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "typewit" -version = "1.14.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c1ae7cc0fdb8b842d65d127cb981574b0d2b249b74d1c7a2986863dc134f71" +checksum = "bc19094686c694eb41b3b99dcc2f2975d4b078512fa22ae6c63f7ca318bdcff7" [[package]] name = "unicode-ident" @@ -6625,9 +6908,9 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[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" @@ -6641,6 +6924,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -6649,9 +6938,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.22.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" +checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" dependencies = [ "getrandom 0.4.2", "js-sys", @@ -6676,7 +6965,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6779878362b9bacadc7893eac76abe69612e8837ef746573c4a5239daf11990b" dependencies = [ - "bindgen 0.65.1", + "bindgen", ] [[package]] @@ -6755,9 +7044,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.114" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" dependencies = [ "cfg-if 1.0.4", "once_cell", @@ -6768,23 +7057,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.64" +version = "0.4.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" +checksum = "03623de6905b7206edd0a75f69f747f134b7f0a2323392d664448bf2d3c5d87e" dependencies = [ - "cfg-if 1.0.4", - "futures-util", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.114" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6792,9 +7077,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.114" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" dependencies = [ "bumpalo", "proc-macro2", @@ -6805,9 +7090,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.114" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" dependencies = [ "unicode-ident", ] @@ -6848,9 +7133,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", @@ -6862,9 +7147,9 @@ 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", "rustix 1.1.4", @@ -6885,9 +7170,9 @@ dependencies = [ [[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", @@ -6896,9 +7181,9 @@ 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", "wayland-backend", @@ -6908,9 +7193,9 @@ 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", "wayland-backend", @@ -6921,9 +7206,9 @@ 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", "wayland-backend", @@ -6934,9 +7219,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", @@ -6945,12 +7230,13 @@ 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", ] @@ -6962,10 +7248,22 @@ checksum = "323f4da9523e9a669e1eaf9c6e763892769b1d38c623913647bfdc1532fe4549" [[package]] name = "web-sys" -version = "0.3.91" +version = "0.3.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-task" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +checksum = "1cdc136a53ccd64a1211f107ccc34404769fbcc0f165f1afa065f5d88ab93538" dependencies = [ + "async-task", + "cfg-if 1.0.4", "js-sys", "wasm-bindgen", ] @@ -6995,7 +7293,7 @@ dependencies = [ "annotate-snippets", "derive_more", "half", - "itertools 0.14.0", + "itertools", "num-traits", "proc-macro2", "quote", @@ -7011,7 +7309,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d321ea9e1cc0a2e3de41c02e3a7586695a9c03beccb5460e938a7ccf00cb612" dependencies = [ - "itertools 0.14.0", + "itertools", "proc-macro2", "quote", "syn", @@ -7019,9 +7317,9 @@ dependencies = [ [[package]] name = "wgpu" -version = "28.0.0" +version = "29.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cb534d5ffd109c7d1135f34cdae29e60eab94855a625dcfe1705f8bc7ad79f" +checksum = "72c239a9a747bbd379590985bac952c2e53cb19873f7072b3370c6a6a8e06837" dependencies = [ "arrayvec", "bitflags 2.11.0", @@ -7048,13 +7346,13 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "28.0.1" +version = "29.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23f4642f53f666adcfd2d3218ab174d1e6681101aef18696b90cbe64d1c10f9" +checksum = "1e80ac6cf1895df6342f87d975162108f9d98772a0d74bc404ab7304ac29469e" dependencies = [ "arrayvec", - "bit-set", - "bit-vec", + "bit-set 0.9.1", + "bit-vec 0.9.1", "bitflags 2.11.0", "bytemuck", "cfg_aliases", @@ -7068,59 +7366,59 @@ dependencies = [ "portable-atomic", "profiling", "raw-window-handle", - "rustc-hash 1.1.0", + "rustc-hash", "smallvec", "thiserror 2.0.18", "wgpu-core-deps-apple", "wgpu-core-deps-wasm", "wgpu-core-deps-windows-linux-android", "wgpu-hal", + "wgpu-naga-bridge", "wgpu-types", ] [[package]] name = "wgpu-core-deps-apple" -version = "28.0.0" +version = "29.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87b7b696b918f337c486bf93142454080a32a37832ba8a31e4f48221890047da" +checksum = "43acd053312501689cd92a01a9638d37f3e41a5fd9534875efa8917ee2d11ac0" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-wasm" -version = "28.0.0" +version = "29.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12a2cf578ce8d7d50d0e63ddc2345c7dcb599f6eb90b888813406ea78b9b7010" +checksum = "2f7b75e72f49035f000dd5262e4126242e92a090a4fd75931ecfe7e60784e6fa" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-windows-linux-android" -version = "28.0.0" +version = "29.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ca976e72b2c9964eb243e281f6ce7f14a514e409920920dcda12ae40febaae" +checksum = "725d5c006a8c02967b6d93ef04f6537ec4593313e330cfe86d9d3f946eb90f28" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-hal" -version = "28.0.1" +version = "29.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d6cb474beb218824dcc9e1ce679d973f719262789bfb27407da560cac20eeb" +checksum = "89a47aef47636562f3937285af4c44b4b5b404b46577471411cc5313a921da7e" dependencies = [ "android_system_properties", "arrayvec", "ash", - "bit-set", + "bit-set 0.9.1", "bitflags 2.11.0", - "block", + "block2 0.6.2", "bytemuck", "cfg-if 1.0.4", "cfg_aliases", - "core-graphics-types 0.2.0", "glow", "glutin_wgl_sys", "gpu-allocator", @@ -7131,10 +7429,13 @@ dependencies = [ "libc", "libloading", "log", - "metal 0.33.0", "naga", - "ndk-sys 0.6.0+11769913", - "objc", + "ndk-sys", + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-metal 0.3.2", + "objc2-quartz-core 0.3.2", "once_cell", "ordered-float", "parking_lot", @@ -7143,26 +7444,40 @@ dependencies = [ "profiling", "range-alloc", "raw-window-handle", + "raw-window-metal", "renderdoc-sys", "smallvec", "thiserror 2.0.18", "wasm-bindgen", + "wayland-sys", "web-sys", + "wgpu-naga-bridge", "wgpu-types", "windows 0.62.2", "windows-core 0.62.2", ] +[[package]] +name = "wgpu-naga-bridge" +version = "29.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4684f4410da0cf95a4cb63bb5edaac022461dedb6adf0b64d0d9b5f6890d51" +dependencies = [ + "naga", + "wgpu-types", +] + [[package]] name = "wgpu-types" -version = "28.0.0" +version = "29.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e18308757e594ed2cd27dddbb16a139c42a683819d32a2e0b1b0167552f5840c" +checksum = "ec2675540fb1a5cfa5ef122d3d5f390e2c75711a0b946410f2d6ac3a0f77d1f6" dependencies = [ "bitflags 2.11.0", "bytemuck", "js-sys", "log", + "raw-window-handle", "serde", "web-sys", ] @@ -7175,7 +7490,7 @@ checksum = "946419efa46664a8070c512fb358ac4acfc6e6215c2396ae5afeb9b72dd6ca7d" dependencies = [ "annotate-snippets", "derive_more", - "itertools 0.14.0", + "itertools", "lalrpop", "lalrpop-util", "lexical", @@ -7191,7 +7506,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7aed068ca1dc8fb182f574c9f2ace45ec988c71ba050f6dd334883fe3b8a88e2" dependencies = [ "half", - "itertools 0.14.0", + "itertools", "num-traits", ] @@ -7238,16 +7553,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.54.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" -dependencies = [ - "windows-core 0.54.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.56.0" @@ -7289,16 +7594,6 @@ dependencies = [ "windows-core 0.62.2", ] -[[package]] -name = "windows-core" -version = "0.54.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" -dependencies = [ - "windows-result 0.1.2", - "windows-targets 0.52.6", -] - [[package]] name = "windows-core" version = "0.56.0" @@ -7738,7 +8033,7 @@ dependencies = [ "js-sys", "libc", "memmap2", - "ndk 0.9.0", + "ndk", "objc2 0.5.2", "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", @@ -7773,15 +8068,12 @@ name = "winnow" version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" -dependencies = [ - "memchr", -] [[package]] name = "winnow" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" +checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" dependencies = [ "memchr", ] @@ -7876,9 +8168,9 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "x11-dl" @@ -7955,6 +8247,29 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zeno" version = "0.3.3" @@ -7963,18 +8278,18 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" [[package]] name = "zerocopy" -version = "0.8.42" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.42" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", @@ -7983,18 +8298,58 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "serde", + "yoke", "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -8020,9 +8375,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.5.13" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec5f41c76397b7da451efd19915684f727d7e1d516384ca6bd0ec43ec94de23c" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" dependencies = [ "zune-core", ] diff --git a/Cargo.toml b/Cargo.toml index 94ff5c85..bdde818a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ too_many_arguments = "allow" [workspace.dependencies] bevy = { git = "https://github.com/bevyengine/bevy", branch = "main", features = ["file_watcher", "shader_format_wesl", "free_camera", "pan_camera"] } bevy_naga_reflect = { git = "https://github.com/tychedelia/bevy_naga_reflect" } -naga = { version = "28", features = ["wgsl-in"] } +naga = { version = "29", features = ["wgsl-in"] } wesl = { version = "0.3", default-features = false } pyo3 = { git = "https://github.com/PyO3/pyo3", branch = "main" } pyo3-introspection = { git = "https://github.com/PyO3/pyo3", branch = "main" } diff --git a/crates/processing_render/src/gltf.rs b/crates/processing_render/src/gltf.rs index 3eca3394..84cd75f1 100644 --- a/crates/processing_render/src/gltf.rs +++ b/crates/processing_render/src/gltf.rs @@ -10,7 +10,7 @@ use bevy::{ ecs::system::RunSystemOnce, gltf::{Gltf, GltfMeshName}, prelude::*, - scene::SceneSpawner, + world_serialization::WorldInstanceSpawner, }; use crate::geometry::{BuiltinAttributes, Geometry, layout::VertexLayout}; @@ -65,7 +65,7 @@ fn compute_global_transform(world: &World, entity: Entity) -> Transform { #[derive(Component)] pub struct GltfHandle { handle: Handle, - instance_id: bevy::scene::InstanceId, + instance_id: bevy::world_serialization::InstanceId, graphics_entity: Entity, base_path: String, } @@ -96,7 +96,7 @@ pub fn load( // we spawn the scene in to the world in a blocking fashion so that bevy runs all // its hooks for the gltf, ex creating standard material instances - let instance_id = world.resource_scope(|world, mut spawner: Mut| { + let instance_id = world.resource_scope(|world, mut spawner: Mut| { spawner .spawn_sync(world, &scene_handle) .map_err(|e| ProcessingError::GltfLoadError(format!("Scene spawn failed: {e}"))) @@ -105,7 +105,7 @@ pub fn load( // we have to remove the existing cameras from the scene -- the user can request to set *this* // graphics to a camera, but the scenes cameras should not exist { - let spawner = world.resource::(); + let spawner = world.resource::(); let cam_entities: Vec = spawner .iter_instance_entities(instance_id) .filter(|&e| world.get::(e).is_some()) @@ -138,7 +138,7 @@ pub fn geometry( let instance_id = gltf_handle.instance_id; let (mesh_handle, global_transform) = { - let spawner = world.resource::(); + let spawner = world.resource::(); // find the mesh with the given name component that bevy added post-spawn // name is derived from gltf node or computed @@ -254,7 +254,7 @@ pub fn camera(In((gltf_entity, index)): In<(Entity, usize)>, world: &mut World) let graphics_entity = gltf_handle.graphics_entity; let (projection, node_xform) = { - let spawner = world.resource::(); + let spawner = world.resource::(); let camera_entity = spawner .iter_instance_entities(instance_id) .filter(|&e| world.get::(e).is_some()) @@ -320,7 +320,7 @@ pub fn light(In((gltf_entity, index)): In<(Entity, usize)>, world: &mut World) - let graphics_entity = gltf_handle.graphics_entity; let light_entities: Vec = { - let spawner = world.resource::(); + let spawner = world.resource::(); spawner .iter_instance_entities(instance_id) .filter(|&e| { diff --git a/crates/processing_render/src/material/custom.rs b/crates/processing_render/src/material/custom.rs index 58427683..608c0479 100644 --- a/crates/processing_render/src/material/custom.rs +++ b/crates/processing_render/src/material/custom.rs @@ -41,6 +41,7 @@ use bevy::{ BindGroupLayoutDescriptor, BindingResources, BlendState, UnpreparedBindGroup, }, renderer::RenderDevice, + storage::GpuShaderBuffer, sync_world::MainEntity, texture::GpuImage, }, @@ -380,6 +381,7 @@ impl ErasedRenderAsset for CustomMaterial { SResMut, SResMut, SRes>, + SRes>, ); fn prepare_asset( @@ -392,6 +394,7 @@ impl ErasedRenderAsset for CustomMaterial { bind_group_allocators, render_material_bindings, gpu_images, + gpu_buffers, ): &mut SystemParamItem, ) -> std::result::Result> { let reflection = source_asset.shader.reflection(); @@ -401,7 +404,7 @@ impl ErasedRenderAsset for CustomMaterial { BindGroupLayoutDescriptor::new("custom_material_bind_group", &layout_entries); let bindings = - reflection.create_bindings(3, &source_asset.shader, render_device, gpu_images); + reflection.create_bindings(3, &source_asset.shader, render_device, gpu_images, gpu_buffers); let unprepared = UnpreparedBindGroup { bindings: BindingResources(bindings), From 8ccb0c7f6f556e21e9f54629327910258bc0ce59 Mon Sep 17 00:00:00 2001 From: Moon Date: Mon, 13 Apr 2026 15:21:44 -0400 Subject: [PATCH 03/15] Update README.md to use `uv` as method to install `mewnala` (#110) merging but this needs to improved. i am merging this incremental improvement --- README.md | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 7af2d326..dc34adff 100644 --- a/README.md +++ b/README.md @@ -10,24 +10,31 @@ Inside of our `processing_pyo3` crate we have created a python package that you Again, we are still very nascent, but let us know what kinds of snags you may run into while getting this set up. Try running the examples in the [processing_pyo3 examples directory](crates/processing_pyo3/examples). -```bash -# have python3 installed on your system +We are big fans of [uv](https://github.com/astral-sh/uv) and this is the easiest way to get started using `mewnala` -# create a sketch folder and go inside -mkdir my-sketch-folder && cd my-sketch-folder +#### Setting up uv on linux or macOS +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +``` -# create a virtual env -python -m venv .venv +#### For Windows users: +```bash +powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" +``` -# activate virtual env -source .venv/bin/activate +#### Install a mewnala +```bash +# Initialize a project with uv +uv init mewnala-sketchbook && cd mewnala-sketchbook -pip install mewnala +# add the package +uv add mewnala -python my_sketch.py +# run a sketch +uv run sketch.py ``` -### Rust +### Rust (libprocessing) You'll need to install the Rust toolchain to work on this project. Most users will want to install Rust via [`rustup`](https://rustup.rs/), which helps manage Rust toolchain versions. From e08ca8305e2df51f1caec595dcb120581820c767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Tue, 14 Apr 2026 09:00:32 -0700 Subject: [PATCH 04/15] Add docs generation. (#109) --- .github/workflows/docs.yml | 68 ++++ .gitignore | 2 + crates/processing_pyo3/pyproject.toml | 5 + crates/processing_pyo3/uv.lock | 308 +++++++++++++++++- .../processing_render/src/material/custom.rs | 9 +- docs/gen_ref_pages.py | 22 ++ justfile | 6 + mkdocs.yml | 65 ++++ tools/generate_stubs/src/main.rs | 5 +- 9 files changed, 486 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/docs.yml create mode 100644 docs/gen_ref_pages.py create mode 100644 mkdocs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..aca6e3df --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,68 @@ +name: Docs + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - uses: ./.github/actions/setup + + - uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - uses: astral-sh/setup-uv@v6 + + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-cargo-docs-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-docs- + ${{ runner.os }}-cargo- + + - name: Build extension and generate stubs + run: | + cd crates/processing_pyo3 + uv run maturin develop --release + cd ../.. + cargo run --release -p generate_stubs + + - name: Build docs + run: uv run --project crates/processing_pyo3 --group docs mkdocs build + + - uses: actions/upload-pages-artifact@v3 + with: + path: site/ + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 6ee9e845..82eb289f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ /target/ +/site/ crates/processing_ffi/include/ +crates/processing_pyo3/mewnala/*.pyi .DS_Store .ipynb_checkpoints/ \ No newline at end of file diff --git a/crates/processing_pyo3/pyproject.toml b/crates/processing_pyo3/pyproject.toml index c3347daf..91dd072d 100644 --- a/crates/processing_pyo3/pyproject.toml +++ b/crates/processing_pyo3/pyproject.toml @@ -35,6 +35,11 @@ Issues = "https://github.com/processing/libprocessing/issues" [dependency-groups] dev = ["maturin>=1.10,<2.0"] +docs = [ + "mkdocs-material>=9.6", + "mkdocstrings[python]>=0.29", + "mkdocs-gen-files>=0.5", +] [tool.maturin] manifest-path = "Cargo.toml" diff --git a/crates/processing_pyo3/uv.lock b/crates/processing_pyo3/uv.lock index f1986982..20d8468d 100644 --- a/crates/processing_pyo3/uv.lock +++ b/crates/processing_pyo3/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 3 +revision = 2 requires-python = ">=3.10" resolution-markers = [ "python_full_version >= '3.14'", @@ -130,6 +130,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, ] +[[package]] +name = "backrefs" +version = "6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/a6/e325ec73b638d3ede4421b5445d4a0b8b219481826cc079d510100af356c/backrefs-6.2.tar.gz", hash = "sha256:f44ff4d48808b243b6c0cdc6231e22195c32f77046018141556c66f8bab72a49", size = 7012303, upload-time = "2026-02-16T19:10:15.828Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/39/3765df263e08a4df37f4f43cb5aa3c6c17a4bdd42ecfe841e04c26037171/backrefs-6.2-py310-none-any.whl", hash = "sha256:0fdc7b012420b6b144410342caeb8adc54c6866cf12064abc9bb211302e496f8", size = 381075, upload-time = "2026-02-16T19:10:04.322Z" }, + { url = "https://files.pythonhosted.org/packages/0f/f0/35240571e1b67ffb19dafb29ab34150b6f59f93f717b041082cdb1bfceb1/backrefs-6.2-py311-none-any.whl", hash = "sha256:08aa7fae530c6b2361d7bdcbda1a7c454e330cc9dbcd03f5c23205e430e5c3be", size = 392874, upload-time = "2026-02-16T19:10:06.314Z" }, + { url = "https://files.pythonhosted.org/packages/e3/63/77e8c9745b4d227cce9f5e0a6f68041278c5f9b18588b35905f5f19c1beb/backrefs-6.2-py312-none-any.whl", hash = "sha256:c3f4b9cb2af8cda0d87ab4f57800b57b95428488477be164dd2b47be54db0c90", size = 398787, upload-time = "2026-02-16T19:10:08.274Z" }, + { url = "https://files.pythonhosted.org/packages/c5/71/c754b1737ad99102e03fa3235acb6cb6d3ac9d6f596cbc3e5f236705abd8/backrefs-6.2-py313-none-any.whl", hash = "sha256:12df81596ab511f783b7d87c043ce26bc5b0288cf3bb03610fe76b8189282b2b", size = 400747, upload-time = "2026-02-16T19:10:09.791Z" }, + { url = "https://files.pythonhosted.org/packages/af/75/be12ba31a6eb20dccef2320cd8ccb3f7d9013b68ba4c70156259fee9e409/backrefs-6.2-py314-none-any.whl", hash = "sha256:e5f805ae09819caa1aa0623b4a83790e7028604aa2b8c73ba602c4454e665de7", size = 412602, upload-time = "2026-02-16T19:10:12.317Z" }, + { url = "https://files.pythonhosted.org/packages/21/f8/d02f650c47d05034dcd6f9c8cf94f39598b7a89c00ecda0ecb2911bc27e9/backrefs-6.2-py39-none-any.whl", hash = "sha256:664e33cd88c6840b7625b826ecf2555f32d491800900f5a541f772c485f7cda7", size = 381077, upload-time = "2026-02-16T19:10:13.74Z" }, +] + [[package]] name = "beautifulsoup4" version = "4.14.3" @@ -340,6 +354,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, ] +[[package]] +name = "click" +version = "8.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/75/31212c6bf2503fdf920d87fee5d7a86a2e3bcf444984126f13d8e4016804/click-8.3.2.tar.gz", hash = "sha256:14162b8b3b3550a7d479eafa77dfd3c38d9dc8951f6f69c78913a8f9a7540fd5", size = 302856, upload-time = "2026-04-03T19:14:45.118Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl", hash = "sha256:1924d2c27c5653561cd2cae4548d1406039cb79b858b747cfea24924bbc1616d", size = 108379, upload-time = "2026-04-03T19:14:43.505Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -444,6 +470,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" }, ] +[[package]] +name = "ghp-import" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, +] + +[[package]] +name = "griffelib" +version = "2.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/82/74f4a3310cdabfbb10da554c3a672847f1ed33c6f61dd472681ce7f1fe67/griffelib-2.0.2.tar.gz", hash = "sha256:3cf20b3bc470e83763ffbf236e0076b1211bac1bc67de13daf494640f2de707e", size = 166461, upload-time = "2026-03-27T11:34:51.091Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl", hash = "sha256:925c857658fb1ba40c0772c37acbc2ab650bd794d9c1b9726922e36ea4117ea1", size = 142357, upload-time = "2026-03-27T11:34:46.275Z" }, +] + [[package]] name = "h11" version = "0.16.0" @@ -899,6 +946,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151, upload-time = "2025-10-27T18:25:54.882Z" }, ] +[[package]] +name = "markdown" +version = "3.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805, upload-time = "2026-02-09T14:57:26.942Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" }, +] + [[package]] name = "markupsafe" version = "3.0.3" @@ -1020,6 +1076,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1b/01/7da60c9f7d5dc92dfa5e8888239fd0fb2613ee19e44e6db5c2ed5595fab3/maturin-1.10.2-py3-none-win_arm64.whl", hash = "sha256:a4c29a770ea2c76082e0afc6d4efd8ee94405588bfae00d10828f72e206c739b", size = 7506680, upload-time = "2025-11-19T11:53:15.403Z" }, ] +[[package]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" }, +] + [[package]] name = "mewnala" source = { editable = "." } @@ -1033,6 +1098,11 @@ dependencies = [ dev = [ { name = "maturin" }, ] +docs = [ + { name = "mkdocs-gen-files" }, + { name = "mkdocs-material" }, + { name = "mkdocstrings", extra = ["python"] }, +] [package.metadata] requires-dist = [ @@ -1042,6 +1112,11 @@ requires-dist = [ [package.metadata.requires-dev] dev = [{ name = "maturin", specifier = ">=1.10,<2.0" }] +docs = [ + { name = "mkdocs-gen-files", specifier = ">=0.5" }, + { name = "mkdocs-material", specifier = ">=9.6" }, + { name = "mkdocstrings", extras = ["python"], specifier = ">=0.29" }, +] [[package]] name = "mistune" @@ -1055,6 +1130,139 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598, upload-time = "2025-12-23T11:36:33.211Z" }, ] +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "ghp-import" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, +] + +[[package]] +name = "mkdocs-autorefs" +version = "1.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/c0/f641843de3f612a6b48253f39244165acff36657a91cc903633d456ae1ac/mkdocs_autorefs-1.4.4.tar.gz", hash = "sha256:d54a284f27a7346b9c38f1f852177940c222da508e66edc816a0fa55fc6da197", size = 56588, upload-time = "2026-02-10T15:23:55.105Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/de/a3e710469772c6a89595fc52816da05c1e164b4c866a89e3cb82fb1b67c5/mkdocs_autorefs-1.4.4-py3-none-any.whl", hash = "sha256:834ef5408d827071ad1bc69e0f39704fa34c7fc05bc8e1c72b227dfdc5c76089", size = 25530, upload-time = "2026-02-10T15:23:53.817Z" }, +] + +[[package]] +name = "mkdocs-gen-files" +version = "0.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mkdocs" }, + { name = "properdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/43/428f312149c161cae557eecd35f3c4a82b867998b1d47fb29fdfe927be26/mkdocs_gen_files-0.6.1.tar.gz", hash = "sha256:57d7ff2229e23d077e46d14a33db6d37c8823f6ce1a503c874c1764a71679763", size = 8746, upload-time = "2026-03-16T23:26:09.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/1b/3075eb67fe66e19db059f0a25744c4e56978a309603a20e1d3353d545b5e/mkdocs_gen_files-0.6.1-py3-none-any.whl", hash = "sha256:b3182bfc6219e35b8d26658cb988368659d5d023aac30c2a819247558fc12189", size = 8282, upload-time = "2026-03-16T23:26:08.292Z" }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ce/25/b3cccb187655b9393572bde9b09261d267c3bf2f2cdabe347673be5976a6/mkdocs_get_deps-0.2.2.tar.gz", hash = "sha256:8ee8d5f316cdbbb2834bc1df6e69c08fe769a83e040060de26d3c19fad3599a1", size = 11047, upload-time = "2026-03-10T02:46:33.632Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl", hash = "sha256:e7878cbeac04860b8b5e0ca31d3abad3df9411a75a32cde82f8e44b6c16ff650", size = 9555, upload-time = "2026-03-10T02:46:32.256Z" }, +] + +[[package]] +name = "mkdocs-material" +version = "9.7.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "backrefs" }, + { name = "colorama" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "mkdocs" }, + { name = "mkdocs-material-extensions" }, + { name = "paginate" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/45/29/6d2bcf41ae40802c4beda2432396fff97b8456fb496371d1bc7aad6512ec/mkdocs_material-9.7.6.tar.gz", hash = "sha256:00bdde50574f776d328b1862fe65daeaf581ec309bd150f7bff345a098c64a69", size = 4097959, upload-time = "2026-03-19T15:41:58.161Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/01/bc663630c510822c95c47a66af9fa7a443c295b47d5f041e5e6ae62ef659/mkdocs_material-9.7.6-py3-none-any.whl", hash = "sha256:71b84353921b8ea1ba84fe11c50912cc512da8fe0881038fcc9a0761c0e635ba", size = 9305470, upload-time = "2026-03-19T15:41:55.217Z" }, +] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847, upload-time = "2023-11-22T19:09:45.208Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" }, +] + +[[package]] +name = "mkdocstrings" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "pymdown-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/62/0dfc5719514115bf1781f44b1d7f2a0923fcc01e9c5d7990e48a05c9ae5d/mkdocstrings-1.0.3.tar.gz", hash = "sha256:ab670f55040722b49bb45865b2e93b824450fb4aef638b00d7acb493a9020434", size = 100946, upload-time = "2026-02-07T14:31:40.973Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/41/1cf02e3df279d2dd846a1bf235a928254eba9006dd22b4a14caa71aed0f7/mkdocstrings-1.0.3-py3-none-any.whl", hash = "sha256:0d66d18430c2201dc7fe85134277382baaa15e6b30979f3f3bdbabd6dbdb6046", size = 35523, upload-time = "2026-02-07T14:31:39.27Z" }, +] + +[package.optional-dependencies] +python = [ + { name = "mkdocstrings-python" }, +] + +[[package]] +name = "mkdocstrings-python" +version = "2.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffelib" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocstrings" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/29/33/c225eaf898634bdda489a6766fc35d1683c640bffe0e0acd10646b13536d/mkdocstrings_python-2.0.3.tar.gz", hash = "sha256:c518632751cc869439b31c9d3177678ad2bfa5c21b79b863956ad68fc92c13b8", size = 199083, upload-time = "2026-02-20T10:38:36.368Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/28/79f0f8de97cce916d5ae88a7bee1ad724855e83e6019c0b4d5b3fabc80f3/mkdocstrings_python-2.0.3-py3-none-any.whl", hash = "sha256:0b83513478bdfd803ff05aa43e9b1fca9dd22bcd9471f09ca6257f009bc5ee12", size = 104779, upload-time = "2026-02-20T10:38:34.517Z" }, +] + [[package]] name = "nbclient" version = "0.10.4" @@ -1165,6 +1373,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, ] +[[package]] +name = "paginate" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252, upload-time = "2024-08-25T14:17:24.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746, upload-time = "2024-08-25T14:17:22.55Z" }, +] + [[package]] name = "pandocfilters" version = "1.5.1" @@ -1183,6 +1400,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b6/61/fae042894f4296ec49e3f193aff5d7c18440da9e48102c3315e1bc4519a7/parso-0.8.6-py2.py3-none-any.whl", hash = "sha256:2c549f800b70a5c4952197248825584cb00f033b29c692671d3bf08bf380baff", size = 106894, upload-time = "2026-02-09T15:45:21.391Z" }, ] +[[package]] +name = "pathspec" +version = "1.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/36/e27608899f9b8d4dff0617b2d9ab17ca5608956ca44461ac14ac48b44015/pathspec-1.0.4.tar.gz", hash = "sha256:0210e2ae8a21a9137c0d470578cb0e595af87edaa6ebf12ff176f14a02e0e645", size = 131200, upload-time = "2026-01-27T03:59:46.938Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/3c/2c197d226f9ea224a9ab8d197933f9da0ae0aac5b6e0f884e2b8d9c8e9f7/pathspec-1.0.4-py3-none-any.whl", hash = "sha256:fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", size = 55206, upload-time = "2026-01-27T03:59:45.137Z" }, +] + [[package]] name = "pexpect" version = "4.9.0" @@ -1225,6 +1451,29 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, ] +[[package]] +name = "properdocs" +version = "1.6.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "ghp-import" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ec/29/f27a4e1eddf72ed3db6e47818fbafe6debbf09fd7051f9c1a007239b46ef/properdocs-1.6.7.tar.gz", hash = "sha256:adc7b16e562890af0e098a7e5b02e3a81c20894a87d6a28d345c9300de73c26e", size = 276141, upload-time = "2026-03-20T20:07:48.167Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/4d/fc923f5c85318ee8cc903566dc4e0ebe41b2dfc1d2ecf5546db232397ed6/properdocs-1.6.7-py3-none-any.whl", hash = "sha256:6fa0cfa2e01bf338f684892c8a506cf70ea88ae7f3479c933b6fa20168101cbd", size = 225406, upload-time = "2026-03-20T20:07:46.875Z" }, +] + [[package]] name = "psutil" version = "7.2.2" @@ -1289,6 +1538,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] +[[package]] +name = "pymdown-extensions" +version = "10.21.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/08/f1c908c581fd11913da4711ea7ba32c0eee40b0190000996bb863b0c9349/pymdown_extensions-10.21.2.tar.gz", hash = "sha256:c3f55a5b8a1d0edf6699e35dcbea71d978d34ff3fa79f3d807b8a5b3fa90fbdc", size = 853922, upload-time = "2026-03-29T15:01:55.233Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/27/a2fc51a4a122dfd1015e921ae9d22fee3d20b0b8080d9a704578bf9deece/pymdown_extensions-10.21.2-py3-none-any.whl", hash = "sha256:5c0fd2a2bea14eb39af8ff284f1066d898ab2187d81b889b75d46d4348c01638", size = 268901, upload-time = "2026-03-29T15:01:53.244Z" }, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -1396,6 +1658,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, ] +[[package]] +name = "pyyaml-env-tag" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, +] + [[package]] name = "pyzmq" version = "27.1.0" @@ -1842,6 +2116,38 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, ] +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/56/90994d789c61df619bfc5ce2ecdabd5eeff564e1eb47512bd01b5e019569/watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", size = 96390, upload-time = "2024-11-01T14:06:24.793Z" }, + { url = "https://files.pythonhosted.org/packages/55/46/9a67ee697342ddf3c6daa97e3a587a56d6c4052f881ed926a849fcf7371c/watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", size = 88389, upload-time = "2024-11-01T14:06:27.112Z" }, + { url = "https://files.pythonhosted.org/packages/44/65/91b0985747c52064d8701e1075eb96f8c40a79df889e59a399453adfb882/watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", size = 89020, upload-time = "2024-11-01T14:06:29.876Z" }, + { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" }, + { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" }, + { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" }, + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, + { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902, upload-time = "2024-11-01T14:06:53.119Z" }, + { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380, upload-time = "2024-11-01T14:06:55.19Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +] + [[package]] name = "wcwidth" version = "0.6.0" diff --git a/crates/processing_render/src/material/custom.rs b/crates/processing_render/src/material/custom.rs index 608c0479..04080b8c 100644 --- a/crates/processing_render/src/material/custom.rs +++ b/crates/processing_render/src/material/custom.rs @@ -403,8 +403,13 @@ impl ErasedRenderAsset for CustomMaterial { let bind_group_layout = BindGroupLayoutDescriptor::new("custom_material_bind_group", &layout_entries); - let bindings = - reflection.create_bindings(3, &source_asset.shader, render_device, gpu_images, gpu_buffers); + let bindings = reflection.create_bindings( + 3, + &source_asset.shader, + render_device, + gpu_images, + gpu_buffers, + ); let unprepared = UnpreparedBindGroup { bindings: BindingResources(bindings), diff --git a/docs/gen_ref_pages.py b/docs/gen_ref_pages.py new file mode 100644 index 00000000..2f45b796 --- /dev/null +++ b/docs/gen_ref_pages.py @@ -0,0 +1,22 @@ +from pathlib import Path + +import mkdocs_gen_files + +readme = Path("crates/processing_pyo3/README.md").read_text(encoding="utf-8") +with mkdocs_gen_files.open("index.md", "w") as f: + f.write(readme) + +modules = { + "reference/index.md": ("API Reference", "mewnala", {"show_submodules": False}), + "reference/math.md": ("mewnala.math", "mewnala.math", {}), + "reference/color.md": ("mewnala.color", "mewnala.color", {}), +} + +for path, (title, module, options) in modules.items(): + with mkdocs_gen_files.open(path, "w") as f: + f.write(f"# {title}\n\n") + if options: + opts = "\n".join(f" {k}: {v}" for k, v in options.items()) + f.write(f"::: {module}\n options:\n{opts}\n") + else: + f.write(f"::: {module}\n") diff --git a/justfile b/justfile index 9d656460..cb036666 100644 --- a/justfile +++ b/justfile @@ -20,6 +20,12 @@ py-jupyter file: py-build py-ipython: py-build cd crates/processing_pyo3; ipython +docs-serve: py-stubs + uv run --project crates/processing_pyo3 --group docs mkdocs serve + +docs-build: py-stubs + uv run --project crates/processing_pyo3 --group docs mkdocs build + wasm-build: wasm-pack build crates/processing_wasm --target web --out-dir ../../target/wasm diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 00000000..c0e22261 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,65 @@ +site_name: mewnala +site_description: Mewnala, I choose you! +site_url: https://processing.github.io/libprocessing/ +repo_url: https://github.com/processing/libprocessing +repo_name: processing/libprocessing + +theme: + name: material + palette: + - scheme: default + primary: deep purple + accent: pink + toggle: + icon: material/brightness-7 + name: Switch to dark mode + - scheme: slate + primary: deep purple + accent: pink + toggle: + icon: material/brightness-4 + name: Switch to light mode + features: + - content.code.copy + - navigation.sections + - navigation.expand + - search.highlight + +plugins: + - search + - gen-files: + scripts: + - docs/gen_ref_pages.py + - mkdocstrings: + handlers: + python: + paths: + - crates/processing_pyo3 + options: + allow_inspection: false + show_source: false + show_root_heading: true + show_root_full_path: false + members_order: alphabetical + docstring_style: google + show_if_no_docstring: true + filters: + - "!^_" + +nav: + - Home: index.md + - API Reference: + - Overview: reference/index.md + - Math: reference/math.md + - Color: reference/color.md + - Design: + - Principles: principles.md + - Internal API: api.md + +markdown_extensions: + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.superfences + - pymdownx.inlinehilite + - admonition + - pymdownx.details diff --git a/tools/generate_stubs/src/main.rs b/tools/generate_stubs/src/main.rs index 522bae15..b80cbed6 100644 --- a/tools/generate_stubs/src/main.rs +++ b/tools/generate_stubs/src/main.rs @@ -41,7 +41,10 @@ fn main() { eprintln!("Introspecting: {}", cdylib_path.display()); - let module = introspect_cdylib(&cdylib_path, "mewnala").expect("Failed to introspect cdylib"); + let mut module = + introspect_cdylib(&cdylib_path, "mewnala").expect("Failed to introspect cdylib"); + + module.incomplete = false; let stubs = module_stub_files(&module); From 13e7e0fb61cad27bf2c7d2afdff57f5e64909076 Mon Sep 17 00:00:00 2001 From: enderversing Date: Thu, 16 Apr 2026 09:37:19 -0400 Subject: [PATCH 05/15] Update README.md to include just installation (#113) --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dc34adff..6e6d8c3d 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,13 @@ You'll need to install the Rust toolchain to work on this project. Most users wi ### Build commands -This project uses [just](https://github.com/casey/just) as a command runner. Run `just` to see available commands. +This project uses [just](https://github.com/casey/just) as a command runner: + +```bash +cargo install just +``` + +Run `just` to see available commands. ## Building for web From 84d6558dded98920d6c9461f63dc7af7cfbd89b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Tue, 21 Apr 2026 18:03:56 -0700 Subject: [PATCH 06/15] Add Cuda support (#108) --- Cargo.lock | 47 +++++ Cargo.toml | 4 + crates/processing_core/src/error.rs | 2 + crates/processing_cuda/Cargo.toml | 17 ++ crates/processing_cuda/src/lib.rs | 213 +++++++++++++++++++++++ crates/processing_pyo3/Cargo.toml | 4 +- crates/processing_pyo3/examples/cuda.py | 40 +++++ crates/processing_pyo3/pyproject.toml | 5 +- crates/processing_pyo3/src/cuda.rs | 59 +++++++ crates/processing_pyo3/src/graphics.rs | 89 +++++++++- crates/processing_pyo3/src/lib.rs | 53 +++++- crates/processing_render/src/graphics.rs | 85 ++------- crates/processing_render/src/image.rs | 64 +++---- crates/processing_render/src/lib.rs | 32 +++- crates/processing_render/src/surface.rs | 4 +- justfile | 8 +- src/lib.rs | 6 + 17 files changed, 590 insertions(+), 142 deletions(-) create mode 100644 crates/processing_cuda/Cargo.toml create mode 100644 crates/processing_cuda/src/lib.rs create mode 100644 crates/processing_pyo3/examples/cuda.py create mode 100644 crates/processing_pyo3/src/cuda.rs diff --git a/Cargo.lock b/Cargo.lock index 54626b33..d8abaabc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -781,6 +781,20 @@ dependencies = [ "nonmax", ] +[[package]] +name = "bevy_cuda" +version = "0.1.0" +source = "git+https://github.com/tychedelia/bevy_cuda#f1e63bb2811eddfb6ed13ff9920f7ae2be091da1" +dependencies = [ + "ash", + "bevy", + "cudarc", + "thiserror 2.0.18", + "wgpu", + "wgpu-hal", + "windows 0.58.0", +] + [[package]] name = "bevy_derive" version = "0.19.0-dev" @@ -2676,6 +2690,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "cudarc" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aa12038120eb13347a6ae2ffab1d34efe78150125108627fd85044dd4d6ff1e" +dependencies = [ + "libloading", +] + [[package]] name = "cursor-icon" version = "1.2.0" @@ -5606,6 +5629,7 @@ dependencies = [ "bevy", "js-sys", "processing_core", + "processing_cuda", "processing_glfw", "processing_input", "processing_midi", @@ -5628,6 +5652,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "processing_cuda" +version = "0.1.0" +dependencies = [ + "bevy", + "bevy_cuda", + "processing_core", + "processing_render", +] + [[package]] name = "processing_ffi" version = "0.0.1" @@ -5672,6 +5706,7 @@ dependencies = [ "bevy", "png", "processing", + "processing_cuda", "processing_glfw", "processing_webcam", "pyo3", @@ -5753,6 +5788,7 @@ name = "pyo3" version = "0.28.3" source = "git+https://github.com/PyO3/pyo3?branch=main#df36c7165663ec70180d71495bd52031edd075d4" dependencies = [ + "inventory", "libc", "once_cell", "portable-atomic", @@ -7331,6 +7367,7 @@ dependencies = [ "js-sys", "log", "naga", + "parking_lot", "portable-atomic", "profiling", "raw-window-handle", @@ -7370,6 +7407,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", @@ -7386,6 +7424,15 @@ dependencies = [ "wgpu-hal", ] +[[package]] +name = "wgpu-core-deps-emscripten" +version = "29.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef043bf135cc68b6f667c55ff4e345ce2b5924d75bad36a47921b0287ca4b24a" +dependencies = [ + "wgpu-hal", +] + [[package]] name = "wgpu-core-deps-wasm" version = "29.0.0" diff --git a/Cargo.toml b/Cargo.toml index bdde818a..5ad01ba4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ default = ["wayland"] wayland = ["processing_render/wayland"] x11 = ["processing_render/x11"] webcam = ["dep:processing_webcam"] +cuda = ["dep:processing_cuda"] [workspace] resolver = "3" @@ -24,12 +25,14 @@ too_many_arguments = "allow" [workspace.dependencies] bevy = { git = "https://github.com/bevyengine/bevy", branch = "main", features = ["file_watcher", "shader_format_wesl", "free_camera", "pan_camera"] } bevy_naga_reflect = { git = "https://github.com/tychedelia/bevy_naga_reflect" } +bevy_cuda = { git = "https://github.com/tychedelia/bevy_cuda" } naga = { version = "29", features = ["wgsl-in"] } wesl = { version = "0.3", default-features = false } pyo3 = { git = "https://github.com/PyO3/pyo3", branch = "main" } pyo3-introspection = { git = "https://github.com/PyO3/pyo3", branch = "main" } processing = { path = "." } processing_core = { path = "crates/processing_core" } +processing_cuda = { path = "crates/processing_cuda" } processing_pyo3 = { path = "crates/processing_pyo3" } processing_render = { path = "crates/processing_render" } processing_midi = { path = "crates/processing_midi" } @@ -44,6 +47,7 @@ processing_render = { workspace = true } processing_midi = { workspace = true } processing_input = { workspace = true } processing_webcam = { workspace = true, optional = true } +processing_cuda = { workspace = true, optional = true } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/crates/processing_core/src/error.rs b/crates/processing_core/src/error.rs index dfd00bae..7cc1e9e4 100644 --- a/crates/processing_core/src/error.rs +++ b/crates/processing_core/src/error.rs @@ -44,4 +44,6 @@ pub enum ProcessingError { ShaderNotFound, #[error("MIDI port {0} not found")] MidiPortNotFound(usize), + #[error("CUDA error: {0}")] + CudaError(String), } diff --git a/crates/processing_cuda/Cargo.toml b/crates/processing_cuda/Cargo.toml new file mode 100644 index 00000000..01310f29 --- /dev/null +++ b/crates/processing_cuda/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "processing_cuda" +version = "0.1.0" +edition = "2024" + +[lints] +workspace = true + +[features] +default = ["cuda-11040"] +cuda-11040 = ["bevy_cuda/cuda-11040"] + +[dependencies] +bevy = { workspace = true } +bevy_cuda = { workspace = true } +processing_core = { workspace = true } +processing_render = { workspace = true } diff --git a/crates/processing_cuda/src/lib.rs b/crates/processing_cuda/src/lib.rs new file mode 100644 index 00000000..e83a3759 --- /dev/null +++ b/crates/processing_cuda/src/lib.rs @@ -0,0 +1,213 @@ +use bevy::prelude::*; +use bevy::render::RenderApp; +use bevy::render::render_resource::{Texture, TextureFormat}; +use bevy::render::renderer::RenderDevice; +use bevy_cuda::{CudaBuffer, CudaContext}; +use processing_core::app_mut; +use processing_core::error::{ProcessingError, Result}; +use processing_render::graphics::view_target; +use processing_render::image::{Image, gpu_image, pixel_size}; + +#[derive(Component)] +pub struct CudaImageBuffer { + pub buffer: CudaBuffer, + pub width: u32, + pub height: u32, + pub texture_format: TextureFormat, +} + +pub struct CudaPlugin; + +impl Plugin for CudaPlugin { + fn build(&self, _app: &mut App) {} + + fn finish(&self, app: &mut App) { + let render_app = app.sub_app(RenderApp); + let render_device = render_app.world().resource::(); + let wgpu_device = render_device.wgpu_device(); + match CudaContext::new(wgpu_device, 0) { + Ok(ctx) => { + app.insert_resource(ctx); + } + Err(e) => { + warn!("CUDA not available, GPU interop disabled: {e}"); + } + } + } +} + +fn cuda_ctx(world: &World) -> Result<&CudaContext> { + world + .get_resource::() + .ok_or(ProcessingError::CudaError("CUDA not available".into())) +} + +fn resolve_texture(app: &mut App, entity: Entity) -> Result<(Texture, TextureFormat, u32, u32)> { + if app.world().get::(entity).is_some() { + let texture = gpu_image(app, entity)?.texture.clone(); + let p_image = app.world().get::(entity).unwrap(); + return Ok(( + texture, + p_image.texture_format, + p_image.size.width, + p_image.size.height, + )); + } + if let Ok(vt) = view_target(app, entity) { + let texture = vt.main_texture().clone(); + let fmt = vt.main_texture_format(); + let size = texture.size(); + return Ok((texture, fmt, size.width, size.height)); + } + Err(ProcessingError::ImageNotFound) +} + +pub fn cuda_export(entity: Entity) -> Result<()> { + app_mut(|app| { + let (texture, texture_format, width, height) = resolve_texture(app, entity)?; + + let px_size = pixel_size(texture_format)?; + let buffer_size = (width as u64) * (height as u64) * (px_size as u64); + + let existing = app.world().get::(entity); + let needs_alloc = existing.is_none_or(|buf| buf.buffer.size() != buffer_size); + + if needs_alloc { + let cuda_ctx = cuda_ctx(app.world())?; + let buffer = cuda_ctx + .create_buffer(buffer_size) + .map_err(|e| ProcessingError::CudaError(format!("Buffer creation failed: {e}")))?; + app.world_mut().entity_mut(entity).insert(CudaImageBuffer { + buffer, + width, + height, + texture_format, + }); + } + + let world = app.world(); + let cuda_buf = world.get::(entity).unwrap(); + let cuda_ctx = cuda_ctx(world)?; + + cuda_ctx + .copy_texture_to_buffer(&texture, &cuda_buf.buffer, width, height, texture_format) + .map_err(|e| { + ProcessingError::CudaError(format!("Texture-to-buffer copy failed: {e}")) + })?; + + Ok(()) + }) +} + +pub fn cuda_import(entity: Entity, src_device_ptr: u64, byte_size: u64) -> Result<()> { + app_mut(|app| { + let (texture, texture_format, width, height) = resolve_texture(app, entity)?; + + let existing = app.world().get::(entity); + let needs_alloc = existing.is_none_or(|buf| buf.buffer.size() != byte_size); + + if needs_alloc { + let cuda_ctx = cuda_ctx(app.world())?; + let buffer = cuda_ctx + .create_buffer(byte_size) + .map_err(|e| ProcessingError::CudaError(format!("Buffer creation failed: {e}")))?; + app.world_mut().entity_mut(entity).insert(CudaImageBuffer { + buffer, + width, + height, + texture_format, + }); + } + + let world = app.world(); + let cuda_buf = world.get::(entity).unwrap(); + let cuda_ctx = cuda_ctx(world)?; + + // wait for work (i.e. python) to be done with the buffer before we read from it + cuda_ctx + .synchronize() + .map_err(|e| ProcessingError::CudaError(format!("synchronize failed: {e}")))?; + + cuda_buf + .buffer + .copy_from_device_ptr(src_device_ptr, byte_size) + .map_err(|e| ProcessingError::CudaError(format!("memcpy_dtod failed: {e}")))?; + + cuda_ctx + .copy_buffer_to_texture(&cuda_buf.buffer, &texture, width, height, texture_format) + .map_err(|e| { + ProcessingError::CudaError(format!("Buffer-to-texture copy failed: {e}")) + })?; + + Ok(()) + }) +} + +pub fn cuda_write_back(entity: Entity) -> Result<()> { + app_mut(|app| { + let (texture, _, _, _) = resolve_texture(app, entity)?; + + let cuda_buf = app + .world() + .get::(entity) + .ok_or(ProcessingError::ImageNotFound)?; + + let cuda_ctx = cuda_ctx(app.world())?; + + cuda_ctx + .copy_buffer_to_texture( + &cuda_buf.buffer, + &texture, + cuda_buf.width, + cuda_buf.height, + cuda_buf.texture_format, + ) + .map_err(|e| { + ProcessingError::CudaError(format!("Buffer-to-texture copy failed: {e}")) + })?; + + Ok(()) + }) +} + +pub struct CudaBufferInfo { + pub device_ptr: u64, + pub width: u32, + pub height: u32, + pub texture_format: TextureFormat, +} + +pub fn cuda_buffer(entity: Entity) -> Result { + app_mut(|app| { + let cuda_buf = app + .world() + .get::(entity) + .ok_or(ProcessingError::ImageNotFound)?; + Ok(CudaBufferInfo { + device_ptr: cuda_buf.buffer.device_ptr(), + width: cuda_buf.width, + height: cuda_buf.height, + texture_format: cuda_buf.texture_format, + }) + }) +} + +pub fn typestr_for_format(format: TextureFormat) -> Result<&'static str> { + match format { + TextureFormat::Rgba8Unorm | TextureFormat::Rgba8UnormSrgb => Ok("|u1"), + TextureFormat::Rgba16Float => Ok(" Ok(" Err(ProcessingError::UnsupportedTextureFormat), + } +} + +pub fn elem_size_for_typestr(typestr: &str) -> Result { + match typestr { + "|u1" => Ok(1), + " Ok(2), + " Ok(4), + _ => Err(ProcessingError::CudaError(format!( + "unsupported typestr: {typestr}" + ))), + } +} diff --git a/crates/processing_pyo3/Cargo.toml b/crates/processing_pyo3/Cargo.toml index 9660e34d..adddc4f6 100644 --- a/crates/processing_pyo3/Cargo.toml +++ b/crates/processing_pyo3/Cargo.toml @@ -16,11 +16,13 @@ wayland = ["processing/wayland", "processing_glfw/wayland"] static-link = ["processing_glfw/static-link"] x11 = ["processing/x11"] webcam = ["processing/webcam", "dep:processing_webcam"] +cuda = ["dep:processing_cuda", "processing/cuda"] [dependencies] -pyo3 = { workspace = true, features = ["experimental-inspect"] } +pyo3 = { workspace = true, features = ["experimental-inspect", "multiple-pymethods"] } processing = { workspace = true } processing_webcam = { workspace = true, optional = true } processing_glfw = { workspace = true } bevy = { workspace = true, features = ["file_watcher"] } png = "0.18" +processing_cuda = { workspace = true, optional = true } diff --git a/crates/processing_pyo3/examples/cuda.py b/crates/processing_pyo3/examples/cuda.py new file mode 100644 index 00000000..817f07b4 --- /dev/null +++ b/crates/processing_pyo3/examples/cuda.py @@ -0,0 +1,40 @@ +from mewnala import * +import torch +import torch.nn.functional as F +import math + +W, H = 512, 512 +KERNEL_SIZE = 15 +sigma = 4.0 + +ax = torch.arange(-KERNEL_SIZE // 2 + 1.0, KERNEL_SIZE // 2 + 1.0, device="cuda") +xx, yy = torch.meshgrid(ax, ax, indexing="ij") +kernel = torch.exp(-(xx**2 + yy**2) / (2.0 * sigma**2)) +kernel = kernel / kernel.sum() +BLUR = kernel.unsqueeze(0).unsqueeze(0).repeat(4, 1, 1, 1) + +img = None + +def setup(): + global img + size(W, H) + img = create_image(W, H) + flush() + +def draw(): + t = frame_count * 0.02 + + no_stroke() + fill(255) + circle(W / 2 + math.cos(t) * 150, H / 2 + math.sin(t) * 150, 60) + + flush() + + tensor = torch.as_tensor(cuda(), device="cuda") + t_img = tensor.permute(2, 0, 1).unsqueeze(0).float() + blurred = F.conv2d(t_img, BLUR, padding=KERNEL_SIZE // 2, groups=4) + result = (blurred.squeeze(0).permute(1, 2, 0).clamp(0, 1) * 255).to(torch.uint8).contiguous() + img.update_from(result) + background(img) + +run() diff --git a/crates/processing_pyo3/pyproject.toml b/crates/processing_pyo3/pyproject.toml index 91dd072d..0f60a428 100644 --- a/crates/processing_pyo3/pyproject.toml +++ b/crates/processing_pyo3/pyproject.toml @@ -54,8 +54,9 @@ include = [ cache-keys = [ { file = "pyproject.toml" }, { file = "Cargo.toml" }, + { file = "../../Cargo.toml" }, { file = "src/**/*.rs" }, { file = "../../src/**/*.rs" }, - { file = "../processing_render/src/**/*.rs" }, - { file = "../processing_render/Cargo.toml" }, + { file = "../*/src/**/*.rs" }, + { file = "../*/Cargo.toml" }, ] diff --git a/crates/processing_pyo3/src/cuda.rs b/crates/processing_pyo3/src/cuda.rs new file mode 100644 index 00000000..e8064c20 --- /dev/null +++ b/crates/processing_pyo3/src/cuda.rs @@ -0,0 +1,59 @@ +use processing::prelude::image::pixel_size; +use processing_cuda::{cuda_buffer, cuda_write_back, typestr_for_format}; +use pyo3::{exceptions::PyRuntimeError, prelude::*, types::PyDict}; + +/// Implements `__cuda_array_interface__` for zero-copy interop +/// with PyTorch, CuPy, and other CUDA-aware Python libraries. +#[pyclass(unsendable)] +pub struct CudaImage { + entity: bevy::prelude::Entity, +} + +impl CudaImage { + pub fn new(entity: bevy::prelude::Entity) -> Self { + Self { entity } + } +} + +#[pymethods] +impl CudaImage { + pub fn sync(&self) -> PyResult<()> { + cuda_write_back(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } + + #[getter] + pub fn shape(&self) -> PyResult<(u32, u32, u32)> { + let info = cuda_buffer(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; + Ok((info.height, info.width, 4)) + } + + #[getter] + pub fn device_ptr(&self) -> PyResult { + let info = cuda_buffer(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; + Ok(info.device_ptr) + } + + #[getter] + pub fn __cuda_array_interface__<'py>(&self, py: Python<'py>) -> PyResult> { + let info = cuda_buffer(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; + + let typestr = typestr_for_format(info.texture_format) + .map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; + let px_size = + pixel_size(info.texture_format).map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; + + let height = info.height as usize; + let width = info.width as usize; + let channels: usize = 4; + let elem_size = px_size / channels; + + let dict = PyDict::new(py); + dict.set_item("data", (info.device_ptr, false))?; + dict.set_item("shape", (height, width, channels))?; + dict.set_item("typestr", typestr)?; + dict.set_item("strides", (width * px_size, px_size, elem_size))?; + dict.set_item("version", 3)?; + + Ok(dict) + } +} diff --git a/crates/processing_pyo3/src/graphics.rs b/crates/processing_pyo3/src/graphics.rs index 1107fde3..1d4ce31d 100644 --- a/crates/processing_pyo3/src/graphics.rs +++ b/crates/processing_pyo3/src/graphics.rs @@ -6,7 +6,7 @@ use bevy::{ color::{ColorToPacked, Srgba}, math::Vec4, prelude::Entity, - render::render_resource::TextureFormat, + render::render_resource::{Extent3d, TextureFormat}, }; use processing::prelude::*; use pyo3::{ @@ -15,6 +15,43 @@ use pyo3::{ types::{PyDict, PyTuple}, }; +#[cfg(feature = "cuda")] +use crate::cuda::CudaImage; + +#[cfg(feature = "cuda")] +fn cuda_import_from_interface( + entity: bevy::prelude::Entity, + obj: &pyo3::Bound<'_, pyo3::PyAny>, +) -> PyResult<()> { + let interface = obj + .getattr("__cuda_array_interface__")? + .cast_into::()?; + + let data_tuple: (u64, bool) = interface + .get_item("data")? + .ok_or_else(|| PyRuntimeError::new_err("missing 'data' in __cuda_array_interface__"))? + .extract()?; + let src_ptr = data_tuple.0; + + let shape: Vec = interface + .get_item("shape")? + .ok_or_else(|| PyRuntimeError::new_err("missing 'shape' in __cuda_array_interface__"))? + .extract()?; + + let typestr: String = interface + .get_item("typestr")? + .ok_or_else(|| PyRuntimeError::new_err("missing 'typestr' in __cuda_array_interface__"))? + .extract()?; + + let elem_size = processing_cuda::elem_size_for_typestr(&typestr) + .map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; + let total_elements: usize = shape.iter().product(); + let byte_size = (total_elements * elem_size) as u64; + + processing_cuda::cuda_import(entity, src_ptr, byte_size) + .map_err(|e| PyRuntimeError::new_err(format!("{e}"))) +} + #[pyclass(name = "BlendMode", from_py_object)] #[derive(Clone)] pub struct PyBlendMode { @@ -164,6 +201,20 @@ impl Drop for Image { } } +#[cfg(feature = "cuda")] +#[pymethods] +impl Image { + pub fn cuda(&self) -> PyResult { + processing_cuda::cuda_export(self.entity) + .map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; + Ok(CudaImage::new(self.entity)) + } + + pub fn update_from(&self, obj: &Bound<'_, pyo3::PyAny>) -> PyResult<()> { + cuda_import_from_interface(self.entity, obj) + } +} + #[pyclass(unsendable)] pub struct Geometry { pub(crate) entity: Entity, @@ -254,8 +305,6 @@ impl Geometry { pub struct Graphics { pub(crate) entity: Entity, pub surface: Surface, - pub width: u32, - pub height: u32, } impl Drop for Graphics { @@ -302,8 +351,6 @@ impl Graphics { Ok(Self { entity: graphics, surface, - width, - height, }) } @@ -339,8 +386,6 @@ impl Graphics { Ok(Self { entity: graphics, surface, - width, - height, }) } @@ -739,6 +784,18 @@ impl Graphics { } } + pub fn create_image(&self, width: u32, height: u32) -> PyResult { + let size = Extent3d { + width, + height, + depth_or_array_layers: 1, + }; + let data = vec![0u8; (width * height * 4) as usize]; + let entity = image_create(size, data, TextureFormat::Rgba8UnormSrgb) + .map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; + Ok(Image { entity }) + } + pub fn push_matrix(&self) -> PyResult<()> { graphics_record_command(self.entity, DrawCommand::PushMatrix) .map_err(|e| PyRuntimeError::new_err(format!("{e}"))) @@ -980,6 +1037,10 @@ impl Graphics { .map_err(|e| PyRuntimeError::new_err(format!("{e}"))) } + pub fn flush(&self) -> PyResult<()> { + graphics_flush(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } + pub fn begin_draw(&self) -> PyResult<()> { graphics_begin_draw(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}"))) } @@ -1195,6 +1256,20 @@ impl Graphics { } } +#[cfg(feature = "cuda")] +#[pymethods] +impl Graphics { + pub fn cuda(&self) -> PyResult { + processing_cuda::cuda_export(self.entity) + .map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; + Ok(CudaImage::new(self.entity)) + } + + pub fn update_from(&self, obj: &Bound<'_, pyo3::PyAny>) -> PyResult<()> { + cuda_import_from_interface(self.entity, obj) + } +} + pub fn get_graphics<'py>(module: &Bound<'py, PyModule>) -> PyResult>> { let Ok(attr) = module.getattr("_graphics") else { return Ok(None); diff --git a/crates/processing_pyo3/src/lib.rs b/crates/processing_pyo3/src/lib.rs index ffd56bb0..71362edc 100644 --- a/crates/processing_pyo3/src/lib.rs +++ b/crates/processing_pyo3/src/lib.rs @@ -9,6 +9,8 @@ //! To allow Python users to create a similar experience, we provide module-level //! functions that forward to a singleton Graphics object pub(crate) behind the scenes. pub(crate) mod color; +#[cfg(feature = "cuda")] +pub(crate) mod cuda; mod glfw; mod gltf; mod graphics; @@ -134,6 +136,9 @@ mod mewnala { use super::Shader; #[pymodule_export] use super::Topology; + #[cfg(feature = "cuda")] + #[pymodule_export] + use super::cuda::CudaImage; // Stroke cap/join #[pymodule_export] @@ -565,6 +570,31 @@ mod mewnala { graphics.readback_png().map(Some) } + #[pyfunction] + #[pyo3(pass_module)] + fn flush(module: &Bound<'_, PyModule>) -> PyResult<()> { + graphics!(module).flush() + } + + #[cfg(feature = "cuda")] + #[pyfunction] + #[pyo3(pass_module)] + fn cuda(module: &Bound<'_, PyModule>) -> PyResult { + let graphics = + get_graphics(module)?.ok_or_else(|| PyRuntimeError::new_err("call size() first"))?; + graphics.cuda() + } + + #[cfg(feature = "cuda")] + #[pyfunction] + #[pyo3(pass_module)] + fn update_graphics_from( + module: &Bound<'_, PyModule>, + obj: &Bound<'_, pyo3::PyAny>, + ) -> PyResult<()> { + graphics!(module).update_from(obj) + } + #[pyfunction] #[pyo3(pass_module)] fn redraw(module: &Bound<'_, PyModule>) -> PyResult<()> { @@ -673,13 +703,12 @@ mod mewnala { // call setup setup_fn.call0()?; + let mut frame_count: u64 = 0; { let graphics = get_graphics(module)? .ok_or_else(|| PyRuntimeError::new_err("call size() first"))?; input::sync_globals(&draw_fn, graphics.surface.entity)?; } - - // start draw loop loop { { let mut graphics = get_graphics_mut(module)? @@ -694,18 +723,13 @@ mod mewnala { let cstr: &CStr = ok.as_c_str(); match py.run(cstr, None, Some(&locals)) { - Ok(_) => { - dbg!("Success of any kind?"); - } + Ok(_) => {} Err(e) => { - dbg!(e); + eprintln!("sketch reload error: {e}"); } } - // setup_fn = locals.get_item("setup").unwrap().unwrap(); draw_fn = locals.get_item("draw").unwrap().unwrap(); - - dbg!(locals); } if !graphics.surface.poll_events() { @@ -718,6 +742,9 @@ mod mewnala { let graphics = get_graphics(module)? .ok_or_else(|| PyRuntimeError::new_err("call size() first"))?; input::sync_globals(&draw_fn, graphics.surface.entity)?; + let globals = draw_fn.getattr("__globals__")?; + globals.set_item("frame_count", frame_count)?; + frame_count += 1; } draw_fn @@ -967,6 +994,14 @@ mod mewnala { graphics.image(image_file) } + #[pyfunction] + #[pyo3(pass_module)] + fn create_image(module: &Bound<'_, PyModule>, width: u32, height: u32) -> PyResult { + let graphics = + get_graphics(module)?.ok_or_else(|| PyRuntimeError::new_err("call size() first"))?; + graphics.create_image(width, height) + } + #[pyfunction] #[pyo3(pass_module)] fn create_directional_light( diff --git a/crates/processing_render/src/graphics.rs b/crates/processing_render/src/graphics.rs index 1038d5a6..11bae9d3 100644 --- a/crates/processing_render/src/graphics.rs +++ b/crates/processing_render/src/graphics.rs @@ -9,18 +9,18 @@ use bevy::{ ImageRenderTarget, MsaaWriteback, Projection, RenderTarget, visibility::RenderLayers, }, core_pipeline::tonemapping::Tonemapping, - ecs::{entity::EntityHashMap, query::QueryEntityError}, + ecs::query::QueryEntityError, math::{Mat4, Vec3A}, prelude::*, render::{ - Render, RenderSystems, + RenderApp, render_resource::{ CommandEncoderDescriptor, Extent3d, MapMode, Origin3d, PollType, TexelCopyBufferInfo, - TexelCopyBufferLayout, TexelCopyTextureInfo, TextureFormat, TextureUsages, + TexelCopyBufferLayout, TexelCopyTextureInfo, Texture, TextureFormat, TextureUsages, }, renderer::{RenderDevice, RenderQueue}, sync_world::MainEntity, - view::{ViewTarget, prepare_view_targets}, + view::ViewTarget, }, window::WindowRef, }; @@ -41,21 +41,6 @@ pub struct GraphicsPlugin; impl Plugin for GraphicsPlugin { fn build(&self, app: &mut App) { app.init_resource::(); - - let (tx, rx) = crossbeam_channel::unbounded::<(Entity, ViewTarget)>(); - app.init_resource::() - .insert_resource(GraphicsTargetReceiver(rx)) - .add_systems(First, update_view_targets); - - let render_app = app.sub_app_mut(bevy::render::RenderApp); - render_app - .add_systems( - Render, - send_view_targets - .in_set(RenderSystems::PrepareViews) - .after(prepare_view_targets), - ) - .insert_resource(GraphicsTargetSender(tx)); } } @@ -66,36 +51,15 @@ pub struct Graphics { pub size: Extent3d, } -// We store a mapping of graphics target entities to their GPU `ViewTarget`s. In the -// Processing API, graphics *are* images, so we need to be able to look up the `ViewTarget` for a -// given graphics entity when referencing it as an image. -#[derive(Resource, Deref, DerefMut, Default)] -pub struct GraphicsTargets(EntityHashMap); - -#[derive(Resource, Deref, DerefMut)] -pub struct GraphicsTargetReceiver(crossbeam_channel::Receiver<(Entity, ViewTarget)>); - -#[derive(Resource, Deref, DerefMut)] -pub struct GraphicsTargetSender(crossbeam_channel::Sender<(Entity, ViewTarget)>); - -fn send_view_targets( - view_targets: Query<(MainEntity, &ViewTarget), Changed>, - sender: Res, -) { - for (main_entity, view_target) in view_targets.iter() { - sender - .send((main_entity, view_target.clone())) - .expect("Failed to send updated view target"); - } -} - -pub fn update_view_targets( - mut graphics_targets: ResMut, - receiver: Res, -) { - while let Ok((entity, view_target)) = receiver.0.try_recv() { - graphics_targets.insert(entity, view_target); +pub fn view_target(app: &mut App, entity: Entity) -> Result<&ViewTarget> { + let rw = app.sub_app_mut(RenderApp).world_mut(); + let mut query = rw.query::<(&MainEntity, &ViewTarget)>(); + for (main_entity, vt) in query.iter(rw) { + if **main_entity == entity { + return Ok(vt); + } } + Err(ProcessingError::GraphicsNotFound) } macro_rules! graphics_mut { @@ -440,10 +404,6 @@ pub fn flush(app: &mut App, entity: Entity) -> Result<()> { graphics_mut!(app, entity).insert(Flush); app.update(); graphics_mut!(app, entity).remove::(); - // ensure graphics targets are available immediately after flush - app.world_mut() - .run_system_cached(update_view_targets) - .expect("Failed to run update_view_targets"); Ok(()) } @@ -489,9 +449,8 @@ pub struct ReadbackData { } pub fn readback_raw( - In(entity): In, + In((entity, texture)): In<(Entity, Texture)>, graphics_query: Query<&Graphics>, - graphics_targets: Res, render_device: Res, render_queue: Res, ) -> Result { @@ -499,12 +458,6 @@ pub fn readback_raw( .get(entity) .map_err(|_| ProcessingError::GraphicsNotFound)?; - let view_target = graphics_targets - .get(&entity) - .ok_or(ProcessingError::GraphicsNotFound)?; - - let texture = view_target.main_texture(); - let mut encoder = render_device.create_command_encoder(&CommandEncoderDescriptor::default()); let px_size = pixel_size(graphics.texture_format)?; @@ -570,8 +523,9 @@ pub fn readback_raw( } pub fn update_region_write( - In((entity, x, y, width, height, data, px_size)): In<( + In((entity, texture, x, y, width, height, data, px_size)): In<( Entity, + Texture, u32, u32, u32, @@ -580,7 +534,6 @@ pub fn update_region_write( u32, )>, graphics_query: Query<&Graphics>, - graphics_targets: Res, render_queue: Res, ) -> Result<()> { let graphics = graphics_query @@ -594,17 +547,11 @@ pub fn update_region_write( x, y, width, height, graphics.size.width, graphics.size.height ))); } - - let view_target = graphics_targets - .get(&entity) - .ok_or(ProcessingError::GraphicsNotFound)?; - - let texture = view_target.main_texture(); let bytes_per_row = width * px_size; render_queue.write_texture( TexelCopyTextureInfo { - texture, + texture: &texture, mip_level: 0, origin: Origin3d { x, y, z: 0 }, aspect: Default::default(), diff --git a/crates/processing_render/src/image.rs b/crates/processing_render/src/image.rs index 60f64c0f..9a4d558b 100644 --- a/crates/processing_render/src/image.rs +++ b/crates/processing_render/src/image.rs @@ -8,11 +8,11 @@ use bevy::{ AssetPath, LoadState, RenderAssetUsages, handle_internal_asset_events, io::{AssetSourceId, embedded::GetAssetServer}, }, - ecs::{entity::EntityHashMap, system::RunSystemOnce}, + ecs::system::RunSystemOnce, prelude::*, render::{ - ExtractSchedule, MainWorld, - render_asset::{AssetExtractionSystems, RenderAssets}, + RenderApp, + render_asset::RenderAssets, render_resource::{ Buffer, BufferDescriptor, BufferUsages, CommandEncoderDescriptor, Extent3d, MapMode, Origin3d, PollType, TexelCopyBufferInfo, TexelCopyBufferLayout, TexelCopyTextureInfo, @@ -30,21 +30,9 @@ use processing_core::error::{ProcessingError, Result}; pub struct ImagePlugin; impl Plugin for ImagePlugin { - fn build(&self, app: &mut App) { - app.init_resource::(); - - let render_app = app.sub_app_mut(bevy::render::RenderApp); - render_app.add_systems(ExtractSchedule, sync_textures.after(AssetExtractionSystems)); - } + fn build(&self, _app: &mut App) {} } -// In Bevy, `Image` is a `RenderResource`, which means its descriptor is stored in the main world -// but its GPU texture is stored in the render world. To avoid tedious lookups or the need to -// explicitly reference the render world, we store a mapping of `PImage` entities to their -// corresponding GPU `Texture` in the main world. This is as bit hacky, but it simplifies the API. -#[derive(Resource, Deref, DerefMut, Default)] -pub struct ImageTextures(EntityHashMap); - #[derive(Component)] pub struct Image { pub handle: Handle, @@ -53,17 +41,6 @@ pub struct Image { pub size: Extent3d, } -fn sync_textures(mut main_world: ResMut, gpu_images: Res>) { - main_world.resource_scope(|world, mut p_image_textures: Mut| { - let mut p_images = world.query_filtered::<(Entity, &Image), Changed>(); - for (entity, p_image) in p_images.iter(world) { - if let Some(gpu_image) = gpu_images.get(&p_image.handle) { - p_image_textures.insert(entity, gpu_image.texture.clone()); - } - } - }); -} - pub fn create( In((size, data, texture_format)): In<(Extent3d, Vec, TextureFormat)>, mut commands: Commands, @@ -208,9 +185,8 @@ pub fn resize( } pub fn readback( - In(entity): In, + In((entity, texture)): In<(Entity, Texture)>, p_images: Query<&Image>, - p_image_textures: Res, mut images: ResMut>, render_device: Res, render_queue: ResMut, @@ -218,9 +194,6 @@ pub fn readback( let p_image = p_images .get(entity) .map_err(|_| ProcessingError::ImageNotFound)?; - let texture = p_image_textures - .get(&entity) - .ok_or(ProcessingError::ImageNotFound)?; let mut encoder = render_device.create_command_encoder(&CommandEncoderDescriptor::default()); @@ -281,8 +254,9 @@ pub fn readback( } pub fn update_region_write( - In((entity, x, y, width, height, data, px_size)): In<( + In((entity, texture, x, y, width, height, data, px_size)): In<( Entity, + Texture, u32, u32, u32, @@ -291,7 +265,6 @@ pub fn update_region_write( u32, )>, p_images: Query<&Image>, - p_image_textures: Res, render_queue: Res, ) -> Result<()> { let p_image = p_images @@ -305,15 +278,11 @@ pub fn update_region_write( ))); } - let texture = p_image_textures - .get(&entity) - .ok_or(ProcessingError::ImageNotFound)?; - let bytes_per_row = width * px_size; render_queue.write_texture( TexelCopyTextureInfo { - texture, + texture: &texture, mip_level: 0, origin: Origin3d { x, y, z: 0 }, aspect: Default::default(), @@ -365,13 +334,11 @@ pub fn destroy( In(entity): In, mut commands: Commands, p_images: Query<&Image>, - mut p_image_textures: ResMut, ) -> Result<()> { p_images .get(entity) .map_err(|_| ProcessingError::ImageNotFound)?; - p_image_textures.remove(&entity); commands.entity(entity).despawn(); Ok(()) } @@ -498,3 +465,18 @@ pub fn create_readback_buffer( mapped_at_creation: false, })) } + +pub fn gpu_image(app: &mut App, entity: Entity) -> Result<&GpuImage> { + let handle = app + .world() + .get::(entity) + .ok_or(ProcessingError::ImageNotFound)? + .handle + .clone(); + let render_world = app.sub_app(RenderApp).world(); + let gpu_images = render_world.resource::>(); + let gpu_image = gpu_images + .get(&handle) + .ok_or(ProcessingError::ImageNotFound)?; + Ok(gpu_image) +} diff --git a/crates/processing_render/src/lib.rs b/crates/processing_render/src/lib.rs index 11ceecdf..09200675 100644 --- a/crates/processing_render/src/lib.rs +++ b/crates/processing_render/src/lib.rs @@ -4,7 +4,7 @@ pub mod camera; pub mod color; pub mod geometry; pub mod gltf; -mod graphics; +pub mod graphics; pub mod image; pub mod light; pub mod material; @@ -26,6 +26,7 @@ use processing_core::error; use crate::geometry::{AttributeFormat, AttributeValue}; use crate::graphics::flush; +use crate::image::gpu_image; use crate::render::command::DrawCommand; #[derive(Component)] @@ -302,8 +303,10 @@ pub fn graphics_destroy(graphics_entity: Entity) -> error::Result<()> { pub fn graphics_readback_raw(graphics_entity: Entity) -> error::Result { app_mut(|app| { graphics::flush(app, graphics_entity)?; + let vt = graphics::view_target(app, graphics_entity)?; + let texture = vt.main_texture().clone(); app.world_mut() - .run_system_cached_with(graphics::readback_raw, graphics_entity) + .run_system_cached_with(graphics::readback_raw, (graphics_entity, texture)) .unwrap() }) } @@ -325,6 +328,8 @@ pub fn graphics_readback(graphics_entity: Entity) -> error::Result error::Result<()> { app_mut(|app| { + let vt = graphics::view_target(app, graphics_entity)?; + let texture = vt.main_texture().clone(); let world = app.world_mut(); let size = world .get::(graphics_entity) @@ -342,6 +347,7 @@ pub fn graphics_update(graphics_entity: Entity, pixels: &[LinearRgba]) -> error: graphics::update_region_write, ( graphics_entity, + texture, 0, 0, size.width, @@ -364,13 +370,15 @@ pub fn graphics_update_region( pixels: &[LinearRgba], ) -> error::Result<()> { app_mut(|app| { + let vt = graphics::view_target(app, graphics_entity)?; + let texture = vt.main_texture().clone(); let world = app.world_mut(); let (data, px_size) = graphics::prepare_update_region(world, graphics_entity, width, height, pixels)?; world .run_system_cached_with( graphics::update_region_write, - (graphics_entity, x, y, width, height, data, px_size), + (graphics_entity, texture, x, y, width, height, data, px_size), ) .unwrap() }) @@ -733,8 +741,9 @@ pub fn image_resize(entity: Entity, new_size: Extent3d) -> error::Result<()> { /// Read back image data from GPU to CPU. pub fn image_readback(entity: Entity) -> error::Result> { app_mut(|app| { + let texture = gpu_image(app, entity)?.texture.clone(); app.world_mut() - .run_system_cached_with(image::readback, entity) + .run_system_cached_with(image::readback, (entity, texture)) .unwrap() }) } @@ -742,6 +751,7 @@ pub fn image_readback(entity: Entity) -> error::Result> { /// Update an existing image with new pixel data. pub fn image_update(entity: Entity, pixels: &[LinearRgba]) -> error::Result<()> { app_mut(|app| { + let texture = gpu_image(app, entity)?.texture.clone(); let world = app.world_mut(); let size = world .get::(entity) @@ -752,7 +762,16 @@ pub fn image_update(entity: Entity, pixels: &[LinearRgba]) -> error::Result<()> world .run_system_cached_with( image::update_region_write, - (entity, 0, 0, size.width, size.height, data, px_size), + ( + entity, + texture, + 0, + 0, + size.width, + size.height, + data, + px_size, + ), ) .unwrap() }) @@ -768,12 +787,13 @@ pub fn image_update_region( pixels: &[LinearRgba], ) -> error::Result<()> { app_mut(|app| { + let texture = gpu_image(app, entity)?.texture.clone(); let world = app.world_mut(); let (data, px_size) = image::prepare_update_region(world, entity, width, height, pixels)?; world .run_system_cached_with( image::update_region_write, - (entity, x, y, width, height, data, px_size), + (entity, texture, x, y, width, height, data, px_size), ) .unwrap() }) diff --git a/crates/processing_render/src/surface.rs b/crates/processing_render/src/surface.rs index afeee6fc..bbda9d53 100644 --- a/crates/processing_render/src/surface.rs +++ b/crates/processing_render/src/surface.rs @@ -35,7 +35,7 @@ use processing_core::error::{self, ProcessingError, Result}; #[cfg(not(target_os = "windows"))] use std::ptr::NonNull; -use crate::image::{Image, ImageTextures}; +use crate::image::Image; #[derive(Component, Debug, Clone)] pub struct Surface; @@ -341,12 +341,10 @@ pub fn destroy( mut commands: Commands, p_images: Query<&Image, With>, mut images: ResMut>, - mut p_image_textures: ResMut, ) -> Result<()> { match p_images.get(surface_entity) { Ok(p_image) => { images.remove(&p_image.handle); - p_image_textures.remove(&surface_entity); commands.entity(surface_entity).despawn(); Ok(()) } diff --git a/justfile b/justfile index cb036666..4af5b1d1 100644 --- a/justfile +++ b/justfile @@ -5,20 +5,20 @@ export PROCESSING_ASSET_ROOT := canonicalize("./assets") default: @just --list -py-build: - cd crates/processing_pyo3; uv run maturin develop --release +py-build *args: + cd crates/processing_pyo3; uv run maturin develop --release {{args}} py-stubs: py-build cargo run --release -p generate_stubs -py-run file: py-build +py-run file *args: (py-build args) cd crates/processing_pyo3; uv run python ./examples/{{file}} py-jupyter file: py-build cd crates/processing_pyo3; uv run jupyter notebook ./examples/{{file}} py-ipython: py-build - cd crates/processing_pyo3; ipython + cd crates/processing_pyo3; uv run ipython docs-serve: py-stubs uv run --project crates/processing_pyo3 --group docs mkdocs serve diff --git a/src/lib.rs b/src/lib.rs index b71988f1..55e36785 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,6 +46,9 @@ fn create_app(config: Config) -> App { app.add_plugins(processing_input::InputPlugin); app.add_plugins(processing_render::ProcessingRenderPlugin); + #[cfg(feature = "cuda")] + app.add_plugins(processing_cuda::CudaPlugin); + #[cfg(feature = "webcam")] app.add_plugins(processing_webcam::WebcamPlugin); @@ -128,6 +131,9 @@ pub fn exit(exit_code: u8) -> error::Result<()> { Ok(()) } +#[cfg(feature = "cuda")] +pub use processing_cuda; + fn setup_tracing(log_level: Option<&str>) -> error::Result<()> { // TODO: figure out wasm compatible tracing subscriber #[cfg(not(target_arch = "wasm32"))] From ff82009f1ad7f08713a0b6c9dbd43a28dae3badb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Tue, 21 Apr 2026 19:51:32 -0700 Subject: [PATCH 07/15] Fix compilation fearures on macos. --- Cargo.toml | 2 +- crates/processing_cuda/Cargo.toml | 6 +++--- crates/processing_cuda/src/lib.rs | 2 ++ crates/processing_pyo3/Cargo.toml | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5ad01ba4..da1c6254 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ default = ["wayland"] wayland = ["processing_render/wayland"] x11 = ["processing_render/x11"] webcam = ["dep:processing_webcam"] -cuda = ["dep:processing_cuda"] +cuda = ["dep:processing_cuda", "processing_cuda/cuda"] [workspace] resolver = "3" diff --git a/crates/processing_cuda/Cargo.toml b/crates/processing_cuda/Cargo.toml index 01310f29..72896dcd 100644 --- a/crates/processing_cuda/Cargo.toml +++ b/crates/processing_cuda/Cargo.toml @@ -7,11 +7,11 @@ edition = "2024" workspace = true [features] -default = ["cuda-11040"] -cuda-11040 = ["bevy_cuda/cuda-11040"] +default = [] +cuda = ["dep:bevy_cuda", "bevy_cuda/cuda-11040"] [dependencies] bevy = { workspace = true } -bevy_cuda = { workspace = true } +bevy_cuda = { workspace = true, optional = true } processing_core = { workspace = true } processing_render = { workspace = true } diff --git a/crates/processing_cuda/src/lib.rs b/crates/processing_cuda/src/lib.rs index e83a3759..8f970b99 100644 --- a/crates/processing_cuda/src/lib.rs +++ b/crates/processing_cuda/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "cuda")] + use bevy::prelude::*; use bevy::render::RenderApp; use bevy::render::render_resource::{Texture, TextureFormat}; diff --git a/crates/processing_pyo3/Cargo.toml b/crates/processing_pyo3/Cargo.toml index adddc4f6..d55b9f12 100644 --- a/crates/processing_pyo3/Cargo.toml +++ b/crates/processing_pyo3/Cargo.toml @@ -16,7 +16,7 @@ wayland = ["processing/wayland", "processing_glfw/wayland"] static-link = ["processing_glfw/static-link"] x11 = ["processing/x11"] webcam = ["processing/webcam", "dep:processing_webcam"] -cuda = ["dep:processing_cuda", "processing/cuda"] +cuda = ["dep:processing_cuda", "processing_cuda/cuda", "processing/cuda"] [dependencies] pyo3 = { workspace = true, features = ["experimental-inspect", "multiple-pymethods"] } From 4e433c1b2bb580e7f67f1b7fb0b017ca4fdd2741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Tue, 21 Apr 2026 23:07:04 -0700 Subject: [PATCH 08/15] DPI and color fixes (#122) --- crates/processing_glfw/src/lib.rs | 12 ++-- crates/processing_pyo3/src/graphics.rs | 13 ++++ crates/processing_pyo3/src/lib.rs | 14 ++++ crates/processing_render/src/graphics.rs | 64 ++++++++++++++++--- crates/processing_render/src/lib.rs | 8 +++ .../src/render/mesh_builder.rs | 2 +- crates/processing_render/src/render/mod.rs | 5 ++ .../src/render/primitive/quad.rs | 2 +- .../src/render/primitive/rect.rs | 2 +- .../src/render/primitive/shape.rs | 4 +- .../src/render/primitive/triangle.rs | 2 +- crates/processing_render/src/surface.rs | 27 +++++++- 12 files changed, 132 insertions(+), 23 deletions(-) diff --git a/crates/processing_glfw/src/lib.rs b/crates/processing_glfw/src/lib.rs index 740762b5..975ddd9e 100644 --- a/crates/processing_glfw/src/lib.rs +++ b/crates/processing_glfw/src/lib.rs @@ -14,7 +14,6 @@ pub struct GlfwContext { window: PWindow, events: GlfwReceiver<(f64, WindowEvent)>, surface: Option, - scale_factor: f32, } impl GlfwContext { @@ -31,14 +30,11 @@ impl GlfwContext { window.set_all_polling(true); window.show(); - let (scale_factor, _) = window.get_content_scale(); - Ok(Self { glfw, window, events, surface: None, - scale_factor, }) } @@ -127,8 +123,7 @@ impl GlfwContext { return false; } WindowEvent::CursorPos(x, y) => { - let s = self.scale_factor; - input_set_mouse_move(surface, x as f32 / s, y as f32 / s).unwrap(); + input_set_mouse_move(surface, x as f32, y as f32).unwrap(); } WindowEvent::MouseButton(button, action, _mods) => { if let Some(btn) = glfw_button_to_bevy(button) { @@ -182,6 +177,11 @@ impl GlfwContext { true } + pub fn content_scale(&self) -> f32 { + let (s, _) = self.window.get_content_scale(); + s + } + fn sync_cursor(&mut self, surface: Entity) { use bevy::window::CursorGrabMode; diff --git a/crates/processing_pyo3/src/graphics.rs b/crates/processing_pyo3/src/graphics.rs index 1d4ce31d..5b0dbc9c 100644 --- a/crates/processing_pyo3/src/graphics.rs +++ b/crates/processing_pyo3/src/graphics.rs @@ -146,6 +146,19 @@ impl Surface { None => true, // no-op, offscreen surfaces never close } } + + #[getter] + pub fn display_density(&self) -> PyResult { + match &self.glfw_ctx { + Some(ctx) => Ok(ctx.content_scale()), + None => Ok(1.0), + } + } + + pub fn set_pixel_density(&self, density: f32) -> PyResult<()> { + surface_set_pixel_density(self.entity, density) + .map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } } impl Drop for Surface { diff --git a/crates/processing_pyo3/src/lib.rs b/crates/processing_pyo3/src/lib.rs index 71362edc..01ddce9f 100644 --- a/crates/processing_pyo3/src/lib.rs +++ b/crates/processing_pyo3/src/lib.rs @@ -1432,4 +1432,18 @@ mod mewnala { fn key_just_pressed(key_code: u32) -> PyResult { input::key_just_pressed(key_code) } + + #[pyfunction] + #[pyo3(pass_module)] + fn pixel_density(module: &Bound<'_, PyModule>, density: f32) -> PyResult<()> { + graphics!(module).surface.set_pixel_density(density) + } + + #[pyfunction] + #[pyo3(pass_module)] + fn display_density(module: &Bound<'_, PyModule>) -> PyResult { + let graphics = + get_graphics(module)?.ok_or_else(|| PyRuntimeError::new_err("call size() first"))?; + graphics.surface.display_density() + } } diff --git a/crates/processing_render/src/graphics.rs b/crates/processing_render/src/graphics.rs index 11bae9d3..da99aae0 100644 --- a/crates/processing_render/src/graphics.rs +++ b/crates/processing_render/src/graphics.rs @@ -40,7 +40,8 @@ pub struct GraphicsPlugin; impl Plugin for GraphicsPlugin { fn build(&self, app: &mut App) { - app.init_resource::(); + app.init_resource::() + .add_systems(PostUpdate, sync_to_surface); } } @@ -149,14 +150,26 @@ pub fn create( mut commands: Commands, mut layer_manager: ResMut, p_images: Query<&Image, With>, + windows: Query<&Window, With>, render_device: Res, ) -> Result { // find the surface entity, if it is an image, we will render to that image // otherwise we will render to the window - let target = match p_images.get(surface_entity) { - Ok(p_image) => RenderTarget::Image(ImageRenderTarget::from(p_image.handle.clone())), + let (target, physical_width, physical_height) = match p_images.get(surface_entity) { + Ok(p_image) => ( + RenderTarget::Image(ImageRenderTarget::from(p_image.handle.clone())), + p_image.size.width, + p_image.size.height, + ), Err(QueryEntityError::QueryDoesNotMatch(..)) => { - RenderTarget::Window(WindowRef::Entity(surface_entity)) + let window = windows + .get(surface_entity) + .map_err(|_| ProcessingError::SurfaceNotFound)?; + ( + RenderTarget::Window(WindowRef::Entity(surface_entity)), + window.resolution.physical_width(), + window.resolution.physical_height(), + ) } Err(_) => return Err(ProcessingError::SurfaceNotFound), }; @@ -165,14 +178,14 @@ pub fn create( let render_layer = layer_manager.allocate(); let size = Extent3d { - width, - height, + width: physical_width, + height: physical_height, depth_or_array_layers: 1, }; let readback_buffer = create_readback_buffer( &render_device, - width, - height, + physical_width, + physical_height, texture_format, "Graphics Readback Buffer", ) @@ -241,6 +254,39 @@ pub fn resize( } } +pub fn sync_to_surface( + mut graphics_query: Query<(&mut Graphics, &RenderTarget)>, + windows: Query<&Window, (With, Changed)>, + render_device: Res, +) { + for (mut graphics, target) in graphics_query.iter_mut() { + let RenderTarget::Window(WindowRef::Entity(surface_entity)) = *target else { + continue; + }; + let Ok(window) = windows.get(surface_entity) else { + continue; + }; + let physical_w = window.resolution.physical_width(); + let physical_h = window.resolution.physical_height(); + if graphics.size.width == physical_w && graphics.size.height == physical_h { + continue; + } + graphics.size = Extent3d { + width: physical_w, + height: physical_h, + depth_or_array_layers: 1, + }; + graphics.readback_buffer = create_readback_buffer( + &render_device, + physical_w, + physical_h, + graphics.texture_format, + "Graphics Readback Buffer", + ) + .expect("Failed to reallocate readback buffer"); + } +} + pub fn mode_3d( In(entity): In, mut projections: Query<&mut Projection>, @@ -396,7 +442,7 @@ pub fn begin_draw(In(entity): In, mut state_query: Query<&mut RenderStat let mut state = state_query .get_mut(entity) .map_err(|_| ProcessingError::GraphicsNotFound)?; - state.reset(); + state.begin_frame(); Ok(()) } diff --git a/crates/processing_render/src/lib.rs b/crates/processing_render/src/lib.rs index 09200675..f2dd7679 100644 --- a/crates/processing_render/src/lib.rs +++ b/crates/processing_render/src/lib.rs @@ -249,6 +249,14 @@ pub fn surface_resize(graphics_entity: Entity, width: u32, height: u32) -> error }) } +pub fn surface_set_pixel_density(entity: Entity, density: f32) -> error::Result<()> { + app_mut(|app| { + app.world_mut() + .run_system_cached_with(surface::set_pixel_density, (entity, density)) + .unwrap() + }) +} + /// Create a new graphics surface for rendering. pub fn graphics_create( surface_entity: Entity, diff --git a/crates/processing_render/src/render/mesh_builder.rs b/crates/processing_render/src/render/mesh_builder.rs index 84665e37..a3aa1563 100644 --- a/crates/processing_render/src/render/mesh_builder.rs +++ b/crates/processing_render/src/render/mesh_builder.rs @@ -36,7 +36,7 @@ impl<'a> MeshBuilder<'a> { if let Some(VertexAttributeValues::Float32x4(colors)) = self.mesh.attribute_mut(Mesh::ATTRIBUTE_COLOR) { - colors.push(self.color.to_srgba().to_f32_array()); + colors.push(self.color.to_linear().to_f32_array()); } if let Some(VertexAttributeValues::Float32x3(normals)) = diff --git a/crates/processing_render/src/render/mod.rs b/crates/processing_render/src/render/mod.rs index 669de540..4f739229 100644 --- a/crates/processing_render/src/render/mod.rs +++ b/crates/processing_render/src/render/mod.rs @@ -122,6 +122,11 @@ impl RenderState { self.shape_builder = None; } + pub fn begin_frame(&mut self) { + self.transform = TransformStack::new(); + self.shape_builder = None; + } + pub fn fill_is_transparent(&self) -> bool { self.fill_color.map(|c| c.alpha() < 1.0).unwrap_or(false) } diff --git a/crates/processing_render/src/render/primitive/quad.rs b/crates/processing_render/src/render/primitive/quad.rs index 2c894868..6550d049 100644 --- a/crates/processing_render/src/render/primitive/quad.rs +++ b/crates/processing_render/src/render/primitive/quad.rs @@ -70,7 +70,7 @@ fn simple_quad( if let Some(VertexAttributeValues::Float32x4(colors)) = mesh.attribute_mut(Mesh::ATTRIBUTE_COLOR) { - let color_array = color.to_srgba().to_f32_array(); + let color_array = color.to_linear().to_f32_array(); for _ in 0..4 { colors.push(color_array); } diff --git a/crates/processing_render/src/render/primitive/rect.rs b/crates/processing_render/src/render/primitive/rect.rs index 36decaa7..d989612b 100644 --- a/crates/processing_render/src/render/primitive/rect.rs +++ b/crates/processing_render/src/render/primitive/rect.rs @@ -87,7 +87,7 @@ fn simple_rect(mesh: &mut Mesh, x: f32, y: f32, w: f32, h: f32, color: Color) { if let Some(VertexAttributeValues::Float32x4(colors)) = mesh.attribute_mut(Mesh::ATTRIBUTE_COLOR) { - let color_array = color.to_srgba().to_f32_array(); + let color_array = color.to_linear().to_f32_array(); for _ in 0..4 { colors.push(color_array); } diff --git a/crates/processing_render/src/render/primitive/shape.rs b/crates/processing_render/src/render/primitive/shape.rs index 5b968aad..ff5674a7 100644 --- a/crates/processing_render/src/render/primitive/shape.rs +++ b/crates/processing_render/src/render/primitive/shape.rs @@ -497,7 +497,7 @@ fn push_triangle( positions.push([x3, y3, 0.0]); } - let color_array = color.to_srgba().to_f32_array(); + let color_array = color.to_linear().to_f32_array(); if let Some(VertexAttributeValues::Float32x4(colors)) = mesh.attribute_mut(Mesh::ATTRIBUTE_COLOR) { @@ -556,7 +556,7 @@ fn push_quad( positions.push([x4, y4, 0.0]); } - let color_array = color.to_srgba().to_f32_array(); + let color_array = color.to_linear().to_f32_array(); if let Some(VertexAttributeValues::Float32x4(colors)) = mesh.attribute_mut(Mesh::ATTRIBUTE_COLOR) { diff --git a/crates/processing_render/src/render/primitive/triangle.rs b/crates/processing_render/src/render/primitive/triangle.rs index 3de05290..5b66b479 100644 --- a/crates/processing_render/src/render/primitive/triangle.rs +++ b/crates/processing_render/src/render/primitive/triangle.rs @@ -64,7 +64,7 @@ fn simple_triangle( if let Some(VertexAttributeValues::Float32x4(colors)) = mesh.attribute_mut(Mesh::ATTRIBUTE_COLOR) { - let color_array = color.to_srgba().to_f32_array(); + let color_array = color.to_linear().to_f32_array(); for _ in 0..3 { colors.push(color_array); } diff --git a/crates/processing_render/src/surface.rs b/crates/processing_render/src/surface.rs index bbda9d53..20f46d39 100644 --- a/crates/processing_render/src/surface.rs +++ b/crates/processing_render/src/surface.rs @@ -94,10 +94,13 @@ fn spawn_surface( let window_wrapper = WindowWrapper::new(glfw_window); let handle_wrapper = RawHandleWrapper::new(&window_wrapper)?; + let physical_width = (width as f32 * scale_factor) as u32; + let physical_height = (height as f32 * scale_factor) as u32; + Ok(commands .spawn(( Window { - resolution: WindowResolution::new(width, height) + resolution: WindowResolution::new(physical_width, physical_height) .with_scale_factor_override(scale_factor), ..default() }, @@ -362,8 +365,28 @@ pub fn resize( mut windows: Query<&mut Window>, ) -> Result<()> { if let Ok(mut window) = windows.get_mut(window_entity) { - window.resolution.set_physical_resolution(width, height); + let scale = window.resolution.scale_factor(); + let physical_w = (width as f32 * scale) as u32; + let physical_h = (height as f32 * scale) as u32; + window.resolution.set_physical_resolution(physical_w, physical_h); + Ok(()) + } else { + Err(error::ProcessingError::SurfaceNotFound) + } +} +pub fn set_pixel_density( + In((window_entity, density)): In<(Entity, f32)>, + mut windows: Query<&mut Window>, +) -> Result<()> { + if let Ok(mut window) = windows.get_mut(window_entity) { + let logical_w = window.resolution.width(); + let logical_h = window.resolution.height(); + window.resolution.set_scale_factor_override(Some(density)); + window.resolution.set_physical_resolution( + (logical_w * density) as u32, + (logical_h * density) as u32, + ); Ok(()) } else { Err(error::ProcessingError::SurfaceNotFound) From 56736ea0c8820da7af5098046d007c2b1004b76b Mon Sep 17 00:00:00 2001 From: Moon Date: Wed, 22 Apr 2026 10:56:55 +0200 Subject: [PATCH 09/15] Update README.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6e6d8c3d..2708b475 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,11 @@ just wasm-serve ## Contributing -We want your help building this library! You can see a list of outstanding tasks in our [issues](https://github.com/processing/libprocessing). However, while we're still in the early phases, consider checking in with us first in the `#devs-chat` channel on [Discord](https://discord.gg/h99u95nU7q) to coordinate our efforts. +We want your help building this library! + +One place we could really use some help is with porting Processing examples to using mewnala, and then reporting where you get stuck or where things could be easier. Check out the effort here: https://github.com/processing/processing-examples-mewnala. + + +You can see a list of outstanding tasks in our [issues](https://github.com/processing/libprocessing). However, while we're still in the early phases, consider checking in with us first in the `#devs-chat` channel on [Discord](https://discord.gg/h99u95nU7q) to coordinate our efforts. You can read our project design principles [here](./docs/principles.md). From 73b6fadaaa4949fca13872920b2f0ea1d713e351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Wed, 22 Apr 2026 02:20:08 -0700 Subject: [PATCH 10/15] Add globals and callback handling (#120) --- crates/processing_input/src/lib.rs | 44 +++++ crates/processing_input/src/state.rs | 24 ++- crates/processing_pyo3/mewnala/__init__.py | 64 ++++++- crates/processing_pyo3/src/graphics.rs | 63 ++++--- crates/processing_pyo3/src/input.rs | 28 +-- crates/processing_pyo3/src/lib.rs | 164 ++++++++++++++++-- crates/processing_pyo3/src/monitor.rs | 50 ++++++ .../src/python/ipython_post_execute.py | 10 +- .../src/python/jupyter_post_execute.py | 7 +- .../src/python/register_inputhook.py | 11 +- crates/processing_pyo3/src/surface.rs | 84 +++++++++ crates/processing_pyo3/src/time.rs | 20 +++ crates/processing_render/src/lib.rs | 113 ++++++++++++ crates/processing_render/src/monitor.rs | 33 ++++ crates/processing_render/src/surface.rs | 25 +++ crates/processing_render/src/time.rs | 15 ++ 16 files changed, 675 insertions(+), 80 deletions(-) create mode 100644 crates/processing_pyo3/src/monitor.rs create mode 100644 crates/processing_pyo3/src/surface.rs create mode 100644 crates/processing_pyo3/src/time.rs create mode 100644 crates/processing_render/src/monitor.rs create mode 100644 crates/processing_render/src/time.rs diff --git a/crates/processing_input/src/lib.rs b/crates/processing_input/src/lib.rs index 38f74e86..9452d989 100644 --- a/crates/processing_input/src/lib.rs +++ b/crates/processing_input/src/lib.rs @@ -295,3 +295,47 @@ pub fn input_key() -> error::Result> { pub fn input_key_code() -> error::Result> { app_mut(|app| Ok(app.world().resource::().code)) } + +pub fn input_mouse_any_just_pressed() -> error::Result { + app_mut(|app| { + Ok(app + .world() + .resource::>() + .get_just_pressed() + .next() + .is_some()) + }) +} + +pub fn input_mouse_any_just_released() -> error::Result { + app_mut(|app| { + Ok(app + .world() + .resource::>() + .get_just_released() + .next() + .is_some()) + }) +} + +pub fn input_key_any_just_pressed() -> error::Result { + app_mut(|app| Ok(app.world().resource::().just_pressed)) +} + +pub fn input_key_any_just_released() -> error::Result { + app_mut(|app| Ok(app.world().resource::().just_released)) +} + +pub fn input_mouse_moved() -> error::Result { + app_mut(|app| { + let d = app.world().resource::().delta; + Ok(d.x != 0.0 || d.y != 0.0) + }) +} + +pub fn input_mouse_scrolled() -> error::Result { + app_mut(|app| { + let d = app.world().resource::().delta; + Ok(d.x != 0.0 || d.y != 0.0) + }) +} diff --git a/crates/processing_input/src/state.rs b/crates/processing_input/src/state.rs index 1db8f3d0..e63995aa 100644 --- a/crates/processing_input/src/state.rs +++ b/crates/processing_input/src/state.rs @@ -26,6 +26,8 @@ impl CursorPosition { pub struct LastKey { pub code: Option, pub character: Option, + pub just_pressed: bool, + pub just_released: bool, } #[derive(Resource, Default)] @@ -51,13 +53,21 @@ pub fn track_cursor_position( } pub fn track_last_key(mut reader: MessageReader, mut last: ResMut) { - if let Some(event) = reader - .read() - .filter(|e| e.state == ButtonState::Pressed) - .last() - { - last.code = Some(event.key_code); - last.character = event.text.as_ref().and_then(|t| t.chars().next()); + // our cbs fire on key auto repeats but bevy just_pressed only fires on the initial press + // we track edge state off of the raw input stream + last.just_pressed = false; + last.just_released = false; + for event in reader.read() { + match event.state { + ButtonState::Pressed => { + last.code = Some(event.key_code); + last.character = event.text.as_ref().and_then(|t| t.chars().next()); + last.just_pressed = true; + } + ButtonState::Released => { + last.just_released = true; + } + } } } diff --git a/crates/processing_pyo3/mewnala/__init__.py b/crates/processing_pyo3/mewnala/__init__.py index 7fe6f793..4427ced4 100644 --- a/crates/processing_pyo3/mewnala/__init__.py +++ b/crates/processing_pyo3/mewnala/__init__.py @@ -9,4 +9,66 @@ _sub = getattr(_native, _name, None) if _sub is not None: _sys.modules[f"{__name__}.{_name}"] = _sub -del _sys, _native, _name, _sub + +# global var handling. for wildcard import of our module, we copy into globals, otherwise +# we dispatch to get attr and call the underlying getter method + +_DYNAMIC_GRAPHICS_ATTRS = ( + "width", + "height", + "focused", + "pixel_width", + "pixel_height", + "pixel_density", +) +_DYNAMIC_FUNCTIONS = ( + "mouse_x", + "mouse_y", + "pmouse_x", + "pmouse_y", + "frame_count", + "delta_time", + "elapsed_time", +) +_DYNAMIC = ( + _DYNAMIC_GRAPHICS_ATTRS + _DYNAMIC_FUNCTIONS + ( + "mouse_is_pressed", + "mouse_button", + "moved_x", + "moved_y", + "mouse_wheel", + "key", + "key_code", + "key_is_pressed", + "display_width", + "display_height", + ) +) + + +def _get_graphics(): + return getattr(_native, "_graphics", None) + + +def __getattr__(name): + if name in _DYNAMIC_GRAPHICS_ATTRS: + g = _get_graphics() + if g is not None: + return getattr(g, name) + if name in _DYNAMIC_FUNCTIONS: + fn = getattr(_native, name, None) + if callable(fn): + return fn() + if name in ("display_width", "display_height"): + mon = getattr(_native, "primary_monitor", lambda: None)() + if mon is None: + return 0 + return mon.width if name == "display_width" else mon.height + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + +def __dir__(): + return sorted(set(list(globals().keys()) + list(_DYNAMIC))) + + +del _sys, _name, _sub diff --git a/crates/processing_pyo3/src/graphics.rs b/crates/processing_pyo3/src/graphics.rs index 5b0dbc9c..bac01371 100644 --- a/crates/processing_pyo3/src/graphics.rs +++ b/crates/processing_pyo3/src/graphics.rs @@ -132,40 +132,7 @@ impl PyBlendMode { const OP_MAX: u8 = 4; } -#[pyclass(unsendable)] -pub struct Surface { - pub(crate) entity: Entity, - glfw_ctx: Option, -} - -#[pymethods] -impl Surface { - pub fn poll_events(&mut self) -> bool { - match &mut self.glfw_ctx { - Some(ctx) => ctx.poll_events(), - None => true, // no-op, offscreen surfaces never close - } - } - - #[getter] - pub fn display_density(&self) -> PyResult { - match &self.glfw_ctx { - Some(ctx) => Ok(ctx.content_scale()), - None => Ok(1.0), - } - } - - pub fn set_pixel_density(&self, density: f32) -> PyResult<()> { - surface_set_pixel_density(self.entity, density) - .map_err(|e| PyRuntimeError::new_err(format!("{e}"))) - } -} - -impl Drop for Surface { - fn drop(&mut self) { - let _ = surface_destroy(self.entity); - } -} +pub use crate::surface::Surface; #[pyclass] #[derive(Debug)] @@ -318,6 +285,10 @@ impl Geometry { pub struct Graphics { pub(crate) entity: Entity, pub surface: Surface, + #[pyo3(get)] + pub width: u32, + #[pyo3(get)] + pub height: u32, } impl Drop for Graphics { @@ -364,6 +335,8 @@ impl Graphics { Ok(Self { entity: graphics, surface, + width, + height, }) } @@ -399,9 +372,31 @@ impl Graphics { Ok(Self { entity: graphics, surface, + width, + height, }) } + #[getter] + pub fn focused(&self) -> PyResult { + self.surface.focused() + } + + #[getter] + pub fn pixel_density(&self) -> PyResult { + self.surface.pixel_density() + } + + #[getter] + pub fn pixel_width(&self) -> PyResult { + self.surface.pixel_width() + } + + #[getter] + pub fn pixel_height(&self) -> PyResult { + self.surface.pixel_height() + } + pub fn readback_png(&self) -> PyResult> { let raw = graphics_readback_raw(self.entity) .map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; diff --git a/crates/processing_pyo3/src/input.rs b/crates/processing_pyo3/src/input.rs index fa9feb47..5096d5cb 100644 --- a/crates/processing_pyo3/src/input.rs +++ b/crates/processing_pyo3/src/input.rs @@ -80,20 +80,20 @@ pub fn key_code() -> PyResult> { .map_err(|e| PyRuntimeError::new_err(format!("{e}"))) } -pub fn sync_globals(func: &Bound<'_, PyAny>, surface: Entity) -> PyResult<()> { - let globals = func.getattr("__globals__")?; - globals.set_item("mouse_x", mouse_x(surface)?)?; - globals.set_item("mouse_y", mouse_y(surface)?)?; - globals.set_item("pmouse_x", pmouse_x(surface)?)?; - globals.set_item("pmouse_y", pmouse_y(surface)?)?; - globals.set_item("mouse_is_pressed", mouse_is_pressed()?)?; - globals.set_item("mouse_button", mouse_button()?)?; - globals.set_item("moved_x", moved_x()?)?; - globals.set_item("moved_y", moved_y()?)?; - globals.set_item("mouse_wheel", mouse_wheel()?)?; - globals.set_item("key", key()?)?; - globals.set_item("key_code", key_code()?)?; - globals.set_item("key_is_pressed", key_is_pressed()?)?; +pub fn sync_globals(globals: &Bound<'_, PyAny>, surface: Entity) -> PyResult<()> { + use crate::set_tracked; + set_tracked(globals, "mouse_x", mouse_x(surface)?)?; + set_tracked(globals, "mouse_y", mouse_y(surface)?)?; + set_tracked(globals, "pmouse_x", pmouse_x(surface)?)?; + set_tracked(globals, "pmouse_y", pmouse_y(surface)?)?; + set_tracked(globals, "mouse_is_pressed", mouse_is_pressed()?)?; + set_tracked(globals, "mouse_button", mouse_button()?)?; + set_tracked(globals, "moved_x", moved_x()?)?; + set_tracked(globals, "moved_y", moved_y()?)?; + set_tracked(globals, "mouse_wheel", mouse_wheel()?)?; + set_tracked(globals, "key", key()?)?; + set_tracked(globals, "key_code", key_code()?)?; + set_tracked(globals, "key_is_pressed", key_is_pressed()?)?; Ok(()) } diff --git a/crates/processing_pyo3/src/lib.rs b/crates/processing_pyo3/src/lib.rs index 01ddce9f..7797510c 100644 --- a/crates/processing_pyo3/src/lib.rs +++ b/crates/processing_pyo3/src/lib.rs @@ -18,7 +18,10 @@ mod input; pub(crate) mod material; pub(crate) mod math; mod midi; +mod monitor; pub(crate) mod shader; +mod surface; +mod time; #[cfg(feature = "webcam")] mod webcam; @@ -28,6 +31,7 @@ use graphics::{ use material::Material; use pyo3::{ + BoundObject, exceptions::PyRuntimeError, prelude::*, types::{PyDict, PyTuple}, @@ -37,8 +41,104 @@ use std::ffi::{CStr, CString}; use bevy::log::warn; use gltf::Gltf; +use std::cell::RefCell; +use std::collections::HashMap; use std::env; +thread_local! { + static LAST_GLOBALS: RefCell>> = RefCell::new(HashMap::new()); +} + + +/// Writes a new value to globals, iff the new value does not match a previous tracked value. +pub(crate) fn set_tracked<'py, V>( + globals: &Bound<'py, PyAny>, + name: &'static str, + new_value: V, +) -> PyResult<()> +where + V: IntoPyObject<'py>, + PyErr: From, +{ + let py = globals.py(); + let owned: Py = new_value.into_pyobject(py)?.into_any().unbind(); + + let user_shadowed = LAST_GLOBALS.with(|cache| -> PyResult { + let cache = cache.borrow(); + let Some(last) = cache.get(name) else { + return Ok(false); + }; + match globals.get_item(name) { + Ok(current) => Ok(!current.eq(last.bind(py))?), + // key isn't in globals, either because the dict is fresh (livecode reload etc) + // or the user deleted it so we can safely repopulate + Err(_) => Ok(false), + } + })?; + + if !user_shadowed { + globals.set_item(name, owned.clone_ref(py))?; + LAST_GLOBALS.with(|cache| { + cache.borrow_mut().insert(name, owned); + }); + } + + Ok(()) +} + +pub(crate) fn reset_tracked_globals() { + LAST_GLOBALS.with(|cache| cache.borrow_mut().clear()); +} + +fn sync_globals(module: &Bound<'_, PyModule>, globals: &Bound<'_, PyAny>) -> PyResult<()> { + let graphics = + get_graphics(module)?.ok_or_else(|| PyRuntimeError::new_err("call size() first"))?; + input::sync_globals(globals, graphics.surface.entity)?; + surface::sync_globals(globals, &graphics.surface, graphics.width, graphics.height)?; + time::sync_globals(globals)?; + Ok(()) +} + +fn try_call(locals: &Bound<'_, PyAny>, name: &str) -> PyResult<()> { + if let Ok(cb) = locals.get_item(name) + && cb.is_callable() + { + cb.call0() + .map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; + } + Ok(()) +} + +fn dispatch_event_callbacks(locals: &Bound<'_, PyAny>) -> PyResult<()> { + use processing::prelude::*; + let err = + |e: processing::prelude::error::ProcessingError| PyRuntimeError::new_err(format!("{e}")); + + if input_mouse_any_just_pressed().map_err(err)? { + try_call(locals, "mouse_pressed")?; + } + if input_mouse_any_just_released().map_err(err)? { + try_call(locals, "mouse_released")?; + } + if input_mouse_moved().map_err(err)? { + if input_mouse_is_pressed().map_err(err)? { + try_call(locals, "mouse_dragged")?; + } else { + try_call(locals, "mouse_moved")?; + } + } + if input_mouse_scrolled().map_err(err)? { + try_call(locals, "mouse_wheel")?; + } + if input_key_any_just_pressed().map_err(err)? { + try_call(locals, "key_pressed")?; + } + if input_key_any_just_released().map_err(err)? { + try_call(locals, "key_released")?; + } + Ok(()) +} + /// Get a shared ref to the Graphics context, or return Ok(()) if not yet initialized. macro_rules! graphics { ($module:expr) => { @@ -139,6 +239,10 @@ mod mewnala { #[cfg(feature = "cuda")] #[pymodule_export] use super::cuda::CudaImage; + #[pymodule_export] + use super::monitor::Monitor; + #[pymodule_export] + use super::surface::Surface; // Stroke cap/join #[pymodule_export] @@ -595,6 +699,17 @@ mod mewnala { graphics!(module).update_from(obj) } + #[pyfunction] + #[pyo3(pass_module)] + fn _tick(module: &Bound<'_, PyModule>, ns: &Bound<'_, PyAny>) -> PyResult<()> { + if get_graphics(module)?.is_none() { + return Ok(()); + } + sync_globals(module, ns)?; + dispatch_event_callbacks(ns)?; + Ok(()) + } + #[pyfunction] #[pyo3(pass_module)] fn redraw(module: &Bound<'_, PyModule>) -> PyResult<()> { @@ -703,12 +818,10 @@ mod mewnala { // call setup setup_fn.call0()?; - let mut frame_count: u64 = 0; - { - let graphics = get_graphics(module)? - .ok_or_else(|| PyRuntimeError::new_err("call size() first"))?; - input::sync_globals(&draw_fn, graphics.surface.entity)?; - } + let mut globals = draw_fn.getattr("__globals__")?; + sync_globals(module, &globals)?; + + // start draw loop loop { { let mut graphics = get_graphics_mut(module)? @@ -730,6 +843,10 @@ mod mewnala { } draw_fn = locals.get_item("draw").unwrap().unwrap(); + globals = draw_fn.getattr("__globals__")?; + reset_tracked_globals(); + + dbg!(locals); } if !graphics.surface.poll_events() { @@ -738,14 +855,8 @@ mod mewnala { graphics.begin_draw()?; } - { - let graphics = get_graphics(module)? - .ok_or_else(|| PyRuntimeError::new_err("call size() first"))?; - input::sync_globals(&draw_fn, graphics.surface.entity)?; - let globals = draw_fn.getattr("__globals__")?; - globals.set_item("frame_count", frame_count)?; - frame_count += 1; - } + sync_globals(module, &globals)?; + dispatch_event_callbacks(&locals)?; draw_fn .call0() @@ -1446,4 +1557,29 @@ mod mewnala { get_graphics(module)?.ok_or_else(|| PyRuntimeError::new_err("call size() first"))?; graphics.surface.display_density() } + + #[pyfunction] + fn frame_count() -> PyResult { + time::frame_count() + } + + #[pyfunction] + fn delta_time() -> PyResult { + time::delta_time() + } + + #[pyfunction] + fn elapsed_time() -> PyResult { + time::elapsed_time() + } + + #[pyfunction] + fn monitors() -> PyResult> { + monitor::list() + } + + #[pyfunction] + fn primary_monitor() -> PyResult> { + monitor::primary() + } } diff --git a/crates/processing_pyo3/src/monitor.rs b/crates/processing_pyo3/src/monitor.rs new file mode 100644 index 00000000..6c72f862 --- /dev/null +++ b/crates/processing_pyo3/src/monitor.rs @@ -0,0 +1,50 @@ +use bevy::prelude::Entity; +use processing::prelude::*; +use pyo3::{exceptions::PyRuntimeError, prelude::*}; + +#[pyclass(unsendable)] +pub struct Monitor { + pub(crate) entity: Entity, +} + +#[pymethods] +impl Monitor { + #[getter] + pub fn width(&self) -> PyResult { + monitor_width(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } + + #[getter] + pub fn height(&self) -> PyResult { + monitor_height(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } + + #[getter] + pub fn scale_factor(&self) -> PyResult { + monitor_scale_factor(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } + + #[getter] + pub fn refresh_rate_millihertz(&self) -> PyResult> { + monitor_refresh_rate_millihertz(self.entity) + .map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } + + #[getter] + pub fn name(&self) -> PyResult> { + monitor_name(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } +} + +pub fn primary() -> PyResult> { + let entity = monitor_primary().map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; + Ok(entity.map(|entity| Monitor { entity })) +} + +pub fn list() -> PyResult> { + let entities = monitor_list().map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; + Ok(entities + .into_iter() + .map(|entity| Monitor { entity }) + .collect()) +} diff --git a/crates/processing_pyo3/src/python/ipython_post_execute.py b/crates/processing_pyo3/src/python/ipython_post_execute.py index 79f98291..29f0344f 100644 --- a/crates/processing_pyo3/src/python/ipython_post_execute.py +++ b/crates/processing_pyo3/src/python/ipython_post_execute.py @@ -1,8 +1,10 @@ -import processing +import mewnala def _processing_post_execute(result): - processing._present() - if not processing._poll_events(): - processing._graphics = None + mewnala._present() + if not mewnala._poll_events(): + mewnala._graphics = None + return + mewnala._tick(get_ipython().user_ns) get_ipython().events.register('post_run_cell', _processing_post_execute) diff --git a/crates/processing_pyo3/src/python/jupyter_post_execute.py b/crates/processing_pyo3/src/python/jupyter_post_execute.py index a0067bdf..9a784720 100644 --- a/crates/processing_pyo3/src/python/jupyter_post_execute.py +++ b/crates/processing_pyo3/src/python/jupyter_post_execute.py @@ -1,9 +1,10 @@ -import processing +import mewnala import IPython.display as _ipy_display def _processing_post_execute(result): - processing._present() - png_data = processing._readback_png() + mewnala._present() + mewnala._tick(get_ipython().user_ns) + png_data = mewnala._readback_png() if png_data is not None: _ipy_display.display(_ipy_display.Image(data=bytes(png_data))) diff --git a/crates/processing_pyo3/src/python/register_inputhook.py b/crates/processing_pyo3/src/python/register_inputhook.py index 0409864c..aa11a17e 100644 --- a/crates/processing_pyo3/src/python/register_inputhook.py +++ b/crates/processing_pyo3/src/python/register_inputhook.py @@ -1,12 +1,17 @@ -import processing +import mewnala import time +import traceback from IPython.terminal.pt_inputhooks import register def _processing_inputhook(context): while not context.input_is_ready(): - if not processing._poll_events(): - processing._graphics = None + if not mewnala._poll_events(): + mewnala._graphics = None break + try: + mewnala._tick(get_ipython().user_ns) + except Exception: + traceback.print_exc() time.sleep(1.0 / 60.0) register('processing', _processing_inputhook) diff --git a/crates/processing_pyo3/src/surface.rs b/crates/processing_pyo3/src/surface.rs new file mode 100644 index 00000000..98877f8f --- /dev/null +++ b/crates/processing_pyo3/src/surface.rs @@ -0,0 +1,84 @@ +use bevy::prelude::Entity; +use processing::prelude::*; +use pyo3::{exceptions::PyRuntimeError, prelude::*}; + +use crate::glfw::GlfwContext; +use crate::monitor; +use crate::set_tracked; + +#[pyclass(unsendable)] +pub struct Surface { + pub(crate) entity: Entity, + pub(crate) glfw_ctx: Option, +} + +#[pymethods] +impl Surface { + pub fn poll_events(&mut self) -> bool { + match &mut self.glfw_ctx { + Some(ctx) => ctx.poll_events(), + None => true, // no-op, offscreen surfaces never close + } + } + + #[getter] + pub fn focused(&self) -> PyResult { + surface_focused(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } + + #[getter] + pub fn pixel_density(&self) -> PyResult { + surface_scale_factor(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } + + #[getter] + pub fn pixel_width(&self) -> PyResult { + surface_physical_width(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } + + #[getter] + pub fn pixel_height(&self) -> PyResult { + surface_physical_height(self.entity).map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } + + #[getter] + pub fn display_density(&self) -> PyResult { + match &self.glfw_ctx { + Some(ctx) => Ok(ctx.content_scale()), + None => Ok(1.0), + } + } + + pub fn set_pixel_density(&self, density: f32) -> PyResult<()> { + surface_set_pixel_density(self.entity, density) + .map_err(|e| PyRuntimeError::new_err(format!("{e}"))) + } +} + +impl Drop for Surface { + fn drop(&mut self) { + let _ = surface_destroy(self.entity); + } +} + +pub fn sync_globals( + globals: &Bound<'_, PyAny>, + surface: &Surface, + canvas_width: u32, + canvas_height: u32, +) -> PyResult<()> { + set_tracked(globals, "width", canvas_width)?; + set_tracked(globals, "height", canvas_height)?; + set_tracked(globals, "focused", surface.focused()?)?; + set_tracked(globals, "pixel_density", surface.pixel_density()?)?; + set_tracked(globals, "pixel_width", surface.pixel_width()?)?; + set_tracked(globals, "pixel_height", surface.pixel_height()?)?; + + let (dw, dh) = match monitor::primary()? { + Some(m) => (m.width()?, m.height()?), + None => (0, 0), + }; + set_tracked(globals, "display_width", dw)?; + set_tracked(globals, "display_height", dh)?; + Ok(()) +} diff --git a/crates/processing_pyo3/src/time.rs b/crates/processing_pyo3/src/time.rs new file mode 100644 index 00000000..d638a568 --- /dev/null +++ b/crates/processing_pyo3/src/time.rs @@ -0,0 +1,20 @@ +use pyo3::{exceptions::PyRuntimeError, prelude::*}; + +pub fn frame_count() -> PyResult { + processing::prelude::frame_count().map_err(|e| PyRuntimeError::new_err(format!("{e}"))) +} + +pub fn delta_time() -> PyResult { + processing::prelude::delta_time().map_err(|e| PyRuntimeError::new_err(format!("{e}"))) +} + +pub fn elapsed_time() -> PyResult { + processing::prelude::elapsed_time().map_err(|e| PyRuntimeError::new_err(format!("{e}"))) +} + +pub fn sync_globals(globals: &Bound<'_, PyAny>) -> PyResult<()> { + crate::set_tracked(globals, "frame_count", frame_count()?)?; + crate::set_tracked(globals, "delta_time", delta_time()?)?; + crate::set_tracked(globals, "elapsed_time", elapsed_time()?)?; + Ok(()) +} diff --git a/crates/processing_render/src/lib.rs b/crates/processing_render/src/lib.rs index f2dd7679..dc188dc4 100644 --- a/crates/processing_render/src/lib.rs +++ b/crates/processing_render/src/lib.rs @@ -8,9 +8,11 @@ pub mod graphics; pub mod image; pub mod light; pub mod material; +pub mod monitor; pub mod render; pub mod sketch; pub(crate) mod surface; +pub mod time; pub mod transform; use std::path::PathBuf; @@ -1307,6 +1309,117 @@ pub fn material_destroy(entity: Entity) -> error::Result<()> { }) } +pub fn surface_focused(entity: Entity) -> error::Result { + app_mut(|app| { + Ok(app + .world_mut() + .run_system_cached_with(surface::focused, entity) + .unwrap()) + }) +} + +pub fn surface_scale_factor(entity: Entity) -> error::Result { + app_mut(|app| { + Ok(app + .world_mut() + .run_system_cached_with(surface::scale_factor, entity) + .unwrap()) + }) +} + +pub fn surface_physical_width(entity: Entity) -> error::Result { + app_mut(|app| { + Ok(app + .world_mut() + .run_system_cached_with(surface::physical_width, entity) + .unwrap()) + }) +} + +pub fn surface_physical_height(entity: Entity) -> error::Result { + app_mut(|app| { + Ok(app + .world_mut() + .run_system_cached_with(surface::physical_height, entity) + .unwrap()) + }) +} + +pub fn monitor_list() -> error::Result> { + app_mut(|app| Ok(app.world_mut().run_system_cached(monitor::list).unwrap())) +} + +pub fn monitor_primary() -> error::Result> { + app_mut(|app| Ok(app.world_mut().run_system_cached(monitor::primary).unwrap())) +} + +pub fn monitor_width(entity: Entity) -> error::Result { + app_mut(|app| { + Ok(app + .world_mut() + .run_system_cached_with(monitor::width, entity) + .unwrap()) + }) +} + +pub fn monitor_height(entity: Entity) -> error::Result { + app_mut(|app| { + Ok(app + .world_mut() + .run_system_cached_with(monitor::height, entity) + .unwrap()) + }) +} + +pub fn monitor_scale_factor(entity: Entity) -> error::Result { + app_mut(|app| { + Ok(app + .world_mut() + .run_system_cached_with(monitor::scale_factor, entity) + .unwrap()) + }) +} + +pub fn monitor_refresh_rate_millihertz(entity: Entity) -> error::Result> { + app_mut(|app| { + Ok(app + .world_mut() + .run_system_cached_with(monitor::refresh_rate_millihertz, entity) + .unwrap()) + }) +} + +pub fn monitor_name(entity: Entity) -> error::Result> { + app_mut(|app| { + Ok(app + .world_mut() + .run_system_cached_with(monitor::name, entity) + .unwrap()) + }) +} + +pub fn frame_count() -> error::Result { + app_mut(|app| { + Ok(app + .world_mut() + .run_system_cached(time::frame_count) + .unwrap()) + }) +} + +pub fn delta_time() -> error::Result { + app_mut(|app| Ok(app.world_mut().run_system_cached(time::delta_secs).unwrap())) +} + +pub fn elapsed_time() -> error::Result { + app_mut(|app| { + Ok(app + .world_mut() + .run_system_cached(time::elapsed_secs) + .unwrap()) + }) +} + #[cfg(not(target_arch = "wasm32"))] pub fn gltf_load(graphics_entity: Entity, path: &str) -> error::Result { app_mut(|app| { diff --git a/crates/processing_render/src/monitor.rs b/crates/processing_render/src/monitor.rs new file mode 100644 index 00000000..845d018e --- /dev/null +++ b/crates/processing_render/src/monitor.rs @@ -0,0 +1,33 @@ +use bevy::prelude::*; +use bevy::window::{Monitor, PrimaryMonitor}; + +pub fn list(query: Query>) -> Vec { + query.iter().collect() +} + +pub fn primary(query: Query>) -> Option { + query.iter().next() +} + +pub fn width(In(entity): In, query: Query<&Monitor>) -> u32 { + query.get(entity).map(|m| m.physical_width).unwrap_or(0) +} + +pub fn height(In(entity): In, query: Query<&Monitor>) -> u32 { + query.get(entity).map(|m| m.physical_height).unwrap_or(0) +} + +pub fn scale_factor(In(entity): In, query: Query<&Monitor>) -> f64 { + query.get(entity).map(|m| m.scale_factor).unwrap_or(1.0) +} + +pub fn refresh_rate_millihertz(In(entity): In, query: Query<&Monitor>) -> Option { + query + .get(entity) + .ok() + .and_then(|m| m.refresh_rate_millihertz) +} + +pub fn name(In(entity): In, query: Query<&Monitor>) -> Option { + query.get(entity).ok().and_then(|m| m.name.clone()) +} diff --git a/crates/processing_render/src/surface.rs b/crates/processing_render/src/surface.rs index 20f46d39..e19f007d 100644 --- a/crates/processing_render/src/surface.rs +++ b/crates/processing_render/src/surface.rs @@ -392,3 +392,28 @@ pub fn set_pixel_density( Err(error::ProcessingError::SurfaceNotFound) } } + +pub fn focused(In(entity): In, query: Query<&Window>) -> bool { + query.get(entity).map(|w| w.focused).unwrap_or(false) +} + +pub fn scale_factor(In(entity): In, query: Query<&Window>) -> f32 { + query + .get(entity) + .map(|w| w.resolution.scale_factor()) + .unwrap_or(1.0) +} + +pub fn physical_width(In(entity): In, query: Query<&Window>) -> u32 { + query + .get(entity) + .map(|w| w.resolution.physical_width()) + .unwrap_or(0) +} + +pub fn physical_height(In(entity): In, query: Query<&Window>) -> u32 { + query + .get(entity) + .map(|w| w.resolution.physical_height()) + .unwrap_or(0) +} diff --git a/crates/processing_render/src/time.rs b/crates/processing_render/src/time.rs new file mode 100644 index 00000000..4f7bcbd6 --- /dev/null +++ b/crates/processing_render/src/time.rs @@ -0,0 +1,15 @@ +use bevy::diagnostic::FrameCount; +use bevy::prelude::*; +use bevy::time::Time; + +pub fn frame_count(count: Option>) -> u32 { + count.map(|c| c.0).unwrap_or(0) +} + +pub fn delta_secs(time: Option>) -> f32 { + time.map(|t| t.delta_secs()).unwrap_or(0.0) +} + +pub fn elapsed_secs(time: Option>) -> f32 { + time.map(|t| t.elapsed_secs()).unwrap_or(0.0) +} From abe084830bc05c930c6261f81af55ba8ec316bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Wed, 22 Apr 2026 11:34:35 +0200 Subject: [PATCH 11/15] fmt --- crates/processing_pyo3/src/lib.rs | 1 - crates/processing_render/src/surface.rs | 11 ++++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/processing_pyo3/src/lib.rs b/crates/processing_pyo3/src/lib.rs index 7797510c..e4c97c9d 100644 --- a/crates/processing_pyo3/src/lib.rs +++ b/crates/processing_pyo3/src/lib.rs @@ -49,7 +49,6 @@ thread_local! { static LAST_GLOBALS: RefCell>> = RefCell::new(HashMap::new()); } - /// Writes a new value to globals, iff the new value does not match a previous tracked value. pub(crate) fn set_tracked<'py, V>( globals: &Bound<'py, PyAny>, diff --git a/crates/processing_render/src/surface.rs b/crates/processing_render/src/surface.rs index e19f007d..ad4c9c5e 100644 --- a/crates/processing_render/src/surface.rs +++ b/crates/processing_render/src/surface.rs @@ -368,7 +368,9 @@ pub fn resize( let scale = window.resolution.scale_factor(); let physical_w = (width as f32 * scale) as u32; let physical_h = (height as f32 * scale) as u32; - window.resolution.set_physical_resolution(physical_w, physical_h); + window + .resolution + .set_physical_resolution(physical_w, physical_h); Ok(()) } else { Err(error::ProcessingError::SurfaceNotFound) @@ -383,10 +385,9 @@ pub fn set_pixel_density( let logical_w = window.resolution.width(); let logical_h = window.resolution.height(); window.resolution.set_scale_factor_override(Some(density)); - window.resolution.set_physical_resolution( - (logical_w * density) as u32, - (logical_h * density) as u32, - ); + window + .resolution + .set_physical_resolution((logical_w * density) as u32, (logical_h * density) as u32); Ok(()) } else { Err(error::ProcessingError::SurfaceNotFound) From 9519a741196e9cd6a2de26542ad61d8652fcd4ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Wed, 22 Apr 2026 12:07:08 +0200 Subject: [PATCH 12/15] near and far flipped when creating projection matrix --- crates/processing_render/src/graphics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/processing_render/src/graphics.rs b/crates/processing_render/src/graphics.rs index da99aae0..ccf42e4a 100644 --- a/crates/processing_render/src/graphics.rs +++ b/crates/processing_render/src/graphics.rs @@ -102,8 +102,8 @@ impl CameraProjection for ProcessingProjection { self.width, self.height, // bottom = height 0.0, // top = 0 - self.far, self.near, + self.far, ) } @@ -720,7 +720,7 @@ mod tests { let clip_matrix = proj.get_clip_from_view(); // Check some values in the matrix to ensure it's correct // In [0,1] depth orthographic projection, w_axis.z = -near/(far-near) - let expected = -0.1 / (1000.0 - 0.1); + let expected: f32 = -0.1 / (1000.0 - 0.1); assert!((clip_matrix.w_axis.z - expected).abs() < 1e-6); } From b0ce4c7972ae2cb55a4d93a8f6b9d20496fdb653 Mon Sep 17 00:00:00 2001 From: Moon Date: Wed, 22 Apr 2026 13:36:26 +0200 Subject: [PATCH 13/15] Update calls to use tuples for colors (#118) --- crates/processing_pyo3/examples/lights.py | 8 ++++---- crates/processing_pyo3/examples/materials.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/processing_pyo3/examples/lights.py b/crates/processing_pyo3/examples/lights.py index 9e60e8be..e825893a 100644 --- a/crates/processing_pyo3/examples/lights.py +++ b/crates/processing_pyo3/examples/lights.py @@ -7,19 +7,19 @@ def setup(): mode_3d() # Directional Light - dir_light = create_directional_light(0.5, 0.24, 1.0, 1500.0) + dir_light = create_directional_light((0.5, 0.24, 1.0), 1500.0) # Point Lights - point_light_a = create_point_light(1.0, 0.5, 0.25, 1000000.0, 200.0, 0.5) + point_light_a = create_point_light((1.0, 0.5, 0.25), 1000000.0, 200.0, 0.5) point_light_a.position(-25.0, 5.0, 51.0) point_light_a.look_at(0.0, 0.0, 0.0) - point_light_b = create_point_light(0.0, 0.5, 0.75, 2000000.0, 200.0, 0.25) + point_light_b = create_point_light((0.0, 0.5, 0.75), 2000000.0, 200.0, 0.25) point_light_b.position(0.0, 5.0, 50.5) point_light_b.look_at(0.0, 0.0, 0.0) # Spot Light - spot_light = create_spot_light(0.25, 0.8, 0.19, 15.0 * 1000000.0, 200.0, 0.84, 0.0, 0.7854) + spot_light = create_spot_light((0.25, 0.8, 0.19), 15.0 * 1000000.0, 200.0, 0.84, 0.0, 0.7854) spot_light.position(40.0, 0.0, 70.0) spot_light.look_at(0.0, 0.0, 0.0) diff --git a/crates/processing_pyo3/examples/materials.py b/crates/processing_pyo3/examples/materials.py index 38b43e46..ffa66cc5 100644 --- a/crates/processing_pyo3/examples/materials.py +++ b/crates/processing_pyo3/examples/materials.py @@ -7,8 +7,8 @@ def setup(): size(800, 600) mode_3d() - dir_light = create_directional_light(1.0, 0.98, 0.95, 1500.0) - point_light = create_point_light(1.0, 1.0, 1.0, 100000.0, 800.0, 0.0) + dir_light = create_directional_light((1.0, 0.98, 0.95), 1500.0) + point_light = create_point_light((1.0, 1.0, 1.0), 100000.0, 800.0, 0.0) point_light.position(200.0, 200.0, 400.0) mat = Material() From 6863c68ab1d23688185e35d2d3cfc90c04957011 Mon Sep 17 00:00:00 2001 From: "Nanashi." Date: Wed, 22 Apr 2026 20:36:45 +0900 Subject: [PATCH 14/15] docs: mention cbindgen instead of bindgen (#116) --- docs/principles.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/principles.md b/docs/principles.md index 785f60bc..2092f0d7 100644 --- a/docs/principles.md +++ b/docs/principles.md @@ -32,7 +32,7 @@ of characteristics that are desirable for a project like Processing: There are several layers required to make this work. Starting from the outermost layer of the onion: -1. `bindgen`, a rust project for generating C headers from Rust code. This is what Java and other languages bind to. +1. `cbindgen`, a rust project for generating C headers from Rust code. This is what Java and other languages bind to. 2. Our Rust FFI library, which wraps libprocessing. FFI rust code mostly means declaring the public interface for `bindgen` using `extern "C"` functions and mapping types compatible with the C ABI to call our libprocessing API. 3. libprocessing is our Rust library that exposes the primary Processing API. From 616c6fe917e85b392d1a97278d51d0d3978d1888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Wed, 22 Apr 2026 14:50:33 +0200 Subject: [PATCH 15/15] Bump pyo3 crate version --- crates/processing_pyo3/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/processing_pyo3/Cargo.toml b/crates/processing_pyo3/Cargo.toml index d55b9f12..73b528d4 100644 --- a/crates/processing_pyo3/Cargo.toml +++ b/crates/processing_pyo3/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "processing_pyo3" -version = "0.0.1" +version = "0.0.2" edition = "2024" [lints]