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/Cargo.lock b/Cargo.lock index 5bfa7b06..d8abaabc 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", @@ -772,10 +781,24 @@ 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" -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 +808,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 +839,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 +856,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 +869,7 @@ dependencies = [ "bumpalo", "concurrent-queue", "derive_more", + "downcast-rs 2.0.2", "fixedbitset", "indexmap", "log", @@ -860,7 +884,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 +895,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 +904,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 +921,7 @@ dependencies = [ "bevy_platform", "bevy_reflect", "bevy_render", + "bevy_scene", "bevy_shader", "bevy_text", "bevy_ui", @@ -909,7 +934,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 +949,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 +957,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 +981,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 +1009,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 +1026,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 +1044,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 +1072,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 +1088,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 +1104,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 +1156,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 +1186,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 +1203,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 +1236,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 +1246,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 +1265,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 +1314,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 +1323,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 +1359,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 +1388,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 +1409,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 +1433,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 +1466,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 +1479,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 +1513,7 @@ dependencies = [ "glam", "image", "indexmap", - "itertools 0.14.0", + "itertools", "js-sys", "naga", "nonmax", @@ -1499,7 +1532,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 +1543,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 +1585,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 +1617,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 +1649,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 +1664,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 +1674,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 +1686,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 +1719,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 +1733,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 +1750,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 +1770,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 +1787,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 +1818,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 +1831,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 +1851,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 +1869,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 +1899,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 +1937,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 +1967,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 +2006,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 +2161,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 +2292,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 +2500,7 @@ dependencies = [ "core-foundation-sys 0.7.0", "core-graphics 0.19.2", "libc", - "metal 0.18.0", + "metal", "objc", ] @@ -2446,22 +2524,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 +2559,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]] @@ -2611,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" @@ -2834,9 +2922,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 +2967,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 +3069,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 +3379,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 +3511,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 +3602,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 +3777,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 +3826,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 +3839,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 +3850,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,7 +3863,7 @@ dependencies = [ "cesu8", "cfg-if 1.0.4", "combine", - "jni-sys", + "jni-sys 0.3.1", "log", "thiserror 1.0.69", "walkdir", @@ -3679,35 +3871,89 @@ dependencies = [ ] [[package]] -name = "jni-sys" -version = "0.3.0" +name = "jni" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +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 = "jobserver" -version = "0.1.34" +name = "jni-macros" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" dependencies = [ - "getrandom 0.3.4", - "libc", + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn", ] [[package]] -name = "js-sys" -version = "0.3.91" +name = "jni-sys" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" dependencies = [ - "once_cell", - "wasm-bindgen", + "jni-sys 0.4.1", ] [[package]] -name = "keccak" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" +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 = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" +dependencies = [ + "cfg-if 1.0.4", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ "cpufeatures 0.2.17", @@ -3766,9 +4012,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 +4139,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 +4171,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 +4211,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 +4320,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 +4331,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 +4396,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 +4431,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 +4478,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 +4497,7 @@ dependencies = [ "num-traits", "once_cell", "pp-rs", - "rustc-hash 1.1.0", + "rustc-hash", "serde", "spirv", "thiserror 2.0.18", @@ -4275,16 +4506,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 +4554,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 +4561,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 +4575,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 +4914,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 +4974,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 +5027,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 +5055,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 +5131,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 +5183,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 +5205,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 +5216,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 +5285,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 +5328,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 +5373,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 +5553,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 +5610,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]] @@ -5348,6 +5629,7 @@ dependencies = [ "bevy", "js-sys", "processing_core", + "processing_cuda", "processing_glfw", "processing_input", "processing_midi", @@ -5370,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" @@ -5414,6 +5706,7 @@ dependencies = [ "bevy", "png", "processing", + "processing_cuda", "processing_glfw", "processing_webcam", "pyo3", @@ -5492,9 +5785,10 @@ 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 = [ + "inventory", "libc", "once_cell", "portable-atomic", @@ -5505,16 +5799,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 +5816,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 +5827,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 +5838,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 +5976,7 @@ dependencies = [ "built", "cfg-if 1.0.4", "interpolate_name", - "itertools 0.14.0", + "itertools", "libc", "libfuzzer-sys", "log", @@ -5722,6 +6016,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 +6050,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 +6138,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 +6170,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 +6276,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 +6331,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 +6365,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 = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "simd_cesu8" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] [[package]] name = "simd_helpers" @@ -6074,6 +6388,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 +6402,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 +6485,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 +6545,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 +6565,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 +6601,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 +6738,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 +6788,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" +version = "0.25.10+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01f2eadbbc6b377a847be05f60791ef1058d9f696ecb51d2c07fe911d8569d8e" +checksum = "a82418ca169e235e6c399a84e395ab6debeb3bc90edc959bf0f48647c6a32d1b" dependencies = [ "indexmap", - "toml_datetime 0.7.5+spec-1.1.0", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", - "winnow 0.7.15", -] - -[[package]] -name = "toml_edit" -version = "0.25.5+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca1a40644a28bce036923f6a431df0b34236949d111cc07cb6dca830c9ef2e1" -dependencies = [ - "indexmap", - "toml_datetime 1.0.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 +6932,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 +6944,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 +6960,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 +6974,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 +7001,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 +7080,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 +7093,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 +7113,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 +7126,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 +7169,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 +7183,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 +7206,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 +7217,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 +7229,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 +7242,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 +7255,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 +7266,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 +7284,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 +7329,7 @@ dependencies = [ "annotate-snippets", "derive_more", "half", - "itertools 0.14.0", + "itertools", "num-traits", "proc-macro2", "quote", @@ -7011,7 +7345,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 +7353,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", @@ -7033,6 +7367,7 @@ dependencies = [ "js-sys", "log", "naga", + "parking_lot", "portable-atomic", "profiling", "raw-window-handle", @@ -7048,13 +7383,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 +7403,69 @@ 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-emscripten", "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-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 = "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 +7476,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 +7491,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 +7537,7 @@ checksum = "946419efa46664a8070c512fb358ac4acfc6e6215c2396ae5afeb9b72dd6ca7d" dependencies = [ "annotate-snippets", "derive_more", - "itertools 0.14.0", + "itertools", "lalrpop", "lalrpop-util", "lexical", @@ -7191,7 +7553,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7aed068ca1dc8fb182f574c9f2ace45ec988c71ba050f6dd334883fe3b8a88e2" dependencies = [ "half", - "itertools 0.14.0", + "itertools", "num-traits", ] @@ -7238,16 +7600,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 +7641,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 +8080,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 +8115,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 +8215,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 +8294,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 +8325,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 +8345,58 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +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 = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +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 +8422,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..da1c6254 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", "processing_cuda/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" } -naga = { version = "28", features = ["wgsl-in"] } +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/README.md b/README.md index ae0fc95b..2708b475 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,49 @@ libprocessing is an experimental native library with the goal of supporting the ## Getting started -### Rust +### 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). + +We are big fans of [uv](https://github.com/astral-sh/uv) and this is the easiest way to get started using `mewnala` + +#### Setting up uv on linux or macOS +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +``` + +#### For Windows users: +```bash +powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" +``` + +#### Install a mewnala +```bash +# Initialize a project with uv +uv init mewnala-sketchbook && cd mewnala-sketchbook + +# add the package +uv add mewnala + +# run a sketch +uv run sketch.py +``` + +### 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. ### 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 @@ -47,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). \ No newline at end of file +You can read our project design principles [here](./docs/principles.md). 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..72896dcd --- /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 = ["dep:bevy_cuda", "bevy_cuda/cuda-11040"] + +[dependencies] +bevy = { 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 new file mode 100644 index 00000000..8f970b99 --- /dev/null +++ b/crates/processing_cuda/src/lib.rs @@ -0,0 +1,215 @@ +#![cfg(feature = "cuda")] + +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_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_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/Cargo.toml b/crates/processing_pyo3/Cargo.toml index 9660e34d..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] @@ -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/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/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() 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/pyproject.toml b/crates/processing_pyo3/pyproject.toml index c3347daf..0f60a428 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" @@ -49,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..bac01371 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 { @@ -95,27 +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 - } - } -} - -impl Drop for Surface { - fn drop(&mut self) { - let _ = surface_destroy(self.entity); - } -} +pub use crate::surface::Surface; #[pyclass] #[derive(Debug)] @@ -164,6 +181,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,7 +285,9 @@ impl Geometry { pub struct Graphics { pub(crate) entity: Entity, pub surface: Surface, + #[pyo3(get)] pub width: u32, + #[pyo3(get)] pub height: u32, } @@ -344,6 +377,26 @@ impl Graphics { }) } + #[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}")))?; @@ -739,6 +792,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 +1045,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 +1264,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/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 ffd56bb0..e4c97c9d 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; @@ -16,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; @@ -26,6 +31,7 @@ use graphics::{ use material::Material; use pyo3::{ + BoundObject, exceptions::PyRuntimeError, prelude::*, types::{PyDict, PyTuple}, @@ -35,8 +41,103 @@ 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) => { @@ -134,6 +235,13 @@ mod mewnala { use super::Shader; #[pymodule_export] use super::Topology; + #[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] @@ -565,6 +673,42 @@ 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 _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<()> { @@ -673,11 +817,8 @@ mod mewnala { // call setup setup_fn.call0()?; - { - 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 { @@ -694,16 +835,15 @@ 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(); + globals = draw_fn.getattr("__globals__")?; + reset_tracked_globals(); dbg!(locals); } @@ -714,11 +854,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)?; - } + sync_globals(module, &globals)?; + dispatch_event_callbacks(&locals)?; draw_fn .call0() @@ -967,6 +1104,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( @@ -1397,4 +1542,43 @@ 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() + } + + #[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_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/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/graphics.rs b/crates/processing_render/src/graphics.rs index 1038d5a6..ccf42e4a 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, }; @@ -40,22 +40,8 @@ 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)); + app.init_resource::() + .add_systems(PostUpdate, sync_to_surface); } } @@ -66,36 +52,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 { @@ -137,8 +102,8 @@ impl CameraProjection for ProcessingProjection { self.width, self.height, // bottom = height 0.0, // top = 0 - self.far, self.near, + self.far, ) } @@ -185,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), }; @@ -201,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", ) @@ -277,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>, @@ -432,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(()) } @@ -440,10 +450,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 +495,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 +504,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 +569,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 +580,6 @@ pub fn update_region_write( u32, )>, graphics_query: Query<&Graphics>, - graphics_targets: Res, render_queue: Res, ) -> Result<()> { let graphics = graphics_query @@ -594,17 +593,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(), @@ -727,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); } 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..dc188dc4 100644 --- a/crates/processing_render/src/lib.rs +++ b/crates/processing_render/src/lib.rs @@ -4,13 +4,15 @@ 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; +pub mod monitor; pub mod render; pub mod sketch; pub(crate) mod surface; +pub mod time; pub mod transform; use std::path::PathBuf; @@ -26,6 +28,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)] @@ -248,6 +251,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, @@ -302,8 +313,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 +338,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 +357,7 @@ pub fn graphics_update(graphics_entity: Entity, pixels: &[LinearRgba]) -> error: graphics::update_region_write, ( graphics_entity, + texture, 0, 0, size.width, @@ -364,13 +380,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 +751,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 +761,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 +772,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 +797,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() }) @@ -1279,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/material/custom.rs b/crates/processing_render/src/material/custom.rs index 58427683..04080b8c 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(); @@ -400,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); + let bindings = reflection.create_bindings( + 3, + &source_asset.shader, + render_device, + gpu_images, + gpu_buffers, + ); let unprepared = UnpreparedBindGroup { bindings: BindingResources(bindings), 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/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 afeee6fc..ad4c9c5e 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; @@ -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() }, @@ -341,12 +344,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(()) } @@ -364,10 +365,56 @@ 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) } } + +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) +} 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/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. diff --git a/justfile b/justfile index 9d656460..4af5b1d1 100644 --- a/justfile +++ b/justfile @@ -5,20 +5,26 @@ 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 + +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/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"))] 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);