diff --git a/.cargo/config.toml b/.cargo/config.toml index b2f50a3..7cc0efe 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,8 +1,8 @@ -[alias] -# Building the xtask package in release mode is normally not necessary, but if -# you're going to compile other plugins in release mode then you'd need to -# recompile serde(-derive) because the xtask packages needs serde to parse the -# `bundler.toml` config file. To avoid needing to compile these expensive crates -# twice, we'll default to also running the xtask target in release mode. -xtask = "run --package xtask --release --" -xtask-debug = "run --package xtask --" +[alias] +# Building the xtask package in release mode is normally not necessary, but if +# you're going to compile other plugins in release mode then you'd need to +# recompile serde(-derive) because the xtask packages needs serde to parse the +# `bundler.toml` config file. To avoid needing to compile these expensive crates +# twice, we'll default to also running the xtask target in release mode. +xtask = "run --package xtask --release --" +xtask-debug = "run --package xtask --" diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index b6b5c86..6fca137 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,29 +1,29 @@ -on: [push, pull_request] - -name: Build - -jobs: - build: - name: Build - strategy: - matrix: - os: [ macos-latest, windows-latest ] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - override: true - - uses: actions-rs/cargo@v1 - with: - command: build - args: --workspace --exclude=python-chop --exclude=td-rs-derive-py -# - uses: actions-rs/cargo@v1 -# with: -# command: xtask -# args: build cpu-memory-top -# - name: Check `cargo fmt` was run -# run: | -# cd protocol_codegen -# cargo fmt -- --check +on: [push, pull_request] + +name: Build + +jobs: + build: + name: Build + strategy: + matrix: + os: [ macos-latest, windows-latest ] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + override: true + - uses: actions-rs/cargo@v1 + with: + command: build + args: --workspace --exclude=python-chop --exclude=bevy-top --exclude=cuda --exclude=td-rs-derive-py +# - uses: actions-rs/cargo@v1 +# with: +# command: xtask +# args: build cpu-memory-top +# - name: Check `cargo fmt` was run +# run: | +# cd protocol_codegen +# cargo fmt -- --check diff --git a/.gitignore b/.gitignore index 2da30fd..fca3795 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,16 @@ -.idea/ -.DS_Store -/target -include/ -build/ -.vs/ -Debug/ -Release/ - -RustCHOP.xcodeproj/project.xcworkspace/xcuserdata -*.xcodeproj/ -cmake-build* -output.plist - -venv/ +.idea/ +.DS_Store +/target +include/ +build/ +.vs/ +Debug/ +Release/ + +RustCHOP.xcodeproj/project.xcworkspace/xcuserdata +*.xcodeproj/ +cmake-build* +output.plist + +venv/ +vendor/ \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..4cae55e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,135 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +**td-rs** is an experimental Rust framework for creating TouchDesigner plugins. It provides Rust bindings for TouchDesigner's C++ plugin API, enabling development of CHOPs, TOPs, SOPs, and DATs in Rust instead of C++. + +## Architecture + +### Workspace Structure +- **`td-rs-base/`** - Core traits, types, and shared functionality for all plugin types +- **`td-rs-chop/`**, **`td-rs-dat/`**, **`td-rs-sop/`**, **`td-rs-top/`** - Operator-specific frameworks +- **`td-rs-derive/`** - Procedural macros for parameter generation +- **`td-rs-xtask/`** - Build system and plugin management tools +- **`plugins/`** - Example plugins organized by operator type + +### Plugin Development Pattern +Each plugin follows this structure: +1. Define parameter struct with `#[derive(Params)]` +2. Implement required traits: `OpNew`, `OpInfo`, `Op`, and operator-specific trait (`Chop`, `Top`, etc.) +3. Use `chop_plugin!()`, `top_plugin!()`, etc. macro to register +4. Configure `Cargo.toml` with `crate-type = ["staticlib"]` and `package.metadata.td-rs.type` + +### Key Traits +- **`OpInfo`** - Plugin metadata (name, version, inputs/outputs) +- **`OpNew`** - Constructor +- **`Op`** - Base functionality (parameters, pulse handling) +- **`Chop`/`Top`/`Sop`/`Dat`** - Operator-specific execution logic + +## Development Commands + +Use `just` (justfile) for all build operations: + +```bash +# Build a specific plugin +just build + +# Install plugin to TouchDesigner plugins directory +just install + +# Watch mode development (requires bacon) +just dev + +# List all available plugins +just list-plugins +``` + +### Plugin locations: +- **Windows**: `$HOME\OneDrive\Documents\Derivative\Plugins\` +- **macOS**: `$HOME/Library/Application Support/Derivative/TouchDesigner099/Plugins` + +## Testing + +No centralized test suite - each plugin can have individual tests. Use standard `cargo test` in plugin directories. + +## Platform Requirements + +### Windows +- MSVC toolchain with Clang support +- May require setting `LIBCLANG_PATH` environment variable +- Target: `x86_64-pc-windows-msvc` + +### macOS +- Xcode with command line tools +- Target: `aarch64-apple-darwin` (Apple Silicon) + +## Current Development Status - Bevy TOP Plugin + +### 🚧 Active Issues (December 2024) + +**PRIMARY FOCUS**: Debugging bevy-top plugin CUDA-Vulkan-Bevy interop pipeline + +**CRITICAL FIXES COMPLETED** ✅: +1. **Format Pipeline Overhaul**: Fixed sRGB vs linear format mismatches + - `BGRA8Fixed` → `Bgra8Unorm` (linear) for base textures + - `Bgra8UnormSrgb` views for Bevy camera compatibility + - Dynamic format detection instead of hardcoded `Bgra8UnormSrgb` + +2. **API Call Ordering**: Fixed "input before output" crash + - Get input CUDA arrays BEFORE `beginCUDAOperations()` (matches C++ sample) + - Proper CUDA array validation timing + +3. **Bytes-per-pixel Calculations**: Fixed hardcoded assumptions + - `get_bytes_per_pixel()` function for all TouchDesigner formats + - Dynamic width calculations instead of `width * 4` + +**CURRENT DETECTIVE WORK** 🕵️‍♀️: +4. **Row Pitch Alignment Issues**: `cudaErrorInvalidPitchValue` + - **Problem**: Vulkan external memory row pitch ≠ CUDA alignment requirements + - **Root Cause**: GPU drivers align texture rows (256/512-byte boundaries) + - **Solution**: Query actual Vulkan row pitch via `get_image_subresource_layout()` + - **Status**: Mega debug logging added, testing alignment fixes + +5. **Pending Investigation**: Segfault when input connected before output + - May be related to row pitch/external memory lifecycle issues + +### 🧬 Technical Deep Dive - CUDA-Vulkan Pipeline + +**Architecture**: TouchDesigner → CUDA → Vulkan External Memory → Bevy → Back to CUDA → TouchDesigner + +**The Problem**: Hardware-level memory layout assumptions +- **TouchDesigner**: Provides CUDA arrays with unknown pitch +- **Vulkan**: Creates external memory with driver-aligned row pitch +- **CUDA**: Strict alignment requirements for `cudaMemcpy2D` operations +- **Mismatch**: `width * bytes_per_pixel` ≠ actual driver row pitch + +**Detective Evidence**: +```rust +// What we calculate: 512 * 4 = 2048 bytes +// What Vulkan actually uses: 2304 bytes (512-byte aligned) +// What CUDA needs: Aligned pitch values +``` + +**Current Fix Strategy**: +- Query real Vulkan row pitch via `vk::get_image_subresource_layout()` +- Align pitch to CUDA requirements (512-byte boundaries) +- Use actual pitch in `cudaMemcpy2DFromArray`/`cudaMemcpy2DToArray` + +## Important Implementation Details + +1. **FFI Safety**: Uses autocxx for C++ bridge generation and careful Pin<> usage +2. **Parameter System**: Derive macros generate TouchDesigner-compatible parameters automatically +3. **Memory Management**: Rust structs are managed via opaque pointers in C++ layer +4. **Optional Features**: `python` (PyO3 integration), `tracing` (logging), `tokio` (async support) +5. **Alpha Status**: Experimental - expect breaking changes and potential instability + +## Working with Plugins + +When creating new plugins: +1. Copy existing plugin structure from `/plugins/` examples +2. Update `Cargo.toml` metadata for operator type +3. Implement required traits following established patterns +4. Use parameter derive macros for TouchDesigner integration +5. Test with `just dev ` for rapid iteration \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ddeb0a..ad37f04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,32 +1,32 @@ -# This is intended only for use with CLion - -cmake_minimum_required(VERSION 3.25) -project(td_rs) - -set(CMAKE_CXX_STANDARD 14) - -include_directories(.) -include_directories(target/aarch64-apple-darwin/cxxbridge/rust) -include_directories(target/aarch64-apple-darwin/cxxbridge/td-rs-base/src) -include_directories(target/aarch64-apple-darwin/cxxbridge/td-rs-chop/src) -include_directories(target/aarch64-apple-darwin/cxxbridge/td-rs-param/src) -include_directories(target/cxxbridge/rust) -include_directories(target/cxxbridge/td-rs-base/src) -include_directories(target/cxxbridge/td-rs-chop/src) -include_directories(target/cxxbridge/td-rs-param/src) -include_directories(td-rs-base/src) -include_directories(td-rs-base/src/operator_input) -include_directories(td-rs-base/src/parameter_manager) -include_directories(td-rs-chop/src) -include_directories(td-rs-sop/src) - -add_executable(td_rs - td-rs-base/src/CPlusPlus_Common.h - td-rs-chop/src/CHOP_CPlusPlusBase.h - td-rs-chop/src/RustChopPlugin.cpp - td-rs-chop/src/RustChopPlugin.h - td-rs-base/src/RustBase.h - td-rs-sop/src/RustSopPlugin.h - td-rs-top/src/RustTopPlugin.cpp - td-rs-top/src/TOP_CPlusPlusBase.h - td-rs-top/src/RustTopPlugin.h td-rs-dat/src/RustDatPlugin.cpp td-rs-sop/src/RustSopPlugin.cpp td-rs-base/src/RustPy.h) +# This is intended only for use with CLion + +cmake_minimum_required(VERSION 3.25) +project(td_rs) + +set(CMAKE_CXX_STANDARD 14) + +include_directories(.) +include_directories(target/aarch64-apple-darwin/cxxbridge/rust) +include_directories(target/aarch64-apple-darwin/cxxbridge/td-rs-base/src) +include_directories(target/aarch64-apple-darwin/cxxbridge/td-rs-chop/src) +include_directories(target/aarch64-apple-darwin/cxxbridge/td-rs-param/src) +include_directories(target/cxxbridge/rust) +include_directories(target/cxxbridge/td-rs-base/src) +include_directories(target/cxxbridge/td-rs-chop/src) +include_directories(target/cxxbridge/td-rs-param/src) +include_directories(td-rs-base/src) +include_directories(td-rs-base/src/operator_input) +include_directories(td-rs-base/src/parameter_manager) +include_directories(td-rs-chop/src) +include_directories(td-rs-sop/src) + +add_executable(td_rs + td-rs-base/src/CPlusPlus_Common.h + td-rs-chop/src/CHOP_CPlusPlusBase.h + td-rs-chop/src/RustChopPlugin.cpp + td-rs-chop/src/RustChopPlugin.h + td-rs-base/src/RustBase.h + td-rs-sop/src/RustSopPlugin.h + td-rs-top/src/RustTopPlugin.cpp + td-rs-top/src/TOP_CPlusPlusBase.h + td-rs-top/src/RustTopPlugin.h td-rs-dat/src/RustDatPlugin.cpp td-rs-sop/src/RustSopPlugin.cpp td-rs-base/src/RustPy.h) diff --git a/Cargo.lock b/Cargo.lock index 1c62d96..721fd84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,65 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "accesskit" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "becf0eb5215b6ecb0a739c31c21bd83c4f326524c9b46b7e882d77559b60a529" + +[[package]] +name = "accesskit_consumer" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0bf66a7bf0b7ea4fd7742d50b64782a88f99217cf246b3f93b4162528dde520" +dependencies = [ + "accesskit", + "hashbrown 0.15.4", + "immutable-chunkmap", +] + +[[package]] +name = "accesskit_macos" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e230718177753b4e4ad9e1d9f6cfc2f4921212d4c1c480b253f526babb258d" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.15.4", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + +[[package]] +name = "accesskit_windows" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65178f3df98a51e4238e584fcb255cb1a4f9111820848eeddd37663be40a625f" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.15.4", + "paste", + "static_assertions", + "windows 0.58.0", + "windows-core 0.58.0", +] + +[[package]] +name = "accesskit_winit" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34d941bb8c414caba6e206de669c7dc0dbeb305640ea890772ee422a40e6b89f" +dependencies = [ + "accesskit", + "accesskit_macos", + "accesskit_windows", + "raw-window-handle", + "winit", +] + [[package]] name = "addr2line" version = "0.19.0" @@ -26,22 +85,11 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if 1.0.0", - "cipher", - "cpufeatures", -] - [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if 1.0.0", "once_cell", @@ -55,14 +103,57 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ - "memchr 2.7.4", + "memchr", ] [[package]] -name = "allocator-api2" -version = "0.2.21" +name = "alsa" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" +dependencies = [ + "alsa-sys", + "bitflags 2.9.1", + "cfg-if 1.0.0", + "libc", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "android-activity" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" +dependencies = [ + "android-properties", + "bitflags 2.9.1", + "cc", + "cesu8", + "jni", + "jni-sys", + "libc", + "log", + "ndk 0.9.0", + "ndk-context", + "ndk-sys 0.6.0+11769913", + "num_enum", + "thiserror 1.0.69", +] + +[[package]] +name = "android-properties" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" [[package]] name = "android-tzdata" @@ -70,6 +161,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" +[[package]] +name = "android_log-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -90,15 +187,24 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "approx" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] [[package]] name = "aquamarine" @@ -119,15 +225,141 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + +[[package]] +name = "ash" +version = "0.38.0+1.3.281" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading", +] + +[[package]] +name = "assert_type_match" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f548ad2c4031f2902e3edc1f29c29e835829437de49562d8eb5dc5584d3a1043" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" +dependencies = [ + "portable-atomic", +] + [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "atomicow" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52e8890bb9844440d0c412fa74b67fd2f14e85248b6e00708059b6da9e5f8bf" +dependencies = [ + "portable-atomic", + "portable-atomic-util", ] [[package]] @@ -170,7 +402,7 @@ version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6740720b363b98ee56ffc5ee246e62185a9828c8c60f6b6f8f314d18b7a311" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "cexpr", "clang-sys", "itertools 0.13.0", @@ -180,7 +412,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.92", + "syn 2.0.101", ] [[package]] @@ -191,7 +423,7 @@ dependencies = [ "autocxx-engine 0.27.0 (git+https://github.com/tychedelia/autocxx.git?branch=main)", "env_logger 0.9.3", "indexmap 1.9.3", - "syn 2.0.92", + "syn 2.0.101", ] [[package]] @@ -202,7 +434,7 @@ dependencies = [ "autocxx-engine 0.27.0 (git+https://github.com/tychedelia/autocxx.git)", "env_logger 0.9.3", "indexmap 1.9.3", - "syn 2.0.92", + "syn 2.0.101", ] [[package]] @@ -227,9 +459,9 @@ dependencies = [ "regex", "rustversion", "serde_json", - "syn 2.0.92", + "syn 2.0.101", "tempfile", - "thiserror", + "thiserror 1.0.69", "version_check", ] @@ -255,9 +487,9 @@ dependencies = [ "regex", "rustversion", "serde_json", - "syn 2.0.92", + "syn 2.0.101", "tempfile", - "thiserror", + "thiserror 1.0.69", "version_check", ] @@ -270,7 +502,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", ] [[package]] @@ -286,8 +518,8 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.92", - "thiserror", + "syn 2.0.101", + "thiserror 1.0.69", ] [[package]] @@ -303,15 +535,15 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.92", - "thiserror", + "syn 2.0.101", + "thiserror 1.0.69", ] [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line 0.24.2", "cfg-if 1.0.0", @@ -344,2346 +576,4296 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bincode" -version = "1.3.3" +name = "bevy" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +checksum = "4b8369c16b7c017437021341521f8b4a0d98e1c70113fb358c3258ae7d661d79" dependencies = [ - "serde", + "bevy_internal", ] [[package]] -name = "bincode" -version = "2.0.0-rc.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95" +name = "bevy-top" +version = "0.1.0" dependencies = [ - "serde", + "anyhow", + "ash", + "bevy", + "cudarc", + "td-rs-derive", + "td-rs-top", + "wgpu", ] [[package]] -name = "bit_field" -version = "0.10.2" +name = "bevy_a11y" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" +checksum = "ed3561712cf49074d89e9989bfc2e6c6add5d33288f689db9a0c333300d2d004" +dependencies = [ + "accesskit", + "bevy_app", + "bevy_derive", + "bevy_ecs", + "bevy_reflect", +] [[package]] -name = "bitflags" -version = "1.3.2" +name = "bevy_animation" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "49796627726d0b9a722ad9a0127719e7c1868f474d6575ec0f411e8299c4d7bb" +dependencies = [ + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_derive", + "bevy_ecs", + "bevy_log", + "bevy_math", + "bevy_mesh", + "bevy_platform", + "bevy_reflect", + "bevy_render", + "bevy_time", + "bevy_transform", + "bevy_utils", + "blake3", + "derive_more", + "downcast-rs", + "either", + "petgraph", + "ron", + "serde", + "smallvec 1.15.1", + "thiserror 2.0.12", + "thread_local", + "tracing", + "uuid", +] [[package]] -name = "bitflags" -version = "2.6.0" +name = "bevy_app" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "4491cc4c718ae76b4c6883df58b94cc88b32dcd894ea8d5b603c7c7da72ca967" +dependencies = [ + "bevy_derive", + "bevy_ecs", + "bevy_platform", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "cfg-if 1.0.0", + "console_error_panic_hook", + "ctrlc", + "downcast-rs", + "log", + "thiserror 2.0.12", + "variadics_please", + "wasm-bindgen", + "web-sys", +] [[package]] -name = "block-buffer" -version = "0.10.4" +name = "bevy_asset" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "f56111d9b88d8649f331a667d9d72163fb26bd09518ca16476d238653823db1e" dependencies = [ - "generic-array", + "async-broadcast", + "async-fs", + "async-lock", + "atomicow", + "bevy_app", + "bevy_asset_macros", + "bevy_ecs", + "bevy_platform", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "bevy_window", + "bitflags 2.9.1", + "blake3", + "crossbeam-channel", + "derive_more", + "disqualified", + "downcast-rs", + "either", + "futures-io", + "futures-lite", + "js-sys", + "parking_lot 0.12.4", + "ron", + "serde", + "stackfuture", + "thiserror 2.0.12", + "tracing", + "uuid", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", ] [[package]] -name = "bumpalo" -version = "3.16.0" +name = "bevy_asset_macros" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "a4cca3e67c0ec760d8889d42293d987ce5da92eaf9c592bf5d503728a63b276d" +dependencies = [ + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn 2.0.101", +] [[package]] -name = "burn" -version = "0.10.0" +name = "bevy_audio" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e06bb3dfa90408228c879224e26a8bbf072aa2a68194c9b512f715624525c7cc" +checksum = "f2b4f6f2a5c6c0e7c6825e791d2a061c76c2d6784f114c8f24382163fabbfaaa" dependencies = [ - "burn-core", + "bevy_app", + "bevy_asset", + "bevy_derive", + "bevy_ecs", + "bevy_math", + "bevy_reflect", + "bevy_transform", + "cpal", + "rodio", + "tracing", ] [[package]] -name = "burn-autodiff" -version = "0.10.0" +name = "bevy_color" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b20c3ba4141da32bbcc48a4ce33a0fbf09742dfb6f17d6e781f27e076bf06d82" +checksum = "5c101cbe1e26b8d701eb77263b14346e2e0cbbd2a6e254b9b1aead814e5ca8d3" dependencies = [ - "burn-common", - "burn-tensor", - "burn-tensor-testgen", - "derive-new", - "spin", + "bevy_math", + "bevy_reflect", + "bytemuck", + "derive_more", + "encase", + "serde", + "thiserror 2.0.12", + "wgpu-types", +] + +[[package]] +name = "bevy_core_pipeline" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed46363cad80dc00f08254c3015232bd6f640738403961c6d63e7ecfc61625" +dependencies = [ + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_derive", + "bevy_diagnostic", + "bevy_ecs", + "bevy_image", + "bevy_math", + "bevy_platform", + "bevy_reflect", + "bevy_render", + "bevy_transform", + "bevy_utils", + "bevy_window", + "bitflags 2.9.1", + "bytemuck", + "nonmax", + "radsort", + "serde", + "smallvec 1.15.1", + "thiserror 2.0.12", + "tracing", ] [[package]] -name = "burn-common" -version = "0.10.0" +name = "bevy_derive" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ce227728da80c4c7f932e66900d285ff6e04b815d77d769fd2ade463acb0d52" +checksum = "1b837bf6c51806b10ebfa9edf1844ad80a3a0760d6c5fac4e90761df91a8901a" dependencies = [ - "async-trait", - "derive-new", - "getrandom", - "rand", - "spin", - "uuid", + "bevy_macro_utils", + "quote", + "syn 2.0.101", ] [[package]] -name = "burn-core" -version = "0.10.0" +name = "bevy_diagnostic" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbbeb7c07436e89d3b7e2445198f5d4142255bf74564eb4dc6cb9898f00d2da5" +checksum = "48797366f312a8f31e237d08ce3ee70162591282d2bfe7c5ad8be196fb263e55" dependencies = [ - "bincode 2.0.0-rc.3", - "burn-common", - "burn-dataset", - "burn-derive", - "burn-tensor", - "derive-new", - "flate2", - "half", - "hashbrown 0.14.5", - "libm", + "bevy_app", + "bevy_ecs", + "bevy_platform", + "bevy_tasks", + "bevy_time", + "bevy_utils", + "const-fnv1a-hash", "log", - "rand", - "rmp-serde", "serde", - "serde_json", - "spin", + "sysinfo", ] [[package]] -name = "burn-dataset" -version = "0.10.0" +name = "bevy_ecs" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c7f12f9a55e82d327384e20c394c79e5a414b245fe59c37346e7a98234d1707" +checksum = "3c2bf6521aae57a0ec3487c4bfb59e36c4a378e834b626a4bea6a885af2fdfe7" dependencies = [ - "csv", - "derive-new", - "dirs", - "rand", - "rmp-serde", - "sanitize-filename", + "arrayvec", + "bevy_ecs_macros", + "bevy_platform", + "bevy_ptr", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "bitflags 2.9.1", + "bumpalo", + "concurrent-queue", + "derive_more", + "disqualified", + "fixedbitset", + "indexmap 2.9.0", + "log", + "nonmax", "serde", - "serde_json", - "strum", - "strum_macros", - "tempfile", - "thiserror", + "smallvec 1.15.1", + "thiserror 2.0.12", + "variadics_please", ] [[package]] -name = "burn-derive" -version = "0.10.0" +name = "bevy_ecs_macros" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0726d6006ab4f1c65b37b079a8663ad168110976fb57234764495ed8c49a94b6" +checksum = "38748d6f3339175c582d751f410fb60a93baf2286c3deb7efebb0878dce7f413" dependencies = [ - "derive-new", + "bevy_macro_utils", "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", ] [[package]] -name = "burn-ndarray" -version = "0.10.0" +name = "bevy_encase_derive" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cbba6e5180a91a48e2e5da7e74107d82dae9cc94a772a73783eb1381dd71fa2" +checksum = "8148f4edee470a2ea5cad010184c492a4c94c36d7a7158ea28e134ea87f274ab" dependencies = [ - "burn-autodiff", - "burn-common", - "burn-tensor", - "derive-new", - "libm", - "matrixmultiply", - "ndarray", - "num-traits", - "rand", - "rayon", - "spin", + "bevy_macro_utils", + "encase_derive_impl", ] [[package]] -name = "burn-tch" -version = "0.10.0" +name = "bevy_gilrs" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d6a7c694493aeef181f495cdcc0e2e694804d1e5cce474d5689fdb91dae9b2" +checksum = "97efef87c631949e67d06bb5d7dfd2a5f936b3b379afb6b1485b08edbb219b87" dependencies = [ - "burn-tensor", - "half", - "libc", - "rand", - "tch", + "bevy_app", + "bevy_ecs", + "bevy_input", + "bevy_platform", + "bevy_time", + "bevy_utils", + "gilrs", + "thiserror 2.0.12", + "tracing", ] [[package]] -name = "burn-tensor" -version = "0.10.0" +name = "bevy_gizmos" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4ddf687c9e2ddf235bb1528530b5e6c04601d4240aca78de6484fd01cc81e9f" +checksum = "7823154a9682128c261d8bddb3a4d7192a188490075c527af04520c2f0f8aad6" dependencies = [ - "burn-common", - "burn-tensor-testgen", - "derive-new", - "half", - "hashbrown 0.14.5", - "libm", - "num-traits", - "rand", - "rand_distr", - "serde", + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core_pipeline", + "bevy_ecs", + "bevy_gizmos_macros", + "bevy_image", + "bevy_math", + "bevy_pbr", + "bevy_reflect", + "bevy_render", + "bevy_sprite", + "bevy_time", + "bevy_transform", + "bevy_utils", + "bytemuck", + "tracing", ] [[package]] -name = "burn-tensor-testgen" -version = "0.10.0" +name = "bevy_gizmos_macros" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92da000e738bcf20ec873d63c3b46ed4e0afa10fb14ea3133874886c0fb591f" +checksum = "f378f3b513218ddc78254bbe76536d9de59c1429ebd0c14f5d8f2a25812131ad" dependencies = [ + "bevy_macro_utils", "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", ] [[package]] -name = "bytemuck" -version = "1.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" - -[[package]] -name = "byteorder" -version = "1.5.0" +name = "bevy_gltf" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "10a080237c0b8842ccc15a06d3379302c68580eeea4497b1c7387e470eda1f07" +dependencies = [ + "base64 0.22.1", + "bevy_animation", + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core_pipeline", + "bevy_ecs", + "bevy_image", + "bevy_math", + "bevy_mesh", + "bevy_pbr", + "bevy_platform", + "bevy_reflect", + "bevy_render", + "bevy_scene", + "bevy_tasks", + "bevy_transform", + "bevy_utils", + "fixedbitset", + "gltf", + "itertools 0.14.0", + "percent-encoding", + "serde", + "serde_json", + "smallvec 1.15.1", + "thiserror 2.0.12", + "tracing", +] [[package]] -name = "bytes" -version = "0.4.12" +name = "bevy_image" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +checksum = "65e6e900cfecadbc3149953169e36b9e26f922ed8b002d62339d8a9dc6129328" dependencies = [ - "byteorder", - "iovec", + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_math", + "bevy_platform", + "bevy_reflect", + "bevy_utils", + "bitflags 2.9.1", + "bytemuck", + "futures-lite", + "guillotiere", + "half", + "image", + "ktx2", + "rectangle-pack", + "ruzstd", + "serde", + "thiserror 2.0.12", + "tracing", + "wgpu-types", ] [[package]] -name = "bytes" -version = "1.9.0" +name = "bevy_input" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "18d6b6516433f6f7d680f648d04eb1866bb3927a1782d52f74831b62042f3cd1" +dependencies = [ + "bevy_app", + "bevy_ecs", + "bevy_math", + "bevy_platform", + "bevy_reflect", + "bevy_utils", + "derive_more", + "log", + "smol_str", + "thiserror 2.0.12", +] [[package]] -name = "bzip2" -version = "0.4.4" +name = "bevy_input_focus" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +checksum = "2e2d079fda74d1416e0a57dac29ea2b79ff77f420cd6b87f833d3aa29a46bc4d" dependencies = [ - "bzip2-sys", - "libc", + "bevy_app", + "bevy_ecs", + "bevy_input", + "bevy_math", + "bevy_reflect", + "bevy_window", + "log", + "thiserror 2.0.12", +] + +[[package]] +name = "bevy_internal" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "857da8785678fde537d02944cd20dec9cafb7d4c447efe15f898dc60e733cacd" +dependencies = [ + "bevy_a11y", + "bevy_animation", + "bevy_app", + "bevy_asset", + "bevy_audio", + "bevy_color", + "bevy_core_pipeline", + "bevy_derive", + "bevy_diagnostic", + "bevy_ecs", + "bevy_gilrs", + "bevy_gizmos", + "bevy_gltf", + "bevy_image", + "bevy_input", + "bevy_input_focus", + "bevy_log", + "bevy_math", + "bevy_pbr", + "bevy_picking", + "bevy_platform", + "bevy_ptr", + "bevy_reflect", + "bevy_render", + "bevy_scene", + "bevy_sprite", + "bevy_state", + "bevy_tasks", + "bevy_text", + "bevy_time", + "bevy_transform", + "bevy_ui", + "bevy_utils", + "bevy_window", + "bevy_winit", +] + +[[package]] +name = "bevy_log" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a61ee8aef17a974f5ca481dcedf0c2bd52670e231d4c4bc9ddef58328865f9" +dependencies = [ + "android_log-sys", + "bevy_app", + "bevy_ecs", + "bevy_utils", + "tracing", + "tracing-log 0.2.0", + "tracing-oslog", + "tracing-subscriber 0.3.19", + "tracing-wasm", ] [[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" +name = "bevy_macro_utils" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +checksum = "052eeebcb8e7e072beea5031b227d9a290f8a7fbbb947573ab6ec81df0fb94be" dependencies = [ - "cc", - "libc", - "pkg-config", + "parking_lot 0.12.4", + "proc-macro2", + "quote", + "syn 2.0.101", + "toml_edit", ] [[package]] -name = "camino" -version = "1.1.9" +name = "bevy_math" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +checksum = "68553e0090fe9c3ba066c65629f636bd58e4ebd9444fdba097b91af6cd3e243f" dependencies = [ + "approx", + "bevy_reflect", + "derive_more", + "glam", + "itertools 0.14.0", + "libm", + "rand", + "rand_distr", "serde", + "smallvec 1.15.1", + "thiserror 2.0.12", + "variadics_please", ] [[package]] -name = "cargo-platform" -version = "0.1.9" +name = "bevy_mesh" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +checksum = "b10399c7027001edbc0406d7d0198596b1f07206c1aae715274106ba5bdcac40" dependencies = [ + "bevy_asset", + "bevy_derive", + "bevy_ecs", + "bevy_image", + "bevy_math", + "bevy_mikktspace", + "bevy_platform", + "bevy_reflect", + "bevy_transform", + "bevy_utils", + "bitflags 2.9.1", + "bytemuck", + "hexasphere", "serde", + "thiserror 2.0.12", + "tracing", + "wgpu-types", ] [[package]] -name = "cargo_metadata" -version = "0.15.4" +name = "bevy_mikktspace" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +checksum = "8bb60c753b968a2de0fd279b76a3d19517695e771edb4c23575c7f92156315de" dependencies = [ - "camino", - "cargo-platform", - "semver 1.0.24", - "serde", - "serde_json", - "thiserror", + "glam", ] [[package]] -name = "cc" -version = "1.2.6" +name = "bevy_pbr" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333" +checksum = "d5e0b4eb871f364a0d217f70f6c41d7fdc6f9f931fa1abbf222180c03d0ae410" dependencies = [ - "jobserver", - "libc", - "shlex", + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core_pipeline", + "bevy_derive", + "bevy_diagnostic", + "bevy_ecs", + "bevy_image", + "bevy_math", + "bevy_platform", + "bevy_reflect", + "bevy_render", + "bevy_transform", + "bevy_utils", + "bevy_window", + "bitflags 2.9.1", + "bytemuck", + "derive_more", + "fixedbitset", + "nonmax", + "offset-allocator", + "radsort", + "smallvec 1.15.1", + "static_assertions", + "thiserror 2.0.12", + "tracing", ] [[package]] -name = "cexpr" -version = "0.6.0" +name = "bevy_picking" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +checksum = "8ed04757938655ed8094ea1efb533f99063a8b22abffc22010c694d291522850" dependencies = [ - "nom 7.1.3", + "bevy_app", + "bevy_asset", + "bevy_derive", + "bevy_ecs", + "bevy_input", + "bevy_math", + "bevy_mesh", + "bevy_platform", + "bevy_reflect", + "bevy_render", + "bevy_time", + "bevy_transform", + "bevy_utils", + "bevy_window", + "crossbeam-channel", + "tracing", + "uuid", ] [[package]] -name = "cfg-if" -version = "0.1.10" +name = "bevy_platform" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "f7573dc824a1b08b4c93fdbe421c53e1e8188e9ca1dd74a414455fe571facb47" +dependencies = [ + "cfg-if 1.0.0", + "critical-section", + "foldhash", + "getrandom 0.2.16", + "hashbrown 0.15.4", + "portable-atomic", + "portable-atomic-util", + "serde", + "spin", + "web-time", +] [[package]] -name = "cfg-if" -version = "1.0.0" +name = "bevy_ptr" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "df7370d0e46b60e071917711d0860721f5347bc958bf325975ae6913a5dfcf01" [[package]] -name = "chrono" -version = "0.4.39" +name = "bevy_reflect" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "daeb91a63a1a4df00aa58da8cc4ddbd4b9f16ab8bb647c5553eb156ce36fa8c2" dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", + "assert_type_match", + "bevy_platform", + "bevy_ptr", + "bevy_reflect_derive", + "bevy_utils", + "derive_more", + "disqualified", + "downcast-rs", + "erased-serde", + "foldhash", + "glam", + "petgraph", "serde", - "windows-targets 0.52.6", + "smallvec 1.15.1", + "smol_str", + "thiserror 2.0.12", + "uuid", + "variadics_please", + "wgpu-types", ] [[package]] -name = "cipher" -version = "0.4.4" +name = "bevy_reflect_derive" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +checksum = "40ddadc55fe16b45faaa54ab2f9cb00548013c74812e8b018aa172387103cce6" dependencies = [ - "crypto-common", - "inout", + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn 2.0.101", + "uuid", ] [[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", +name = "bevy_render" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef91fed1f09405769214b99ebe4390d69c1af5cdd27967deae9135c550eb1667" +dependencies = [ + "async-channel", + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_derive", + "bevy_diagnostic", + "bevy_ecs", + "bevy_encase_derive", + "bevy_image", + "bevy_math", + "bevy_mesh", + "bevy_platform", + "bevy_reflect", + "bevy_render_macros", + "bevy_tasks", + "bevy_time", + "bevy_transform", + "bevy_utils", + "bevy_window", + "bitflags 2.9.1", + "bytemuck", + "codespan-reporting 0.11.1", + "derive_more", + "downcast-rs", + "encase", + "fixedbitset", + "futures-lite", + "image", + "indexmap 2.9.0", + "js-sys", + "ktx2", + "naga", + "naga_oil", + "nonmax", + "offset-allocator", + "send_wrapper", + "serde", + "smallvec 1.15.1", + "thiserror 2.0.12", + "tracing", + "variadics_please", + "wasm-bindgen", + "web-sys", + "wgpu", ] [[package]] -name = "clap" -version = "4.5.23" +name = "bevy_render_macros" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +checksum = "abd42cf6c875bcf38da859f8e731e119a6aff190d41dd0a1b6000ad57cf2ed3d" dependencies = [ - "clap_builder", + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn 2.0.101", ] [[package]] -name = "clap_builder" -version = "4.5.23" +name = "bevy_scene" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +checksum = "5c52ca165200995fe8afd2a1a6c03e4ffee49198a1d4653d32240ea7f217d4ab" dependencies = [ - "anstyle", - "clap_lex", - "strsim", + "bevy_app", + "bevy_asset", + "bevy_derive", + "bevy_ecs", + "bevy_platform", + "bevy_reflect", + "bevy_render", + "bevy_transform", + "bevy_utils", + "derive_more", + "serde", + "thiserror 2.0.12", + "uuid", ] [[package]] -name = "clap_lex" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +name = "bevy_sprite" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ccae7bab2cb956fb0434004c359e432a3a1a074a6ef4eb471f1fb099f0b620b" +dependencies = [ + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core_pipeline", + "bevy_derive", + "bevy_ecs", + "bevy_image", + "bevy_math", + "bevy_picking", + "bevy_platform", + "bevy_reflect", + "bevy_render", + "bevy_transform", + "bevy_utils", + "bevy_window", + "bitflags 2.9.1", + "bytemuck", + "derive_more", + "fixedbitset", + "nonmax", + "radsort", + "tracing", +] [[package]] -name = "cloudabi" -version = "0.0.3" +name = "bevy_state" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +checksum = "155d3cd97b900539008cdcaa702f88b724d94b08977b8e591a32536ce66faa8c" dependencies = [ - "bitflags 1.3.2", + "bevy_app", + "bevy_ecs", + "bevy_platform", + "bevy_reflect", + "bevy_state_macros", + "bevy_utils", + "log", + "variadics_please", ] [[package]] -name = "codespan-reporting" -version = "0.11.1" +name = "bevy_state_macros" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +checksum = "2481c1304fd2a1851a0d4cb63a1ce6421ae40f3f0117cbc9882963ee4c9bb609" dependencies = [ - "termcolor", - "unicode-width 0.1.14", + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn 2.0.101", ] [[package]] -name = "color_quant" -version = "1.1.0" +name = "bevy_tasks" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +checksum = "5b674242641cab680688fc3b850243b351c1af49d4f3417a576debd6cca8dcf5" +dependencies = [ + "async-executor", + "async-task", + "atomic-waker", + "bevy_platform", + "cfg-if 1.0.0", + "crossbeam-queue 0.3.12", + "derive_more", + "futures-channel", + "futures-lite", + "heapless", + "pin-project", + "wasm-bindgen-futures", +] [[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +name = "bevy_text" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d76c85366159f5f54110f33321c76d8429cfd8f39638f26793a305dae568b60" +dependencies = [ + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_derive", + "bevy_ecs", + "bevy_image", + "bevy_log", + "bevy_math", + "bevy_platform", + "bevy_reflect", + "bevy_render", + "bevy_sprite", + "bevy_transform", + "bevy_utils", + "bevy_window", + "cosmic-text", + "serde", + "smallvec 1.15.1", + "sys-locale", + "thiserror 2.0.12", + "tracing", + "unicode-bidi", +] [[package]] -name = "convert_case" -version = "0.6.0" +name = "bevy_time" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +checksum = "bc98eb356c75be04fbbc77bb3d8ffa24c8bacd99f76111cee23d444be6ac8c9c" dependencies = [ - "unicode-segmentation", + "bevy_app", + "bevy_ecs", + "bevy_platform", + "bevy_reflect", + "crossbeam-channel", + "log", + "serde", ] [[package]] -name = "core-foundation" -version = "0.9.4" +name = "bevy_transform" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "df218e440bb9a19058e1b80a68a031c887bcf7bd3a145b55f361359a2fa3100d" dependencies = [ - "core-foundation-sys", - "libc", + "bevy_app", + "bevy_ecs", + "bevy_log", + "bevy_math", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "derive_more", + "serde", + "thiserror 2.0.12", +] + +[[package]] +name = "bevy_ui" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea4a4d2ba51865bc3039af29a26b4f52c48b54cc758369f52004caf4b6f03770" +dependencies = [ + "accesskit", + "bevy_a11y", + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core_pipeline", + "bevy_derive", + "bevy_ecs", + "bevy_image", + "bevy_input", + "bevy_math", + "bevy_picking", + "bevy_platform", + "bevy_reflect", + "bevy_render", + "bevy_sprite", + "bevy_text", + "bevy_transform", + "bevy_utils", + "bevy_window", + "bytemuck", + "derive_more", + "nonmax", + "smallvec 1.15.1", + "taffy", + "thiserror 2.0.12", + "tracing", ] [[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpp_demangle" -version = "0.3.5" +name = "bevy_utils" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" +checksum = "94f7a8905a125d2017e8561beefb7f2f5e67e93ff6324f072ad87c5fd6ec3b99" dependencies = [ - "cfg-if 1.0.0", + "bevy_platform", + "thread_local", ] [[package]] -name = "cpu-memory-top" -version = "0.1.0" +name = "bevy_window" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df7e8ad0c17c3cc23ff5566ae2905c255e6986037fb041f74c446216f5c38431" dependencies = [ + "android-activity", + "bevy_app", + "bevy_ecs", + "bevy_input", + "bevy_math", + "bevy_platform", + "bevy_reflect", + "bevy_utils", + "log", + "raw-window-handle", + "serde", + "smol_str", +] + +[[package]] +name = "bevy_winit" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a5e7f00c6b3b6823df5ec2a5e9067273607208919bc8c211773ebb9643c87f0" +dependencies = [ + "accesskit", + "accesskit_winit", + "approx", + "bevy_a11y", + "bevy_app", + "bevy_asset", + "bevy_derive", + "bevy_ecs", + "bevy_image", + "bevy_input", + "bevy_input_focus", + "bevy_log", + "bevy_math", + "bevy_platform", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "bevy_window", "bytemuck", - "td-rs-derive", - "td-rs-top", + "cfg-if 1.0.0", + "crossbeam-channel", + "raw-window-handle", + "tracing", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "winit", ] [[package]] -name = "cpufeatures" -version = "0.2.16" +name = "bincode" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "libc", + "serde", ] [[package]] -name = "cranelift-bforest" -version = "0.97.2" +name = "bindgen" +version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aae6f552c4c0ccfb30b9559b77bc985a387d998e1736cbbe6b14c903f3656cf" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "cranelift-entity", + "bitflags 2.9.1", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.101", ] [[package]] -name = "cranelift-codegen" -version = "0.97.2" +name = "bit-set" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95551de96900cefae691ce895ff2abc691ae3a0b97911a76b45faf99e432937b" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ - "bumpalo", - "cranelift-bforest", - "cranelift-codegen-meta", - "cranelift-codegen-shared", - "cranelift-control", - "cranelift-entity", - "cranelift-isle", - "gimli 0.27.3", - "hashbrown 0.13.2", - "log", - "regalloc2", - "smallvec 1.13.2", - "target-lexicon", + "bit-vec 0.6.3", ] [[package]] -name = "cranelift-codegen-meta" -version = "0.97.2" +name = "bit-set" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36a3ad7b2bb03de3383f258b00ca29d80234bebd5130cb6ef3bae37ada5baab0" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "cranelift-codegen-shared", + "bit-vec 0.8.0", ] [[package]] -name = "cranelift-codegen-shared" -version = "0.97.2" +name = "bit-vec" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915918fee4142c85fb04bafe0bcd697e2fd6c15a260301ea6f8d2ea332a30e86" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] -name = "cranelift-control" -version = "0.97.2" +name = "bit-vec" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e447d548cd7f4fcb87fbd10edbd66a4f77966d17785ed50a08c8f3835483c8" -dependencies = [ - "arbitrary", -] +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] -name = "cranelift-entity" -version = "0.97.2" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d8ab3352a1e5966968d7ab424bd3de8e6b58314760745c3817c2eec3fa2f918" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" dependencies = [ "serde", ] [[package]] -name = "cranelift-frontend" -version = "0.97.2" +name = "blake3" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bffa38431f7554aa1594f122263b87c9e04abc55c9f42b81d37342ac44f79f0" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" dependencies = [ - "cranelift-codegen", - "log", - "smallvec 1.13.2", - "target-lexicon", + "arrayref", + "arrayvec", + "cc", + "cfg-if 1.0.0", + "constant_time_eq", ] [[package]] -name = "cranelift-isle" -version = "0.97.2" +name = "block" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84cef66a71c77938148b72bf006892c89d6be9274a08f7e669ff15a56145d701" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] -name = "cranelift-native" -version = "0.97.2" +name = "block-buffer" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f33c7e5eb446e162d2d10b17fe68e1f091020cc2e4e38b5501c21099600b0a1b" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "cranelift-codegen", - "libc", - "target-lexicon", + "generic-array", ] [[package]] -name = "cranelift-wasm" -version = "0.97.2" +name = "block2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632f7b64fa6a8c5b980eb6a17ef22089e15cb9f779f1ed3bd3072beab0686c09" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" dependencies = [ - "cranelift-codegen", - "cranelift-entity", - "cranelift-frontend", - "itertools 0.10.5", - "log", - "smallvec 1.13.2", - "wasmparser 0.107.0", - "wasmtime-types", + "objc2", ] [[package]] -name = "crc32fast" -version = "1.4.2" +name = "blocking" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ - "cfg-if 1.0.0", + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", ] [[package]] -name = "crossbeam" -version = "0.8.4" +name = "bumpalo" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" + +[[package]] +name = "bytemuck" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" dependencies = [ - "crossbeam-channel", - "crossbeam-deque 0.8.6", - "crossbeam-epoch 0.9.18", - "crossbeam-queue 0.3.12", - "crossbeam-utils 0.8.21", + "bytemuck_derive", ] [[package]] -name = "crossbeam-channel" -version = "0.5.14" +name = "bytemuck_derive" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" dependencies = [ - "crossbeam-utils 0.8.21", + "proc-macro2", + "quote", + "syn 2.0.101", ] [[package]] -name = "crossbeam-deque" -version = "0.7.4" +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" dependencies = [ - "crossbeam-epoch 0.8.2", - "crossbeam-utils 0.7.2", - "maybe-uninit", + "byteorder", + "iovec", ] [[package]] -name = "crossbeam-deque" -version = "0.8.6" +name = "bytes" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "calloop" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "crossbeam-epoch 0.9.18", - "crossbeam-utils 0.8.21", + "bitflags 2.9.1", + "log", + "polling", + "rustix 0.38.44", + "slab", + "thiserror 1.0.69", ] [[package]] -name = "crossbeam-epoch" -version = "0.8.2" +name = "camino" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" dependencies = [ - "autocfg", - "cfg-if 0.1.10", - "crossbeam-utils 0.7.2", - "lazy_static", - "maybe-uninit", - "memoffset 0.5.6", - "scopeguard", + "serde", ] [[package]] -name = "crossbeam-epoch" -version = "0.9.18" +name = "cargo-platform" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ - "crossbeam-utils 0.8.21", + "serde", ] [[package]] -name = "crossbeam-queue" -version = "0.2.3" +name = "cargo_metadata" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ - "cfg-if 0.1.10", - "crossbeam-utils 0.7.2", - "maybe-uninit", + "camino", + "cargo-platform", + "semver 1.0.26", + "serde", + "serde_json", + "thiserror 1.0.69", ] [[package]] -name = "crossbeam-queue" -version = "0.3.12" +name = "cc" +version = "1.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" dependencies = [ - "crossbeam-utils 0.8.21", + "jobserver", + "libc", + "shlex", ] [[package]] -name = "crossbeam-utils" -version = "0.7.2" +name = "cesu8" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "autocfg", - "cfg-if 0.1.10", - "lazy_static", + "nom", ] [[package]] -name = "crossbeam-utils" -version = "0.8.21" +name = "cfg-if" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] -name = "crunchy" -version = "0.2.2" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "crypto-common" -version = "0.1.6" +name = "cfg_aliases" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] -name = "csv" -version = "1.3.1" +name = "chrono" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ - "csv-core", - "itoa", - "ryu", + "android-tzdata", + "iana-time-zone", + "num-traits", "serde", + "windows-link", ] [[package]] -name = "csv-core" -version = "0.1.11" +name = "clang-sys" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ - "memchr 2.7.4", + "glob", + "libc", + "libloading", ] [[package]] -name = "cxx" -version = "1.0.136" +name = "clap" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad7c7515609502d316ab9a24f67dc045132d93bfd3f00713389e90d9898bf30d" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" dependencies = [ - "cc", - "cxxbridge-cmd", - "cxxbridge-flags", - "cxxbridge-macro", - "foldhash", - "link-cplusplus", + "clap_builder", ] [[package]] -name = "cxx-build" -version = "1.0.136" +name = "clap_builder" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bfd16fca6fd420aebbd80d643c201ee4692114a0de208b790b9cd02ceae65fb" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" dependencies = [ - "cc", - "codespan-reporting", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.92", + "anstyle", + "clap_lex", + "strsim", ] [[package]] -name = "cxx-gen" -version = "0.7.136" +name = "clap_lex" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ac2e8f398454ccd7f9183a602cf0f67b5c1d201e2ecb5ef2a95b9b7a8b22bf" -dependencies = [ - "codespan-reporting", - "proc-macro2", - "quote", - "syn 2.0.92", -] +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] -name = "cxxbridge-cmd" -version = "1.0.136" +name = "cloudabi" +version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c33fd49f5d956a1b7ee5f7a9768d58580c6752838d92e39d0d56439efdedc35" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "clap", - "codespan-reporting", - "proc-macro2", - "quote", - "syn 2.0.92", + "bitflags 1.3.2", ] [[package]] -name = "cxxbridge-flags" -version = "1.0.136" +name = "codespan-reporting" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0f1077278fac36299cce8446effd19fe93a95eedb10d39265f3bf67b3036c9" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width 0.1.14", +] [[package]] -name = "cxxbridge-macro" -version = "1.0.136" +name = "codespan-reporting" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da7e4d6e74af6b79031d264b2f13c3ea70af1978083741c41ffce9308f1f24f" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.92", + "serde", + "termcolor", + "unicode-width 0.2.0", ] [[package]] -name = "debugid" -version = "0.8.0" +name = "combine" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ - "uuid", + "bytes 1.10.1", + "memchr", ] [[package]] -name = "deranged" -version = "0.3.11" +name = "concurrent-queue" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ - "powerfmt", + "crossbeam-utils 0.8.21", + "portable-atomic", ] [[package]] -name = "derive-new" -version = "0.5.9" +name = "console_error_panic_hook" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "cfg-if 1.0.0", + "wasm-bindgen", ] [[package]] -name = "derive_more" -version = "1.0.0" +name = "const-fnv1a-hash" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" -dependencies = [ - "derive_more-impl", -] +checksum = "32b13ea120a812beba79e34316b3942a857c86ec1593cb34f27bb28272ce2cca" [[package]] -name = "derive_more-impl" -version = "1.0.0" +name = "const_panic" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "syn 2.0.92", - "unicode-xid", -] +checksum = "2459fc9262a1aa204eb4b5764ad4f189caec88aea9634389c0a25f8be7f6265e" [[package]] -name = "digest" -version = "0.10.7" +name = "const_soft_float" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] +checksum = "87ca1caa64ef4ed453e68bb3db612e51cf1b2f5b871337f0fcab1c8f87cc3dff" [[package]] -name = "directories-next" -version = "2.0.0" +name = "constant_time_eq" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "constgebra" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1aaf9b65849a68662ac6c0810c8893a765c960b907dd7cfab9c4a50bf764fbc" dependencies = [ - "cfg-if 1.0.0", - "dirs-sys-next", + "const_soft_float", ] [[package]] -name = "dirs" -version = "5.0.1" +name = "convert_case" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" dependencies = [ - "dirs-sys", + "unicode-segmentation", ] [[package]] -name = "dirs-sys" -version = "0.4.1" +name = "core-foundation" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ + "core-foundation-sys", "libc", - "option-ext", - "redox_users", - "windows-sys 0.48.0", ] [[package]] -name = "dirs-sys-next" -version = "0.1.2" +name = "core-foundation" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ + "core-foundation-sys", "libc", - "redox_users", - "winapi 0.3.9", ] [[package]] -name = "displaydoc" -version = "0.2.5" +name = "core-foundation-sys" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.92", -] +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "dynamic-menu" -version = "0.1.0" +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ - "td-rs-dat", - "td-rs-derive", + "bitflags 1.3.2", + "core-foundation 0.9.4", + "core-graphics-types", + "foreign-types", + "libc", ] [[package]] -name = "either" -version = "1.13.0" +name = "core-graphics-types" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "libc", +] [[package]] -name = "encoding_rs" -version = "0.8.35" +name = "coreaudio-rs" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" dependencies = [ - "cfg-if 1.0.0", + "bitflags 1.3.2", + "core-foundation-sys", + "coreaudio-sys", ] [[package]] -name = "env_logger" -version = "0.9.3" +name = "coreaudio-sys" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +checksum = "2ce857aa0b77d77287acc1ac3e37a05a8c95a2af3647d23b15f263bdaeb7562b" dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", + "bindgen", ] [[package]] -name = "env_logger" -version = "0.10.2" +name = "cosmic-text" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +checksum = "e418dd4f5128c3e93eab12246391c54a20c496811131f85754dc8152ee207892" dependencies = [ - "humantime", - "is-terminal", + "bitflags 2.9.1", + "fontdb", "log", - "regex", - "termcolor", + "rangemap", + "rustc-hash", + "rustybuzz", + "self_cell", + "smol_str", + "swash", + "sys-locale", + "ttf-parser 0.21.1", + "unicode-bidi", + "unicode-linebreak", + "unicode-script", + "unicode-segmentation", ] [[package]] -name = "equivalent" -version = "1.0.1" +name = "cpal" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" +dependencies = [ + "alsa", + "core-foundation-sys", + "coreaudio-rs", + "dasp_sample", + "jni", + "js-sys", + "libc", + "mach2", + "ndk 0.8.0", + "ndk-context", + "oboe", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows 0.54.0", +] [[package]] -name = "errno" -version = "0.3.10" +name = "cpp_demangle" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" dependencies = [ - "libc", - "windows-sys 0.59.0", + "cfg-if 1.0.0", ] [[package]] -name = "euro-filter-chop" +name = "cpu-memory-top" version = "0.1.0" dependencies = [ - "td-rs-chop", + "bytemuck", "td-rs-derive", + "td-rs-top", ] [[package]] -name = "exr" -version = "1.73.0" +name = "cpufeatures" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ - "bit_field", - "half", - "lebe", - "miniz_oxide", - "rayon-core", - "smallvec 1.13.2", - "zune-inflate", + "libc", ] [[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "fdeflate" -version = "0.3.7" +name = "cranelift-bforest" +version = "0.97.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +checksum = "7aae6f552c4c0ccfb30b9559b77bc985a387d998e1736cbbe6b14c903f3656cf" dependencies = [ - "simd-adler32", + "cranelift-entity", ] [[package]] -name = "file-per-thread-logger" -version = "0.2.0" +name = "cranelift-codegen" +version = "0.97.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a3cc21c33af89af0930c8cae4ade5e6fdc17b5d2c97b3d2e2edb67a1cf683f3" +checksum = "95551de96900cefae691ce895ff2abc691ae3a0b97911a76b45faf99e432937b" dependencies = [ - "env_logger 0.10.2", + "bumpalo", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli 0.27.3", + "hashbrown 0.13.2", "log", + "regalloc2", + "smallvec 1.15.1", + "target-lexicon", ] [[package]] -name = "filter-chop" -version = "0.1.0" +name = "cranelift-codegen-meta" +version = "0.97.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36a3ad7b2bb03de3383f258b00ca29d80234bebd5130cb6ef3bae37ada5baab0" dependencies = [ - "td-rs-chop", - "td-rs-derive", + "cranelift-codegen-shared", ] [[package]] -name = "filter-dat" -version = "0.1.0" +name = "cranelift-codegen-shared" +version = "0.97.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915918fee4142c85fb04bafe0bcd697e2fd6c15a260301ea6f8d2ea332a30e86" + +[[package]] +name = "cranelift-control" +version = "0.97.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e447d548cd7f4fcb87fbd10edbd66a4f77966d17785ed50a08c8f3835483c8" dependencies = [ - "td-rs-dat", - "td-rs-derive", + "arbitrary", ] [[package]] -name = "flate2" -version = "1.0.35" +name = "cranelift-entity" +version = "0.97.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "9d8ab3352a1e5966968d7ab424bd3de8e6b58314760745c3817c2eec3fa2f918" dependencies = [ - "crc32fast", - "miniz_oxide", + "serde", ] [[package]] -name = "fnv" -version = "1.0.7" +name = "cranelift-frontend" +version = "0.97.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "1bffa38431f7554aa1594f122263b87c9e04abc55c9f42b81d37342ac44f79f0" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec 1.15.1", + "target-lexicon", +] [[package]] -name = "foldhash" -version = "0.1.4" +name = "cranelift-isle" +version = "0.97.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +checksum = "84cef66a71c77938148b72bf006892c89d6be9274a08f7e669ff15a56145d701" [[package]] -name = "form_urlencoded" -version = "1.2.1" +name = "cranelift-native" +version = "0.97.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "f33c7e5eb446e162d2d10b17fe68e1f091020cc2e4e38b5501c21099600b0a1b" dependencies = [ - "percent-encoding", + "cranelift-codegen", + "libc", + "target-lexicon", ] [[package]] -name = "fs_extra" -version = "1.3.0" +name = "cranelift-wasm" +version = "0.97.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +checksum = "632f7b64fa6a8c5b980eb6a17ef22089e15cb9f779f1ed3bd3072beab0686c09" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "itertools 0.10.5", + "log", + "smallvec 1.15.1", + "wasmparser 0.107.0", + "wasmtime-types", +] [[package]] -name = "fuchsia-zircon" -version = "0.3.3" +name = "crc32fast" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ - "bitflags 1.3.2", - "fuchsia-zircon-sys", + "cfg-if 1.0.0", ] [[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" +name = "critical-section" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] -name = "futures" -version = "0.1.31" +name = "crossbeam" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" - +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque 0.8.6", + "crossbeam-epoch 0.9.18", + "crossbeam-queue 0.3.12", + "crossbeam-utils 0.8.21", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils 0.8.21", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" +dependencies = [ + "crossbeam-epoch 0.8.2", + "crossbeam-utils 0.7.2", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch 0.9.18", + "crossbeam-utils 0.8.21", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +dependencies = [ + "autocfg", + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", + "lazy_static", + "maybe-uninit", + "memoffset 0.5.6", + "scopeguard", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils 0.8.21", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +dependencies = [ + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils 0.8.21", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if 0.1.10", + "lazy_static", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctrlc" +version = "3.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" +dependencies = [ + "nix 0.30.1", + "windows-sys 0.59.0", +] + +[[package]] +name = "cuda" +version = "0.1.0" +dependencies = [ + "anyhow", + "cudarc", + "td-rs-derive", + "td-rs-top", +] + +[[package]] +name = "cudarc" +version = "0.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9574894139a982bf26fbb44473a9d416c015e779c51ef0fbc0789f1a1c17b25" +dependencies = [ + "libloading", +] + +[[package]] +name = "cursor-icon" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" + +[[package]] +name = "cxx" +version = "1.0.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a71ea7f29c73f7ffa64c50b83c9fe4d3a6d4be89a86b009eb80d5a6d3429d741" +dependencies = [ + "cc", + "cxxbridge-cmd", + "cxxbridge-flags", + "cxxbridge-macro", + "foldhash", + "link-cplusplus", +] + +[[package]] +name = "cxx-gen" +version = "0.7.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68318fef0ae96135291398a97ef84763d1be248bef10a9140e1a728b44e24627" +dependencies = [ + "codespan-reporting 0.12.0", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "cxxbridge-cmd" +version = "1.0.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f44296c8693e9ea226a48f6a122727f77aa9e9e338380cb021accaeeb7ee279" +dependencies = [ + "clap", + "codespan-reporting 0.12.0", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f69c181c176981ae44ba9876e2ea41ce8e574c296b38d06925ce9214fb8e4" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8faff5d4467e0709448187df29ccbf3b0982cc426ee444a193f87b11afb565a8" +dependencies = [ + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.101", +] + +[[package]] +name = "dasp_sample" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" + +[[package]] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "syn 2.0.101", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi 0.3.9", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "disqualified" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9c272297e804878a2a4b707cfcfc6d2328b5bb936944613b4fdf2b9269afdfd" + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", +] + +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + +[[package]] +name = "downcast-rs" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea8a8b81cacc08888170eef4d13b775126db426d0b348bee9d18c2c1eaf123cf" + +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" + +[[package]] +name = "dynamic-menu" +version = "0.1.0" +dependencies = [ + "td-rs-dat", + "td-rs-derive", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "encase" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0a05902cf601ed11d564128448097b98ebe3c6574bd7b6a653a3d56d54aa020" +dependencies = [ + "const_panic", + "encase_derive", + "glam", + "thiserror 1.0.69", +] + +[[package]] +name = "encase_derive" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "181d475b694e2dd56ae919ce7699d344d1fd259292d590c723a50d1189a2ea85" +dependencies = [ + "encase_derive_impl", +] + +[[package]] +name = "encase_derive_impl" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f97b51c5cc57ef7c5f7a0c57c250251c49ee4c28f819f87ac32f4aceabc36792" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" +dependencies = [ + "serde", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "euclid" +version = "0.22.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48" +dependencies = [ + "num-traits", +] + +[[package]] +name = "euro-filter-chop" +version = "0.1.0" +dependencies = [ + "td-rs-chop", + "td-rs-derive", +] + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "file-per-thread-logger" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a3cc21c33af89af0930c8cae4ade5e6fdc17b5d2c97b3d2e2edb67a1cf683f3" +dependencies = [ + "env_logger 0.10.2", + "log", +] + +[[package]] +name = "filter-chop" +version = "0.1.0" +dependencies = [ + "td-rs-chop", + "td-rs-derive", +] + +[[package]] +name = "filter-dat" +version = "0.1.0" +dependencies = [ + "td-rs-dat", + "td-rs-derive", +] + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "font-types" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02a596f5713680923a2080d86de50fe472fb290693cf0f701187a1c8b36996b7" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "fontconfig-parser" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646" +dependencies = [ + "roxmltree", +] + +[[package]] +name = "fontdb" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0299020c3ef3f60f526a4f64ab4a3d4ce116b1acbf24cdd22da0068e5d81dc3" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2", + "slotmap", + "tinyvec", + "ttf-parser 0.20.0", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags 1.3.2", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + +[[package]] +name = "futures" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-lite" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "fxprof-processed-profile" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27d12c0aed7f1e24276a241aadc4cb8ea9f83000f34bc062b7cc2d51e3b0fabd" +dependencies = [ + "bitflags 2.9.1", + "debugid", + "fxhash", + "serde", + "serde_json", +] + +[[package]] +name = "generator-chop" +version = "0.1.0" +dependencies = [ + "td-rs-chop", + "td-rs-derive", + "tracing", +] + +[[package]] +name = "generator-sop" +version = "0.1.0" +dependencies = [ + "td-rs-derive", + "td-rs-sop", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "gethostname" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +dependencies = [ + "libc", + "windows-targets 0.48.5", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + +[[package]] +name = "gilrs" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb2c998745a3c1ac90f64f4f7b3a54219fd3612d7705e7798212935641ed18f" +dependencies = [ + "fnv", + "gilrs-core", + "log", + "uuid", + "vec_map", +] + +[[package]] +name = "gilrs-core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6d95ae10ce5aa99543a28cf74e41c11f3b9e3c14f0452bbde46024753cd683e" +dependencies = [ + "core-foundation 0.10.1", + "inotify", + "io-kit-sys", + "js-sys", + "libc", + "libudev-sys", + "log", + "nix 0.29.0", + "uuid", + "vec_map", + "wasm-bindgen", + "web-sys", + "windows 0.58.0", +] + +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +dependencies = [ + "fallible-iterator", + "indexmap 1.9.3", + "stable_deref_trait", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "glam" +version = "0.29.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8babf46d4c1c9d92deac9f7be466f76dfc4482b6452fc5024b5e8daf6ffeb3ee" +dependencies = [ + "bytemuck", + "libm", + "rand", + "serde", +] + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "glow" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gltf" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ce1918195723ce6ac74e80542c5a96a40c2b26162c1957a5cd70799b8cacf7" +dependencies = [ + "byteorder", + "gltf-json", + "lazy_static", + "serde_json", +] + +[[package]] +name = "gltf-derive" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14070e711538afba5d6c807edb74bcb84e5dbb9211a3bf5dea0dfab5b24f4c51" +dependencies = [ + "inflections", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "gltf-json" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6176f9d60a7eab0a877e8e96548605dedbde9190a7ae1e80bbcc1c9af03ab14" +dependencies = [ + "gltf-derive", + "serde", + "serde_derive", + "serde_json", +] + [[package]] -name = "futures" -version = "0.3.31" +name = "glutin_wgl_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "gpu-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.9.1", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "gpu-allocator" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" +dependencies = [ + "log", + "presser", + "thiserror 1.0.69", + "windows 0.58.0", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" +dependencies = [ + "bitflags 2.9.1", + "gpu-descriptor-types", + "hashbrown 0.15.4", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "grid" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36119f3a540b086b4e436bb2b588cf98a68863470e0e880f4d0842f112a3183a" + +[[package]] +name = "guillotiere" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62d5865c036cb1393e23c50693df631d3f5d7bcca4c04fe4cc0fd592e74a782" +dependencies = [ + "euclid", + "svg_fmt", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes 1.10.1", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.9.0", + "slab", + "tokio 1.45.1", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "cfg-if 1.0.0", + "crunchy", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +dependencies = [ + "equivalent", + "foldhash", + "serde", +] + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "portable-atomic", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" + +[[package]] +name = "hexasphere" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c9e718d32b6e6b2b32354e1b0367025efdd0b11d6a740b905ddf5db1074679" +dependencies = [ + "constgebra", + "glam", + "tinyvec", +] + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "homedir" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22074da8bba2ef26fc1737ae6c777b5baab5524c2dc403b5c6a76166766ccda5" +dependencies = [ + "cfg-if 1.0.0", + "nix 0.26.4", + "serde", + "widestring", + "windows-sys 0.48.0", + "wmi", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes 1.10.1", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes 1.10.1", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes 1.10.1", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio 1.45.1", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.61.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "futures-channel" -version = "0.3.31" +name = "icu_normalizer" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ - "futures-core", - "futures-sink", + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec 1.15.1", + "zerovec", ] [[package]] -name = "futures-core" -version = "0.3.31" +name = "icu_normalizer_data" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] -name = "futures-executor" -version = "0.3.31" +name = "icu_properties" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ - "futures-core", - "futures-task", - "futures-util", + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", ] [[package]] -name = "futures-io" -version = "0.3.31" +name = "icu_properties_data" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] -name = "futures-macro" -version = "0.3.31" +name = "icu_provider" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.92", + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", ] [[package]] -name = "futures-sink" -version = "0.3.31" +name = "id-arena" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" [[package]] -name = "futures-task" -version = "0.3.31" +name = "idna" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec 1.15.1", + "utf8_iter", +] [[package]] -name = "futures-util" -version = "0.3.31" +name = "idna_adapter" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr 2.7.4", - "pin-project-lite", - "pin-utils", - "slab", + "icu_normalizer", + "icu_properties", ] [[package]] -name = "fxhash" -version = "0.2.1" +name = "image" +version = "0.25.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" dependencies = [ - "byteorder", + "bytemuck", + "byteorder-lite", + "num-traits", + "png", ] [[package]] -name = "fxprof-processed-profile" -version = "0.6.0" +name = "immutable-chunkmap" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27d12c0aed7f1e24276a241aadc4cb8ea9f83000f34bc062b7cc2d51e3b0fabd" +checksum = "12f97096f508d54f8f8ab8957862eee2ccd628847b6217af1a335e1c44dee578" dependencies = [ - "bitflags 2.6.0", - "debugid", - "fxhash", - "serde", - "serde_json", + "arrayvec", ] [[package]] -name = "generator-chop" -version = "0.1.0" +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "td-rs-chop", - "td-rs-derive", - "tracing", + "autocfg", + "hashbrown 0.12.3", + "serde", ] [[package]] -name = "generator-sop" -version = "0.1.0" +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ - "td-rs-derive", - "td-rs-sop", + "equivalent", + "hashbrown 0.15.4", + "serde", ] [[package]] -name = "generic-array" -version = "0.14.7" +name = "indoc" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" + +[[package]] +name = "indoc" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" + +[[package]] +name = "inflections" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" + +[[package]] +name = "inotify" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "typenum", - "version_check", + "bitflags 2.9.1", + "inotify-sys", + "libc", ] [[package]] -name = "getrandom" -version = "0.2.15" +name = "inotify-sys" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" dependencies = [ - "cfg-if 1.0.0", - "js-sys", "libc", - "wasi", - "wasm-bindgen", ] [[package]] -name = "gif" -version = "0.13.1" +name = "io-kit-sys" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b" dependencies = [ - "color_quant", - "weezl", + "core-foundation-sys", + "mach2", ] [[package]] -name = "gimli" -version = "0.27.3" +name = "io-lifetimes" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "fallible-iterator", - "indexmap 1.9.3", - "stable_deref_trait", + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", ] [[package]] -name = "gimli" -version = "0.31.1" +name = "iovec" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] [[package]] -name = "glob" -version = "0.3.1" +name = "ipnet" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] -name = "h2" -version = "0.3.26" +name = "is-terminal" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "bytes 1.9.0", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap 2.7.0", - "slab", - "tokio 1.42.0", - "tokio-util", - "tracing", + "hermit-abi 0.5.1", + "libc", + "windows-sys 0.59.0", ] [[package]] -name = "half" -version = "2.4.1" +name = "is_ci" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if 1.0.0", - "crunchy", - "num-traits", - "serde", -] +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" [[package]] -name = "hashbrown" -version = "0.12.3" +name = "itertools" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] [[package]] -name = "hashbrown" -version = "0.13.2" +name = "itertools" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ - "ahash", + "either", ] [[package]] -name = "hashbrown" -version = "0.14.5" +name = "itertools" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ - "ahash", - "allocator-api2", - "serde", + "either", ] [[package]] -name = "hashbrown" -version = "0.15.2" +name = "itertools" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] [[package]] -name = "heck" -version = "0.4.1" +name = "itoa" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] -name = "heck" -version = "0.5.0" +name = "ittapi" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "25a5c0b993601cad796222ea076565c5d9f337d35592f8622c753724f06d7271" +dependencies = [ + "anyhow", + "ittapi-sys", + "log", +] [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "ittapi-sys" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "cb7b5e473765060536a660eed127f758cf1a810c73e49063264959c60d1727d9" dependencies = [ - "libc", + "cc", ] [[package]] -name = "hermit-abi" -version = "0.3.9" +name = "jni" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if 1.0.0", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] [[package]] -name = "hermit-abi" -version = "0.4.0" +name = "jni-sys" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] -name = "hmac" -version = "0.12.1" +name = "jobserver" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ - "digest", + "getrandom 0.3.3", + "libc", ] [[package]] -name = "homedir" -version = "0.2.1" +name = "js-sys" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22074da8bba2ef26fc1737ae6c777b5baab5524c2dc403b5c6a76166766ccda5" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ - "cfg-if 1.0.0", - "nix", - "serde", - "widestring", - "windows-sys 0.48.0", - "wmi", + "once_cell", + "wasm-bindgen", ] [[package]] -name = "http" -version = "0.2.12" +name = "kernel32-sys" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" dependencies = [ - "bytes 1.9.0", - "fnv", - "itoa", + "winapi 0.2.8", + "winapi-build", ] [[package]] -name = "http-body" -version = "0.4.6" +name = "khronos-egl" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ - "bytes 1.9.0", - "http", - "pin-project-lite", + "libc", + "libloading", + "pkg-config", ] [[package]] -name = "httparse" -version = "1.9.5" +name = "khronos_api" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" [[package]] -name = "httpdate" -version = "1.0.3" +name = "ktx2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +checksum = "87d65e08a9ec02e409d27a0139eaa6b9756b4d81fe7cde71f6941a83730ce838" +dependencies = [ + "bitflags 1.3.2", +] [[package]] -name = "humantime" -version = "2.1.0" +name = "lazy_static" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] -name = "hyper" -version = "0.14.32" +name = "leb128fmt" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes 1.9.0", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio 1.42.0", - "tower-service", - "tracing", - "want", -] +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] -name = "iana-time-zone" -version = "0.1.61" +name = "lewton" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030" dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core 0.52.0", + "byteorder", + "ogg", + "tinyvec", ] [[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" +name = "libc" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ - "cc", + "cfg-if 1.0.0", + "windows-targets 0.53.0", ] [[package]] -name = "icu_collections" -version = "1.5.0" +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libredox" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", + "bitflags 2.9.1", + "libc", + "redox_syscall 0.5.12", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "libudev-sys" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", + "libc", + "pkg-config", ] [[package]] -name = "icu_locid_transform" -version = "1.5.0" +name = "link-cplusplus" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212" dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", + "cc", ] [[package]] -name = "icu_locid_transform_data" -version = "1.5.0" +name = "linux-raw-sys" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] -name = "icu_normalizer" -version = "1.5.0" +name = "linux-raw-sys" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec 1.13.2", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] -name = "icu_normalizer_data" -version = "1.5.0" +name = "linux-raw-sys" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] -name = "icu_properties" -version = "1.5.1" +name = "litemap" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] -name = "icu_properties_data" -version = "1.5.0" +name = "litrs" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] -name = "icu_provider" -version = "1.5.0" +name = "lock_api" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", + "scopeguard", ] [[package]] -name = "icu_provider_macros" -version = "1.5.0" +name = "lock_api" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.92", + "autocfg", + "scopeguard", ] [[package]] -name = "id-arena" -version = "2.2.1" +name = "log" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] -name = "idna" -version = "1.0.3" +name = "mach" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" dependencies = [ - "idna_adapter", - "smallvec 1.13.2", - "utf8_iter", + "libc", ] [[package]] -name = "idna_adapter" -version = "1.2.0" +name = "mach2" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" dependencies = [ - "icu_normalizer", - "icu_properties", + "libc", ] [[package]] -name = "image" -version = "0.24.9" +name = "malloc_buf" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "exr", - "gif", - "jpeg-decoder", - "num-traits", - "png", - "qoi", - "tiff", + "libc", ] [[package]] -name = "indexmap" -version = "1.9.3" +name = "matchers" +version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", + "regex-automata 0.1.10", ] [[package]] -name = "indexmap" -version = "2.7.0" +name = "matchers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "equivalent", - "hashbrown 0.15.2", + "regex-automata 0.1.10", ] [[package]] -name = "indoc" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" - -[[package]] -name = "indoc" -version = "2.0.5" +name = "maybe-uninit" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] -name = "inout" -version = "0.1.3" +name = "memchr" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] -name = "io-lifetimes" -version = "1.0.11" +name = "memfd" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", + "rustix 0.38.44", ] [[package]] -name = "iovec" -version = "0.1.4" +name = "memmap2" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", ] [[package]] -name = "ipnet" -version = "2.10.1" +name = "memoffset" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" +dependencies = [ + "autocfg", +] [[package]] -name = "is-terminal" -version = "0.4.13" +name = "memoffset" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" dependencies = [ - "hermit-abi 0.4.0", - "libc", - "windows-sys 0.52.0", + "autocfg", ] [[package]] -name = "is_ci" -version = "1.2.0" +name = "memoffset" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] [[package]] -name = "itertools" -version = "0.9.0" +name = "memoffset" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ - "either", + "autocfg", ] [[package]] -name = "itertools" -version = "0.10.5" +name = "metal" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" dependencies = [ - "either", + "bitflags 2.9.1", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", + "paste", ] [[package]] -name = "itertools" -version = "0.11.0" +name = "miette" +version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" dependencies = [ - "either", + "backtrace", + "backtrace-ext", + "is-terminal", + "miette-derive", + "once_cell", + "owo-colors", + "supports-color", + "supports-hyperlinks", + "supports-unicode", + "terminal_size", + "textwrap", + "thiserror 1.0.69", + "unicode-width 0.1.14", ] [[package]] -name = "itertools" -version = "0.13.0" +name = "miette-derive" +version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ - "either", + "proc-macro2", + "quote", + "syn 2.0.101", ] [[package]] -name = "itoa" -version = "1.0.14" +name = "mime" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] -name = "ittapi" -version = "0.3.5" +name = "minimal-lexical" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a5c0b993601cad796222ea076565c5d9f337d35592f8622c753724f06d7271" -dependencies = [ - "anyhow", - "ittapi-sys", - "log", -] +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "ittapi-sys" -version = "0.3.5" +name = "miniz_oxide" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7b5e473765060536a660eed127f758cf1a810c73e49063264959c60d1727d9" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" dependencies = [ - "cc", + "adler2", + "simd-adler32", ] [[package]] -name = "jobserver" -version = "0.1.32" +name = "mio" +version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" dependencies = [ + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", ] [[package]] -name = "jpeg-decoder" -version = "0.3.1" +name = "mio" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ - "rayon", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] -name = "js-sys" -version = "0.3.76" +name = "mio-uds" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" dependencies = [ - "once_cell", - "wasm-bindgen", + "iovec", + "libc", + "mio 0.6.23", ] [[package]] -name = "kernel32-sys" +name = "miow" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" dependencies = [ + "kernel32-sys", + "net2", "winapi 0.2.8", - "winapi-build", + "ws2_32-sys", ] [[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - -[[package]] -name = "lebe" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" - -[[package]] -name = "libc" -version = "0.2.169" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +name = "monome-grid" +version = "0.1.0" +dependencies = [ + "monome-rs", + "td-rs-chop", + "td-rs-derive", +] [[package]] -name = "libloading" -version = "0.8.6" +name = "monome-rs" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "6bc28e83659730c8b09b24aeb579b20de64fdbdb5836f45b70e506607c230207" dependencies = [ - "cfg-if 1.0.0", - "windows-targets 0.52.6", + "crossbeam", + "futures 0.1.31", + "log", + "rosc", + "tokio 0.1.22", ] [[package]] -name = "libm" -version = "0.2.11" +name = "moveit" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "87d7335204cb6ef7bd647fa6db0be3e4d7aa25b5823a7aa030027ddf512cefba" +dependencies = [ + "cxx", +] [[package]] -name = "libredox" -version = "0.1.3" +name = "naga" +version = "24.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "e380993072e52eef724eddfcde0ed013b0c023c3f0417336ed041aa9f076994e" dependencies = [ - "bitflags 2.6.0", - "libc", + "arrayvec", + "bit-set 0.8.0", + "bitflags 2.9.1", + "cfg_aliases", + "codespan-reporting 0.11.1", + "hexf-parse", + "indexmap 2.9.0", + "log", + "pp-rs", + "rustc-hash", + "spirv", + "strum", + "termcolor", + "thiserror 2.0.12", + "unicode-xid", ] [[package]] -name = "link-cplusplus" -version = "1.0.9" +name = "naga_oil" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" +checksum = "f2464f7395decfd16bb4c33fb0cb3b2c645cc60d051bc7fb652d3720bfb20f18" dependencies = [ - "cc", + "bit-set 0.5.3", + "codespan-reporting 0.11.1", + "data-encoding", + "indexmap 2.9.0", + "naga", + "once_cell", + "regex", + "regex-syntax 0.8.5", + "rustc-hash", + "thiserror 1.0.69", + "tracing", + "unicode-ident", ] [[package]] -name = "linux-raw-sys" -version = "0.3.8" +name = "ndk" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +dependencies = [ + "bitflags 2.9.1", + "jni-sys", + "log", + "ndk-sys 0.5.0+25.2.9519653", + "num_enum", + "thiserror 1.0.69", +] [[package]] -name = "linux-raw-sys" -version = "0.4.14" +name = "ndk" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.9.1", + "jni-sys", + "log", + "ndk-sys 0.6.0+11769913", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] [[package]] -name = "litemap" -version = "0.7.4" +name = "ndk-context" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] -name = "lock_api" -version = "0.3.4" +name = "ndk-sys" +version = "0.5.0+25.2.9519653" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" dependencies = [ - "scopeguard", + "jni-sys", ] [[package]] -name = "lock_api" -version = "0.4.12" +name = "ndk-sys" +version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ - "autocfg", - "scopeguard", + "jni-sys", ] [[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "mach" -version = "0.3.2" +name = "net2" +version = "0.2.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" dependencies = [ + "cfg-if 0.1.10", "libc", + "winapi 0.3.9", ] [[package]] -name = "matchers" -version = "0.0.1" +name = "nix" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ - "regex-automata 0.1.10", + "bitflags 1.3.2", + "cfg-if 1.0.0", + "libc", + "memoffset 0.7.1", + "pin-utils", ] [[package]] -name = "matchers" -version = "0.1.0" +name = "nix" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "regex-automata 0.1.10", + "bitflags 2.9.1", + "cfg-if 1.0.0", + "cfg_aliases", + "libc", ] [[package]] -name = "matrixmultiply" -version = "0.3.9" +name = "nix" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "autocfg", - "num_cpus", - "once_cell", - "rawpointer", - "thread-tree", -] - -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + "bitflags 2.9.1", + "cfg-if 1.0.0", + "cfg_aliases", + "libc", +] [[package]] -name = "memchr" -version = "1.0.2" +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "libc", + "memchr", + "minimal-lexical", ] [[package]] -name = "memchr" -version = "2.7.4" +name = "nonmax" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" [[package]] -name = "memfd" -version = "0.6.4" +name = "ntapi" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" dependencies = [ - "rustix 0.38.42", + "winapi 0.3.9", ] [[package]] -name = "memoffset" -version = "0.5.6" +name = "nu-ansi-term" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ - "autocfg", + "overload", + "winapi 0.3.9", ] [[package]] -name = "memoffset" -version = "0.7.1" +name = "num-derive" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ - "autocfg", + "proc-macro2", + "quote", + "syn 2.0.101", ] [[package]] -name = "memoffset" -version = "0.8.0" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] -name = "memoffset" -version = "0.9.1" +name = "num_cpus" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "autocfg", + "hermit-abi 0.5.1", + "libc", ] [[package]] -name = "miette" -version = "5.10.0" +name = "num_enum" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" dependencies = [ - "backtrace", - "backtrace-ext", - "is-terminal", - "miette-derive", - "once_cell", - "owo-colors", - "supports-color", - "supports-hyperlinks", - "supports-unicode", - "terminal_size", - "textwrap", - "thiserror", - "unicode-width 0.1.14", + "num_enum_derive", ] [[package]] -name = "miette-derive" -version = "5.10.0" +name = "num_enum_derive" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ + "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", ] [[package]] -name = "mime" -version = "0.3.17" +name = "objc" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] [[package]] -name = "minimal-lexical" -version = "0.2.1" +name = "objc-sys" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" [[package]] -name = "miniz_oxide" -version = "0.8.2" +name = "objc2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" dependencies = [ - "adler2", - "simd-adler32", + "objc-sys", + "objc2-encode", ] [[package]] -name = "mio" -version = "0.6.23" +name = "objc2-app-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", + "bitflags 2.9.1", + "block2", "libc", - "log", - "miow", - "net2", - "slab", - "winapi 0.2.8", + "objc2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", ] [[package]] -name = "mio" -version = "1.0.3" +name = "objc2-cloud-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "libc", - "wasi", - "windows-sys 0.52.0", + "bitflags 2.9.1", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", ] [[package]] -name = "mio-uds" -version = "0.6.8" +name = "objc2-contacts" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ - "iovec", - "libc", - "mio 0.6.23", + "block2", + "objc2", + "objc2-foundation", ] [[package]] -name = "miow" +name = "objc2-core-data" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", + "bitflags 2.9.1", + "block2", + "objc2", + "objc2-foundation", ] [[package]] -name = "monome-grid" -version = "0.1.0" +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" dependencies = [ - "monome-rs", - "td-rs-chop", - "td-rs-derive", + "bitflags 2.9.1", ] [[package]] -name = "monome-rs" -version = "1.1.3" +name = "objc2-core-image" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bc28e83659730c8b09b24aeb579b20de64fdbdb5836f45b70e506607c230207" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ - "crossbeam", - "futures 0.1.31", - "log", - "rosc", - "tokio 0.1.22", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", ] [[package]] -name = "moveit" -version = "0.6.0" +name = "objc2-core-location" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87d7335204cb6ef7bd647fa6db0be3e4d7aa25b5823a7aa030027ddf512cefba" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" dependencies = [ - "cxx", + "block2", + "objc2", + "objc2-contacts", + "objc2-foundation", ] [[package]] -name = "ndarray" -version = "0.15.6" +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "matrixmultiply", - "num-complex", - "num-integer", - "num-traits", - "rawpointer", - "rayon", + "bitflags 2.9.1", + "block2", + "dispatch", + "libc", + "objc2", ] [[package]] -name = "net2" -version = "0.2.39" +name = "objc2-link-presentation" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", ] [[package]] -name = "nix" -version = "0.26.4" +name = "objc2-metal" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 1.3.2", - "cfg-if 1.0.0", - "libc", - "memoffset 0.7.1", - "pin-utils", + "bitflags 2.9.1", + "block2", + "objc2", + "objc2-foundation", ] [[package]] -name = "nom" -version = "3.2.1" +name = "objc2-quartz-core" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "memchr 1.0.2", + "bitflags 2.9.1", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", ] [[package]] -name = "nom" -version = "7.1.3" +name = "objc2-symbols" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" dependencies = [ - "memchr 2.7.4", - "minimal-lexical", + "objc2", + "objc2-foundation", ] [[package]] -name = "npy" -version = "0.4.0" +name = "objc2-ui-kit" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428bbb4dd63ca4318d430b61e64e9ba7809d11525605905eaa88c73b01d91ed4" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "byteorder", - "nom 3.2.1", + "bitflags 2.9.1", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", ] [[package]] -name = "nu-ansi-term" -version = "0.46.0" +name = "objc2-uniform-type-identifiers" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ - "overload", - "winapi 0.3.9", + "block2", + "objc2", + "objc2-foundation", ] [[package]] -name = "num-complex" -version = "0.4.6" +name = "objc2-user-notifications" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "num-traits", + "bitflags 2.9.1", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", ] [[package]] -name = "num-conv" -version = "0.1.0" +name = "object" +version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +dependencies = [ + "crc32fast", + "hashbrown 0.13.2", + "indexmap 1.9.3", + "memchr", +] [[package]] -name = "num-integer" -version = "0.1.46" +name = "object" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ - "num-traits", + "memchr", ] [[package]] -name = "num-traits" -version = "0.2.19" +name = "oboe" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" dependencies = [ - "autocfg", - "libm", + "jni", + "ndk 0.8.0", + "ndk-context", + "num-derive", + "num-traits", + "oboe-sys", ] [[package]] -name = "num_cpus" -version = "1.16.0" +name = "oboe-sys" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d" dependencies = [ - "hermit-abi 0.3.9", - "libc", + "cc", ] [[package]] -name = "object" -version = "0.30.4" +name = "offset-allocator" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "e234d535da3521eb95106f40f0b73483d80bfb3aacf27c40d7e2b72f1a3e00a2" dependencies = [ - "crc32fast", - "hashbrown 0.13.2", - "indexmap 1.9.3", - "memchr 2.7.4", + "log", + "nonmax", ] [[package]] -name = "object" -version = "0.36.7" +name = "ogg" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e" dependencies = [ - "memchr 2.7.4", + "byteorder", ] [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] -name = "option-ext" -version = "0.2.0" +name = "orbclient" +version = "0.3.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba0b26cec2e24f08ed8bb31519a9333140a6599b867dac464bb150bdb796fd43" +dependencies = [ + "libredox", +] + +[[package]] +name = "ordered-float" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] [[package]] name = "overload" @@ -2699,14 +4881,19 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "packedvec" -version = "1.2.4" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde3c690ec20e4a2b4fb46f0289a451181eb50011a1e2acc8d85e2fde9062a45" +checksum = "a69e0a534dd2e6aefce319af62a0aa0066a76bdfcec0201dfe02df226bc9ec70" dependencies = [ "num-traits", - "serde", ] +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.9.0" @@ -2714,8 +4901,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" dependencies = [ "lock_api 0.3.4", - "parking_lot_core", - "rustc_version 0.2.3", + "parking_lot_core 0.6.3", + "rustc_version", +] + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api 0.4.13", + "parking_lot_core 0.9.11", ] [[package]] @@ -2727,21 +4924,23 @@ dependencies = [ "cfg-if 0.1.10", "cloudabi", "libc", - "redox_syscall", - "rustc_version 0.2.3", + "redox_syscall 0.1.57", + "rustc_version", "smallvec 0.6.14", "winapi 0.3.9", ] [[package]] -name = "password-hash" -version = "0.4.2" +name = "parking_lot_core" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ - "base64ct", - "rand_core", - "subtle", + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.5.12", + "smallvec 1.15.1", + "windows-targets 0.52.6", ] [[package]] @@ -2751,28 +4950,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] -name = "pbkdf2" -version = "0.11.0" +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "petgraph" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ - "digest", - "hmac", - "password-hash", - "sha2", + "fixedbitset", + "indexmap 2.9.0", + "serde", + "serde_derive", +] + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", ] [[package]] -name = "percent-encoding" -version = "2.3.1" +name = "pin-project-internal" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -2780,11 +4999,22 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "png" @@ -2799,35 +5029,86 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "polling" +version = "3.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b53a684391ad002dd6a596ceb6c74fd004fdce75f4be2e3f615068abbea5fd50" +dependencies = [ + "cfg-if 1.0.0", + "concurrent-queue", + "hermit-abi 0.5.1", + "pin-project-lite", + "rustix 1.0.7", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "portable-atomic" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] -name = "powerfmt" -version = "0.2.0" +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "pp-rs" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +checksum = "bb458bb7f6e250e6eb79d5026badc10a3ebb8f9a15d1fff0f13d17c71f4d6dee" +dependencies = [ + "unicode-xid", +] [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + [[package]] name = "prettyplease" -version = "0.2.25" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" dependencies = [ "proc-macro2", - "syn 2.0.92", + "syn 2.0.101", +] + +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", ] [[package]] @@ -2856,24 +5137,24 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] -name = "protobuf" -version = "2.28.0" +name = "profiling" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" +checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" [[package]] name = "psm" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" +checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f" dependencies = [ "cc", ] @@ -2885,7 +5166,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" dependencies = [ "bitflags 1.3.2", - "memchr 2.7.4", + "memchr", "unicase", ] @@ -2895,7 +5176,7 @@ version = "0.23.0-dev" source = "git+https://github.com/tychedelia/pyo3?branch=td-rs#87522fd4202b66702957f7dd4becf5c17cf2d289" dependencies = [ "cfg-if 1.0.0", - "indoc 2.0.5", + "indoc 2.0.6", "libc", "memoffset 0.9.1", "once_cell", @@ -2932,7 +5213,7 @@ dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.92", + "syn 2.0.101", ] [[package]] @@ -2944,7 +5225,7 @@ dependencies = [ "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.92", + "syn 2.0.101", ] [[package]] @@ -2958,22 +5239,25 @@ dependencies = [ ] [[package]] -name = "qoi" -version = "0.4.1" +name = "quote" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ - "bytemuck", + "proc-macro2", ] [[package]] -name = "quote" -version = "1.0.38" +name = "r-efi" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" -dependencies = [ - "proc-macro2", -] +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "radsort" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "019b4b213425016d7d84a153c4c73afb0946fbb4840e4eece7ba8848b9d6da22" [[package]] name = "rand" @@ -3002,7 +5286,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.16", ] [[package]] @@ -3016,10 +5300,22 @@ dependencies = [ ] [[package]] -name = "rawpointer" -version = "0.2.1" +name = "range-alloc" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde" + +[[package]] +name = "rangemap" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" + +[[package]] +name = "raw-window-handle" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" [[package]] name = "rayon" @@ -3041,41 +5337,75 @@ dependencies = [ "crossbeam-utils 0.8.21", ] +[[package]] +name = "read-fonts" +version = "0.29.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04ca636dac446b5664bd16c069c00a9621806895b8bb02c2dc68542b23b8f25d" +dependencies = [ + "bytemuck", + "font-types", +] + +[[package]] +name = "rectangle-pack" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0d463f2884048e7153449a55166f91028d5b0ea53c79377099ce4e8cf0cf9bb" + [[package]] name = "redox_syscall" version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +dependencies = [ + "bitflags 2.9.1", +] + [[package]] name = "redox_users" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom", + "getrandom 0.2.16", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "ref-cast" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", ] [[package]] @@ -3088,7 +5418,7 @@ dependencies = [ "log", "rustc-hash", "slice-group-by", - "smallvec 1.13.2", + "smallvec 1.15.1", ] [[package]] @@ -3098,7 +5428,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", - "memchr 2.7.4", + "memchr", "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -3119,7 +5449,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", - "memchr 2.7.4", + "memchr", "regex-syntax 0.8.5", ] @@ -3135,6 +5465,12 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + [[package]] name = "reqwest" version = "0.11.27" @@ -3142,7 +5478,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "base64 0.21.7", - "bytes 1.9.0", + "bytes 1.10.1", "encoding_rs", "futures-core", "futures-util", @@ -3162,7 +5498,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "system-configuration", - "tokio 1.42.0", + "tokio 1.45.1", "tower-service", "url", "wasm-bindgen", @@ -3181,40 +5517,25 @@ dependencies = [ ] [[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if 1.0.0", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rmp" -version = "0.8.14" +name = "rodio" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +checksum = "e7ceb6607dd738c99bc8cb28eff249b7cd5c8ec88b9db96c0608c1480d140fb1" dependencies = [ - "byteorder", - "num-traits", - "paste", + "cpal", + "lewton", ] [[package]] -name = "rmp-serde" -version = "1.3.0" +name = "ron" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ - "byteorder", - "rmp", + "base64 0.21.7", + "bitflags 2.9.1", "serde", + "serde_derive", ] [[package]] @@ -3227,24 +5548,10 @@ dependencies = [ ] [[package]] -name = "rust_tokenizers" -version = "8.1.1" +name = "roxmltree" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19599f60a688b5160247ee9c37a6af8b0c742ee8b160c5b44acc0f0eb265a59f" -dependencies = [ - "csv", - "hashbrown 0.14.5", - "itertools 0.11.0", - "lazy_static", - "protobuf", - "rayon", - "regex", - "serde", - "serde_json", - "thiserror", - "unicode-normalization", - "unicode-normalization-alignments", -] +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" [[package]] name = "rustc-demangle" @@ -3267,20 +5574,11 @@ dependencies = [ "semver 0.9.0", ] -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver 1.0.24", -] - [[package]] name = "rustix" -version = "0.37.27" +version = "0.37.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6" dependencies = [ "bitflags 1.3.2", "errno", @@ -3292,79 +5590,75 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.42" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.1", "errno", "libc", - "linux-raw-sys 0.4.14", + "linux-raw-sys 0.4.15", "windows-sys 0.59.0", ] [[package]] -name = "rustls" -version = "0.23.20" +name = "rustix" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "log", - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", + "bitflags 2.9.1", + "errno", + "libc", + "linux-raw-sys 0.9.4", + "windows-sys 0.59.0", ] [[package]] -name = "rustls-pki-types" -version = "1.10.1" +name = "rustversion" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] -name = "rustls-webpki" -version = "0.102.8" +name = "rustybuzz" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +checksum = "cfb9cf8877777222e4a3bc7eb247e398b56baba500c38c1c46842431adc8b55c" dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", + "bitflags 2.9.1", + "bytemuck", + "libm", + "smallvec 1.15.1", + "ttf-parser 0.21.1", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", ] [[package]] -name = "rustversion" -version = "1.0.19" +name = "ruzstd" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "3640bec8aad418d7d03c72ea2de10d5c646a598f9883c7babc160d91e3c1b26c" +dependencies = [ + "twox-hash", +] [[package]] name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "safetensors" -version = "0.3.3" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93279b86b3de76f820a8854dd06cbc33cfa57a417b19c47f6a25280112fb1df" -dependencies = [ - "serde", - "serde_json", -] +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] -name = "sanitize-filename" -version = "0.5.0" +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ed72fbaf78e6f2d41744923916966c4fbe3d7c74e3037a8ee482f1115572603" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ - "lazy_static", - "regex", + "winapi-util", ] [[package]] @@ -3374,10 +5668,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "scratch" -version = "1.0.7" +name = "self_cell" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" +checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" [[package]] name = "semver" @@ -3390,9 +5684,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] @@ -3403,43 +5697,49 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + [[package]] name = "serde" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", ] [[package]] name = "serde_json" -version = "1.0.134" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", - "memchr 2.7.4", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -3456,22 +5756,11 @@ dependencies = [ "serde", ] -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "digest", -] - [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if 1.0.0", "cpufeatures", @@ -3499,6 +5788,16 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "skrifa" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbeb4ca4399663735553a09dd17ce7e49a0a0203f03b706b39628c4d913a8607" +dependencies = [ + "bytemuck", + "read-fonts", +] + [[package]] name = "slab" version = "0.4.9" @@ -3514,6 +5813,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + [[package]] name = "smallvec" version = "0.6.14" @@ -3525,9 +5833,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "smawk" @@ -3535,11 +5843,20 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + [[package]] name = "socket2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -3547,9 +5864,9 @@ dependencies = [ [[package]] name = "sparsevec" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ef4657ebc254f6e84a863cb495c2feb60e5b48eba5141bf2bbbe202adb65b4" +checksum = "68b4a8ce3045f0fe173fb5ae3c6b7dcfbec02bfa650bb8618b2301f52af0134d" dependencies = [ "num-traits", "packedvec", @@ -3562,7 +5879,16 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" dependencies = [ - "lock_api 0.4.12", + "portable-atomic", +] + +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.9.1", ] [[package]] @@ -3571,20 +5897,6 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" -[[package]] -name = "stable-diffusion" -version = "0.1.0" -dependencies = [ - "burn", - "burn-autodiff", - "burn-ndarray", - "burn-tch", - "stablediffusion", - "tch", - "td-rs-derive", - "td-rs-top", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -3592,23 +5904,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] -name = "stablediffusion" -version = "0.2.0" -source = "git+https://github.com/tychedelia/stable-diffusion-burn.git#8d9dc1015ad0467a751d0405f8cb3910060a527b" -dependencies = [ - "burn", - "burn-autodiff", - "burn-ndarray", - "burn-tch", - "cfg-if 0.1.10", - "image", - "npy", - "num-traits", - "regex", - "rust_tokenizers", - "serde", - "tch", -] +name = "stackfuture" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eae92052b72ef70dafa16eddbabffc77e5ca3574be2f7bc1127b36f0a7ad7f2" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" @@ -3618,21 +5923,24 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.25.0" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] [[package]] name = "strum_macros" -version = "0.25.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "rustversion", - "syn 2.0.92", + "syn 2.0.101", ] [[package]] @@ -3644,17 +5952,11 @@ dependencies = [ "reqwest", "td-rs-derive", "td-rs-top", - "tokio 1.42.0", + "tokio 1.45.1", "tracing", "tracing-subscriber 0.3.19", ] -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - [[package]] name = "supports-color" version = "2.1.0" @@ -3678,9 +5980,26 @@ dependencies = [ name = "supports-unicode" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f850c19edd184a205e883199a261ed44471c81e39bd95b1357f5febbef00e77a" +checksum = "f850c19edd184a205e883199a261ed44471c81e39bd95b1357f5febbef00e77a" +dependencies = [ + "is-terminal", +] + +[[package]] +name = "svg_fmt" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb" + +[[package]] +name = "swash" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f745de914febc7c9ab4388dfaf94bbc87e69f57bb41133a9b0c84d4be49856f3" dependencies = [ - "is-terminal", + "skrifa", + "yazi", + "zeno", ] [[package]] @@ -3696,9 +6015,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.92" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -3713,13 +6032,35 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", +] + +[[package]] +name = "sys-locale" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4" +dependencies = [ + "libc", +] + +[[package]] +name = "sysinfo" +version = "0.34.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b93974b3d3aeaa036504b8eefd4c039dced109171c1ae973f1dc63b2c7e4b2" +dependencies = [ + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "windows 0.57.0", ] [[package]] @@ -3729,7 +6070,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -3743,6 +6084,18 @@ dependencies = [ "libc", ] +[[package]] +name = "taffy" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4f4d046dd956a47a7e1a2947083d7ac3e6aa3cfaaead36173ceaa5ab11878c" +dependencies = [ + "arrayvec", + "grid", + "serde", + "slotmap", +] + [[package]] name = "target-lexicon" version = "0.12.16" @@ -3751,36 +6104,13 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "target-triple" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" - -[[package]] -name = "tch" -version = "0.14.0" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed5dddab3812892bf5fb567136e372ea49f31672931e21cec967ca68aec03da" -dependencies = [ - "half", - "lazy_static", - "libc", - "ndarray", - "rand", - "safetensors", - "thiserror", - "torch-sys", - "zip", -] +checksum = "1ac9aa371f599d22256307c24a9d748c041e548cbf599f35d890f9d365361790" [[package]] name = "td-rs" version = "0.1.0" -dependencies = [ - "cxx", - "cxx-build", - "libc", - "monome-rs", -] [[package]] name = "td-rs-autocxx-build" @@ -3794,9 +6124,11 @@ dependencies = [ name = "td-rs-base" version = "0.1.0" dependencies = [ + "anyhow", "auto_ops", "autocxx", "autocxx-build 0.27.0 (git+https://github.com/tychedelia/autocxx.git)", + "cudarc", "cxx", "derive_more", "miette", @@ -3804,7 +6136,7 @@ dependencies = [ "ref-cast", "rgb", "td-rs-autocxx-build", - "tokio 1.42.0", + "tokio 1.45.1", "tracing", "tracing-subscriber 0.3.19", ] @@ -3885,8 +6217,10 @@ dependencies = [ name = "td-rs-top" version = "0.1.0" dependencies = [ + "anyhow", "autocxx", "autocxx-build 0.27.0 (git+https://github.com/tychedelia/autocxx.git)", + "cudarc", "cxx", "miette", "pyo3", @@ -3907,19 +6241,19 @@ dependencies = [ "homedir", "serde", "serde_json", - "toml 0.8.19", + "toml 0.8.23", ] [[package]] name = "tempfile" -version = "3.14.0" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ - "cfg-if 1.0.0", "fastrand", + "getrandom 0.3.3", "once_cell", - "rustix 0.38.42", + "rustix 1.0.7", "windows-sys 0.59.0", ] @@ -3959,7 +6293,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", ] [[package]] @@ -3970,16 +6313,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", ] [[package]] -name = "thread-tree" -version = "0.3.3" +name = "thiserror-impl" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbd370cb847953a25954d9f63e14824a36113f8c72eecf6eccef5dc4b45d630" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ - "crossbeam-channel", + "proc-macro2", + "quote", + "syn 2.0.101", ] [[package]] @@ -3992,41 +6337,11 @@ dependencies = [ "once_cell", ] -[[package]] -name = "tiff" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" -dependencies = [ - "flate2", - "jpeg-decoder", - "weezl", -] - -[[package]] -name = "time" -version = "0.3.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" -dependencies = [ - "deranged", - "num-conv", - "powerfmt", - "serde", - "time-core", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -4034,9 +6349,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" dependencies = [ "tinyvec_macros", ] @@ -4073,14 +6388,14 @@ dependencies = [ [[package]] name = "tokio" -version = "1.42.0" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", - "bytes 1.9.0", + "bytes 1.10.1", "libc", - "mio 1.0.3", + "mio 1.0.4", "pin-project-lite", "socket2", "windows-sys 0.52.0", @@ -4151,7 +6466,7 @@ dependencies = [ "log", "mio 0.6.23", "num_cpus", - "parking_lot", + "parking_lot 0.9.0", "slab", "tokio-executor", "tokio-io", @@ -4246,15 +6561,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.13" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ - "bytes 1.9.0", + "bytes 1.10.1", "futures-core", "futures-sink", "pin-project-lite", - "tokio 1.42.0", + "tokio 1.45.1", ] [[package]] @@ -4268,9 +6583,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -4280,40 +6595,32 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.9.0", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] [[package]] -name = "torch-sys" -version = "0.14.0" +name = "toml_write" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "803446f89fb877a117503dbfb8375b6a29fa8b0e0f44810fac3863c798ecef22" -dependencies = [ - "anyhow", - "cc", - "libc", - "serde", - "serde_json", - "ureq", - "zip", -] +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "tower-service" @@ -4334,20 +6641,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", ] [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -4375,6 +6682,21 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-oslog" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528bdd1f0e27b5dd9a4ededf154e824b0532731e4af73bb531de46276e0aab1e" +dependencies = [ + "bindgen", + "cc", + "cfg-if 1.0.0", + "once_cell", + "parking_lot 0.12.4", + "tracing-core", + "tracing-subscriber 0.3.19", +] + [[package]] name = "tracing-serde" version = "0.1.3" @@ -4399,7 +6721,7 @@ dependencies = [ "serde", "serde_json", "sharded-slab", - "smallvec 1.13.2", + "smallvec 1.15.1", "thread_local", "tracing", "tracing-core", @@ -4418,13 +6740,24 @@ dependencies = [ "once_cell", "regex", "sharded-slab", - "smallvec 1.13.2", + "smallvec 1.15.1", "thread_local", "tracing", "tracing-core", "tracing-log 0.2.0", ] +[[package]] +name = "tracing-wasm" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" +dependencies = [ + "tracing", + "tracing-subscriber 0.3.19", + "wasm-bindgen", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -4433,9 +6766,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.101" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dcd332a5496c026f1e14b7f3d2b7bd98e509660c04239c58b0ba38a12daded4" +checksum = "1c9bf9513a2f4aeef5fdac8677d7d349c79fdbcc03b9c86da6e9d254f1e43be2" dependencies = [ "glob", "serde", @@ -4443,14 +6776,38 @@ dependencies = [ "serde_json", "target-triple", "termcolor", - "toml 0.8.19", + "toml 0.8.23", ] +[[package]] +name = "ttf-parser" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" + +[[package]] +name = "ttf-parser" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" + +[[package]] +name = "twox-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7b17f197b3050ba473acf9181f7b1d3b66d1cf7356c6cc57886662276e65908" + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "unicase" @@ -4458,11 +6815,29 @@ version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-bidi-mirroring" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cb788ffebc92c5948d0e997106233eeb1d8b9512f93f41651f52b6c5f5af86" + +[[package]] +name = "unicode-ccc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656" + [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-linebreak" @@ -4471,22 +6846,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] -name = "unicode-normalization" -version = "0.1.24" +name = "unicode-properties" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] -name = "unicode-normalization-alignments" -version = "0.1.12" +name = "unicode-script" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f613e4fa046e69818dd287fdc4bc78175ff20331479dab6e1b0f98d57062de" -dependencies = [ - "smallvec 1.13.2", -] +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" [[package]] name = "unicode-segmentation" @@ -4514,33 +6883,9 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unindent" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "ureq" -version = "2.12.1" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" -dependencies = [ - "base64 0.22.1", - "flate2", - "log", - "once_cell", - "rustls", - "rustls-pki-types", - "serde", - "serde_json", - "url", - "webpki-roots", -] +checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" [[package]] name = "url" @@ -4553,12 +6898,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -4567,15 +6906,38 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.11.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +dependencies = [ + "getrandom 0.3.3", + "js-sys", + "serde", + "wasm-bindgen", +] [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "variadics_please" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b6d82be61465f97d42bd1d15bf20f3b0a3a0905018f38f9d6f6962055b0b5c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "vec_map" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" @@ -4585,13 +6947,21 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vob" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c058f4c41e71a043c67744cb76dcc1ae63ece328c1732a72489ccccc2dec23e6" +checksum = "ba59a857adc264b7783397cc7b4bb2aa02d7fff59fd89be54ae701af5f64eb5c" dependencies = [ "num-traits", - "rustc_version 0.4.1", - "serde", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", ] [[package]] @@ -4609,36 +6979,46 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if 1.0.0", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.49" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -4649,9 +7029,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4659,22 +7039,25 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "wasm-chop" @@ -4688,12 +7071,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.222.0" +version = "0.233.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3432682105d7e994565ef928ccf5856cf6af4ba3dddebedb737f61caed70f956" +checksum = "9679ae3cf7cfa2ca3a327f7fab97f27f3294d402fd1a76ca8ab514e17973e4d3" dependencies = [ - "leb128", - "wasmparser 0.222.0", + "leb128fmt", + "wasmparser 0.233.0", ] [[package]] @@ -4703,7 +7086,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29e3ac9b780c7dda0cac7a52a5d6d2d6707cc6e3451c9db209b6c758f40d7acb" dependencies = [ "indexmap 1.9.3", - "semver 1.0.24", + "semver 1.0.26", ] [[package]] @@ -4712,20 +7095,20 @@ version = "0.121.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" dependencies = [ - "bitflags 2.6.0", - "indexmap 2.7.0", - "semver 1.0.24", + "bitflags 2.9.1", + "indexmap 2.9.0", + "semver 1.0.26", ] [[package]] name = "wasmparser" -version = "0.222.0" +version = "0.233.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4adf50fde1b1a49c1add6a80d47aea500c88db70551805853aa8b88f3ea27ab5" +checksum = "b51cb03afce7964bbfce46602d6cb358726f36430b6ba084ac6020d8ce5bc102" dependencies = [ - "bitflags 2.6.0", - "indexmap 2.7.0", - "semver 1.0.24", + "bitflags 2.9.1", + "indexmap 2.9.0", + "semver 1.0.26", ] [[package]] @@ -4746,7 +7129,7 @@ checksum = "1bc104ced94ff0a6981bde77a0bc29aab4af279914a4143b8d1af9fd4b2c9d41" dependencies = [ "anyhow", "async-trait", - "bincode 1.3.3", + "bincode", "bumpalo", "cfg-if 1.0.0", "fxprof-processed-profile", @@ -4790,11 +7173,11 @@ checksum = "3f58ddfe801df3886feaf466d883ea37e941bcc6d841b9f644a08c7acabfe7f8" dependencies = [ "anyhow", "base64 0.21.7", - "bincode 1.3.3", + "bincode", "directories-next", "file-per-thread-logger", "log", - "rustix 0.37.27", + "rustix 0.37.28", "serde", "sha2", "toml 0.5.11", @@ -4840,7 +7223,7 @@ dependencies = [ "log", "object 0.30.4", "target-lexicon", - "thiserror", + "thiserror 1.0.69", "wasmparser 0.107.0", "wasmtime-cranelift-shared", "wasmtime-environ", @@ -4876,7 +7259,7 @@ dependencies = [ "object 0.30.4", "serde", "target-lexicon", - "thiserror", + "thiserror 1.0.69", "wasmparser 0.107.0", "wasmtime-types", ] @@ -4889,7 +7272,7 @@ checksum = "7dd40c8d869916ee6b1f3fcf1858c52041445475ca8550aee81c684c0eb530ca" dependencies = [ "cc", "cfg-if 1.0.0", - "rustix 0.37.27", + "rustix 0.37.28", "wasmtime-asm-macros", "windows-sys 0.48.0", ] @@ -4902,7 +7285,7 @@ checksum = "655b23a10eddfe7814feb548a466f3f25aa4bb4f43098a147305c544a2de28e1" dependencies = [ "addr2line 0.19.0", "anyhow", - "bincode 1.3.3", + "bincode", "cfg-if 1.0.0", "cpp_demangle", "gimli 0.27.3", @@ -4910,7 +7293,7 @@ dependencies = [ "log", "object 0.30.4", "rustc-demangle", - "rustix 0.37.27", + "rustix 0.37.28", "serde", "target-lexicon", "wasmtime-environ", @@ -4928,7 +7311,7 @@ checksum = "e46b7e98979a69d3df093076bde8431204e3c96a770e8d216fea365c627d88a4" dependencies = [ "object 0.30.4", "once_cell", - "rustix 0.37.27", + "rustix 0.37.28", ] [[package]] @@ -4959,7 +7342,7 @@ dependencies = [ "memoffset 0.8.0", "paste", "rand", - "rustix 0.37.27", + "rustix 0.37.28", "sptr", "wasmtime-asm-macros", "wasmtime-environ", @@ -4976,7 +7359,7 @@ checksum = "7473a07bebd85671bada453123e3d465c8e0a59668ff79f5004076e6a2235ef5" dependencies = [ "cranelift-entity", "serde", - "thiserror", + "thiserror 1.0.69", "wasmparser 0.107.0", ] @@ -4993,56 +7376,161 @@ dependencies = [ [[package]] name = "wast" -version = "222.0.0" +version = "233.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce7191f4b7da0dd300cc32476abae6457154e4625d9b1bc26890828a9a26f6e" +checksum = "2eaf4099d8d0c922b83bf3c90663f5666f0769db9e525184284ebbbdb1dd2180" dependencies = [ "bumpalo", - "leb128", - "memchr 2.7.4", + "leb128fmt", + "memchr", "unicode-width 0.2.0", "wasm-encoder", ] [[package]] name = "wat" -version = "1.222.0" +version = "1.233.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fde61b4b52f9a84ae31b5e8902a2cd3162ea45d8bf564c729c3288fe52f4334" +checksum = "3d9bc80f5e4b25ea086ef41b91ccd244adde45d931c384d94a8ff64ab8bd7d87" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "webpki-roots" -version = "0.26.7" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ - "rustls-pki-types", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "weezl" -version = "0.1.8" +name = "wgpu" +version = "24.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b0b3436f0729f6cdf2e6e9201f3d39dc95813fad61d826c1ed07918b4539353" +dependencies = [ + "arrayvec", + "bitflags 2.9.1", + "cfg_aliases", + "document-features", + "js-sys", + "log", + "naga", + "parking_lot 0.12.4", + "profiling", + "raw-window-handle", + "smallvec 1.15.1", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "24.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f0aa306497a238d169b9dc70659105b4a096859a34894544ca81719242e1499" +dependencies = [ + "arrayvec", + "bit-vec 0.8.0", + "bitflags 2.9.1", + "cfg_aliases", + "document-features", + "indexmap 2.9.0", + "log", + "naga", + "once_cell", + "parking_lot 0.12.4", + "profiling", + "raw-window-handle", + "rustc-hash", + "smallvec 1.15.1", + "thiserror 2.0.12", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "24.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f112f464674ca69f3533248508ee30cb84c67cf06c25ff6800685f5e0294e259" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set 0.8.0", + "bitflags 2.9.1", + "block", + "bytemuck", + "cfg_aliases", + "core-graphics-types", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-allocator", + "gpu-descriptor", + "js-sys", + "khronos-egl", + "libc", + "libloading", + "log", + "metal", + "naga", + "ndk-sys 0.5.0+25.2.9519653", + "objc", + "once_cell", + "ordered-float", + "parking_lot 0.12.4", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "rustc-hash", + "smallvec 1.15.1", + "thiserror 2.0.12", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "windows 0.58.0", + "windows-core 0.58.0", +] + +[[package]] +name = "wgpu-types" +version = "24.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" +checksum = "50ac044c0e76c03a0378e7786ac505d010a873665e2d51383dcff8dd227dc69c" +dependencies = [ + "bitflags 2.9.1", + "js-sys", + "log", + "serde", + "web-sys", +] [[package]] name = "widestring" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" +checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" [[package]] name = "winapi" @@ -5085,7 +7573,27 @@ dependencies = [ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +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.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +dependencies = [ + "windows-core 0.57.0", + "windows-targets 0.52.6", +] [[package]] name = "windows" @@ -5099,10 +7607,23 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.52.0" +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.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ + "windows-implement 0.57.0", + "windows-interface 0.57.0", + "windows-result 0.1.2", "windows-targets 0.52.6", ] @@ -5112,13 +7633,37 @@ version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-strings", + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement 0.60.0", + "windows-interface 0.59.1", + "windows-link", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-implement" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "windows-implement" version = "0.58.0" @@ -5127,7 +7672,29 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-interface" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", ] [[package]] @@ -5138,7 +7705,33 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -5150,16 +7743,43 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-strings" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -5187,6 +7807,21 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -5211,13 +7846,35 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -5230,6 +7887,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -5242,6 +7911,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -5254,12 +7935,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -5272,6 +7971,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -5284,6 +7995,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -5296,6 +8019,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -5308,13 +8043,63 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winit" +version = "0.30.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4409c10174df8779dc29a4788cac85ed84024ccbc1743b776b21a520ee1aaf4" +dependencies = [ + "android-activity", + "atomic-waker", + "bitflags 2.9.1", + "block2", + "bytemuck", + "calloop", + "cfg_aliases", + "concurrent-queue", + "core-foundation 0.9.4", + "core-graphics", + "cursor-icon", + "dpi", + "js-sys", + "libc", + "ndk 0.9.0", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "orbclient", + "percent-encoding", + "pin-project", + "raw-window-handle", + "redox_syscall 0.4.1", + "rustix 0.38.44", + "smol_str", + "tracing", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "web-time", + "windows-sys 0.52.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + [[package]] name = "winnow" -version = "0.6.20" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ - "memchr 2.7.4", + "memchr", ] [[package]] @@ -5327,6 +8112,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.1", +] + [[package]] name = "wit-parser" version = "0.8.0" @@ -5338,7 +8132,7 @@ dependencies = [ "indexmap 1.9.3", "log", "pulldown-cmark", - "semver 1.0.24", + "semver 1.0.26", "unicode-xid", "url", ] @@ -5353,22 +8147,16 @@ dependencies = [ "futures 0.3.31", "log", "serde", - "thiserror", - "windows", + "thiserror 1.0.69", + "windows 0.58.0", "windows-core 0.58.0", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "ws2_32-sys" @@ -5380,6 +8168,63 @@ dependencies = [ "winapi-build", ] +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading", + "once_cell", + "rustix 0.38.44", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.9.1", + "dlib", + "log", + "once_cell", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + +[[package]] +name = "xml-rs" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda" + [[package]] name = "xtask" version = "0.1.0" @@ -5387,11 +8232,17 @@ dependencies = [ "td-rs-xtask", ] +[[package]] +name = "yazi" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" + [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -5401,69 +8252,79 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", "synstructure", ] +[[package]] +name = "zeno" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" + [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", ] [[package]] name = "zerofrom" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", + "syn 2.0.101", "synstructure", ] [[package]] -name = "zeroize" -version = "1.8.1" +name = "zerotrie" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -5472,33 +8333,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.92", -] - -[[package]] -name = "zip" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" -dependencies = [ - "aes", - "byteorder", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils 0.8.21", - "flate2", - "hmac", - "pbkdf2", - "sha1", - "time", - "zstd", + "syn 2.0.101", ] [[package]] @@ -5522,19 +8363,10 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" +version = "2.0.15+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" dependencies = [ "cc", "pkg-config", ] - -[[package]] -name = "zune-inflate" -version = "0.2.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" -dependencies = [ - "simd-adler32", -] diff --git a/Cargo.toml b/Cargo.toml index 38d9225..c59aa81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,38 +1,35 @@ -[package] -name = "td-rs" -version = "0.1.0" -edition = "2021" - -[dependencies] -libc = "*" -cxx = "1" -monome-rs = "1.1" - -[build-dependencies] -cxx-build = "1" - -[workspace] -members = [ - "plugins/chop/euro-filter", - "plugins/chop/filter", - "plugins/chop/generator", - "plugins/chop/monome-grid", - "plugins/chop/python", - "plugins/chop/wasm", - "plugins/dat/filter", - "plugins/dat/dynamic_menu", - "plugins/sop/generator-sop", - "plugins/top/cpu-memory-top", - "plugins/top/stable-diffusion", - "plugins/top/stylegan-http", - "td-rs-autocxx-build", - "td-rs-base", - "td-rs-chop", - "td-rs-dat", - "td-rs-derive", - "td-rs-derive-py", - "td-rs-sop", - "td-rs-top", - "td-rs-xtask", - "xtask", -] +[package] +name = "td-rs" +version = "0.1.0" +edition = "2021" + +[dependencies] + +[build-dependencies] + +[workspace] +members = [ + "plugins/chop/euro-filter", + "plugins/chop/filter", + "plugins/chop/generator", + "plugins/chop/monome-grid", + "plugins/chop/python", + "plugins/chop/wasm", + "plugins/dat/filter", + "plugins/dat/dynamic_menu", + "plugins/sop/generator-sop", + "plugins/top/bevy-top", + "plugins/top/cpu-memory-top", + "plugins/top/cuda", + "plugins/top/stylegan-http", + "td-rs-autocxx-build", + "td-rs-base", + "td-rs-chop", + "td-rs-dat", + "td-rs-derive", + "td-rs-derive-py", + "td-rs-sop", + "td-rs-top", + "td-rs-xtask", + "xtask", +] diff --git a/CppProperties.json b/CppProperties.json index 6017def..1d74fde 100644 --- a/CppProperties.json +++ b/CppProperties.json @@ -1,21 +1,21 @@ -{ - "configurations": [ - { - "inheritEnvironments": [ - "msvc_x64" - ], - "name": "x64-Release", - "includePath": [ - "${env.INCLUDE}", - "${workspaceRoot}\\**" - ], - "defines": [ - "WIN32", - "NDEBUG", - "UNICODE", - "_UNICODE" - ], - "intelliSenseMode": "windows-msvc-x64" - } - ] +{ + "configurations": [ + { + "inheritEnvironments": [ + "msvc_x64" + ], + "name": "x64-Release", + "includePath": [ + "${env.INCLUDE}", + "${workspaceRoot}\\**" + ], + "defines": [ + "WIN32", + "NDEBUG", + "UNICODE", + "_UNICODE" + ], + "intelliSenseMode": "windows-msvc-x64" + } + ] } \ No newline at end of file diff --git a/Info.plist b/Info.plist index 671a488..ae16160 100644 --- a/Info.plist +++ b/Info.plist @@ -1,26 +1,26 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - NSHumanReadableCopyright - Copyright © 2021 Derivative. All rights reserved. - NSPrincipalClass - - - + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright © 2021 Derivative. All rights reserved. + NSPrincipalClass + + + diff --git a/README.md b/README.md index 2f43294..5e106b0 100644 --- a/README.md +++ b/README.md @@ -1,97 +1,97 @@ -# `td-rs` 🎨👩‍💻 ![example workflow](https://github.com/tychedelia/td-rs/actions/workflows/build.yaml/badge.svg) - -Experiments integrating Rust into TouchDesigner's plugin framework. - -## Version compatibility - -The library is currently intended to be used with TouchDesigner version `2023.12000`. - -## Getting started - -Fork and clone this repository. Plugins are built using the build system described below. New plugins -can be added by creating a new directory in `plugins/` and adding it to root `Cargo.toml` as a workspace -member. - -A plugin's `Cargo.toml` should have the following properties: -- `name` - The name of the plugin. This should be unique across all plugins. -- `lib` - The type of crate. This should be set to `staticlib`. The name of the lib should be the same as the - `package.name` property, but with underscores instead of hyphens. -- `package.metadata.td-rs` - The `type` should be set to the operator type, e.g. `top`, `chop`, `sop`, `dat`. - This is used by the build system to generate the correct C++ code. -- A dependency on the parent chop crate, e.g. `td-rs-chop = { path = "../../../td-rs-chop" }`. - -All plugins must call their plugin constructor macro in their `lib.rs` file. For example, a `chop` plugin -would call `chop_plugin!(PluginName)`. This macro will generate the necessary FFI code to register the plugin -with TouchDesigner. - -See example plugins for reference. A good starting point can be just to copy an existing plugin. - -### Features - -The following features are available for all parent operator dependencies: -- `python` - Enable Python support. This can be used in combination with `td-rs-derive-py` to generate - Python bindings for the plugin. -- `tracing` - Enable tracing support using the [`tracing`](https://crates.io/crates/tracing) crate. This - can be used to log messages to the TouchDesigner console. -- `tokio` - Enable Tokio support. This can be used to spawn asynchronous tasks from the plugin from the shared - Tokio runtime exported as `RUNTIME`. - -## ⚠️ Status ⚠️ - -This project should be considered in **alpha** status. It is not yet ready for production use, however -is mostly stable and usable for experimentation. Please file an issue if you encounter any problems, -as it is our goal to make this project viable for production use. - -In particular, users may experience any of the following: -- Crashes -- Memory leaks -- Missing APIs -- Performance issues -- Incomplete documentation -- Breaking changes -- Violations of Rust's aliasing rules leading to [scary things](https://predr.ag/blog/falsehoods-programmers-believe-about-undefined-behavior/) - -In other words, no warranty is provided, express or implied. - -## Structure - -Using `autocxx` we generate a C++ interface or "bridge" to our Rust library, which is then compiled -into a C++ plugin that can be loaded in TouchDesigner. - -## Build - -`cargo-xtask` is used for the build framework. A [`justfile`](./justfile) is also provided. - -### Dev/Watch Command - -You can use [bacon](https://dystroy.org/bacon) to watch for changes and build + install for you. - -1. `cargo install bacon` -2. `just dev ` or `bacon dev -- ` - -### `cargo-xtask` - -- `cargo xtask build $PLUGIN` - Build the plugin for the current platform. -- `cargo xtask install $PLUGIN` - Install a built plugin to the TouchDesigner plugins directory. -- `cargo xtask list-plugins` - List all available plugins. - -### Windows - -#### Dependencies -- TouchDesigner, installed in the default location (`C:\Program Files\Derivative\TouchDesigner`). -- MSVC toolchain (Desktop C++, including Clang from additional components). Note: it may be necessary to set the - `LIBCLANG_PATH` environment variable to the path of the Clang DLL. This can be found in the Visual Studio - installation directory, e.g. `C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\Llvm\bin`. -- Rust `x86_64-pc-windows-msvc` target. - -### macOS - -Currently only supports aarch64 (Apple Silicon) builds. Submit a PR if you'd like to add support for x86_64. - -#### Dependencies -- TouchDesigner, installed in the default location (`/Applications/TouchDesigner.app`). -- Xcode (installable from App Store). - ---- -TouchDesigner is a registered trademark of Derivative Inc. This project is not affiliated with or endorsed +# `td-rs` 🎨👩‍💻 ![example workflow](https://github.com/tychedelia/td-rs/actions/workflows/build.yaml/badge.svg) + +Experiments integrating Rust into TouchDesigner's plugin framework. + +## Version compatibility + +The library is currently intended to be used with TouchDesigner version `2023.12000`. + +## Getting started + +Fork and clone this repository. Plugins are built using the build system described below. New plugins +can be added by creating a new directory in `plugins/` and adding it to root `Cargo.toml` as a workspace +member. + +A plugin's `Cargo.toml` should have the following properties: +- `name` - The name of the plugin. This should be unique across all plugins. +- `lib` - The type of crate. This should be set to `staticlib`. The name of the lib should be the same as the + `package.name` property, but with underscores instead of hyphens. +- `package.metadata.td-rs` - The `type` should be set to the operator type, e.g. `top`, `chop`, `sop`, `dat`. + This is used by the build system to generate the correct C++ code. +- A dependency on the parent chop crate, e.g. `td-rs-chop = { path = "../../../td-rs-chop" }`. + +All plugins must call their plugin constructor macro in their `lib.rs` file. For example, a `chop` plugin +would call `chop_plugin!(PluginName)`. This macro will generate the necessary FFI code to register the plugin +with TouchDesigner. + +See example plugins for reference. A good starting point can be just to copy an existing plugin. + +### Features + +The following features are available for all parent operator dependencies: +- `python` - Enable Python support. This can be used in combination with `td-rs-derive-py` to generate + Python bindings for the plugin. +- `tracing` - Enable tracing support using the [`tracing`](https://crates.io/crates/tracing) crate. This + can be used to log messages to the TouchDesigner console. +- `tokio` - Enable Tokio support. This can be used to spawn asynchronous tasks from the plugin from the shared + Tokio runtime exported as `RUNTIME`. + +## ⚠️ Status ⚠️ + +This project should be considered in **alpha** status. It is not yet ready for production use, however +is mostly stable and usable for experimentation. Please file an issue if you encounter any problems, +as it is our goal to make this project viable for production use. + +In particular, users may experience any of the following: +- Crashes +- Memory leaks +- Missing APIs +- Performance issues +- Incomplete documentation +- Breaking changes +- Violations of Rust's aliasing rules leading to [scary things](https://predr.ag/blog/falsehoods-programmers-believe-about-undefined-behavior/) + +In other words, no warranty is provided, express or implied. + +## Structure + +Using `autocxx` we generate a C++ interface or "bridge" to our Rust library, which is then compiled +into a C++ plugin that can be loaded in TouchDesigner. + +## Build + +`cargo-xtask` is used for the build framework. A [`justfile`](./justfile) is also provided. + +### Dev/Watch Command + +You can use [bacon](https://dystroy.org/bacon) to watch for changes and build + install for you. + +1. `cargo install bacon` +2. `just dev ` or `bacon dev -- ` + +### `cargo-xtask` + +- `cargo xtask build $PLUGIN` - Build the plugin for the current platform. +- `cargo xtask install $PLUGIN` - Install a built plugin to the TouchDesigner plugins directory. +- `cargo xtask list-plugins` - List all available plugins. + +### Windows + +#### Dependencies +- TouchDesigner, installed in the default location (`C:\Program Files\Derivative\TouchDesigner`). +- MSVC toolchain (Desktop C++, including Clang from additional components). Note: it may be necessary to set the + `LIBCLANG_PATH` environment variable to the path of the Clang DLL. This can be found in the Visual Studio + installation directory, e.g. `C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\Llvm\bin`. +- Rust `x86_64-pc-windows-msvc` target. + +### macOS + +Currently only supports aarch64 (Apple Silicon) builds. Submit a PR if you'd like to add support for x86_64. + +#### Dependencies +- TouchDesigner, installed in the default location (`/Applications/TouchDesigner.app`). +- Xcode (installable from App Store). + +--- +TouchDesigner is a registered trademark of Derivative Inc. This project is not affiliated with or endorsed by Derivative Inc. \ No newline at end of file diff --git a/bacon.toml b/bacon.toml index 1c3d660..89d16ac 100644 --- a/bacon.toml +++ b/bacon.toml @@ -1,16 +1,16 @@ -[jobs.dev] -command = [ - "cargo", "xtask", - "build", -] -need_stdout = true -background = false -on_success = "job:install" - -[jobs.install] -command = [ - "cargo", "xtask", - "install", -] -need_stdout = true +[jobs.dev] +command = [ + "cargo", "xtask", + "build", +] +need_stdout = true +background = false +on_success = "job:install" + +[jobs.install] +command = [ + "cargo", "xtask", + "install", +] +need_stdout = true background = false \ No newline at end of file diff --git a/justfile b/justfile index 22b5d83..a1e285f 100644 --- a/justfile +++ b/justfile @@ -1,11 +1,11 @@ -build PLUGIN: - cargo xtask build {{PLUGIN}} - -install PLUGIN: - cargo xtask install {{PLUGIN}} - -dev PLUGIN: - bacon dev -- {{PLUGIN}} - -list-plugins: +build PLUGIN: + cargo xtask build {{PLUGIN}} + +install PLUGIN: + cargo xtask install {{PLUGIN}} + +dev PLUGIN: + bacon dev -- {{PLUGIN}} + +list-plugins: cargo xtask list-plugins \ No newline at end of file diff --git a/plugins/chop/euro-filter/Cargo.toml b/plugins/chop/euro-filter/Cargo.toml index e3f74d1..2dbcd04 100644 --- a/plugins/chop/euro-filter/Cargo.toml +++ b/plugins/chop/euro-filter/Cargo.toml @@ -1,15 +1,15 @@ -[package] -name = "euro-filter-chop" -version = "0.1.0" -edition = "2021" - -[package.metadata.td-rs] -type = "chop" - -[lib] -name = "euro_filter_chop" -crate-type = ["staticlib"] - -[dependencies] -td-rs-chop = { path = "../../../td-rs-chop" } +[package] +name = "euro-filter-chop" +version = "0.1.0" +edition = "2021" + +[package.metadata.td-rs] +type = "chop" + +[lib] +name = "euro_filter_chop" +crate-type = ["staticlib"] + +[dependencies] +td-rs-chop = { path = "../../../td-rs-chop" } td-rs-derive = { path = "../../../td-rs-derive" } \ No newline at end of file diff --git a/plugins/chop/euro-filter/src/filter.rs b/plugins/chop/euro-filter/src/filter.rs index 4bd55ef..a1140db 100644 --- a/plugins/chop/euro-filter/src/filter.rs +++ b/plugins/chop/euro-filter/src/filter.rs @@ -1,80 +1,80 @@ -use std::f64::consts::PI; - -pub struct LowPassFilter { - first_filtering: bool, - hat_x_prev: f64, - hat_x: f64, -} - -impl LowPassFilter { - pub fn new() -> Self { - Self { - first_filtering: true, - hat_x_prev: 0.0, - hat_x: 0.0, - } - } - - pub fn filter(&mut self, value: f64, alpha: f64) -> f64 { - if self.first_filtering { - self.first_filtering = false; - self.hat_x_prev = value; - } - self.hat_x = alpha * value + (1.0 - alpha) * self.hat_x_prev; - self.hat_x_prev = self.hat_x; - self.hat_x - } - - pub fn hat_x_prev(&self) -> f64 { - self.hat_x_prev - } -} - -pub struct OneEuroImpl { - first_filtering: bool, - rate: f64, - min_cut_off: f64, - beta: f64, - x_filt: LowPassFilter, - d_cut_off: f64, - dx_filt: LowPassFilter, -} - -impl OneEuroImpl { - pub fn new(rate: f64, min_cut_off: f64, beta: f64, d_cut_off: f64) -> Self { - Self { - first_filtering: true, - rate, - min_cut_off, - beta, - x_filt: LowPassFilter::new(), - d_cut_off, - dx_filt: LowPassFilter::new(), - } - } - - pub fn change_input(&mut self, rate: f64, min_cut_off: f64, beta: f64, d_cut_off: f64) { - self.rate = rate; - self.min_cut_off = min_cut_off; - self.beta = beta; - self.d_cut_off = d_cut_off; - } - - pub fn filter(&mut self, x: f64) -> f64 { - let dx = if self.first_filtering { - 0.0 - } else { - (x - self.x_filt.hat_x_prev()) * self.rate - }; - self.first_filtering = false; - let edx = self.dx_filt.filter(dx, Self::alpha(self.d_cut_off)); - let cut_off = self.min_cut_off + self.beta * edx.abs(); - self.x_filt.filter(x, Self::alpha(cut_off)) - } - - fn alpha(cutoff: f64) -> f64 { - let tau = 1.0 / (2.0 * PI * cutoff); - let te = 1.0 / cutoff; - 1.0 / (1.0 + tau / te) - } -} +use std::f64::consts::PI; + +pub struct LowPassFilter { + first_filtering: bool, + hat_x_prev: f64, + hat_x: f64, +} + +impl LowPassFilter { + pub fn new() -> Self { + Self { + first_filtering: true, + hat_x_prev: 0.0, + hat_x: 0.0, + } + } + + pub fn filter(&mut self, value: f64, alpha: f64) -> f64 { + if self.first_filtering { + self.first_filtering = false; + self.hat_x_prev = value; + } + self.hat_x = alpha * value + (1.0 - alpha) * self.hat_x_prev; + self.hat_x_prev = self.hat_x; + self.hat_x + } + + pub fn hat_x_prev(&self) -> f64 { + self.hat_x_prev + } +} + +pub struct OneEuroImpl { + first_filtering: bool, + rate: f64, + min_cut_off: f64, + beta: f64, + x_filt: LowPassFilter, + d_cut_off: f64, + dx_filt: LowPassFilter, +} + +impl OneEuroImpl { + pub fn new(rate: f64, min_cut_off: f64, beta: f64, d_cut_off: f64) -> Self { + Self { + first_filtering: true, + rate, + min_cut_off, + beta, + x_filt: LowPassFilter::new(), + d_cut_off, + dx_filt: LowPassFilter::new(), + } + } + + pub fn change_input(&mut self, rate: f64, min_cut_off: f64, beta: f64, d_cut_off: f64) { + self.rate = rate; + self.min_cut_off = min_cut_off; + self.beta = beta; + self.d_cut_off = d_cut_off; + } + + pub fn filter(&mut self, x: f64) -> f64 { + let dx = if self.first_filtering { + 0.0 + } else { + (x - self.x_filt.hat_x_prev()) * self.rate + }; + self.first_filtering = false; + let edx = self.dx_filt.filter(dx, Self::alpha(self.d_cut_off)); + let cut_off = self.min_cut_off + self.beta * edx.abs(); + self.x_filt.filter(x, Self::alpha(cut_off)) + } + + fn alpha(cutoff: f64) -> f64 { + let tau = 1.0 / (2.0 * PI * cutoff); + let te = 1.0 / cutoff; + 1.0 / (1.0 + tau / te) + } +} diff --git a/plugins/chop/euro-filter/src/lib.rs b/plugins/chop/euro-filter/src/lib.rs index 694c498..bd3d859 100644 --- a/plugins/chop/euro-filter/src/lib.rs +++ b/plugins/chop/euro-filter/src/lib.rs @@ -1,93 +1,93 @@ -use crate::filter::OneEuroImpl; - -use td_rs_chop::*; -use td_rs_derive::Params; - -mod filter; - -#[derive(Params, Default, Clone, Debug)] -struct EuroFilterChopParams { - #[param(label = "Cutoff Frequency (Hz)", page = "EuroFilter")] - min_cutoff: f64, - #[param(label = "Speed Coefficient", page = "EuroFilter")] - beta: f64, - #[param(label = "Slope Cutoff Frequency (Hz)", page = "EuroFilter")] - d_cutoff: f64, -} - -/// Struct representing our CHOP's state -#[derive(Default)] -pub struct EuroFilterChop { - filters: Vec, - params: EuroFilterChopParams, -} - -impl OpNew for EuroFilterChop { - fn new(_info: NodeInfo) -> Self { - Default::default() - } -} - -impl OpInfo for EuroFilterChop { - const OPERATOR_TYPE: &'static str = "Eurofilter"; - const OPERATOR_LABEL: &'static str = "Euro Filter"; - const MIN_INPUTS: usize = 1; - const MAX_INPUTS: usize = 1; -} - -impl Op for EuroFilterChop { - fn params_mut(&mut self) -> Option> { - Some(Box::new(&mut self.params)) - } -} - -impl Chop for EuroFilterChop { - fn channel_name(&self, index: usize, _inputs: &OperatorInputs) -> String { - format!("chan{}", index) - } - - fn execute(&mut self, output: &mut ChopOutput, inputs: &OperatorInputs) { - if let Some(input) = &inputs.input(0) { - for filter in &mut self.filters { - filter.change_input( - input.num_samples() as f64, - self.params.min_cutoff, - self.params.beta, - self.params.d_cutoff, - ); - } - - for _ in self.filters.len()..input.num_channels() { - self.filters.push(OneEuroImpl::new( - input.num_samples() as f64, - self.params.min_cutoff, - self.params.beta, - self.params.d_cutoff, - )); - } - - let mut input_sample_idx = 0; - for i in 0..output.num_channels() { - for j in 0..output.num_samples() { - input_sample_idx = (input_sample_idx + 1) % input.num_samples(); - output[i][j] = self.filters[i].filter(input[i][input_sample_idx] as f64) as f32; - } - } - } - } - - fn general_info(&self, _inputs: &OperatorInputs) -> ChopGeneralInfo { - ChopGeneralInfo { - cook_every_frame: false, - cook_every_frame_if_asked: true, - timeslice: true, - input_match_index: 0, - } - } - - fn output_info(&self, _inputs: &OperatorInputs) -> Option { - None - } -} - -chop_plugin!(EuroFilterChop); +use crate::filter::OneEuroImpl; + +use td_rs_chop::*; +use td_rs_derive::Params; + +mod filter; + +#[derive(Params, Default, Clone, Debug)] +struct EuroFilterChopParams { + #[param(label = "Cutoff Frequency (Hz)", page = "EuroFilter")] + min_cutoff: f64, + #[param(label = "Speed Coefficient", page = "EuroFilter")] + beta: f64, + #[param(label = "Slope Cutoff Frequency (Hz)", page = "EuroFilter")] + d_cutoff: f64, +} + +/// Struct representing our CHOP's state +#[derive(Default)] +pub struct EuroFilterChop { + filters: Vec, + params: EuroFilterChopParams, +} + +impl OpNew for EuroFilterChop { + fn new(_info: NodeInfo) -> Self { + Default::default() + } +} + +impl OpInfo for EuroFilterChop { + const OPERATOR_TYPE: &'static str = "Eurofilter"; + const OPERATOR_LABEL: &'static str = "Euro Filter"; + const MIN_INPUTS: usize = 1; + const MAX_INPUTS: usize = 1; +} + +impl Op for EuroFilterChop { + fn params_mut(&mut self) -> Option> { + Some(Box::new(&mut self.params)) + } +} + +impl Chop for EuroFilterChop { + fn channel_name(&self, index: usize, _inputs: &OperatorInputs) -> String { + format!("chan{}", index) + } + + fn execute(&mut self, output: &mut ChopOutput, inputs: &OperatorInputs) { + if let Some(input) = &inputs.input(0) { + for filter in &mut self.filters { + filter.change_input( + input.num_samples() as f64, + self.params.min_cutoff, + self.params.beta, + self.params.d_cutoff, + ); + } + + for _ in self.filters.len()..input.num_channels() { + self.filters.push(OneEuroImpl::new( + input.num_samples() as f64, + self.params.min_cutoff, + self.params.beta, + self.params.d_cutoff, + )); + } + + let mut input_sample_idx = 0; + for i in 0..output.num_channels() { + for j in 0..output.num_samples() { + input_sample_idx = (input_sample_idx + 1) % input.num_samples(); + output[i][j] = self.filters[i].filter(input[i][input_sample_idx] as f64) as f32; + } + } + } + } + + fn general_info(&self, _inputs: &OperatorInputs) -> ChopGeneralInfo { + ChopGeneralInfo { + cook_every_frame: false, + cook_every_frame_if_asked: true, + timeslice: true, + input_match_index: 0, + } + } + + fn output_info(&self, _inputs: &OperatorInputs) -> Option { + None + } +} + +chop_plugin!(EuroFilterChop); diff --git a/plugins/chop/filter/Cargo.toml b/plugins/chop/filter/Cargo.toml index a0fa41e..e9b7f58 100644 --- a/plugins/chop/filter/Cargo.toml +++ b/plugins/chop/filter/Cargo.toml @@ -1,15 +1,15 @@ -[package] -name = "filter-chop" -version = "0.1.0" -edition = "2021" - -[package.metadata.td-rs] -type = "chop" - -[lib] -name = "filter_chop" -crate-type = ["staticlib"] - -[dependencies] -td-rs-chop = { path = "../../../td-rs-chop" } +[package] +name = "filter-chop" +version = "0.1.0" +edition = "2021" + +[package.metadata.td-rs] +type = "chop" + +[lib] +name = "filter_chop" +crate-type = ["staticlib"] + +[dependencies] +td-rs-chop = { path = "../../../td-rs-chop" } td-rs-derive = { path = "../../../td-rs-derive" } \ No newline at end of file diff --git a/plugins/chop/filter/src/lib.rs b/plugins/chop/filter/src/lib.rs index f7f3198..f2634ea 100644 --- a/plugins/chop/filter/src/lib.rs +++ b/plugins/chop/filter/src/lib.rs @@ -1,76 +1,76 @@ -use td_rs_chop::*; -use td_rs_derive::Params; - -#[derive(Params, Default, Clone)] -struct FilterChopParams { - #[param(label = "Apply Scale", page = "Filter")] - apply_scale: bool, - #[param(label = "Scale", page = "Filter", min = - 10.0, max = 10.0)] - scale: f32, - #[param(label = "Apply Offset", page = "Filter")] - apply_offset: bool, - #[param(label = "Offset", page = "Filter", min = - 10.0, max = 10.0)] - offset: f32, -} - -/// Struct representing our CHOP's state -pub struct FilterChop { - params: FilterChopParams, -} - -impl OpNew for FilterChop { - fn new(_info: NodeInfo) -> Self { - Self { - params: FilterChopParams { - apply_scale: true, - scale: 1.0, - apply_offset: false, - offset: 0.0, - }, - } - } -} - -impl OpInfo for FilterChop { - const OPERATOR_TYPE: &'static str = "Basicfilter"; - const OPERATOR_LABEL: &'static str = "Basic Filter"; - const MIN_INPUTS: usize = 1; - const MAX_INPUTS: usize = 1; -} - -impl Op for FilterChop { - fn params_mut(&mut self) -> Option> { - Some(Box::new(&mut self.params)) - } -} - -impl Chop for FilterChop { - fn execute(&mut self, output: &mut ChopOutput, inputs: &OperatorInputs) { - let params = inputs.params(); - params.enable_param("Scale", true); - params.enable_param("Offset", true); - - if let Some(input) = &inputs.input(0) { - for i in 0..output.num_channels() { - for j in 0..output.num_samples() { - output[i][j] = input[i][j] * self.params.scale + self.params.offset; - } - } - } - } - - fn general_info(&self, _inputs: &OperatorInputs) -> ChopGeneralInfo { - ChopGeneralInfo { - cook_every_frame: false, - cook_every_frame_if_asked: false, - timeslice: false, - input_match_index: 0, - } - } - - fn channel_name(&self, index: usize, _inputs: &OperatorInputs) -> String { - format!("chan{}", index) - } -} - -chop_plugin!(FilterChop); +use td_rs_chop::*; +use td_rs_derive::Params; + +#[derive(Params, Default, Clone)] +struct FilterChopParams { + #[param(label = "Apply Scale", page = "Filter")] + apply_scale: bool, + #[param(label = "Scale", page = "Filter", min = - 10.0, max = 10.0)] + scale: f32, + #[param(label = "Apply Offset", page = "Filter")] + apply_offset: bool, + #[param(label = "Offset", page = "Filter", min = - 10.0, max = 10.0)] + offset: f32, +} + +/// Struct representing our CHOP's state +pub struct FilterChop { + params: FilterChopParams, +} + +impl OpNew for FilterChop { + fn new(_info: NodeInfo) -> Self { + Self { + params: FilterChopParams { + apply_scale: true, + scale: 1.0, + apply_offset: false, + offset: 0.0, + }, + } + } +} + +impl OpInfo for FilterChop { + const OPERATOR_TYPE: &'static str = "Basicfilter"; + const OPERATOR_LABEL: &'static str = "Basic Filter"; + const MIN_INPUTS: usize = 1; + const MAX_INPUTS: usize = 1; +} + +impl Op for FilterChop { + fn params_mut(&mut self) -> Option> { + Some(Box::new(&mut self.params)) + } +} + +impl Chop for FilterChop { + fn execute(&mut self, output: &mut ChopOutput, inputs: &OperatorInputs) { + let params = inputs.params(); + params.enable_param("Scale", true); + params.enable_param("Offset", true); + + if let Some(input) = &inputs.input(0) { + for i in 0..output.num_channels() { + for j in 0..output.num_samples() { + output[i][j] = input[i][j] * self.params.scale + self.params.offset; + } + } + } + } + + fn general_info(&self, _inputs: &OperatorInputs) -> ChopGeneralInfo { + ChopGeneralInfo { + cook_every_frame: false, + cook_every_frame_if_asked: false, + timeslice: false, + input_match_index: 0, + } + } + + fn channel_name(&self, index: usize, _inputs: &OperatorInputs) -> String { + format!("chan{}", index) + } +} + +chop_plugin!(FilterChop); diff --git a/plugins/chop/generator/Cargo.toml b/plugins/chop/generator/Cargo.toml index e696361..d7b8044 100644 --- a/plugins/chop/generator/Cargo.toml +++ b/plugins/chop/generator/Cargo.toml @@ -1,16 +1,16 @@ -[package] -name = "generator-chop" -version = "0.1.0" -edition = "2021" - -[package.metadata.td-rs] -type = "chop" - -[lib] -name = "generator_chop" -crate-type = ["staticlib"] - -[dependencies] -td-rs-chop = { path = "../../../td-rs-chop", features = ["tracing"] } -td-rs-derive = { path = "../../../td-rs-derive" } +[package] +name = "generator-chop" +version = "0.1.0" +edition = "2021" + +[package.metadata.td-rs] +type = "chop" + +[lib] +name = "generator_chop" +crate-type = ["staticlib"] + +[dependencies] +td-rs-chop = { path = "../../../td-rs-chop", features = ["tracing"] } +td-rs-derive = { path = "../../../td-rs-derive" } tracing = "0.1" \ No newline at end of file diff --git a/plugins/chop/generator/src/lib.rs b/plugins/chop/generator/src/lib.rs index 31c8d15..9d8a1c4 100644 --- a/plugins/chop/generator/src/lib.rs +++ b/plugins/chop/generator/src/lib.rs @@ -1,107 +1,107 @@ -use td_rs_chop::param::MenuParam; -use td_rs_chop::*; -use td_rs_derive::{Param, Params}; - -#[derive(Param, Default, Clone, Debug)] -enum Operation { - #[default] - Add, - Multiply, - Power, -} - -#[derive(Params, Default, Clone, Debug)] -struct GeneratorChopParams { - #[param(label = "Length", page = "Generator")] - length: u32, - #[param(label = "Number of Channels", page = "Generator", min = -10.0, max = 10.0)] - num_channels: u32, - #[param(label = "Apply Scale", page = "Generator")] - apply_scale: bool, - #[param(label = "Scale", page = "Generator")] - scale: f32, - #[param(label = "Operation", page = "Generator")] - operation: Operation, -} - -/// Struct representing our CHOP's state -#[derive(Debug)] -pub struct GeneratorChop { - params: GeneratorChopParams, -} - -/// Impl block providing default constructor for plugin -impl OpNew for GeneratorChop { - fn new(_info: NodeInfo) -> Self { - Self { - params: GeneratorChopParams { - length: 0, - num_channels: 0, - apply_scale: false, - scale: 1.0, - operation: Operation::Add, - }, - } - } -} - -impl OpInfo for GeneratorChop { - const OPERATOR_LABEL: &'static str = "Basic Generator"; - const OPERATOR_TYPE: &'static str = "Basicgenerator"; -} - -impl Op for GeneratorChop { - fn params_mut(&mut self) -> Option> { - Some(Box::new(&mut self.params)) - } -} - -impl Chop for GeneratorChop { - #[tracing::instrument] - fn execute(&mut self, output: &mut ChopOutput, inputs: &OperatorInputs) { - let params = inputs.params(); - params.enable_param("Scale", self.params.apply_scale); - - tracing::info!("Executing chop with params: {:?}", self.params); - for i in 0..output.num_channels() { - for j in 0..output.num_samples() { - let cur_value = match self.params.operation { - Operation::Add => (i as f32) + (j as f32), - Operation::Multiply => (i as f32) * (j as f32), - Operation::Power => (i as f32).powf(j as f32), - }; - let scale = if self.params.apply_scale { - self.params.scale - } else { - 1.0 - }; - let cur_value = cur_value * scale; - output[i][j] = cur_value; - } - } - } - - fn general_info(&self, _inputs: &OperatorInputs) -> ChopGeneralInfo { - ChopGeneralInfo { - cook_every_frame: false, - cook_every_frame_if_asked: false, - timeslice: false, - input_match_index: 0, - } - } - - fn channel_name(&self, index: usize, _inputs: &OperatorInputs) -> String { - format!("chan{}", index) - } - - fn output_info(&self, _inputs: &OperatorInputs) -> Option { - Some(ChopOutputInfo { - num_channels: self.params.num_channels, - num_samples: self.params.length, - start_index: 0, - ..Default::default() - }) - } -} - -chop_plugin!(GeneratorChop); +use td_rs_chop::param::MenuParam; +use td_rs_chop::*; +use td_rs_derive::{Param, Params}; + +#[derive(Param, Default, Clone, Debug)] +enum Operation { + #[default] + Add, + Multiply, + Power, +} + +#[derive(Params, Default, Clone, Debug)] +struct GeneratorChopParams { + #[param(label = "Length", page = "Generator")] + length: u32, + #[param(label = "Number of Channels", page = "Generator", min = -10.0, max = 10.0)] + num_channels: u32, + #[param(label = "Apply Scale", page = "Generator")] + apply_scale: bool, + #[param(label = "Scale", page = "Generator")] + scale: f32, + #[param(label = "Operation", page = "Generator")] + operation: Operation, +} + +/// Struct representing our CHOP's state +#[derive(Debug)] +pub struct GeneratorChop { + params: GeneratorChopParams, +} + +/// Impl block providing default constructor for plugin +impl OpNew for GeneratorChop { + fn new(_info: NodeInfo) -> Self { + Self { + params: GeneratorChopParams { + length: 0, + num_channels: 0, + apply_scale: false, + scale: 1.0, + operation: Operation::Add, + }, + } + } +} + +impl OpInfo for GeneratorChop { + const OPERATOR_LABEL: &'static str = "Basic Generator"; + const OPERATOR_TYPE: &'static str = "Basicgenerator"; +} + +impl Op for GeneratorChop { + fn params_mut(&mut self) -> Option> { + Some(Box::new(&mut self.params)) + } +} + +impl Chop for GeneratorChop { + #[tracing::instrument] + fn execute(&mut self, output: &mut ChopOutput, inputs: &OperatorInputs) { + let params = inputs.params(); + params.enable_param("Scale", self.params.apply_scale); + + tracing::info!("Executing chop with params: {:?}", self.params); + for i in 0..output.num_channels() { + for j in 0..output.num_samples() { + let cur_value = match self.params.operation { + Operation::Add => (i as f32) + (j as f32), + Operation::Multiply => (i as f32) * (j as f32), + Operation::Power => (i as f32).powf(j as f32), + }; + let scale = if self.params.apply_scale { + self.params.scale + } else { + 1.0 + }; + let cur_value = cur_value * scale; + output[i][j] = cur_value; + } + } + } + + fn general_info(&self, _inputs: &OperatorInputs) -> ChopGeneralInfo { + ChopGeneralInfo { + cook_every_frame: false, + cook_every_frame_if_asked: false, + timeslice: false, + input_match_index: 0, + } + } + + fn channel_name(&self, index: usize, _inputs: &OperatorInputs) -> String { + format!("chan{}", index) + } + + fn output_info(&self, _inputs: &OperatorInputs) -> Option { + Some(ChopOutputInfo { + num_channels: self.params.num_channels, + num_samples: self.params.length, + start_index: 0, + ..Default::default() + }) + } +} + +chop_plugin!(GeneratorChop); diff --git a/plugins/chop/monome-grid/Cargo.toml b/plugins/chop/monome-grid/Cargo.toml index 2785081..fa1b0ac 100644 --- a/plugins/chop/monome-grid/Cargo.toml +++ b/plugins/chop/monome-grid/Cargo.toml @@ -1,16 +1,16 @@ -[package] -name = "monome-grid" -version = "0.1.0" -edition = "2021" - -[package.metadata.td-rs] -type = "chop" - -[lib] -name = "monome_grid" -crate-type = ["staticlib"] - -[dependencies] -td-rs-chop = { path = "../../../td-rs-chop" } -td-rs-derive = { path = "../../../td-rs-derive" } +[package] +name = "monome-grid" +version = "0.1.0" +edition = "2021" + +[package.metadata.td-rs] +type = "chop" + +[lib] +name = "monome_grid" +crate-type = ["staticlib"] + +[dependencies] +td-rs-chop = { path = "../../../td-rs-chop" } +td-rs-derive = { path = "../../../td-rs-derive" } monome-rs = "1.1.3" \ No newline at end of file diff --git a/plugins/chop/monome-grid/src/lib.rs b/plugins/chop/monome-grid/src/lib.rs index 7430dab..b5da77b 100644 --- a/plugins/chop/monome-grid/src/lib.rs +++ b/plugins/chop/monome-grid/src/lib.rs @@ -1,119 +1,119 @@ -use monome::{KeyDirection, Monome, MonomeDevice, MonomeEvent}; -use td_rs_chop::cxx::OP_Inputs; -use td_rs_chop::*; -use td_rs_derive::{Param, Params}; - -#[derive(Param, Default, Clone, Debug)] -enum Operation { - #[default] - Add, - Multiply, - Power, -} - -#[derive(Params, Default, Clone, Debug, Eq, PartialEq)] -struct MonomeGridParams { - #[param(label = "Prefix", page = "Grid", default = "/touchdesigner")] - prefix: String, - #[param(label = "Hold", page = "Grid")] - hold: bool, -} - -/// Struct representing our CHOP's state -#[derive(Debug)] -pub struct MonomeGrid { - params: MonomeGridParams, - prev_params: MonomeGridParams, - device: Option, - grid: [bool; 128], -} - -/// Impl block providing default constructor for plugin -impl OpNew for MonomeGrid { - fn new(_info: NodeInfo) -> Self { - Self { - params: MonomeGridParams { - prefix: "/touchdesigner".to_string(), - hold: false, - }, - prev_params: Default::default(), - device: None, - grid: [false; 128], - } - } -} - -impl OpInfo for MonomeGrid { - const OPERATOR_LABEL: &'static str = "Monome Grid"; - const OPERATOR_TYPE: &'static str = "Monomegrid"; -} - -impl Op for MonomeGrid { - fn params_mut(&mut self) -> Option> { - Some(Box::new(&mut self.params)) - } -} - -impl Chop for MonomeGrid { - fn execute(&mut self, output: &mut ChopOutput, inputs: &OperatorInputs) { - if self.params != self.prev_params || self.device.is_none() { - self.prev_params = self.params.clone(); - let device = match Monome::new(&self.params.prefix) { - Ok(device) => device, - Err(err) => { - self.set_error(&format!("Error connecting to monome: {}", err)); - return; - } - }; - self.device = Some(device); - } - - if let Some(ref mut device) = &mut self.device { - while let Some(event) = device.poll() { - match event { - MonomeEvent::GridKey { x, y, direction } => { - let index = (y * 16 + x) as usize; - if self.params.hold { - if matches!(direction, KeyDirection::Down) { - self.grid[index] = !self.grid[index]; - } - } else { - self.grid[index] = !self.grid[index]; - } - } - _ => {} - } - } - - device.set_all(&self.grid); - } - - for i in 0..output.num_channels() { - output[i][0] = if self.grid[i] { 1.0 } else { 0.0 }; - } - } - - fn general_info(&self, _inputs: &OperatorInputs) -> ChopGeneralInfo { - ChopGeneralInfo { - cook_every_frame: true, - cook_every_frame_if_asked: true, - timeslice: false, - input_match_index: 0, - } - } - - fn channel_name(&self, index: usize, _inputs: &OperatorInputs) -> String { - format!("grid{}", index) - } - - fn output_info(&self, _inputs: &OperatorInputs) -> Option { - Some(ChopOutputInfo { - num_channels: 128, - num_samples: 1, - start_index: 0, - ..Default::default() - }) - } -} - -chop_plugin!(MonomeGrid); +use monome::{KeyDirection, Monome, MonomeDevice, MonomeEvent}; +use td_rs_chop::cxx::OP_Inputs; +use td_rs_chop::*; +use td_rs_derive::{Param, Params}; + +#[derive(Param, Default, Clone, Debug)] +enum Operation { + #[default] + Add, + Multiply, + Power, +} + +#[derive(Params, Default, Clone, Debug, Eq, PartialEq)] +struct MonomeGridParams { + #[param(label = "Prefix", page = "Grid", default = "/touchdesigner")] + prefix: String, + #[param(label = "Hold", page = "Grid")] + hold: bool, +} + +/// Struct representing our CHOP's state +#[derive(Debug)] +pub struct MonomeGrid { + params: MonomeGridParams, + prev_params: MonomeGridParams, + device: Option, + grid: [bool; 128], +} + +/// Impl block providing default constructor for plugin +impl OpNew for MonomeGrid { + fn new(_info: NodeInfo) -> Self { + Self { + params: MonomeGridParams { + prefix: "/touchdesigner".to_string(), + hold: false, + }, + prev_params: Default::default(), + device: None, + grid: [false; 128], + } + } +} + +impl OpInfo for MonomeGrid { + const OPERATOR_LABEL: &'static str = "Monome Grid"; + const OPERATOR_TYPE: &'static str = "Monomegrid"; +} + +impl Op for MonomeGrid { + fn params_mut(&mut self) -> Option> { + Some(Box::new(&mut self.params)) + } +} + +impl Chop for MonomeGrid { + fn execute(&mut self, output: &mut ChopOutput, inputs: &OperatorInputs) { + if self.params != self.prev_params || self.device.is_none() { + self.prev_params = self.params.clone(); + let device = match Monome::new(&self.params.prefix) { + Ok(device) => device, + Err(err) => { + self.set_error(&format!("Error connecting to monome: {}", err)); + return; + } + }; + self.device = Some(device); + } + + if let Some(ref mut device) = &mut self.device { + while let Some(event) = device.poll() { + match event { + MonomeEvent::GridKey { x, y, direction } => { + let index = (y * 16 + x) as usize; + if self.params.hold { + if matches!(direction, KeyDirection::Down) { + self.grid[index] = !self.grid[index]; + } + } else { + self.grid[index] = !self.grid[index]; + } + } + _ => {} + } + } + + device.set_all(&self.grid); + } + + for i in 0..output.num_channels() { + output[i][0] = if self.grid[i] { 1.0 } else { 0.0 }; + } + } + + fn general_info(&self, _inputs: &OperatorInputs) -> ChopGeneralInfo { + ChopGeneralInfo { + cook_every_frame: true, + cook_every_frame_if_asked: true, + timeslice: false, + input_match_index: 0, + } + } + + fn channel_name(&self, index: usize, _inputs: &OperatorInputs) -> String { + format!("grid{}", index) + } + + fn output_info(&self, _inputs: &OperatorInputs) -> Option { + Some(ChopOutputInfo { + num_channels: 128, + num_samples: 1, + start_index: 0, + ..Default::default() + }) + } +} + +chop_plugin!(MonomeGrid); diff --git a/plugins/chop/python/Cargo.toml b/plugins/chop/python/Cargo.toml index 57f1e2c..7b7f909 100644 --- a/plugins/chop/python/Cargo.toml +++ b/plugins/chop/python/Cargo.toml @@ -1,17 +1,17 @@ -[package] -name = "python-chop" -version = "0.1.0" -edition = "2021" - -[package.metadata.td-rs] -type = "chop" - -[lib] -name = "python_chop" -crate-type = ["staticlib"] - -[dependencies] -pyo3 = { git = "https://github.com/tychedelia/pyo3", branch = "td-rs", features = ["abi3-py311"] } -td-rs-chop = { path = "../../../td-rs-chop", features = ["python"] } -td-rs-derive = { path = "../../../td-rs-derive" } -td-rs-derive-py = { path = "../../../td-rs-derive-py" } +[package] +name = "python-chop" +version = "0.1.0" +edition = "2021" + +[package.metadata.td-rs] +type = "chop" + +[lib] +name = "python_chop" +crate-type = ["staticlib"] + +[dependencies] +pyo3 = { git = "https://github.com/tychedelia/pyo3", branch = "td-rs", features = ["abi3-py311"] } +td-rs-chop = { path = "../../../td-rs-chop", features = ["python"] } +td-rs-derive = { path = "../../../td-rs-derive" } +td-rs-derive-py = { path = "../../../td-rs-derive-py" } diff --git a/plugins/chop/python/src/lib.rs b/plugins/chop/python/src/lib.rs index 37978f9..95b3772 100644 --- a/plugins/chop/python/src/lib.rs +++ b/plugins/chop/python/src/lib.rs @@ -1,221 +1,221 @@ -#![feature(min_specialization)] - -use td_rs_chop::prelude::*; -use td_rs_derive::*; -use td_rs_derive_py::PyOp; - -#[derive(Param, Default, Debug)] -enum PythonChopShape { - #[default] - Sine, - Square, - Ramp, -} - -#[derive(Params, Default, Debug)] -struct PythonChopParams { - #[param(label="Speed", min=-10.0, max=10.0, default=1.0)] - speed: f32, - #[param(label="Scale", min=-10.0, max=10.0, default=1.0)] - scale: f32, - #[param(label = "Shape")] - shape: PythonChopShape, - #[param(label = "Reset")] - reset: Pulse, -} - -#[derive(PyOp)] -#[pyclass(unsendable)] -pub struct PythonChop { - info: NodeInfo, - #[pyo3(get, set)] - speed: f32, - #[pyo3(get)] - execute_count: u32, - offset: f32, - params: PythonChopParams, -} - -#[pymethods] -impl PythonChop { - pub fn reset(&mut self) { - self.offset = 0.0; - } -} - -impl OpNew for PythonChop { - fn new(info: NodeInfo) -> Self { - Self { - info, - speed: 1.0, - execute_count: 0, - offset: 0.0, - params: Default::default(), - } - } -} - -impl OpInfo for PythonChop { - const OPERATOR_TYPE: &'static str = "Customsignalpython"; - const OPERATOR_LABEL: &'static str = "Custom Signal Python"; - const MIN_INPUTS: usize = 0; - const MAX_INPUTS: usize = 1; - const PYTHON_CALLBACKS_DAT: &'static str = " -# This is an example callbacks DAT. -# -# op - The OP that is doing the callback -# curSpeed - The current speed value the node will be using. -# -# Change the 0.0 to make the speed get adjusted by this callback. -def getSpeedAdjust(op, curSpeed): - return curSpeed + 0.0 -"; -} - -impl Op for PythonChop { - fn params_mut(&mut self) -> Option> { - Some(Box::new(&mut self.params)) - } - - fn info_dat(&self) -> Option> { - Some(Box::new(self)) - } - - fn info_chop(&self) -> Option> { - Some(Box::new(self)) - } - - fn pulse_pressed(&mut self, name: &str) { - if name == "Reset" { - self.reset(); - } - } -} - -impl Chop for PythonChop { - fn channel_name(&self, _index: usize, _input: &OperatorInputs) -> String { - "chan1".to_string() - } - - fn execute(&mut self, output: &mut ChopOutput, inputs: &OperatorInputs) { - self.execute_count += 1; - if inputs.num_inputs() > 0 { - inputs.params().enable_param("Speed", false); - inputs.params().enable_param("Reset", false); - inputs.params().enable_param("Shape", false); - if let Some(input) = inputs.input(0) { - let num_samples = output.num_samples(); - let num_channels = output.num_channels(); - for channel in 0..num_channels { - let input_channel = input.channel(channel); - let output_channel = output.channel_mut(channel); - for sample in 0..num_samples { - output_channel[sample] = input_channel[sample] * self.params.scale; - } - } - } - } else { - inputs.params().enable_param("Speed", true); - inputs.params().enable_param("Reset", true); - inputs.params().enable_param("Shape", true); - // Apply Python class modifications - self.params.speed *= self.speed; - - Python::with_gil(|py| { - self.info.context().call_python_callback( - py, - "getSpeedAdjust", - (self.speed,), - None, - |py, res| { - if let Ok(speed) = res.extract::(py) { - self.params.speed *= speed; - } - }, - ) - }) - .unwrap(); - - let phase = 2.0 * std::f32::consts::PI / output.num_channels() as f32; - let num_samples = output.num_samples(); - let num_channels = output.num_channels(); - let step = self.params.speed * 0.01; - for channel in 0..num_channels { - let mut offset = self.offset + phase * channel as f32; - let v = match self.params.shape { - PythonChopShape::Sine => offset.sin(), - PythonChopShape::Square => { - if (offset % 1.0).abs() > 0.5 { - 1.0 - } else { - 0.0 - } - } - PythonChopShape::Ramp => (offset % 1.0).abs(), - }; - let v = v * self.params.scale; - - let output_channel = output.channel_mut(channel); - for sample in 0..num_samples { - output_channel[sample] = v; - offset += step; - } - } - self.offset += step * num_samples as f32; - } - } - - fn general_info(&self, _inputs: &OperatorInputs) -> ChopGeneralInfo { - ChopGeneralInfo { - cook_every_frame: false, - cook_every_frame_if_asked: true, - timeslice: true, - input_match_index: 0, - } - } - - fn output_info(&self, input: &OperatorInputs) -> Option { - if input.num_inputs() > 0 { - None - } else { - Some(ChopOutputInfo { - num_channels: 1, - sample_rate: 120.0, - num_samples: 1, - start_index: 0, - }) - } - } -} - -impl InfoChop for PythonChop { - fn size(&self) -> usize { - 2 - } - - fn channel(&self, index: usize) -> (String, f32) { - match index { - 0 => ("execute_count".to_string(), self.execute_count as f32), - 1 => ("offset".to_string(), self.offset), - _ => panic!("Invalid channel index"), - } - } -} - -impl InfoDat for PythonChop { - fn size(&self) -> (u32, u32) { - (2, 2) - } - - fn entry(&self, index: usize, entry_index: usize) -> String { - match (index, entry_index) { - (0, 0) => "executeCount".to_string(), - (0, 1) => "offset".to_string(), - (1, 0) => self.execute_count.to_string(), - (1, 1) => self.offset.to_string(), - (_, _) => panic!("Invalid entry index"), - } - } -} - -chop_plugin!(PythonChop); +#![feature(min_specialization)] + +use td_rs_chop::prelude::*; +use td_rs_derive::*; +use td_rs_derive_py::PyOp; + +#[derive(Param, Default, Debug)] +enum PythonChopShape { + #[default] + Sine, + Square, + Ramp, +} + +#[derive(Params, Default, Debug)] +struct PythonChopParams { + #[param(label="Speed", min=-10.0, max=10.0, default=1.0)] + speed: f32, + #[param(label="Scale", min=-10.0, max=10.0, default=1.0)] + scale: f32, + #[param(label = "Shape")] + shape: PythonChopShape, + #[param(label = "Reset")] + reset: Pulse, +} + +#[derive(PyOp)] +#[pyclass(unsendable)] +pub struct PythonChop { + info: NodeInfo, + #[pyo3(get, set)] + speed: f32, + #[pyo3(get)] + execute_count: u32, + offset: f32, + params: PythonChopParams, +} + +#[pymethods] +impl PythonChop { + pub fn reset(&mut self) { + self.offset = 0.0; + } +} + +impl OpNew for PythonChop { + fn new(info: NodeInfo) -> Self { + Self { + info, + speed: 1.0, + execute_count: 0, + offset: 0.0, + params: Default::default(), + } + } +} + +impl OpInfo for PythonChop { + const OPERATOR_TYPE: &'static str = "Customsignalpython"; + const OPERATOR_LABEL: &'static str = "Custom Signal Python"; + const MIN_INPUTS: usize = 0; + const MAX_INPUTS: usize = 1; + const PYTHON_CALLBACKS_DAT: &'static str = " +# This is an example callbacks DAT. +# +# op - The OP that is doing the callback +# curSpeed - The current speed value the node will be using. +# +# Change the 0.0 to make the speed get adjusted by this callback. +def getSpeedAdjust(op, curSpeed): + return curSpeed + 0.0 +"; +} + +impl Op for PythonChop { + fn params_mut(&mut self) -> Option> { + Some(Box::new(&mut self.params)) + } + + fn info_dat(&self) -> Option> { + Some(Box::new(self)) + } + + fn info_chop(&self) -> Option> { + Some(Box::new(self)) + } + + fn pulse_pressed(&mut self, name: &str) { + if name == "Reset" { + self.reset(); + } + } +} + +impl Chop for PythonChop { + fn channel_name(&self, _index: usize, _input: &OperatorInputs) -> String { + "chan1".to_string() + } + + fn execute(&mut self, output: &mut ChopOutput, inputs: &OperatorInputs) { + self.execute_count += 1; + if inputs.num_inputs() > 0 { + inputs.params().enable_param("Speed", false); + inputs.params().enable_param("Reset", false); + inputs.params().enable_param("Shape", false); + if let Some(input) = inputs.input(0) { + let num_samples = output.num_samples(); + let num_channels = output.num_channels(); + for channel in 0..num_channels { + let input_channel = input.channel(channel); + let output_channel = output.channel_mut(channel); + for sample in 0..num_samples { + output_channel[sample] = input_channel[sample] * self.params.scale; + } + } + } + } else { + inputs.params().enable_param("Speed", true); + inputs.params().enable_param("Reset", true); + inputs.params().enable_param("Shape", true); + // Apply Python class modifications + self.params.speed *= self.speed; + + Python::with_gil(|py| { + self.info.context().call_python_callback( + py, + "getSpeedAdjust", + (self.speed,), + None, + |py, res| { + if let Ok(speed) = res.extract::(py) { + self.params.speed *= speed; + } + }, + ) + }) + .unwrap(); + + let phase = 2.0 * std::f32::consts::PI / output.num_channels() as f32; + let num_samples = output.num_samples(); + let num_channels = output.num_channels(); + let step = self.params.speed * 0.01; + for channel in 0..num_channels { + let mut offset = self.offset + phase * channel as f32; + let v = match self.params.shape { + PythonChopShape::Sine => offset.sin(), + PythonChopShape::Square => { + if (offset % 1.0).abs() > 0.5 { + 1.0 + } else { + 0.0 + } + } + PythonChopShape::Ramp => (offset % 1.0).abs(), + }; + let v = v * self.params.scale; + + let output_channel = output.channel_mut(channel); + for sample in 0..num_samples { + output_channel[sample] = v; + offset += step; + } + } + self.offset += step * num_samples as f32; + } + } + + fn general_info(&self, _inputs: &OperatorInputs) -> ChopGeneralInfo { + ChopGeneralInfo { + cook_every_frame: false, + cook_every_frame_if_asked: true, + timeslice: true, + input_match_index: 0, + } + } + + fn output_info(&self, input: &OperatorInputs) -> Option { + if input.num_inputs() > 0 { + None + } else { + Some(ChopOutputInfo { + num_channels: 1, + sample_rate: 120.0, + num_samples: 1, + start_index: 0, + }) + } + } +} + +impl InfoChop for PythonChop { + fn size(&self) -> usize { + 2 + } + + fn channel(&self, index: usize) -> (String, f32) { + match index { + 0 => ("execute_count".to_string(), self.execute_count as f32), + 1 => ("offset".to_string(), self.offset), + _ => panic!("Invalid channel index"), + } + } +} + +impl InfoDat for PythonChop { + fn size(&self) -> (u32, u32) { + (2, 2) + } + + fn entry(&self, index: usize, entry_index: usize) -> String { + match (index, entry_index) { + (0, 0) => "executeCount".to_string(), + (0, 1) => "offset".to_string(), + (1, 0) => self.execute_count.to_string(), + (1, 1) => self.offset.to_string(), + (_, _) => panic!("Invalid entry index"), + } + } +} + +chop_plugin!(PythonChop); diff --git a/plugins/chop/wasm/Cargo.toml b/plugins/chop/wasm/Cargo.toml index d53404b..5ddaf69 100644 --- a/plugins/chop/wasm/Cargo.toml +++ b/plugins/chop/wasm/Cargo.toml @@ -1,17 +1,17 @@ -[package] -name = "wasm-chop" -version = "0.1.0" -edition = "2021" - -[package.metadata.td-rs] -type = "chop" - -[lib] -name = "wasm_chop" -crate-type = ["staticlib"] - -[dependencies] -td-rs-chop = { path = "../../../td-rs-chop" } -td-rs-derive = { path = "../../../td-rs-derive" } -wasmtime = "10.0.1" -wasmprinter = "0.2.60" +[package] +name = "wasm-chop" +version = "0.1.0" +edition = "2021" + +[package.metadata.td-rs] +type = "chop" + +[lib] +name = "wasm_chop" +crate-type = ["staticlib"] + +[dependencies] +td-rs-chop = { path = "../../../td-rs-chop" } +td-rs-derive = { path = "../../../td-rs-derive" } +wasmtime = "10.0.1" +wasmprinter = "0.2.60" diff --git a/plugins/chop/wasm/src/lib.rs b/plugins/chop/wasm/src/lib.rs index 942f3f8..125845f 100644 --- a/plugins/chop/wasm/src/lib.rs +++ b/plugins/chop/wasm/src/lib.rs @@ -1,127 +1,127 @@ -#![feature(min_specialization)] -use wasmtime::{Engine, Linker, Module, Store}; - -use td_rs_chop::*; -use td_rs_derive::Params; - -#[derive(Params, Default, Clone)] -struct WasmChopParams { - #[param(label = "Apply Scale", page = "Filter")] - apply_scale: bool, - #[param(label = "Scale", page = "Filter", min = - 10.0, max = 10.0)] - scale: f32, - #[param(label = "Wasm", page = "Wasm")] - wasm: FileParam, -} - -pub struct WasmChop { - params: WasmChopParams, - engine: Engine, - module: Option, -} - -impl OpNew for WasmChop { - fn new(_info: NodeInfo) -> Self { - Self { - params: WasmChopParams { - ..Default::default() - }, - engine: Engine::default(), - module: None, - } - } -} - -impl OpInfo for WasmChop { - const OPERATOR_TYPE: &'static str = "Wasm"; - const OPERATOR_LABEL: &'static str = "Wasm"; - const MIN_INPUTS: usize = 1; - const MAX_INPUTS: usize = 1; -} - -impl Op for WasmChop { - fn params_mut(&mut self) -> Option> { - Some(Box::new(&mut self.params)) - } - - fn info_dat(&self) -> Option> { - Some(Box::new(self)) - } -} - -impl InfoDat for WasmChop { - fn entry(&self, _index: usize, _entry_index: usize) -> String { - let wasm_file = &self.params.wasm; - if wasm_file.exists() && wasm_file.is_file() { - wasmprinter::print_file(wasm_file.as_path()).expect("Failed to print wasm file") - } else { - "".to_string() - } - } - - fn size(&self) -> (u32, u32) { - (1, 1) - } -} - -impl Chop for WasmChop { - fn execute(&mut self, output: &mut ChopOutput, inputs: &OperatorInputs) { - let params = inputs.params(); - params.enable_param("Wasm", false); - params.enable_param("Scale", self.params.apply_scale); - - if let Some(input) = &inputs.input(0) { - params.enable_param("Wasm", true); - - let wasm_file = &self.params.wasm; - if wasm_file.exists() && wasm_file.is_file() { - let module = Module::from_file(&self.engine.clone(), wasm_file.as_path()) - .expect("Failed to load wasm file"); - self.module = Some(module); - } - - if let Some(module) = &self.module { - let mut linker = Linker::new(&self.engine.clone()); - - let scale = self.params.scale; - linker.func_wrap("env", "scale", move || scale).unwrap(); - - let mut store = Store::new(&self.engine.clone(), ()); - let instance = match linker.instantiate(&mut store, module) { - Ok(instance) => instance, - Err(e) => { - self.set_error(&format!("Failed to instantiate module: {}", e)); - return; - } - }; - let execute = instance - .get_typed_func::<(u32, u32, f32), f32>(&mut store, "execute") - .expect("Failed to get execute function"); - - for i in 0..output.num_channels() { - for j in 0..output.num_samples() { - let res = execute - .call(&mut store, (i as u32, j as u32, input[i][j])) - .expect("Failed to call execute function"); - output[i][j] = res; - } - } - } - } - } - - fn general_info(&self, _inputs: &OperatorInputs) -> ChopGeneralInfo { - ChopGeneralInfo { - cook_every_frame: false, - cook_every_frame_if_asked: false, - timeslice: false, - input_match_index: 0, - } - } - - fn channel_name(&self, index: usize, _inputs: &OperatorInputs) -> String { - format!("chan{}", index) - } -} - -chop_plugin!(WasmChop); +#![feature(min_specialization)] +use wasmtime::{Engine, Linker, Module, Store}; + +use td_rs_chop::*; +use td_rs_derive::Params; + +#[derive(Params, Default, Clone)] +struct WasmChopParams { + #[param(label = "Apply Scale", page = "Filter")] + apply_scale: bool, + #[param(label = "Scale", page = "Filter", min = - 10.0, max = 10.0)] + scale: f32, + #[param(label = "Wasm", page = "Wasm")] + wasm: FileParam, +} + +pub struct WasmChop { + params: WasmChopParams, + engine: Engine, + module: Option, +} + +impl OpNew for WasmChop { + fn new(_info: NodeInfo) -> Self { + Self { + params: WasmChopParams { + ..Default::default() + }, + engine: Engine::default(), + module: None, + } + } +} + +impl OpInfo for WasmChop { + const OPERATOR_TYPE: &'static str = "Wasm"; + const OPERATOR_LABEL: &'static str = "Wasm"; + const MIN_INPUTS: usize = 1; + const MAX_INPUTS: usize = 1; +} + +impl Op for WasmChop { + fn params_mut(&mut self) -> Option> { + Some(Box::new(&mut self.params)) + } + + fn info_dat(&self) -> Option> { + Some(Box::new(self)) + } +} + +impl InfoDat for WasmChop { + fn entry(&self, _index: usize, _entry_index: usize) -> String { + let wasm_file = &self.params.wasm; + if wasm_file.exists() && wasm_file.is_file() { + wasmprinter::print_file(wasm_file.as_path()).expect("Failed to print wasm file") + } else { + "".to_string() + } + } + + fn size(&self) -> (u32, u32) { + (1, 1) + } +} + +impl Chop for WasmChop { + fn execute(&mut self, output: &mut ChopOutput, inputs: &OperatorInputs) { + let params = inputs.params(); + params.enable_param("Wasm", false); + params.enable_param("Scale", self.params.apply_scale); + + if let Some(input) = &inputs.input(0) { + params.enable_param("Wasm", true); + + let wasm_file = &self.params.wasm; + if wasm_file.exists() && wasm_file.is_file() { + let module = Module::from_file(&self.engine.clone(), wasm_file.as_path()) + .expect("Failed to load wasm file"); + self.module = Some(module); + } + + if let Some(module) = &self.module { + let mut linker = Linker::new(&self.engine.clone()); + + let scale = self.params.scale; + linker.func_wrap("env", "scale", move || scale).unwrap(); + + let mut store = Store::new(&self.engine.clone(), ()); + let instance = match linker.instantiate(&mut store, module) { + Ok(instance) => instance, + Err(e) => { + self.set_error(&format!("Failed to instantiate module: {}", e)); + return; + } + }; + let execute = instance + .get_typed_func::<(u32, u32, f32), f32>(&mut store, "execute") + .expect("Failed to get execute function"); + + for i in 0..output.num_channels() { + for j in 0..output.num_samples() { + let res = execute + .call(&mut store, (i as u32, j as u32, input[i][j])) + .expect("Failed to call execute function"); + output[i][j] = res; + } + } + } + } + } + + fn general_info(&self, _inputs: &OperatorInputs) -> ChopGeneralInfo { + ChopGeneralInfo { + cook_every_frame: false, + cook_every_frame_if_asked: false, + timeslice: false, + input_match_index: 0, + } + } + + fn channel_name(&self, index: usize, _inputs: &OperatorInputs) -> String { + format!("chan{}", index) + } +} + +chop_plugin!(WasmChop); diff --git a/plugins/dat/dynamic_menu/Cargo.toml b/plugins/dat/dynamic_menu/Cargo.toml index 65ff2da..4131b44 100644 --- a/plugins/dat/dynamic_menu/Cargo.toml +++ b/plugins/dat/dynamic_menu/Cargo.toml @@ -1,15 +1,15 @@ -[package] -name = "dynamic-menu" -version = "0.1.0" -edition = "2021" - -[package.metadata.td-rs] -type = "dat" - -[lib] -name = "dynamic_menu" -crate-type = ["staticlib"] - -[dependencies] -td-rs-dat = { path = "../../../td-rs-dat" } +[package] +name = "dynamic-menu" +version = "0.1.0" +edition = "2021" + +[package.metadata.td-rs] +type = "dat" + +[lib] +name = "dynamic_menu" +crate-type = ["staticlib"] + +[dependencies] +td-rs-dat = { path = "../../../td-rs-dat" } td-rs-derive = { path = "../../../td-rs-derive" } \ No newline at end of file diff --git a/plugins/dat/dynamic_menu/src/lib.rs b/plugins/dat/dynamic_menu/src/lib.rs index 72bd862..8b0c8c6 100644 --- a/plugins/dat/dynamic_menu/src/lib.rs +++ b/plugins/dat/dynamic_menu/src/lib.rs @@ -1,91 +1,91 @@ -use td_rs_dat::chop::ChopInput; -use td_rs_dat::*; -use td_rs_derive::{Param, Params}; - -#[derive(Params, Default, Clone, Debug)] -struct DynamicMenuDatParams { - #[param(label = "Menu")] - menu: DynamicMenuParam, -} - -/// Struct representing our DAT's state -pub struct DynamicMenuDat { - params: DynamicMenuDatParams, -} - -impl OpNew for DynamicMenuDat { - fn new(_info: NodeInfo) -> Self { - Self { - params: Default::default(), - } - } -} - -impl OpInfo for DynamicMenuDat { - const OPERATOR_TYPE: &'static str = "Dynamicmenu"; - const OPERATOR_LABEL: &'static str = "Dynamic Menu"; - const MIN_INPUTS: usize = 1; - // This Dat takes no input - const MAX_INPUTS: usize = 1; -} - -impl Op for DynamicMenuDat { - fn params_mut(&mut self) -> Option> { - Some(Box::new(&mut self.params)) - } -} - -impl Dat for DynamicMenuDat { - fn general_info(&self, _inputs: &OperatorInputs) -> DatGeneralInfo { - DatGeneralInfo { - cook_every_frame: false, - cook_every_frame_if_asked: false, - } - } - - fn execute(&mut self, output: DatOutput, inputs: &OperatorInputs) { - if let Some(input) = inputs.input(0) { - match input.dat_type() { - DatType::Text => { - if let Some(output_text) = &self.params.menu.0 { - output - .text() - .set_text(&format!("Selected: {}", output_text)); - } else { - output.text().set_text(""); - } - } - _ => self.set_warning("Input must be a text DAT"), - } - } - } - - fn build_dynamic_menu( - &mut self, - inputs: &OperatorInputs, - menu_info: &mut DynamicMenuInfo, - ) { - if menu_info.param_name() == "Menu" { - if let Some(input) = inputs.input(0) { - match input.dat_type() { - DatType::Text => { - let text = input.text(); - let labels = text - .split('\n') - .map(|s| s.to_string()) - .collect::>(); - for label in labels { - let name = label.replace(" ", ""); - menu_info.add_menu_entry(&name, &label); - } - } - _ => self.set_warning("Input must be a text DAT"), - } - } - } - } -} - -impl DynamicMenuDat {} - -dat_plugin!(DynamicMenuDat); +use td_rs_dat::chop::ChopInput; +use td_rs_dat::*; +use td_rs_derive::{Param, Params}; + +#[derive(Params, Default, Clone, Debug)] +struct DynamicMenuDatParams { + #[param(label = "Menu")] + menu: DynamicMenuParam, +} + +/// Struct representing our DAT's state +pub struct DynamicMenuDat { + params: DynamicMenuDatParams, +} + +impl OpNew for DynamicMenuDat { + fn new(_info: NodeInfo) -> Self { + Self { + params: Default::default(), + } + } +} + +impl OpInfo for DynamicMenuDat { + const OPERATOR_TYPE: &'static str = "Dynamicmenu"; + const OPERATOR_LABEL: &'static str = "Dynamic Menu"; + const MIN_INPUTS: usize = 1; + // This Dat takes no input + const MAX_INPUTS: usize = 1; +} + +impl Op for DynamicMenuDat { + fn params_mut(&mut self) -> Option> { + Some(Box::new(&mut self.params)) + } +} + +impl Dat for DynamicMenuDat { + fn general_info(&self, _inputs: &OperatorInputs) -> DatGeneralInfo { + DatGeneralInfo { + cook_every_frame: false, + cook_every_frame_if_asked: false, + } + } + + fn execute(&mut self, output: DatOutput, inputs: &OperatorInputs) { + if let Some(input) = inputs.input(0) { + match input.dat_type() { + DatType::Text => { + if let Some(output_text) = &self.params.menu.0 { + output + .text() + .set_text(&format!("Selected: {}", output_text)); + } else { + output.text().set_text(""); + } + } + _ => self.set_warning("Input must be a text DAT"), + } + } + } + + fn build_dynamic_menu( + &mut self, + inputs: &OperatorInputs, + menu_info: &mut DynamicMenuInfo, + ) { + if menu_info.param_name() == "Menu" { + if let Some(input) = inputs.input(0) { + match input.dat_type() { + DatType::Text => { + let text = input.text(); + let labels = text + .split('\n') + .map(|s| s.to_string()) + .collect::>(); + for label in labels { + let name = label.replace(" ", ""); + menu_info.add_menu_entry(&name, &label); + } + } + _ => self.set_warning("Input must be a text DAT"), + } + } + } + } +} + +impl DynamicMenuDat {} + +dat_plugin!(DynamicMenuDat); diff --git a/plugins/dat/filter/Cargo.toml b/plugins/dat/filter/Cargo.toml index defbb3d..169ac73 100644 --- a/plugins/dat/filter/Cargo.toml +++ b/plugins/dat/filter/Cargo.toml @@ -1,15 +1,15 @@ -[package] -name = "filter-dat" -version = "0.1.0" -edition = "2021" - -[package.metadata.td-rs] -type = "dat" - -[lib] -name = "filter_dat" -crate-type = ["staticlib"] - -[dependencies] -td-rs-dat = { path = "../../../td-rs-dat" } +[package] +name = "filter-dat" +version = "0.1.0" +edition = "2021" + +[package.metadata.td-rs] +type = "dat" + +[lib] +name = "filter_dat" +crate-type = ["staticlib"] + +[dependencies] +td-rs-dat = { path = "../../../td-rs-dat" } td-rs-derive = { path = "../../../td-rs-derive" } \ No newline at end of file diff --git a/plugins/dat/filter/src/lib.rs b/plugins/dat/filter/src/lib.rs index 00c1e86..a55660c 100644 --- a/plugins/dat/filter/src/lib.rs +++ b/plugins/dat/filter/src/lib.rs @@ -1,156 +1,156 @@ -use td_rs_dat::*; -use td_rs_derive::{Param, Params}; - -#[derive(Param, Default, Clone, Debug)] -enum FilterType { - UpperCamelCase, - #[default] - LowerCase, - UpperCase, -} - -#[derive(Params, Default, Clone, Debug)] -struct FilterDatParams { - #[param(label = "Case", page = "Filter")] - case: FilterType, - #[param(label = "Keep Spaces", page = "Filter")] - keep_spaces: bool, -} - -/// Struct representing our DAT's state -pub struct FilterDat { - params: FilterDatParams, -} - -impl OpNew for FilterDat { - fn new(_info: NodeInfo) -> Self { - Self { - params: Default::default(), - } - } -} - -impl OpInfo for FilterDat { - const OPERATOR_TYPE: &'static str = "Basicfilter"; - const OPERATOR_LABEL: &'static str = "Basic Filter"; - const MIN_INPUTS: usize = 1; - // This Dat takes no input - const MAX_INPUTS: usize = 1; -} - -impl Op for FilterDat { - fn params_mut(&mut self) -> Option> { - Some(Box::new(&mut self.params)) - } -} - -impl Dat for FilterDat { - fn general_info(&self, _inputs: &OperatorInputs) -> DatGeneralInfo { - DatGeneralInfo { - cook_every_frame: false, - cook_every_frame_if_asked: false, - } - } - - fn execute(&mut self, output: DatOutput, inputs: &OperatorInputs) { - if let Some(input) = inputs.input(0) { - match input.dat_type() { - DatType::Table => self.execute_table(output, input), - DatType::Text => self.execute_text(output, input), - } - } - } -} - -impl FilterDat { - fn execute_table(&mut self, output: DatOutput, input: &DatInput) { - let mut output = output.table::(); - let [rows, cols] = input.table_size(); - output.set_table_size(rows, cols); - for row in 0..rows { - for col in 0..cols { - if let Some(cell) = input.cell(row, col) { - match self.params.case { - FilterType::UpperCamelCase => { - let formatted = to_camel_case(cell, self.params.keep_spaces); - output[[row, col]] = formatted; - } - FilterType::LowerCase => { - let formatted = to_lower_case(cell, self.params.keep_spaces); - output[[row, col]] = formatted; - } - FilterType::UpperCase => { - let formatted = to_upper_case(cell, self.params.keep_spaces); - output[[row, col]] = formatted; - } - } - } - } - } - } - - fn execute_text(&mut self, output: DatOutput, input: &DatInput) { - let mut output = output.text(); - match self.params.case { - FilterType::UpperCamelCase => { - let formatted = to_camel_case(input.text(), self.params.keep_spaces); - output.set_text(&formatted); - } - FilterType::LowerCase => { - let formatted = to_lower_case(input.text(), self.params.keep_spaces); - output.set_text(&formatted); - } - FilterType::UpperCase => { - let formatted = to_upper_case(input.text(), self.params.keep_spaces); - output.set_text(&formatted); - } - } - } -} - -pub fn to_camel_case(s: &str, keep_spaces: bool) -> String { - let mut out = String::new(); - let mut next_upper = true; - - for c in s.chars() { - if c.is_whitespace() { - next_upper = true; - if keep_spaces { - out.push(c); - } - } else if next_upper { - out.push(c.to_ascii_uppercase()); - next_upper = false; - } else { - out.push(c.to_ascii_lowercase()); - } - } - - out -} - -pub fn change_case(s: &str, keep_spaces: bool, upper: bool) -> String { - let mut out = String::new(); - - for c in s.chars() { - if keep_spaces || !c.is_whitespace() { - out.push(if upper { - c.to_ascii_uppercase() - } else { - c.to_ascii_lowercase() - }); - } - } - - out -} - -pub fn to_upper_case(s: &str, keep_spaces: bool) -> String { - change_case(s, keep_spaces, true) -} - -pub fn to_lower_case(s: &str, keep_spaces: bool) -> String { - change_case(s, keep_spaces, false) -} - -dat_plugin!(FilterDat); +use td_rs_dat::*; +use td_rs_derive::{Param, Params}; + +#[derive(Param, Default, Clone, Debug)] +enum FilterType { + UpperCamelCase, + #[default] + LowerCase, + UpperCase, +} + +#[derive(Params, Default, Clone, Debug)] +struct FilterDatParams { + #[param(label = "Case", page = "Filter")] + case: FilterType, + #[param(label = "Keep Spaces", page = "Filter")] + keep_spaces: bool, +} + +/// Struct representing our DAT's state +pub struct FilterDat { + params: FilterDatParams, +} + +impl OpNew for FilterDat { + fn new(_info: NodeInfo) -> Self { + Self { + params: Default::default(), + } + } +} + +impl OpInfo for FilterDat { + const OPERATOR_TYPE: &'static str = "Basicfilter"; + const OPERATOR_LABEL: &'static str = "Basic Filter"; + const MIN_INPUTS: usize = 1; + // This Dat takes no input + const MAX_INPUTS: usize = 1; +} + +impl Op for FilterDat { + fn params_mut(&mut self) -> Option> { + Some(Box::new(&mut self.params)) + } +} + +impl Dat for FilterDat { + fn general_info(&self, _inputs: &OperatorInputs) -> DatGeneralInfo { + DatGeneralInfo { + cook_every_frame: false, + cook_every_frame_if_asked: false, + } + } + + fn execute(&mut self, output: DatOutput, inputs: &OperatorInputs) { + if let Some(input) = inputs.input(0) { + match input.dat_type() { + DatType::Table => self.execute_table(output, input), + DatType::Text => self.execute_text(output, input), + } + } + } +} + +impl FilterDat { + fn execute_table(&mut self, output: DatOutput, input: &DatInput) { + let mut output = output.table::(); + let [rows, cols] = input.table_size(); + output.set_table_size(rows, cols); + for row in 0..rows { + for col in 0..cols { + if let Some(cell) = input.cell(row, col) { + match self.params.case { + FilterType::UpperCamelCase => { + let formatted = to_camel_case(cell, self.params.keep_spaces); + output[[row, col]] = formatted; + } + FilterType::LowerCase => { + let formatted = to_lower_case(cell, self.params.keep_spaces); + output[[row, col]] = formatted; + } + FilterType::UpperCase => { + let formatted = to_upper_case(cell, self.params.keep_spaces); + output[[row, col]] = formatted; + } + } + } + } + } + } + + fn execute_text(&mut self, output: DatOutput, input: &DatInput) { + let mut output = output.text(); + match self.params.case { + FilterType::UpperCamelCase => { + let formatted = to_camel_case(input.text(), self.params.keep_spaces); + output.set_text(&formatted); + } + FilterType::LowerCase => { + let formatted = to_lower_case(input.text(), self.params.keep_spaces); + output.set_text(&formatted); + } + FilterType::UpperCase => { + let formatted = to_upper_case(input.text(), self.params.keep_spaces); + output.set_text(&formatted); + } + } + } +} + +pub fn to_camel_case(s: &str, keep_spaces: bool) -> String { + let mut out = String::new(); + let mut next_upper = true; + + for c in s.chars() { + if c.is_whitespace() { + next_upper = true; + if keep_spaces { + out.push(c); + } + } else if next_upper { + out.push(c.to_ascii_uppercase()); + next_upper = false; + } else { + out.push(c.to_ascii_lowercase()); + } + } + + out +} + +pub fn change_case(s: &str, keep_spaces: bool, upper: bool) -> String { + let mut out = String::new(); + + for c in s.chars() { + if keep_spaces || !c.is_whitespace() { + out.push(if upper { + c.to_ascii_uppercase() + } else { + c.to_ascii_lowercase() + }); + } + } + + out +} + +pub fn to_upper_case(s: &str, keep_spaces: bool) -> String { + change_case(s, keep_spaces, true) +} + +pub fn to_lower_case(s: &str, keep_spaces: bool) -> String { + change_case(s, keep_spaces, false) +} + +dat_plugin!(FilterDat); diff --git a/plugins/sop/generator-sop/Cargo.toml b/plugins/sop/generator-sop/Cargo.toml index c5300ed..a6a30f6 100644 --- a/plugins/sop/generator-sop/Cargo.toml +++ b/plugins/sop/generator-sop/Cargo.toml @@ -1,15 +1,15 @@ -[package] -name = "generator-sop" -version = "0.1.0" -edition = "2021" - -[package.metadata.td-rs] -type = "sop" - -[lib] -name = "generator_sop" -crate-type = ["staticlib"] - -[dependencies] -td-rs-sop = { path = "../../../td-rs-sop" } -td-rs-derive = { path = "../../../td-rs-derive" } +[package] +name = "generator-sop" +version = "0.1.0" +edition = "2021" + +[package.metadata.td-rs] +type = "sop" + +[lib] +name = "generator_sop" +crate-type = ["staticlib"] + +[dependencies] +td-rs-sop = { path = "../../../td-rs-sop" } +td-rs-derive = { path = "../../../td-rs-derive" } diff --git a/plugins/sop/generator-sop/src/lib.rs b/plugins/sop/generator-sop/src/lib.rs index 0598f32..2503989 100644 --- a/plugins/sop/generator-sop/src/lib.rs +++ b/plugins/sop/generator-sop/src/lib.rs @@ -1,129 +1,129 @@ -mod shapes; - -use td_rs_derive::{Param, Params}; -use td_rs_sop::*; - -#[derive(Param, Default)] -enum Shape { - #[default] - Point, - Line, - Square, - Cube, -} - -#[derive(Params)] -struct GeneratorSopParams { - #[param(label = "Shape")] - shape: Shape, - #[param(label = "Color")] - color: Color, - #[param(label = "GPU Direct")] - gpu_direct: bool, -} - -struct GeneratorSop { - params: GeneratorSopParams, - shape_gen: shapes::ShapeGenerator, -} - -impl OpNew for GeneratorSop { - fn new(_info: NodeInfo) -> Self { - Self { - params: GeneratorSopParams { - shape: Shape::default(), - color: (0, 0, 0, 0).into(), - gpu_direct: false, - }, - shape_gen: shapes::ShapeGenerator {}, - } - } -} - -impl OpInfo for GeneratorSop { - const OPERATOR_TYPE: &'static str = "Generator"; - const OPERATOR_LABEL: &'static str = "Generator"; - const MIN_INPUTS: usize = 0; - const MAX_INPUTS: usize = 0; -} - -impl Op for GeneratorSop { - fn params_mut(&mut self) -> Option> { - Some(Box::new(&mut self.params)) - } -} - -impl Sop for GeneratorSop { - fn general_info(&self, _input: &OperatorInputs) -> SopGeneralInfo { - SopGeneralInfo { - cook_every_frame: false, - cook_every_frame_if_asked: false, - direct_to_gpu: self.params.gpu_direct, - } - } - - fn execute(&mut self, output: &mut SopOutput, _inputs: &OperatorInputs) { - match self.params.shape { - Shape::Point => self.shape_gen.output_dot(output), - Shape::Line => self.shape_gen.output_line(output), - Shape::Square => self.shape_gen.output_square(output), - Shape::Cube => self.shape_gen.output_cube(output), - } - - for i in 0..output.num_points() { - output.set_color(&self.params.color, i); - } - - output.set_bounding_box((-1, -1, -1, 1, 1, 1)); - } - - fn execute_vbo(&mut self, output: SopVboOutput, _inputs: &OperatorInputs) { - let mut output = match self.params.shape { - Shape::Point => { - let mut output = output.alloc_all(1, 1, 1, BufferMode::Static); - self.shape_gen.output_dot_vbo(&mut output); - output - } - Shape::Line => { - let mut output = output.alloc_all( - shapes::THE_LINE_NUM_PTS, - shapes::THE_LINE_NUM_PTS, - 1, - BufferMode::Static, - ); - self.shape_gen.output_line_vbo(&mut output); - output - } - Shape::Square => { - let mut output = output.alloc_all( - shapes::THE_SQUARE_NUM_PTS, - shapes::THE_SQUARE_NUM_PRIM * 3, - 1, - BufferMode::Static, - ); - self.shape_gen.output_square_vbo(&mut output); - output - } - Shape::Cube => { - let mut output = output.alloc_all( - shapes::THE_CUBE_NUM_PTS, - shapes::THE_CUBE_NUM_PRIM * 3, - 1, - BufferMode::Static, - ); - self.shape_gen.output_cube_vbo(&mut output); - output - } - }; - - let colors = output.colors(); - let num_vertices = output.state.vertices; - for i in 0..num_vertices { - colors[i] = self.params.color.clone(); - } - output.set_bounding_box((-1, -1, -1, 1, 1, 1)); - let _output = output.update_complete(); - } -} - -sop_plugin!(GeneratorSop); +mod shapes; + +use td_rs_derive::{Param, Params}; +use td_rs_sop::*; + +#[derive(Param, Default)] +enum Shape { + #[default] + Point, + Line, + Square, + Cube, +} + +#[derive(Params)] +struct GeneratorSopParams { + #[param(label = "Shape")] + shape: Shape, + #[param(label = "Color")] + color: Color, + #[param(label = "GPU Direct")] + gpu_direct: bool, +} + +struct GeneratorSop { + params: GeneratorSopParams, + shape_gen: shapes::ShapeGenerator, +} + +impl OpNew for GeneratorSop { + fn new(_info: NodeInfo) -> Self { + Self { + params: GeneratorSopParams { + shape: Shape::default(), + color: (0, 0, 0, 0).into(), + gpu_direct: false, + }, + shape_gen: shapes::ShapeGenerator {}, + } + } +} + +impl OpInfo for GeneratorSop { + const OPERATOR_TYPE: &'static str = "Generator"; + const OPERATOR_LABEL: &'static str = "Generator"; + const MIN_INPUTS: usize = 0; + const MAX_INPUTS: usize = 0; +} + +impl Op for GeneratorSop { + fn params_mut(&mut self) -> Option> { + Some(Box::new(&mut self.params)) + } +} + +impl Sop for GeneratorSop { + fn general_info(&self, _input: &OperatorInputs) -> SopGeneralInfo { + SopGeneralInfo { + cook_every_frame: false, + cook_every_frame_if_asked: false, + direct_to_gpu: self.params.gpu_direct, + } + } + + fn execute(&mut self, output: &mut SopOutput, _inputs: &OperatorInputs) { + match self.params.shape { + Shape::Point => self.shape_gen.output_dot(output), + Shape::Line => self.shape_gen.output_line(output), + Shape::Square => self.shape_gen.output_square(output), + Shape::Cube => self.shape_gen.output_cube(output), + } + + for i in 0..output.num_points() { + output.set_color(&self.params.color, i); + } + + output.set_bounding_box((-1, -1, -1, 1, 1, 1)); + } + + fn execute_vbo(&mut self, output: SopVboOutput, _inputs: &OperatorInputs) { + let mut output = match self.params.shape { + Shape::Point => { + let mut output = output.alloc_all(1, 1, 1, BufferMode::Static); + self.shape_gen.output_dot_vbo(&mut output); + output + } + Shape::Line => { + let mut output = output.alloc_all( + shapes::THE_LINE_NUM_PTS, + shapes::THE_LINE_NUM_PTS, + 1, + BufferMode::Static, + ); + self.shape_gen.output_line_vbo(&mut output); + output + } + Shape::Square => { + let mut output = output.alloc_all( + shapes::THE_SQUARE_NUM_PTS, + shapes::THE_SQUARE_NUM_PRIM * 3, + 1, + BufferMode::Static, + ); + self.shape_gen.output_square_vbo(&mut output); + output + } + Shape::Cube => { + let mut output = output.alloc_all( + shapes::THE_CUBE_NUM_PTS, + shapes::THE_CUBE_NUM_PRIM * 3, + 1, + BufferMode::Static, + ); + self.shape_gen.output_cube_vbo(&mut output); + output + } + }; + + let colors = output.colors(); + let num_vertices = output.state.vertices; + for i in 0..num_vertices { + colors[i] = self.params.color.clone(); + } + output.set_bounding_box((-1, -1, -1, 1, 1, 1)); + let _output = output.update_complete(); + } +} + +sop_plugin!(GeneratorSop); diff --git a/plugins/sop/generator-sop/src/shapes.rs b/plugins/sop/generator-sop/src/shapes.rs index 962cb85..b51a823 100644 --- a/plugins/sop/generator-sop/src/shapes.rs +++ b/plugins/sop/generator-sop/src/shapes.rs @@ -1,229 +1,229 @@ -use td_rs_sop::*; - -pub(crate) const THE_CUBE_NUM_PTS: usize = 24; -pub(crate) const THE_CUBE_NUM_PRIM: usize = 12; -pub(crate) const THE_SQUARE_NUM_PTS: usize = 4; -pub(crate) const THE_SQUARE_NUM_PRIM: usize = 2; -pub(crate) const THE_LINE_NUM_PTS: usize = 2; - -pub const THE_CUBE_POS: [Position; THE_CUBE_NUM_PTS] = [ - // front - Position::new(-1.0, -1.0, 1.0), - Position::new(-1.0, 1.0, 1.0), - Position::new(1.0, -1.0, 1.0), - Position::new(1.0, 1.0, 1.0), - // back - Position::new(-1.0, -1.0, -1.0), - Position::new(-1.0, 1.0, -1.0), - Position::new(1.0, -1.0, -1.0), - Position::new(1.0, 1.0, -1.0), - // top - Position::new(-1.0, 1.0, -1.0), - Position::new(1.0, 1.0, -1.0), - Position::new(-1.0, 1.0, 1.0), - Position::new(1.0, 1.0, 1.0), - // bottom - Position::new(-1.0, -1.0, -1.0), - Position::new(1.0, -1.0, -1.0), - Position::new(-1.0, -1.0, 1.0), - Position::new(1.0, -1.0, 1.0), - // right - Position::new(1.0, -1.0, -1.0), - Position::new(1.0, -1.0, 1.0), - Position::new(1.0, 1.0, -1.0), - Position::new(1.0, 1.0, 1.0), - // left - Position::new(-1.0, -1.0, -1.0), - Position::new(-1.0, -1.0, 1.0), - Position::new(-1.0, 1.0, -1.0), - Position::new(-1.0, 1.0, 1.0), -]; - -pub const THE_CUBE_NORMALS: [Vec3; THE_CUBE_NUM_PTS] = [ - // front - Vec3::new(0.0, 0.0, 1.0), - Vec3::new(0.0, 0.0, 1.0), - Vec3::new(0.0, 0.0, 1.0), - Vec3::new(0.0, 0.0, 1.0), - // back - Vec3::new(0.0, 0.0, -1.0), - Vec3::new(0.0, 0.0, -1.0), - Vec3::new(0.0, 0.0, -1.0), - Vec3::new(0.0, 0.0, -1.0), - // top - Vec3::new(0.0, 1.0, 0.0), - Vec3::new(0.0, 1.0, 0.0), - Vec3::new(0.0, 1.0, 0.0), - Vec3::new(0.0, 1.0, 0.0), - // bottom - Vec3::new(0.0, -1.0, 0.0), - Vec3::new(0.0, -1.0, 0.0), - Vec3::new(0.0, -1.0, 0.0), - Vec3::new(0.0, -1.0, 0.0), - // right - Vec3::new(1.0, 0.0, 0.0), - Vec3::new(1.0, 0.0, 0.0), - Vec3::new(1.0, 0.0, 0.0), - Vec3::new(1.0, 0.0, 0.0), - // left - Vec3::new(-1.0, 0.0, 0.0), - Vec3::new(-1.0, 0.0, 0.0), - Vec3::new(-1.0, 0.0, 0.0), - Vec3::new(-1.0, 0.0, 0.0), -]; - -pub const THE_CUBE_VERTICES: [u32; THE_CUBE_NUM_PRIM * 3] = [ - // front - 0, 1, 2, 3, 2, 1, // back - 6, 5, 4, 5, 6, 7, // top - 8, 9, 10, 11, 10, 9, // bottom - 14, 13, 12, 13, 14, 15, // right - 16, 17, 18, 19, 18, 17, // left - 22, 21, 20, 21, 22, 23, -]; - -pub const THE_CUBE_TEXTURE: [TexCoord; THE_CUBE_NUM_PTS] = [ - // front - TexCoord::new(2.0 / 3.0, 0.0, 0.0), - TexCoord::new(2.0 / 3.0, 0.5, 0.0), - TexCoord::new(1.0, 0.0, 0.0), - TexCoord::new(1.0, 0.5, 0.0), - // back - TexCoord::new(0.0 / 3.0, 0.5, 0.0), - TexCoord::new(0.0 / 3.0, 0.0, 0.0), - TexCoord::new(1.0 / 3.0, 0.5, 0.0), - TexCoord::new(1.0 / 3.0, 0.0, 0.0), - // top - TexCoord::new(2.0 / 3.0, 1.0, 0.0), - TexCoord::new(1.0, 1.0, 0.0), - TexCoord::new(2.0 / 3.0, 0.5, 0.0), - TexCoord::new(1.0, 0.5, 0.0), - // bottom - TexCoord::new(1.0 / 3.0, 0.5, 0.0), - TexCoord::new(2.0 / 3.0, 0.5, 0.0), - TexCoord::new(1.0 / 3.0, 1.0, 0.0), - TexCoord::new(2.0 / 3.0, 1.0, 0.0), - // right - TexCoord::new(2.0 / 3.0, 0.0, 0.0), - TexCoord::new(1.0 / 3.0, 0.0, 0.0), - TexCoord::new(2.0 / 3.0, 0.5, 0.0), - TexCoord::new(1.0 / 3.0, 0.5, 0.0), - // left - TexCoord::new(1.0 / 3.0, 1.0, 0.0), - TexCoord::new(0.0 / 3.0, 1.0, 0.0), - TexCoord::new(1.0 / 3.0, 0.5, 0.0), - TexCoord::new(0.0 / 3.0, 0.5, 0.0), -]; - -// Square descriptors -pub const THE_SQUARE_POS: [Position; THE_SQUARE_NUM_PTS] = [ - Position::new(-1.0, -1.0, 0.0), - Position::new(-1.0, 1.0, 0.0), - Position::new(1.0, -1.0, 0.0), - Position::new(1.0, 1.0, 0.0), -]; - -pub const THE_SQUARE_NORMALS: [Vec3; THE_SQUARE_NUM_PTS] = [ - Vec3::new(0.0, 0.0, 1.0), - Vec3::new(0.0, 0.0, 1.0), - Vec3::new(0.0, 0.0, 1.0), - Vec3::new(0.0, 0.0, 1.0), -]; - -pub const THE_SQUARE_VERTICES: [u32; THE_SQUARE_NUM_PRIM * 3] = [0, 1, 2, 3, 2, 1]; - -pub const THE_SQUARE_TEXTURE: [TexCoord; THE_SQUARE_NUM_PTS] = [ - TexCoord::new(0.0, 0.0, 0.0), - TexCoord::new(0.0, 1.0, 0.0), - TexCoord::new(1.0, 0.0, 0.0), - TexCoord::new(1.0, 1.0, 0.0), -]; - -// Line descriptors -pub const THE_LINE_POS: [Position; THE_LINE_NUM_PTS] = [ - Position::new(-1.0, -1.0, -1.0), - Position::new(1.0, 1.0, 1.0), -]; - -pub const THE_LINE_NORMALS: [Vec3; THE_LINE_NUM_PTS] = - [Vec3::new(-1.0, 0.0, 1.0), Vec3::new(-1.0, 0.0, 1.0)]; - -pub const THE_LINE_VERTICES: [u32; THE_LINE_NUM_PTS] = [0, 1]; - -pub const THE_LINE_TEXTURE: [TexCoord; THE_LINE_NUM_PTS] = - [TexCoord::new(0.0, 0.0, 0.0), TexCoord::new(1.0, 1.0, 0.0)]; - -// Point descriptors -pub const THE_POINT_POS: Position = Position::new(0.0, 0.0, 0.0); -pub const THE_POINT_NORMAL: Vec3 = Vec3::new(0.0, 0.0, 1.0); -pub const THE_POINT_TEXTURE: TexCoord = TexCoord::new(0.0, 0.0, 0.0); - -pub(crate) struct ShapeGenerator {} - -impl ShapeGenerator { - pub fn output_dot(&self, output: &mut SopOutput) { - output.add_point(THE_POINT_POS); - output.set_normal(THE_POINT_NORMAL, 0); - output.add_particle_system(1, 0); - // output.set_tex_coord(&THE_POINT_TEXTURE, 1, 0); - } - - pub fn output_line(&self, output: &mut SopOutput) { - output.add_points(&THE_LINE_POS); - output.set_normals(&THE_LINE_NORMALS, 0); - output.add_line(&THE_LINE_VERTICES); - // output.set_tex_coords(&THE_LINE_TEXTURE, 1, 0); - } - - pub fn output_square(&self, output: &mut SopOutput) { - output.add_points(&THE_SQUARE_POS); - output.set_normals(&THE_SQUARE_NORMALS, 0); - output.add_triangles(&THE_SQUARE_VERTICES); - output.set_tex_coords(&THE_SQUARE_TEXTURE, 1, 0); - } - - pub fn output_cube(&self, output: &mut SopOutput) { - output.add_points(&THE_CUBE_POS); - output.set_normals(&THE_CUBE_NORMALS, 0); - output.add_triangles(&THE_CUBE_VERTICES); - output.set_tex_coords(&THE_CUBE_TEXTURE, 1, 0); - } - - pub fn output_dot_vbo(&mut self, output: &mut SopVboOutput) { - output.positions()[0] = THE_POINT_POS; - output.normals()[0] = THE_POINT_NORMAL; - output.tex_coords()[0] = THE_POINT_TEXTURE; - } - - pub fn output_line_vbo(&mut self, output: &mut SopVboOutput) { - output.positions().clone_from_slice(&THE_LINE_POS); - output.normals().clone_from_slice(&THE_LINE_NORMALS); - output.tex_coords().clone_from_slice(&THE_LINE_TEXTURE); - output - .add_lines(THE_LINE_NUM_PTS) - .clone_from_slice(&THE_LINE_VERTICES); - } - - pub fn output_square_vbo(&mut self, output: &mut SopVboOutput) { - output.positions().clone_from_slice(&THE_SQUARE_POS); - // Here we manually invert the normals as per original C++ logic - for (i, normal) in output.normals().iter_mut().enumerate() { - *normal = &THE_SQUARE_NORMALS[i] * -1.0; - } - output.tex_coords().clone_from_slice(&THE_SQUARE_TEXTURE); - output - .add_triangles(THE_SQUARE_NUM_PRIM) - .clone_from_slice(&THE_SQUARE_VERTICES); - } - - pub fn output_cube_vbo(&mut self, output: &mut SopVboOutput) { - output.positions().clone_from_slice(&THE_CUBE_POS); - for (i, normal) in output.normals().iter_mut().enumerate() { - *normal = &THE_CUBE_NORMALS[i] * -1.0; - } - output.tex_coords().clone_from_slice(&THE_CUBE_TEXTURE); - output - .add_triangles(THE_CUBE_NUM_PRIM) - .clone_from_slice(&THE_CUBE_VERTICES); - } -} +use td_rs_sop::*; + +pub(crate) const THE_CUBE_NUM_PTS: usize = 24; +pub(crate) const THE_CUBE_NUM_PRIM: usize = 12; +pub(crate) const THE_SQUARE_NUM_PTS: usize = 4; +pub(crate) const THE_SQUARE_NUM_PRIM: usize = 2; +pub(crate) const THE_LINE_NUM_PTS: usize = 2; + +pub const THE_CUBE_POS: [Position; THE_CUBE_NUM_PTS] = [ + // front + Position::new(-1.0, -1.0, 1.0), + Position::new(-1.0, 1.0, 1.0), + Position::new(1.0, -1.0, 1.0), + Position::new(1.0, 1.0, 1.0), + // back + Position::new(-1.0, -1.0, -1.0), + Position::new(-1.0, 1.0, -1.0), + Position::new(1.0, -1.0, -1.0), + Position::new(1.0, 1.0, -1.0), + // top + Position::new(-1.0, 1.0, -1.0), + Position::new(1.0, 1.0, -1.0), + Position::new(-1.0, 1.0, 1.0), + Position::new(1.0, 1.0, 1.0), + // bottom + Position::new(-1.0, -1.0, -1.0), + Position::new(1.0, -1.0, -1.0), + Position::new(-1.0, -1.0, 1.0), + Position::new(1.0, -1.0, 1.0), + // right + Position::new(1.0, -1.0, -1.0), + Position::new(1.0, -1.0, 1.0), + Position::new(1.0, 1.0, -1.0), + Position::new(1.0, 1.0, 1.0), + // left + Position::new(-1.0, -1.0, -1.0), + Position::new(-1.0, -1.0, 1.0), + Position::new(-1.0, 1.0, -1.0), + Position::new(-1.0, 1.0, 1.0), +]; + +pub const THE_CUBE_NORMALS: [Vec3; THE_CUBE_NUM_PTS] = [ + // front + Vec3::new(0.0, 0.0, 1.0), + Vec3::new(0.0, 0.0, 1.0), + Vec3::new(0.0, 0.0, 1.0), + Vec3::new(0.0, 0.0, 1.0), + // back + Vec3::new(0.0, 0.0, -1.0), + Vec3::new(0.0, 0.0, -1.0), + Vec3::new(0.0, 0.0, -1.0), + Vec3::new(0.0, 0.0, -1.0), + // top + Vec3::new(0.0, 1.0, 0.0), + Vec3::new(0.0, 1.0, 0.0), + Vec3::new(0.0, 1.0, 0.0), + Vec3::new(0.0, 1.0, 0.0), + // bottom + Vec3::new(0.0, -1.0, 0.0), + Vec3::new(0.0, -1.0, 0.0), + Vec3::new(0.0, -1.0, 0.0), + Vec3::new(0.0, -1.0, 0.0), + // right + Vec3::new(1.0, 0.0, 0.0), + Vec3::new(1.0, 0.0, 0.0), + Vec3::new(1.0, 0.0, 0.0), + Vec3::new(1.0, 0.0, 0.0), + // left + Vec3::new(-1.0, 0.0, 0.0), + Vec3::new(-1.0, 0.0, 0.0), + Vec3::new(-1.0, 0.0, 0.0), + Vec3::new(-1.0, 0.0, 0.0), +]; + +pub const THE_CUBE_VERTICES: [u32; THE_CUBE_NUM_PRIM * 3] = [ + // front + 0, 1, 2, 3, 2, 1, // back + 6, 5, 4, 5, 6, 7, // top + 8, 9, 10, 11, 10, 9, // bottom + 14, 13, 12, 13, 14, 15, // right + 16, 17, 18, 19, 18, 17, // left + 22, 21, 20, 21, 22, 23, +]; + +pub const THE_CUBE_TEXTURE: [TexCoord; THE_CUBE_NUM_PTS] = [ + // front + TexCoord::new(2.0 / 3.0, 0.0, 0.0), + TexCoord::new(2.0 / 3.0, 0.5, 0.0), + TexCoord::new(1.0, 0.0, 0.0), + TexCoord::new(1.0, 0.5, 0.0), + // back + TexCoord::new(0.0 / 3.0, 0.5, 0.0), + TexCoord::new(0.0 / 3.0, 0.0, 0.0), + TexCoord::new(1.0 / 3.0, 0.5, 0.0), + TexCoord::new(1.0 / 3.0, 0.0, 0.0), + // top + TexCoord::new(2.0 / 3.0, 1.0, 0.0), + TexCoord::new(1.0, 1.0, 0.0), + TexCoord::new(2.0 / 3.0, 0.5, 0.0), + TexCoord::new(1.0, 0.5, 0.0), + // bottom + TexCoord::new(1.0 / 3.0, 0.5, 0.0), + TexCoord::new(2.0 / 3.0, 0.5, 0.0), + TexCoord::new(1.0 / 3.0, 1.0, 0.0), + TexCoord::new(2.0 / 3.0, 1.0, 0.0), + // right + TexCoord::new(2.0 / 3.0, 0.0, 0.0), + TexCoord::new(1.0 / 3.0, 0.0, 0.0), + TexCoord::new(2.0 / 3.0, 0.5, 0.0), + TexCoord::new(1.0 / 3.0, 0.5, 0.0), + // left + TexCoord::new(1.0 / 3.0, 1.0, 0.0), + TexCoord::new(0.0 / 3.0, 1.0, 0.0), + TexCoord::new(1.0 / 3.0, 0.5, 0.0), + TexCoord::new(0.0 / 3.0, 0.5, 0.0), +]; + +// Square descriptors +pub const THE_SQUARE_POS: [Position; THE_SQUARE_NUM_PTS] = [ + Position::new(-1.0, -1.0, 0.0), + Position::new(-1.0, 1.0, 0.0), + Position::new(1.0, -1.0, 0.0), + Position::new(1.0, 1.0, 0.0), +]; + +pub const THE_SQUARE_NORMALS: [Vec3; THE_SQUARE_NUM_PTS] = [ + Vec3::new(0.0, 0.0, 1.0), + Vec3::new(0.0, 0.0, 1.0), + Vec3::new(0.0, 0.0, 1.0), + Vec3::new(0.0, 0.0, 1.0), +]; + +pub const THE_SQUARE_VERTICES: [u32; THE_SQUARE_NUM_PRIM * 3] = [0, 1, 2, 3, 2, 1]; + +pub const THE_SQUARE_TEXTURE: [TexCoord; THE_SQUARE_NUM_PTS] = [ + TexCoord::new(0.0, 0.0, 0.0), + TexCoord::new(0.0, 1.0, 0.0), + TexCoord::new(1.0, 0.0, 0.0), + TexCoord::new(1.0, 1.0, 0.0), +]; + +// Line descriptors +pub const THE_LINE_POS: [Position; THE_LINE_NUM_PTS] = [ + Position::new(-1.0, -1.0, -1.0), + Position::new(1.0, 1.0, 1.0), +]; + +pub const THE_LINE_NORMALS: [Vec3; THE_LINE_NUM_PTS] = + [Vec3::new(-1.0, 0.0, 1.0), Vec3::new(-1.0, 0.0, 1.0)]; + +pub const THE_LINE_VERTICES: [u32; THE_LINE_NUM_PTS] = [0, 1]; + +pub const THE_LINE_TEXTURE: [TexCoord; THE_LINE_NUM_PTS] = + [TexCoord::new(0.0, 0.0, 0.0), TexCoord::new(1.0, 1.0, 0.0)]; + +// Point descriptors +pub const THE_POINT_POS: Position = Position::new(0.0, 0.0, 0.0); +pub const THE_POINT_NORMAL: Vec3 = Vec3::new(0.0, 0.0, 1.0); +pub const THE_POINT_TEXTURE: TexCoord = TexCoord::new(0.0, 0.0, 0.0); + +pub(crate) struct ShapeGenerator {} + +impl ShapeGenerator { + pub fn output_dot(&self, output: &mut SopOutput) { + output.add_point(THE_POINT_POS); + output.set_normal(THE_POINT_NORMAL, 0); + output.add_particle_system(1, 0); + // output.set_tex_coord(&THE_POINT_TEXTURE, 1, 0); + } + + pub fn output_line(&self, output: &mut SopOutput) { + output.add_points(&THE_LINE_POS); + output.set_normals(&THE_LINE_NORMALS, 0); + output.add_line(&THE_LINE_VERTICES); + // output.set_tex_coords(&THE_LINE_TEXTURE, 1, 0); + } + + pub fn output_square(&self, output: &mut SopOutput) { + output.add_points(&THE_SQUARE_POS); + output.set_normals(&THE_SQUARE_NORMALS, 0); + output.add_triangles(&THE_SQUARE_VERTICES); + output.set_tex_coords(&THE_SQUARE_TEXTURE, 1, 0); + } + + pub fn output_cube(&self, output: &mut SopOutput) { + output.add_points(&THE_CUBE_POS); + output.set_normals(&THE_CUBE_NORMALS, 0); + output.add_triangles(&THE_CUBE_VERTICES); + output.set_tex_coords(&THE_CUBE_TEXTURE, 1, 0); + } + + pub fn output_dot_vbo(&mut self, output: &mut SopVboOutput) { + output.positions()[0] = THE_POINT_POS; + output.normals()[0] = THE_POINT_NORMAL; + output.tex_coords()[0] = THE_POINT_TEXTURE; + } + + pub fn output_line_vbo(&mut self, output: &mut SopVboOutput) { + output.positions().clone_from_slice(&THE_LINE_POS); + output.normals().clone_from_slice(&THE_LINE_NORMALS); + output.tex_coords().clone_from_slice(&THE_LINE_TEXTURE); + output + .add_lines(THE_LINE_NUM_PTS) + .clone_from_slice(&THE_LINE_VERTICES); + } + + pub fn output_square_vbo(&mut self, output: &mut SopVboOutput) { + output.positions().clone_from_slice(&THE_SQUARE_POS); + // Here we manually invert the normals as per original C++ logic + for (i, normal) in output.normals().iter_mut().enumerate() { + *normal = &THE_SQUARE_NORMALS[i] * -1.0; + } + output.tex_coords().clone_from_slice(&THE_SQUARE_TEXTURE); + output + .add_triangles(THE_SQUARE_NUM_PRIM) + .clone_from_slice(&THE_SQUARE_VERTICES); + } + + pub fn output_cube_vbo(&mut self, output: &mut SopVboOutput) { + output.positions().clone_from_slice(&THE_CUBE_POS); + for (i, normal) in output.normals().iter_mut().enumerate() { + *normal = &THE_CUBE_NORMALS[i] * -1.0; + } + output.tex_coords().clone_from_slice(&THE_CUBE_TEXTURE); + output + .add_triangles(THE_CUBE_NUM_PRIM) + .clone_from_slice(&THE_CUBE_VERTICES); + } +} diff --git a/plugins/top/bevy-top/Cargo.toml b/plugins/top/bevy-top/Cargo.toml new file mode 100644 index 0000000..33d949e --- /dev/null +++ b/plugins/top/bevy-top/Cargo.toml @@ -0,0 +1,58 @@ +[package] +name = "bevy-top" +version = "0.1.0" +edition = "2021" + +[package.metadata.td-rs] +type = "top" + +[lib] +name = "bevy_top" +crate-type = ["staticlib"] + +[dependencies] +td-rs-top = { path = "../../../td-rs-top", features = ["cuda"] } +td-rs-derive = { path = "../../../td-rs-derive" } +bevy = { version = "0.16", default-features = false, features = [ + "std", + "async_executor", + "android-game-activity", + "android_shared_stdcxx", + "animation", + "bevy_asset", + "bevy_audio", + "bevy_color", + "bevy_core_pipeline", + "bevy_gilrs", + "bevy_gizmos", + "bevy_gltf", + "bevy_input_focus", + "bevy_log", + "bevy_mesh_picking_backend", + "bevy_pbr", + "bevy_picking", + "bevy_render", + "bevy_scene", + "bevy_sprite", + "bevy_sprite_picking_backend", + "bevy_state", + "bevy_text", + "bevy_ui", + "bevy_ui_picking_backend", + "bevy_window", + "bevy_winit", + "custom_cursor", + "default_font", + "hdr", + "png", + "smaa_luts", + "sysinfo_plugin", + "tonemapping_luts", + "vorbis", + "webgl2", + "x11", +] } +ash = "0.38" +cudarc = { version = "0.16.4", features = ["runtime", "nvrtc", "driver", "cuda-12080", "dynamic-linking"], default-features = false } +anyhow = "1.0" +wgpu = "24.0" \ No newline at end of file diff --git a/plugins/top/bevy-top/src/lib.rs b/plugins/top/bevy-top/src/lib.rs new file mode 100644 index 0000000..5be6f17 --- /dev/null +++ b/plugins/top/bevy-top/src/lib.rs @@ -0,0 +1,1689 @@ +use anyhow::Result; +use ash::{khr, vk, Device, Instance}; +use bevy::ecs::entity::EntityHashMap; +use bevy::reflect::List; +use bevy::render::camera::{ + ManualTextureView, ManualTextureViewHandle, ManualTextureViews, RenderTarget, +}; +use bevy::render::pipelined_rendering::PipelinedRenderingPlugin; +use bevy::render::render_resource::{Texture, TextureDescriptor, TextureFormat, TextureView}; +use bevy::render::texture::DefaultImageSampler; +use bevy::render::Extract; +use bevy::{ + core_pipeline::post_process::ChromaticAberration, + prelude::*, + render::{ + render_asset::RenderAssets, renderer::RenderDevice, texture::GpuImage, ExtractSchedule, + RenderApp, + }, + window::WindowPlugin, +}; +use cudarc::driver::{sys, CudaContext}; +use cudarc::runtime::sys::CUstream_st; +use std::collections::HashMap; +use std::f32::consts::PI; +use std::fs::File; +use std::mem::ManuallyDrop; +use std::os::windows::io::{AsRawHandle, FromRawHandle, RawHandle}; +use std::sync::{Arc, Mutex}; +use td_rs_derive::Params; +use td_rs_top::*; +use wgpu::{Extent3d, TextureDimension, TextureUsages}; + +fn get_bytes_per_pixel(format: &PixelFormat) -> usize { + match format { + PixelFormat::Invalid => 0, + + PixelFormat::BGRA8Fixed + | PixelFormat::RGBA8Fixed + | PixelFormat::SBGRA8Fixed + | PixelFormat::SRGBA8Fixed => 4, + PixelFormat::MonoA8Fixed | PixelFormat::RG8Fixed => 2, + PixelFormat::Mono8Fixed | PixelFormat::A8Fixed => 1, + + PixelFormat::RGBA16Fixed | PixelFormat::RGBA16Float => 8, + PixelFormat::MonoA16Fixed + | PixelFormat::MonoA16Float + | PixelFormat::RG16Fixed + | PixelFormat::RG16Float => 4, + PixelFormat::Mono16Fixed + | PixelFormat::Mono16Float + | PixelFormat::A16Fixed + | PixelFormat::A16Float => 2, + + PixelFormat::RGBA32Float => 16, + PixelFormat::MonoA32Float | PixelFormat::RG32Float => 8, + PixelFormat::Mono32Float | PixelFormat::A32Float => 4, + + PixelFormat::RGB10A2Fixed => 4, + PixelFormat::RGB11Float => 4, + } +} + +fn get_preferred_output_format(input_format: &PixelFormat) -> PixelFormat { + match input_format { + PixelFormat::RGBA8Fixed => PixelFormat::BGRA8Fixed, + PixelFormat::BGRA8Fixed => PixelFormat::BGRA8Fixed, + PixelFormat::SRGBA8Fixed => PixelFormat::SBGRA8Fixed, + PixelFormat::SBGRA8Fixed => PixelFormat::SBGRA8Fixed, + + PixelFormat::RGBA16Fixed => PixelFormat::RGBA16Fixed, + PixelFormat::RGBA16Float => PixelFormat::RGBA16Float, + + PixelFormat::RGBA32Float => PixelFormat::RGBA32Float, + + PixelFormat::Mono8Fixed | PixelFormat::MonoA8Fixed | PixelFormat::RG8Fixed => { + PixelFormat::BGRA8Fixed + } + PixelFormat::Mono16Fixed | PixelFormat::MonoA16Fixed | PixelFormat::RG16Fixed => { + PixelFormat::RGBA16Fixed + } + PixelFormat::Mono32Float | PixelFormat::MonoA32Float | PixelFormat::RG32Float => { + PixelFormat::RGBA32Float + } + + _ => PixelFormat::BGRA8Fixed, + } +} + +fn pixel_format_to_vulkan_format(format: &PixelFormat) -> vk::Format { + match format { + PixelFormat::BGRA8Fixed => vk::Format::B8G8R8A8_UNORM, + PixelFormat::RGBA8Fixed => vk::Format::R8G8B8A8_UNORM, + PixelFormat::SBGRA8Fixed => vk::Format::B8G8R8A8_SRGB, + PixelFormat::SRGBA8Fixed => vk::Format::R8G8B8A8_SRGB, + + PixelFormat::RGBA16Fixed => vk::Format::R16G16B16A16_UNORM, + PixelFormat::RGBA16Float => vk::Format::R16G16B16A16_SFLOAT, + + PixelFormat::RGBA32Float => vk::Format::R32G32B32A32_SFLOAT, + + PixelFormat::Mono8Fixed => vk::Format::R8_UNORM, + PixelFormat::Mono16Fixed => vk::Format::R16_UNORM, + PixelFormat::Mono16Float => vk::Format::R16_SFLOAT, + PixelFormat::Mono32Float => vk::Format::R32_SFLOAT, + PixelFormat::RG8Fixed => vk::Format::R8G8_UNORM, + PixelFormat::RG16Fixed => vk::Format::R16G16_UNORM, + PixelFormat::RG16Float => vk::Format::R16G16_SFLOAT, + PixelFormat::RG32Float => vk::Format::R32G32_SFLOAT, + + PixelFormat::A8Fixed => vk::Format::R8_UNORM, + PixelFormat::A16Fixed => vk::Format::R16_UNORM, + PixelFormat::A16Float => vk::Format::R16_SFLOAT, + PixelFormat::A32Float => vk::Format::R32_SFLOAT, + + PixelFormat::MonoA8Fixed => vk::Format::R8G8_UNORM, + PixelFormat::MonoA16Fixed => vk::Format::R16G16_UNORM, + PixelFormat::MonoA16Float => vk::Format::R16G16_SFLOAT, + PixelFormat::MonoA32Float => vk::Format::R32G32_SFLOAT, + + PixelFormat::RGB10A2Fixed => vk::Format::A2B10G10R10_UNORM_PACK32, + PixelFormat::RGB11Float => vk::Format::B10G11R11_UFLOAT_PACK32, + + _ => vk::Format::B8G8R8A8_UNORM, + } +} + +fn pixel_format_to_wgpu_format(format: &PixelFormat) -> TextureFormat { + match format { + PixelFormat::BGRA8Fixed => TextureFormat::Bgra8Unorm, + PixelFormat::RGBA8Fixed => TextureFormat::Rgba8Unorm, + PixelFormat::SBGRA8Fixed => TextureFormat::Bgra8UnormSrgb, + PixelFormat::SRGBA8Fixed => TextureFormat::Rgba8UnormSrgb, + + PixelFormat::RGBA16Fixed => TextureFormat::Rgba16Unorm, + PixelFormat::RGBA16Float => TextureFormat::Rgba16Float, + + PixelFormat::RGBA32Float => TextureFormat::Rgba32Float, + + PixelFormat::Mono8Fixed => TextureFormat::R8Unorm, + PixelFormat::Mono16Fixed => TextureFormat::R16Unorm, + PixelFormat::Mono16Float => TextureFormat::R16Float, + PixelFormat::Mono32Float => TextureFormat::R32Float, + PixelFormat::RG8Fixed => TextureFormat::Rg8Unorm, + PixelFormat::RG16Fixed => TextureFormat::Rg16Unorm, + PixelFormat::RG16Float => TextureFormat::Rg16Float, + PixelFormat::RG32Float => TextureFormat::Rg32Float, + + PixelFormat::A8Fixed => TextureFormat::R8Unorm, + PixelFormat::A16Fixed => TextureFormat::R16Unorm, + PixelFormat::A16Float => TextureFormat::R16Float, + PixelFormat::A32Float => TextureFormat::R32Float, + + PixelFormat::MonoA8Fixed => TextureFormat::Rg8Unorm, + PixelFormat::MonoA16Fixed => TextureFormat::Rg16Unorm, + PixelFormat::MonoA16Float => TextureFormat::Rg16Float, + PixelFormat::MonoA32Float => TextureFormat::Rg32Float, + + PixelFormat::RGB10A2Fixed => TextureFormat::Rgb10a2Unorm, + PixelFormat::RGB11Float => TextureFormat::Rg11b10Ufloat, + + _ => TextureFormat::Bgra8Unorm, + } +} + +#[derive(Params, Default, Clone, Debug)] +struct BevyTopParams { + #[param( + label = "Intensity", + page = "Chromatic Aberration ", + default = 0.01, + min = 0.0, + max = 0.4 + )] + chromatic_aberration_intensity: f64, + #[param(label = "Color LUT", page = "Chromatic Aberration ")] + chromatic_aberration_color_lut: TopParam, + #[param( + label = "Intensity", + page = "Chromatic Aberration ", + default = 8.0, + min = 1.0, + max = 16.0 + )] + chromatic_aberration_max_samples: u32, +} + +pub struct BevyTop { + params: BevyTopParams, + context: Arc>, + app: Option, + inputs_entities: HashMap, + output_entities: HashMap, +} + +#[derive(Component)] +struct SharedTexture { + vulkan_memory: vk::DeviceMemory, + vulkan_image: vk::Image, + vulkan_device: Device, + width: u32, + height: u32, + texture_desc: TextureDesc, + pixel_format: PixelFormat, + row_pitch: usize, +} + +#[derive(Default, Deref, DerefMut)] +pub struct SharedTextureExternalMemory(EntityHashMap); + +impl Drop for SharedTexture { + fn drop(&mut self) { + unsafe { + self.vulkan_device.destroy_image(self.vulkan_image, None); + } + + unsafe { + self.vulkan_device.free_memory(self.vulkan_memory, None); + } + } +} + +#[derive(Component)] +struct InputTexture(usize); + +#[derive(Component, Deref)] +struct InputTextureImage(Handle); + +#[derive(Component)] +struct OutputTexture(usize); + +#[derive(Component, Deref)] +pub struct WgpuTexture(Texture); + +#[derive(Component, Deref)] +pub struct WgpuTextureView(TextureView); + +#[derive(Component, PartialEq)] +pub struct TextureKey(TextureDesc); + +#[derive(Component)] +struct OutputCamera(usize); + +#[derive(Component)] +struct InputTexturedQuad; + +#[derive(Component, Deref)] +pub struct CudaArray(CudaArrayInfo); + +#[derive(Resource)] +pub struct CudaCtx(Arc); + +#[derive(Deref)] +pub struct CudaStream(*mut CUstream_st); + +#[derive(Resource)] +struct AppSettings { + chromatic_aberration_intensity: f32, +} + +impl Default for AppSettings { + fn default() -> Self { + Self { + chromatic_aberration_intensity: 0.01, + } + } +} + +#[derive(Resource)] +struct PreferredOutput { + format: PixelFormat, + resolution: UVec2, +} + +impl TopNew for BevyTop { + fn new(_info: NodeInfo, context: TopContext) -> Self { + Self { + params: BevyTopParams::default(), + context: Arc::new(Mutex::new(context)), + app: None, + inputs_entities: HashMap::default(), + output_entities: HashMap::default(), + } + } +} + +impl OpInfo for BevyTop { + const OPERATOR_LABEL: &'static str = "Bevy"; + const OPERATOR_TYPE: &'static str = "Bevy"; + const OPERATOR_ICON: &'static str = "BVY"; + const MIN_INPUTS: usize = 1; + const MAX_INPUTS: usize = 1; +} + +impl TopInfo for BevyTop { + const EXECUTE_MODE: ExecuteMode = ExecuteMode::Cuda; +} + +impl Op for BevyTop { + fn params_mut(&mut self) -> Option> { + Some(Box::new(&mut self.params)) + } +} + +impl Top for BevyTop { + fn general_info(&self, _input: &OperatorInputs) -> TopGeneralInfo { + TopGeneralInfo { + cook_every_frame_if_asked: true, + ..Default::default() + } + } + + fn execute(&mut self, mut output: TopOutput, input: &OperatorInputs) { + match self.execute_inner(&mut output, input) { + Err(e) => self.set_error(&format!("Bevy TOP execution failed: {}", e)), + _ => {} + } + } +} + +impl BevyTop { + fn execute_inner( + &mut self, + output: &mut TopOutput, + top_input: &OperatorInputs, + ) -> Result<()> { + if self.app.is_none() { + self.app = Some(Self::init_bevy_app()); + } + + let Some(app) = self.app.as_mut() else { + return Err(anyhow::anyhow!("Bevy app is not initialized")); + }; + + Self::update_app_settings(&self.params, app); + + // Setup cuda context and stream + if let None = app.world().get_resource::() { + let ctx = CudaContext::new(0) + .map_err(|e| anyhow::anyhow!("Failed to create CUDA context: {:?}", e))?; + app.world_mut().insert_resource(CudaCtx(ctx)); + } + if let None = app.world().get_non_send_resource::() { + unsafe { + use cudarc::runtime::sys::*; + let mut stream = std::ptr::null_mut(); + let result = cudaStreamCreate(&mut stream); + if result != cudaError::cudaSuccess { + return Err(anyhow::anyhow!( + "Failed to create CUDA stream: {:?}", + result + )); + } + app.world_mut().insert_non_send_resource(CudaStream(stream)); + } + } + + let (output_width, output_height, output_format) = Self::get_resolution_and_format( + top_input.params(), + top_input.input(0).map(|x| x.texture_desc()), + ); + app.world_mut().insert_resource(PreferredOutput { + format: output_format, + resolution: UVec2::new(output_width as u32, output_height as u32), + }); + + for idx in 0..top_input.num_inputs() { + let input = top_input + .input(idx) + .ok_or_else(|| anyhow::anyhow!("Input {} not found in OperatorInputs", idx))?; + let cuda_array = + input.get_cuda_array(app.world().non_send_resource::().0)?; + let texture_desc = cuda_array.texture_desc(); + let cuda_array = CudaArray(cuda_array); + let entity = self.inputs_entities.entry(idx).or_insert_with(|| { + let image_handle = app + .world_mut() + .resource_mut::>() + .reserve_handle(); + app.world_mut() + .spawn(( + InputTexture(idx), + InputTextureImage(image_handle), + TextureKey(texture_desc), + )) + .id() + }); + app.world_mut().entity_mut(*entity).insert(cuda_array); + } + + let output_cuda_info = CudaOutputInfo { + stream: std::ptr::null_mut(), + texture_desc: TextureDesc { + width: output_width, + height: output_height, + depth: 1, + tex_dim: TexDim::E2D, + pixel_format: output_format, + aspect_x: 0.0, + aspect_y: 0.0, + }, + color_buffer_index: 0, + }; + + let output_array_info = output.create_cuda_array(&output_cuda_info)?; + + self.output_entities.entry(0).or_insert_with(|| { + app.world_mut() + .spawn(( + OutputTexture(0), + TextureKey(output_array_info.texture_desc()), + CudaArray(output_array_info), + )) + .id() + }); + + let began_successfully = { + let mut ctx = self + .context + .lock() + .map_err(|e| anyhow::anyhow!("Failed to lock context: {}", e))?; + ctx.begin_cuda_operations() + }; + + if !began_successfully { + return Err(anyhow::anyhow!("Failed to begin CUDA operations")); + } + + Self::update(app); + Self::export_output(app.world_mut()) + .map_err(|e| anyhow::anyhow!("Failed to export output: {}", e))?; + + self.context + .lock() + .map_err(|e| anyhow::anyhow!("Failed to lock context: {}", e))? + .end_cuda_operations(); + + Ok(()) + } + + fn get_resolution_and_format( + params: ParamInputs, + first_input_desc: Option, + ) -> (usize, usize, PixelFormat) { + let mut output_width = 512; + let mut output_height = 512; + let output_resolution = params.get_string("outputresolution"); + let mut output_format = PixelFormat::BGRA8Fixed; + + match output_resolution { + "useinput" => { + if let Some(input_desc) = &first_input_desc { + output_width = input_desc.width; + output_height = input_desc.height; + } + } + "eigth" => { + if let Some(input_desc) = &first_input_desc { + output_width = input_desc.width / 8; + output_height = input_desc.height / 8; + } + } + "quarter" => { + if let Some(input_desc) = &first_input_desc { + output_width = input_desc.width / 4; + output_height = input_desc.height / 4; + } + } + "half" => { + if let Some(input_desc) = &first_input_desc { + output_width = input_desc.width / 2; + output_height = input_desc.height / 2; + } + } + "2x" => { + if let Some(input_desc) = &first_input_desc { + output_width = input_desc.width * 2; + output_height = input_desc.height * 2; + } + } + "4x" => { + if let Some(input_desc) = &first_input_desc { + output_width = input_desc.width * 4; + output_height = input_desc.height * 4; + } + } + "8x" => { + if let Some(input_desc) = &first_input_desc { + output_width = input_desc.width * 8; + output_height = input_desc.height * 8; + } + } + "fit" => { + if let Some(input_desc) = &first_input_desc { + let aspect_ratio = input_desc.width as f32 / input_desc.height as f32; + if aspect_ratio > 1.0 { + output_width = 512; + output_height = (512.0 / aspect_ratio) as usize; + } else { + output_height = 512; + output_width = (512.0 * aspect_ratio) as usize; + } + } + } + "limit" => { + if let Some(input_desc) = &first_input_desc { + let max_size = 512; + if input_desc.width > max_size || input_desc.height > max_size { + let aspect_ratio = input_desc.width as f32 / input_desc.height as f32; + if aspect_ratio > 1.0 { + output_width = max_size; + output_height = (max_size as f32 / aspect_ratio) as usize; + } else { + output_height = max_size; + output_width = (max_size as f32 * aspect_ratio) as usize; + } + } else { + output_width = input_desc.width; + output_height = input_desc.height; + } + } + } + "custom" => { + let custom_width = params.get_int("resolution", 0); + let custom_height = params.get_int("resolution", 1); + if custom_width > 0 && custom_height > 0 { + output_width = custom_width as usize; + output_height = custom_height as usize; + } + } + "parpanel" => {} + _ => {} + }; + + let format = params.get_string("format"); + match format { + "useinput" => { + if let Some(input_desc) = &first_input_desc { + output_format = input_desc.pixel_format; + } + } + "rgba8fixed" => { + output_format = PixelFormat::RGBA8Fixed; + } + "bgra8fixed" => { + output_format = PixelFormat::BGRA8Fixed; + } + "srgba8fixed" => { + output_format = PixelFormat::SRGBA8Fixed; + } + "sbgra8fixed" => { + output_format = PixelFormat::SBGRA8Fixed; + } + "rgba16fixed" => { + output_format = PixelFormat::RGBA16Fixed; + } + "rgba16float" => { + output_format = PixelFormat::RGBA16Float; + } + "rgba32float" => { + output_format = PixelFormat::RGBA32Float; + } + "mono8fixed" => { + output_format = PixelFormat::Mono8Fixed; + } + "mono16fixed" => { + output_format = PixelFormat::Mono16Fixed; + } + "mono16float" => { + output_format = PixelFormat::Mono16Float; + } + "mono32float" => { + output_format = PixelFormat::Mono32Float; + } + "rg8fixed" => { + output_format = PixelFormat::RG8Fixed; + } + "rg16fixed" => { + output_format = PixelFormat::RG16Fixed; + } + "rg16float" => { + output_format = PixelFormat::RG16Float; + } + "rg32float" => { + output_format = PixelFormat::RG32Float; + } + "a8fixed" => { + output_format = PixelFormat::A8Fixed; + } + "a16fixed" => { + output_format = PixelFormat::A16Fixed; + } + "a16float" => { + output_format = PixelFormat::A16Float; + } + "a32float" => { + output_format = PixelFormat::A32Float; + } + "monoalpha8fixed" => { + output_format = PixelFormat::MonoA8Fixed; + } + "monoalpha16fixed" => { + output_format = PixelFormat::MonoA16Fixed; + } + "monoalpha16float" => { + output_format = PixelFormat::MonoA16Float; + } + "monoalpha32float" => { + output_format = PixelFormat::MonoA32Float; + } + "rgb10a2fixed" => { + output_format = PixelFormat::RGB10A2Fixed; + } + "rgba11float" => { + output_format = PixelFormat::RGB11Float; + } + _ => {} + } + + (output_width, output_height, output_format) + } + + fn import_inputs( + mut commands: Commands, + arrays: Query<(Entity, &CudaArray, &TextureKey), With>, + render_device: Res, + cuda_ctx: Res, + mut shared_texture_external_memory: NonSendMut, + ) -> bevy::prelude::Result { + for (entity, array, key) in arrays.iter() { + let texture_desc = array.texture_desc(); + let width = texture_desc.width as u32; + let height = texture_desc.height as u32; + + if *key != TextureKey(texture_desc) { + unsafe { + render_device + .wgpu_device() + .as_hal::(|device| { + let Some(device) = device else { + return Err(anyhow::anyhow!("Failed to get Vulkan device")); + }; + + let instance = device.shared_instance().raw_instance(); + let physical_device = device.raw_physical_device(); + let vulkan_device = device.raw_device(); + let (texture, external_memory) = Self::create_input_external_memory( + &cuda_ctx.0, + instance, + vulkan_device, + physical_device, + &array, + width, + height, + )?; + commands + .entity(entity) + .remove::() + .insert(texture); + shared_texture_external_memory.insert(entity, external_memory); + Ok(()) + })?; + } + } + } + + Ok(()) + } + + fn import_outputs( + mut commands: Commands, + arrays: Query<(Entity, &CudaArray, &TextureKey), With>, + render_device: Res, + cuda_ctx: Res, + mut shared_texture_external_memory: NonSendMut, + ) -> bevy::prelude::Result { + for (entity, array, key) in arrays.iter() { + let texture_desc = array.texture_desc(); + + if *key != TextureKey(texture_desc) { + let output_desc = array.texture_desc(); + if *key != TextureKey(output_desc) { + unsafe { + render_device + .wgpu_device() + .as_hal::(|device| { + let Some(device) = device else { + return Err(anyhow::anyhow!("Failed to get Vulkan device")); + }; + + let instance = device.shared_instance().raw_instance(); + let physical_device = device.raw_physical_device(); + let vulkan_device = device.raw_device(); + + let (texture, external_memory) = + Self::create_output_external_memory( + &cuda_ctx.0, + instance, + vulkan_device, + physical_device, + array, + )?; + + commands + .entity(entity) + .remove::() + .insert(texture); + shared_texture_external_memory.insert(entity, external_memory); + Ok(()) + })?; + }; + } + } + } + + Ok(()) + } + + fn create_output_external_memory( + ctx: &CudaContext, + instance: &Instance, + device: &Device, + physical_device: vk::PhysicalDevice, + output_array_info: &CudaArrayInfo, + ) -> Result<(SharedTexture, ExternalMemory)> { + let output_desc = output_array_info.texture_desc(); + let width = output_desc.width as u32; + let height = output_desc.height as u32; + + let vulkan_format = pixel_format_to_vulkan_format(&output_desc.pixel_format); + + let mut ext_mem_image_info = vk::ExternalMemoryImageCreateInfoKHR::default(); + ext_mem_image_info.handle_types = vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32; + + let mut image_create_info = vk::ImageCreateInfo::default(); + image_create_info.p_next = &ext_mem_image_info as *const _ as *const std::ffi::c_void; + image_create_info.image_type = vk::ImageType::TYPE_2D; + image_create_info.format = vulkan_format; + image_create_info.extent = vk::Extent3D { + width, + height, + depth: 1, + }; + image_create_info.mip_levels = 1; + image_create_info.array_layers = 1; + image_create_info.samples = vk::SampleCountFlags::TYPE_1; + image_create_info.tiling = vk::ImageTiling::LINEAR; + image_create_info.usage = vk::ImageUsageFlags::COLOR_ATTACHMENT + | vk::ImageUsageFlags::TRANSFER_SRC + | vk::ImageUsageFlags::SAMPLED; + image_create_info.sharing_mode = vk::SharingMode::EXCLUSIVE; + image_create_info.initial_layout = vk::ImageLayout::UNDEFINED; + + let output_image = unsafe { + device + .create_image(&image_create_info, None) + .map_err(|e| anyhow::anyhow!("Failed to create output image: {:?}", e))? + }; + + let image_mem_reqs = unsafe { device.get_image_memory_requirements(output_image) }; + + let memory_type_index = find_memory_type_for_external( + instance, + physical_device, + image_mem_reqs.memory_type_bits, + )?; + + let mut export_mem_info = vk::ExportMemoryAllocateInfo::default(); + export_mem_info.handle_types = vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32; + + let mut alloc_info = vk::MemoryAllocateInfo::default(); + alloc_info.p_next = &export_mem_info as *const _ as *const std::ffi::c_void; + alloc_info.allocation_size = image_mem_reqs.size; + alloc_info.memory_type_index = memory_type_index; + + let output_memory = unsafe { + device + .allocate_memory(&alloc_info, None) + .map_err(|e| anyhow::anyhow!("Failed to allocate output memory: {:?}", e))? + }; + + unsafe { + device + .bind_image_memory(output_image, output_memory, 0) + .map_err(|e| anyhow::anyhow!("Failed to bind output image memory: {:?}", e))?; + } + + let ext_mem_win32 = khr::external_memory_win32::Device::new(instance, device); + let mut handle_info = vk::MemoryGetWin32HandleInfoKHR::default(); + handle_info.memory = output_memory; + handle_info.handle_type = vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32; + + let handle = unsafe { + ext_mem_win32 + .get_memory_win32_handle(&handle_info) + .map_err(|e| anyhow::anyhow!("Failed to get Win32 handle for output: {:?}", e))? + }; + + let file = unsafe { File::from_raw_handle(handle as RawHandle) }; + let cuda_external_memory = + unsafe { import_external_memory_dedicated(&ctx, file, image_mem_reqs.size) } + .map_err(|e| anyhow::anyhow!("Failed to import output external memory: {:?}", e))?; + + let image_subresource = vk::ImageSubresource { + aspect_mask: vk::ImageAspectFlags::COLOR, + mip_level: 0, + array_layer: 0, + }; + let actual_layout = + unsafe { device.get_image_subresource_layout(output_image, image_subresource) }; + let row_pitch = actual_layout.row_pitch as usize; + + let output_texture = SharedTexture { + vulkan_memory: output_memory, + vulkan_image: output_image, + vulkan_device: device.clone(), + width, + height, + texture_desc: output_desc.clone(), + pixel_format: output_desc.pixel_format, + row_pitch, + }; + + Ok((output_texture, cuda_external_memory)) + } + + fn create_input_external_memory( + ctx: &CudaContext, + instance: &Instance, + device: &Device, + physical_device: vk::PhysicalDevice, + cuda_array_info: &CudaArrayInfo, + width: u32, + height: u32, + ) -> Result<(SharedTexture, ExternalMemory)> { + let mut ext_mem_image_info = vk::ExternalMemoryImageCreateInfoKHR::default(); + ext_mem_image_info.handle_types = vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32; + + let mut image_create_info = vk::ImageCreateInfo::default(); + image_create_info.p_next = &ext_mem_image_info as *const _ as *const std::ffi::c_void; + image_create_info.image_type = vk::ImageType::TYPE_2D; + image_create_info.format = + pixel_format_to_vulkan_format(&cuda_array_info.texture_desc().pixel_format); + image_create_info.extent = vk::Extent3D { + width, + height, + depth: 1, + }; + image_create_info.mip_levels = 1; + image_create_info.array_layers = 1; + image_create_info.samples = vk::SampleCountFlags::TYPE_1; + image_create_info.tiling = vk::ImageTiling::LINEAR; + image_create_info.usage = vk::ImageUsageFlags::TRANSFER_DST + | vk::ImageUsageFlags::TRANSFER_SRC + | vk::ImageUsageFlags::SAMPLED; + image_create_info.sharing_mode = vk::SharingMode::EXCLUSIVE; + image_create_info.initial_layout = vk::ImageLayout::UNDEFINED; + + let input_image = unsafe { + device + .create_image(&image_create_info, None) + .map_err(|e| anyhow::anyhow!("Failed to create input image: {:?}", e))? + }; + + let image_mem_reqs = unsafe { device.get_image_memory_requirements(input_image) }; + + let memory_type_index = find_memory_type_for_external( + instance, + physical_device, + image_mem_reqs.memory_type_bits, + )?; + + let mut export_mem_info = vk::ExportMemoryAllocateInfo::default(); + export_mem_info.handle_types = vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32; + + let mut alloc_info = vk::MemoryAllocateInfo::default(); + alloc_info.p_next = &export_mem_info as *const _ as *const std::ffi::c_void; + alloc_info.allocation_size = image_mem_reqs.size; + alloc_info.memory_type_index = memory_type_index; + + let input_memory = unsafe { + device + .allocate_memory(&alloc_info, None) + .map_err(|e| anyhow::anyhow!("Failed to allocate input memory: {:?}", e))? + }; + + unsafe { + device + .bind_image_memory(input_image, input_memory, 0) + .map_err(|e| anyhow::anyhow!("Failed to bind input image memory: {:?}", e))?; + } + + let ext_mem_win32 = khr::external_memory_win32::Device::new(instance, device); + let mut handle_info = vk::MemoryGetWin32HandleInfoKHR::default(); + handle_info.memory = input_memory; + handle_info.handle_type = vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32; + + let handle = unsafe { + ext_mem_win32 + .get_memory_win32_handle(&handle_info) + .map_err(|e| anyhow::anyhow!("Failed to get Win32 handle for input: {:?}", e))? + }; + + let file = unsafe { File::from_raw_handle(handle as RawHandle) }; + let cuda_external_memory = + unsafe { import_external_memory_dedicated(ctx, file, image_mem_reqs.size) } + .map_err(|e| anyhow::anyhow!("Failed to import external memory: {:?}", e))?; + + let input_subresource = vk::ImageSubresource { + aspect_mask: vk::ImageAspectFlags::COLOR, + mip_level: 0, + array_layer: 0, + }; + let input_layout = + unsafe { device.get_image_subresource_layout(input_image, input_subresource) }; + let row_pitch = input_layout.row_pitch as usize; + + let input_texture = SharedTexture { + vulkan_memory: input_memory, + vulkan_image: input_image, + vulkan_device: device.clone(), + width, + height, + texture_desc: cuda_array_info.texture_desc(), + pixel_format: cuda_array_info.texture_desc().pixel_format, + row_pitch, + }; + + Ok((input_texture, cuda_external_memory)) + } + + fn update_input_texture_data( + input_textures: Query<(Entity, &SharedTexture, &CudaArray), With>, + cuda_stream: NonSend, + shared_texture_external_memory: NonSend, + ) -> bevy::prelude::Result { + for (entity, input_texture, cuda_array) in input_textures { + let cuda_external_memory = + shared_texture_external_memory.get(&entity).ok_or_else(|| { + anyhow::anyhow!( + "External memory for input texture {:?} not found", + input_texture.vulkan_image + ) + })?; + let device_ptr = cuda_external_memory.map_all_ref().map_err(|e| { + anyhow::anyhow!("Failed to map input external memory for update: {:?}", e) + })?; + + let (width, height, row_pitch) = ( + input_texture.width, + input_texture.height, + input_texture.row_pitch, + ); + + let input_desc = cuda_array.texture_desc(); + let cuda_array = unsafe { cuda_array.cuda_array() }; + + Self::copy_from_array( + cuda_array, + device_ptr, + width, + height, + &input_desc.pixel_format, + row_pitch, + **cuda_stream, + )?; + } + + unsafe { + use cudarc::runtime::sys::*; + let sync_result = cudaStreamSynchronize(**cuda_stream); + if sync_result != cudaError::cudaSuccess { + return Err(anyhow::anyhow!( + "Failed to synchronize CUDA stream after updating input textures: {:?}", + sync_result + ))?; + } + } + + Ok(()) + } + + fn sync_textures( + mut commands: Commands, + input_textures: Query< + (Entity, &SharedTexture, &InputTexture), + (With, Without), + >, + output_textures: Query< + (Entity, &SharedTexture, &OutputTexture), + (With, Without), + >, + render_device: Res, + mut manual_texture_views: ResMut, + ) -> bevy::prelude::Result { + let srgb_view_formats = vec![TextureFormat::Bgra8UnormSrgb]; + let rgba_srgb_view_formats = vec![TextureFormat::Rgba8UnormSrgb]; + let empty_view_formats: Vec = vec![]; + + for (entity, shared_texture, input_tag) in input_textures { + let input_format = shared_texture.pixel_format.clone(); + let wgpu_format = pixel_format_to_wgpu_format(&input_format); + let hal_texture = Self::image_as_hal( + shared_texture.vulkan_image, + shared_texture.width, + shared_texture.height, + wgpu_format, + )?; + let texture_descriptor = TextureDescriptor { + label: Some("input_texture"), + size: Extent3d { + width: shared_texture.width, + height: shared_texture.height, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: TextureDimension::D2, + format: wgpu_format, + usage: TextureUsages::COPY_SRC | TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }; + + let input_texture = unsafe { + render_device + .wgpu_device() + .create_texture_from_hal::( + hal_texture, + &texture_descriptor, + ) + }; + let input_texture_view = + input_texture.create_view(&wgpu::TextureViewDescriptor::default()); + + let handle = ManualTextureViewHandle(input_tag.0 as u32); + manual_texture_views.insert( + handle, + ManualTextureView { + texture_view: input_texture_view.clone().into(), + size: UVec2::new( + texture_descriptor.size.width, + texture_descriptor.size.height, + ), + format: wgpu_format, + }, + ); + + commands.entity(entity).insert(( + WgpuTexture(Texture::from(input_texture)), + WgpuTextureView(TextureView::from(input_texture_view)), + handle, + )); + } + + for (entity, output_texture, output_tag) in output_textures { + let output_format = output_texture.pixel_format.clone(); + let wgpu_format = pixel_format_to_wgpu_format(&output_format); + + let view_formats_slice = match wgpu_format { + TextureFormat::Bgra8Unorm => &srgb_view_formats, + TextureFormat::Rgba8Unorm => &rgba_srgb_view_formats, + _ => &empty_view_formats, + }; + + let hal_texture = Self::image_as_hal( + output_texture.vulkan_image, + output_texture.width, + output_texture.height, + wgpu_format, + )?; + let texture_descriptor = TextureDescriptor { + label: Some("output_texture"), + size: Extent3d { + width: output_texture.width, + height: output_texture.height, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: TextureDimension::D2, + format: wgpu_format, + usage: TextureUsages::COPY_DST | TextureUsages::RENDER_ATTACHMENT, + view_formats: view_formats_slice, + }; + let output_texture = unsafe { + render_device + .wgpu_device() + .create_texture_from_hal::( + hal_texture, + &texture_descriptor, + ) + }; + + let output_view_format = match wgpu_format { + TextureFormat::Bgra8Unorm => TextureFormat::Bgra8UnormSrgb, + TextureFormat::Rgba8Unorm => TextureFormat::Rgba8UnormSrgb, + _ => wgpu_format, + }; + let output_texture_view = output_texture.create_view(&wgpu::TextureViewDescriptor { + label: Some("output_texture_view"), + format: Some(output_view_format), + ..Default::default() + }); + + let handle = ManualTextureViewHandle((output_tag.0 * 10) as u32); + manual_texture_views.insert( + handle, + ManualTextureView { + texture_view: output_texture_view.clone().into(), + size: UVec2::new( + texture_descriptor.size.width, + texture_descriptor.size.height, + ), + format: wgpu_format, + }, + ); + + commands.entity(entity).insert(( + WgpuTexture(Texture::from(output_texture)), + WgpuTextureView(TextureView::from(output_texture_view)), + handle, + )); + } + Ok(()) + } + + fn image_as_hal( + vulkan_image: vk::Image, + width: u32, + height: u32, + format: TextureFormat, + ) -> Result { + use wgpu::hal::TextureUses; + + let hal_desc = wgpu::hal::TextureDescriptor { + label: Some("external_texture"), + size: wgpu::Extent3d { + width, + height, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format, + usage: TextureUses::COLOR_TARGET | TextureUses::RESOURCE, + memory_flags: wgpu::hal::MemoryFlags::empty(), + view_formats: vec![], + }; + + let hal_texture = unsafe { + wgpu::hal::vulkan::Device::texture_from_raw( + vulkan_image, + &hal_desc, + Some(Box::new(|| {})), + ) + }; + + Ok(hal_texture) + } + + fn export_output(world: &mut World) -> bevy::prelude::Result { + let mut outputs = world.query::<(Entity, &CudaArray, &SharedTexture, &OutputTexture)>(); + let cuda_stream = world.non_send_resource::(); + let shared_texture_external_memory = + world.non_send_resource::(); + + let stream = **cuda_stream; + + for (entity, cuda_array, shared_texture, output_tag) in outputs.iter(world) { + let cuda_array = unsafe { cuda_array.cuda_array() }; + + if cuda_array.is_null() { + return Err(anyhow::anyhow!("Output CUDA array is null"))?; + } + + let cuda_external_memory = + shared_texture_external_memory.get(&entity).ok_or_else(|| { + anyhow::anyhow!("External memory for output {} not found", output_tag.0) + })?; + let device_ptr = cuda_external_memory + .map_all_ref() + .map_err(|e| anyhow::anyhow!("Failed to map output external memory: {:?}", e))?; + + Self::copy_to_array( + device_ptr, + cuda_array, + shared_texture.texture_desc.width as u32, + shared_texture.texture_desc.height as u32, + &shared_texture.pixel_format, + shared_texture.row_pitch, + stream, + )?; + } + + if !stream.is_null() { + unsafe { + use cudarc::runtime::sys::*; + let sync_result = cudaStreamSynchronize(stream); + if sync_result == cudaError::cudaSuccess {} + } + } + + Ok(()) + } + + fn update(app: &mut App) { + app.update(); + + let render_device = app.world().resource::(); + render_device.wgpu_device().poll(wgpu::Maintain::Wait); + } + + fn copy_from_array( + cuda_array: *mut cudarc::runtime::sys::cudaArray, + device_ptr: sys::CUdeviceptr, + width: u32, + height: u32, + input_format: &PixelFormat, + vulkan_row_pitch: usize, + stream: cudarc::runtime::sys::cudaStream_t, + ) -> Result<()> { + unsafe { + use cudarc::runtime::sys::*; + + if cuda_array.is_null() { + return Ok(()); + } + + let bytes_per_pixel = get_bytes_per_pixel(input_format); + if bytes_per_pixel == 0 { + return Err(anyhow::anyhow!("Invalid input format: {:?}", input_format)); + } + + let calculated_pitch = width * bytes_per_pixel as u32; + + let width_in_bytes = calculated_pitch; + + let copy_result = cudaMemcpy2DFromArrayAsync( + device_ptr as *mut std::ffi::c_void, + vulkan_row_pitch, + cuda_array as cudaArray_const_t, + 0, + 0, + width_in_bytes as usize, + height as usize, + cudaMemcpyKind::cudaMemcpyDeviceToDevice, + stream, + ); + + if copy_result != cudaError::cudaSuccess { + return Err(anyhow::anyhow!( + "CUDA async input copy failed: {:?}", + copy_result + )); + } + } + + Ok(()) + } + + fn copy_to_array( + device_ptr: sys::CUdeviceptr, + td_cuda_array: *mut cudarc::runtime::sys::cudaArray, + width: u32, + height: u32, + output_format: &PixelFormat, + vulkan_row_pitch: usize, + stream: cudarc::runtime::sys::cudaStream_t, + ) -> Result<()> { + unsafe { + use cudarc::runtime::sys::*; + + if td_cuda_array.is_null() { + return Ok(()); + } + + let bytes_per_pixel = get_bytes_per_pixel(output_format); + if bytes_per_pixel == 0 { + return Err(anyhow::anyhow!( + "Invalid output format: {:?}", + output_format + )); + } + + let calculated_pitch = width * bytes_per_pixel as u32; + let cuda_aligned_pitch = if vulkan_row_pitch % 512 != 0 { + ((vulkan_row_pitch + 511) / 512) * 512 + } else { + vulkan_row_pitch + }; + + let src_pitch = cuda_aligned_pitch; + + let width_in_bytes = calculated_pitch; + + let copy_result = cudaMemcpy2DToArrayAsync( + td_cuda_array as cudaArray_t, + 0, + 0, + device_ptr as *const std::ffi::c_void, + src_pitch, + width_in_bytes as usize, + height as usize, + cudaMemcpyKind::cudaMemcpyDeviceToDevice, + stream, + ); + + if copy_result != cudaError::cudaSuccess { + return Err(anyhow::anyhow!( + "CUDA async output copy failed: {:?}", + copy_result + )); + } + } + + Ok(()) + } + + fn init_bevy_app() -> App { + let mut app = App::new(); + + app.add_plugins( + DefaultPlugins + .set(WindowPlugin { + primary_window: None, + exit_condition: bevy::window::ExitCondition::DontExit, + close_when_requested: false, + }) + ); + + app.init_resource::(); + app.init_non_send_resource::(); + app.add_systems(Startup, setup_scene); + app.add_systems( + First, + ( + Self::import_inputs, + Self::import_outputs, + Self::update_input_texture_data, + Self::sync_textures, + ) + .chain(), + ); + app.add_systems( + Update, + ( + update_camera_target, + update_input_texture, + update_chromatic_aberration_settings, + ), + ); + + let render_app = app.sub_app_mut(RenderApp); + render_app.add_systems(ExtractSchedule, extract_external_textures); + + app.finish(); + app.cleanup(); + + app + } + + fn update_app_settings(params: &BevyTopParams, app: &mut App) { + let mut app_settings = app.world_mut().resource_mut::(); + app_settings.chromatic_aberration_intensity = params.chromatic_aberration_intensity as f32; + } +} + +fn find_memory_type_for_external( + instance: &Instance, + physical_device: vk::PhysicalDevice, + type_filter: u32, +) -> Result { + let mem_properties = unsafe { instance.get_physical_device_memory_properties(physical_device) }; + + for i in 0..mem_properties.memory_type_count { + let memory_type = mem_properties.memory_types[i as usize]; + if (type_filter & (1 << i)) != 0 + && (memory_type.property_flags + & (vk::MemoryPropertyFlags::HOST_VISIBLE + | vk::MemoryPropertyFlags::HOST_COHERENT + | vk::MemoryPropertyFlags::DEVICE_LOCAL)) + == (vk::MemoryPropertyFlags::HOST_VISIBLE + | vk::MemoryPropertyFlags::HOST_COHERENT + | vk::MemoryPropertyFlags::DEVICE_LOCAL) + { + return Ok(i); + } + } + + for i in 0..mem_properties.memory_type_count { + let memory_type = mem_properties.memory_types[i as usize]; + if (type_filter & (1 << i)) != 0 + && (memory_type.property_flags + & (vk::MemoryPropertyFlags::DEVICE_LOCAL | vk::MemoryPropertyFlags::HOST_VISIBLE)) + == (vk::MemoryPropertyFlags::DEVICE_LOCAL | vk::MemoryPropertyFlags::HOST_VISIBLE) + { + return Ok(i); + } + } + + for i in 0..mem_properties.memory_type_count { + let memory_type = mem_properties.memory_types[i as usize]; + if (type_filter & (1 << i)) != 0 + && (memory_type.property_flags & vk::MemoryPropertyFlags::HOST_VISIBLE) + == vk::MemoryPropertyFlags::HOST_VISIBLE + { + return Ok(i); + } + } + + for i in 0..mem_properties.memory_type_count { + if (type_filter & (1 << i)) != 0 { + return Ok(i); + } + } + + Err(anyhow::anyhow!( + "Failed to find suitable memory type for external memory" + )) +} + +unsafe fn import_external_memory_dedicated( + cuda_context: &CudaContext, + file: File, + size: u64, +) -> Result { + cuda_context + .bind_to_thread() + .map_err(|e| anyhow::anyhow!("Failed to bind CUDA context to thread: {:?}", e))?; + + #[cfg(windows)] + let external_memory = unsafe { + let raw_handle = file.as_raw_handle(); + + let mut external_memory = std::mem::MaybeUninit::uninit(); + let handle_description = sys::CUDA_EXTERNAL_MEMORY_HANDLE_DESC { + type_: sys::CUexternalMemoryHandleType::CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32, + handle: sys::CUDA_EXTERNAL_MEMORY_HANDLE_DESC_st__bindgen_ty_1 { + win32: sys::CUDA_EXTERNAL_MEMORY_HANDLE_DESC_st__bindgen_ty_1__bindgen_ty_1 { + handle: raw_handle, + name: std::ptr::null(), + }, + }, + size, + flags: 1, + reserved: [0; 16], + }; + + let result = cudarc::driver::sys::cuImportExternalMemory( + external_memory.as_mut_ptr(), + &handle_description, + ); + if result != cudarc::driver::sys::CUresult::CUDA_SUCCESS { + return Err(anyhow::anyhow!( + "CUDA external memory import failed: {:?}", + result + )); + } + + external_memory.assume_init() + }; + + Ok(ExternalMemory { + external_memory, + size, + _file: ManuallyDrop::new(file), + }) +} + +#[derive(Debug)] +pub struct ExternalMemory { + external_memory: sys::CUexternalMemory, + size: u64, + _file: ManuallyDrop, +} + +impl ExternalMemory { + pub fn map_all(self) -> Result { + let size = self.size as usize; + self.map_range(0..size) + } + + pub fn map_all_ref(&self) -> Result { + let size = self.size as usize; + self.map_range_ref(0..size) + } + + pub fn map_range_ref( + &self, + range: std::ops::Range, + ) -> Result { + assert!(range.start as u64 <= self.size); + assert!(range.end as u64 <= self.size); + + let device_ptr = unsafe { + let buffer_desc = sys::CUDA_EXTERNAL_MEMORY_BUFFER_DESC { + offset: range.start as u64, + size: range.len() as u64, + flags: 0, + reserved: [0; 16], + }; + + let mut device_ptr = std::mem::MaybeUninit::uninit(); + let result = cudarc::driver::sys::cuExternalMemoryGetMappedBuffer( + device_ptr.as_mut_ptr(), + self.external_memory, + &buffer_desc, + ); + + if result != cudarc::driver::sys::CUresult::CUDA_SUCCESS { + return Err(anyhow::anyhow!( + "CUDA external memory mapping failed: {:?}", + result + )); + } + + device_ptr.assume_init() + }; + + Ok(device_ptr) + } + + pub fn map_range(self, range: std::ops::Range) -> Result { + assert!(range.start as u64 <= self.size); + assert!(range.end as u64 <= self.size); + + let device_ptr = unsafe { + let buffer_desc = sys::CUDA_EXTERNAL_MEMORY_BUFFER_DESC { + offset: range.start as u64, + size: range.len() as u64, + flags: 0, + reserved: [0; 16], + }; + + let mut device_ptr = std::mem::MaybeUninit::uninit(); + let result = cudarc::driver::sys::cuExternalMemoryGetMappedBuffer( + device_ptr.as_mut_ptr(), + self.external_memory, + &buffer_desc, + ); + + if result != cudarc::driver::sys::CUresult::CUDA_SUCCESS { + return Err(anyhow::anyhow!( + "CUDA external memory mapping failed: {:?}", + result + )); + } + + device_ptr.assume_init() + }; + + Ok(MappedBuffer { + device_ptr, + len: range.len(), + external_memory: self, + }) + } +} + +impl Drop for ExternalMemory { + fn drop(&mut self) { + unsafe { + cudarc::driver::sys::cuDestroyExternalMemory(self.external_memory); + ManuallyDrop::::drop(&mut self._file); + } + } +} + +#[derive(Debug)] +pub struct MappedBuffer { + pub device_ptr: sys::CUdeviceptr, + pub len: usize, + external_memory: ExternalMemory, +} + +impl Drop for MappedBuffer { + fn drop(&mut self) {} +} + +fn setup_scene( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, + inputs: Query<&InputTextureImage>, +) { + let Some(input_handle) = inputs.iter().next() else { + return; + }; + commands.spawn(( + Mesh3d(meshes.add(Plane3d::default().mesh().size(2.0, 2.0))), + MeshMaterial3d(materials.add(StandardMaterial { + base_color: Color::WHITE, + base_color_texture: Some((**input_handle).clone()), + unlit: true, + ..default() + })), + Transform::from_xyz(0.0, 0.0, 0.0), + InputTexturedQuad, + )); + + commands.spawn(( + Camera3d::default(), + Camera { + clear_color: ClearColorConfig::Custom(Color::BLACK), + ..default() + }, + Transform::from_xyz(0.0, 0.0, 1.0) + .looking_at(Vec3::ZERO, Vec3::Y) + .with_scale(Vec3::new(1.0, -1.0, 1.0)), + ChromaticAberration::default(), + OutputCamera(0), + )); +} + +fn update_camera_target( + mut camera_query: Query<&mut Camera, With>, + output_textures: Query<&ManualTextureViewHandle, With>, +) { + let Some(output_manual_view_handle) = output_textures.iter().next() else { + warn!("No output texture found for camera target update."); + return; + }; + + for mut camera in camera_query.iter_mut() { + camera.target = RenderTarget::TextureView(*output_manual_view_handle); + } +} + +fn update_chromatic_aberration_settings( + mut chromatic_aberration: Query<&mut ChromaticAberration>, + app_settings: Res, +) { + if app_settings.is_changed() { + let intensity = app_settings.chromatic_aberration_intensity; + + // Pick a reasonable maximum sample size for the intensity to avoid an + // artifact whereby the individual samples appear instead of producing + // smooth streaks of color. + let max_samples = ((intensity - 0.02) / (0.20 - 0.02) * 56.0 + 8.0) + .clamp(8.0, 64.0) + .round() as u32; + + for mut chromatic_aberration in &mut chromatic_aberration { + chromatic_aberration.intensity = intensity; + chromatic_aberration.max_samples = max_samples; + } + } +} + +fn update_input_texture( + inputs: Query<&InputTextureImage>, + mut materials: ResMut>, + mut quad_query: Query<&MeshMaterial3d, With>, +) { + let Some(input_handle) = inputs.iter().next() else { + warn!("No input texture found for updating materials."); + return; + }; + + for material_handle in quad_query.iter_mut() { + if let Some(material) = materials.get_mut(&material_handle.0) { + material.base_color_texture = Some((**input_handle).clone()); + } + } +} + +fn extract_external_textures( + inputs: Extract>, + default_sampler: Res, + mut gpu_images: ResMut>, +) { + for (input_handle, input_texture, input_texture_view) in &inputs { + let input_gpu_image = GpuImage { + texture: input_texture.0.clone(), + texture_view: input_texture_view.0.clone(), + texture_format: input_texture.0.format(), + sampler: (**default_sampler).clone(), + size: Extent3d { + width: input_texture.0.size().width, + height: input_texture.0.size().height, + depth_or_array_layers: 1, + }, + mip_level_count: 0, + }; + gpu_images.insert((**input_handle).id(), input_gpu_image); + } +} + +top_plugin!(BevyTop); diff --git a/plugins/top/cpu-memory-top/Cargo.toml b/plugins/top/cpu-memory-top/Cargo.toml index 0508418..b9a92d9 100644 --- a/plugins/top/cpu-memory-top/Cargo.toml +++ b/plugins/top/cpu-memory-top/Cargo.toml @@ -1,16 +1,16 @@ -[package] -name = "cpu-memory-top" -version = "0.1.0" -edition = "2021" - -[package.metadata.td-rs] -type = "top" - -[lib] -name = "cpu_memory_top" -crate-type = ["staticlib"] - -[dependencies] -td-rs-top = { path = "../../../td-rs-top" } -td-rs-derive = { path = "../../../td-rs-derive" } +[package] +name = "cpu-memory-top" +version = "0.1.0" +edition = "2021" + +[package.metadata.td-rs] +type = "top" + +[lib] +name = "cpu_memory_top" +crate-type = ["staticlib"] + +[dependencies] +td-rs-top = { path = "../../../td-rs-top" } +td-rs-derive = { path = "../../../td-rs-derive" } bytemuck = "1.14" \ No newline at end of file diff --git a/plugins/top/cpu-memory-top/src/frame_queue.rs b/plugins/top/cpu-memory-top/src/frame_queue.rs index ecb0bc4..7220c8b 100644 --- a/plugins/top/cpu-memory-top/src/frame_queue.rs +++ b/plugins/top/cpu-memory-top/src/frame_queue.rs @@ -1,61 +1,61 @@ -use std::collections::VecDeque; -use std::sync::{Arc, Mutex}; -use td_rs_top::{TopBuffer, TopBufferFlags, TopContext, UploadInfo}; - -pub struct BufferInfo { - pub buf: Option, - pub upload_info: UploadInfo, -} - -pub struct FrameQueue { - context: Arc>, - updated_buffers: Mutex>, -} - -impl FrameQueue { - pub fn new(context: Arc>) -> Self { - Self { - context, - updated_buffers: Mutex::new(VecDeque::new()), - } - } - - pub fn get_buffer_to_update( - &mut self, - byte_size: usize, - flags: TopBufferFlags, - ) -> Option { - let mut buffers = self.updated_buffers.lock().unwrap(); - - const MAX_QUEUE_SIZE: usize = 2; - - // If we've already reached the max queue size, replace the oldest buffer - if buffers.len() >= MAX_QUEUE_SIZE { - let old_buf = buffers.pop_front()?.buf; - - if let Some(b) = &old_buf { - if b.size() < byte_size || b.size() > byte_size * 2 || b.flags() != flags { - let mut ctx = self.context.lock().unwrap(); - return Some(ctx.create_output_buffer(byte_size, flags)); - } - return old_buf; - } - } - let mut ctx = self.context.lock().unwrap(); - Some(ctx.create_output_buffer(byte_size, flags)) - } - - pub fn update_complete(&self, buf_info: BufferInfo) { - let mut buffers = self.updated_buffers.lock().unwrap(); - buffers.push_back(buf_info); - } - - pub fn update_cancelled(&self, buf: Arc) { - drop(buf); - } - - pub fn get_buffer_to_upload(&self) -> Option { - let mut buffers = self.updated_buffers.lock().unwrap(); - buffers.pop_front() - } -} +use std::collections::VecDeque; +use std::sync::{Arc, Mutex}; +use td_rs_top::{TopBuffer, TopBufferFlags, TopContext, UploadInfo}; + +pub struct BufferInfo { + pub buf: Option, + pub upload_info: UploadInfo, +} + +pub struct FrameQueue { + context: Arc>, + updated_buffers: Mutex>, +} + +impl FrameQueue { + pub fn new(context: Arc>) -> Self { + Self { + context, + updated_buffers: Mutex::new(VecDeque::new()), + } + } + + pub fn get_buffer_to_update( + &mut self, + byte_size: usize, + flags: TopBufferFlags, + ) -> Option { + let mut buffers = self.updated_buffers.lock().unwrap(); + + const MAX_QUEUE_SIZE: usize = 2; + + // If we've already reached the max queue size, replace the oldest buffer + if buffers.len() >= MAX_QUEUE_SIZE { + let old_buf = buffers.pop_front()?.buf; + + if let Some(b) = &old_buf { + if b.size() < byte_size || b.size() > byte_size * 2 || b.flags() != flags { + let mut ctx = self.context.lock().unwrap(); + return Some(ctx.create_output_buffer(byte_size, flags)); + } + return old_buf; + } + } + let mut ctx = self.context.lock().unwrap(); + Some(ctx.create_output_buffer(byte_size, flags)) + } + + pub fn update_complete(&self, buf_info: BufferInfo) { + let mut buffers = self.updated_buffers.lock().unwrap(); + buffers.push_back(buf_info); + } + + pub fn update_cancelled(&self, buf: Arc) { + drop(buf); + } + + pub fn get_buffer_to_upload(&self) -> Option { + let mut buffers = self.updated_buffers.lock().unwrap(); + buffers.pop_front() + } +} diff --git a/plugins/top/cpu-memory-top/src/lib.rs b/plugins/top/cpu-memory-top/src/lib.rs index 68f5118..50954ac 100644 --- a/plugins/top/cpu-memory-top/src/lib.rs +++ b/plugins/top/cpu-memory-top/src/lib.rs @@ -1,189 +1,189 @@ -mod frame_queue; - -use crate::frame_queue::FrameQueue; -use std::sync::{Arc, Mutex}; -use td_rs_derive::Params; -use td_rs_top::*; - -#[derive(Params, Default, Clone, Debug)] -struct CpuMemoryTopParams { - #[param(label = "Brightness", min = 0.0, max = 1.0)] - brightness: f64, - #[param(label = "Speed", min = -10.0, max = 10.0, default = 1.0)] - speed: f64, - #[param(label = "Reset")] - reset: Pulse, -} - -/// Struct representing our SOP's state -pub struct CpuMemoryTop { - execute_count: u32, - step: f64, - params: CpuMemoryTopParams, - pub ctx: Arc>, - pub frame_queue: FrameQueue, - previous_result: Option, -} - -impl CpuMemoryTop { - fn fill_buffer( - buf: &mut TopBuffer, - byte_offset: usize, - width: usize, - height: usize, - step: f64, - brightness: f64, - ) { - let required_size = byte_offset + width * height * 4 * std::mem::size_of::(); - assert!(buf.size() >= required_size); - - let byte_slice: &mut [f32] = &mut buf.data_mut()[byte_offset..]; - let mem: &mut [f32] = bytemuck::cast_slice_mut(byte_slice); - - let xstep = - ((step as isize).wrapping_rem(width as isize)).rem_euclid(width as isize) as usize; - let ystep = - ((step as isize).wrapping_rem(height as isize)).rem_euclid(height as isize) as usize; - - for y in 0..height { - for x in 0..width { - let pixel = &mut mem[4 * (y * width + x)..4 * (y * width + x + 1)]; - - // RGBA - pixel[0] = if x > xstep { brightness as f32 } else { 0.0 }; - pixel[1] = if y > ystep { brightness as f32 } else { 0.0 }; - pixel[2] = ((xstep % 50) as f32 / 50.0) * brightness as f32; - pixel[3] = 1.0; - } - } - } - - fn fill_and_upload( - &mut self, - output: &mut TopOutput, - speed: f64, - width: usize, - height: usize, - tex_dim: TexDim, - mut num_layers: usize, - color_buffer_index: usize, - ) { - let depth = match tex_dim { - TexDim::E2DArray | TexDim::E3D => num_layers, - _ => 1, - }; - - if tex_dim == TexDim::ECube { - num_layers = 6; - }; - let info = UploadInfo { - buffer_offset: 0, - texture_desc: TextureDesc { - tex_dim, - width, - height, - pixel_format: PixelFormat::RGBA32Float, - aspect_x: 0.0, - depth, - aspect_y: 0.0, - }, - first_pixel: Default::default(), - color_buffer_index, - }; - - let layer_bytes = - (info.texture_desc.width * info.texture_desc.height * 4 * std::mem::size_of::()) - as u64; - let byte_size = layer_bytes * num_layers as u64; - let mut ctx = self.ctx.lock().unwrap(); - let mut buf = ctx.create_output_buffer(byte_size as usize, TopBufferFlags::None); - - let mut byte_offset = 0; - for _ in 0..num_layers { - self.step += speed; - Self::fill_buffer( - &mut buf, - byte_offset as usize, - info.texture_desc.width, - info.texture_desc.height, - self.step, - self.params.brightness, - ); - byte_offset += layer_bytes; - } - - output.upload_buffer(&mut buf, &info); - } -} - -impl TopNew for CpuMemoryTop { - fn new(_info: NodeInfo, context: TopContext) -> Self { - let ctx = Arc::new(Mutex::new(context)); - Self { - frame_queue: FrameQueue::new(ctx.clone()), - execute_count: 0, - ctx, - params: CpuMemoryTopParams::default(), - step: 0.0, - previous_result: None, - } - } -} - -impl OpInfo for CpuMemoryTop { - const OPERATOR_LABEL: &'static str = "CPU Mem Sample"; - const OPERATOR_TYPE: &'static str = "Cpumemsample"; - const OPERATOR_ICON: &'static str = "CPM"; - const MAX_INPUTS: usize = 1; - const MIN_INPUTS: usize = 0; -} - -impl TopInfo for CpuMemoryTop { - const EXECUTE_MODE: ExecuteMode = ExecuteMode::Cpu; -} - -impl Op for CpuMemoryTop { - fn params_mut(&mut self) -> Option> { - Some(Box::new(&mut self.params)) - } - - fn pulse_pressed(&mut self, name: &str) { - if name == "Reset" { - self.step = 0.0; - } - } -} - -impl Top for CpuMemoryTop { - fn execute(&mut self, mut output: TopOutput, input: &OperatorInputs) { - self.execute_count += 1; - - if let Some(buf_info) = self.frame_queue.get_buffer_to_upload() { - if let Some(mut buf) = buf_info.buf { - output.upload_buffer(&mut buf, &buf_info.upload_info) - } - } - - self.fill_and_upload(&mut output, self.params.speed, 256, 256, TexDim::E2D, 1, 0); - - if let Some(input) = input.input(0) { - let download_opts = DownloadOptions::default(); - let res = input.download_texture(download_opts); - if let Some(prev) = &mut self.previous_result { - let upload_info = UploadInfo { - color_buffer_index: 3, - texture_desc: prev.texture_desc(), - ..Default::default() - }; - let mut ctx = self.ctx.lock().unwrap(); - let mut buf = ctx.create_output_buffer(prev.size(), TopBufferFlags::None); - buf.data_mut::().copy_from_slice(prev.data()); - output.upload_buffer(&mut buf, &upload_info); - } - - self.previous_result = Some(res); - } - } -} - -top_plugin!(CpuMemoryTop); +mod frame_queue; + +use crate::frame_queue::FrameQueue; +use std::sync::{Arc, Mutex}; +use td_rs_derive::Params; +use td_rs_top::*; + +#[derive(Params, Default, Clone, Debug)] +struct CpuMemoryTopParams { + #[param(label = "Brightness", min = 0.0, max = 1.0)] + brightness: f64, + #[param(label = "Speed", min = -10.0, max = 10.0, default = 1.0)] + speed: f64, + #[param(label = "Reset")] + reset: Pulse, +} + +/// Struct representing our SOP's state +pub struct CpuMemoryTop { + execute_count: u32, + step: f64, + params: CpuMemoryTopParams, + pub ctx: Arc>, + pub frame_queue: FrameQueue, + previous_result: Option, +} + +impl CpuMemoryTop { + fn fill_buffer( + buf: &mut TopBuffer, + byte_offset: usize, + width: usize, + height: usize, + step: f64, + brightness: f64, + ) { + let required_size = byte_offset + width * height * 4 * std::mem::size_of::(); + assert!(buf.size() >= required_size); + + let byte_slice: &mut [f32] = &mut buf.data_mut()[byte_offset..]; + let mem: &mut [f32] = bytemuck::cast_slice_mut(byte_slice); + + let xstep = + ((step as isize).wrapping_rem(width as isize)).rem_euclid(width as isize) as usize; + let ystep = + ((step as isize).wrapping_rem(height as isize)).rem_euclid(height as isize) as usize; + + for y in 0..height { + for x in 0..width { + let pixel = &mut mem[4 * (y * width + x)..4 * (y * width + x + 1)]; + + // RGBA + pixel[0] = if x > xstep { brightness as f32 } else { 0.0 }; + pixel[1] = if y > ystep { brightness as f32 } else { 0.0 }; + pixel[2] = ((xstep % 50) as f32 / 50.0) * brightness as f32; + pixel[3] = 1.0; + } + } + } + + fn fill_and_upload( + &mut self, + output: &mut TopOutput, + speed: f64, + width: usize, + height: usize, + tex_dim: TexDim, + mut num_layers: usize, + color_buffer_index: usize, + ) { + let depth = match tex_dim { + TexDim::E2DArray | TexDim::E3D => num_layers, + _ => 1, + }; + + if tex_dim == TexDim::ECube { + num_layers = 6; + }; + let info = UploadInfo { + buffer_offset: 0, + texture_desc: TextureDesc { + tex_dim, + width, + height, + pixel_format: PixelFormat::RGBA32Float, + aspect_x: 0.0, + depth, + aspect_y: 0.0, + }, + first_pixel: Default::default(), + color_buffer_index, + }; + + let layer_bytes = + (info.texture_desc.width * info.texture_desc.height * 4 * std::mem::size_of::()) + as u64; + let byte_size = layer_bytes * num_layers as u64; + let mut ctx = self.ctx.lock().unwrap(); + let mut buf = ctx.create_output_buffer(byte_size as usize, TopBufferFlags::None); + + let mut byte_offset = 0; + for _ in 0..num_layers { + self.step += speed; + Self::fill_buffer( + &mut buf, + byte_offset as usize, + info.texture_desc.width, + info.texture_desc.height, + self.step, + self.params.brightness, + ); + byte_offset += layer_bytes; + } + + output.upload_buffer(&mut buf, &info); + } +} + +impl TopNew for CpuMemoryTop { + fn new(_info: NodeInfo, context: TopContext) -> Self { + let ctx = Arc::new(Mutex::new(context)); + Self { + frame_queue: FrameQueue::new(ctx.clone()), + execute_count: 0, + ctx, + params: CpuMemoryTopParams::default(), + step: 0.0, + previous_result: None, + } + } +} + +impl OpInfo for CpuMemoryTop { + const OPERATOR_LABEL: &'static str = "CPU Mem Sample"; + const OPERATOR_TYPE: &'static str = "Cpumemsample"; + const OPERATOR_ICON: &'static str = "CPM"; + const MAX_INPUTS: usize = 1; + const MIN_INPUTS: usize = 0; +} + +impl TopInfo for CpuMemoryTop { + const EXECUTE_MODE: ExecuteMode = ExecuteMode::Cpu; +} + +impl Op for CpuMemoryTop { + fn params_mut(&mut self) -> Option> { + Some(Box::new(&mut self.params)) + } + + fn pulse_pressed(&mut self, name: &str) { + if name == "Reset" { + self.step = 0.0; + } + } +} + +impl Top for CpuMemoryTop { + fn execute(&mut self, mut output: TopOutput, input: &OperatorInputs) { + self.execute_count += 1; + + if let Some(buf_info) = self.frame_queue.get_buffer_to_upload() { + if let Some(mut buf) = buf_info.buf { + output.upload_buffer(&mut buf, &buf_info.upload_info) + } + } + + self.fill_and_upload(&mut output, self.params.speed, 256, 256, TexDim::E2D, 1, 0); + + if let Some(input) = input.input(0) { + let download_opts = DownloadOptions::default(); + let res = input.download_texture(download_opts); + if let Some(prev) = &mut self.previous_result { + let upload_info = UploadInfo { + color_buffer_index: 3, + texture_desc: prev.texture_desc(), + ..Default::default() + }; + let mut ctx = self.ctx.lock().unwrap(); + let mut buf = ctx.create_output_buffer(prev.size(), TopBufferFlags::None); + buf.data_mut::().copy_from_slice(prev.data()); + output.upload_buffer(&mut buf, &upload_info); + } + + self.previous_result = Some(res); + } + } +} + +top_plugin!(CpuMemoryTop); diff --git a/plugins/top/cuda/Cargo.toml b/plugins/top/cuda/Cargo.toml new file mode 100644 index 0000000..38e39bd --- /dev/null +++ b/plugins/top/cuda/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "cuda" +version = "0.1.0" +edition = "2024" + +[package.metadata.td-rs] +type = "top" + +[lib] +name = "cuda" +crate-type = ["staticlib"] + +[dependencies] +td-rs-top = { path = "../../../td-rs-top", features = ["cuda"] } +td-rs-derive = { path = "../../../td-rs-derive" } +cudarc = { version = "0.16.4", features = ["runtime", "nvrtc", "driver", "cuda-12080", "dynamic-linking"], default-features = false } +anyhow = "1.0" \ No newline at end of file diff --git a/plugins/top/cuda/src/lib.rs b/plugins/top/cuda/src/lib.rs new file mode 100644 index 0000000..cf752d3 --- /dev/null +++ b/plugins/top/cuda/src/lib.rs @@ -0,0 +1,273 @@ +use cudarc::runtime::sys::{cudaError::cudaSuccess, cudaStream_t, cudaSurfaceObject_t}; +use std::sync::{Arc, Mutex}; +use td_rs_derive::Params; +use td_rs_top::*; + +#[derive(Params, Default, Clone, Debug)] +struct CudaExampleParams { + #[param(label = "Brightness", min = 0.0, max = 1.0, default = 1.0)] + brightness: f64, + #[param(label = "Speed", min = -10.0, max = 10.0, default = 1.0)] + speed: f64, + #[param(label = "Reset")] + reset: Pulse, +} + +pub struct CudaExample { + execute_count: u32, + params: CudaExampleParams, + + stream: Option, + surface_cache: td_rs_top::cuda::SurfaceCache, + context: Arc>, +} + +impl TopNew for CudaExample { + fn new(_info: NodeInfo, context: TopContext) -> Self { + Self { + execute_count: 0, + params: CudaExampleParams::default(), + stream: None, + surface_cache: td_rs_top::cuda::SurfaceCache::new(), + context: Arc::new(Mutex::new(context)), + } + } +} + +impl OpInfo for CudaExample { + const OPERATOR_LABEL: &'static str = "CUDA Example"; + const OPERATOR_TYPE: &'static str = "Cudaexample"; + const OPERATOR_ICON: &'static str = "CDA"; + const MIN_INPUTS: usize = 0; + const MAX_INPUTS: usize = 1; +} + +impl TopInfo for CudaExample { + const EXECUTE_MODE: ExecuteMode = ExecuteMode::Cuda; +} + +impl Op for CudaExample { + fn params_mut(&mut self) -> Option> { + Some(Box::new(&mut self.params)) + } + + fn pulse_pressed(&mut self, name: &str) { + match name { + "Reset" => { + self.execute_count = 0; + } + _ => {} + } + } +} + +impl Top for CudaExample { + fn general_info(&self, _input: &OperatorInputs) -> TopGeneralInfo { + TopGeneralInfo { + cook_every_frame_if_asked: true, + ..Default::default() + } + } + + fn execute(&mut self, mut output: TopOutput, input: &OperatorInputs) { + self.execute_count += 1; + + if let Err(e) = self.execute_cuda(&mut output, input) { + eprintln!("CUDA execution failed: {}", e); + } + } +} + +impl CudaExample { + fn execute_cuda( + &mut self, + output: &mut TopOutput, + _input: &OperatorInputs, + ) -> Result<(), anyhow::Error> { + use td_rs_top::cuda::CudaOutputInfo; + + let brightness = self.params.brightness as f32; + let speed = self.params.speed as f32; + let time = self.execute_count as f32 * speed * 0.01; + + let cuda_info = CudaOutputInfo { + stream: std::ptr::null_mut(), + texture_desc: td_rs_top::TextureDesc { + width: 512, + height: 512, + depth: 1, + tex_dim: td_rs_top::TexDim::E2D, + pixel_format: td_rs_top::PixelFormat::BGRA8Fixed, + aspect_x: 0.0, + aspect_y: 0.0, + }, + color_buffer_index: 0, + }; + + let array_info = output.create_cuda_array(&cuda_info)?; + + let began_successfully = { + let mut ctx = self.context.lock().unwrap(); + ctx.begin_cuda_operations() + }; + + if !began_successfully { + return Err(anyhow::anyhow!("Failed to begin CUDA operations")); + } + + if self.stream.is_none() { + let mut stream = std::ptr::null_mut(); + unsafe { + let result = cudarc::runtime::sys::cudaStreamCreate(&mut stream); + if result != cudaSuccess { + self.context.lock().unwrap().end_cuda_operations(); + return Err(anyhow::anyhow!( + "Failed to create CUDA stream: {:?}", + result + )); + } + } + self.stream = Some(stream); + } + + let cuda_array = unsafe { array_info.cuda_array() }; + + let mut surface_obj = 0; + unsafe { + use cudarc::runtime::sys::*; + + let mut res_desc: cudaResourceDesc = std::mem::zeroed(); + res_desc.resType = cudarc::runtime::sys::cudaResourceType::cudaResourceTypeArray; + res_desc.res.array.array = cuda_array as cudaArray_t; + + let result = cudaCreateSurfaceObject(&mut surface_obj, &res_desc); + if result != cudaSuccess { + self.context.lock().unwrap().end_cuda_operations(); + return Err(anyhow::anyhow!( + "Failed to create surface object: {:?}", + result + )); + } + } + + self.execute_pattern_kernel(surface_obj, 512, 512, brightness, time)?; + + unsafe { + cudarc::runtime::sys::cudaDestroySurfaceObject(surface_obj); + } + + self.context.lock().unwrap().end_cuda_operations(); + + Ok(()) + } + + fn execute_pattern_kernel( + &self, + surface: cudaSurfaceObject_t, + width: u32, + height: u32, + brightness: f32, + time: f32, + ) -> Result<(), anyhow::Error> { + let kernel_src = r#" +extern "C" __global__ void pattern_kernel( + cudaSurfaceObject_t surface, + unsigned int width, + unsigned int height, + float brightness, + float time +) { + unsigned int x = blockIdx.x * blockDim.x + threadIdx.x; + unsigned int y = blockIdx.y * blockDim.y + threadIdx.y; + + if (x >= width || y >= height) return; + + + float fx = (float)x / width; + float fy = (float)y / height; + + + float wave1 = sinf((fx * 10.0f + time) * 3.14159f * 2.0f) * 0.5f + 0.5f; + float wave2 = cosf((fy * 8.0f + time * 0.7f) * 3.14159f * 2.0f) * 0.5f + 0.5f; + float pattern = wave1 * wave2 * brightness; + + + uchar4 color = make_uchar4( + (unsigned char)(pattern * 100.0f), + (unsigned char)(pattern * 150.0f), + (unsigned char)(pattern * 255.0f), + 255 + ); + + + surf2Dwrite(color, surface, x * sizeof(uchar4), y); +} +"#; + + use cudarc::driver::CudaContext; + use cudarc::nvrtc::compile_ptx; + + let ptx = compile_ptx(kernel_src) + .map_err(|e| anyhow::anyhow!("Failed to compile CUDA kernel: {:?}", e))?; + + let ctx = CudaContext::new(0) + .map_err(|e| anyhow::anyhow!("Failed to create CUDA context: {:?}", e))?; + + let module = ctx + .load_module(ptx) + .map_err(|e| anyhow::anyhow!("Failed to load CUDA module: {:?}", e))?; + + let kernel = module + .load_function("pattern_kernel") + .map_err(|e| anyhow::anyhow!("Failed to load kernel function: {:?}", e))?; + + let block_size = (16, 16, 1); + let grid_size = ( + (width + block_size.0 - 1) / block_size.0, + (height + block_size.1 - 1) / block_size.1, + 1, + ); + + let stream = ctx.default_stream(); + + unsafe { + use cudarc::driver::{LaunchConfig, PushKernelArg}; + + let config = LaunchConfig { + grid_dim: grid_size, + block_dim: block_size, + shared_mem_bytes: 0, + }; + + stream + .launch_builder(&kernel) + .arg(&surface) + .arg(&width) + .arg(&height) + .arg(&brightness) + .arg(&time) + .launch(config) + .map_err(|e| anyhow::anyhow!("Failed to launch kernel: {:?}", e))?; + } + + stream + .synchronize() + .map_err(|e| anyhow::anyhow!("Failed to synchronize stream: {:?}", e))?; + + Ok(()) + } +} + +impl Drop for CudaExample { + fn drop(&mut self) { + if let Some(stream) = self.stream { + if !stream.is_null() { + unsafe { + cudarc::runtime::sys::cudaStreamDestroy(stream); + } + } + } + } +} + +top_plugin!(CudaExample); diff --git a/plugins/top/stable-diffusion/Cargo.toml b/plugins/top/stable-diffusion/Cargo.toml deleted file mode 100644 index e9243a2..0000000 --- a/plugins/top/stable-diffusion/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "stable-diffusion" -version = "0.1.0" -edition = "2021" - -[package.metadata.td-rs] -type = "top" - -[lib] -name = "stable_diffusion" -crate-type = ["staticlib"] - - -[dependencies] -td-rs-top = { path = "../../../td-rs-top" } -td-rs-derive = { path = "../../../td-rs-derive" } -stablediffusion = { git = "https://github.com/tychedelia/stable-diffusion-burn.git", version = "0.2.0" } -burn = "0.10" -burn-ndarray = "0.10" -burn-tch = "0.10" -burn-autodiff = "0.10" -tch = "0.14.0" \ No newline at end of file diff --git a/plugins/top/stable-diffusion/src/lib.rs b/plugins/top/stable-diffusion/src/lib.rs deleted file mode 100644 index f355d02..0000000 --- a/plugins/top/stable-diffusion/src/lib.rs +++ /dev/null @@ -1,263 +0,0 @@ -use burn::module::Module; -use burn::record; -use burn::record::{BinFileRecorder, FullPrecisionSettings, Recorder}; -use burn::tensor::backend::Backend; -use burn_tch::{TchBackend, TchDevice}; -use stablediffusion::model::stablediffusion::{StableDiffusion, StableDiffusionConfig}; -use stablediffusion::tokenizer::SimpleTokenizer; -use std::fmt::format; -use std::path::PathBuf; -use std::sync::atomic::AtomicBool; -use std::sync::mpsc::{Receiver, SyncSender, TryRecvError, TrySendError}; -use std::sync::{Arc, Mutex, MutexGuard, RwLock}; -use std::thread::JoinHandle; -use td_rs_derive::Params; -use td_rs_top::*; - -const WIDTH: usize = 512; -const HEIGHT: usize = 512; - -#[derive(Params, Default, Clone, Debug)] -struct StableDiffusionTopParams { - #[param(label = "Reset")] - reset: Pulse, - #[param(label = "Prompt")] - prompt: String, - #[param(label = "Model")] - model: FileParam, -} - -/// Struct representing our SOP's state -pub struct StableDiffusionTop { - params: StableDiffusionTopParams, - execute_count: u32, - context: TopContext, - sd_producer: StableDiffusionProducer, - init: bool, - prompt: String, -} - -impl TopNew for StableDiffusionTop { - fn new(_info: NodeInfo, context: TopContext) -> Self { - Self { - params: Default::default(), - execute_count: 0, - context, - sd_producer: StableDiffusionProducer::new(), - init: false, - prompt: "".to_string(), - } - } -} - -impl OpInfo for StableDiffusionTop { - const OPERATOR_LABEL: &'static str = "Stable Diffusion"; - const OPERATOR_TYPE: &'static str = "Stablediffusion"; - const MAX_INPUTS: usize = 0; - const MIN_INPUTS: usize = 0; -} - -impl TopInfo for StableDiffusionTop { - const EXECUTE_MODE: ExecuteMode = ExecuteMode::Cpu; -} - -impl Op for StableDiffusionTop { - fn params_mut(&mut self) -> Option> { - Some(Box::new(&mut self.params)) - } - - fn pulse_pressed(&mut self, name: &str) { - if name == "Reset" {} - } -} - -impl Top for StableDiffusionTop { - fn general_info(&self, _input: &OperatorInputs) -> TopGeneralInfo { - TopGeneralInfo { - cook_every_frame: false, - cook_every_frame_if_asked: true, - input_size_index: 0, - } - } - - fn execute(&mut self, mut output: TopOutput, input: &OperatorInputs) { - if !self.params.model.exists() && !self.params.model.is_file() { - self.set_warning("A model must be loaded!"); - return; - } - self.set_warning(""); - - if self.prompt != self.params.prompt { - self.sd_producer.set_prompt(&self.params.prompt); - self.prompt = self.params.prompt.clone(); - } - if !self.init { - self.sd_producer.init_model(&self.params.model); - self.init = true; - } - - if let Some(image) = self.sd_producer.get_image() { - let mut buf = self - .context - .create_output_buffer(image.len(), TopBufferFlags::None); - buf.data_mut().copy_from_slice(image.as_slice()); - - let info = UploadInfo { - buffer_offset: 0, - texture_desc: TextureDesc { - tex_dim: TexDim::E2D, - width: WIDTH, - height: HEIGHT, - pixel_format: PixelFormat::BGRA8Fixed, - aspect_x: 0.0, - depth: 1, - aspect_y: 0.0, - }, - first_pixel: FirstPixel::TopLeft, - color_buffer_index: 0, - }; - output.upload_buffer(&mut buf, &info); - } - } -} - -struct StableDiffusionProducer { - sd: Arc>>>>, - prompt: Arc>, - produce_loop: JoinHandle<()>, - rx: Receiver>, - trigger_tx: SyncSender<()>, -} - -impl StableDiffusionProducer { - fn new() -> Self { - let (tx, rx) = std::sync::mpsc::sync_channel(3); - let (trigger_tx, trigger_rx) = std::sync::mpsc::sync_channel(1); - let tokenizer = SimpleTokenizer::new().unwrap(); - let sd = Arc::new(RwLock::new(None::>>)); - let prompt = Arc::new(RwLock::new(String::new())); - let produce_loop_sd = sd.clone(); - let produce_loop_prompt = prompt.clone(); - let produce_loop = Self::produce_loop( - tx, - trigger_rx, - tokenizer, - produce_loop_sd, - produce_loop_prompt, - ); - - StableDiffusionProducer { - sd, - rx, - trigger_tx, - prompt, - produce_loop, - } - } - - fn produce_loop( - tx: SyncSender>, - trigger_rx: Receiver<()>, - tokenizer: SimpleTokenizer, - produce_loop_sd: Arc>>>>, - produce_loop_prompt: Arc>, - ) -> JoinHandle<()> { - let produce_loop = std::thread::spawn(move || { - loop { - // Wait for a frame to be requested - let _ = trigger_rx.recv().unwrap(); - - let sd = produce_loop_sd.read().unwrap(); - match sd.as_ref() { - None => {} - Some(sd) => { - let device = TchDevice::Cuda(0); - let sd = sd.clone(); - let sd = sd.to_device(&device); - let unconditional_context = sd.unconditional_context(&tokenizer); - let unconditional_guidance_scale: f64 = 7.5; - let n_steps: usize = 20; - - let prompt = produce_loop_prompt.read().unwrap(); - let context = sd.context(&tokenizer, &prompt).unsqueeze::<3>(); //.repeat(0, 2); // generate 2 samples - let images = sd.sample_image( - context, - unconditional_context, - unconditional_guidance_scale, - n_steps, - ); - - let image = &images[0]; - let layer_bytes = (WIDTH * HEIGHT * 4 * std::mem::size_of::()) as u64; - let mut pixels = Vec::with_capacity(layer_bytes as usize); - - for chunk in image.chunks(3) { - pixels.push(chunk[2]); // Blue - pixels.push(chunk[1]); // Green - pixels.push(chunk[0]); // Red - pixels.push(255); // Alpha (full opacity) - } - - tx.send(pixels).unwrap(); - } - } - } - }); - produce_loop - } - - fn init_model(&mut self, model_file: &PathBuf) { - let self_sd = self.sd.clone(); - let model_file = model_file.clone(); - // Load the model in a separate thread - std::thread::spawn(move || { - let sd = Self::load_stable_diffusion_model_file(&model_file).unwrap(); - *self_sd.write().unwrap() = Some(sd); - }); - return; - } - - fn set_prompt(&mut self, p: &str) { - let mut prompt = self.prompt.write().unwrap(); - *prompt = p.to_string(); - } - - fn get_image(&self) -> Option> { - match self.trigger_tx.try_send(()) { - Ok(_) => {} - Err(err) => { - match err { - TrySendError::Full(_) => { - // would block, so just return - } - TrySendError::Disconnected(_) => { - panic!("Stable Diffusion Producer thread disconnected!") - } - } - } - }; - - match self.rx.try_recv() { - Ok(img) => { - return Some(img); - } - Err(err) => match err { - TryRecvError::Empty => {} - TryRecvError::Disconnected => { - panic!("Stable Diffusion Producer thread disconnected!") - } - }, - }; - - None - } - fn load_stable_diffusion_model_file( - filename: &PathBuf, - ) -> Result, record::RecorderError> { - BinFileRecorder::::new() - .load(filename.into()) - .map(|record| StableDiffusionConfig::new().init().load_record(record)) - } -} - -top_plugin!(StableDiffusionTop); diff --git a/plugins/top/stylegan-http/Cargo.toml b/plugins/top/stylegan-http/Cargo.toml index 8a93826..96233b2 100644 --- a/plugins/top/stylegan-http/Cargo.toml +++ b/plugins/top/stylegan-http/Cargo.toml @@ -1,22 +1,22 @@ -[package] -name = "stylegan-http" -version = "0.1.0" -edition = "2021" - -[package.metadata.td-rs] -type = "top" - -[lib] -name = "stylegan_http" -crate-type = ["staticlib"] - - -[dependencies] -td-rs-top = { path = "../../../td-rs-top", features = ["tokio"] } -td-rs-derive = { path = "../../../td-rs-derive" } -tokio = "1" -reqwest = { version = "0.11", default-features = false } -futures = "0.3" -anyhow = "1" -tracing = "0.1" +[package] +name = "stylegan-http" +version = "0.1.0" +edition = "2021" + +[package.metadata.td-rs] +type = "top" + +[lib] +name = "stylegan_http" +crate-type = ["staticlib"] + + +[dependencies] +td-rs-top = { path = "../../../td-rs-top", features = ["tokio"] } +td-rs-derive = { path = "../../../td-rs-derive" } +tokio = "1" +reqwest = { version = "0.11", default-features = false } +futures = "0.3" +anyhow = "1" +tracing = "0.1" tracing-subscriber = "0.3" \ No newline at end of file diff --git a/plugins/top/stylegan-http/src/lib.rs b/plugins/top/stylegan-http/src/lib.rs index df9a4d2..4af77e7 100644 --- a/plugins/top/stylegan-http/src/lib.rs +++ b/plugins/top/stylegan-http/src/lib.rs @@ -1,265 +1,265 @@ -use futures::task::noop_waker_ref; -use std::collections::VecDeque; -use std::future; -use std::future::Future; -use std::pin::{pin, Pin}; -use std::sync::Arc; -use std::task::Poll; -use td_rs_derive::Params; -use td_rs_top::*; -use tokio::task::JoinHandle; -use tracing::{error, info}; - -const WIDTH: usize = 1024; -const HEIGHT: usize = 1024; -const MAX_TASKS: usize = 10; - -#[derive(Params, Default, Clone, Debug)] -struct StyleganHttpTopParams { - #[param(label = "Ip Address", page = "Config", default = "localhost")] - ip: String, - #[param(label = "Port", page = "Config", default = 5000)] - port: u16, - #[param(label = "Seed", page = "Stylegan")] - seed: u16, - #[param(label = "Blocing", page = "Config")] - blocking: bool, - #[param( - label = "X Feature", - page = "Stylegan", - min = 0.0, - max = 512.0, - clamp = true - )] - x_feature: u32, - #[param( - label = "X Range", - page = "Stylegan", - min = 0.0, - max = 512.0, - clamp = true - )] - x_range: f32, - #[param( - label = "Y Feature", - page = "Stylegan", - min = 0.0, - max = 512.0, - clamp = true - )] - y_feature: u32, - #[param( - label = "Y Range", - page = "Stylegan", - min = 0.0, - max = 512.0, - clamp = true - )] - y_range: f32, - #[param( - label = "Z Feature", - page = "Stylegan", - min = 0.0, - max = 512.0, - clamp = true - )] - z_feature: u32, - #[param( - label = "Z Range", - page = "Stylegan", - min = 0.0, - max = 512.0, - clamp = true - )] - z_range: f32, -} - -pub type Task = JoinHandle>>; - -/// Struct representing our SOP's state -pub struct StyleganHttpTop { - params: StyleganHttpTopParams, - execute_count: u32, - context: TopContext, - tasks: VecDeque, - last_req: Option, -} - -impl Future for StyleganHttpTop { - type Output = Option>; - - // Poll internal tasks,s - fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { - let req = self.params_as_req(); - if self.last_req.as_ref() != Some(&req) && self.tasks.len() < MAX_TASKS { - self.tasks - .push_back(tokio::spawn(Self::request_image(req.clone()))); - self.last_req = Some(req); - }; - - // While we have tasks, poll them - // If they're ready, return the image - // If they're failed, throw them away - // If they're not ready, reinsert them at the beginning - while let Some(mut task) = self.tasks.pop_front() { - // Pin'n'poll - match Pin::new(&mut task).poll(cx) { - Poll::Ready(Ok(Ok(image))) => { - return Poll::Ready(Some(image)); - } - Poll::Ready(Ok(Err(_))) | Poll::Ready(Err(_)) => { - self.set_warning(&format!("Error fetching image")); - continue; - } - Poll::Pending => { - self.tasks.insert(0, task); - if !self.params.blocking { - return Poll::Ready(None); - } - } - } - } - - Poll::Ready(None) - } -} - -#[derive(Default, Clone, Debug, PartialEq)] -struct ImageReq { - url: String, - seed: u16, - x: u32, - x_range: f32, - y: u32, - y_range: f32, - z: u32, - z_range: f32, -} - -impl StyleganHttpTop { - fn get_image(&mut self) -> Option> { - RUNTIME.block_on(self) - } - - fn params_as_req(&self) -> ImageReq { - ImageReq { - url: format!( - "http://{ip}:{port}", - ip = self.params.ip, - port = self.params.port - ), - seed: self.params.seed, - x: self.params.x_feature, - x_range: self.params.x_range, - y: self.params.y_feature, - y_range: self.params.y_range, - z: self.params.z_feature, - z_range: self.params.z_range, - } - } - - async fn request_image(image_req: ImageReq) -> anyhow::Result> { - let ImageReq { - url, - seed, - x, - x_range, - y, - y_range, - z, - z_range, - } = image_req; - let bytes = reqwest::get(format!( - "{url}?seed={seed}&x={x}&x_range={x_range}&y={y}&y_range={y_range}&z={z}&z_range={z_range}" - )) - .await? - .bytes() - .await? - .to_vec(); - - Ok(bytes) - } -} - -impl TopNew for StyleganHttpTop { - fn new(_info: NodeInfo, context: TopContext) -> Self { - Self { - params: Default::default(), - execute_count: 0, - context, - tasks: VecDeque::with_capacity(MAX_TASKS), - last_req: None, - } - } -} - -impl OpInfo for StyleganHttpTop { - const OPERATOR_LABEL: &'static str = "Stylegan Http"; - const OPERATOR_TYPE: &'static str = "Styleganhttpn"; - const MAX_INPUTS: usize = 0; - const MIN_INPUTS: usize = 0; -} - -impl TopInfo for StyleganHttpTop { - const EXECUTE_MODE: ExecuteMode = ExecuteMode::Cpu; -} - -impl Op for StyleganHttpTop { - fn params_mut(&mut self) -> Option> { - Some(Box::new(&mut self.params)) - } - - fn pulse_pressed(&mut self, name: &str) { - if name == "Reset" {} - } -} - -impl Top for StyleganHttpTop { - fn general_info(&self, _input: &OperatorInputs) -> TopGeneralInfo { - TopGeneralInfo { - cook_every_frame: false, - cook_every_frame_if_asked: true, - input_size_index: 0, - } - } - - fn execute(&mut self, mut output: TopOutput, input: &OperatorInputs) { - self.execute_count += 1; - - if let Some(mut image) = self.get_image() { - if image.len() < WIDTH * HEIGHT * 4 { - self.set_warning(&format!( - "Image size mismatch, expected 1024x1024x4, got {len:?}", - len = image.len() - )); - return; - } - - // kick off another request optimistically - self.get_image(); - let mut buf = self - .context - .create_output_buffer(image.len(), TopBufferFlags::None); - buf.data_mut().copy_from_slice(image.as_slice()); - - let info = UploadInfo { - buffer_offset: 0, - texture_desc: TextureDesc { - tex_dim: TexDim::E2D, - width: WIDTH, - height: HEIGHT, - pixel_format: PixelFormat::BGRA8Fixed, - aspect_x: 0.0, - depth: 1, - aspect_y: 0.0, - }, - first_pixel: FirstPixel::TopLeft, - color_buffer_index: 0, - }; - - output.upload_buffer(&mut buf, &info); - } - } -} - -top_plugin!(StyleganHttpTop); +use futures::task::noop_waker_ref; +use std::collections::VecDeque; +use std::future; +use std::future::Future; +use std::pin::{pin, Pin}; +use std::sync::Arc; +use std::task::Poll; +use td_rs_derive::Params; +use td_rs_top::*; +use tokio::task::JoinHandle; +use tracing::{error, info}; + +const WIDTH: usize = 1024; +const HEIGHT: usize = 1024; +const MAX_TASKS: usize = 10; + +#[derive(Params, Default, Clone, Debug)] +struct StyleganHttpTopParams { + #[param(label = "Ip Address", page = "Config", default = "localhost")] + ip: String, + #[param(label = "Port", page = "Config", default = 5000)] + port: u16, + #[param(label = "Seed", page = "Stylegan")] + seed: u16, + #[param(label = "Blocing", page = "Config")] + blocking: bool, + #[param( + label = "X Feature", + page = "Stylegan", + min = 0.0, + max = 512.0, + clamp = true + )] + x_feature: u32, + #[param( + label = "X Range", + page = "Stylegan", + min = 0.0, + max = 512.0, + clamp = true + )] + x_range: f32, + #[param( + label = "Y Feature", + page = "Stylegan", + min = 0.0, + max = 512.0, + clamp = true + )] + y_feature: u32, + #[param( + label = "Y Range", + page = "Stylegan", + min = 0.0, + max = 512.0, + clamp = true + )] + y_range: f32, + #[param( + label = "Z Feature", + page = "Stylegan", + min = 0.0, + max = 512.0, + clamp = true + )] + z_feature: u32, + #[param( + label = "Z Range", + page = "Stylegan", + min = 0.0, + max = 512.0, + clamp = true + )] + z_range: f32, +} + +pub type Task = JoinHandle>>; + +/// Struct representing our SOP's state +pub struct StyleganHttpTop { + params: StyleganHttpTopParams, + execute_count: u32, + context: TopContext, + tasks: VecDeque, + last_req: Option, +} + +impl Future for StyleganHttpTop { + type Output = Option>; + + // Poll internal tasks,s + fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { + let req = self.params_as_req(); + if self.last_req.as_ref() != Some(&req) && self.tasks.len() < MAX_TASKS { + self.tasks + .push_back(tokio::spawn(Self::request_image(req.clone()))); + self.last_req = Some(req); + }; + + // While we have tasks, poll them + // If they're ready, return the image + // If they're failed, throw them away + // If they're not ready, reinsert them at the beginning + while let Some(mut task) = self.tasks.pop_front() { + // Pin'n'poll + match Pin::new(&mut task).poll(cx) { + Poll::Ready(Ok(Ok(image))) => { + return Poll::Ready(Some(image)); + } + Poll::Ready(Ok(Err(_))) | Poll::Ready(Err(_)) => { + self.set_warning(&format!("Error fetching image")); + continue; + } + Poll::Pending => { + self.tasks.insert(0, task); + if !self.params.blocking { + return Poll::Ready(None); + } + } + } + } + + Poll::Ready(None) + } +} + +#[derive(Default, Clone, Debug, PartialEq)] +struct ImageReq { + url: String, + seed: u16, + x: u32, + x_range: f32, + y: u32, + y_range: f32, + z: u32, + z_range: f32, +} + +impl StyleganHttpTop { + fn get_image(&mut self) -> Option> { + RUNTIME.block_on(self) + } + + fn params_as_req(&self) -> ImageReq { + ImageReq { + url: format!( + "http://{ip}:{port}", + ip = self.params.ip, + port = self.params.port + ), + seed: self.params.seed, + x: self.params.x_feature, + x_range: self.params.x_range, + y: self.params.y_feature, + y_range: self.params.y_range, + z: self.params.z_feature, + z_range: self.params.z_range, + } + } + + async fn request_image(image_req: ImageReq) -> anyhow::Result> { + let ImageReq { + url, + seed, + x, + x_range, + y, + y_range, + z, + z_range, + } = image_req; + let bytes = reqwest::get(format!( + "{url}?seed={seed}&x={x}&x_range={x_range}&y={y}&y_range={y_range}&z={z}&z_range={z_range}" + )) + .await? + .bytes() + .await? + .to_vec(); + + Ok(bytes) + } +} + +impl TopNew for StyleganHttpTop { + fn new(_info: NodeInfo, context: TopContext) -> Self { + Self { + params: Default::default(), + execute_count: 0, + context, + tasks: VecDeque::with_capacity(MAX_TASKS), + last_req: None, + } + } +} + +impl OpInfo for StyleganHttpTop { + const OPERATOR_LABEL: &'static str = "Stylegan Http"; + const OPERATOR_TYPE: &'static str = "Styleganhttpn"; + const MAX_INPUTS: usize = 0; + const MIN_INPUTS: usize = 0; +} + +impl TopInfo for StyleganHttpTop { + const EXECUTE_MODE: ExecuteMode = ExecuteMode::Cpu; +} + +impl Op for StyleganHttpTop { + fn params_mut(&mut self) -> Option> { + Some(Box::new(&mut self.params)) + } + + fn pulse_pressed(&mut self, name: &str) { + if name == "Reset" {} + } +} + +impl Top for StyleganHttpTop { + fn general_info(&self, _input: &OperatorInputs) -> TopGeneralInfo { + TopGeneralInfo { + cook_every_frame: false, + cook_every_frame_if_asked: true, + input_size_index: 0, + } + } + + fn execute(&mut self, mut output: TopOutput, input: &OperatorInputs) { + self.execute_count += 1; + + if let Some(mut image) = self.get_image() { + if image.len() < WIDTH * HEIGHT * 4 { + self.set_warning(&format!( + "Image size mismatch, expected 1024x1024x4, got {len:?}", + len = image.len() + )); + return; + } + + // kick off another request optimistically + self.get_image(); + let mut buf = self + .context + .create_output_buffer(image.len(), TopBufferFlags::None); + buf.data_mut().copy_from_slice(image.as_slice()); + + let info = UploadInfo { + buffer_offset: 0, + texture_desc: TextureDesc { + tex_dim: TexDim::E2D, + width: WIDTH, + height: HEIGHT, + pixel_format: PixelFormat::BGRA8Fixed, + aspect_x: 0.0, + depth: 1, + aspect_y: 0.0, + }, + first_pixel: FirstPixel::TopLeft, + color_buffer_index: 0, + }; + + output.upload_buffer(&mut buf, &info); + } + } +} + +top_plugin!(StyleganHttpTop); diff --git a/src/lib.rs b/src/lib.rs index 8b13789..d3f5a12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1 @@ - + diff --git a/td-rs-autocxx-build/Cargo.toml b/td-rs-autocxx-build/Cargo.toml index 8538a6a..af523b8 100644 --- a/td-rs-autocxx-build/Cargo.toml +++ b/td-rs-autocxx-build/Cargo.toml @@ -1,8 +1,8 @@ -[package] -name = "td-rs-autocxx-build" -version = "0.1.0" -edition = "2021" - -[dependencies] -autocxx-build = { git = "https://github.com/tychedelia/autocxx.git", branch = "main" } -miette = { version="5", features = [ "fancy" ] } +[package] +name = "td-rs-autocxx-build" +version = "0.1.0" +edition = "2021" + +[dependencies] +autocxx-build = { git = "https://github.com/tychedelia/autocxx.git", branch = "main" } +miette = { version="5", features = [ "fancy" ] } diff --git a/td-rs-autocxx-build/src/lib.rs b/td-rs-autocxx-build/src/lib.rs index 7205b91..726bab5 100644 --- a/td-rs-autocxx-build/src/lib.rs +++ b/td-rs-autocxx-build/src/lib.rs @@ -1,57 +1,57 @@ -pub fn build(output: &str, include_base: bool) -> miette::Result<()> { - let python_enabled = std::env::var("CARGO_FEATURE_PYTHON").is_ok(); - - let path = std::path::PathBuf::from("src"); - let mut incs = vec![path]; - let mut clang_args = vec![]; - - if include_base { - let base_path = std::path::PathBuf::from("../td-rs-base/src"); - incs.push(base_path); - } - - println!("python_enabled: {}", python_enabled); - - if python_enabled { - if cfg!(windows) { - incs.push(std::path::PathBuf::from( - "C:\\Program Files\\Derivative\\TouchDesigner\\Samples\\CPlusPlus\\3rdParty\\Python\\Include" - )); - incs.push(std::path::PathBuf::from( - "C:\\Program Files\\Derivative\\TouchDesigner\\Samples\\CPlusPlus\\3rdParty\\Python\\Include\\PC" - )); - } else { - incs.push(std::path::PathBuf::from( - "/Applications/TouchDesigner.app/Contents/Frameworks/Python.framework/Headers", - )); - }; - clang_args.push("-DPYTHON_ENABLED"); - } - - if cfg!(windows) { - clang_args.push("-std=c++17"); - clang_args.push("-D_CRT_USE_BUILTIN_OFFSETOF"); - } - - let b = autocxx_build::Builder::new("src/cxx.rs", &incs) - .extra_clang_args(&clang_args) - .auto_allowlist(true); - - let mut b = b.build()?; - if python_enabled { - b.define("PYTHON_ENABLED", None); - } - - b.flag_if_supported("-std=c++17"); - - if !cfg!(windows) { - b.flag("-Wno-unused-parameter") - .flag("-Wno-reorder-ctor") - .flag("-Wno-mismatched-tags") - .flag("-Wno-unused-private-field"); - } - - b.compile(output); - println!("cargo:rerun-if-changed=src/cxx.rs"); - Ok(()) -} +pub fn build(output: &str, include_base: bool) -> miette::Result<()> { + let python_enabled = std::env::var("CARGO_FEATURE_PYTHON").is_ok(); + + let path = std::path::PathBuf::from("src"); + let mut incs = vec![path]; + let mut clang_args = vec![]; + + if include_base { + let base_path = std::path::PathBuf::from("../td-rs-base/src"); + incs.push(base_path); + } + + println!("python_enabled: {}", python_enabled); + + if python_enabled { + if cfg!(windows) { + incs.push(std::path::PathBuf::from( + "C:\\Program Files\\Derivative\\TouchDesigner\\Samples\\CPlusPlus\\3rdParty\\Python\\Include" + )); + incs.push(std::path::PathBuf::from( + "C:\\Program Files\\Derivative\\TouchDesigner\\Samples\\CPlusPlus\\3rdParty\\Python\\Include\\PC" + )); + } else { + incs.push(std::path::PathBuf::from( + "/Applications/TouchDesigner.app/Contents/Frameworks/Python.framework/Headers", + )); + }; + clang_args.push("-DPYTHON_ENABLED"); + } + + if cfg!(windows) { + clang_args.push("-std=c++17"); + clang_args.push("-D_CRT_USE_BUILTIN_OFFSETOF"); + } + + let b = autocxx_build::Builder::new("src/cxx.rs", &incs) + .extra_clang_args(&clang_args) + .auto_allowlist(true); + + let mut b = b.build()?; + if python_enabled { + b.define("PYTHON_ENABLED", None); + } + + b.flag_if_supported("-std=c++17"); + + if !cfg!(windows) { + b.flag("-Wno-unused-parameter") + .flag("-Wno-reorder-ctor") + .flag("-Wno-mismatched-tags") + .flag("-Wno-unused-private-field"); + } + + b.compile(output); + println!("cargo:rerun-if-changed=src/cxx.rs"); + Ok(()) +} diff --git a/td-rs-base/Cargo.toml b/td-rs-base/Cargo.toml index 079eadb..b7c684c 100644 --- a/td-rs-base/Cargo.toml +++ b/td-rs-base/Cargo.toml @@ -1,31 +1,34 @@ -[package] -name = "td-rs-base" -version = "0.1.0" -edition = "2021" - -[lib] -name = "td_rs_base" -crate-type = ["lib", "staticlib"] - -[dependencies] -autocxx = { git = "https://github.com/tychedelia/autocxx.git" } -cxx = "1.0.78" -rgb = "0.8.36" -ref-cast = "1.0" -auto_ops = "0.3.0" -derive_more = { version = "1", features = ["full"] } -pyo3 = { git = "https://github.com/tychedelia/pyo3", branch = "td-rs", features = ["abi3-py311"], optional = true } -tracing-base = { package = "tracing", version = "0.1", optional = true} -tracing-subscriber = { version = "0.3", optional = true } -tokio-core = { package = "tokio", version = "1", optional = true } - -[build-dependencies] -td-rs-autocxx-build = { path = "../td-rs-autocxx-build" } -autocxx-build = { git = "https://github.com/tychedelia/autocxx.git" } -miette = { version = "5", features = [ "fancy" ] } - -[features] -default = [] -python = ["pyo3"] -tracing = ["tracing-base", "tracing-subscriber", "tracing-subscriber/env-filter"] -tokio = ["tokio-core", "tokio-core/rt-multi-thread"] \ No newline at end of file +[package] +name = "td-rs-base" +version = "0.1.0" +edition = "2021" + +[lib] +name = "td_rs_base" +crate-type = ["lib", "staticlib"] + +[dependencies] +autocxx = { git = "https://github.com/tychedelia/autocxx.git" } +cxx = "1.0.78" +rgb = "0.8.36" +ref-cast = "1.0" +auto_ops = "0.3.0" +derive_more = { version = "1", features = ["full"] } +pyo3 = { git = "https://github.com/tychedelia/pyo3", branch = "td-rs", features = ["abi3-py311"], optional = true } +tracing-base = { package = "tracing", version = "0.1", optional = true} +tracing-subscriber = { version = "0.3", optional = true } +tokio-core = { package = "tokio", version = "1", optional = true } +anyhow = "1.0" +cudarc = { version = "0.16.4", optional = true, features = ["runtime", "nvrtc", "driver", "cuda-12080", "dynamic-linking"], default-features = false } + +[build-dependencies] +td-rs-autocxx-build = { path = "../td-rs-autocxx-build" } +autocxx-build = { git = "https://github.com/tychedelia/autocxx.git" } +miette = { version = "5", features = [ "fancy" ] } + +[features] +default = [] +python = ["pyo3"] +tracing = ["tracing-base", "tracing-subscriber", "tracing-subscriber/env-filter"] +tokio = ["tokio-core", "tokio-core/rt-multi-thread"] +cuda = ["cudarc"] \ No newline at end of file diff --git a/td-rs-base/build.rs b/td-rs-base/build.rs index a544cbf..6bda4db 100644 --- a/td-rs-base/build.rs +++ b/td-rs-base/build.rs @@ -1,3 +1,3 @@ -fn main() -> miette::Result<()> { - td_rs_autocxx_build::build("td-rs-base", false) -} +fn main() -> miette::Result<()> { + td_rs_autocxx_build::build("td-rs-base", false) +} diff --git a/td-rs-base/src/CPlusPlus_Common.h b/td-rs-base/src/CPlusPlus_Common.h index b80b4de..897acd8 100644 --- a/td-rs-base/src/CPlusPlus_Common.h +++ b/td-rs-base/src/CPlusPlus_Common.h @@ -51,7 +51,6 @@ typedef struct CUstream_st *cudaStream_t; class TOP_CPlusPlus; namespace TD { - class CHOP_PluginInfo; class CHOP_CPlusPlusBase; class DAT_PluginInfo; @@ -105,7 +104,6 @@ enum class OP_PixelFormat : int32_t { RGB10A2Fixed = 700, // 11-bit float, positive values only. B is actually 10 bits RGB11Float, - }; typedef OP_PixelFormat OP_CPUMemPixelType; @@ -125,6 +123,7 @@ class OP_TOPInputDownloadOptionsOpenGL; class PY_GetInfo { public: PY_GetInfo() { memset(this, 0, sizeof(PY_GetInfo)); } + // If this is set to true then the node will cook if it needs to before your // class instance is returned. This should be set to true if the python code // requires the node's state to be up-to-date before doing it's work. @@ -177,14 +176,19 @@ class OP_RefCount { protected: // Increase the reference count to this instance. virtual void acquire() = 0; + // Decrease the reference count to this instance. When the reference count // reaches 0 the class will be deleted. virtual void release() = 0; virtual void reserved0() = 0; + virtual void reserved1() = 0; + virtual void reserved2() = 0; + virtual void reserved3() = 0; + virtual void reserved4() = 0; template friend class OP_SmartRef; @@ -339,7 +343,11 @@ class OP_CustomOPInfo { // OP, not as a C++ OP. const char *pythonCallbacksDAT = nullptr; - int32_t reserved[88]; + // If you want to specify a website URL to direct to when the Operator Help + // button is pressed set this to that URL + OP_String *opHelpURL; + + int32_t reserved[85]; }; // This class is used to provide direct access to the instance of a Custom OP @@ -373,6 +381,7 @@ template class OP_CustomOPInstance { class OP_Context { public: OP_Context() { memset(reserved, 0, sizeof(reserved)); } + virtual ~OP_Context() {} // By convention all callbacks in TouchDesigner have the first argument as @@ -401,6 +410,7 @@ class OP_Context { // these functions. This is needed to ensure the order of operations between // Vulkan and CUDA is properly managed. virtual bool beginCUDAOperations(void *reserved1) = 0; + virtual void endCUDAOperations(void *reserved1) = 0; int32_t reserved[50]; @@ -408,19 +418,33 @@ class OP_Context { protected: // Reserved for later use virtual void *reservedFunc0() = 0; + virtual void *reservedFunc1() = 0; + virtual void *reservedFunc2() = 0; + virtual void *reservedFunc3() = 0; + virtual void *reservedFunc4() = 0; + virtual void *reservedFunc5() = 0; + virtual void *reservedFunc6() = 0; + virtual void *reservedFunc7() = 0; + virtual void *reservedFunc8() = 0; + virtual void *reservedFunc9() = 0; + virtual void *reservedFunc10() = 0; + virtual void *reservedFunc11() = 0; + virtual void *reservedFunc12() = 0; + virtual void *reservedFunc13() = 0; + virtual void *reservedFunc14() = 0; }; @@ -490,7 +514,8 @@ class OP_DATInput { // The number of times this node has cooked int64_t totalCooks; - // See documentation for OPCustomOPInstance + // See comments that preceed the declaration of the OP_CustomOPInstance class + // for more information const OP_CustomOPInstance *customOP; int32_t reserved[16]; @@ -611,16 +636,21 @@ class OP_TOPInput { // The number of times this node has cooked int64_t totalCooks; - // See documentation for OPCustomOPInstance + // See comments that preceed the declaration of the OP_CustomOPInstance class + // for more information const OP_CustomOPInstance *customOP; int32_t reserved[12]; protected: virtual void *reserved0() = 0; + virtual void *reserved1() = 0; + virtual void *reserved2() = 0; + virtual void *reserved3() = 0; + virtual void *reserved4() = 0; }; @@ -666,7 +696,8 @@ class OP_CHOPInput { // The number of times this node has cooked int64_t totalCooks; - // See documentation for OPCustomOPInstance + // See comments that preceed the declaration of the OP_CustomOPInstance class + // for more information const OP_CustomOPInstance *customOP; int32_t reserved[16]; @@ -1241,7 +1272,8 @@ class OP_SOPInput { // The number of times this node has cooked int64_t totalCooks; - // See documentation for OPCustomOPInstance + // See comments that preceed the declaration of the OP_CustomOPInstance class + // for more information const OP_CustomOPInstance *customOP; int32_t reserved[95]; @@ -1302,6 +1334,7 @@ class OP_Inputs { public: // Only valid for C++ CHOP operators virtual const OP_CHOPInput *getInputCHOP(int32_t index) const = 0; + // getInputSOP() declared later on in the class // getInputDAT() declared later on in the class @@ -1317,7 +1350,9 @@ class OP_Inputs { public: virtual const OP_CHOPInput *getParCHOP(const char *name) const = 0; + virtual const OP_ObjectInput *getParObject(const char *name) const = 0; + // getParSOP() declared later on in the class // these work on any type of parameter and can be interchanged @@ -1330,8 +1365,10 @@ class OP_Inputs { // for multiple values: returns True on success/false otherwise virtual bool getParDouble2(const char *name, double &v0, double &v1) const = 0; + virtual bool getParDouble3(const char *name, double &v0, double &v1, double &v2) const = 0; + virtual bool getParDouble4(const char *name, double &v0, double &v1, double &v2, double &v3) const = 0; @@ -1340,8 +1377,10 @@ class OP_Inputs { // for multiple values: returns True on success/false otherwise virtual bool getParInt2(const char *name, int32_t &v0, int32_t &v1) const = 0; + virtual bool getParInt3(const char *name, int32_t &v0, int32_t &v1, int32_t &v2) const = 0; + virtual bool getParInt4(const char *name, int32_t &v0, int32_t &v1, int32_t &v2, int32_t &v3) const = 0; @@ -1377,6 +1416,7 @@ class OP_Inputs { public: virtual const OP_CHOPInput *getCHOP(const char *path) const = 0; + virtual const OP_ObjectInput *getObject(const char *path) const = 0; private: @@ -1388,8 +1428,10 @@ class OP_Inputs { public: virtual const OP_SOPInput *getParSOP(const char *name) const = 0; + // only valid for C++ SOP operators virtual const OP_SOPInput *getInputSOP(int32_t index) const = 0; + virtual const OP_SOPInput *getSOP(const char *path) const = 0; // only valid for C++ DAT operators @@ -1408,7 +1450,9 @@ class OP_Inputs { virtual const OP_TimeInfo *getTimeInfo() const = 0; virtual const OP_TOPInput *getTOP(const char *path) const = 0; + virtual const OP_TOPInput *getInputTOP(int32_t index) const = 0; + virtual const OP_TOPInput *getParTOP(const char *name) const = 0; }; @@ -1532,34 +1576,46 @@ class OP_BuildDynamicMenuInfo { }; class OP_ParameterManager { - public: // Returns OP_ParAppendResult::Success on success virtual OP_ParAppendResult appendFloat(const OP_NumericParameter &np, int32_t size = 1) = 0; + virtual OP_ParAppendResult appendInt(const OP_NumericParameter &np, int32_t size = 1) = 0; virtual OP_ParAppendResult appendXY(const OP_NumericParameter &np) = 0; + virtual OP_ParAppendResult appendXYZ(const OP_NumericParameter &np) = 0; + // appendXYZW() added further down + virtual OP_ParAppendResult appendUV(const OP_NumericParameter &np) = 0; + virtual OP_ParAppendResult appendUVW(const OP_NumericParameter &np) = 0; virtual OP_ParAppendResult appendRGB(const OP_NumericParameter &np) = 0; + virtual OP_ParAppendResult appendRGBA(const OP_NumericParameter &np) = 0; virtual OP_ParAppendResult appendToggle(const OP_NumericParameter &np) = 0; + virtual OP_ParAppendResult appendPulse(const OP_NumericParameter &np) = 0; virtual OP_ParAppendResult appendString(const OP_StringParameter &sp) = 0; + virtual OP_ParAppendResult appendFile(const OP_StringParameter &sp) = 0; + virtual OP_ParAppendResult appendFolder(const OP_StringParameter &sp) = 0; virtual OP_ParAppendResult appendDAT(const OP_StringParameter &sp) = 0; + virtual OP_ParAppendResult appendCHOP(const OP_StringParameter &sp) = 0; + virtual OP_ParAppendResult appendTOP(const OP_StringParameter &sp) = 0; + virtual OP_ParAppendResult appendObject(const OP_StringParameter &sp) = 0; + // appendSOP() located further down in the class // Any char* values passed are copied immediately by the append parameter @@ -1582,12 +1638,17 @@ class OP_ParameterManager { virtual OP_ParAppendResult appendPython(const OP_StringParameter &sp) = 0; virtual OP_ParAppendResult appendOP(const OP_StringParameter &sp) = 0; + virtual OP_ParAppendResult appendCOMP(const OP_StringParameter &sp) = 0; + virtual OP_ParAppendResult appendMAT(const OP_StringParameter &sp) = 0; + virtual OP_ParAppendResult appendPanelCOMP(const OP_StringParameter &sp) = 0; virtual OP_ParAppendResult appendHeader(const OP_StringParameter &np) = 0; + virtual OP_ParAppendResult appendMomentary(const OP_NumericParameter &np) = 0; + virtual OP_ParAppendResult appendWH(const OP_NumericParameter &np) = 0; // The buildDynamicMenu() function will be called in your class instance when @@ -1595,8 +1656,11 @@ class OP_ParameterManager { // parameters or external state (such as available devices). virtual OP_ParAppendResult appendDynamicStringMenu(const OP_StringParameter &sp) = 0; + virtual OP_ParAppendResult appendDynamicMenu(const OP_NumericParameter &np) = 0; + + virtual OP_ParAppendResult appendXYZW(const OP_NumericParameter &np) = 0; }; #pragma pack(pop) @@ -1785,21 +1849,32 @@ static_assert(offsetof(PY_Struct, context) == // These are the definitions for the C-functions that are used to // load the library and create instances of the object you define typedef void(__cdecl *FILLCHOPPLUGININFO)(TD::CHOP_PluginInfo *info); + typedef TD::CHOP_CPlusPlusBase *(__cdecl *CREATECHOPINSTANCE)( const TD::OP_NodeInfo *); + typedef void(__cdecl *DESTROYCHOPINSTANCE)(TD::CHOP_CPlusPlusBase *); + typedef void(__cdecl *FILLDATPLUGININFO)(TD::DAT_PluginInfo *info); + typedef TD::DAT_CPlusPlusBase *(__cdecl *CREATEDATINSTANCE)( const TD::OP_NodeInfo *); + typedef void(__cdecl *DESTROYDATINSTANCE)(TD::DAT_CPlusPlusBase *); + typedef void(__cdecl *FILLTOPPLUGININFO)(TD::TOP_PluginInfo *info); + typedef TD::TOP_CPlusPlusBase *(__cdecl *CREATETOPINSTANCE)( const TD::OP_NodeInfo *, TD::TOP_Context *); + typedef void(__cdecl *DESTROYTOPINSTANCE)(TD::TOP_CPlusPlusBase *, TD::TOP_Context *); + typedef void(__cdecl *FILLSOPPLUGININFO)(TD::SOP_PluginInfo *info); + typedef TD::SOP_CPlusPlusBase *(__cdecl *CREATESOPINSTANCE)( const TD::OP_NodeInfo *); + typedef void(__cdecl *DESTROYSOPINSTANCE)(TD::SOP_CPlusPlusBase *); #endif diff --git a/td-rs-base/src/GL_Extensions.h b/td-rs-base/src/GL_Extensions.h index 75f3ecb..0ce8f79 100644 --- a/td-rs-base/src/GL_Extensions.h +++ b/td-rs-base/src/GL_Extensions.h @@ -1,2 +1,2 @@ -// Stub file for simpler CHOP usage than an OpenGLTOP +// Stub file for simpler CHOP usage than an OpenGLTOP #include \ No newline at end of file diff --git a/td-rs-base/src/RustBase.h b/td-rs-base/src/RustBase.h index 1927d43..748c793 100644 --- a/td-rs-base/src/RustBase.h +++ b/td-rs-base/src/RustBase.h @@ -1,34 +1,58 @@ -#include "CPlusPlus_Common.h" -#include -#include -#include - -#ifndef TD_RS_RUSTBASE_H -#define TD_RS_RUSTBASE_H - -void setString(TD::OP_String *dest, const char *src) { dest->setString(src); } - -uint64_t getDownloadDataSize(TD::OP_SmartRef &result) { - uint64_t size = result->size; - return size; -} - -void* getDownloadData(TD::OP_SmartRef &result) { - void* data = result->getData(); - return data; -} - -TD::OP_TextureDesc getDownloadTextureDesc(TD::OP_SmartRef &result) { - TD::OP_TextureDesc desc = result->textureDesc; - return desc; -} - -void releaseDownloadResult(TD::OP_SmartRef &result) { - result.release(); -} - -const char* getBuildDynamicMenuInfoNames(TD::OP_BuildDynamicMenuInfo &info) { - return info.name; -} - -#endif // TD_RS_RUSTBASE_H +#include "CPlusPlus_Common.h" +#include +#include +#include + +#ifndef TD_RS_RUSTBASE_H +#define TD_RS_RUSTBASE_H + +void setString(TD::OP_String *dest, const char *src) { dest->setString(src); } + +uint64_t getDownloadDataSize(TD::OP_SmartRef &result) { + uint64_t size = result->size; + return size; +} + +void* getDownloadData(TD::OP_SmartRef &result) { + void* data = result->getData(); + return data; +} + +TD::OP_TextureDesc getDownloadTextureDesc(TD::OP_SmartRef &result) { + TD::OP_TextureDesc desc = result->textureDesc; + return desc; +} + +void releaseDownloadResult(TD::OP_SmartRef &result) { + result.release(); +} + +const char* getBuildDynamicMenuInfoNames(TD::OP_BuildDynamicMenuInfo &info) { + return info.name; +} + +// CUDA helper functions for base types +TD::OP_TextureDesc getCUDAArrayInfoTextureDesc(const TD::OP_CUDAArrayInfo &info) { + return info.textureDesc; +} + +void* getCUDAArrayInfoArray(const TD::OP_CUDAArrayInfo &info) { + return info.cudaArray; +} + +void* getCUDAAcquireInfoStream(const TD::OP_CUDAAcquireInfo &info) { + return info.stream; +} + +TD::OP_CUDAAcquireInfo createCUDAAcquireInfo(void* stream) { + TD::OP_CUDAAcquireInfo info; + info.stream = static_cast(stream); + return info; +} + +// Helper function to get texture descriptor from TOP input +TD::OP_TextureDesc getTOPInputTextureDesc(const TD::OP_TOPInput &input) { + return input.textureDesc; +} + +#endif // TD_RS_RUSTBASE_H diff --git a/td-rs-base/src/RustPy.h b/td-rs-base/src/RustPy.h index 1752096..c1d4695 100644 --- a/td-rs-base/src/RustPy.h +++ b/td-rs-base/src/RustPy.h @@ -1,42 +1,42 @@ -#include "CPlusPlus_Common.h" -#include -#ifdef PYTHON_ENABLED -#include -#endif -#include -#include - -#ifndef TD_RS_RUSTPY_H -#define TD_RS_RUSTPY_H - -#ifdef PYTHON_ENABLED -TD::PY_Context* getPyContext(TD::PY_Struct *pyStruct) { - return pyStruct->context; -} - -void setPyInfo(TD::OP_CustomOPInfo &opInfo, void *pymethods, size_t size, void *pygetsets, size_t getsetsize) { - if (size == 0) { - opInfo.pythonMethods = nullptr; - } else { - opInfo.pythonMethods = static_cast(pymethods); - } - - if (getsetsize == 0) { - opInfo.pythonGetSets = nullptr; - } else { - opInfo.pythonGetSets = static_cast(pygetsets); - } -} -#else - -std::unique_ptr getPyContext(TD::PY_Struct *pyStruct) { - return nullptr; -} - -void setPyInfo(TD::OP_CustomOPInfo &opInfo, void *pymethods, size_t size, void *pygetsets, size_t getsetsize) { - std::cout << "Python is not enabled" << std::endl; -} - -#endif - -#endif //TD_RS_RUSTPY_H +#include "CPlusPlus_Common.h" +#include +#ifdef PYTHON_ENABLED +#include +#endif +#include +#include + +#ifndef TD_RS_RUSTPY_H +#define TD_RS_RUSTPY_H + +#ifdef PYTHON_ENABLED +TD::PY_Context* getPyContext(TD::PY_Struct *pyStruct) { + return pyStruct->context; +} + +void setPyInfo(TD::OP_CustomOPInfo &opInfo, void *pymethods, size_t size, void *pygetsets, size_t getsetsize) { + if (size == 0) { + opInfo.pythonMethods = nullptr; + } else { + opInfo.pythonMethods = static_cast(pymethods); + } + + if (getsetsize == 0) { + opInfo.pythonGetSets = nullptr; + } else { + opInfo.pythonGetSets = static_cast(pygetsets); + } +} +#else + +std::unique_ptr getPyContext(TD::PY_Struct *pyStruct) { + return nullptr; +} + +void setPyInfo(TD::OP_CustomOPInfo &opInfo, void *pymethods, size_t size, void *pygetsets, size_t getsetsize) { + std::cout << "Python is not enabled" << std::endl; +} + +#endif + +#endif //TD_RS_RUSTPY_H diff --git a/td-rs-base/src/chop.rs b/td-rs-base/src/chop.rs index 9a610ca..391ca73 100644 --- a/td-rs-base/src/chop.rs +++ b/td-rs-base/src/chop.rs @@ -1,60 +1,60 @@ -use crate::cxx::OP_CHOPInput; -use crate::{GetInput, OperatorInputs}; -use ref_cast::RefCast; -use std::ops::Index; - -/// A chop input. -#[repr(transparent)] -#[derive(RefCast)] -pub struct ChopInput { - input: OP_CHOPInput, -} - -impl ChopInput { - /// Get the number of channels in this input. - pub fn num_channels(&self) -> usize { - self.input.numChannels as usize - } - - /// Get the number of samples in this input. - pub fn num_samples(&self) -> usize { - self.input.numSamples as usize - } - - /// Get a channel. - pub fn channel(&self, index: usize) -> &[f32] { - if index >= self.num_channels() { - panic!("index out of bounds"); - } - - unsafe { - std::slice::from_raw_parts( - *self.input.channelData.add(index), - self.input.numSamples as usize, - ) - } - } -} - -impl<'cook> GetInput<'cook, ChopInput> for OperatorInputs<'cook, ChopInput> { - fn num_inputs(&self) -> usize { - self.inputs.getNumInputs() as usize - } - - fn input(&self, index: usize) -> Option<&'cook ChopInput> { - let input = self.inputs.getInputCHOP(index as i32); - if input.is_null() { - None - } else { - Some(ChopInput::ref_cast(unsafe { &*input })) - } - } -} - -impl Index for ChopInput { - type Output = [f32]; - - fn index(&self, index: usize) -> &Self::Output { - self.channel(index) - } -} +use crate::cxx::OP_CHOPInput; +use crate::{GetInput, OperatorInputs}; +use ref_cast::RefCast; +use std::ops::Index; + +/// A chop input. +#[repr(transparent)] +#[derive(RefCast)] +pub struct ChopInput { + input: OP_CHOPInput, +} + +impl ChopInput { + /// Get the number of channels in this input. + pub fn num_channels(&self) -> usize { + self.input.numChannels as usize + } + + /// Get the number of samples in this input. + pub fn num_samples(&self) -> usize { + self.input.numSamples as usize + } + + /// Get a channel. + pub fn channel(&self, index: usize) -> &[f32] { + if index >= self.num_channels() { + panic!("index out of bounds"); + } + + unsafe { + std::slice::from_raw_parts( + *self.input.channelData.add(index), + self.input.numSamples as usize, + ) + } + } +} + +impl<'cook> GetInput<'cook, ChopInput> for OperatorInputs<'cook, ChopInput> { + fn num_inputs(&self) -> usize { + self.inputs.getNumInputs() as usize + } + + fn input(&self, index: usize) -> Option<&'cook ChopInput> { + let input = self.inputs.getInputCHOP(index as i32); + if input.is_null() { + None + } else { + Some(ChopInput::ref_cast(unsafe { &*input })) + } + } +} + +impl Index for ChopInput { + type Output = [f32]; + + fn index(&self, index: usize) -> &Self::Output { + self.channel(index) + } +} diff --git a/td-rs-base/src/cuda.rs b/td-rs-base/src/cuda.rs new file mode 100644 index 0000000..f30eb0b --- /dev/null +++ b/td-rs-base/src/cuda.rs @@ -0,0 +1,28 @@ +#[derive(Debug)] +pub struct CudaContext { + context: Option>, +} + +impl Default for CudaContext { + fn default() -> Self { + Self { context: None } + } +} + +impl CudaContext { + pub fn new(device_ordinal: usize) -> Result { + let context = cudarc::driver::CudaContext::new(device_ordinal) + .map_err(|e| anyhow::anyhow!("Failed to create CUDA context: {:?}", e))?; + Ok(Self { + context: Some(context), + }) + } + + pub fn cudarc_context(&self) -> Option<&std::sync::Arc> { + self.context.as_ref() + } + + pub fn default_stream(&self) -> Option> { + self.context.as_ref().map(|ctx| ctx.default_stream()) + } +} diff --git a/td-rs-base/src/cxx.rs b/td-rs-base/src/cxx.rs index 47fb9aa..45b3db6 100644 --- a/td-rs-base/src/cxx.rs +++ b/td-rs-base/src/cxx.rs @@ -37,7 +37,9 @@ include_cpp! { generate_pod!("TD::OP_TextureDesc") generate_pod!("TD::OP_TexDim") generate!("TD::OP_BuildDynamicMenuInfo") - + // CUDA types (opaque pointers due to non-POD members) + generate!("TD::OP_CUDAArrayInfo") + generate!("TD::OP_CUDAAcquireInfo") // util fns generate!("setString") @@ -47,6 +49,13 @@ include_cpp! { generate!("releaseDownloadResult") generate!("getBuildDynamicMenuInfoNames") + // CUDA helper functions for base types + generate!("getCUDAArrayInfoTextureDesc") + generate!("getCUDAArrayInfoArray") + generate!("getTOPInputTextureDesc") + generate!("getCUDAAcquireInfoStream") + generate!("createCUDAAcquireInfo") + // Custom ops generate!("TD::OP_CustomOPInstance") generate!("TD::CHOP_CPlusPlusBase") diff --git a/td-rs-base/src/dat.rs b/td-rs-base/src/dat.rs index 1020495..5954227 100644 --- a/td-rs-base/src/dat.rs +++ b/td-rs-base/src/dat.rs @@ -1,75 +1,75 @@ -use crate::cxx::OP_DATInput; -use crate::{GetInput, OperatorInputs}; -use ref_cast::RefCast; - -/// A dat input. -#[repr(transparent)] -#[derive(RefCast)] -pub struct DatInput { - input: OP_DATInput, -} - -pub enum DatType { - Table, - Text, -} - -impl DatInput { - pub fn dat_type(&self) -> DatType { - if self.input.isTable { - DatType::Table - } else { - DatType::Text - } - } - - pub fn num_rows(&self) -> usize { - self.input.numRows as usize - } - - pub fn num_cols(&self) -> usize { - self.input.numCols as usize - } - - pub fn table_size(&self) -> [usize; 2] { - let rows = self.num_rows(); - let cols = self.num_cols(); - [rows, cols] - } - - pub fn cell(&self, row: usize, col: usize) -> Option<&str> { - if row >= self.num_rows() || col >= self.num_cols() { - None - } else { - let cell = self.input.getCell(row as i32, col as i32); - if cell.is_null() { - None - } else { - Some( - unsafe { std::ffi::CStr::from_ptr(cell) } - .to_str() - .expect("invalid utf8"), - ) - } - } - } - - pub fn text(&self) -> &str { - self.cell(0, 0).unwrap() - } -} - -impl<'cook> GetInput<'cook, DatInput> for OperatorInputs<'cook, DatInput> { - fn num_inputs(&self) -> usize { - self.inputs.getNumInputs() as usize - } - - fn input(&self, index: usize) -> Option<&'cook DatInput> { - let input = self.inputs.getInputDAT(index as i32); - if input.is_null() { - None - } else { - Some(DatInput::ref_cast(unsafe { &*input })) - } - } -} +use crate::cxx::OP_DATInput; +use crate::{GetInput, OperatorInputs}; +use ref_cast::RefCast; + +/// A dat input. +#[repr(transparent)] +#[derive(RefCast)] +pub struct DatInput { + input: OP_DATInput, +} + +pub enum DatType { + Table, + Text, +} + +impl DatInput { + pub fn dat_type(&self) -> DatType { + if self.input.isTable { + DatType::Table + } else { + DatType::Text + } + } + + pub fn num_rows(&self) -> usize { + self.input.numRows as usize + } + + pub fn num_cols(&self) -> usize { + self.input.numCols as usize + } + + pub fn table_size(&self) -> [usize; 2] { + let rows = self.num_rows(); + let cols = self.num_cols(); + [rows, cols] + } + + pub fn cell(&self, row: usize, col: usize) -> Option<&str> { + if row >= self.num_rows() || col >= self.num_cols() { + None + } else { + let cell = self.input.getCell(row as i32, col as i32); + if cell.is_null() { + None + } else { + Some( + unsafe { std::ffi::CStr::from_ptr(cell) } + .to_str() + .expect("invalid utf8"), + ) + } + } + } + + pub fn text(&self) -> &str { + self.cell(0, 0).unwrap() + } +} + +impl<'cook> GetInput<'cook, DatInput> for OperatorInputs<'cook, DatInput> { + fn num_inputs(&self) -> usize { + self.inputs.getNumInputs() as usize + } + + fn input(&self, index: usize) -> Option<&'cook DatInput> { + let input = self.inputs.getInputDAT(index as i32); + if input.is_null() { + None + } else { + Some(DatInput::ref_cast(unsafe { &*input })) + } + } +} diff --git a/td-rs-base/src/gltypes.h b/td-rs-base/src/gltypes.h index bba4bef..1750865 100644 --- a/td-rs-base/src/gltypes.h +++ b/td-rs-base/src/gltypes.h @@ -1,59 +1,59 @@ -/* - Copyright: (c) 2010-2012 Apple Inc. All rights reserved. -*/ -#ifndef __gltypes_h_ -#define __gltypes_h_ - -#include - -typedef uint32_t GLbitfield; -typedef uint8_t GLboolean; -typedef int8_t GLbyte; -typedef float GLclampf; -typedef uint32_t GLenum; -typedef float GLfloat; -typedef int32_t GLint; -typedef int16_t GLshort; -typedef int32_t GLsizei; -typedef uint8_t GLubyte; -typedef uint32_t GLuint; -typedef uint16_t GLushort; -typedef void GLvoid; - -#if !defined(GL_VERSION_2_0) -typedef char GLchar; -#endif -#if !defined(GL_ARB_shader_objects) -typedef char GLcharARB; -typedef void *GLhandleARB; -#endif -typedef double GLdouble; -typedef double GLclampd; -#if !defined(ARB_ES2_compatibility) && !defined(GL_VERSION_4_1) -typedef int32_t GLfixed; -#endif -#if !defined(GL_ARB_half_float_vertex) && !defined(GL_VERSION_3_0) -typedef uint16_t GLhalf; -#endif -#if !defined(GL_ARB_half_float_pixel) -typedef uint16_t GLhalfARB; -#endif -#if !defined(GL_ARB_sync) && !defined(GL_VERSION_3_2) -typedef int64_t GLint64; -typedef struct __GLsync *GLsync; -typedef uint64_t GLuint64; -#endif -#if !defined(GL_EXT_timer_query) -typedef int64_t GLint64EXT; -typedef uint64_t GLuint64EXT; -#endif -#if !defined(GL_VERSION_1_5) -typedef intptr_t GLintptr; -typedef intptr_t GLsizeiptr; -#endif -#if !defined(GL_ARB_vertex_buffer_object) -typedef intptr_t GLintptrARB; -typedef intptr_t GLsizeiptrARB; -#endif - -#endif +/* + Copyright: (c) 2010-2012 Apple Inc. All rights reserved. +*/ +#ifndef __gltypes_h_ +#define __gltypes_h_ + +#include + +typedef uint32_t GLbitfield; +typedef uint8_t GLboolean; +typedef int8_t GLbyte; +typedef float GLclampf; +typedef uint32_t GLenum; +typedef float GLfloat; +typedef int32_t GLint; +typedef int16_t GLshort; +typedef int32_t GLsizei; +typedef uint8_t GLubyte; +typedef uint32_t GLuint; +typedef uint16_t GLushort; +typedef void GLvoid; + +#if !defined(GL_VERSION_2_0) +typedef char GLchar; +#endif +#if !defined(GL_ARB_shader_objects) +typedef char GLcharARB; +typedef void *GLhandleARB; +#endif +typedef double GLdouble; +typedef double GLclampd; +#if !defined(ARB_ES2_compatibility) && !defined(GL_VERSION_4_1) +typedef int32_t GLfixed; +#endif +#if !defined(GL_ARB_half_float_vertex) && !defined(GL_VERSION_3_0) +typedef uint16_t GLhalf; +#endif +#if !defined(GL_ARB_half_float_pixel) +typedef uint16_t GLhalfARB; +#endif +#if !defined(GL_ARB_sync) && !defined(GL_VERSION_3_2) +typedef int64_t GLint64; +typedef struct __GLsync *GLsync; +typedef uint64_t GLuint64; +#endif +#if !defined(GL_EXT_timer_query) +typedef int64_t GLint64EXT; +typedef uint64_t GLuint64EXT; +#endif +#if !defined(GL_VERSION_1_5) +typedef intptr_t GLintptr; +typedef intptr_t GLsizeiptr; +#endif +#if !defined(GL_ARB_vertex_buffer_object) +typedef intptr_t GLintptrARB; +typedef intptr_t GLsizeiptrARB; +#endif + +#endif diff --git a/td-rs-base/src/lib.rs b/td-rs-base/src/lib.rs index 592ff24..273e7e3 100644 --- a/td-rs-base/src/lib.rs +++ b/td-rs-base/src/lib.rs @@ -1,609 +1,611 @@ -#![feature(associated_type_defaults)] -#![feature(min_specialization)] - -use crate::cxx::OP_Inputs; -pub use param::*; -#[cfg(feature = "python")] -pub use py::*; -#[cfg(feature = "python")] -use pyo3::prelude::*; -#[cfg(feature = "python")] -use pyo3::types::{IntoPyDict, PyTuple}; -#[cfg(feature = "python")] -use pyo3::BoundObject; -use std::ffi; -use std::ffi::c_int; -use std::fmt::Formatter; -use std::ops::Index; -use std::pin::Pin; -use std::sync::Mutex; - -#[cfg(feature = "tokio")] -pub static RUNTIME: std::sync::LazyLock = - std::sync::LazyLock::new(|| { - tokio_core::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .expect("Failed to create tokio runtime") - }); - -pub mod chop; -pub mod cxx; -pub mod dat; -pub mod param; -#[cfg(feature = "python")] -pub mod py; -pub mod sop; -pub mod top; - -static INFO_STR: Mutex = Mutex::new(String::new()); -static ERROR_STR: Mutex = Mutex::new(String::new()); -static WARNING_STR: Mutex = Mutex::new(String::new()); - -/// Metadata describing the operator plugin. -pub trait OpInfo { - /// The type of the operator. - const OPERATOR_TYPE: &'static str = ""; - /// The label of the operator. - const OPERATOR_LABEL: &'static str = ""; - /// The icon of the operator. - const OPERATOR_ICON: &'static str = ""; - /// The minimum number of inputs the operator accepts. - const MIN_INPUTS: usize = 0; - /// The maximum number of inputs the operator accepts. - const MAX_INPUTS: usize = 0; - /// The author name of the operator. - const AUTHOR_NAME: &'static str = ""; - /// The author email of the operator. - const AUTHOR_EMAIL: &'static str = ""; - /// The major version of the operator. - const MAJOR_VERSION: i32 = 0; - /// The minor version of the operator. - const MINOR_VERSION: i32 = 0; - /// Whether to cook on start. - const COOK_ON_START: bool = false; - /// Python callbacks DAT. - const PYTHON_CALLBACKS_DAT: &'static str = ""; -} - -pub trait InfoChop { - fn size(&self) -> usize; - - fn channel(&self, index: usize) -> (String, f32); -} - -pub trait InfoDat { - fn size(&self) -> (u32, u32); - - fn entry(&self, index: usize, entry_index: usize) -> String; -} - -pub trait OpNew { - fn new(info: NodeInfo) -> Self; -} - -/// Functionality for all operator plugin types. -/// This can commonly be left as the default implementation for most plugins. -pub trait Op { - fn params_mut(&mut self) -> Option> { - None - } - - fn info_dat(&self) -> Option> { - None - } - - fn info_chop(&self) -> Option> { - None - } - - fn set_info(&mut self, info: &str) { - INFO_STR.lock().unwrap().replace_range(.., info); - } - - fn info(&self) -> String { - INFO_STR.lock().unwrap().clone() - } - - fn set_error(&mut self, error: &str) { - ERROR_STR.lock().unwrap().replace_range(.., error); - } - - fn error(&self) -> String { - ERROR_STR.lock().unwrap().clone() - } - - fn set_warning(&mut self, warning: &str) { - WARNING_STR.lock().unwrap().replace_range(.., warning); - } - - fn warning(&self) -> String { - WARNING_STR.lock().unwrap().clone() - } - - fn pulse_pressed(&mut self, _name: &str) {} -} - -pub struct NodeInfo { - info: &'static cxx::OP_NodeInfo, -} - -impl NodeInfo { - pub fn new(info: &'static cxx::OP_NodeInfo) -> Self { - Self { info } - } - - pub fn context(&self) -> Context { - Context { - context: self.info.context, - } - } -} - -pub struct Context { - #[allow(dead_code)] - context: *mut cxx::OP_Context, -} - -impl Context { - #[cfg(feature = "python")] - pub fn call_python_callback<'py, F>( - &self, - py: Python<'py>, - callback: &str, - args: impl IntoPyObject<'py, Target = PyTuple>, - kwargs: Option<&Bound<'py, pyo3::types::PyDict>>, - f: F, - ) -> PyResult<()> - where - F: FnOnce(Python, &PyObject), - { - unsafe { - let callback = ffi::CString::new(callback)?; - let args = args.into_pyobject(py).map_err(Into::into)?.into_bound(); - let mut ctx = Pin::new_unchecked(&mut *self.context); - let op_tuple = ctx.createArgumentsTuple(autocxx::c_int(1), std::ptr::null_mut()); - let op_tuple = op_tuple as *mut pyo3::ffi::PyObject; - let op_tuple = PyObject::from_owned_ptr(py, op_tuple); - let op_tuple = op_tuple.downcast_bound::(py)?; - let op = op_tuple.get_item(0)?; - let mut args_elements = vec![op]; - - for args in args.iter() { - args_elements.push(args); - } - let args = PyTuple::new(py, &args_elements)?; - - let mut ctx = Pin::new_unchecked(&mut *self.context); - let args = args.as_ptr(); - let kwargs = kwargs.map(|kw| kw.as_ptr()).unwrap_or(std::ptr::null_mut()); - let res = ctx.callPythonCallback( - callback.as_ptr(), - args as *mut cxx::_object, - kwargs as *mut cxx::_object, - std::ptr::null_mut(), - ); - let res = res as *mut pyo3::ffi::PyObject; - let res = PyObject::from_owned_ptr(py, res); - f(py, &res); - Ok(()) - } - } -} - -impl std::fmt::Debug for NodeInfo { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "NodeInfo") - } -} - -/// Input to an operator, which can be used to get parameters, channels, -/// and other information. -pub struct OperatorInputs<'cook, Op> { - pub inputs: &'cook cxx::OP_Inputs, - _marker: std::marker::PhantomData, -} - -impl std::fmt::Debug for OperatorInputs<'_, T> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "OperatorInputs") - } -} - -impl<'cook, Op> OperatorInputs<'cook, Op> -where - Self: GetInput<'cook, Op>, -{ - /// Create a new operator input. This is only called by the operator. - pub fn new(inputs: &'cook crate::cxx::OP_Inputs) -> OperatorInputs<'cook, Op> { - Self { - inputs, - _marker: Default::default(), - } - } - - /// Get the parameters for this operator. - pub fn params(&self) -> ParamInputs { - ParamInputs::new(self.inputs) - } - - /// Get an input channel. - pub fn input(&self, index: usize) -> Option<&>::Input> - where - OperatorInputs<'cook, Op>: GetInput<'cook, Op>, - { - GetInput::input(self, index) - } - - /// Get the number of input channels. - pub fn num_inputs(&self) -> usize - where - OperatorInputs<'cook, Op>: GetInput<'cook, Op>, - { - GetInput::num_inputs(self) - } -} - -pub struct DynamicMenuInfo<'cook> { - pub menu_info: Pin<&'cook mut cxx::OP_BuildDynamicMenuInfo>, -} - -impl<'cook> DynamicMenuInfo<'cook> { - pub fn new(menu_info: Pin<&'cook mut cxx::OP_BuildDynamicMenuInfo>) -> Self { - Self { menu_info } - } - - pub fn param_name(&mut self) -> &str { - let name = cxx::getBuildDynamicMenuInfoNames(self.menu_info.as_mut()); - unsafe { ffi::CStr::from_ptr(name).to_str().unwrap() } - } - - pub fn add_menu_entry(&mut self, name: &str, label: &str) -> bool { - unsafe { - self.menu_info.as_mut().addMenuEntry( - ffi::CString::new(name).unwrap().into_raw(), - ffi::CString::new(label).unwrap().into_raw(), - ) - } - } -} - -/// Parameter inputs to an operator. -pub struct ParamInputs<'cook> { - inputs: &'cook crate::cxx::OP_Inputs, -} - -impl<'cook> ParamInputs<'cook> { - /// Create a new operator input. This is only called by the operator. - pub fn new(inputs: &'cook crate::cxx::OP_Inputs) -> ParamInputs<'cook> { - Self { inputs } - } - - /// Get a float parameter. - pub fn get_float(&self, name: &str, index: usize) -> f64 { - unsafe { - self.inputs - .getParDouble(ffi::CString::new(name).unwrap().into_raw(), index as i32) - } - } - - /// Get an integer parameter. - pub fn get_int(&self, name: &str, index: usize) -> i32 { - unsafe { - self.inputs - .getParInt(ffi::CString::new(name).unwrap().into_raw(), index as i32) - } - } - - /// Get a string parameter. - pub fn get_string(&self, name: &str) -> &str { - unsafe { - let res = self - .inputs - .getParString(ffi::CString::new(name).unwrap().into_raw()); - - if res.is_null() { - return ""; - } - - ffi::CStr::from_ptr(res).to_str().unwrap() - } - } - - /// Get a toggle parameter. - pub fn get_toggle(&self, name: &str) -> bool { - unsafe { - self.inputs - .getParInt(ffi::CString::new(name).unwrap().into_raw(), 0) - != 0 - } - } - - /// Enable or disable a parameter. - pub fn enable_param(&self, name: &str, enable: bool) { - unsafe { - self.inputs - .enablePar(ffi::CString::new(name).unwrap().into_raw(), enable); - } - } - - /// Get a chop parameter. - fn get_chop(&self, name: &str) -> ChopParam { - unsafe { - let chop = self - .inputs - .getParCHOP(ffi::CString::new(name).unwrap().into_raw()); - if chop.is_null() { - ChopParam { input: None } - } else { - ChopParam { input: Some(chop) } - } - } - } - - fn get_sop(&self, name: &str) -> SopParam { - unsafe { - let sop = self - .inputs - .getParSOP(ffi::CString::new(name).unwrap().into_raw()); - if sop.is_null() { - SopParam { input: None } - } else { - SopParam { input: Some(sop) } - } - } - } - - fn get_top(&self, name: &str) -> TopParam { - unsafe { - let top = self - .inputs - .getParTOP(ffi::CString::new(name).unwrap().into_raw()); - if top.is_null() { - TopParam { input: None } - } else { - TopParam { input: Some(top) } - } - } - } - - fn get_dat(&self, name: &str) -> DatParam { - unsafe { - let dat = self - .inputs - .getParDAT(ffi::CString::new(name).unwrap().into_raw()); - if dat.is_null() { - DatParam { input: None } - } else { - DatParam { input: Some(dat) } - } - } - } - - #[cfg(feature = "python")] - fn get_python(&self, name: &str) -> *mut pyo3::ffi::PyObject { - unsafe { - let python = self - .inputs - .getParPython(ffi::CString::new(name).unwrap().into_raw()); - if python.is_null() { - std::ptr::null_mut() - } else { - python as *mut pyo3::ffi::PyObject - } - } - } - - fn get_double_arr(&self, name: &str) -> [f64; N] { - assert!(N > 1 && N <= 4); - unsafe { - let mut arr = [0.0; N]; - let name = ffi::CString::new(name).unwrap().into_raw(); - match N { - 2 => { - let mut a = 0.0; - let mut b = 0.0; - self.inputs - .getParDouble2(name, Pin::new(&mut a), Pin::new(&mut b)); - arr[0] = a; - arr[1] = b; - } - 3 => { - let mut a = 0.0; - let mut b = 0.0; - let mut c = 0.0; - self.inputs.getParDouble3( - name, - Pin::new(&mut a), - Pin::new(&mut b), - Pin::new(&mut c), - ); - arr[0] = a; - arr[1] = b; - arr[2] = c; - } - 4 => { - let mut a = 0.0; - let mut b = 0.0; - let mut c = 0.0; - let mut d = 0.0; - self.inputs.getParDouble4( - name, - Pin::new(&mut a), - Pin::new(&mut b), - Pin::new(&mut c), - Pin::new(&mut d), - ); - arr[0] = a; - arr[1] = b; - arr[2] = c; - arr[3] = d; - } - _ => {} - }; - - arr - } - } - - fn get_int_arr(&self, name: &str) -> [i32; N] { - assert!(N > 1 && N <= 4); - unsafe { - let mut arr = [0; N]; - let name = ffi::CString::new(name).unwrap().into_raw(); - match N { - 2 => { - let mut a = 0; - let mut b = 0; - self.inputs - .getParInt2(name, Pin::new(&mut a), Pin::new(&mut b)); - arr[0] = a; - arr[1] = b; - } - 3 => { - let mut a = 0; - let mut b = 0; - let mut c = 0; - self.inputs.getParInt3( - name, - Pin::new(&mut a), - Pin::new(&mut b), - Pin::new(&mut c), - ); - arr[0] = a; - arr[1] = b; - arr[2] = c; - } - 4 => { - let mut a = 0; - let mut b = 0; - let mut c = 0; - let mut d = 0; - self.inputs.getParInt4( - name, - Pin::new(&mut a), - Pin::new(&mut b), - Pin::new(&mut c), - Pin::new(&mut d), - ); - arr[0] = a; - arr[1] = b; - arr[2] = c; - arr[3] = d; - } - _ => {} - }; - arr - } - } -} - -/// Get an input to an operator. -pub trait GetInput<'cook, Op>: Index { - /// The type of the input. - type Input = Op; - /// The number of inputs available. - fn num_inputs(&self) -> usize; - /// Get an input. - fn input(&self, index: usize) -> Option<&Self::Input>; -} - -impl<'cook, Op> Index for OperatorInputs<'cook, Op> -where - Self: GetInput<'cook, Op>, -{ - type Output = >::Input; - - fn index(&self, index: usize) -> &Self::Output { - self.input(index).expect("Invalid input index") - } -} - -#[cfg(not(feature = "python"))] -pub unsafe fn op_info(mut op_info: std::pin::Pin<&mut cxx::OP_CustomOPInfo>) { - let new_string = std::ffi::CString::new(T::OPERATOR_TYPE).unwrap(); - let new_string_ptr = new_string.as_ptr(); - cxx::setString(op_info.opType, new_string_ptr); - let new_string = std::ffi::CString::new(T::OPERATOR_LABEL).unwrap(); - let new_string_ptr = new_string.as_ptr(); - cxx::setString(op_info.opLabel, new_string_ptr); - let new_string = std::ffi::CString::new(T::OPERATOR_ICON).unwrap(); - let new_string_ptr = new_string.as_ptr(); - cxx::setString(op_info.opIcon, new_string_ptr); - op_info.minInputs = T::MIN_INPUTS as i32; - op_info.maxInputs = T::MAX_INPUTS as i32; - let new_string = std::ffi::CString::new(T::AUTHOR_NAME).unwrap(); - let new_string_ptr = new_string.as_ptr(); - cxx::setString(op_info.authorName, new_string_ptr); - let new_string = std::ffi::CString::new(T::AUTHOR_EMAIL).unwrap(); - let new_string_ptr = new_string.as_ptr(); - cxx::setString(op_info.authorEmail, new_string_ptr); - op_info.majorVersion = T::MAJOR_VERSION; - op_info.minorVersion = T::MINOR_VERSION; - op_info.cookOnStart = T::COOK_ON_START; - let callbacks = std::ffi::CString::new(T::PYTHON_CALLBACKS_DAT).unwrap(); - op_info.pythonCallbacksDAT = callbacks.as_ptr(); - std::mem::forget(callbacks); // Callbacks are static -} - -#[cfg(feature = "python")] -pub unsafe fn op_info( - mut op_info: std::pin::Pin<&mut cxx::OP_CustomOPInfo>, -) { - let new_string = std::ffi::CString::new(T::OPERATOR_TYPE).unwrap(); - let new_string_ptr = new_string.as_ptr(); - cxx::setString(op_info.opType, new_string_ptr); - let new_string = std::ffi::CString::new(T::OPERATOR_LABEL).unwrap(); - let new_string_ptr = new_string.as_ptr(); - cxx::setString(op_info.opLabel, new_string_ptr); - let new_string = std::ffi::CString::new(T::OPERATOR_ICON).unwrap(); - let new_string_ptr = new_string.as_ptr(); - cxx::setString(op_info.opIcon, new_string_ptr); - op_info.minInputs = T::MIN_INPUTS as i32; - op_info.maxInputs = T::MAX_INPUTS as i32; - let new_string = std::ffi::CString::new(T::AUTHOR_NAME).unwrap(); - let new_string_ptr = new_string.as_ptr(); - cxx::setString(op_info.authorName, new_string_ptr); - let new_string = std::ffi::CString::new(T::AUTHOR_EMAIL).unwrap(); - let new_string_ptr = new_string.as_ptr(); - cxx::setString(op_info.authorEmail, new_string_ptr); - op_info.majorVersion = T::MAJOR_VERSION; - op_info.minorVersion = T::MINOR_VERSION; - op_info.cookOnStart = T::COOK_ON_START; - let callbacks = std::ffi::CString::new(T::PYTHON_CALLBACKS_DAT).unwrap(); - op_info.pythonCallbacksDAT = callbacks.as_ptr(); - std::mem::forget(callbacks); // Callbacks are static - py::py_op_info::(op_info); -} - -/// Base functionality for all operator types. -pub fn op_init() { - #[cfg(feature = "tracing")] - { - use tracing_subscriber::fmt; - use tracing_subscriber::layer::SubscriberExt; - use tracing_subscriber::util::{SubscriberInitExt, TryInitError}; - use tracing_subscriber::EnvFilter; - - let fmt_layer = if cfg!(target_os = "windows") { - let mut f = fmt::layer(); - f.set_ansi(false); - f - } else { - fmt::layer() - }; - let init = tracing_subscriber::registry() - .with(fmt_layer) - .with(EnvFilter::from_default_env()) - .try_init(); - match init { - Ok(_) => {} - Err(err) => match err { - TryInitError { .. } => {} - _ => { - eprintln!("Failed to initialize tracing: {}", err); - } - }, - } - } -} +#![feature(associated_type_defaults)] +#![feature(min_specialization)] + +use crate::cxx::OP_Inputs; +pub use param::*; +#[cfg(feature = "python")] +pub use py::*; +#[cfg(feature = "python")] +use pyo3::prelude::*; +#[cfg(feature = "python")] +use pyo3::types::{IntoPyDict, PyTuple}; +#[cfg(feature = "python")] +use pyo3::BoundObject; +use std::ffi; +use std::ffi::c_int; +use std::fmt::Formatter; +use std::ops::Index; +use std::pin::Pin; +use std::sync::Mutex; + +#[cfg(feature = "tokio")] +pub static RUNTIME: std::sync::LazyLock = + std::sync::LazyLock::new(|| { + tokio_core::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .expect("Failed to create tokio runtime") + }); + +pub mod chop; +#[cfg(feature = "cuda")] +pub mod cuda; +pub mod cxx; +pub mod dat; +pub mod param; +#[cfg(feature = "python")] +pub mod py; +pub mod sop; +pub mod top; + +static INFO_STR: Mutex = Mutex::new(String::new()); +static ERROR_STR: Mutex = Mutex::new(String::new()); +static WARNING_STR: Mutex = Mutex::new(String::new()); + +/// Metadata describing the operator plugin. +pub trait OpInfo { + /// The type of the operator. + const OPERATOR_TYPE: &'static str = ""; + /// The label of the operator. + const OPERATOR_LABEL: &'static str = ""; + /// The icon of the operator. + const OPERATOR_ICON: &'static str = ""; + /// The minimum number of inputs the operator accepts. + const MIN_INPUTS: usize = 0; + /// The maximum number of inputs the operator accepts. + const MAX_INPUTS: usize = 0; + /// The author name of the operator. + const AUTHOR_NAME: &'static str = ""; + /// The author email of the operator. + const AUTHOR_EMAIL: &'static str = ""; + /// The major version of the operator. + const MAJOR_VERSION: i32 = 0; + /// The minor version of the operator. + const MINOR_VERSION: i32 = 0; + /// Whether to cook on start. + const COOK_ON_START: bool = false; + /// Python callbacks DAT. + const PYTHON_CALLBACKS_DAT: &'static str = ""; +} + +pub trait InfoChop { + fn size(&self) -> usize; + + fn channel(&self, index: usize) -> (String, f32); +} + +pub trait InfoDat { + fn size(&self) -> (u32, u32); + + fn entry(&self, index: usize, entry_index: usize) -> String; +} + +pub trait OpNew { + fn new(info: NodeInfo) -> Self; +} + +/// Functionality for all operator plugin types. +/// This can commonly be left as the default implementation for most plugins. +pub trait Op { + fn params_mut(&mut self) -> Option> { + None + } + + fn info_dat(&self) -> Option> { + None + } + + fn info_chop(&self) -> Option> { + None + } + + fn set_info(&mut self, info: &str) { + INFO_STR.lock().unwrap().replace_range(.., info); + } + + fn info(&self) -> String { + INFO_STR.lock().unwrap().clone() + } + + fn set_error(&mut self, error: &str) { + ERROR_STR.lock().unwrap().replace_range(.., error); + } + + fn error(&self) -> String { + ERROR_STR.lock().unwrap().clone() + } + + fn set_warning(&mut self, warning: &str) { + WARNING_STR.lock().unwrap().replace_range(.., warning); + } + + fn warning(&self) -> String { + WARNING_STR.lock().unwrap().clone() + } + + fn pulse_pressed(&mut self, _name: &str) {} +} + +pub struct NodeInfo { + info: &'static cxx::OP_NodeInfo, +} + +impl NodeInfo { + pub fn new(info: &'static cxx::OP_NodeInfo) -> Self { + Self { info } + } + + pub fn context(&self) -> Context { + Context { + context: self.info.context, + } + } +} + +pub struct Context { + #[allow(dead_code)] + context: *mut cxx::OP_Context, +} + +impl Context { + #[cfg(feature = "python")] + pub fn call_python_callback<'py, F>( + &self, + py: Python<'py>, + callback: &str, + args: impl IntoPyObject<'py, Target = PyTuple>, + kwargs: Option<&Bound<'py, pyo3::types::PyDict>>, + f: F, + ) -> PyResult<()> + where + F: FnOnce(Python, &PyObject), + { + unsafe { + let callback = ffi::CString::new(callback)?; + let args = args.into_pyobject(py).map_err(Into::into)?.into_bound(); + let mut ctx = Pin::new_unchecked(&mut *self.context); + let op_tuple = ctx.createArgumentsTuple(autocxx::c_int(1), std::ptr::null_mut()); + let op_tuple = op_tuple as *mut pyo3::ffi::PyObject; + let op_tuple = PyObject::from_owned_ptr(py, op_tuple); + let op_tuple = op_tuple.downcast_bound::(py)?; + let op = op_tuple.get_item(0)?; + let mut args_elements = vec![op]; + + for args in args.iter() { + args_elements.push(args); + } + let args = PyTuple::new(py, &args_elements)?; + + let mut ctx = Pin::new_unchecked(&mut *self.context); + let args = args.as_ptr(); + let kwargs = kwargs.map(|kw| kw.as_ptr()).unwrap_or(std::ptr::null_mut()); + let res = ctx.callPythonCallback( + callback.as_ptr(), + args as *mut cxx::_object, + kwargs as *mut cxx::_object, + std::ptr::null_mut(), + ); + let res = res as *mut pyo3::ffi::PyObject; + let res = PyObject::from_owned_ptr(py, res); + f(py, &res); + Ok(()) + } + } +} + +impl std::fmt::Debug for NodeInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "NodeInfo") + } +} + +/// Input to an operator, which can be used to get parameters, channels, +/// and other information. +pub struct OperatorInputs<'cook, Op> { + pub inputs: &'cook cxx::OP_Inputs, + _marker: std::marker::PhantomData, +} + +impl std::fmt::Debug for OperatorInputs<'_, T> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "OperatorInputs") + } +} + +impl<'cook, Op> OperatorInputs<'cook, Op> +where + Self: GetInput<'cook, Op>, +{ + /// Create a new operator input. This is only called by the operator. + pub fn new(inputs: &'cook crate::cxx::OP_Inputs) -> OperatorInputs<'cook, Op> { + Self { + inputs, + _marker: Default::default(), + } + } + + /// Get the parameters for this operator. + pub fn params(&self) -> ParamInputs { + ParamInputs::new(self.inputs) + } + + /// Get an input channel. + pub fn input(&self, index: usize) -> Option<&>::Input> + where + OperatorInputs<'cook, Op>: GetInput<'cook, Op>, + { + GetInput::input(self, index) + } + + /// Get the number of input channels. + pub fn num_inputs(&self) -> usize + where + OperatorInputs<'cook, Op>: GetInput<'cook, Op>, + { + GetInput::num_inputs(self) + } +} + +pub struct DynamicMenuInfo<'cook> { + pub menu_info: Pin<&'cook mut cxx::OP_BuildDynamicMenuInfo>, +} + +impl<'cook> DynamicMenuInfo<'cook> { + pub fn new(menu_info: Pin<&'cook mut cxx::OP_BuildDynamicMenuInfo>) -> Self { + Self { menu_info } + } + + pub fn param_name(&mut self) -> &str { + let name = cxx::getBuildDynamicMenuInfoNames(self.menu_info.as_mut()); + unsafe { ffi::CStr::from_ptr(name).to_str().unwrap() } + } + + pub fn add_menu_entry(&mut self, name: &str, label: &str) -> bool { + unsafe { + self.menu_info.as_mut().addMenuEntry( + ffi::CString::new(name).unwrap().into_raw(), + ffi::CString::new(label).unwrap().into_raw(), + ) + } + } +} + +/// Parameter inputs to an operator. +pub struct ParamInputs<'cook> { + inputs: &'cook crate::cxx::OP_Inputs, +} + +impl<'cook> ParamInputs<'cook> { + /// Create a new operator input. This is only called by the operator. + pub fn new(inputs: &'cook crate::cxx::OP_Inputs) -> ParamInputs<'cook> { + Self { inputs } + } + + /// Get a float parameter. + pub fn get_float(&self, name: &str, index: usize) -> f64 { + unsafe { + self.inputs + .getParDouble(ffi::CString::new(name).unwrap().into_raw(), index as i32) + } + } + + /// Get an integer parameter. + pub fn get_int(&self, name: &str, index: usize) -> i32 { + unsafe { + self.inputs + .getParInt(ffi::CString::new(name).unwrap().into_raw(), index as i32) + } + } + + /// Get a string parameter. + pub fn get_string(&self, name: &str) -> &str { + unsafe { + let res = self + .inputs + .getParString(ffi::CString::new(name).unwrap().into_raw()); + + if res.is_null() { + return ""; + } + + ffi::CStr::from_ptr(res).to_str().unwrap() + } + } + + /// Get a toggle parameter. + pub fn get_toggle(&self, name: &str) -> bool { + unsafe { + self.inputs + .getParInt(ffi::CString::new(name).unwrap().into_raw(), 0) + != 0 + } + } + + /// Enable or disable a parameter. + pub fn enable_param(&self, name: &str, enable: bool) { + unsafe { + self.inputs + .enablePar(ffi::CString::new(name).unwrap().into_raw(), enable); + } + } + + /// Get a chop parameter. + fn get_chop(&self, name: &str) -> ChopParam { + unsafe { + let chop = self + .inputs + .getParCHOP(ffi::CString::new(name).unwrap().into_raw()); + if chop.is_null() { + ChopParam { input: None } + } else { + ChopParam { input: Some(chop) } + } + } + } + + fn get_sop(&self, name: &str) -> SopParam { + unsafe { + let sop = self + .inputs + .getParSOP(ffi::CString::new(name).unwrap().into_raw()); + if sop.is_null() { + SopParam { input: None } + } else { + SopParam { input: Some(sop) } + } + } + } + + fn get_top(&self, name: &str) -> TopParam { + unsafe { + let top = self + .inputs + .getParTOP(ffi::CString::new(name).unwrap().into_raw()); + if top.is_null() { + TopParam { input: None } + } else { + TopParam { input: Some(top) } + } + } + } + + fn get_dat(&self, name: &str) -> DatParam { + unsafe { + let dat = self + .inputs + .getParDAT(ffi::CString::new(name).unwrap().into_raw()); + if dat.is_null() { + DatParam { input: None } + } else { + DatParam { input: Some(dat) } + } + } + } + + #[cfg(feature = "python")] + fn get_python(&self, name: &str) -> *mut pyo3::ffi::PyObject { + unsafe { + let python = self + .inputs + .getParPython(ffi::CString::new(name).unwrap().into_raw()); + if python.is_null() { + std::ptr::null_mut() + } else { + python as *mut pyo3::ffi::PyObject + } + } + } + + fn get_double_arr(&self, name: &str) -> [f64; N] { + assert!(N > 1 && N <= 4); + unsafe { + let mut arr = [0.0; N]; + let name = ffi::CString::new(name).unwrap().into_raw(); + match N { + 2 => { + let mut a = 0.0; + let mut b = 0.0; + self.inputs + .getParDouble2(name, Pin::new(&mut a), Pin::new(&mut b)); + arr[0] = a; + arr[1] = b; + } + 3 => { + let mut a = 0.0; + let mut b = 0.0; + let mut c = 0.0; + self.inputs.getParDouble3( + name, + Pin::new(&mut a), + Pin::new(&mut b), + Pin::new(&mut c), + ); + arr[0] = a; + arr[1] = b; + arr[2] = c; + } + 4 => { + let mut a = 0.0; + let mut b = 0.0; + let mut c = 0.0; + let mut d = 0.0; + self.inputs.getParDouble4( + name, + Pin::new(&mut a), + Pin::new(&mut b), + Pin::new(&mut c), + Pin::new(&mut d), + ); + arr[0] = a; + arr[1] = b; + arr[2] = c; + arr[3] = d; + } + _ => {} + }; + + arr + } + } + + fn get_int_arr(&self, name: &str) -> [i32; N] { + assert!(N > 1 && N <= 4); + unsafe { + let mut arr = [0; N]; + let name = ffi::CString::new(name).unwrap().into_raw(); + match N { + 2 => { + let mut a = 0; + let mut b = 0; + self.inputs + .getParInt2(name, Pin::new(&mut a), Pin::new(&mut b)); + arr[0] = a; + arr[1] = b; + } + 3 => { + let mut a = 0; + let mut b = 0; + let mut c = 0; + self.inputs.getParInt3( + name, + Pin::new(&mut a), + Pin::new(&mut b), + Pin::new(&mut c), + ); + arr[0] = a; + arr[1] = b; + arr[2] = c; + } + 4 => { + let mut a = 0; + let mut b = 0; + let mut c = 0; + let mut d = 0; + self.inputs.getParInt4( + name, + Pin::new(&mut a), + Pin::new(&mut b), + Pin::new(&mut c), + Pin::new(&mut d), + ); + arr[0] = a; + arr[1] = b; + arr[2] = c; + arr[3] = d; + } + _ => {} + }; + arr + } + } +} + +/// Get an input to an operator. +pub trait GetInput<'cook, Op>: Index { + /// The type of the input. + type Input = Op; + /// The number of inputs available. + fn num_inputs(&self) -> usize; + /// Get an input. + fn input(&self, index: usize) -> Option<&Self::Input>; +} + +impl<'cook, Op> Index for OperatorInputs<'cook, Op> +where + Self: GetInput<'cook, Op>, +{ + type Output = >::Input; + + fn index(&self, index: usize) -> &Self::Output { + self.input(index).expect("Invalid input index") + } +} + +#[cfg(not(feature = "python"))] +pub unsafe fn op_info(mut op_info: std::pin::Pin<&mut cxx::OP_CustomOPInfo>) { + let new_string = std::ffi::CString::new(T::OPERATOR_TYPE).unwrap(); + let new_string_ptr = new_string.as_ptr(); + cxx::setString(op_info.opType, new_string_ptr); + let new_string = std::ffi::CString::new(T::OPERATOR_LABEL).unwrap(); + let new_string_ptr = new_string.as_ptr(); + cxx::setString(op_info.opLabel, new_string_ptr); + let new_string = std::ffi::CString::new(T::OPERATOR_ICON).unwrap(); + let new_string_ptr = new_string.as_ptr(); + cxx::setString(op_info.opIcon, new_string_ptr); + op_info.minInputs = T::MIN_INPUTS as i32; + op_info.maxInputs = T::MAX_INPUTS as i32; + let new_string = std::ffi::CString::new(T::AUTHOR_NAME).unwrap(); + let new_string_ptr = new_string.as_ptr(); + cxx::setString(op_info.authorName, new_string_ptr); + let new_string = std::ffi::CString::new(T::AUTHOR_EMAIL).unwrap(); + let new_string_ptr = new_string.as_ptr(); + cxx::setString(op_info.authorEmail, new_string_ptr); + op_info.majorVersion = T::MAJOR_VERSION; + op_info.minorVersion = T::MINOR_VERSION; + op_info.cookOnStart = T::COOK_ON_START; + let callbacks = std::ffi::CString::new(T::PYTHON_CALLBACKS_DAT).unwrap(); + op_info.pythonCallbacksDAT = callbacks.as_ptr(); + std::mem::forget(callbacks); // Callbacks are static +} + +#[cfg(feature = "python")] +pub unsafe fn op_info( + mut op_info: std::pin::Pin<&mut cxx::OP_CustomOPInfo>, +) { + let new_string = std::ffi::CString::new(T::OPERATOR_TYPE).unwrap(); + let new_string_ptr = new_string.as_ptr(); + cxx::setString(op_info.opType, new_string_ptr); + let new_string = std::ffi::CString::new(T::OPERATOR_LABEL).unwrap(); + let new_string_ptr = new_string.as_ptr(); + cxx::setString(op_info.opLabel, new_string_ptr); + let new_string = std::ffi::CString::new(T::OPERATOR_ICON).unwrap(); + let new_string_ptr = new_string.as_ptr(); + cxx::setString(op_info.opIcon, new_string_ptr); + op_info.minInputs = T::MIN_INPUTS as i32; + op_info.maxInputs = T::MAX_INPUTS as i32; + let new_string = std::ffi::CString::new(T::AUTHOR_NAME).unwrap(); + let new_string_ptr = new_string.as_ptr(); + cxx::setString(op_info.authorName, new_string_ptr); + let new_string = std::ffi::CString::new(T::AUTHOR_EMAIL).unwrap(); + let new_string_ptr = new_string.as_ptr(); + cxx::setString(op_info.authorEmail, new_string_ptr); + op_info.majorVersion = T::MAJOR_VERSION; + op_info.minorVersion = T::MINOR_VERSION; + op_info.cookOnStart = T::COOK_ON_START; + let callbacks = std::ffi::CString::new(T::PYTHON_CALLBACKS_DAT).unwrap(); + op_info.pythonCallbacksDAT = callbacks.as_ptr(); + std::mem::forget(callbacks); // Callbacks are static + py::py_op_info::(op_info); +} + +/// Base functionality for all operator types. +pub fn op_init() { + #[cfg(feature = "tracing")] + { + use tracing_subscriber::fmt; + use tracing_subscriber::layer::SubscriberExt; + use tracing_subscriber::util::{SubscriberInitExt, TryInitError}; + use tracing_subscriber::EnvFilter; + + let fmt_layer = if cfg!(target_os = "windows") { + let mut f = fmt::layer(); + f.set_ansi(false); + f + } else { + fmt::layer() + }; + let init = tracing_subscriber::registry() + .with(fmt_layer) + .with(EnvFilter::from_default_env()) + .try_init(); + match init { + Ok(_) => {} + Err(err) => match err { + TryInitError { .. } => {} + _ => { + eprintln!("Failed to initialize tracing: {}", err); + } + }, + } + } +} diff --git a/td-rs-base/src/param.rs b/td-rs-base/src/param.rs index 941fbc6..8b57f35 100644 --- a/td-rs-base/src/param.rs +++ b/td-rs-base/src/param.rs @@ -1,731 +1,731 @@ -use crate::chop::ChopInput; -use crate::sop::{Color, SopInput}; -use crate::{cxx, ParamInputs}; -use ref_cast::RefCast; -use std::ffi; -use std::ffi::{c_char, CString}; -use std::ops::{Deref, DerefMut}; -use std::path::PathBuf; -use std::pin::Pin; - -/// A numeric parameter. -// TODO: switch to enum to describe parameter types -#[derive(Debug)] -pub struct NumericParameter { - /// The name of the parameter. - pub name: String, - /// The label of the parameter. - pub label: String, - /// The page of the parameter. - pub page: String, - - /// The default values of the parameter. - pub default_values: [f64; 4], - /// The minimum values of the parameter. - pub min_values: [f64; 4], - /// The maximum values of the parameter. - pub max_values: [f64; 4], - /// Whether to clamp the minimum values of the parameter. - pub clamp_mins: [bool; 4], - /// Whether to clamp the maximum values of the parameter. - pub clamp_maxes: [bool; 4], - /// The minimum slider values of the parameter. - pub min_sliders: [f64; 4], - /// The maximum slider values of the parameter. - pub max_sliders: [f64; 4], -} - -impl Default for NumericParameter { - fn default() -> Self { - Self { - name: "".to_string(), - label: "".to_string(), - page: "".to_string(), - default_values: [0.0; 4], - min_values: [0.0; 4], - max_values: [1.0; 4], - clamp_mins: [false; 4], - clamp_maxes: [false; 4], - min_sliders: [0.0; 4], - max_sliders: [1.0; 4], - } - } -} - -/// Trait for defining operator parameters. -pub trait OperatorParams { - /// Register parameters with the parameter manager. - fn register(&mut self, parameter_manager: &mut ParameterManager); - /// Update parameters from operator input. - fn update(&mut self, inputs: &ParamInputs); -} - -impl From for cxx::OP_NumericParameter { - fn from(param: NumericParameter) -> Self { - cxx::OP_NumericParameter { - name: ffi::CString::new(param.name).unwrap().into_raw(), - label: ffi::CString::new(param.label).unwrap().into_raw(), - page: ffi::CString::new(param.page).unwrap().into_raw(), - defaultValues: param.default_values, - minValues: param.min_values, - maxValues: param.max_values, - clampMins: param.clamp_mins, - clampMaxes: param.clamp_maxes, - minSliders: param.min_sliders, - maxSliders: param.max_sliders, - reserved: Default::default(), - } - } -} - -/// A string parameter. -#[derive(Debug, Default)] -pub struct StringParameter { - /// The name of the parameter. - pub name: String, - /// The label of the parameter. - pub label: String, - /// The page of the parameter. - pub page: String, - /// The default value of the parameter. - pub default_value: String, -} - -impl From for cxx::OP_StringParameter { - fn from(param: StringParameter) -> Self { - cxx::OP_StringParameter { - name: ffi::CString::new(param.name).unwrap().into_raw(), - label: ffi::CString::new(param.label).unwrap().into_raw(), - page: ffi::CString::new(param.page).unwrap().into_raw(), - defaultValue: ffi::CString::new(param.default_value).unwrap().into_raw(), - reserved: Default::default(), - } - } -} - -/// Manager for registering parameters with TouchDesigner. -pub struct ParameterManager<'cook> { - manager: Pin<&'cook mut crate::cxx::OP_ParameterManager>, -} - -impl<'cook> ParameterManager<'cook> { - /// Create a new parameter manager. Should not be called by - /// users. - pub fn new( - manager: Pin<&'cook mut crate::cxx::OP_ParameterManager>, - ) -> ParameterManager<'cook> { - Self { manager } - } - - /// Append a float parameter. - pub fn append_float(&mut self, param: NumericParameter) { - let param = param.into(); - self.manager.as_mut().appendFloat(¶m, 1); - } - - /// Append a pulse parameter. - pub fn append_pulse(&mut self, param: NumericParameter) { - let param = param.into(); - self.manager.as_mut().appendPulse(¶m); - } - - /// Append an integer parameter. - pub fn append_int(&mut self, param: NumericParameter) { - let param = param.into(); - self.manager.as_mut().appendInt(¶m, 1); - } - - /// Append an xy parameter. - pub fn append_xy(&mut self, param: NumericParameter) { - let param = param.into(); - self.manager.as_mut().appendXY(¶m); - } - - /// Append an xyz parameter. - pub fn append_xyz(&mut self, param: NumericParameter) { - let param = param.into(); - self.manager.as_mut().appendXYZ(¶m); - } - - /// Append a uv parameter. - pub fn append_uv(&mut self, param: NumericParameter) { - let param = param.into(); - self.manager.as_mut().appendUV(¶m); - } - - /// Append a uvw parameter. - pub fn append_uvw(&mut self, param: NumericParameter) { - let param = param.into(); - self.manager.as_mut().appendUVW(¶m); - } - - /// Append a rgb parameter. - pub fn append_rgb(&mut self, param: NumericParameter) { - let param = param.into(); - self.manager.as_mut().appendRGB(¶m); - } - - /// Append a rgba parameter. - pub fn append_rgba(&mut self, param: NumericParameter) { - let param = param.into(); - self.manager.as_mut().appendRGBA(¶m); - } - - /// Append a toggle parameter. - pub fn append_toggle(&mut self, param: NumericParameter) { - let param = param.into(); - self.manager.as_mut().appendToggle(¶m); - } - - /// Append a string parameter. - pub fn append_string(&mut self, param: StringParameter) { - let param = param.into(); - self.manager.as_mut().appendString(¶m); - } - - /// Append a file parameter. - pub fn append_file(&mut self, param: StringParameter) { - let param = param.into(); - self.manager.as_mut().appendFile(¶m); - } - - /// Append a folder parameter. - pub fn append_folder(&mut self, param: StringParameter) { - let param = param.into(); - self.manager.as_mut().appendFolder(¶m); - } - - /// Append a dat reference parameter. - pub fn append_dat(&mut self, param: StringParameter) { - let param = param.into(); - self.manager.as_mut().appendDAT(¶m); - } - - /// Append a chop reference parameter. - pub fn append_chop(&mut self, param: StringParameter) { - let param = param.into(); - self.manager.as_mut().appendCHOP(¶m); - } - - /// Append a top reference parameter. - pub fn append_top(&mut self, param: StringParameter) { - let param = param.into(); - self.manager.as_mut().appendTOP(¶m); - } - - /// Append an object reference parameter. - pub fn append_object(&mut self, param: StringParameter) { - let param = param.into(); - self.manager.as_mut().appendObject(¶m); - } - - pub fn append_menu(&mut self, param: StringParameter, names: &[String], labels: &[String]) { - assert_eq!(names.len(), labels.len()); - let n_items = names.len() as i32; - let c_strings: Vec = names - .iter() - .map(|s| CString::new(s.as_bytes()).unwrap()) - .collect(); - - let name_ptrs: Vec<*const c_char> = c_strings.iter().map(|cs| cs.as_ptr()).collect(); - let names: *mut *const c_char = name_ptrs.as_ptr() as *mut *const c_char; - - let c_strings: Vec = labels - .iter() - .map(|s| CString::new(s.as_bytes()).unwrap()) - .collect(); - - let label_ptrs: Vec<*const c_char> = c_strings.iter().map(|cs| cs.as_ptr()).collect(); - let labels: *mut *const c_char = label_ptrs.as_ptr() as *mut *const c_char; - - let param = param.into(); - unsafe { - self.manager - .as_mut() - .appendMenu(¶m, n_items, names, labels); - } - } - - // pub fn append_string_menu(&mut self, param: StringParameter, names: &[&str], labels: &[&str]) { - // self.manager.as_mut().appendStringMenu(¶m, names.len(), names.as_ptr(), labels.as_ptr()); - // } - - /// Append a sop reference parameter. - pub fn append_sop(&mut self, param: StringParameter) { - let param = param.into(); - self.manager.as_mut().appendSOP(¶m); - } - - /// Append a python parameter. - pub fn append_python(&mut self, param: StringParameter) { - let param = param.into(); - self.manager.as_mut().appendPython(¶m); - } - - /// Append an op reference parameter. - pub fn append_op(&mut self, param: StringParameter) { - let param = param.into(); - self.manager.as_mut().appendOP(¶m); - } - - /// Append a comp reference parameter. - pub fn append_comp(&mut self, param: StringParameter) { - let param = param.into(); - self.manager.as_mut().appendCOMP(¶m); - } - - /// Append a mat reference parameter. - pub fn append_mat(&mut self, param: StringParameter) { - let param = param.into(); - self.manager.as_mut().appendMAT(¶m); - } - - /// Append a panel comp parameter. - pub fn append_panel_comp(&mut self, param: StringParameter) { - let param = param.into(); - self.manager.as_mut().appendPanelCOMP(¶m); - } - - /// Append a header parameter. - pub fn append_header(&mut self, param: StringParameter) { - let param = param.into(); - self.manager.as_mut().appendHeader(¶m); - } - - /// Append a momentary parameter. - pub fn append_momentary(&mut self, param: NumericParameter) { - let param = param.into(); - self.manager.as_mut().appendMomentary(¶m); - } - - /// Append a wh parameter. - pub fn append_wh(&mut self, param: NumericParameter) { - let param = param.into(); - self.manager.as_mut().appendWH(¶m); - } - - /// Append a dynamic menu parameter. - pub fn append_dynamic_menu(&mut self, param: StringParameter) { - let param = param.into(); - self.manager.as_mut().appendDynamicStringMenu(¶m); - } -} - -/// Options for creating parameters in derive macro. -/// Not intended for direct use. -#[derive(Debug)] -pub struct ParamOptions { - pub name: String, - pub label: String, - pub page: String, - pub min: f64, - pub max: f64, - pub min_slider: f64, - pub max_slider: f64, - pub clamp: bool, - pub default: f64, -} - -impl From for NumericParameter { - fn from(options: ParamOptions) -> Self { - NumericParameter { - name: options.name, - label: options.label, - page: options.page, - default_values: [options.default; 4], - min_values: [options.min; 4], - max_values: [options.max; 4], - clamp_mins: [options.clamp; 4], - clamp_maxes: [options.clamp; 4], - min_sliders: [options.min_slider; 4], - max_sliders: [options.max_slider; 4], - } - } -} - -impl From for StringParameter { - fn from(options: ParamOptions) -> Self { - StringParameter { - name: options.name, - label: options.label, - page: options.page, - ..Default::default() - } - } -} - -/// Trait for implementing parameter types. -pub trait Param { - /// Register parameter with the parameter manager. - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager); - /// Update parameter from operator input. - fn update(&mut self, name: &str, inputs: &ParamInputs); -} - -macro_rules! impl_param_int { - ( $t:ty ) => { - impl Param for $t { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let mut param: NumericParameter = options.into(); - param.default_values = [*self as f64, 0.0, 0.0, 0.0]; - parameter_manager.append_int(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - *self = inputs.get_int(name, 0) as $t; - } - } - }; -} - -impl_param_int!(i8); -impl_param_int!(i16); -impl_param_int!(i32); -impl_param_int!(i64); -impl_param_int!(i128); -impl_param_int!(isize); -impl_param_int!(u8); -impl_param_int!(u16); -impl_param_int!(u32); -impl_param_int!(u64); -impl_param_int!(u128); -impl_param_int!(usize); - -macro_rules! impl_param_float { - ( $t:ty ) => { - impl Param for $t { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let mut param: NumericParameter = options.into(); - param.default_values = [*self as f64, 0.0, 0.0, 0.0]; - parameter_manager.append_float(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - *self = inputs.get_float(name, 0) as $t; - } - } - }; -} - -impl_param_float!(f32); -impl_param_float!(f64); - -impl Param for String { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let mut param: StringParameter = options.into(); - param.default_value = self.clone(); - parameter_manager.append_string(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - *self = inputs.get_string(name).to_string(); - } -} - -impl Param for rgb::RGB8 { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let mut param: NumericParameter = options.into(); - param.default_values = [self.r as f64, self.g as f64, self.b as f64, 0.0]; - parameter_manager.append_rgb(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - *self = rgb::RGB8::new( - inputs.get_int(name, 0) as u8, - inputs.get_int(name, 1) as u8, - inputs.get_int(name, 2) as u8, - ); - } -} - -impl Param for rgb::RGB16 { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let mut param: NumericParameter = options.into(); - param.default_values = [self.r as f64, self.g as f64, self.b as f64, 0.0]; - parameter_manager.append_rgb(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - *self = rgb::RGB16::new( - inputs.get_int(name, 0) as u16, - inputs.get_int(name, 1) as u16, - inputs.get_int(name, 2) as u16, - ); - } -} - -impl Param for rgb::RGBA8 { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let mut param: NumericParameter = options.into(); - param.default_values = [self.r as f64, self.g as f64, self.b as f64, self.a as f64]; - parameter_manager.append_rgba(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - *self = rgb::RGBA8::new( - inputs.get_int(name, 0) as u8, - inputs.get_int(name, 1) as u8, - inputs.get_int(name, 2) as u8, - inputs.get_int(name, 3) as u8, - ); - } -} - -impl Param for rgb::RGBA16 { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let mut param: NumericParameter = options.into(); - param.default_values = [self.r as f64, self.g as f64, self.b as f64, self.a as f64]; - parameter_manager.append_rgba(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - *self = rgb::RGBA16::new( - inputs.get_int(name, 0) as u16, - inputs.get_int(name, 1) as u16, - inputs.get_int(name, 2) as u16, - inputs.get_int(name, 3) as u16, - ); - } -} - -/// A parameter wrapping a `PathBuf` that will be registered as a folder parameter. -pub struct FolderParam(PathBuf); - -impl Deref for FolderParam { - type Target = PathBuf; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for FolderParam { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl Param for FolderParam { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let mut param: StringParameter = options.into(); - param.default_value = self.to_string_lossy().to_string(); - parameter_manager.append_folder(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - self.0 = PathBuf::from(inputs.get_string(name)); - } -} - -/// A parameter wrapping a `PathBuf` that will be registered as a file parameter. -#[derive(Default, Clone, Debug)] -pub struct FileParam(PathBuf); - -impl Deref for FileParam { - type Target = PathBuf; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for FileParam { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl Param for FileParam { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let mut param: StringParameter = options.into(); - param.default_value = self.to_string_lossy().to_string(); - parameter_manager.append_file(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - self.0 = PathBuf::from(inputs.get_string(name)); - } -} - -impl Param for PathBuf { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let mut param: StringParameter = options.into(); - param.default_value = self.to_string_lossy().to_string(); - parameter_manager.append_file(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - *self = PathBuf::from(inputs.get_string(name)); - } -} - -impl Param for bool { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let mut param: NumericParameter = options.into(); - param.default_values[0] = true as usize as f64; - parameter_manager.append_toggle(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - *self = inputs.get_toggle(name); - } -} - -#[derive(Default, Debug, Clone, Copy)] -pub struct Pulse; - -impl Param for Pulse { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let param: NumericParameter = options.into(); - parameter_manager.append_pulse(param); - } - - fn update(&mut self, _name: &str, _inputs: &ParamInputs) {} -} - -/// A chop parameter. -#[derive(Default, Debug, Clone)] -pub struct ChopParam { - pub(crate) input: Option<*const cxx::OP_CHOPInput>, -} - -impl Param for ChopParam { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let param: StringParameter = options.into(); - parameter_manager.append_chop(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - *self = inputs.get_chop(name); - } -} - -impl ChopParam { - /// Get the chop input for this parameter, if it exists. - pub fn input(&self) -> Option<&ChopInput> { - self.input - .map(|input| unsafe { ChopInput::ref_cast(&*input) }) - } -} - -#[derive(Default, Debug, Clone)] -pub struct SopParam { - pub(crate) input: Option<*const cxx::OP_SOPInput>, -} - -impl Param for SopParam { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let param: StringParameter = options.into(); - parameter_manager.append_sop(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - *self = inputs.get_sop(name); - } -} - -impl SopParam { - /// Get the sop input for this parameter, if it exists. - pub fn input(&self) -> Option<&SopInput> { - self.input - .map(|input| unsafe { SopInput::ref_cast(&*input) }) - } -} - -#[derive(Default, Debug, Clone)] -pub struct TopParam { - pub(crate) input: Option<*const cxx::OP_TOPInput>, -} - -impl Param for TopParam { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let param: StringParameter = options.into(); - parameter_manager.append_top(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - *self = inputs.get_top(name); - } -} - -impl TopParam { - /// Get the top input for this parameter, if it exists. - pub fn input(&self) -> Option<&crate::top::TopInput> { - self.input - .map(|input| unsafe { crate::top::TopInput::ref_cast(&*input) }) - } -} - -#[derive(Default, Debug, Clone)] -pub struct DatParam { - pub(crate) input: Option<*const cxx::OP_DATInput>, -} - -impl Param for DatParam { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let param: StringParameter = options.into(); - parameter_manager.append_dat(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - *self = inputs.get_dat(name); - } -} - -impl DatParam { - /// Get the dat input for this parameter, if it exists. - pub fn input(&self) -> Option<&crate::dat::DatInput> { - self.input - .map(|input| unsafe { crate::dat::DatInput::ref_cast(&*input) }) - } -} - -#[cfg(feature = "python")] -impl Param for *mut pyo3::ffi::PyObject { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let param = options.into(); - parameter_manager.append_python(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - // Ensure that the old object is decref'd - unsafe { - pyo3::ffi::Py_XDECREF(*self); - } - *self = inputs.get_python(name); - } -} - -pub trait MenuParam { - fn names() -> Vec; - fn labels() -> Vec; -} - -impl Param for Color { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let param = options.into(); - parameter_manager.append_rgba(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - let [r, g, b, a] = inputs.get_double_arr::<4>(name); - *self = (r, g, b, a).into(); - } -} - -#[derive(Default, Debug, Clone)] -pub struct DynamicMenuParam(pub Option); - -impl Param for DynamicMenuParam { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let param = options.into(); - parameter_manager.append_dynamic_menu(param); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - let name = inputs.get_string(name); - if !name.is_empty() { - self.0 = Some(name.to_string()); - } - } -} +use crate::chop::ChopInput; +use crate::sop::{Color, SopInput}; +use crate::{cxx, ParamInputs}; +use ref_cast::RefCast; +use std::ffi; +use std::ffi::{c_char, CString}; +use std::ops::{Deref, DerefMut}; +use std::path::PathBuf; +use std::pin::Pin; + +/// A numeric parameter. +// TODO: switch to enum to describe parameter types +#[derive(Debug)] +pub struct NumericParameter { + /// The name of the parameter. + pub name: String, + /// The label of the parameter. + pub label: String, + /// The page of the parameter. + pub page: String, + + /// The default values of the parameter. + pub default_values: [f64; 4], + /// The minimum values of the parameter. + pub min_values: [f64; 4], + /// The maximum values of the parameter. + pub max_values: [f64; 4], + /// Whether to clamp the minimum values of the parameter. + pub clamp_mins: [bool; 4], + /// Whether to clamp the maximum values of the parameter. + pub clamp_maxes: [bool; 4], + /// The minimum slider values of the parameter. + pub min_sliders: [f64; 4], + /// The maximum slider values of the parameter. + pub max_sliders: [f64; 4], +} + +impl Default for NumericParameter { + fn default() -> Self { + Self { + name: "".to_string(), + label: "".to_string(), + page: "".to_string(), + default_values: [0.0; 4], + min_values: [0.0; 4], + max_values: [1.0; 4], + clamp_mins: [false; 4], + clamp_maxes: [false; 4], + min_sliders: [0.0; 4], + max_sliders: [1.0; 4], + } + } +} + +/// Trait for defining operator parameters. +pub trait OperatorParams { + /// Register parameters with the parameter manager. + fn register(&mut self, parameter_manager: &mut ParameterManager); + /// Update parameters from operator input. + fn update(&mut self, inputs: &ParamInputs); +} + +impl From for cxx::OP_NumericParameter { + fn from(param: NumericParameter) -> Self { + cxx::OP_NumericParameter { + name: ffi::CString::new(param.name).unwrap().into_raw(), + label: ffi::CString::new(param.label).unwrap().into_raw(), + page: ffi::CString::new(param.page).unwrap().into_raw(), + defaultValues: param.default_values, + minValues: param.min_values, + maxValues: param.max_values, + clampMins: param.clamp_mins, + clampMaxes: param.clamp_maxes, + minSliders: param.min_sliders, + maxSliders: param.max_sliders, + reserved: Default::default(), + } + } +} + +/// A string parameter. +#[derive(Debug, Default)] +pub struct StringParameter { + /// The name of the parameter. + pub name: String, + /// The label of the parameter. + pub label: String, + /// The page of the parameter. + pub page: String, + /// The default value of the parameter. + pub default_value: String, +} + +impl From for cxx::OP_StringParameter { + fn from(param: StringParameter) -> Self { + cxx::OP_StringParameter { + name: ffi::CString::new(param.name).unwrap().into_raw(), + label: ffi::CString::new(param.label).unwrap().into_raw(), + page: ffi::CString::new(param.page).unwrap().into_raw(), + defaultValue: ffi::CString::new(param.default_value).unwrap().into_raw(), + reserved: Default::default(), + } + } +} + +/// Manager for registering parameters with TouchDesigner. +pub struct ParameterManager<'cook> { + manager: Pin<&'cook mut crate::cxx::OP_ParameterManager>, +} + +impl<'cook> ParameterManager<'cook> { + /// Create a new parameter manager. Should not be called by + /// users. + pub fn new( + manager: Pin<&'cook mut crate::cxx::OP_ParameterManager>, + ) -> ParameterManager<'cook> { + Self { manager } + } + + /// Append a float parameter. + pub fn append_float(&mut self, param: NumericParameter) { + let param = param.into(); + self.manager.as_mut().appendFloat(¶m, 1); + } + + /// Append a pulse parameter. + pub fn append_pulse(&mut self, param: NumericParameter) { + let param = param.into(); + self.manager.as_mut().appendPulse(¶m); + } + + /// Append an integer parameter. + pub fn append_int(&mut self, param: NumericParameter) { + let param = param.into(); + self.manager.as_mut().appendInt(¶m, 1); + } + + /// Append an xy parameter. + pub fn append_xy(&mut self, param: NumericParameter) { + let param = param.into(); + self.manager.as_mut().appendXY(¶m); + } + + /// Append an xyz parameter. + pub fn append_xyz(&mut self, param: NumericParameter) { + let param = param.into(); + self.manager.as_mut().appendXYZ(¶m); + } + + /// Append a uv parameter. + pub fn append_uv(&mut self, param: NumericParameter) { + let param = param.into(); + self.manager.as_mut().appendUV(¶m); + } + + /// Append a uvw parameter. + pub fn append_uvw(&mut self, param: NumericParameter) { + let param = param.into(); + self.manager.as_mut().appendUVW(¶m); + } + + /// Append a rgb parameter. + pub fn append_rgb(&mut self, param: NumericParameter) { + let param = param.into(); + self.manager.as_mut().appendRGB(¶m); + } + + /// Append a rgba parameter. + pub fn append_rgba(&mut self, param: NumericParameter) { + let param = param.into(); + self.manager.as_mut().appendRGBA(¶m); + } + + /// Append a toggle parameter. + pub fn append_toggle(&mut self, param: NumericParameter) { + let param = param.into(); + self.manager.as_mut().appendToggle(¶m); + } + + /// Append a string parameter. + pub fn append_string(&mut self, param: StringParameter) { + let param = param.into(); + self.manager.as_mut().appendString(¶m); + } + + /// Append a file parameter. + pub fn append_file(&mut self, param: StringParameter) { + let param = param.into(); + self.manager.as_mut().appendFile(¶m); + } + + /// Append a folder parameter. + pub fn append_folder(&mut self, param: StringParameter) { + let param = param.into(); + self.manager.as_mut().appendFolder(¶m); + } + + /// Append a dat reference parameter. + pub fn append_dat(&mut self, param: StringParameter) { + let param = param.into(); + self.manager.as_mut().appendDAT(¶m); + } + + /// Append a chop reference parameter. + pub fn append_chop(&mut self, param: StringParameter) { + let param = param.into(); + self.manager.as_mut().appendCHOP(¶m); + } + + /// Append a top reference parameter. + pub fn append_top(&mut self, param: StringParameter) { + let param = param.into(); + self.manager.as_mut().appendTOP(¶m); + } + + /// Append an object reference parameter. + pub fn append_object(&mut self, param: StringParameter) { + let param = param.into(); + self.manager.as_mut().appendObject(¶m); + } + + pub fn append_menu(&mut self, param: StringParameter, names: &[String], labels: &[String]) { + assert_eq!(names.len(), labels.len()); + let n_items = names.len() as i32; + let c_strings: Vec = names + .iter() + .map(|s| CString::new(s.as_bytes()).unwrap()) + .collect(); + + let name_ptrs: Vec<*const c_char> = c_strings.iter().map(|cs| cs.as_ptr()).collect(); + let names: *mut *const c_char = name_ptrs.as_ptr() as *mut *const c_char; + + let c_strings: Vec = labels + .iter() + .map(|s| CString::new(s.as_bytes()).unwrap()) + .collect(); + + let label_ptrs: Vec<*const c_char> = c_strings.iter().map(|cs| cs.as_ptr()).collect(); + let labels: *mut *const c_char = label_ptrs.as_ptr() as *mut *const c_char; + + let param = param.into(); + unsafe { + self.manager + .as_mut() + .appendMenu(¶m, n_items, names, labels); + } + } + + // pub fn append_string_menu(&mut self, param: StringParameter, names: &[&str], labels: &[&str]) { + // self.manager.as_mut().appendStringMenu(¶m, names.len(), names.as_ptr(), labels.as_ptr()); + // } + + /// Append a sop reference parameter. + pub fn append_sop(&mut self, param: StringParameter) { + let param = param.into(); + self.manager.as_mut().appendSOP(¶m); + } + + /// Append a python parameter. + pub fn append_python(&mut self, param: StringParameter) { + let param = param.into(); + self.manager.as_mut().appendPython(¶m); + } + + /// Append an op reference parameter. + pub fn append_op(&mut self, param: StringParameter) { + let param = param.into(); + self.manager.as_mut().appendOP(¶m); + } + + /// Append a comp reference parameter. + pub fn append_comp(&mut self, param: StringParameter) { + let param = param.into(); + self.manager.as_mut().appendCOMP(¶m); + } + + /// Append a mat reference parameter. + pub fn append_mat(&mut self, param: StringParameter) { + let param = param.into(); + self.manager.as_mut().appendMAT(¶m); + } + + /// Append a panel comp parameter. + pub fn append_panel_comp(&mut self, param: StringParameter) { + let param = param.into(); + self.manager.as_mut().appendPanelCOMP(¶m); + } + + /// Append a header parameter. + pub fn append_header(&mut self, param: StringParameter) { + let param = param.into(); + self.manager.as_mut().appendHeader(¶m); + } + + /// Append a momentary parameter. + pub fn append_momentary(&mut self, param: NumericParameter) { + let param = param.into(); + self.manager.as_mut().appendMomentary(¶m); + } + + /// Append a wh parameter. + pub fn append_wh(&mut self, param: NumericParameter) { + let param = param.into(); + self.manager.as_mut().appendWH(¶m); + } + + /// Append a dynamic menu parameter. + pub fn append_dynamic_menu(&mut self, param: StringParameter) { + let param = param.into(); + self.manager.as_mut().appendDynamicStringMenu(¶m); + } +} + +/// Options for creating parameters in derive macro. +/// Not intended for direct use. +#[derive(Debug)] +pub struct ParamOptions { + pub name: String, + pub label: String, + pub page: String, + pub min: f64, + pub max: f64, + pub min_slider: f64, + pub max_slider: f64, + pub clamp: bool, + pub default: f64, +} + +impl From for NumericParameter { + fn from(options: ParamOptions) -> Self { + NumericParameter { + name: options.name, + label: options.label, + page: options.page, + default_values: [options.default; 4], + min_values: [options.min; 4], + max_values: [options.max; 4], + clamp_mins: [options.clamp; 4], + clamp_maxes: [options.clamp; 4], + min_sliders: [options.min_slider; 4], + max_sliders: [options.max_slider; 4], + } + } +} + +impl From for StringParameter { + fn from(options: ParamOptions) -> Self { + StringParameter { + name: options.name, + label: options.label, + page: options.page, + ..Default::default() + } + } +} + +/// Trait for implementing parameter types. +pub trait Param { + /// Register parameter with the parameter manager. + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager); + /// Update parameter from operator input. + fn update(&mut self, name: &str, inputs: &ParamInputs); +} + +macro_rules! impl_param_int { + ( $t:ty ) => { + impl Param for $t { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let mut param: NumericParameter = options.into(); + param.default_values = [*self as f64, 0.0, 0.0, 0.0]; + parameter_manager.append_int(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + *self = inputs.get_int(name, 0) as $t; + } + } + }; +} + +impl_param_int!(i8); +impl_param_int!(i16); +impl_param_int!(i32); +impl_param_int!(i64); +impl_param_int!(i128); +impl_param_int!(isize); +impl_param_int!(u8); +impl_param_int!(u16); +impl_param_int!(u32); +impl_param_int!(u64); +impl_param_int!(u128); +impl_param_int!(usize); + +macro_rules! impl_param_float { + ( $t:ty ) => { + impl Param for $t { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let mut param: NumericParameter = options.into(); + param.default_values = [*self as f64, 0.0, 0.0, 0.0]; + parameter_manager.append_float(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + *self = inputs.get_float(name, 0) as $t; + } + } + }; +} + +impl_param_float!(f32); +impl_param_float!(f64); + +impl Param for String { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let mut param: StringParameter = options.into(); + param.default_value = self.clone(); + parameter_manager.append_string(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + *self = inputs.get_string(name).to_string(); + } +} + +impl Param for rgb::RGB8 { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let mut param: NumericParameter = options.into(); + param.default_values = [self.r as f64, self.g as f64, self.b as f64, 0.0]; + parameter_manager.append_rgb(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + *self = rgb::RGB8::new( + inputs.get_int(name, 0) as u8, + inputs.get_int(name, 1) as u8, + inputs.get_int(name, 2) as u8, + ); + } +} + +impl Param for rgb::RGB16 { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let mut param: NumericParameter = options.into(); + param.default_values = [self.r as f64, self.g as f64, self.b as f64, 0.0]; + parameter_manager.append_rgb(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + *self = rgb::RGB16::new( + inputs.get_int(name, 0) as u16, + inputs.get_int(name, 1) as u16, + inputs.get_int(name, 2) as u16, + ); + } +} + +impl Param for rgb::RGBA8 { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let mut param: NumericParameter = options.into(); + param.default_values = [self.r as f64, self.g as f64, self.b as f64, self.a as f64]; + parameter_manager.append_rgba(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + *self = rgb::RGBA8::new( + inputs.get_int(name, 0) as u8, + inputs.get_int(name, 1) as u8, + inputs.get_int(name, 2) as u8, + inputs.get_int(name, 3) as u8, + ); + } +} + +impl Param for rgb::RGBA16 { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let mut param: NumericParameter = options.into(); + param.default_values = [self.r as f64, self.g as f64, self.b as f64, self.a as f64]; + parameter_manager.append_rgba(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + *self = rgb::RGBA16::new( + inputs.get_int(name, 0) as u16, + inputs.get_int(name, 1) as u16, + inputs.get_int(name, 2) as u16, + inputs.get_int(name, 3) as u16, + ); + } +} + +/// A parameter wrapping a `PathBuf` that will be registered as a folder parameter. +pub struct FolderParam(PathBuf); + +impl Deref for FolderParam { + type Target = PathBuf; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for FolderParam { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Param for FolderParam { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let mut param: StringParameter = options.into(); + param.default_value = self.to_string_lossy().to_string(); + parameter_manager.append_folder(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + self.0 = PathBuf::from(inputs.get_string(name)); + } +} + +/// A parameter wrapping a `PathBuf` that will be registered as a file parameter. +#[derive(Default, Clone, Debug)] +pub struct FileParam(PathBuf); + +impl Deref for FileParam { + type Target = PathBuf; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for FileParam { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Param for FileParam { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let mut param: StringParameter = options.into(); + param.default_value = self.to_string_lossy().to_string(); + parameter_manager.append_file(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + self.0 = PathBuf::from(inputs.get_string(name)); + } +} + +impl Param for PathBuf { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let mut param: StringParameter = options.into(); + param.default_value = self.to_string_lossy().to_string(); + parameter_manager.append_file(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + *self = PathBuf::from(inputs.get_string(name)); + } +} + +impl Param for bool { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let mut param: NumericParameter = options.into(); + param.default_values[0] = true as usize as f64; + parameter_manager.append_toggle(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + *self = inputs.get_toggle(name); + } +} + +#[derive(Default, Debug, Clone, Copy)] +pub struct Pulse; + +impl Param for Pulse { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let param: NumericParameter = options.into(); + parameter_manager.append_pulse(param); + } + + fn update(&mut self, _name: &str, _inputs: &ParamInputs) {} +} + +/// A chop parameter. +#[derive(Default, Debug, Clone)] +pub struct ChopParam { + pub(crate) input: Option<*const cxx::OP_CHOPInput>, +} + +impl Param for ChopParam { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let param: StringParameter = options.into(); + parameter_manager.append_chop(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + *self = inputs.get_chop(name); + } +} + +impl ChopParam { + /// Get the chop input for this parameter, if it exists. + pub fn input(&self) -> Option<&ChopInput> { + self.input + .map(|input| unsafe { ChopInput::ref_cast(&*input) }) + } +} + +#[derive(Default, Debug, Clone)] +pub struct SopParam { + pub(crate) input: Option<*const cxx::OP_SOPInput>, +} + +impl Param for SopParam { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let param: StringParameter = options.into(); + parameter_manager.append_sop(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + *self = inputs.get_sop(name); + } +} + +impl SopParam { + /// Get the sop input for this parameter, if it exists. + pub fn input(&self) -> Option<&SopInput> { + self.input + .map(|input| unsafe { SopInput::ref_cast(&*input) }) + } +} + +#[derive(Default, Debug, Clone)] +pub struct TopParam { + pub(crate) input: Option<*const cxx::OP_TOPInput>, +} + +impl Param for TopParam { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let param: StringParameter = options.into(); + parameter_manager.append_top(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + *self = inputs.get_top(name); + } +} + +impl TopParam { + /// Get the top input for this parameter, if it exists. + pub fn input(&self) -> Option<&crate::top::TopInput> { + self.input + .map(|input| unsafe { crate::top::TopInput::ref_cast(&*input) }) + } +} + +#[derive(Default, Debug, Clone)] +pub struct DatParam { + pub(crate) input: Option<*const cxx::OP_DATInput>, +} + +impl Param for DatParam { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let param: StringParameter = options.into(); + parameter_manager.append_dat(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + *self = inputs.get_dat(name); + } +} + +impl DatParam { + /// Get the dat input for this parameter, if it exists. + pub fn input(&self) -> Option<&crate::dat::DatInput> { + self.input + .map(|input| unsafe { crate::dat::DatInput::ref_cast(&*input) }) + } +} + +#[cfg(feature = "python")] +impl Param for *mut pyo3::ffi::PyObject { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let param = options.into(); + parameter_manager.append_python(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + // Ensure that the old object is decref'd + unsafe { + pyo3::ffi::Py_XDECREF(*self); + } + *self = inputs.get_python(name); + } +} + +pub trait MenuParam { + fn names() -> Vec; + fn labels() -> Vec; +} + +impl Param for Color { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let param = options.into(); + parameter_manager.append_rgba(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + let [r, g, b, a] = inputs.get_double_arr::<4>(name); + *self = (r, g, b, a).into(); + } +} + +#[derive(Default, Debug, Clone)] +pub struct DynamicMenuParam(pub Option); + +impl Param for DynamicMenuParam { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let param = options.into(); + parameter_manager.append_dynamic_menu(param); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + let name = inputs.get_string(name); + if !name.is_empty() { + self.0 = Some(name.to_string()); + } + } +} diff --git a/td-rs-base/src/py.rs b/td-rs-base/src/py.rs index ff920f8..2478677 100644 --- a/td-rs-base/src/py.rs +++ b/td-rs-base/src/py.rs @@ -1,36 +1,36 @@ -use crate::Op; -use pyo3::ffi::PyGetSetDef; - -pub trait PyOp: Op {} - -pub trait PyGetSets { - fn get_get_sets() -> &'static [pyo3::ffi::PyGetSetDef]; -} - -impl PyGetSets for T { - default fn get_get_sets() -> &'static [PyGetSetDef] { - &[] - } -} - -pub trait PyMethods { - fn get_methods() -> &'static [pyo3::ffi::PyMethodDef]; -} - -impl PyMethods for T { - default fn get_methods() -> &'static [pyo3::ffi::PyMethodDef] { - &[] - } -} - -pub(crate) unsafe fn py_op_info( - op_info: std::pin::Pin<&mut crate::cxx::OP_CustomOPInfo>, -) { - let methods = T::get_methods(); - let m_len = methods.len(); - let m_arr = methods.as_ptr() as *mut autocxx::prelude::c_void; - let get_sets = T::get_get_sets(); - let gs_len = get_sets.len(); - let gs_arr = get_sets.as_ptr() as *mut autocxx::prelude::c_void; - crate::cxx::setPyInfo(op_info, m_arr, m_len, gs_arr, gs_len); -} +use crate::Op; +use pyo3::ffi::PyGetSetDef; + +pub trait PyOp: Op {} + +pub trait PyGetSets { + fn get_get_sets() -> &'static [pyo3::ffi::PyGetSetDef]; +} + +impl PyGetSets for T { + default fn get_get_sets() -> &'static [PyGetSetDef] { + &[] + } +} + +pub trait PyMethods { + fn get_methods() -> &'static [pyo3::ffi::PyMethodDef]; +} + +impl PyMethods for T { + default fn get_methods() -> &'static [pyo3::ffi::PyMethodDef] { + &[] + } +} + +pub(crate) unsafe fn py_op_info( + op_info: std::pin::Pin<&mut crate::cxx::OP_CustomOPInfo>, +) { + let methods = T::get_methods(); + let m_len = methods.len(); + let m_arr = methods.as_ptr() as *mut autocxx::prelude::c_void; + let get_sets = T::get_get_sets(); + let gs_len = get_sets.len(); + let gs_arr = get_sets.as_ptr() as *mut autocxx::prelude::c_void; + crate::cxx::setPyInfo(op_info, m_arr, m_len, gs_arr, gs_len); +} diff --git a/td-rs-base/src/sop.rs b/td-rs-base/src/sop.rs index 7741f6b..8123cc8 100644 --- a/td-rs-base/src/sop.rs +++ b/td-rs-base/src/sop.rs @@ -1,631 +1,631 @@ -#![allow(non_snake_case)] - -use crate::cxx::PrimitiveType; -use crate::{cxx, GetInput, OperatorInputs}; -use auto_ops::impl_op_ex; -use derive_more::{AsRef, Deref, DerefMut, From, Into}; -use ref_cast::RefCast; - -/// A sop input. -#[repr(transparent)] -#[derive(RefCast)] -pub struct SopInput { - input: cxx::OP_SOPInput, -} - -impl SopInput { - pub fn point_positions(&self) -> &[Position] { - let num_points = self.num_points(); - unsafe { - std::slice::from_raw_parts( - Position::ref_cast(&*self.input.getPointPositions()), - num_points, - ) - } - } - - pub fn num_points(&self) -> usize { - self.input.getNumPoints() as usize - } - - pub fn has_normals(&self) -> bool { - self.input.hasNormals() - } - - pub fn normals(&self) -> &[Vec3] { - unsafe { - let normals = self.input.getNormals(); - let num_normals = (*normals).numNormals; - let normals = (*normals).normals; - - std::slice::from_raw_parts(Vec3::ref_cast(&*normals), num_normals as usize) - } - } - - pub fn has_colors(&self) -> bool { - self.input.hasColors() - } - - pub fn colors(&self) -> &[Color] { - unsafe { - let colors = self.input.getColors(); - let num_colors = (*colors).numColors; - let colors = (*colors).colors; - - std::slice::from_raw_parts(Color::ref_cast(&*colors), num_colors as usize) - } - } - - pub fn textures(&self) -> (&[TexCoord], usize) { - unsafe { - let textures = self.input.getTextures(); - let num_textures = (*textures).numTextureLayers; - let textures = (*textures).textures; - let textures = - std::slice::from_raw_parts(TexCoord::ref_cast(&*textures), num_textures as usize); - (textures, num_textures as usize) - } - } - - pub fn num_custom_attributes(&self) -> usize { - self.input.getNumCustomAttributes() as usize - } - - pub fn custom_attribute(&self, index: usize) -> (CustomAttributeInfo, CustomAttributeData) { - unsafe { - let custom_attribute = self.input.getCustomAttribute(index as i32); - if custom_attribute.is_null() { - panic!("Custom attribute is null"); - } - let custom_attribute = &*custom_attribute; - - let name = custom_attribute._base.name; - let name = std::ffi::CStr::from_ptr(name) - .to_string_lossy() - .into_owned(); - let num_components = custom_attribute._base.numComponents as usize; - let attr_type = &custom_attribute._base.attribType; - let attr_type = attr_type.into(); - let info = CustomAttributeInfo { - name, - num_components, - attr_type, - }; - let data = match info.attr_type { - AttributeType::Float => { - let data = std::slice::from_raw_parts( - custom_attribute.floatData as *const f32, - num_components * self.num_points(), - ); - CustomAttributeData::Float(data.to_vec()) - } - AttributeType::Int => { - let data = std::slice::from_raw_parts( - custom_attribute.floatData as *const i32, - num_components * self.num_points(), - ); - CustomAttributeData::Int(data.to_vec()) - } - }; - (info, data) - } - } - - pub fn custom_attributes( - &self, - ) -> impl Iterator + '_ { - let num_custom_attributes = self.num_custom_attributes(); - (0..num_custom_attributes).map(move |i| self.custom_attribute(i)) - } - - pub fn num_primitives(&self) -> usize { - self.input.getNumPrimitives() as usize - } - - pub fn primitive(&self, index: usize) -> PrimitiveInfo { - let info = self.input.getPrimitive(index as i32); - PrimitiveInfo(info) - } - - pub fn primitives(&self) -> impl Iterator + '_ { - let num_primitives = self.num_primitives(); - (0..num_primitives).map(move |i| self.primitive(i)) - } - - pub fn num_vertices(&self) -> usize { - self.input.getNumVertices() as usize - } -} - -#[derive(RefCast, Deref, DerefMut, AsRef, From, Into)] -#[repr(transparent)] -pub struct PrimitiveInfo<'a>(&'a cxx::SOP_PrimitiveInfo); - -impl<'a> PrimitiveInfo<'a> { - pub fn vertices(&self) -> &[u32] { - unsafe { - std::slice::from_raw_parts(self.pointIndices as *const u32, self.numVertices as usize) - } - } - - pub fn point_indices(&self) -> &[u32] { - unsafe { - std::slice::from_raw_parts(self.pointIndices as *const u32, self.numVertices as usize) - } - } - - pub fn point_indices_offset(&self) -> usize { - self.pointIndicesOffset as usize - } - - pub fn primitive_type(&self) -> &PrimitiveType { - &self.type_ - } - - pub fn is_closed(&self) -> bool { - self.isClosed - } -} - -#[derive(Debug)] -pub enum AttributeType { - Float, - Int, -} - -impl From for AttributeType { - fn from(t: cxx::AttribType) -> Self { - match t { - cxx::AttribType::Float => AttributeType::Float, - cxx::AttribType::Int => AttributeType::Int, - } - } -} - -impl From<&cxx::AttribType> for AttributeType { - fn from(t: &cxx::AttribType) -> Self { - match t { - cxx::AttribType::Float => AttributeType::Float, - cxx::AttribType::Int => AttributeType::Int, - } - } -} - -impl From for cxx::AttribType { - fn from(t: AttributeType) -> Self { - match t { - AttributeType::Float => cxx::AttribType::Float, - AttributeType::Int => cxx::AttribType::Int, - } - } -} - -impl From<&AttributeType> for cxx::AttribType { - fn from(t: &AttributeType) -> Self { - match t { - AttributeType::Float => cxx::AttribType::Float, - AttributeType::Int => cxx::AttribType::Int, - } - } -} - -#[derive(Debug)] -pub struct CustomAttributeInfo { - pub name: String, - pub num_components: usize, - pub attr_type: AttributeType, -} - -#[derive(Debug)] -pub enum CustomAttributeData { - Float(Vec), - Int(Vec), -} - -impl<'cook> GetInput<'cook, SopInput> for OperatorInputs<'cook, SopInput> { - fn num_inputs(&self) -> usize { - self.inputs.getNumInputs() as usize - } - - fn input(&self, index: usize) -> Option<&'cook SopInput> { - let input = self.inputs.getInputSOP(index as i32); - if input.is_null() { - None - } else { - Some(SopInput::ref_cast(unsafe { &*input })) - } - } -} - -#[derive(RefCast, Deref, DerefMut, AsRef, From, Into)] -#[repr(transparent)] -pub struct Vec3(cxx::Vector); - -impl Vec3 { - pub const fn new(x: f32, y: f32, z: f32) -> Self { - Self(cxx::Vector { x, y, z }) - } - - pub fn zero() -> Self { - Self(cxx::Vector { - x: 0.0, - y: 0.0, - z: 0.0, - }) - } -} - -impl Clone for Vec3 { - fn clone(&self) -> Self { - Self(cxx::Vector { - x: self.x, - y: self.y, - z: self.z, - }) - } -} - -impl From<&Vec3> for Vec3 { - fn from(v: &Vec3) -> Self { - Self(cxx::Vector { - x: v.x, - y: v.y, - z: v.z, - }) - } -} - -impl From<(f32, f32, f32)> for Vec3 { - fn from((x, y, z): (f32, f32, f32)) -> Self { - Self(cxx::Vector { x, y, z }) - } -} - -impl From<(f64, f64, f64)> for Vec3 { - fn from((x, y, z): (f64, f64, f64)) -> Self { - Self(cxx::Vector { - x: x as f32, - y: y as f32, - z: z as f32, - }) - } -} - -impl From<(f32, f32, f64)> for Vec3 { - fn from((x, y, z): (f32, f32, f64)) -> Self { - Self(cxx::Vector { x, y, z: z as f32 }) - } -} - -impl From<(f32, f64, f32)> for Vec3 { - fn from((x, y, z): (f32, f64, f32)) -> Self { - Self(cxx::Vector { x, y: y as f32, z }) - } -} - -impl From<(f64, f32, f32)> for Vec3 { - fn from((x, y, z): (f64, f32, f32)) -> Self { - Self(cxx::Vector { x: x as f32, y, z }) - } -} - -impl From<(f64, f64, f32)> for Vec3 { - fn from((x, y, z): (f64, f64, f32)) -> Self { - Self(cxx::Vector { - x: x as f32, - y: y as f32, - z, - }) - } -} - -impl From<(f64, f32, f64)> for Vec3 { - fn from((x, y, z): (f64, f32, f64)) -> Self { - Self(cxx::Vector { - x: x as f32, - y, - z: z as f32, - }) - } -} - -impl From<(f32, f64, f64)> for Vec3 { - fn from((x, y, z): (f32, f64, f64)) -> Self { - Self(cxx::Vector { - x, - y: y as f32, - z: z as f32, - }) - } -} - -impl_op_ex!(+ |a: &Vec3, b: &Vec3| -> Vec3 { - Vec3(cxx::Vector { - x: a.x + b.x, - y: a.y + b.y, - z: a.z + b.z, - }) -}); -impl_op_ex!(*|a: &Vec3, b: f32| -> Vec3 { - Vec3(cxx::Vector { - x: a.x * b, - y: a.y * b, - z: a.z * b, - }) -}); - -#[derive(RefCast, Deref, DerefMut, AsRef, From, Into)] -#[repr(transparent)] -pub struct Position(cxx::Position); - -impl Position { - pub const fn new(x: f32, y: f32, z: f32) -> Self { - Self(cxx::Position { x, y, z }) - } -} - -impl Clone for Position { - fn clone(&self) -> Self { - Self(cxx::Position { - x: self.x, - y: self.y, - z: self.z, - }) - } -} - -impl From<&Position> for Position { - fn from(p: &Position) -> Self { - Self(cxx::Position { - x: p.x, - y: p.y, - z: p.z, - }) - } -} - -impl From<(f32, f32, f32)> for Position { - fn from((x, y, z): (f32, f32, f32)) -> Self { - Self(cxx::Position { x, y, z }) - } -} - -impl From<(f64, f64, f64)> for Position { - fn from((x, y, z): (f64, f64, f64)) -> Self { - Self(cxx::Position { - x: x as f32, - y: y as f32, - z: z as f32, - }) - } -} - -impl From<(f32, f32, f64)> for Position { - fn from((x, y, z): (f32, f32, f64)) -> Self { - Self(cxx::Position { x, y, z: z as f32 }) - } -} - -impl From<(f32, f64, f32)> for Position { - fn from((x, y, z): (f32, f64, f32)) -> Self { - Self(cxx::Position { x, y: y as f32, z }) - } -} - -impl From<(f64, f32, f32)> for Position { - fn from((x, y, z): (f64, f32, f32)) -> Self { - Self(cxx::Position { x: x as f32, y, z }) - } -} - -impl From<(f64, f64, f32)> for Position { - fn from((x, y, z): (f64, f64, f32)) -> Self { - Self(cxx::Position { - x: x as f32, - y: y as f32, - z, - }) - } -} - -impl From<(f64, f32, f64)> for Position { - fn from((x, y, z): (f64, f32, f64)) -> Self { - Self(cxx::Position { - x: x as f32, - y, - z: z as f32, - }) - } -} - -impl From<(f32, f64, f64)> for Position { - fn from((x, y, z): (f32, f64, f64)) -> Self { - Self(cxx::Position { - x, - y: y as f32, - z: z as f32, - }) - } -} - -impl_op_ex!(+ |a: &Position, b: &Vec3| -> Position { - Position(cxx::Position { - x: a.x + b.x, - y: a.y + b.y, - z: a.z + b.z, - }) -}); -impl_op_ex!(*|a: &Position, b: f32| -> Position { - Position(cxx::Position { - x: a.x * b, - y: a.y * b, - z: a.z * b, - }) -}); - -#[derive(RefCast, Deref, DerefMut, AsRef, From, Into)] -#[repr(transparent)] -pub struct Color(cxx::Color); - -impl Clone for Color { - fn clone(&self) -> Self { - Self(cxx::Color { - r: self.r, - g: self.g, - b: self.b, - a: self.a, - }) - } -} - -impl From<&Color> for Color { - fn from(c: &Color) -> Self { - Self(cxx::Color { - r: c.r, - g: c.g, - b: c.b, - a: c.a, - }) - } -} - -impl From<(f32, f32, f32, f32)> for Color { - fn from((r, g, b, a): (f32, f32, f32, f32)) -> Self { - Self(cxx::Color { r, g, b, a }) - } -} - -impl From<(f64, f64, f64, f64)> for Color { - fn from((r, g, b, a): (f64, f64, f64, f64)) -> Self { - Self(cxx::Color { - r: r as f32, - g: g as f32, - b: b as f32, - a: a as f32, - }) - } -} - -impl From<(u32, u32, u32, u32)> for Color { - fn from((r, g, b, a): (u32, u32, u32, u32)) -> Self { - Self(cxx::Color { - r: r as f32 / 255.0, - g: g as f32 / 255.0, - b: b as f32 / 255.0, - a: a as f32 / 255.0, - }) - } -} - -impl From<(i32, i32, i32, i32)> for Color { - fn from((r, g, b, a): (i32, i32, i32, i32)) -> Self { - Self(cxx::Color { - r: r as f32 / 255.0, - g: g as f32 / 255.0, - b: b as f32 / 255.0, - a: a as f32 / 255.0, - }) - } -} - -#[derive(RefCast, Deref, DerefMut, AsRef, From, Into)] -#[repr(transparent)] -pub struct TexCoord(cxx::TexCoord); - -impl TexCoord { - pub const fn new(u: f32, v: f32, w: f32) -> Self { - Self(cxx::TexCoord { u, v, w }) - } -} - -impl Clone for TexCoord { - fn clone(&self) -> Self { - Self(cxx::TexCoord { - u: self.u, - v: self.v, - w: self.w, - }) - } -} - -impl From<&TexCoord> for TexCoord { - fn from(t: &TexCoord) -> Self { - Self(cxx::TexCoord { - u: t.u, - v: t.v, - w: t.w, - }) - } -} - -impl From<(f32, f32, f32)> for TexCoord { - fn from((u, v, w): (f32, f32, f32)) -> Self { - Self(cxx::TexCoord { u, v, w }) - } -} - -impl From<(f64, f64, f64)> for TexCoord { - fn from((u, v, w): (f64, f64, f64)) -> Self { - Self(cxx::TexCoord { - u: u as f32, - v: v as f32, - w: w as f32, - }) - } -} - -#[derive(RefCast, Deref, DerefMut, AsRef, From, Into)] -#[repr(transparent)] -pub struct BoundingBox(cxx::BoundingBox); - -impl From<&BoundingBox> for BoundingBox { - fn from(b: &BoundingBox) -> Self { - Self(cxx::BoundingBox { - minX: b.minX, - minY: b.minY, - minZ: b.minZ, - maxX: b.maxX, - maxY: b.maxY, - maxZ: b.maxZ, - }) - } -} - -impl From<(f32, f32, f32, f32, f32, f32)> for BoundingBox { - fn from((minX, minY, minZ, maxX, maxY, maxZ): (f32, f32, f32, f32, f32, f32)) -> Self { - Self(cxx::BoundingBox { - minX, - minY, - minZ, - maxX, - maxY, - maxZ, - }) - } -} - -impl From<(f64, f64, f64, f64, f64, f64)> for BoundingBox { - fn from((minX, minY, minZ, maxX, maxY, maxZ): (f64, f64, f64, f64, f64, f64)) -> Self { - Self(cxx::BoundingBox { - minX: minX as f32, - minY: minY as f32, - minZ: minZ as f32, - maxX: maxX as f32, - maxY: maxY as f32, - maxZ: maxZ as f32, - }) - } -} - -impl From<(i32, i32, i32, i32, i32, i32)> for BoundingBox { - fn from((minX, minY, minZ, maxX, maxY, maxZ): (i32, i32, i32, i32, i32, i32)) -> Self { - Self(cxx::BoundingBox { - minX: minX as f32, - minY: minY as f32, - minZ: minZ as f32, - maxX: maxX as f32, - maxY: maxY as f32, - maxZ: maxZ as f32, - }) - } -} +#![allow(non_snake_case)] + +use crate::cxx::PrimitiveType; +use crate::{cxx, GetInput, OperatorInputs}; +use auto_ops::impl_op_ex; +use derive_more::{AsRef, Deref, DerefMut, From, Into}; +use ref_cast::RefCast; + +/// A sop input. +#[repr(transparent)] +#[derive(RefCast)] +pub struct SopInput { + input: cxx::OP_SOPInput, +} + +impl SopInput { + pub fn point_positions(&self) -> &[Position] { + let num_points = self.num_points(); + unsafe { + std::slice::from_raw_parts( + Position::ref_cast(&*self.input.getPointPositions()), + num_points, + ) + } + } + + pub fn num_points(&self) -> usize { + self.input.getNumPoints() as usize + } + + pub fn has_normals(&self) -> bool { + self.input.hasNormals() + } + + pub fn normals(&self) -> &[Vec3] { + unsafe { + let normals = self.input.getNormals(); + let num_normals = (*normals).numNormals; + let normals = (*normals).normals; + + std::slice::from_raw_parts(Vec3::ref_cast(&*normals), num_normals as usize) + } + } + + pub fn has_colors(&self) -> bool { + self.input.hasColors() + } + + pub fn colors(&self) -> &[Color] { + unsafe { + let colors = self.input.getColors(); + let num_colors = (*colors).numColors; + let colors = (*colors).colors; + + std::slice::from_raw_parts(Color::ref_cast(&*colors), num_colors as usize) + } + } + + pub fn textures(&self) -> (&[TexCoord], usize) { + unsafe { + let textures = self.input.getTextures(); + let num_textures = (*textures).numTextureLayers; + let textures = (*textures).textures; + let textures = + std::slice::from_raw_parts(TexCoord::ref_cast(&*textures), num_textures as usize); + (textures, num_textures as usize) + } + } + + pub fn num_custom_attributes(&self) -> usize { + self.input.getNumCustomAttributes() as usize + } + + pub fn custom_attribute(&self, index: usize) -> (CustomAttributeInfo, CustomAttributeData) { + unsafe { + let custom_attribute = self.input.getCustomAttribute(index as i32); + if custom_attribute.is_null() { + panic!("Custom attribute is null"); + } + let custom_attribute = &*custom_attribute; + + let name = custom_attribute._base.name; + let name = std::ffi::CStr::from_ptr(name) + .to_string_lossy() + .into_owned(); + let num_components = custom_attribute._base.numComponents as usize; + let attr_type = &custom_attribute._base.attribType; + let attr_type = attr_type.into(); + let info = CustomAttributeInfo { + name, + num_components, + attr_type, + }; + let data = match info.attr_type { + AttributeType::Float => { + let data = std::slice::from_raw_parts( + custom_attribute.floatData as *const f32, + num_components * self.num_points(), + ); + CustomAttributeData::Float(data.to_vec()) + } + AttributeType::Int => { + let data = std::slice::from_raw_parts( + custom_attribute.floatData as *const i32, + num_components * self.num_points(), + ); + CustomAttributeData::Int(data.to_vec()) + } + }; + (info, data) + } + } + + pub fn custom_attributes( + &self, + ) -> impl Iterator + '_ { + let num_custom_attributes = self.num_custom_attributes(); + (0..num_custom_attributes).map(move |i| self.custom_attribute(i)) + } + + pub fn num_primitives(&self) -> usize { + self.input.getNumPrimitives() as usize + } + + pub fn primitive(&self, index: usize) -> PrimitiveInfo { + let info = self.input.getPrimitive(index as i32); + PrimitiveInfo(info) + } + + pub fn primitives(&self) -> impl Iterator + '_ { + let num_primitives = self.num_primitives(); + (0..num_primitives).map(move |i| self.primitive(i)) + } + + pub fn num_vertices(&self) -> usize { + self.input.getNumVertices() as usize + } +} + +#[derive(RefCast, Deref, DerefMut, AsRef, From, Into)] +#[repr(transparent)] +pub struct PrimitiveInfo<'a>(&'a cxx::SOP_PrimitiveInfo); + +impl<'a> PrimitiveInfo<'a> { + pub fn vertices(&self) -> &[u32] { + unsafe { + std::slice::from_raw_parts(self.pointIndices as *const u32, self.numVertices as usize) + } + } + + pub fn point_indices(&self) -> &[u32] { + unsafe { + std::slice::from_raw_parts(self.pointIndices as *const u32, self.numVertices as usize) + } + } + + pub fn point_indices_offset(&self) -> usize { + self.pointIndicesOffset as usize + } + + pub fn primitive_type(&self) -> &PrimitiveType { + &self.type_ + } + + pub fn is_closed(&self) -> bool { + self.isClosed + } +} + +#[derive(Debug)] +pub enum AttributeType { + Float, + Int, +} + +impl From for AttributeType { + fn from(t: cxx::AttribType) -> Self { + match t { + cxx::AttribType::Float => AttributeType::Float, + cxx::AttribType::Int => AttributeType::Int, + } + } +} + +impl From<&cxx::AttribType> for AttributeType { + fn from(t: &cxx::AttribType) -> Self { + match t { + cxx::AttribType::Float => AttributeType::Float, + cxx::AttribType::Int => AttributeType::Int, + } + } +} + +impl From for cxx::AttribType { + fn from(t: AttributeType) -> Self { + match t { + AttributeType::Float => cxx::AttribType::Float, + AttributeType::Int => cxx::AttribType::Int, + } + } +} + +impl From<&AttributeType> for cxx::AttribType { + fn from(t: &AttributeType) -> Self { + match t { + AttributeType::Float => cxx::AttribType::Float, + AttributeType::Int => cxx::AttribType::Int, + } + } +} + +#[derive(Debug)] +pub struct CustomAttributeInfo { + pub name: String, + pub num_components: usize, + pub attr_type: AttributeType, +} + +#[derive(Debug)] +pub enum CustomAttributeData { + Float(Vec), + Int(Vec), +} + +impl<'cook> GetInput<'cook, SopInput> for OperatorInputs<'cook, SopInput> { + fn num_inputs(&self) -> usize { + self.inputs.getNumInputs() as usize + } + + fn input(&self, index: usize) -> Option<&'cook SopInput> { + let input = self.inputs.getInputSOP(index as i32); + if input.is_null() { + None + } else { + Some(SopInput::ref_cast(unsafe { &*input })) + } + } +} + +#[derive(RefCast, Deref, DerefMut, AsRef, From, Into)] +#[repr(transparent)] +pub struct Vec3(cxx::Vector); + +impl Vec3 { + pub const fn new(x: f32, y: f32, z: f32) -> Self { + Self(cxx::Vector { x, y, z }) + } + + pub fn zero() -> Self { + Self(cxx::Vector { + x: 0.0, + y: 0.0, + z: 0.0, + }) + } +} + +impl Clone for Vec3 { + fn clone(&self) -> Self { + Self(cxx::Vector { + x: self.x, + y: self.y, + z: self.z, + }) + } +} + +impl From<&Vec3> for Vec3 { + fn from(v: &Vec3) -> Self { + Self(cxx::Vector { + x: v.x, + y: v.y, + z: v.z, + }) + } +} + +impl From<(f32, f32, f32)> for Vec3 { + fn from((x, y, z): (f32, f32, f32)) -> Self { + Self(cxx::Vector { x, y, z }) + } +} + +impl From<(f64, f64, f64)> for Vec3 { + fn from((x, y, z): (f64, f64, f64)) -> Self { + Self(cxx::Vector { + x: x as f32, + y: y as f32, + z: z as f32, + }) + } +} + +impl From<(f32, f32, f64)> for Vec3 { + fn from((x, y, z): (f32, f32, f64)) -> Self { + Self(cxx::Vector { x, y, z: z as f32 }) + } +} + +impl From<(f32, f64, f32)> for Vec3 { + fn from((x, y, z): (f32, f64, f32)) -> Self { + Self(cxx::Vector { x, y: y as f32, z }) + } +} + +impl From<(f64, f32, f32)> for Vec3 { + fn from((x, y, z): (f64, f32, f32)) -> Self { + Self(cxx::Vector { x: x as f32, y, z }) + } +} + +impl From<(f64, f64, f32)> for Vec3 { + fn from((x, y, z): (f64, f64, f32)) -> Self { + Self(cxx::Vector { + x: x as f32, + y: y as f32, + z, + }) + } +} + +impl From<(f64, f32, f64)> for Vec3 { + fn from((x, y, z): (f64, f32, f64)) -> Self { + Self(cxx::Vector { + x: x as f32, + y, + z: z as f32, + }) + } +} + +impl From<(f32, f64, f64)> for Vec3 { + fn from((x, y, z): (f32, f64, f64)) -> Self { + Self(cxx::Vector { + x, + y: y as f32, + z: z as f32, + }) + } +} + +impl_op_ex!(+ |a: &Vec3, b: &Vec3| -> Vec3 { + Vec3(cxx::Vector { + x: a.x + b.x, + y: a.y + b.y, + z: a.z + b.z, + }) +}); +impl_op_ex!(*|a: &Vec3, b: f32| -> Vec3 { + Vec3(cxx::Vector { + x: a.x * b, + y: a.y * b, + z: a.z * b, + }) +}); + +#[derive(RefCast, Deref, DerefMut, AsRef, From, Into)] +#[repr(transparent)] +pub struct Position(cxx::Position); + +impl Position { + pub const fn new(x: f32, y: f32, z: f32) -> Self { + Self(cxx::Position { x, y, z }) + } +} + +impl Clone for Position { + fn clone(&self) -> Self { + Self(cxx::Position { + x: self.x, + y: self.y, + z: self.z, + }) + } +} + +impl From<&Position> for Position { + fn from(p: &Position) -> Self { + Self(cxx::Position { + x: p.x, + y: p.y, + z: p.z, + }) + } +} + +impl From<(f32, f32, f32)> for Position { + fn from((x, y, z): (f32, f32, f32)) -> Self { + Self(cxx::Position { x, y, z }) + } +} + +impl From<(f64, f64, f64)> for Position { + fn from((x, y, z): (f64, f64, f64)) -> Self { + Self(cxx::Position { + x: x as f32, + y: y as f32, + z: z as f32, + }) + } +} + +impl From<(f32, f32, f64)> for Position { + fn from((x, y, z): (f32, f32, f64)) -> Self { + Self(cxx::Position { x, y, z: z as f32 }) + } +} + +impl From<(f32, f64, f32)> for Position { + fn from((x, y, z): (f32, f64, f32)) -> Self { + Self(cxx::Position { x, y: y as f32, z }) + } +} + +impl From<(f64, f32, f32)> for Position { + fn from((x, y, z): (f64, f32, f32)) -> Self { + Self(cxx::Position { x: x as f32, y, z }) + } +} + +impl From<(f64, f64, f32)> for Position { + fn from((x, y, z): (f64, f64, f32)) -> Self { + Self(cxx::Position { + x: x as f32, + y: y as f32, + z, + }) + } +} + +impl From<(f64, f32, f64)> for Position { + fn from((x, y, z): (f64, f32, f64)) -> Self { + Self(cxx::Position { + x: x as f32, + y, + z: z as f32, + }) + } +} + +impl From<(f32, f64, f64)> for Position { + fn from((x, y, z): (f32, f64, f64)) -> Self { + Self(cxx::Position { + x, + y: y as f32, + z: z as f32, + }) + } +} + +impl_op_ex!(+ |a: &Position, b: &Vec3| -> Position { + Position(cxx::Position { + x: a.x + b.x, + y: a.y + b.y, + z: a.z + b.z, + }) +}); +impl_op_ex!(*|a: &Position, b: f32| -> Position { + Position(cxx::Position { + x: a.x * b, + y: a.y * b, + z: a.z * b, + }) +}); + +#[derive(RefCast, Deref, DerefMut, AsRef, From, Into)] +#[repr(transparent)] +pub struct Color(cxx::Color); + +impl Clone for Color { + fn clone(&self) -> Self { + Self(cxx::Color { + r: self.r, + g: self.g, + b: self.b, + a: self.a, + }) + } +} + +impl From<&Color> for Color { + fn from(c: &Color) -> Self { + Self(cxx::Color { + r: c.r, + g: c.g, + b: c.b, + a: c.a, + }) + } +} + +impl From<(f32, f32, f32, f32)> for Color { + fn from((r, g, b, a): (f32, f32, f32, f32)) -> Self { + Self(cxx::Color { r, g, b, a }) + } +} + +impl From<(f64, f64, f64, f64)> for Color { + fn from((r, g, b, a): (f64, f64, f64, f64)) -> Self { + Self(cxx::Color { + r: r as f32, + g: g as f32, + b: b as f32, + a: a as f32, + }) + } +} + +impl From<(u32, u32, u32, u32)> for Color { + fn from((r, g, b, a): (u32, u32, u32, u32)) -> Self { + Self(cxx::Color { + r: r as f32 / 255.0, + g: g as f32 / 255.0, + b: b as f32 / 255.0, + a: a as f32 / 255.0, + }) + } +} + +impl From<(i32, i32, i32, i32)> for Color { + fn from((r, g, b, a): (i32, i32, i32, i32)) -> Self { + Self(cxx::Color { + r: r as f32 / 255.0, + g: g as f32 / 255.0, + b: b as f32 / 255.0, + a: a as f32 / 255.0, + }) + } +} + +#[derive(RefCast, Deref, DerefMut, AsRef, From, Into)] +#[repr(transparent)] +pub struct TexCoord(cxx::TexCoord); + +impl TexCoord { + pub const fn new(u: f32, v: f32, w: f32) -> Self { + Self(cxx::TexCoord { u, v, w }) + } +} + +impl Clone for TexCoord { + fn clone(&self) -> Self { + Self(cxx::TexCoord { + u: self.u, + v: self.v, + w: self.w, + }) + } +} + +impl From<&TexCoord> for TexCoord { + fn from(t: &TexCoord) -> Self { + Self(cxx::TexCoord { + u: t.u, + v: t.v, + w: t.w, + }) + } +} + +impl From<(f32, f32, f32)> for TexCoord { + fn from((u, v, w): (f32, f32, f32)) -> Self { + Self(cxx::TexCoord { u, v, w }) + } +} + +impl From<(f64, f64, f64)> for TexCoord { + fn from((u, v, w): (f64, f64, f64)) -> Self { + Self(cxx::TexCoord { + u: u as f32, + v: v as f32, + w: w as f32, + }) + } +} + +#[derive(RefCast, Deref, DerefMut, AsRef, From, Into)] +#[repr(transparent)] +pub struct BoundingBox(cxx::BoundingBox); + +impl From<&BoundingBox> for BoundingBox { + fn from(b: &BoundingBox) -> Self { + Self(cxx::BoundingBox { + minX: b.minX, + minY: b.minY, + minZ: b.minZ, + maxX: b.maxX, + maxY: b.maxY, + maxZ: b.maxZ, + }) + } +} + +impl From<(f32, f32, f32, f32, f32, f32)> for BoundingBox { + fn from((minX, minY, minZ, maxX, maxY, maxZ): (f32, f32, f32, f32, f32, f32)) -> Self { + Self(cxx::BoundingBox { + minX, + minY, + minZ, + maxX, + maxY, + maxZ, + }) + } +} + +impl From<(f64, f64, f64, f64, f64, f64)> for BoundingBox { + fn from((minX, minY, minZ, maxX, maxY, maxZ): (f64, f64, f64, f64, f64, f64)) -> Self { + Self(cxx::BoundingBox { + minX: minX as f32, + minY: minY as f32, + minZ: minZ as f32, + maxX: maxX as f32, + maxY: maxY as f32, + maxZ: maxZ as f32, + }) + } +} + +impl From<(i32, i32, i32, i32, i32, i32)> for BoundingBox { + fn from((minX, minY, minZ, maxX, maxY, maxZ): (i32, i32, i32, i32, i32, i32)) -> Self { + Self(cxx::BoundingBox { + minX: minX as f32, + minY: minY as f32, + minZ: minZ as f32, + maxX: maxX as f32, + maxY: maxY as f32, + maxZ: maxZ as f32, + }) + } +} diff --git a/td-rs-base/src/top.rs b/td-rs-base/src/top.rs index a1c41cb..05fcb05 100644 --- a/td-rs-base/src/top.rs +++ b/td-rs-base/src/top.rs @@ -1,237 +1,338 @@ -use crate::cxx::{OP_PixelFormat, OP_TOPInput}; -use crate::{GetInput, OperatorInputs}; -use ref_cast::RefCast; - -#[derive(Debug, Default, Eq, PartialEq)] -pub enum TexDim { - #[default] - EInvalid, - E2D, - E2DArray, - E3D, - ECube, -} - -#[derive(Debug)] -pub struct TextureDesc { - pub width: usize, - pub height: usize, - pub depth: usize, - pub tex_dim: TexDim, - pub pixel_format: PixelFormat, - pub aspect_x: f32, - pub aspect_y: f32, -} - -impl Default for TextureDesc { - fn default() -> Self { - Self { - width: 0, - height: 0, - depth: 1, - tex_dim: TexDim::EInvalid, - pixel_format: PixelFormat::Invalid, - aspect_x: 0.0, - aspect_y: 0.0, - } - } -} - -#[derive(Debug, Default)] -pub enum PixelFormat { - #[default] - Invalid, - - // 8-bit per color, BGRA pixels. This is preferred for 4 channel 8-bit data - BGRA8Fixed, - // 8-bit per color, RGBA pixels. Only use this one if absolutely nessessary. - RGBA8Fixed, - RGBA16Fixed, - RGBA16Float, - RGBA32Float, - - Mono8Fixed, - Mono16Fixed, - Mono16Float, - Mono32Float, - - // RG two channel - RG8Fixed, - RG16Fixed, - RG16Float, - RG32Float, - - // Alpha only - A8Fixed, - A16Fixed, - A16Float, - A32Float, - - // Mono with Alpha - MonoA8Fixed, - MonoA16Fixed, - MonoA16Float, - MonoA32Float, - - // sRGB. use SBGRA if possible since that's what most GPUs use - SBGRA8Fixed, - SRGBA8Fixed, - - RGB10A2Fixed, - // 11-bit float, positive values only. B is actually 10 bits - RGB11Float, -} - -impl From<&OP_PixelFormat> for PixelFormat { - fn from(pixel_format: &OP_PixelFormat) -> Self { - match pixel_format { - OP_PixelFormat::Invalid => PixelFormat::Invalid, - OP_PixelFormat::BGRA8Fixed => PixelFormat::BGRA8Fixed, - OP_PixelFormat::RGBA8Fixed => PixelFormat::RGBA8Fixed, - OP_PixelFormat::RGBA16Fixed => PixelFormat::RGBA16Fixed, - OP_PixelFormat::RGBA16Float => PixelFormat::RGBA16Float, - OP_PixelFormat::RGBA32Float => PixelFormat::RGBA32Float, - OP_PixelFormat::Mono8Fixed => PixelFormat::Mono8Fixed, - OP_PixelFormat::Mono16Fixed => PixelFormat::Mono16Fixed, - OP_PixelFormat::Mono16Float => PixelFormat::Mono16Float, - OP_PixelFormat::Mono32Float => PixelFormat::Mono32Float, - OP_PixelFormat::RG8Fixed => PixelFormat::RG8Fixed, - OP_PixelFormat::RG16Fixed => PixelFormat::RG16Fixed, - OP_PixelFormat::RG16Float => PixelFormat::RG16Float, - OP_PixelFormat::RG32Float => PixelFormat::RG32Float, - OP_PixelFormat::A8Fixed => PixelFormat::A8Fixed, - OP_PixelFormat::A16Fixed => PixelFormat::A16Fixed, - OP_PixelFormat::A16Float => PixelFormat::A16Float, - OP_PixelFormat::A32Float => PixelFormat::A32Float, - OP_PixelFormat::MonoA8Fixed => PixelFormat::MonoA8Fixed, - OP_PixelFormat::MonoA16Fixed => PixelFormat::MonoA16Fixed, - OP_PixelFormat::MonoA16Float => PixelFormat::MonoA16Float, - OP_PixelFormat::MonoA32Float => PixelFormat::MonoA32Float, - OP_PixelFormat::SBGRA8Fixed => PixelFormat::SBGRA8Fixed, - OP_PixelFormat::SRGBA8Fixed => PixelFormat::SRGBA8Fixed, - OP_PixelFormat::RGB10A2Fixed => PixelFormat::RGB10A2Fixed, - OP_PixelFormat::RGB11Float => PixelFormat::RGB11Float, - } - } -} - -impl From<&PixelFormat> for OP_PixelFormat { - fn from(pixel_format: &PixelFormat) -> Self { - match pixel_format { - PixelFormat::Invalid => crate::cxx::OP_PixelFormat::Invalid, - PixelFormat::BGRA8Fixed => crate::cxx::OP_PixelFormat::BGRA8Fixed, - PixelFormat::RGBA8Fixed => crate::cxx::OP_PixelFormat::RGBA8Fixed, - PixelFormat::RGBA16Fixed => crate::cxx::OP_PixelFormat::RGBA16Fixed, - PixelFormat::RGBA16Float => crate::cxx::OP_PixelFormat::RGBA16Float, - PixelFormat::RGBA32Float => crate::cxx::OP_PixelFormat::RGBA32Float, - PixelFormat::Mono8Fixed => crate::cxx::OP_PixelFormat::Mono8Fixed, - PixelFormat::Mono16Fixed => crate::cxx::OP_PixelFormat::Mono16Fixed, - PixelFormat::Mono16Float => crate::cxx::OP_PixelFormat::Mono16Float, - PixelFormat::Mono32Float => crate::cxx::OP_PixelFormat::Mono32Float, - PixelFormat::RG8Fixed => crate::cxx::OP_PixelFormat::RG8Fixed, - PixelFormat::RG16Fixed => crate::cxx::OP_PixelFormat::RG16Fixed, - PixelFormat::RG16Float => crate::cxx::OP_PixelFormat::RG16Float, - PixelFormat::RG32Float => crate::cxx::OP_PixelFormat::RG32Float, - PixelFormat::A8Fixed => crate::cxx::OP_PixelFormat::A8Fixed, - PixelFormat::A16Fixed => crate::cxx::OP_PixelFormat::A16Fixed, - PixelFormat::A16Float => crate::cxx::OP_PixelFormat::A16Float, - PixelFormat::A32Float => crate::cxx::OP_PixelFormat::A32Float, - PixelFormat::MonoA8Fixed => crate::cxx::OP_PixelFormat::MonoA8Fixed, - PixelFormat::MonoA16Fixed => crate::cxx::OP_PixelFormat::MonoA16Fixed, - PixelFormat::MonoA16Float => crate::cxx::OP_PixelFormat::MonoA16Float, - PixelFormat::MonoA32Float => crate::cxx::OP_PixelFormat::MonoA32Float, - PixelFormat::SBGRA8Fixed => crate::cxx::OP_PixelFormat::SBGRA8Fixed, - PixelFormat::SRGBA8Fixed => crate::cxx::OP_PixelFormat::SRGBA8Fixed, - PixelFormat::RGB10A2Fixed => crate::cxx::OP_PixelFormat::RGB10A2Fixed, - PixelFormat::RGB11Float => crate::cxx::OP_PixelFormat::RGB11Float, - } - } -} - -#[derive(Debug, Default)] -pub struct DownloadOptions { - pub vertical_flip: bool, - pub pixel_format: PixelFormat, -} - -#[repr(transparent)] -#[derive(RefCast)] -pub struct TopInput { - input: OP_TOPInput, -} - -impl TopInput { - pub fn download_texture(&self, opts: DownloadOptions) -> TopDownloadResult { - let opts = crate::cxx::OP_TOPInputDownloadOptions { - verticalFlip: false, - pixelFormat: (&opts.pixel_format).into(), - }; - let download = unsafe { self.input.downloadTexture(&opts, std::ptr::null_mut()) }; - TopDownloadResult::new(download) - } -} - -pub struct TopDownloadResult { - result: cxx::UniquePtr, -} - -impl TopDownloadResult { - pub fn new( - result: cxx::UniquePtr, - ) -> Self { - Self { result } - } - - pub fn size(&mut self) -> usize { - crate::cxx::getDownloadDataSize(self.result.pin_mut()) as usize - } - - pub fn data(&mut self) -> &[T] { - let size = self.size(); - let data = crate::cxx::getDownloadData(self.result.pin_mut()); - unsafe { std::slice::from_raw_parts(data as *const T, size) } - } - - pub fn texture_desc(&mut self) -> TextureDesc { - let desc = crate::cxx::getDownloadTextureDesc(self.result.pin_mut()); - TextureDesc { - width: desc.width as usize, - height: desc.height as usize, - depth: desc.depth as usize, - tex_dim: match desc.texDim { - crate::cxx::OP_TexDim::eInvalid => TexDim::EInvalid, - crate::cxx::OP_TexDim::e2D => TexDim::E2D, - crate::cxx::OP_TexDim::e2DArray => TexDim::E2DArray, - crate::cxx::OP_TexDim::e3D => TexDim::E3D, - crate::cxx::OP_TexDim::eCube => TexDim::ECube, - }, - pixel_format: PixelFormat::from(&desc.pixelFormat), - aspect_x: 0.0, - aspect_y: 0.0, - } - } -} - -impl Drop for TopDownloadResult { - fn drop(&mut self) { - if self.result.is_null() { - return; - } - crate::cxx::releaseDownloadResult(self.result.pin_mut()) - } -} - -impl<'cook> GetInput<'cook, TopInput> for OperatorInputs<'cook, TopInput> { - fn num_inputs(&self) -> usize { - self.inputs.getNumInputs() as usize - } - - fn input(&self, index: usize) -> Option<&'cook TopInput> { - let input = self.inputs.getInputTOP(index as i32); - if input.is_null() { - None - } else { - Some(TopInput::ref_cast(unsafe { &*input })) - } - } -} +use crate::cxx::{OP_PixelFormat, OP_TOPInput, OP_TexDim}; +use crate::{GetInput, OperatorInputs}; +use ref_cast::RefCast; + +#[cfg(feature = "cuda")] +use crate::cxx::OP_CUDAArrayInfo; + +#[derive(Debug, Default, Eq, PartialEq, Clone)] +pub enum TexDim { + #[default] + EInvalid, + E2D, + E2DArray, + E3D, + ECube, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct TextureDesc { + pub width: usize, + pub height: usize, + pub depth: usize, + pub tex_dim: TexDim, + pub pixel_format: PixelFormat, + pub aspect_x: f32, + pub aspect_y: f32, +} + +impl Default for TextureDesc { + fn default() -> Self { + Self { + width: 0, + height: 0, + depth: 1, + tex_dim: TexDim::EInvalid, + pixel_format: PixelFormat::Invalid, + aspect_x: 0.0, + aspect_y: 0.0, + } + } +} + +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] +pub enum PixelFormat { + #[default] + Invalid, + + // 8-bit per color, BGRA pixels. This is preferred for 4 channel 8-bit data + BGRA8Fixed, + // 8-bit per color, RGBA pixels. Only use this one if absolutely nessessary. + RGBA8Fixed, + RGBA16Fixed, + RGBA16Float, + RGBA32Float, + + Mono8Fixed, + Mono16Fixed, + Mono16Float, + Mono32Float, + + // RG two channel + RG8Fixed, + RG16Fixed, + RG16Float, + RG32Float, + + // Alpha only + A8Fixed, + A16Fixed, + A16Float, + A32Float, + + // Mono with Alpha + MonoA8Fixed, + MonoA16Fixed, + MonoA16Float, + MonoA32Float, + + // sRGB. use SBGRA if possible since that's what most GPUs use + SBGRA8Fixed, + SRGBA8Fixed, + + RGB10A2Fixed, + // 11-bit float, positive values only. B is actually 10 bits + RGB11Float, +} + +impl From<&OP_PixelFormat> for PixelFormat { + fn from(pixel_format: &OP_PixelFormat) -> Self { + match pixel_format { + OP_PixelFormat::Invalid => PixelFormat::Invalid, + OP_PixelFormat::BGRA8Fixed => PixelFormat::BGRA8Fixed, + OP_PixelFormat::RGBA8Fixed => PixelFormat::RGBA8Fixed, + OP_PixelFormat::RGBA16Fixed => PixelFormat::RGBA16Fixed, + OP_PixelFormat::RGBA16Float => PixelFormat::RGBA16Float, + OP_PixelFormat::RGBA32Float => PixelFormat::RGBA32Float, + OP_PixelFormat::Mono8Fixed => PixelFormat::Mono8Fixed, + OP_PixelFormat::Mono16Fixed => PixelFormat::Mono16Fixed, + OP_PixelFormat::Mono16Float => PixelFormat::Mono16Float, + OP_PixelFormat::Mono32Float => PixelFormat::Mono32Float, + OP_PixelFormat::RG8Fixed => PixelFormat::RG8Fixed, + OP_PixelFormat::RG16Fixed => PixelFormat::RG16Fixed, + OP_PixelFormat::RG16Float => PixelFormat::RG16Float, + OP_PixelFormat::RG32Float => PixelFormat::RG32Float, + OP_PixelFormat::A8Fixed => PixelFormat::A8Fixed, + OP_PixelFormat::A16Fixed => PixelFormat::A16Fixed, + OP_PixelFormat::A16Float => PixelFormat::A16Float, + OP_PixelFormat::A32Float => PixelFormat::A32Float, + OP_PixelFormat::MonoA8Fixed => PixelFormat::MonoA8Fixed, + OP_PixelFormat::MonoA16Fixed => PixelFormat::MonoA16Fixed, + OP_PixelFormat::MonoA16Float => PixelFormat::MonoA16Float, + OP_PixelFormat::MonoA32Float => PixelFormat::MonoA32Float, + OP_PixelFormat::SBGRA8Fixed => PixelFormat::SBGRA8Fixed, + OP_PixelFormat::SRGBA8Fixed => PixelFormat::SRGBA8Fixed, + OP_PixelFormat::RGB10A2Fixed => PixelFormat::RGB10A2Fixed, + OP_PixelFormat::RGB11Float => PixelFormat::RGB11Float, + } + } +} + +impl From<&PixelFormat> for OP_PixelFormat { + fn from(pixel_format: &PixelFormat) -> Self { + match pixel_format { + PixelFormat::Invalid => OP_PixelFormat::Invalid, + PixelFormat::BGRA8Fixed => OP_PixelFormat::BGRA8Fixed, + PixelFormat::RGBA8Fixed => OP_PixelFormat::RGBA8Fixed, + PixelFormat::RGBA16Fixed => OP_PixelFormat::RGBA16Fixed, + PixelFormat::RGBA16Float => OP_PixelFormat::RGBA16Float, + PixelFormat::RGBA32Float => OP_PixelFormat::RGBA32Float, + PixelFormat::Mono8Fixed => OP_PixelFormat::Mono8Fixed, + PixelFormat::Mono16Fixed => OP_PixelFormat::Mono16Fixed, + PixelFormat::Mono16Float => OP_PixelFormat::Mono16Float, + PixelFormat::Mono32Float => OP_PixelFormat::Mono32Float, + PixelFormat::RG8Fixed => OP_PixelFormat::RG8Fixed, + PixelFormat::RG16Fixed => OP_PixelFormat::RG16Fixed, + PixelFormat::RG16Float => OP_PixelFormat::RG16Float, + PixelFormat::RG32Float => OP_PixelFormat::RG32Float, + PixelFormat::A8Fixed => OP_PixelFormat::A8Fixed, + PixelFormat::A16Fixed => OP_PixelFormat::A16Fixed, + PixelFormat::A16Float => OP_PixelFormat::A16Float, + PixelFormat::A32Float => OP_PixelFormat::A32Float, + PixelFormat::MonoA8Fixed => OP_PixelFormat::MonoA8Fixed, + PixelFormat::MonoA16Fixed => OP_PixelFormat::MonoA16Fixed, + PixelFormat::MonoA16Float => OP_PixelFormat::MonoA16Float, + PixelFormat::MonoA32Float => OP_PixelFormat::MonoA32Float, + PixelFormat::SBGRA8Fixed => OP_PixelFormat::SBGRA8Fixed, + PixelFormat::SRGBA8Fixed => OP_PixelFormat::SRGBA8Fixed, + PixelFormat::RGB10A2Fixed => OP_PixelFormat::RGB10A2Fixed, + PixelFormat::RGB11Float => OP_PixelFormat::RGB11Float, + } + } +} + +impl From<&TexDim> for OP_TexDim { + fn from(tex_dim: &TexDim) -> Self { + match tex_dim { + TexDim::EInvalid => OP_TexDim::eInvalid, + TexDim::E2D => OP_TexDim::e2D, + TexDim::E2DArray => OP_TexDim::e2DArray, + TexDim::E3D => OP_TexDim::e3D, + TexDim::ECube => OP_TexDim::eCube, + } + } +} + +#[derive(Debug, Default)] +pub struct DownloadOptions { + pub vertical_flip: bool, + pub pixel_format: PixelFormat, +} + +#[repr(transparent)] +#[derive(RefCast)] +pub struct TopInput { + input: OP_TOPInput, +} + +impl TopInput { + pub fn texture_desc(&self) -> TextureDesc { + let desc = crate::cxx::getTOPInputTextureDesc(&self.input); + TextureDesc { + width: desc.width as usize, + height: desc.height as usize, + depth: desc.depth as usize, + tex_dim: match desc.texDim { + OP_TexDim::eInvalid => TexDim::EInvalid, + OP_TexDim::e2D => TexDim::E2D, + OP_TexDim::e2DArray => TexDim::E2DArray, + OP_TexDim::e3D => TexDim::E3D, + OP_TexDim::eCube => TexDim::ECube, + }, + pixel_format: PixelFormat::from(&desc.pixelFormat), + aspect_x: desc.aspectX, + aspect_y: desc.aspectY, + } + } + + pub fn download_texture(&self, opts: DownloadOptions) -> TopDownloadResult { + let opts = crate::cxx::OP_TOPInputDownloadOptions { + verticalFlip: false, + pixelFormat: (&opts.pixel_format).into(), + }; + let download = unsafe { self.input.downloadTexture(&opts, std::ptr::null_mut()) }; + TopDownloadResult::new(download) + } + + #[cfg(feature = "cuda")] + pub fn get_cuda_array( + &self, + stream: cudarc::runtime::sys::cudaStream_t, + ) -> Result { + use autocxx::moveit::moveit; + + moveit! { let acquire_info = unsafe { + crate::cxx::createCUDAAcquireInfo(stream as *mut autocxx::c_void) + } } + + let array_info = unsafe { + self.input + .getCUDAArray(acquire_info.as_ref().get_ref(), std::ptr::null_mut()) + }; + + CudaArrayInfo::new(array_info) + } +} + +pub struct TopDownloadResult { + result: cxx::UniquePtr, +} + +impl TopDownloadResult { + pub fn new( + result: cxx::UniquePtr, + ) -> Self { + Self { result } + } + + pub fn size(&mut self) -> usize { + crate::cxx::getDownloadDataSize(self.result.pin_mut()) as usize + } + + pub fn data(&mut self) -> &[T] { + let size = self.size(); + let data = crate::cxx::getDownloadData(self.result.pin_mut()); + unsafe { std::slice::from_raw_parts(data as *const T, size) } + } + + pub fn texture_desc(&mut self) -> TextureDesc { + let desc = crate::cxx::getDownloadTextureDesc(self.result.pin_mut()); + TextureDesc { + width: desc.width as usize, + height: desc.height as usize, + depth: desc.depth as usize, + tex_dim: match desc.texDim { + OP_TexDim::eInvalid => TexDim::EInvalid, + OP_TexDim::e2D => TexDim::E2D, + OP_TexDim::e2DArray => TexDim::E2DArray, + OP_TexDim::e3D => TexDim::E3D, + OP_TexDim::eCube => TexDim::ECube, + }, + pixel_format: PixelFormat::from(&desc.pixelFormat), + aspect_x: 0.0, + aspect_y: 0.0, + } + } +} + +impl Drop for TopDownloadResult { + fn drop(&mut self) { + if self.result.is_null() { + return; + } + crate::cxx::releaseDownloadResult(self.result.pin_mut()) + } +} + +impl<'cook> GetInput<'cook, TopInput> for OperatorInputs<'cook, TopInput> { + fn num_inputs(&self) -> usize { + self.inputs.getNumInputs() as usize + } + + fn input(&self, index: usize) -> Option<&'cook TopInput> { + let input = self.inputs.getInputTOP(index as i32); + if input.is_null() { + None + } else { + Some(TopInput::ref_cast(unsafe { &*input })) + } + } +} + +#[cfg(feature = "cuda")] +#[derive(Debug)] +pub struct CudaArrayInfo { + pub(crate) info: *const OP_CUDAArrayInfo, +} + +#[cfg(feature = "cuda")] +unsafe impl Send for CudaArrayInfo {} +#[cfg(feature = "cuda")] +unsafe impl Sync for CudaArrayInfo {} + +#[cfg(feature = "cuda")] +impl CudaArrayInfo { + pub fn new(info: *const OP_CUDAArrayInfo) -> Result { + if info.is_null() { + return Err(anyhow::anyhow!("Null CUDA array info pointer")); + } + Ok(Self { info }) + } + + pub fn texture_desc(&self) -> TextureDesc { + unsafe { + let cpp_desc = crate::cxx::getCUDAArrayInfoTextureDesc(self.info.as_ref().unwrap()); + TextureDesc { + width: cpp_desc.width as usize, + height: cpp_desc.height as usize, + depth: cpp_desc.depth as usize, + tex_dim: match cpp_desc.texDim { + OP_TexDim::eInvalid => TexDim::EInvalid, + OP_TexDim::e2D => TexDim::E2D, + OP_TexDim::e2DArray => TexDim::E2DArray, + OP_TexDim::e3D => TexDim::E3D, + OP_TexDim::eCube => TexDim::ECube, + }, + pixel_format: (&cpp_desc.pixelFormat).into(), + aspect_x: cpp_desc.aspectX, + aspect_y: cpp_desc.aspectY, + } + } + } + + #[cfg(feature = "cuda")] + pub unsafe fn cuda_array(&self) -> *mut cudarc::runtime::sys::cudaArray { + crate::cxx::getCUDAArrayInfoArray(self.info.as_ref().unwrap()) + as *mut cudarc::runtime::sys::cudaArray + } +} diff --git a/td-rs-chop/Cargo.toml b/td-rs-chop/Cargo.toml index 24604a1..7f9ce51 100644 --- a/td-rs-chop/Cargo.toml +++ b/td-rs-chop/Cargo.toml @@ -1,27 +1,27 @@ -[package] -name = "td-rs-chop" -version = "0.1.0" -edition = "2021" - -[lib] -name = "td_rs_chop" -crate-type = ["lib", "staticlib"] - -[dependencies] -autocxx = { git = "https://github.com/tychedelia/autocxx.git" } -cxx = "1.0.78" -td-rs-base = { path = "../td-rs-base" } -tracing-base = { package = "tracing", version = "0.1", optional = true } -tracing-subscriber = { version = "0.2", optional = true } -pyo3 = { git = "https://github.com/tychedelia/pyo3", branch = "td-rs", features = ["abi3-py311"], optional = true } - -[build-dependencies] -td-rs-autocxx-build = { path = "../td-rs-autocxx-build" } -autocxx-build = { git = "https://github.com/tychedelia/autocxx.git" } -miette = { version="5", features = [ "fancy" ] } - -[features] -default = [] -python = ["td-rs-base/python", "dep:pyo3"] -tracing = ["td-rs-base/tracing", "tracing-base", "tracing-subscriber"] +[package] +name = "td-rs-chop" +version = "0.1.0" +edition = "2021" + +[lib] +name = "td_rs_chop" +crate-type = ["lib", "staticlib"] + +[dependencies] +autocxx = { git = "https://github.com/tychedelia/autocxx.git" } +cxx = "1.0.78" +td-rs-base = { path = "../td-rs-base" } +tracing-base = { package = "tracing", version = "0.1", optional = true } +tracing-subscriber = { version = "0.2", optional = true } +pyo3 = { git = "https://github.com/tychedelia/pyo3", branch = "td-rs", features = ["abi3-py311"], optional = true } + +[build-dependencies] +td-rs-autocxx-build = { path = "../td-rs-autocxx-build" } +autocxx-build = { git = "https://github.com/tychedelia/autocxx.git" } +miette = { version="5", features = [ "fancy" ] } + +[features] +default = [] +python = ["td-rs-base/python", "dep:pyo3"] +tracing = ["td-rs-base/tracing", "tracing-base", "tracing-subscriber"] tokio = ["td-rs-base/tokio"] \ No newline at end of file diff --git a/td-rs-chop/build.rs b/td-rs-chop/build.rs index ee94ac3..630340d 100644 --- a/td-rs-chop/build.rs +++ b/td-rs-chop/build.rs @@ -1,3 +1,3 @@ -fn main() -> miette::Result<()> { - td_rs_autocxx_build::build("td-rs-chop", true) -} +fn main() -> miette::Result<()> { + td_rs_autocxx_build::build("td-rs-chop", true) +} diff --git a/td-rs-chop/src/CHOP_CPlusPlusBase.h b/td-rs-chop/src/CHOP_CPlusPlusBase.h index b679d4f..f288244 100644 --- a/td-rs-chop/src/CHOP_CPlusPlusBase.h +++ b/td-rs-chop/src/CHOP_CPlusPlusBase.h @@ -124,7 +124,7 @@ class CHOP_OutputInfo { uint32_t startIndex; // Specify the sample rate of the channel data - // DEFAULT : whatever the timeline FPS is ($FPS) + // DEFAULT : whatever the component timeline FPS is. (me.time.rate) float sampleRate; void *reserved1; @@ -353,7 +353,6 @@ static_assert(offsetof(CHOP_Output, startIndex) == 12, "Incorrect Alignment"); static_assert(offsetof(CHOP_Output, names) == 16, "Incorrect Alignment"); static_assert(offsetof(CHOP_Output, channels) == 24, "Incorrect Alignment"); static_assert(sizeof(CHOP_Output) == 112, "Incorrect Size"); - }; // namespace TD -#endif \ No newline at end of file +#endif diff --git a/td-rs-chop/src/RustChopPlugin.cpp b/td-rs-chop/src/RustChopPlugin.cpp index 3a0a31a..ca0bf56 100644 --- a/td-rs-chop/src/RustChopPlugin.cpp +++ b/td-rs-chop/src/RustChopPlugin.cpp @@ -1,32 +1,32 @@ -#include "RustChopPlugin.h" -#include "CPlusPlus_Common.h" -#include -#ifdef PYTHON_ENABLED -#include -#endif - -extern "C" { - -RustChopPlugin *chop_new(const OP_NodeInfo &info); -void chop_get_plugin_info_impl(OP_CustomOPInfo &opInfo); - -DLLEXPORT -void FillCHOPPluginInfo(CHOP_PluginInfo *info) { - info->apiVersion = CHOPCPlusPlusAPIVersion; - auto opInfo = &info->customOPInfo; - chop_get_plugin_info_impl(*opInfo); -#ifdef PYTHON_ENABLED - opInfo->pythonVersion->setString(PY_VERSION); -#endif -} - -DLLEXPORT -CHOP_CPlusPlusBase *CreateCHOPInstance(const OP_NodeInfo *info) { - return chop_new(*info); -} - -DLLEXPORT -void DestroyCHOPInstance(CHOP_CPlusPlusBase *instance) { - delete (RustChopPlugin *)instance; -} -} +#include "RustChopPlugin.h" +#include "CPlusPlus_Common.h" +#include +#ifdef PYTHON_ENABLED +#include +#endif + +extern "C" { + +RustChopPlugin *chop_new(const OP_NodeInfo &info); +void chop_get_plugin_info_impl(OP_CustomOPInfo &opInfo); + +DLLEXPORT +void FillCHOPPluginInfo(CHOP_PluginInfo *info) { + info->apiVersion = CHOPCPlusPlusAPIVersion; + auto opInfo = &info->customOPInfo; + chop_get_plugin_info_impl(*opInfo); +#ifdef PYTHON_ENABLED + opInfo->pythonVersion->setString(PY_VERSION); +#endif +} + +DLLEXPORT +CHOP_CPlusPlusBase *CreateCHOPInstance(const OP_NodeInfo *info) { + return chop_new(*info); +} + +DLLEXPORT +void DestroyCHOPInstance(CHOP_CPlusPlusBase *instance) { + delete (RustChopPlugin *)instance; +} +} diff --git a/td-rs-chop/src/RustChopPlugin.h b/td-rs-chop/src/RustChopPlugin.h index c72e81a..99048d9 100644 --- a/td-rs-chop/src/RustChopPlugin.h +++ b/td-rs-chop/src/RustChopPlugin.h @@ -1,155 +1,155 @@ -#include -#include "CHOP_CPlusPlusBase.h" -#include "CPlusPlus_Common.h" -#include - -#ifndef TD_RS_RUSTCHOP_H -#define TD_RS_RUSTCHOP_H - -using namespace TD; - -class ChopPlugin : public CHOP_CPlusPlusBase { -public: - virtual ~ChopPlugin() {}; - - void getGeneralInfo(CHOP_GeneralInfo *info, const OP_Inputs *inputs, void *reserved1) override { - this->getGeneralInfo(*info, *inputs); - } - - virtual void getGeneralInfo(CHOP_GeneralInfo &info, const OP_Inputs &inputs) {} - - bool getOutputInfo(CHOP_OutputInfo *info, const OP_Inputs *inputs, void *reserved1) override { - return this->getOutputInfo(*info, *inputs); - } - - virtual bool getOutputInfo(CHOP_OutputInfo &info, const OP_Inputs &inputs) { - return false; - } - - void getChannelName(int32_t index, OP_String *name, const OP_Inputs *inputs, void *reserved1) override { - this->getChannelName(index, *name, *inputs); - } - - virtual void getChannelName(int32_t index, OP_String &name, const OP_Inputs &inputs) {} - - void execute(CHOP_Output *outputs, const OP_Inputs *inputs, void *reserved1) override { - this->execute(*outputs, *inputs); - }; - - virtual void execute(CHOP_Output &outputs, const OP_Inputs &inputs) {} - - virtual int32_t getNumInfoCHOPChans(void *reserved1) override { - return this->getNumInfoCHOPChans(); - } - - virtual int32_t getNumInfoCHOPChans() { - return 0; - } - - void getInfoCHOPChan(int32_t index, OP_InfoCHOPChan *chan, void *reserved1) override { - OP_String *name = chan->name; - float v = 0.f; - float *value = &v; - this->getInfoCHOPChan(index, *name, *value); - chan->name = name; - chan->value = *value; - } - - virtual void getInfoCHOPChan(int32_t index, OP_String &name, float &value) {} - - bool getInfoDATSize(OP_InfoDATSize *infoSize, void *reserved1) override { - return this->getInfoDATSize(*infoSize); - } - - virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) { - return false; - } - - void getInfoDATEntries(int32_t index, int32_t nEntries, OP_InfoDATEntries *entries, void *reserved1) override { - for (int i = 0; i < nEntries; i++) { - auto entry = entries->values[i]; - this->getInfoDATEntry(index, i, *entry); - } - } - - virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, OP_String &entry) {} - - void getWarningString(OP_String *warning, void *reserved1) override { - this->getWarningString(*warning); - }; - - virtual void getWarningString(OP_String &warning) {} - - void getErrorString(OP_String *error, void *reserved1) override { - this->getErrorString(*error); - }; - - virtual void getErrorString(OP_String &error) {} - - void getInfoPopupString(OP_String *popup, void *reserved1) override { - this->getInfoPopupString(*popup); - }; - - virtual void getInfoPopupString(OP_String &popup) {} - - void setupParameters(OP_ParameterManager *manager, void *reserved1) override { - this->setupParameters(*manager); - }; - - virtual void setupParameters(OP_ParameterManager &manager) {} - - void pulsePressed(const char *name, void *reserved1) override { - this->pulsePressed(name); - }; - - virtual void pulsePressed(const char *name) {} - - virtual void buildDynamicMenu(const OP_Inputs *inputs, - OP_BuildDynamicMenuInfo *info, - void *reserved1) { - this->buildDynamicMenu(*inputs, *info); - } - - virtual void buildDynamicMenu(const OP_Inputs &inputs, - OP_BuildDynamicMenuInfo &info) {} -}; - -class RustChopPlugin : public ChopPlugin { -public: - virtual ~RustChopPlugin() {}; - - virtual void* inner() const = 0; - - virtual void* innerMut() = 0; - - virtual void getGeneralInfo(CHOP_GeneralInfo &info, const OP_Inputs &inputs) = 0; - - virtual bool getOutputInfo(CHOP_OutputInfo &info, const OP_Inputs &inputs) = 0; - - virtual void getChannelName(int32_t index, OP_String &name, const OP_Inputs &inputs) = 0; - - virtual void execute(CHOP_Output &outputs, const OP_Inputs &inputs) = 0; - - virtual int32_t getNumInfoCHOPChans() = 0; - - virtual void getInfoCHOPChan(int32_t index, OP_String &name, float &value) = 0; - - virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) = 0; - - virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, OP_String &entry) = 0; - - virtual void getWarningString(OP_String &warning) = 0; - - virtual void getErrorString(OP_String &error) = 0; - - virtual void getInfoPopupString(OP_String &popup) = 0; - - virtual void setupParameters(OP_ParameterManager &manager) = 0; - - virtual void pulsePressed(const char *name) = 0; - - virtual void buildDynamicMenu(const OP_Inputs &inputs, - OP_BuildDynamicMenuInfo &info) = 0; -}; - -#endif //TD_RS_RUSTCHOP_H +#include +#include "CHOP_CPlusPlusBase.h" +#include "CPlusPlus_Common.h" +#include + +#ifndef TD_RS_RUSTCHOP_H +#define TD_RS_RUSTCHOP_H + +using namespace TD; + +class ChopPlugin : public CHOP_CPlusPlusBase { +public: + virtual ~ChopPlugin() {}; + + void getGeneralInfo(CHOP_GeneralInfo *info, const OP_Inputs *inputs, void *reserved1) override { + this->getGeneralInfo(*info, *inputs); + } + + virtual void getGeneralInfo(CHOP_GeneralInfo &info, const OP_Inputs &inputs) {} + + bool getOutputInfo(CHOP_OutputInfo *info, const OP_Inputs *inputs, void *reserved1) override { + return this->getOutputInfo(*info, *inputs); + } + + virtual bool getOutputInfo(CHOP_OutputInfo &info, const OP_Inputs &inputs) { + return false; + } + + void getChannelName(int32_t index, OP_String *name, const OP_Inputs *inputs, void *reserved1) override { + this->getChannelName(index, *name, *inputs); + } + + virtual void getChannelName(int32_t index, OP_String &name, const OP_Inputs &inputs) {} + + void execute(CHOP_Output *outputs, const OP_Inputs *inputs, void *reserved1) override { + this->execute(*outputs, *inputs); + }; + + virtual void execute(CHOP_Output &outputs, const OP_Inputs &inputs) {} + + virtual int32_t getNumInfoCHOPChans(void *reserved1) override { + return this->getNumInfoCHOPChans(); + } + + virtual int32_t getNumInfoCHOPChans() { + return 0; + } + + void getInfoCHOPChan(int32_t index, OP_InfoCHOPChan *chan, void *reserved1) override { + OP_String *name = chan->name; + float v = 0.f; + float *value = &v; + this->getInfoCHOPChan(index, *name, *value); + chan->name = name; + chan->value = *value; + } + + virtual void getInfoCHOPChan(int32_t index, OP_String &name, float &value) {} + + bool getInfoDATSize(OP_InfoDATSize *infoSize, void *reserved1) override { + return this->getInfoDATSize(*infoSize); + } + + virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) { + return false; + } + + void getInfoDATEntries(int32_t index, int32_t nEntries, OP_InfoDATEntries *entries, void *reserved1) override { + for (int i = 0; i < nEntries; i++) { + auto entry = entries->values[i]; + this->getInfoDATEntry(index, i, *entry); + } + } + + virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, OP_String &entry) {} + + void getWarningString(OP_String *warning, void *reserved1) override { + this->getWarningString(*warning); + }; + + virtual void getWarningString(OP_String &warning) {} + + void getErrorString(OP_String *error, void *reserved1) override { + this->getErrorString(*error); + }; + + virtual void getErrorString(OP_String &error) {} + + void getInfoPopupString(OP_String *popup, void *reserved1) override { + this->getInfoPopupString(*popup); + }; + + virtual void getInfoPopupString(OP_String &popup) {} + + void setupParameters(OP_ParameterManager *manager, void *reserved1) override { + this->setupParameters(*manager); + }; + + virtual void setupParameters(OP_ParameterManager &manager) {} + + void pulsePressed(const char *name, void *reserved1) override { + this->pulsePressed(name); + }; + + virtual void pulsePressed(const char *name) {} + + virtual void buildDynamicMenu(const OP_Inputs *inputs, + OP_BuildDynamicMenuInfo *info, + void *reserved1) { + this->buildDynamicMenu(*inputs, *info); + } + + virtual void buildDynamicMenu(const OP_Inputs &inputs, + OP_BuildDynamicMenuInfo &info) {} +}; + +class RustChopPlugin : public ChopPlugin { +public: + virtual ~RustChopPlugin() {}; + + virtual void* inner() const = 0; + + virtual void* innerMut() = 0; + + virtual void getGeneralInfo(CHOP_GeneralInfo &info, const OP_Inputs &inputs) = 0; + + virtual bool getOutputInfo(CHOP_OutputInfo &info, const OP_Inputs &inputs) = 0; + + virtual void getChannelName(int32_t index, OP_String &name, const OP_Inputs &inputs) = 0; + + virtual void execute(CHOP_Output &outputs, const OP_Inputs &inputs) = 0; + + virtual int32_t getNumInfoCHOPChans() = 0; + + virtual void getInfoCHOPChan(int32_t index, OP_String &name, float &value) = 0; + + virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) = 0; + + virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, OP_String &entry) = 0; + + virtual void getWarningString(OP_String &warning) = 0; + + virtual void getErrorString(OP_String &error) = 0; + + virtual void getInfoPopupString(OP_String &popup) = 0; + + virtual void setupParameters(OP_ParameterManager &manager) = 0; + + virtual void pulsePressed(const char *name) = 0; + + virtual void buildDynamicMenu(const OP_Inputs &inputs, + OP_BuildDynamicMenuInfo &info) = 0; +}; + +#endif //TD_RS_RUSTCHOP_H diff --git a/td-rs-chop/src/cxx.rs b/td-rs-chop/src/cxx.rs index 02da45d..b283a14 100644 --- a/td-rs-chop/src/cxx.rs +++ b/td-rs-chop/src/cxx.rs @@ -1,248 +1,248 @@ -#![allow(non_snake_case)] -#![allow(ambiguous_glob_reexports)] - -use std::ffi::CString; -use std::pin::Pin; - -pub use autocxx::c_void; -use autocxx::prelude::*; -use autocxx::subclass::*; - -pub use ffi::TD::*; -pub use ffi::*; -pub use td_rs_base::cxx::*; -use td_rs_base::{DynamicMenuInfo, NodeInfo, OperatorInputs, ParameterManager}; - -use crate::{Chop, ChopOutput}; - -include_cpp! { - #include "CHOP_CPlusPlusBase.h" - #include "RustChopPlugin.h" - safety!(unsafe) - extern_cpp_type!("TD::OP_ParameterManager", td_rs_base::cxx::OP_ParameterManager) - extern_cpp_type!("TD::OP_String", td_rs_base::cxx::OP_String) - extern_cpp_type!("TD::OP_InfoDATSize", td_rs_base::cxx::OP_InfoDATSize) - extern_cpp_type!("TD::OP_InfoCHOPChan", td_rs_base::cxx::OP_InfoCHOPChan) - extern_cpp_type!("TD::OP_Inputs", td_rs_base::cxx::OP_Inputs) - extern_cpp_type!("TD::OP_CustomOPInfo", td_rs_base::cxx::OP_CustomOPInfo) - extern_cpp_type!("TD::OP_BuildDynamicMenuInfo", td_rs_base::cxx::OP_BuildDynamicMenuInfo) - pod!("TD::OP_CustomOPInfo") - generate_pod!("TD::CHOP_PluginInfo") - generate_pod!("TD::CHOP_GeneralInfo") - generate_pod!("TD::CHOP_OutputInfo") - generate_pod!("TD::CHOP_Output") - extern_cpp_type!("TD::PY_Struct", td_rs_base::cxx::PY_Struct) - extern_cpp_type!("TD::PY_GetInfo", td_rs_base::cxx::PY_GetInfo) -} - -extern "C" { - // SAFETY: `chop_new_impl` is only ever called from Rust compiled - // at the same time as the plugin, so the types are guaranteed to - // match - #[allow(improper_ctypes)] - fn chop_new_impl(info: NodeInfo) -> Box; -} - -#[subclass(superclass("RustChopPlugin"))] -pub struct RustChopPluginImpl { - pub inner: Box, -} - -// SAFETY: This can only be used with pointers returned from getNodeInstance() and -// should not be used in plugin code. -pub unsafe fn plugin_cast(plugin: *mut c_void) -> &'static mut RustChopPluginImplCpp { - &mut *(plugin as *mut RustChopPluginImplCpp) -} - -impl AsPlugin for RustChopPluginImplCpp { - type Plugin = RustChopPlugin; - - fn as_plugin(&self) -> &Self::Plugin { - self.As_RustChopPlugin() - } - - fn as_plugin_mut(&mut self) -> Pin<&mut Self::Plugin> { - // Safety: self can't be moved during the lifetime of 'cook. - unsafe { Pin::new_unchecked(self).As_RustChopPlugin_mut() } - } -} - -#[no_mangle] -extern "C" fn chop_new(info: &'static OP_NodeInfo) -> *mut RustChopPluginImplCpp { - unsafe { - let info = NodeInfo::new(info); - RustChopPluginImpl::new_cpp_owned(RustChopPluginImpl { - inner: chop_new_impl(info), - cpp_peer: CppSubclassCppPeerHolder::Empty, - }) - .into_raw() - } -} - -impl RustChopPlugin_methods for RustChopPluginImpl { - fn inner(&self) -> *mut c_void { - self.inner.as_ref() as *const dyn Chop as *mut c_void - } - - fn innerMut(&mut self) -> *mut c_void { - self.inner.as_mut() as *mut dyn Chop as *mut c_void - } - - fn getGeneralInfo(&mut self, mut info: Pin<&mut CHOP_GeneralInfo>, input: &OP_Inputs) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getGeneralInfo").entered() }; - let input = OperatorInputs::new(input); - if let Some(params) = self.inner.params_mut() { - params.update(&input.params()); - } - let gen_info = self.inner.general_info(&input); - info.cookEveryFrame = gen_info.cook_every_frame; - info.cookEveryFrameIfAsked = gen_info.cook_every_frame_if_asked; - info.timeslice = gen_info.timeslice; - info.inputMatchIndex = gen_info.input_match_index; - } - - fn getOutputInfo(&mut self, mut info: Pin<&mut CHOP_OutputInfo>, input: &OP_Inputs) -> bool { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getOutputInfo").entered() }; - let input = OperatorInputs::new(input); - if let Some(params) = self.inner.params_mut() { - params.update(&input.params()); - } - let out_info = self.inner.output_info(&input); - if let Some(out_info) = out_info { - info.numChannels = out_info.num_channels as i32; - info.sampleRate = out_info.sample_rate; - info.numSamples = out_info.num_samples as i32; - info.startIndex = out_info.start_index as u32; - true - } else { - false - } - } - - fn getChannelName(&mut self, index: i32, name: Pin<&mut OP_String>, input: &OP_Inputs) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getChannelName").entered() }; - let input = OperatorInputs::new(input); - let chan_name = self.inner.channel_name(index as usize, &input); - unsafe { - let new_string = CString::new(chan_name.as_str()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - name.setString(new_string_ptr); - } - } - - fn execute(&mut self, output: Pin<&mut CHOP_Output>, input: &OP_Inputs) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("execute").entered() }; - let input = OperatorInputs::new(input); - let mut output = ChopOutput::new(output); - if let Some(params) = self.inner.params_mut() { - params.update(&input.params()); - } - self.inner.execute(&mut output, &input); - } - - fn getNumInfoCHOPChans(&mut self) -> i32 { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getNumInfoCHOPChans").entered() }; - if let Some(info_chop) = self.inner.info_chop() { - info_chop.size() as i32 - } else { - 0 - } - } - - fn getInfoCHOPChan(&mut self, index: i32, name: Pin<&mut OP_String>, mut value: Pin<&mut f32>) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getInfoCHOPChan").entered() }; - if let Some(info_chop) = self.inner.info_chop() { - let (info_name, info_value) = info_chop.channel(index as usize); - unsafe { - let new_string = CString::new(info_name.as_str()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - name.setString(new_string_ptr); - } - value.set(info_value); - } - } - - fn getInfoDATSize(&mut self, mut info: Pin<&mut OP_InfoDATSize>) -> bool { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getInfoDATSize").entered() }; - if let Some(info_dat) = self.inner.info_dat() { - let (rows, cols) = info_dat.size(); - info.rows = rows as i32; - info.cols = cols as i32; - true - } else { - false - } - } - - fn getInfoDATEntry(&mut self, index: i32, entryIndex: i32, entry: Pin<&mut OP_String>) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getInfoDATEntry").entered() }; - if let Some(info_dat) = self.inner.info_dat() { - let entry_str = info_dat.entry(index as usize, entryIndex as usize); - if entry_str.is_empty() { - return; - } - unsafe { - let new_string = CString::new(entry_str.as_str()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - entry.setString(new_string_ptr); - } - } - } - - fn getWarningString(&mut self, warning: Pin<&mut OP_String>) { - unsafe { - let new_string = CString::new(self.inner.warning()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - warning.setString(new_string_ptr); - } - } - - fn getErrorString(&mut self, error: Pin<&mut OP_String>) { - unsafe { - let new_string = CString::new(self.inner.error()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - error.setString(new_string_ptr); - } - } - - fn getInfoPopupString(&mut self, info: Pin<&mut OP_String>) { - unsafe { - let new_string = CString::new(self.inner.info()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - info.setString(new_string_ptr); - } - } - - fn setupParameters(&mut self, manager: Pin<&mut OP_ParameterManager>) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("setupParameters").entered() }; - let params = self.inner.params_mut(); - if let Some(params) = params { - let mut manager = ParameterManager::new(manager); - params.register(&mut manager); - } - } - - unsafe fn pulsePressed(&mut self, name: *const std::ffi::c_char) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("pulsePressed").entered() }; - self.inner - .pulse_pressed(std::ffi::CStr::from_ptr(name).to_str().unwrap()); - } - - fn buildDynamicMenu(&mut self, inputs: &OP_Inputs, info: Pin<&mut OP_BuildDynamicMenuInfo>) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("buildDynamicMenu").entered() }; - let input = OperatorInputs::new(inputs); - let mut info = DynamicMenuInfo::new(info); - self.inner.build_dynamic_menu(&input, &mut info); - } -} +#![allow(non_snake_case)] +#![allow(ambiguous_glob_reexports)] + +use std::ffi::CString; +use std::pin::Pin; + +pub use autocxx::c_void; +use autocxx::prelude::*; +use autocxx::subclass::*; + +pub use ffi::TD::*; +pub use ffi::*; +pub use td_rs_base::cxx::*; +use td_rs_base::{DynamicMenuInfo, NodeInfo, OperatorInputs, ParameterManager}; + +use crate::{Chop, ChopOutput}; + +include_cpp! { + #include "CHOP_CPlusPlusBase.h" + #include "RustChopPlugin.h" + safety!(unsafe) + extern_cpp_type!("TD::OP_ParameterManager", td_rs_base::cxx::OP_ParameterManager) + extern_cpp_type!("TD::OP_String", td_rs_base::cxx::OP_String) + extern_cpp_type!("TD::OP_InfoDATSize", td_rs_base::cxx::OP_InfoDATSize) + extern_cpp_type!("TD::OP_InfoCHOPChan", td_rs_base::cxx::OP_InfoCHOPChan) + extern_cpp_type!("TD::OP_Inputs", td_rs_base::cxx::OP_Inputs) + extern_cpp_type!("TD::OP_CustomOPInfo", td_rs_base::cxx::OP_CustomOPInfo) + extern_cpp_type!("TD::OP_BuildDynamicMenuInfo", td_rs_base::cxx::OP_BuildDynamicMenuInfo) + pod!("TD::OP_CustomOPInfo") + generate_pod!("TD::CHOP_PluginInfo") + generate_pod!("TD::CHOP_GeneralInfo") + generate_pod!("TD::CHOP_OutputInfo") + generate_pod!("TD::CHOP_Output") + extern_cpp_type!("TD::PY_Struct", td_rs_base::cxx::PY_Struct) + extern_cpp_type!("TD::PY_GetInfo", td_rs_base::cxx::PY_GetInfo) +} + +extern "C" { + // SAFETY: `chop_new_impl` is only ever called from Rust compiled + // at the same time as the plugin, so the types are guaranteed to + // match + #[allow(improper_ctypes)] + fn chop_new_impl(info: NodeInfo) -> Box; +} + +#[subclass(superclass("RustChopPlugin"))] +pub struct RustChopPluginImpl { + pub inner: Box, +} + +// SAFETY: This can only be used with pointers returned from getNodeInstance() and +// should not be used in plugin code. +pub unsafe fn plugin_cast(plugin: *mut c_void) -> &'static mut RustChopPluginImplCpp { + &mut *(plugin as *mut RustChopPluginImplCpp) +} + +impl AsPlugin for RustChopPluginImplCpp { + type Plugin = RustChopPlugin; + + fn as_plugin(&self) -> &Self::Plugin { + self.As_RustChopPlugin() + } + + fn as_plugin_mut(&mut self) -> Pin<&mut Self::Plugin> { + // Safety: self can't be moved during the lifetime of 'cook. + unsafe { Pin::new_unchecked(self).As_RustChopPlugin_mut() } + } +} + +#[no_mangle] +extern "C" fn chop_new(info: &'static OP_NodeInfo) -> *mut RustChopPluginImplCpp { + unsafe { + let info = NodeInfo::new(info); + RustChopPluginImpl::new_cpp_owned(RustChopPluginImpl { + inner: chop_new_impl(info), + cpp_peer: CppSubclassCppPeerHolder::Empty, + }) + .into_raw() + } +} + +impl RustChopPlugin_methods for RustChopPluginImpl { + fn inner(&self) -> *mut c_void { + self.inner.as_ref() as *const dyn Chop as *mut c_void + } + + fn innerMut(&mut self) -> *mut c_void { + self.inner.as_mut() as *mut dyn Chop as *mut c_void + } + + fn getGeneralInfo(&mut self, mut info: Pin<&mut CHOP_GeneralInfo>, input: &OP_Inputs) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getGeneralInfo").entered() }; + let input = OperatorInputs::new(input); + if let Some(params) = self.inner.params_mut() { + params.update(&input.params()); + } + let gen_info = self.inner.general_info(&input); + info.cookEveryFrame = gen_info.cook_every_frame; + info.cookEveryFrameIfAsked = gen_info.cook_every_frame_if_asked; + info.timeslice = gen_info.timeslice; + info.inputMatchIndex = gen_info.input_match_index; + } + + fn getOutputInfo(&mut self, mut info: Pin<&mut CHOP_OutputInfo>, input: &OP_Inputs) -> bool { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getOutputInfo").entered() }; + let input = OperatorInputs::new(input); + if let Some(params) = self.inner.params_mut() { + params.update(&input.params()); + } + let out_info = self.inner.output_info(&input); + if let Some(out_info) = out_info { + info.numChannels = out_info.num_channels as i32; + info.sampleRate = out_info.sample_rate; + info.numSamples = out_info.num_samples as i32; + info.startIndex = out_info.start_index as u32; + true + } else { + false + } + } + + fn getChannelName(&mut self, index: i32, name: Pin<&mut OP_String>, input: &OP_Inputs) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getChannelName").entered() }; + let input = OperatorInputs::new(input); + let chan_name = self.inner.channel_name(index as usize, &input); + unsafe { + let new_string = CString::new(chan_name.as_str()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + name.setString(new_string_ptr); + } + } + + fn execute(&mut self, output: Pin<&mut CHOP_Output>, input: &OP_Inputs) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("execute").entered() }; + let input = OperatorInputs::new(input); + let mut output = ChopOutput::new(output); + if let Some(params) = self.inner.params_mut() { + params.update(&input.params()); + } + self.inner.execute(&mut output, &input); + } + + fn getNumInfoCHOPChans(&mut self) -> i32 { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getNumInfoCHOPChans").entered() }; + if let Some(info_chop) = self.inner.info_chop() { + info_chop.size() as i32 + } else { + 0 + } + } + + fn getInfoCHOPChan(&mut self, index: i32, name: Pin<&mut OP_String>, mut value: Pin<&mut f32>) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getInfoCHOPChan").entered() }; + if let Some(info_chop) = self.inner.info_chop() { + let (info_name, info_value) = info_chop.channel(index as usize); + unsafe { + let new_string = CString::new(info_name.as_str()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + name.setString(new_string_ptr); + } + value.set(info_value); + } + } + + fn getInfoDATSize(&mut self, mut info: Pin<&mut OP_InfoDATSize>) -> bool { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getInfoDATSize").entered() }; + if let Some(info_dat) = self.inner.info_dat() { + let (rows, cols) = info_dat.size(); + info.rows = rows as i32; + info.cols = cols as i32; + true + } else { + false + } + } + + fn getInfoDATEntry(&mut self, index: i32, entryIndex: i32, entry: Pin<&mut OP_String>) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getInfoDATEntry").entered() }; + if let Some(info_dat) = self.inner.info_dat() { + let entry_str = info_dat.entry(index as usize, entryIndex as usize); + if entry_str.is_empty() { + return; + } + unsafe { + let new_string = CString::new(entry_str.as_str()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + entry.setString(new_string_ptr); + } + } + } + + fn getWarningString(&mut self, warning: Pin<&mut OP_String>) { + unsafe { + let new_string = CString::new(self.inner.warning()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + warning.setString(new_string_ptr); + } + } + + fn getErrorString(&mut self, error: Pin<&mut OP_String>) { + unsafe { + let new_string = CString::new(self.inner.error()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + error.setString(new_string_ptr); + } + } + + fn getInfoPopupString(&mut self, info: Pin<&mut OP_String>) { + unsafe { + let new_string = CString::new(self.inner.info()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + info.setString(new_string_ptr); + } + } + + fn setupParameters(&mut self, manager: Pin<&mut OP_ParameterManager>) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("setupParameters").entered() }; + let params = self.inner.params_mut(); + if let Some(params) = params { + let mut manager = ParameterManager::new(manager); + params.register(&mut manager); + } + } + + unsafe fn pulsePressed(&mut self, name: *const std::ffi::c_char) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("pulsePressed").entered() }; + self.inner + .pulse_pressed(std::ffi::CStr::from_ptr(name).to_str().unwrap()); + } + + fn buildDynamicMenu(&mut self, inputs: &OP_Inputs, info: Pin<&mut OP_BuildDynamicMenuInfo>) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("buildDynamicMenu").entered() }; + let input = OperatorInputs::new(inputs); + let mut info = DynamicMenuInfo::new(info); + self.inner.build_dynamic_menu(&input, &mut info); + } +} diff --git a/td-rs-chop/src/lib.rs b/td-rs-chop/src/lib.rs index ff2dcca..77e456b 100644 --- a/td-rs-chop/src/lib.rs +++ b/td-rs-chop/src/lib.rs @@ -1,154 +1,154 @@ -#![feature(min_specialization)] - -use std::fmt::Formatter; -use std::ops::{Index, IndexMut}; -use std::pin::Pin; - -pub use td_rs_base::chop::*; -pub use td_rs_base::*; - -pub mod cxx; -pub mod prelude; - -#[derive(Debug, Default)] -pub struct ChopOutputInfo { - pub num_channels: u32, - pub num_samples: u32, - pub sample_rate: f32, - pub start_index: usize, -} - -#[derive(Debug, Default)] -pub struct ChopGeneralInfo { - pub cook_every_frame: bool, - pub cook_every_frame_if_asked: bool, - pub timeslice: bool, - pub input_match_index: i32, -} - -/// A wrapper around a `ChopOutput` that provides a safe interface to the -/// underlying C++ object and writing to the output buffer. -pub struct ChopOutput<'cook> { - output: Pin<&'cook mut cxx::CHOP_Output>, -} - -impl std::fmt::Debug for ChopOutput<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("ChopOutput") - .field("num_channels", &self.num_channels()) - .field("num_samples", &self.num_samples()) - .field("sample_rate", &self.sample_rate()) - .field("start_index", &self.start_index()) - .finish() - } -} - -impl<'cook> ChopOutput<'cook> { - /// Create a new `ChopOutput` from a pinning reference to a - /// `ChopOutput`. - pub fn new(output: Pin<&'cook mut cxx::CHOP_Output>) -> ChopOutput<'cook> { - Self { output } - } - - /// Get the number of channels in the output buffer. - pub fn num_channels(&self) -> usize { - self.output.numChannels as usize - } - - /// Get the number of samples in the output buffer. - pub fn num_samples(&self) -> usize { - self.output.numSamples as usize - } - - /// Get the sample rate of the output buffer. - pub fn sample_rate(&self) -> u32 { - self.output.sampleRate as u32 - } - - /// Get the start index of the output buffer. - pub fn start_index(&self) -> usize { - self.output.startIndex as usize - } - - pub fn channel(&self, index: usize) -> &[f32] { - if index >= self.num_channels() { - panic!("Channel index out of bounds"); - } - - unsafe { - let channel_ptr = *self.output.channels.add(index); - std::slice::from_raw_parts(channel_ptr, self.num_samples()) - } - } - - pub fn channel_mut(&mut self, index: usize) -> &mut [f32] { - if index >= self.num_channels() { - panic!("Channel index out of bounds"); - } - - unsafe { - let channel_ptr = *self.output.channels.add(index); - std::slice::from_raw_parts_mut(channel_ptr, self.num_samples()) - } - } -} - -impl Index for ChopOutput<'_> { - type Output = [f32]; - - fn index(&self, index: usize) -> &Self::Output { - self.channel(index) - } -} - -impl IndexMut for ChopOutput<'_> { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - self.channel_mut(index) - } -} - -/// Trait for defining a custom operator. -pub trait Chop: Op { - fn channel_name(&self, _index: usize, _input: &OperatorInputs) -> String { - String::from("") - } - - fn execute(&mut self, output: &mut ChopOutput, input: &OperatorInputs); - - fn general_info(&self, input: &OperatorInputs) -> ChopGeneralInfo; - - fn output_info(&self, _input: &OperatorInputs) -> Option { - None - } - - fn build_dynamic_menu( - &self, - inputs: &OperatorInputs, - menu_info: &mut DynamicMenuInfo, - ) { - } -} - -#[macro_export] -macro_rules! chop_plugin { - ($plugin_ty:ty) => { - use td_rs_chop::cxx::c_void; - use td_rs_chop::cxx::OP_CustomOPInfo; - use td_rs_chop::NodeInfo; - - #[no_mangle] - pub extern "C" fn chop_get_plugin_info_impl( - mut op_info: std::pin::Pin<&mut OP_CustomOPInfo>, - ) { - unsafe { - td_rs_chop::op_info::<$plugin_ty>(op_info); - } - } - - #[no_mangle] - pub extern "C" fn chop_new_impl(info: NodeInfo) -> Box { - op_init(); - Box::new(<$plugin_ty>::new(info)) - } - }; -} +#![feature(min_specialization)] + +use std::fmt::Formatter; +use std::ops::{Index, IndexMut}; +use std::pin::Pin; + +pub use td_rs_base::chop::*; +pub use td_rs_base::*; + +pub mod cxx; +pub mod prelude; + +#[derive(Debug, Default)] +pub struct ChopOutputInfo { + pub num_channels: u32, + pub num_samples: u32, + pub sample_rate: f32, + pub start_index: usize, +} + +#[derive(Debug, Default)] +pub struct ChopGeneralInfo { + pub cook_every_frame: bool, + pub cook_every_frame_if_asked: bool, + pub timeslice: bool, + pub input_match_index: i32, +} + +/// A wrapper around a `ChopOutput` that provides a safe interface to the +/// underlying C++ object and writing to the output buffer. +pub struct ChopOutput<'cook> { + output: Pin<&'cook mut cxx::CHOP_Output>, +} + +impl std::fmt::Debug for ChopOutput<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ChopOutput") + .field("num_channels", &self.num_channels()) + .field("num_samples", &self.num_samples()) + .field("sample_rate", &self.sample_rate()) + .field("start_index", &self.start_index()) + .finish() + } +} + +impl<'cook> ChopOutput<'cook> { + /// Create a new `ChopOutput` from a pinning reference to a + /// `ChopOutput`. + pub fn new(output: Pin<&'cook mut cxx::CHOP_Output>) -> ChopOutput<'cook> { + Self { output } + } + + /// Get the number of channels in the output buffer. + pub fn num_channels(&self) -> usize { + self.output.numChannels as usize + } + + /// Get the number of samples in the output buffer. + pub fn num_samples(&self) -> usize { + self.output.numSamples as usize + } + + /// Get the sample rate of the output buffer. + pub fn sample_rate(&self) -> u32 { + self.output.sampleRate as u32 + } + + /// Get the start index of the output buffer. + pub fn start_index(&self) -> usize { + self.output.startIndex as usize + } + + pub fn channel(&self, index: usize) -> &[f32] { + if index >= self.num_channels() { + panic!("Channel index out of bounds"); + } + + unsafe { + let channel_ptr = *self.output.channels.add(index); + std::slice::from_raw_parts(channel_ptr, self.num_samples()) + } + } + + pub fn channel_mut(&mut self, index: usize) -> &mut [f32] { + if index >= self.num_channels() { + panic!("Channel index out of bounds"); + } + + unsafe { + let channel_ptr = *self.output.channels.add(index); + std::slice::from_raw_parts_mut(channel_ptr, self.num_samples()) + } + } +} + +impl Index for ChopOutput<'_> { + type Output = [f32]; + + fn index(&self, index: usize) -> &Self::Output { + self.channel(index) + } +} + +impl IndexMut for ChopOutput<'_> { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.channel_mut(index) + } +} + +/// Trait for defining a custom operator. +pub trait Chop: Op { + fn channel_name(&self, _index: usize, _input: &OperatorInputs) -> String { + String::from("") + } + + fn execute(&mut self, output: &mut ChopOutput, input: &OperatorInputs); + + fn general_info(&self, input: &OperatorInputs) -> ChopGeneralInfo; + + fn output_info(&self, _input: &OperatorInputs) -> Option { + None + } + + fn build_dynamic_menu( + &self, + inputs: &OperatorInputs, + menu_info: &mut DynamicMenuInfo, + ) { + } +} + +#[macro_export] +macro_rules! chop_plugin { + ($plugin_ty:ty) => { + use td_rs_chop::cxx::c_void; + use td_rs_chop::cxx::OP_CustomOPInfo; + use td_rs_chop::NodeInfo; + + #[no_mangle] + pub extern "C" fn chop_get_plugin_info_impl( + mut op_info: std::pin::Pin<&mut OP_CustomOPInfo>, + ) { + unsafe { + td_rs_chop::op_info::<$plugin_ty>(op_info); + } + } + + #[no_mangle] + pub extern "C" fn chop_new_impl(info: NodeInfo) -> Box { + op_init(); + Box::new(<$plugin_ty>::new(info)) + } + }; +} diff --git a/td-rs-chop/src/prelude.rs b/td-rs-chop/src/prelude.rs index dd44555..c36e0d9 100644 --- a/td-rs-chop/src/prelude.rs +++ b/td-rs-chop/src/prelude.rs @@ -1,9 +1,9 @@ -pub use crate::cxx::AsPlugin; -pub use crate::*; - -#[cfg(feature = "python")] -pub use pyo3::impl_::pyclass::PyClassImpl; -#[cfg(feature = "python")] -pub use pyo3::prelude::*; -#[cfg(feature = "python")] -pub use std::pin::Pin; +pub use crate::cxx::AsPlugin; +pub use crate::*; + +#[cfg(feature = "python")] +pub use pyo3::impl_::pyclass::PyClassImpl; +#[cfg(feature = "python")] +pub use pyo3::prelude::*; +#[cfg(feature = "python")] +pub use std::pin::Pin; diff --git a/td-rs-dat/Cargo.toml b/td-rs-dat/Cargo.toml index dd3568b..441aac9 100644 --- a/td-rs-dat/Cargo.toml +++ b/td-rs-dat/Cargo.toml @@ -1,29 +1,29 @@ -[package] -name = "td-rs-dat" -version = "0.1.0" -edition = "2021" - -[lib] -name = "td_rs_dat" -crate-type = ["lib", "staticlib"] - -[dependencies] -autocxx = { git = "https://github.com/tychedelia/autocxx.git" } -cxx = "1.0.78" -td-rs-base = { path = "../td-rs-base" } -ref-cast = "1.0" -sparsevec = "0.2.0" -tracing-base = { package = "tracing", version = "0.1", optional = true } -tracing-subscriber = { version = "0.2", optional = true } -pyo3 = { git = "https://github.com/tychedelia/pyo3", branch = "td-rs", features = ["abi3-py311"], optional = true } - -[build-dependencies] -td-rs-autocxx-build = { path = "../td-rs-autocxx-build" } -autocxx-build = { git = "https://github.com/tychedelia/autocxx.git" } -miette = { version="5", features = [ "fancy" ] } - -[features] -default = [] -python = ["td-rs-base/python", "dep:pyo3"] -tracing = ["td-rs-base/tracing", "tracing-base", "tracing-subscriber"] -tokio = ["td-rs-base/tokio"] +[package] +name = "td-rs-dat" +version = "0.1.0" +edition = "2021" + +[lib] +name = "td_rs_dat" +crate-type = ["lib", "staticlib"] + +[dependencies] +autocxx = { git = "https://github.com/tychedelia/autocxx.git" } +cxx = "1.0.78" +td-rs-base = { path = "../td-rs-base" } +ref-cast = "1.0" +sparsevec = "0.2.0" +tracing-base = { package = "tracing", version = "0.1", optional = true } +tracing-subscriber = { version = "0.2", optional = true } +pyo3 = { git = "https://github.com/tychedelia/pyo3", branch = "td-rs", features = ["abi3-py311"], optional = true } + +[build-dependencies] +td-rs-autocxx-build = { path = "../td-rs-autocxx-build" } +autocxx-build = { git = "https://github.com/tychedelia/autocxx.git" } +miette = { version="5", features = [ "fancy" ] } + +[features] +default = [] +python = ["td-rs-base/python", "dep:pyo3"] +tracing = ["td-rs-base/tracing", "tracing-base", "tracing-subscriber"] +tokio = ["td-rs-base/tokio"] diff --git a/td-rs-dat/build.rs b/td-rs-dat/build.rs index 037a2e0..228cb0a 100644 --- a/td-rs-dat/build.rs +++ b/td-rs-dat/build.rs @@ -1,3 +1,3 @@ -fn main() -> miette::Result<()> { - td_rs_autocxx_build::build("td-rs-dat", true) -} +fn main() -> miette::Result<()> { + td_rs_autocxx_build::build("td-rs-dat", true) +} diff --git a/td-rs-dat/src/RustDatPlugin.cpp b/td-rs-dat/src/RustDatPlugin.cpp index 9455644..efd8ca9 100644 --- a/td-rs-dat/src/RustDatPlugin.cpp +++ b/td-rs-dat/src/RustDatPlugin.cpp @@ -1,34 +1,34 @@ -#include "CPlusPlus_Common.h" -#include "RustDatPlugin.h" -#include -#ifdef PYTHON_ENABLED -#include -#endif - - -extern "C" { - -RustDatPlugin *dat_new(const OP_NodeInfo &info); -void dat_get_plugin_info_impl(OP_CustomOPInfo &opInfo); - -DLLEXPORT -void FillDATPluginInfo(DAT_PluginInfo *info) { - info->apiVersion = DATCPlusPlusAPIVersion; - auto opInfo = &info->customOPInfo; - dat_get_plugin_info_impl(*opInfo); -#ifdef PYTHON_ENABLED - opInfo->pythonVersion->setString(PY_VERSION); -#endif -} - -DLLEXPORT -DAT_CPlusPlusBase *CreateDATInstance(const OP_NodeInfo *info) { - return dat_new(*info); -} - -DLLEXPORT -void DestroyDATInstance(DAT_CPlusPlusBase *instance) { - delete (RustDatPlugin *) instance; -} - +#include "CPlusPlus_Common.h" +#include "RustDatPlugin.h" +#include +#ifdef PYTHON_ENABLED +#include +#endif + + +extern "C" { + +RustDatPlugin *dat_new(const OP_NodeInfo &info); +void dat_get_plugin_info_impl(OP_CustomOPInfo &opInfo); + +DLLEXPORT +void FillDATPluginInfo(DAT_PluginInfo *info) { + info->apiVersion = DATCPlusPlusAPIVersion; + auto opInfo = &info->customOPInfo; + dat_get_plugin_info_impl(*opInfo); +#ifdef PYTHON_ENABLED + opInfo->pythonVersion->setString(PY_VERSION); +#endif +} + +DLLEXPORT +DAT_CPlusPlusBase *CreateDATInstance(const OP_NodeInfo *info) { + return dat_new(*info); +} + +DLLEXPORT +void DestroyDATInstance(DAT_CPlusPlusBase *instance) { + delete (RustDatPlugin *) instance; +} + } \ No newline at end of file diff --git a/td-rs-dat/src/RustDatPlugin.h b/td-rs-dat/src/RustDatPlugin.h index 2b46931..00771b2 100644 --- a/td-rs-dat/src/RustDatPlugin.h +++ b/td-rs-dat/src/RustDatPlugin.h @@ -1,140 +1,140 @@ -#include "CPlusPlus_Common.h" -#include "DAT_CPlusPlusBase.h" -#include -#include - -#ifndef TD_RS_RUSTDAT_H -#define TD_RS_RUSTDAT_H - -using namespace TD; - -class DatPlugin : public DAT_CPlusPlusBase { -public: - virtual ~DatPlugin(){}; - - void getGeneralInfo(DAT_GeneralInfo *info, const OP_Inputs *inputs, - void *reserved1) { - this->getGeneralInfo(*info, *inputs); - } - - virtual void getGeneralInfo(DAT_GeneralInfo &info, const OP_Inputs &inputs) {} - - void execute(DAT_Output *outputs, const OP_Inputs *inputs, void *reserved1) { - this->execute(*outputs, *inputs); - } - - virtual void execute(DAT_Output &outputs, const OP_Inputs &inputs) {} - - int32_t getNumInfoCHOPChans(void *reserved1) { - return this->getNumInfoCHOPChans(); - } - - virtual int32_t getNumInfoCHOPChans() { return 0; } - - void getInfoCHOPChan(int32_t index, OP_InfoCHOPChan *chan, - void *reserved1) override { - OP_String *name = chan->name; - float v = 0.f; - float *value = &v; - this->getInfoCHOPChan(index, *name, *value); - chan->name = name; - chan->value = *value; - } - - virtual void getInfoCHOPChan(int32_t index, OP_String &name, float &value) {} - - bool getInfoDATSize(OP_InfoDATSize *infoSize, void *reserved1) { - return this->getInfoDATSize(*infoSize); - } - - virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) { return false; } - - void getInfoDATEntries(int32_t index, int32_t nEntries, - OP_InfoDATEntries *entries, void *reserved1) override { - for (int i = 0; i < nEntries; i++) { - auto entry = entries->values[i]; - this->getInfoDATEntry(index, i, *entry); - } - } - - virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, - OP_String &entry) {} - - void getWarningString(OP_String *warning, void *reserved1) override { - this->getWarningString(*warning); - }; - - virtual void getWarningString(OP_String &warning) {} - - void getErrorString(OP_String *error, void *reserved1) override { - this->getErrorString(*error); - }; - - virtual void getErrorString(OP_String &error) {} - - void getInfoPopupString(OP_String *popup, void *reserved1) override { - this->getInfoPopupString(*popup); - }; - - virtual void getInfoPopupString(OP_String &popup) {} - - void setupParameters(OP_ParameterManager *manager, void *reserved1) override { - this->setupParameters(*manager); - }; - - virtual void setupParameters(OP_ParameterManager &manager) {} - - void pulsePressed(const char *name, void *reserved1) override { - this->pulsePressed(name); - }; - - virtual void pulsePressed(const char *name) {} - - virtual void buildDynamicMenu(const OP_Inputs *inputs, - OP_BuildDynamicMenuInfo *info, - void *reserved1) { - this->buildDynamicMenu(*inputs, *info); - } - - virtual void buildDynamicMenu(const OP_Inputs &inputs, - OP_BuildDynamicMenuInfo &info) {} -}; - -class RustDatPlugin : public DatPlugin { -public: - virtual ~RustDatPlugin(){}; - - virtual void *inner() const = 0; - - virtual void *innerMut() = 0; - - virtual void getGeneralInfo(DAT_GeneralInfo &info, - const OP_Inputs &inputs) = 0; - - virtual void execute(DAT_Output &outputs, const OP_Inputs &inputs) = 0; - - virtual int32_t getNumInfoCHOPChans() = 0; - - virtual void getInfoCHOPChan(int32_t index, OP_String &name, - float &value) = 0; - - virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) = 0; - - virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, - OP_String &entry) = 0; - - virtual void getWarningString(OP_String &warning) = 0; - - virtual void getErrorString(OP_String &error) = 0; - - virtual void getInfoPopupString(OP_String &popup) = 0; - - virtual void setupParameters(OP_ParameterManager &manager) = 0; - - virtual void pulsePressed(const char *name) = 0; - - virtual void buildDynamicMenu(const OP_Inputs &inputs, - OP_BuildDynamicMenuInfo &info) = 0; -}; - -#endif // TD_RS_RUSTDAT_H +#include "CPlusPlus_Common.h" +#include "DAT_CPlusPlusBase.h" +#include +#include + +#ifndef TD_RS_RUSTDAT_H +#define TD_RS_RUSTDAT_H + +using namespace TD; + +class DatPlugin : public DAT_CPlusPlusBase { +public: + virtual ~DatPlugin(){}; + + void getGeneralInfo(DAT_GeneralInfo *info, const OP_Inputs *inputs, + void *reserved1) { + this->getGeneralInfo(*info, *inputs); + } + + virtual void getGeneralInfo(DAT_GeneralInfo &info, const OP_Inputs &inputs) {} + + void execute(DAT_Output *outputs, const OP_Inputs *inputs, void *reserved1) { + this->execute(*outputs, *inputs); + } + + virtual void execute(DAT_Output &outputs, const OP_Inputs &inputs) {} + + int32_t getNumInfoCHOPChans(void *reserved1) { + return this->getNumInfoCHOPChans(); + } + + virtual int32_t getNumInfoCHOPChans() { return 0; } + + void getInfoCHOPChan(int32_t index, OP_InfoCHOPChan *chan, + void *reserved1) override { + OP_String *name = chan->name; + float v = 0.f; + float *value = &v; + this->getInfoCHOPChan(index, *name, *value); + chan->name = name; + chan->value = *value; + } + + virtual void getInfoCHOPChan(int32_t index, OP_String &name, float &value) {} + + bool getInfoDATSize(OP_InfoDATSize *infoSize, void *reserved1) { + return this->getInfoDATSize(*infoSize); + } + + virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) { return false; } + + void getInfoDATEntries(int32_t index, int32_t nEntries, + OP_InfoDATEntries *entries, void *reserved1) override { + for (int i = 0; i < nEntries; i++) { + auto entry = entries->values[i]; + this->getInfoDATEntry(index, i, *entry); + } + } + + virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, + OP_String &entry) {} + + void getWarningString(OP_String *warning, void *reserved1) override { + this->getWarningString(*warning); + }; + + virtual void getWarningString(OP_String &warning) {} + + void getErrorString(OP_String *error, void *reserved1) override { + this->getErrorString(*error); + }; + + virtual void getErrorString(OP_String &error) {} + + void getInfoPopupString(OP_String *popup, void *reserved1) override { + this->getInfoPopupString(*popup); + }; + + virtual void getInfoPopupString(OP_String &popup) {} + + void setupParameters(OP_ParameterManager *manager, void *reserved1) override { + this->setupParameters(*manager); + }; + + virtual void setupParameters(OP_ParameterManager &manager) {} + + void pulsePressed(const char *name, void *reserved1) override { + this->pulsePressed(name); + }; + + virtual void pulsePressed(const char *name) {} + + virtual void buildDynamicMenu(const OP_Inputs *inputs, + OP_BuildDynamicMenuInfo *info, + void *reserved1) { + this->buildDynamicMenu(*inputs, *info); + } + + virtual void buildDynamicMenu(const OP_Inputs &inputs, + OP_BuildDynamicMenuInfo &info) {} +}; + +class RustDatPlugin : public DatPlugin { +public: + virtual ~RustDatPlugin(){}; + + virtual void *inner() const = 0; + + virtual void *innerMut() = 0; + + virtual void getGeneralInfo(DAT_GeneralInfo &info, + const OP_Inputs &inputs) = 0; + + virtual void execute(DAT_Output &outputs, const OP_Inputs &inputs) = 0; + + virtual int32_t getNumInfoCHOPChans() = 0; + + virtual void getInfoCHOPChan(int32_t index, OP_String &name, + float &value) = 0; + + virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) = 0; + + virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, + OP_String &entry) = 0; + + virtual void getWarningString(OP_String &warning) = 0; + + virtual void getErrorString(OP_String &error) = 0; + + virtual void getInfoPopupString(OP_String &popup) = 0; + + virtual void setupParameters(OP_ParameterManager &manager) = 0; + + virtual void pulsePressed(const char *name) = 0; + + virtual void buildDynamicMenu(const OP_Inputs &inputs, + OP_BuildDynamicMenuInfo &info) = 0; +}; + +#endif // TD_RS_RUSTDAT_H diff --git a/td-rs-dat/src/cxx.rs b/td-rs-dat/src/cxx.rs index d9b9ef8..d30b21b 100644 --- a/td-rs-dat/src/cxx.rs +++ b/td-rs-dat/src/cxx.rs @@ -1,213 +1,213 @@ -#![allow(non_snake_case)] -#![allow(ambiguous_glob_reexports)] - -use crate::{Dat, DatOutput}; -use autocxx::prelude::*; -use autocxx::subclass::*; - -use std::ffi::CString; - -use std::pin::Pin; -use td_rs_base::{param::ParameterManager, DynamicMenuInfo, NodeInfo, OperatorInputs}; - -include_cpp! { - #include "DAT_CPlusPlusBase.h" - #include "RustDatPlugin.h" - safety!(unsafe) - extern_cpp_type!("TD::OP_ParameterManager", td_rs_base::cxx::OP_ParameterManager) - extern_cpp_type!("TD::OP_String", td_rs_base::cxx::OP_String) - extern_cpp_type!("TD::OP_InfoDATSize", td_rs_base::cxx::OP_InfoDATSize) - extern_cpp_type!("TD::OP_InfoCHOPChan", td_rs_base::cxx::OP_InfoCHOPChan) - extern_cpp_type!("TD::OP_Inputs", td_rs_base::cxx::OP_Inputs) - extern_cpp_type!("TD::OP_CustomOPInfo", td_rs_base::cxx::OP_CustomOPInfo) - extern_cpp_type!("TD::OP_BuildDynamicMenuInfo", td_rs_base::cxx::OP_BuildDynamicMenuInfo) - pod!("TD::OP_CustomOPInfo") - generate!("TD::DAT_Output") - generate_pod!("TD::DAT_GeneralInfo") -} - -pub use autocxx::c_void; -pub use ffi::TD::*; -pub use ffi::*; -pub use td_rs_base::cxx::*; - -extern "C" { - // SAFETY: `dat_new_impl` is only ever called from Rust compiled - // at the same time as the plugin, so the types are guaranteed to - // match - #[allow(improper_ctypes)] - fn dat_new_impl(info: NodeInfo) -> Box; -} - -// SAFETY: This can only be used with pointers returned from getNodeInstance() and -// should not be used in plugin code. -pub unsafe fn plugin_cast(plugin: *mut c_void) -> &'static mut RustDatPluginImplCpp { - &mut *(plugin as *mut RustDatPluginImplCpp) -} - -impl AsPlugin for RustDatPluginImplCpp { - type Plugin = RustDatPlugin; - - fn as_plugin(&self) -> &Self::Plugin { - self.As_RustDatPlugin() - } - - fn as_plugin_mut(&mut self) -> Pin<&mut Self::Plugin> { - // Safety: self can't be moved during the lifetime of 'cook. - unsafe { Pin::new_unchecked(self).As_RustDatPlugin_mut() } - } -} - -#[subclass(superclass("RustDatPlugin"))] -pub struct RustDatPluginImpl { - inner: Box, -} - -#[no_mangle] -extern "C" fn dat_new(info: &'static OP_NodeInfo) -> *mut RustDatPluginImplCpp { - unsafe { - let info = NodeInfo::new(info); - RustDatPluginImpl::new_cpp_owned(RustDatPluginImpl { - inner: dat_new_impl(info), - cpp_peer: CppSubclassCppPeerHolder::Empty, - }) - .into_raw() - } -} - -impl RustDatPlugin_methods for RustDatPluginImpl { - fn inner(&self) -> *mut c_void { - self.inner.as_ref() as *const dyn Dat as *mut c_void - } - - fn innerMut(&mut self) -> *mut c_void { - self.inner.as_mut() as *mut dyn Dat as *mut c_void - } - - fn getGeneralInfo(&mut self, mut info: Pin<&mut DAT_GeneralInfo>, inputs: &OP_Inputs) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getGeneralInfo").entered() }; - let input = OperatorInputs::new(inputs); - if let Some(params) = self.inner.params_mut() { - params.update(&input.params()); - } - let gen_info = self.inner.general_info(&input); - info.cookEveryFrame = gen_info.cook_every_frame; - info.cookEveryFrameIfAsked = gen_info.cook_every_frame_if_asked; - } - - fn execute(&mut self, outputs: Pin<&mut DAT_Output>, inputs: &OP_Inputs) { - #[cfg(feature = "tracing")] - let span = { - tracing_base::trace_span!("execute").entered(); - }; - let input = OperatorInputs::new(inputs); - let output = DatOutput::new(outputs); - if let Some(params) = self.inner.params_mut() { - params.update(&input.params()); - } - self.inner.execute(output, &input); - } - - fn getNumInfoCHOPChans(&mut self) -> i32 { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getNumInfoCHOPChans").entered() }; - if let Some(info_chop) = self.inner.info_chop() { - info_chop.size() as i32 - } else { - 0 - } - } - - fn getInfoCHOPChan(&mut self, index: i32, name: Pin<&mut OP_String>, mut value: Pin<&mut f32>) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getInfoCHOPChan").entered() }; - if let Some(info_chop) = self.inner.info_chop() { - let (info_name, info_value) = info_chop.channel(index as usize); - unsafe { - let new_string = CString::new(info_name.as_str()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - name.setString(new_string_ptr); - } - value.set(info_value); - } - } - - fn getInfoDATSize(&mut self, mut info: Pin<&mut OP_InfoDATSize>) -> bool { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getInfoDATSize").entered() }; - if let Some(info_dat) = self.inner.info_dat() { - let (rows, cols) = info_dat.size(); - info.rows = rows as i32; - info.cols = cols as i32; - true - } else { - false - } - } - - fn getInfoDATEntry(&mut self, index: i32, entryIndex: i32, entry: Pin<&mut OP_String>) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getInfoDATEntry").entered() }; - if let Some(info_dat) = self.inner.info_dat() { - let entry_str = info_dat.entry(index as usize, entryIndex as usize); - if entry_str.is_empty() { - return; - } - unsafe { - let new_string = CString::new(entry_str.as_str()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - entry.setString(new_string_ptr); - } - } - } - - fn getWarningString(&mut self, warning: Pin<&mut OP_String>) { - unsafe { - let new_string = CString::new(self.inner.warning()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - warning.setString(new_string_ptr); - } - } - - fn getErrorString(&mut self, error: Pin<&mut OP_String>) { - unsafe { - let new_string = CString::new(self.inner.error()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - error.setString(new_string_ptr); - } - } - - fn getInfoPopupString(&mut self, info: Pin<&mut OP_String>) { - unsafe { - let new_string = CString::new(self.inner.info()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - info.setString(new_string_ptr); - } - } - - fn setupParameters(&mut self, manager: Pin<&mut OP_ParameterManager>) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("setupParameters").entered() }; - let params = self.inner.params_mut(); - if let Some(params) = params { - let mut manager = ParameterManager::new(manager); - params.register(&mut manager); - } - } - - unsafe fn pulsePressed(&mut self, name: *const std::ffi::c_char) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("pulsePressed").entered() }; - self.inner - .pulse_pressed(std::ffi::CStr::from_ptr(name).to_str().unwrap()); - } - - fn buildDynamicMenu(&mut self, inputs: &OP_Inputs, info: Pin<&mut OP_BuildDynamicMenuInfo>) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("buildDynamicMenu").entered() }; - let input = OperatorInputs::new(inputs); - let mut info = DynamicMenuInfo::new(info); - self.inner.build_dynamic_menu(&input, &mut info); - } -} +#![allow(non_snake_case)] +#![allow(ambiguous_glob_reexports)] + +use crate::{Dat, DatOutput}; +use autocxx::prelude::*; +use autocxx::subclass::*; + +use std::ffi::CString; + +use std::pin::Pin; +use td_rs_base::{param::ParameterManager, DynamicMenuInfo, NodeInfo, OperatorInputs}; + +include_cpp! { + #include "DAT_CPlusPlusBase.h" + #include "RustDatPlugin.h" + safety!(unsafe) + extern_cpp_type!("TD::OP_ParameterManager", td_rs_base::cxx::OP_ParameterManager) + extern_cpp_type!("TD::OP_String", td_rs_base::cxx::OP_String) + extern_cpp_type!("TD::OP_InfoDATSize", td_rs_base::cxx::OP_InfoDATSize) + extern_cpp_type!("TD::OP_InfoCHOPChan", td_rs_base::cxx::OP_InfoCHOPChan) + extern_cpp_type!("TD::OP_Inputs", td_rs_base::cxx::OP_Inputs) + extern_cpp_type!("TD::OP_CustomOPInfo", td_rs_base::cxx::OP_CustomOPInfo) + extern_cpp_type!("TD::OP_BuildDynamicMenuInfo", td_rs_base::cxx::OP_BuildDynamicMenuInfo) + pod!("TD::OP_CustomOPInfo") + generate!("TD::DAT_Output") + generate_pod!("TD::DAT_GeneralInfo") +} + +pub use autocxx::c_void; +pub use ffi::TD::*; +pub use ffi::*; +pub use td_rs_base::cxx::*; + +extern "C" { + // SAFETY: `dat_new_impl` is only ever called from Rust compiled + // at the same time as the plugin, so the types are guaranteed to + // match + #[allow(improper_ctypes)] + fn dat_new_impl(info: NodeInfo) -> Box; +} + +// SAFETY: This can only be used with pointers returned from getNodeInstance() and +// should not be used in plugin code. +pub unsafe fn plugin_cast(plugin: *mut c_void) -> &'static mut RustDatPluginImplCpp { + &mut *(plugin as *mut RustDatPluginImplCpp) +} + +impl AsPlugin for RustDatPluginImplCpp { + type Plugin = RustDatPlugin; + + fn as_plugin(&self) -> &Self::Plugin { + self.As_RustDatPlugin() + } + + fn as_plugin_mut(&mut self) -> Pin<&mut Self::Plugin> { + // Safety: self can't be moved during the lifetime of 'cook. + unsafe { Pin::new_unchecked(self).As_RustDatPlugin_mut() } + } +} + +#[subclass(superclass("RustDatPlugin"))] +pub struct RustDatPluginImpl { + inner: Box, +} + +#[no_mangle] +extern "C" fn dat_new(info: &'static OP_NodeInfo) -> *mut RustDatPluginImplCpp { + unsafe { + let info = NodeInfo::new(info); + RustDatPluginImpl::new_cpp_owned(RustDatPluginImpl { + inner: dat_new_impl(info), + cpp_peer: CppSubclassCppPeerHolder::Empty, + }) + .into_raw() + } +} + +impl RustDatPlugin_methods for RustDatPluginImpl { + fn inner(&self) -> *mut c_void { + self.inner.as_ref() as *const dyn Dat as *mut c_void + } + + fn innerMut(&mut self) -> *mut c_void { + self.inner.as_mut() as *mut dyn Dat as *mut c_void + } + + fn getGeneralInfo(&mut self, mut info: Pin<&mut DAT_GeneralInfo>, inputs: &OP_Inputs) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getGeneralInfo").entered() }; + let input = OperatorInputs::new(inputs); + if let Some(params) = self.inner.params_mut() { + params.update(&input.params()); + } + let gen_info = self.inner.general_info(&input); + info.cookEveryFrame = gen_info.cook_every_frame; + info.cookEveryFrameIfAsked = gen_info.cook_every_frame_if_asked; + } + + fn execute(&mut self, outputs: Pin<&mut DAT_Output>, inputs: &OP_Inputs) { + #[cfg(feature = "tracing")] + let span = { + tracing_base::trace_span!("execute").entered(); + }; + let input = OperatorInputs::new(inputs); + let output = DatOutput::new(outputs); + if let Some(params) = self.inner.params_mut() { + params.update(&input.params()); + } + self.inner.execute(output, &input); + } + + fn getNumInfoCHOPChans(&mut self) -> i32 { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getNumInfoCHOPChans").entered() }; + if let Some(info_chop) = self.inner.info_chop() { + info_chop.size() as i32 + } else { + 0 + } + } + + fn getInfoCHOPChan(&mut self, index: i32, name: Pin<&mut OP_String>, mut value: Pin<&mut f32>) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getInfoCHOPChan").entered() }; + if let Some(info_chop) = self.inner.info_chop() { + let (info_name, info_value) = info_chop.channel(index as usize); + unsafe { + let new_string = CString::new(info_name.as_str()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + name.setString(new_string_ptr); + } + value.set(info_value); + } + } + + fn getInfoDATSize(&mut self, mut info: Pin<&mut OP_InfoDATSize>) -> bool { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getInfoDATSize").entered() }; + if let Some(info_dat) = self.inner.info_dat() { + let (rows, cols) = info_dat.size(); + info.rows = rows as i32; + info.cols = cols as i32; + true + } else { + false + } + } + + fn getInfoDATEntry(&mut self, index: i32, entryIndex: i32, entry: Pin<&mut OP_String>) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getInfoDATEntry").entered() }; + if let Some(info_dat) = self.inner.info_dat() { + let entry_str = info_dat.entry(index as usize, entryIndex as usize); + if entry_str.is_empty() { + return; + } + unsafe { + let new_string = CString::new(entry_str.as_str()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + entry.setString(new_string_ptr); + } + } + } + + fn getWarningString(&mut self, warning: Pin<&mut OP_String>) { + unsafe { + let new_string = CString::new(self.inner.warning()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + warning.setString(new_string_ptr); + } + } + + fn getErrorString(&mut self, error: Pin<&mut OP_String>) { + unsafe { + let new_string = CString::new(self.inner.error()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + error.setString(new_string_ptr); + } + } + + fn getInfoPopupString(&mut self, info: Pin<&mut OP_String>) { + unsafe { + let new_string = CString::new(self.inner.info()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + info.setString(new_string_ptr); + } + } + + fn setupParameters(&mut self, manager: Pin<&mut OP_ParameterManager>) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("setupParameters").entered() }; + let params = self.inner.params_mut(); + if let Some(params) = params { + let mut manager = ParameterManager::new(manager); + params.register(&mut manager); + } + } + + unsafe fn pulsePressed(&mut self, name: *const std::ffi::c_char) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("pulsePressed").entered() }; + self.inner + .pulse_pressed(std::ffi::CStr::from_ptr(name).to_str().unwrap()); + } + + fn buildDynamicMenu(&mut self, inputs: &OP_Inputs, info: Pin<&mut OP_BuildDynamicMenuInfo>) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("buildDynamicMenu").entered() }; + let input = OperatorInputs::new(inputs); + let mut info = DynamicMenuInfo::new(info); + self.inner.build_dynamic_menu(&input, &mut info); + } +} diff --git a/td-rs-dat/src/lib.rs b/td-rs-dat/src/lib.rs index 3ecedfd..89e2c44 100644 --- a/td-rs-dat/src/lib.rs +++ b/td-rs-dat/src/lib.rs @@ -1,272 +1,272 @@ -use std::ffi::CString; -use std::ops::{Index, IndexMut}; -use std::pin::Pin; - -use td_rs_base::chop::ChopInput; -pub use td_rs_base::dat::*; -pub use td_rs_base::param::OperatorParams; -pub use td_rs_base::*; - -pub mod cxx; -pub mod prelude; - -#[derive(Debug, Default)] -pub struct DatGeneralInfo { - pub cook_every_frame: bool, - pub cook_every_frame_if_asked: bool, -} - -pub struct DatOutput<'cook> { - output: Pin<&'cook mut cxx::DAT_Output>, -} - -impl<'cook> DatOutput<'cook> { - pub fn new(output: Pin<&'cook mut cxx::DAT_Output>) -> Self { - Self { output } - } - - pub fn table + Default>(mut self) -> DatTableOutput<'cook, T> { - self.output - .as_mut() - .setOutputDataType(cxx::DAT_OutDataType::Table); - let table = Vec::new(); - let mut table_out = DatTableOutput { - output: self.output, - table, - }; - table_out - .table - .resize(table_out.table_size().iter().product(), T::default()); - table_out - } - - pub fn text(mut self) -> DatTextOutput<'cook> { - self.output - .as_mut() - .setOutputDataType(cxx::DAT_OutDataType::Text); - DatTextOutput { - output: self.output, - } - } -} - -pub struct DatTableOutput<'cook, T> { - output: Pin<&'cook mut cxx::DAT_Output>, - table: Vec, -} - -impl<'cook, T> DatTableOutput<'cook, T> -where - T: CellType<'cook> + Default, -{ - pub fn get(&self, row: usize, col: usize) -> &T { - T::get(self, row, col) - } - - pub fn set(&mut self, row: usize, col: usize, value: T) { - T::set(self, row, col, value) - } - - pub fn table_size(&self) -> [usize; 2] { - let mut rows = 0; - let mut cols = 0; - unsafe { - self.output.as_ref().getTableSize(&mut rows, &mut cols); - } - [rows as usize, cols as usize] - } - - pub fn set_table_size(&mut self, rows: usize, cols: usize) { - self.output.as_mut().setTableSize(rows as i32, cols as i32); - self.table.resize(rows * cols, T::default()); - } -} - -/// A type which can be used as a cell in a DAT table. Should not be implemented manually or used -/// directly. -pub trait CellType<'cook> -where - Self: Clone, -{ - /// Get a reference to the value of this cell from the table. - fn get<'a>(table: &'a DatTableOutput<'cook, Self>, row: usize, col: usize) -> &'a Self; - /// Set the value of this cell in the table. - fn set(table: &mut DatTableOutput, row: usize, col: usize, value: Self); -} - -impl<'cook> CellType<'cook> for f64 { - fn get<'a>(table: &'a DatTableOutput<'cook, Self>, row: usize, col: usize) -> &'a Self { - let mut out = f64::default(); - let [rows, _] = table.table_size(); - let offset = row * rows + col; - unsafe { - table - .output - .as_ref() - .getCellDouble(row as i32, col as i32, &mut out); - } - let ptr = table.table.as_ptr(); - - unsafe { - let y = ptr.add(offset) as *mut f64; - *y = out; - } - - &table.table[offset] - } - - fn set(table: &mut DatTableOutput, row: usize, col: usize, value: Self) { - let [rows, _] = table.table_size(); - let offset = row * rows + col; - table.table[offset] = value; - table - .output - .as_mut() - .setCellDouble(row as i32, col as i32, value); - } -} - -impl<'cook> CellType<'cook> for i32 { - fn get<'a>(table: &'a DatTableOutput<'cook, Self>, row: usize, col: usize) -> &'a Self { - let mut out = i32::default(); - let [rows, _] = table.table_size(); - let offset = row * rows + col; - unsafe { - table - .output - .as_ref() - .getCellInt(row as i32, col as i32, &mut out); - } - let ptr = table.table.as_ptr(); - - unsafe { - let y = ptr.add(offset) as *mut i32; - *y = out; - } - - &table.table[offset] - } - - fn set(table: &mut DatTableOutput, row: usize, col: usize, value: Self) { - let rows = table.table_size()[0]; - let offset = row * rows + col; - table.table[offset] = value; - table - .output - .as_mut() - .setCellInt(row as i32, col as i32, value); - } -} - -impl<'cook> CellType<'cook> for String { - fn get<'a>(table: &'a DatTableOutput<'cook, Self>, row: usize, col: usize) -> &'a Self { - let rows = table.table_size()[0]; - let offset = row * rows + col; - let out = unsafe { - let out = table.output.as_ref().getCellString(row as i32, col as i32); - std::ffi::CStr::from_ptr(out).to_str().unwrap() - }; - - let ptr = table.table.as_ptr(); - - unsafe { - let y = ptr.add(offset) as *mut &str; - *y = out; - } - - &table.table[offset] - } - - fn set(table: &mut DatTableOutput, row: usize, col: usize, value: Self) { - let rows = table.table_size()[0]; - let offset = row * rows + col; - table.table[offset] = value.clone(); - let cstr = std::ffi::CString::new(value).unwrap(); - unsafe { - table - .output - .as_mut() - .setCellString(row as i32, col as i32, cstr.as_ptr()); - } - } -} - -impl<'cook, T> Index<[usize; 2]> for DatTableOutput<'cook, T> -where - T: CellType<'cook> + Default, -{ - type Output = T; - - fn index(&self, index: [usize; 2]) -> &Self::Output { - let [row, col] = index; - self.get(row, col) - } -} - -impl<'cook, T> IndexMut<[usize; 2]> for DatTableOutput<'cook, T> -where - T: CellType<'cook> + Default, -{ - fn index_mut(&mut self, index: [usize; 2]) -> &mut Self::Output { - let [row, col] = index; - let [rows, _] = self.table_size(); - let out = T::default(); - self.table[row * rows + col] = out; - //self.set(row, col, out); - &mut self.table[row * rows + col] - } -} - -pub struct DatTextOutput<'cook> { - output: Pin<&'cook mut cxx::DAT_Output>, -} - -impl<'cook> DatTextOutput<'cook> { - pub fn set_text(&mut self, text: &str) { - unsafe { - let c_str = CString::new(text).unwrap(); - self.output.as_mut().setText(c_str.as_ptr()); - } - } -} - -pub trait Dat: Op { - fn general_info(&self, _input: &OperatorInputs) -> DatGeneralInfo { - DatGeneralInfo::default() - } - - fn execute(&mut self, _output: DatOutput, _input: &OperatorInputs) { - // Do nothing by default. - } - - fn build_dynamic_menu( - &mut self, - inputs: &OperatorInputs, - menu_info: &mut DynamicMenuInfo, - ) { - } -} - -#[macro_export] -macro_rules! dat_plugin { - ($plugin_ty:ty) => { - use td_rs_dat::cxx::c_void; - use td_rs_dat::cxx::OP_CustomOPInfo; - use td_rs_dat::NodeInfo; - - #[no_mangle] - pub extern "C" fn dat_get_plugin_info_impl( - mut op_info: std::pin::Pin<&mut OP_CustomOPInfo>, - ) { - unsafe { - td_rs_dat::op_info::<$plugin_ty>(op_info); - } - } - - #[no_mangle] - pub extern "C" fn dat_new_impl(info: NodeInfo) -> Box { - op_init(); - Box::new(<$plugin_ty>::new(info)) - } - }; -} +use std::ffi::CString; +use std::ops::{Index, IndexMut}; +use std::pin::Pin; + +use td_rs_base::chop::ChopInput; +pub use td_rs_base::dat::*; +pub use td_rs_base::param::OperatorParams; +pub use td_rs_base::*; + +pub mod cxx; +pub mod prelude; + +#[derive(Debug, Default)] +pub struct DatGeneralInfo { + pub cook_every_frame: bool, + pub cook_every_frame_if_asked: bool, +} + +pub struct DatOutput<'cook> { + output: Pin<&'cook mut cxx::DAT_Output>, +} + +impl<'cook> DatOutput<'cook> { + pub fn new(output: Pin<&'cook mut cxx::DAT_Output>) -> Self { + Self { output } + } + + pub fn table + Default>(mut self) -> DatTableOutput<'cook, T> { + self.output + .as_mut() + .setOutputDataType(cxx::DAT_OutDataType::Table); + let table = Vec::new(); + let mut table_out = DatTableOutput { + output: self.output, + table, + }; + table_out + .table + .resize(table_out.table_size().iter().product(), T::default()); + table_out + } + + pub fn text(mut self) -> DatTextOutput<'cook> { + self.output + .as_mut() + .setOutputDataType(cxx::DAT_OutDataType::Text); + DatTextOutput { + output: self.output, + } + } +} + +pub struct DatTableOutput<'cook, T> { + output: Pin<&'cook mut cxx::DAT_Output>, + table: Vec, +} + +impl<'cook, T> DatTableOutput<'cook, T> +where + T: CellType<'cook> + Default, +{ + pub fn get(&self, row: usize, col: usize) -> &T { + T::get(self, row, col) + } + + pub fn set(&mut self, row: usize, col: usize, value: T) { + T::set(self, row, col, value) + } + + pub fn table_size(&self) -> [usize; 2] { + let mut rows = 0; + let mut cols = 0; + unsafe { + self.output.as_ref().getTableSize(&mut rows, &mut cols); + } + [rows as usize, cols as usize] + } + + pub fn set_table_size(&mut self, rows: usize, cols: usize) { + self.output.as_mut().setTableSize(rows as i32, cols as i32); + self.table.resize(rows * cols, T::default()); + } +} + +/// A type which can be used as a cell in a DAT table. Should not be implemented manually or used +/// directly. +pub trait CellType<'cook> +where + Self: Clone, +{ + /// Get a reference to the value of this cell from the table. + fn get<'a>(table: &'a DatTableOutput<'cook, Self>, row: usize, col: usize) -> &'a Self; + /// Set the value of this cell in the table. + fn set(table: &mut DatTableOutput, row: usize, col: usize, value: Self); +} + +impl<'cook> CellType<'cook> for f64 { + fn get<'a>(table: &'a DatTableOutput<'cook, Self>, row: usize, col: usize) -> &'a Self { + let mut out = f64::default(); + let [rows, _] = table.table_size(); + let offset = row * rows + col; + unsafe { + table + .output + .as_ref() + .getCellDouble(row as i32, col as i32, &mut out); + } + let ptr = table.table.as_ptr(); + + unsafe { + let y = ptr.add(offset) as *mut f64; + *y = out; + } + + &table.table[offset] + } + + fn set(table: &mut DatTableOutput, row: usize, col: usize, value: Self) { + let [rows, _] = table.table_size(); + let offset = row * rows + col; + table.table[offset] = value; + table + .output + .as_mut() + .setCellDouble(row as i32, col as i32, value); + } +} + +impl<'cook> CellType<'cook> for i32 { + fn get<'a>(table: &'a DatTableOutput<'cook, Self>, row: usize, col: usize) -> &'a Self { + let mut out = i32::default(); + let [rows, _] = table.table_size(); + let offset = row * rows + col; + unsafe { + table + .output + .as_ref() + .getCellInt(row as i32, col as i32, &mut out); + } + let ptr = table.table.as_ptr(); + + unsafe { + let y = ptr.add(offset) as *mut i32; + *y = out; + } + + &table.table[offset] + } + + fn set(table: &mut DatTableOutput, row: usize, col: usize, value: Self) { + let rows = table.table_size()[0]; + let offset = row * rows + col; + table.table[offset] = value; + table + .output + .as_mut() + .setCellInt(row as i32, col as i32, value); + } +} + +impl<'cook> CellType<'cook> for String { + fn get<'a>(table: &'a DatTableOutput<'cook, Self>, row: usize, col: usize) -> &'a Self { + let rows = table.table_size()[0]; + let offset = row * rows + col; + let out = unsafe { + let out = table.output.as_ref().getCellString(row as i32, col as i32); + std::ffi::CStr::from_ptr(out).to_str().unwrap() + }; + + let ptr = table.table.as_ptr(); + + unsafe { + let y = ptr.add(offset) as *mut &str; + *y = out; + } + + &table.table[offset] + } + + fn set(table: &mut DatTableOutput, row: usize, col: usize, value: Self) { + let rows = table.table_size()[0]; + let offset = row * rows + col; + table.table[offset] = value.clone(); + let cstr = std::ffi::CString::new(value).unwrap(); + unsafe { + table + .output + .as_mut() + .setCellString(row as i32, col as i32, cstr.as_ptr()); + } + } +} + +impl<'cook, T> Index<[usize; 2]> for DatTableOutput<'cook, T> +where + T: CellType<'cook> + Default, +{ + type Output = T; + + fn index(&self, index: [usize; 2]) -> &Self::Output { + let [row, col] = index; + self.get(row, col) + } +} + +impl<'cook, T> IndexMut<[usize; 2]> for DatTableOutput<'cook, T> +where + T: CellType<'cook> + Default, +{ + fn index_mut(&mut self, index: [usize; 2]) -> &mut Self::Output { + let [row, col] = index; + let [rows, _] = self.table_size(); + let out = T::default(); + self.table[row * rows + col] = out; + //self.set(row, col, out); + &mut self.table[row * rows + col] + } +} + +pub struct DatTextOutput<'cook> { + output: Pin<&'cook mut cxx::DAT_Output>, +} + +impl<'cook> DatTextOutput<'cook> { + pub fn set_text(&mut self, text: &str) { + unsafe { + let c_str = CString::new(text).unwrap(); + self.output.as_mut().setText(c_str.as_ptr()); + } + } +} + +pub trait Dat: Op { + fn general_info(&self, _input: &OperatorInputs) -> DatGeneralInfo { + DatGeneralInfo::default() + } + + fn execute(&mut self, _output: DatOutput, _input: &OperatorInputs) { + // Do nothing by default. + } + + fn build_dynamic_menu( + &mut self, + inputs: &OperatorInputs, + menu_info: &mut DynamicMenuInfo, + ) { + } +} + +#[macro_export] +macro_rules! dat_plugin { + ($plugin_ty:ty) => { + use td_rs_dat::cxx::c_void; + use td_rs_dat::cxx::OP_CustomOPInfo; + use td_rs_dat::NodeInfo; + + #[no_mangle] + pub extern "C" fn dat_get_plugin_info_impl( + mut op_info: std::pin::Pin<&mut OP_CustomOPInfo>, + ) { + unsafe { + td_rs_dat::op_info::<$plugin_ty>(op_info); + } + } + + #[no_mangle] + pub extern "C" fn dat_new_impl(info: NodeInfo) -> Box { + op_init(); + Box::new(<$plugin_ty>::new(info)) + } + }; +} diff --git a/td-rs-dat/src/prelude.rs b/td-rs-dat/src/prelude.rs index dd44555..c36e0d9 100644 --- a/td-rs-dat/src/prelude.rs +++ b/td-rs-dat/src/prelude.rs @@ -1,9 +1,9 @@ -pub use crate::cxx::AsPlugin; -pub use crate::*; - -#[cfg(feature = "python")] -pub use pyo3::impl_::pyclass::PyClassImpl; -#[cfg(feature = "python")] -pub use pyo3::prelude::*; -#[cfg(feature = "python")] -pub use std::pin::Pin; +pub use crate::cxx::AsPlugin; +pub use crate::*; + +#[cfg(feature = "python")] +pub use pyo3::impl_::pyclass::PyClassImpl; +#[cfg(feature = "python")] +pub use pyo3::prelude::*; +#[cfg(feature = "python")] +pub use std::pin::Pin; diff --git a/td-rs-dat/src/table.rs b/td-rs-dat/src/table.rs index eecb681..68ef25e 100644 --- a/td-rs-dat/src/table.rs +++ b/td-rs-dat/src/table.rs @@ -1,123 +1,123 @@ -use std::collections::HashMap; -use std::ops::{Index, IndexMut}; - -pub struct Table { - size: [usize; 2], - r: HashMap<[usize; 2], T>, - w: HashMap<[usize; 2], T>, -} - -impl Table { - pub fn new(size: [usize; 2]) -> Self { - Self { - size, - r: HashMap::new(), - w: HashMap::new(), - } - } - - pub fn size(&self) -> [usize; 2] { - self.size - } - - pub fn contains_key(&self, index: [usize; 2]) -> bool { - self.r.contains_key(&index) || self.w.contains_key(&index) - } - - pub fn for_each(&self, mut f: F) - where - F: FnMut(&[usize; 2], &T), - { - for (k, v) in self.w.iter() { - f(k, v); - } - } - - pub fn resize(&mut self, size: [usize; 2]) { - self.size = size; - } -} - -impl Index<[usize; 2]> for Table { - type Output = T; - - fn index(&self, index: [usize; 2]) -> &Self::Output { - let [row, col] = index; - if row >= self.size[0] || col >= self.size[1] { - panic!("Index out of bounds: {:?}", index); - } - - if self.w.contains_key(&index) { - return &self.w[&index]; - } - - &self.r[&index] - } -} - -impl IndexMut<[usize; 2]> for Table -where - T: Default, -{ - fn index_mut(&mut self, index: [usize; 2]) -> &mut Self::Output { - let [row, col] = index; - if row >= self.size[0] || col >= self.size[1] { - panic!("Index out of bounds: {:?}", index); - } - - self.w.entry(index).or_insert_with(|| T::default()) - } -} - -#[cfg(test)] -mod test { - use std::sync::Arc; - - #[test] - fn test_table() { - let mut table = super::Table::new([2, 2]); - table[[0, 0]] = 1; - assert_eq!(table[[0, 0]], 1); - } - - #[test] - fn test_table_default() { - let table = super::Table::::new([2, 2]); - assert_eq!(table[[0, 0]], 0); - } - - #[test] - fn test_table_default_2() { - let mut table = super::Table::::new([2, 2]); - table[[0, 0]] = 1; - assert_eq!(table[[0, 0]], 1); - assert_eq!(table[[0, 1]], 0); - } - - #[test] - fn test_table_for_each() { - let mut table = super::Table::new([2, 2]); - table[[0, 0]] = 1; - table[[0, 1]] = 2; - table[[1, 0]] = 3; - table[[1, 1]] = 4; - let mut sum = 0; - table.for_each(|_, v| sum += v); - assert_eq!(sum, 10); - } - - #[test] - fn test_table_resize() { - let mut table = super::Table::new([2, 2]); - table[[0, 0]] = 1; - table[[0, 1]] = 2; - table[[1, 0]] = 3; - table[[1, 1]] = 4; - table.resize([3, 3]); - assert_eq!(table[[0, 0]], 1); - assert_eq!(table[[0, 1]], 2); - assert_eq!(table[[1, 0]], 3); - assert_eq!(table[[1, 1]], 4); - assert_eq!(table[[2, 0]], 0); - } -} +use std::collections::HashMap; +use std::ops::{Index, IndexMut}; + +pub struct Table { + size: [usize; 2], + r: HashMap<[usize; 2], T>, + w: HashMap<[usize; 2], T>, +} + +impl Table { + pub fn new(size: [usize; 2]) -> Self { + Self { + size, + r: HashMap::new(), + w: HashMap::new(), + } + } + + pub fn size(&self) -> [usize; 2] { + self.size + } + + pub fn contains_key(&self, index: [usize; 2]) -> bool { + self.r.contains_key(&index) || self.w.contains_key(&index) + } + + pub fn for_each(&self, mut f: F) + where + F: FnMut(&[usize; 2], &T), + { + for (k, v) in self.w.iter() { + f(k, v); + } + } + + pub fn resize(&mut self, size: [usize; 2]) { + self.size = size; + } +} + +impl Index<[usize; 2]> for Table { + type Output = T; + + fn index(&self, index: [usize; 2]) -> &Self::Output { + let [row, col] = index; + if row >= self.size[0] || col >= self.size[1] { + panic!("Index out of bounds: {:?}", index); + } + + if self.w.contains_key(&index) { + return &self.w[&index]; + } + + &self.r[&index] + } +} + +impl IndexMut<[usize; 2]> for Table +where + T: Default, +{ + fn index_mut(&mut self, index: [usize; 2]) -> &mut Self::Output { + let [row, col] = index; + if row >= self.size[0] || col >= self.size[1] { + panic!("Index out of bounds: {:?}", index); + } + + self.w.entry(index).or_insert_with(|| T::default()) + } +} + +#[cfg(test)] +mod test { + use std::sync::Arc; + + #[test] + fn test_table() { + let mut table = super::Table::new([2, 2]); + table[[0, 0]] = 1; + assert_eq!(table[[0, 0]], 1); + } + + #[test] + fn test_table_default() { + let table = super::Table::::new([2, 2]); + assert_eq!(table[[0, 0]], 0); + } + + #[test] + fn test_table_default_2() { + let mut table = super::Table::::new([2, 2]); + table[[0, 0]] = 1; + assert_eq!(table[[0, 0]], 1); + assert_eq!(table[[0, 1]], 0); + } + + #[test] + fn test_table_for_each() { + let mut table = super::Table::new([2, 2]); + table[[0, 0]] = 1; + table[[0, 1]] = 2; + table[[1, 0]] = 3; + table[[1, 1]] = 4; + let mut sum = 0; + table.for_each(|_, v| sum += v); + assert_eq!(sum, 10); + } + + #[test] + fn test_table_resize() { + let mut table = super::Table::new([2, 2]); + table[[0, 0]] = 1; + table[[0, 1]] = 2; + table[[1, 0]] = 3; + table[[1, 1]] = 4; + table.resize([3, 3]); + assert_eq!(table[[0, 0]], 1); + assert_eq!(table[[0, 1]], 2); + assert_eq!(table[[1, 0]], 3); + assert_eq!(table[[1, 1]], 4); + assert_eq!(table[[2, 0]], 0); + } +} diff --git a/td-rs-derive-py/Cargo.toml b/td-rs-derive-py/Cargo.toml index a65606e..941c192 100644 --- a/td-rs-derive-py/Cargo.toml +++ b/td-rs-derive-py/Cargo.toml @@ -1,17 +1,17 @@ -[package] -name = "td-rs-derive-py" -version = "0.1.0" -edition = "2021" - -[lib] -proc-macro = true - -[dependencies] -td-rs-base = { path = "../td-rs-base", features = ["python"] } -syn = { version = "1.0", features = ["full"] } -quote = "1.0" -proc-macro2 = "1.0" - -[dev-dependencies] -trybuild = "1.0" -rgb = "0.8.36" +[package] +name = "td-rs-derive-py" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +td-rs-base = { path = "../td-rs-base", features = ["python"] } +syn = { version = "1.0", features = ["full"] } +quote = "1.0" +proc-macro2 = "1.0" + +[dev-dependencies] +trybuild = "1.0" +rgb = "0.8.36" diff --git a/td-rs-derive-py/src/lib.rs b/td-rs-derive-py/src/lib.rs index e55144e..dda74dd 100644 --- a/td-rs-derive-py/src/lib.rs +++ b/td-rs-derive-py/src/lib.rs @@ -1,371 +1,371 @@ -extern crate proc_macro; - -use proc_macro::TokenStream; - -use quote::{format_ident, quote}; -use syn::{parse_macro_input, DeriveInput}; - -#[proc_macro_derive(PyOp, attributes(py))] -pub fn params_derive(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - impl_py_op(&input) -} - -struct PyOpArgs { - get: bool, - set: bool, - auto_cook: bool, - doc: Option, -} - -impl Default for PyOpArgs { - fn default() -> Self { - Self { - get: true, - set: true, - auto_cook: false, - doc: None, - } - } -} - -fn parse_attribute_args(args: syn::AttributeArgs) -> Result { - let mut get = false; - let mut set = false; - let mut auto_cook = false; - let mut doc = None; - - for nested_meta in args { - match nested_meta { - syn::NestedMeta::Meta(syn::Meta::Path(path)) => { - if path.is_ident("get") { - get = true; - } else if path.is_ident("set") { - set = true; - } else if path.is_ident("auto_cook") { - auto_cook = true; - } else { - return Err(syn::Error::new_spanned(path, "Unknown option")); - } - } - syn::NestedMeta::Meta(syn::Meta::NameValue(name_value)) => { - if name_value.path.is_ident("doc") { - if let syn::Lit::Str(lit_str) = name_value.lit { - doc = Some(lit_str); - } else { - return Err(syn::Error::new_spanned( - name_value.lit, - "Expected a string literal for 'doc'", - )); - } - } else { - return Err(syn::Error::new_spanned(name_value.path, "Unknown option")); - } - } - _ => return Err(syn::Error::new_spanned(nested_meta, "Invalid option")), - } - } - - // allow user to just pass doc / autocook - if !get && !set { - get = true; - set = true; - } - Ok(PyOpArgs { - get, - set, - auto_cook, - doc, - }) -} - -fn impl_py_op(input: &DeriveInput) -> TokenStream { - let struct_name = &input.ident; - - struct PyGetSet { - py_get_set_def: proc_macro2::TokenStream, - get_body: Option, - set_body: Option, - } - - let gen = match &input.data { - syn::Data::Struct(data_struct) => match &data_struct.fields { - syn::Fields::Named(fields_named) => { - quote! { - impl<'a, 'py> pyo3::impl_::extract_argument::ExtractPyClassRef<'a, 'py> for #struct_name { - fn extract_ref( - obj: &'a pyo3::Bound<'py, pyo3::PyAny>, - holder: &'a mut Option>, - ) -> pyo3::PyResult<&'a Self> { - unsafe { - let me = obj.as_ptr(); - let py_struct = me as *mut cxx::PY_Struct; - let info = cxx::PY_GetInfo { - autoCook: true, - reserved: [0; 50], - }; - // SAFETY: - // Pinning the context is safe because the context is not moved or dropped as it is - // derived from our C++ operator instance which is not moved or dropped during the - // lifetime of the Python object. - let mut ctx = Pin::new_unchecked(&mut *cxx::getPyContext(py_struct)); - // Look up our operator instance. - let me = ctx.getNodeInstance(&info, std::ptr::null_mut()); - if me.is_null() { - return Err(pyo3::exceptions::PyTypeError::new_err("operator is null")); - } - let py_op = { - let me = cxx::plugin_cast(me); - let me = me.as_plugin().inner(); - &*(me as *const #struct_name) - }; - - Ok(py_op) - } - } - } - - impl<'a, 'py> pyo3::impl_::extract_argument::ExtractPyClassRefMut<'a, 'py> for #struct_name { - fn extract_mut( - obj: &'a pyo3::Bound<'py, pyo3::PyAny>, - holder: &'a mut Option>, - ) -> PyResult<&'a mut Self> { - unsafe { - let me = obj.as_ptr(); - let py_struct = me as *mut cxx::PY_Struct; - let info = cxx::PY_GetInfo { - autoCook: true, - reserved: [0; 50], - }; - // SAFETY: - // Pinning the context is safe because the context is not moved or dropped as it is - // derived from our C++ operator instance which is not moved or dropped during the - // lifetime of the Python object. - let py_ctx = cxx::getPyContext(py_struct); - // Mark the node as dirty so that it will be cooked on the next frame. - Pin::new_unchecked(&mut *py_ctx).makeNodeDirty(std::ptr::null_mut()); - // Look up our operator instance. - let me = Pin::new_unchecked(&mut *py_ctx).getNodeInstance(&info, std::ptr::null_mut()); - if me.is_null() { - return Err(pyo3::exceptions::PyTypeError::new_err("operator is null")); - } - // SAFETY: - // We have a valid operator instance pointer - let py_op = { - let me = cxx::plugin_cast(me); - let me = me.as_plugin_mut().innerMut(); - &mut *(me as *mut #struct_name) - }; - Ok(py_op) - } - } - } - - impl PyGetSets for #struct_name { - fn get_get_sets() -> &'static [pyo3::ffi::PyGetSetDef] { - let clazz = pyo3::impl_::pyclass::PyClassImplCollector::<#struct_name>::new(); - let methods = as pyo3::impl_::pyclass::PyMethods::<#struct_name>>::py_methods(clazz); - let mut getset_builders = std::collections::HashMap::<&std::ffi::CStr, pyo3::pyclass::create_type_object::GetSetDefBuilder>::new(); - for method in methods.methods { - let method_def = match method { - pyo3::impl_::pyclass::MaybeRuntimePyMethodDef::Runtime(m) => &m(), - pyo3::impl_::pyclass::MaybeRuntimePyMethodDef::Static(m) => m, - }; - - match method_def { - pyo3::PyMethodDefType::Getter(getter) => { - getset_builders - .entry(getter.name) - .or_default() - .add_getter(getter) - } - pyo3::PyMethodDefType::Setter(setter) => { - getset_builders - .entry(setter.name) - .or_default() - .add_setter(setter) - } - _ => {} - } - } - - let items = #struct_name::items_iter(); - for item in items { - for method in item.methods { - let method_def = match method { - pyo3::impl_::pyclass::MaybeRuntimePyMethodDef::Runtime(m) => &m(), - pyo3::impl_::pyclass::MaybeRuntimePyMethodDef::Static(m) => m, - }; - - match method_def { - pyo3::PyMethodDefType::Getter(getter) => { - getset_builders - .entry(getter.name) - .or_default() - .add_getter(getter) - } - pyo3::PyMethodDefType::Setter(setter) => { - getset_builders - .entry(setter.name) - .or_default() - .add_setter(setter) - } - _ => {} - } - } - } - - let mut getset_destructors = Vec::with_capacity(getset_builders.len()); - - let property_defs: Vec = getset_builders - .iter() - .map(|(name, builder)| { - let (def, destructor) = builder.as_get_set_def(name); - getset_destructors.push(destructor); - def - }) - .collect(); - - - // We just have to leak these to keep them alive - // TODO: right now we are leaking the memory, we should free it when the plugin is unloaded - // but unless you're loading and unloading the plugin a lot, it's not a big deal - getset_destructors.leak(); - property_defs.leak() - } - } - - impl PyMethods for #struct_name { - fn get_methods() -> &'static [pyo3::ffi::PyMethodDef] { - let clazz = pyo3::impl_::pyclass::PyClassImplCollector::<#struct_name>::new(); - let methods = as pyo3::impl_::pyclass::PyMethods::<#struct_name>>::py_methods(clazz); - let mut method_defs = Vec::new(); - for method in methods.methods { - let method_def = match method { - pyo3::impl_::pyclass::MaybeRuntimePyMethodDef::Runtime(m) => &m(), - pyo3::impl_::pyclass::MaybeRuntimePyMethodDef::Static(m) => m, - }; - - match method_def { - pyo3::PyMethodDefType::Method(m) => { - method_defs.push(m.as_method_def()); - } - _ => {} - } - } - - method_defs.leak() - } - } - - - impl PyOp for #struct_name {} - } - } - _ => panic!("Only named fields are supported"), - }, - _ => panic!("Only structs are supported"), - }; - - gen.into() -} - -fn is_py_meth_attr(attr: &syn::Attribute) -> bool { - attr.path.is_ident("py_meth") -} - -#[proc_macro_attribute] -pub fn py_op_methods(_attr: TokenStream, item: TokenStream) -> TokenStream { - let input = parse_macro_input!(item as syn::ItemImpl); - let struct_name = &input.self_ty; - struct PyMeth { - py_meth: proc_macro2::TokenStream, - fn_body: proc_macro2::TokenStream, - } - - let generated_functions: Vec<_> = input.items.iter().filter_map(|item| { - if let syn::ImplItem::Method(method) = item { - let has_py_meth = method.attrs.iter().any(is_py_meth_attr); - if has_py_meth { - let fn_name = &method.sig.ident; - Some(PyMeth { - py_meth: quote! { - pyo3::ffi::PyMethodDef { - ml_name: concat!(stringify!(#fn_name), '\0').as_ptr().cast::(), - ml_meth: pyo3::ffi::PyMethodDefPointer { - _PyCFunctionFast: #fn_name, - }, - ml_flags: pyo3::ffi::METH_FASTCALL, - ml_doc: std::ptr::null_mut(), - }, - }, - fn_body: quote! { - pub unsafe extern "C" fn #fn_name( - _self: *mut pyo3::ffi::PyObject, - args: *mut *mut pyo3::ffi::PyObject, - nargs: pyo3::ffi::Py_ssize_t, - ) -> *mut pyo3::ffi::PyObject { - use cxx::AsPlugin; - let py_struct = _self as *mut cxx::PY_Struct; - let info = cxx::PY_GetInfo { - autoCook: true, - reserved: [0; 50] - }; - let mut ctx = std::pin::Pin::new_unchecked(&mut*cxx::getPyContext(py_struct));; - let me = ctx.getNodeInstance(&info, std::ptr::null_mut()); - if me.is_null() { - pyo3::ffi::PyErr_SetString( - pyo3::ffi::PyExc_TypeError, - "operator is null\0" - .as_ptr() - .cast::(), - ); - return std::ptr::null_mut(); - } - let py_op = { - let me = cxx::plugin_cast(me); - let me = me.as_plugin_mut().innerMut(); - &mut *(me as *mut #struct_name) - }; - let res = py_op.#fn_name(args, nargs as usize); - let mut ctx = std::pin::Pin::new_unchecked(&mut*cxx::getPyContext(py_struct));; - ctx.makeNodeDirty(std::ptr::null_mut()); - res - } - } - }) - } else { - None - } - } else { - None - } - }).collect(); - - let methods: Vec<_> = generated_functions.iter().map(|gf| &gf.py_meth).collect(); - let fns: Vec<_> = generated_functions.iter().map(|gf| &gf.fn_body).collect(); - let size = generated_functions.len() + 1; - - let gen = quote! { - #input - - impl PyMethods for #struct_name { - fn get_methods() -> &'static [pyo3::ffi::PyMethodDef] { - &METHODS - } - } - - pub const METHODS: [pyo3::ffi::PyMethodDef; #size] = [ - #( #methods )* - pyo3::ffi::PyMethodDef::zeroed() - ]; - - #( #fns )* - }; - gen.into() -} - -#[proc_macro_attribute] -pub fn py_meth(_attrs: TokenStream, input: TokenStream) -> TokenStream { - input // just return the input unchanged -} +extern crate proc_macro; + +use proc_macro::TokenStream; + +use quote::{format_ident, quote}; +use syn::{parse_macro_input, DeriveInput}; + +#[proc_macro_derive(PyOp, attributes(py))] +pub fn params_derive(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + impl_py_op(&input) +} + +struct PyOpArgs { + get: bool, + set: bool, + auto_cook: bool, + doc: Option, +} + +impl Default for PyOpArgs { + fn default() -> Self { + Self { + get: true, + set: true, + auto_cook: false, + doc: None, + } + } +} + +fn parse_attribute_args(args: syn::AttributeArgs) -> Result { + let mut get = false; + let mut set = false; + let mut auto_cook = false; + let mut doc = None; + + for nested_meta in args { + match nested_meta { + syn::NestedMeta::Meta(syn::Meta::Path(path)) => { + if path.is_ident("get") { + get = true; + } else if path.is_ident("set") { + set = true; + } else if path.is_ident("auto_cook") { + auto_cook = true; + } else { + return Err(syn::Error::new_spanned(path, "Unknown option")); + } + } + syn::NestedMeta::Meta(syn::Meta::NameValue(name_value)) => { + if name_value.path.is_ident("doc") { + if let syn::Lit::Str(lit_str) = name_value.lit { + doc = Some(lit_str); + } else { + return Err(syn::Error::new_spanned( + name_value.lit, + "Expected a string literal for 'doc'", + )); + } + } else { + return Err(syn::Error::new_spanned(name_value.path, "Unknown option")); + } + } + _ => return Err(syn::Error::new_spanned(nested_meta, "Invalid option")), + } + } + + // allow user to just pass doc / autocook + if !get && !set { + get = true; + set = true; + } + Ok(PyOpArgs { + get, + set, + auto_cook, + doc, + }) +} + +fn impl_py_op(input: &DeriveInput) -> TokenStream { + let struct_name = &input.ident; + + struct PyGetSet { + py_get_set_def: proc_macro2::TokenStream, + get_body: Option, + set_body: Option, + } + + let gen = match &input.data { + syn::Data::Struct(data_struct) => match &data_struct.fields { + syn::Fields::Named(fields_named) => { + quote! { + impl<'a, 'py> pyo3::impl_::extract_argument::ExtractPyClassRef<'a, 'py> for #struct_name { + fn extract_ref( + obj: &'a pyo3::Bound<'py, pyo3::PyAny>, + holder: &'a mut Option>, + ) -> pyo3::PyResult<&'a Self> { + unsafe { + let me = obj.as_ptr(); + let py_struct = me as *mut cxx::PY_Struct; + let info = cxx::PY_GetInfo { + autoCook: true, + reserved: [0; 50], + }; + // SAFETY: + // Pinning the context is safe because the context is not moved or dropped as it is + // derived from our C++ operator instance which is not moved or dropped during the + // lifetime of the Python object. + let mut ctx = Pin::new_unchecked(&mut *cxx::getPyContext(py_struct)); + // Look up our operator instance. + let me = ctx.getNodeInstance(&info, std::ptr::null_mut()); + if me.is_null() { + return Err(pyo3::exceptions::PyTypeError::new_err("operator is null")); + } + let py_op = { + let me = cxx::plugin_cast(me); + let me = me.as_plugin().inner(); + &*(me as *const #struct_name) + }; + + Ok(py_op) + } + } + } + + impl<'a, 'py> pyo3::impl_::extract_argument::ExtractPyClassRefMut<'a, 'py> for #struct_name { + fn extract_mut( + obj: &'a pyo3::Bound<'py, pyo3::PyAny>, + holder: &'a mut Option>, + ) -> PyResult<&'a mut Self> { + unsafe { + let me = obj.as_ptr(); + let py_struct = me as *mut cxx::PY_Struct; + let info = cxx::PY_GetInfo { + autoCook: true, + reserved: [0; 50], + }; + // SAFETY: + // Pinning the context is safe because the context is not moved or dropped as it is + // derived from our C++ operator instance which is not moved or dropped during the + // lifetime of the Python object. + let py_ctx = cxx::getPyContext(py_struct); + // Mark the node as dirty so that it will be cooked on the next frame. + Pin::new_unchecked(&mut *py_ctx).makeNodeDirty(std::ptr::null_mut()); + // Look up our operator instance. + let me = Pin::new_unchecked(&mut *py_ctx).getNodeInstance(&info, std::ptr::null_mut()); + if me.is_null() { + return Err(pyo3::exceptions::PyTypeError::new_err("operator is null")); + } + // SAFETY: + // We have a valid operator instance pointer + let py_op = { + let me = cxx::plugin_cast(me); + let me = me.as_plugin_mut().innerMut(); + &mut *(me as *mut #struct_name) + }; + Ok(py_op) + } + } + } + + impl PyGetSets for #struct_name { + fn get_get_sets() -> &'static [pyo3::ffi::PyGetSetDef] { + let clazz = pyo3::impl_::pyclass::PyClassImplCollector::<#struct_name>::new(); + let methods = as pyo3::impl_::pyclass::PyMethods::<#struct_name>>::py_methods(clazz); + let mut getset_builders = std::collections::HashMap::<&std::ffi::CStr, pyo3::pyclass::create_type_object::GetSetDefBuilder>::new(); + for method in methods.methods { + let method_def = match method { + pyo3::impl_::pyclass::MaybeRuntimePyMethodDef::Runtime(m) => &m(), + pyo3::impl_::pyclass::MaybeRuntimePyMethodDef::Static(m) => m, + }; + + match method_def { + pyo3::PyMethodDefType::Getter(getter) => { + getset_builders + .entry(getter.name) + .or_default() + .add_getter(getter) + } + pyo3::PyMethodDefType::Setter(setter) => { + getset_builders + .entry(setter.name) + .or_default() + .add_setter(setter) + } + _ => {} + } + } + + let items = #struct_name::items_iter(); + for item in items { + for method in item.methods { + let method_def = match method { + pyo3::impl_::pyclass::MaybeRuntimePyMethodDef::Runtime(m) => &m(), + pyo3::impl_::pyclass::MaybeRuntimePyMethodDef::Static(m) => m, + }; + + match method_def { + pyo3::PyMethodDefType::Getter(getter) => { + getset_builders + .entry(getter.name) + .or_default() + .add_getter(getter) + } + pyo3::PyMethodDefType::Setter(setter) => { + getset_builders + .entry(setter.name) + .or_default() + .add_setter(setter) + } + _ => {} + } + } + } + + let mut getset_destructors = Vec::with_capacity(getset_builders.len()); + + let property_defs: Vec = getset_builders + .iter() + .map(|(name, builder)| { + let (def, destructor) = builder.as_get_set_def(name); + getset_destructors.push(destructor); + def + }) + .collect(); + + + // We just have to leak these to keep them alive + // TODO: right now we are leaking the memory, we should free it when the plugin is unloaded + // but unless you're loading and unloading the plugin a lot, it's not a big deal + getset_destructors.leak(); + property_defs.leak() + } + } + + impl PyMethods for #struct_name { + fn get_methods() -> &'static [pyo3::ffi::PyMethodDef] { + let clazz = pyo3::impl_::pyclass::PyClassImplCollector::<#struct_name>::new(); + let methods = as pyo3::impl_::pyclass::PyMethods::<#struct_name>>::py_methods(clazz); + let mut method_defs = Vec::new(); + for method in methods.methods { + let method_def = match method { + pyo3::impl_::pyclass::MaybeRuntimePyMethodDef::Runtime(m) => &m(), + pyo3::impl_::pyclass::MaybeRuntimePyMethodDef::Static(m) => m, + }; + + match method_def { + pyo3::PyMethodDefType::Method(m) => { + method_defs.push(m.as_method_def()); + } + _ => {} + } + } + + method_defs.leak() + } + } + + + impl PyOp for #struct_name {} + } + } + _ => panic!("Only named fields are supported"), + }, + _ => panic!("Only structs are supported"), + }; + + gen.into() +} + +fn is_py_meth_attr(attr: &syn::Attribute) -> bool { + attr.path.is_ident("py_meth") +} + +#[proc_macro_attribute] +pub fn py_op_methods(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as syn::ItemImpl); + let struct_name = &input.self_ty; + struct PyMeth { + py_meth: proc_macro2::TokenStream, + fn_body: proc_macro2::TokenStream, + } + + let generated_functions: Vec<_> = input.items.iter().filter_map(|item| { + if let syn::ImplItem::Method(method) = item { + let has_py_meth = method.attrs.iter().any(is_py_meth_attr); + if has_py_meth { + let fn_name = &method.sig.ident; + Some(PyMeth { + py_meth: quote! { + pyo3::ffi::PyMethodDef { + ml_name: concat!(stringify!(#fn_name), '\0').as_ptr().cast::(), + ml_meth: pyo3::ffi::PyMethodDefPointer { + _PyCFunctionFast: #fn_name, + }, + ml_flags: pyo3::ffi::METH_FASTCALL, + ml_doc: std::ptr::null_mut(), + }, + }, + fn_body: quote! { + pub unsafe extern "C" fn #fn_name( + _self: *mut pyo3::ffi::PyObject, + args: *mut *mut pyo3::ffi::PyObject, + nargs: pyo3::ffi::Py_ssize_t, + ) -> *mut pyo3::ffi::PyObject { + use cxx::AsPlugin; + let py_struct = _self as *mut cxx::PY_Struct; + let info = cxx::PY_GetInfo { + autoCook: true, + reserved: [0; 50] + }; + let mut ctx = std::pin::Pin::new_unchecked(&mut*cxx::getPyContext(py_struct));; + let me = ctx.getNodeInstance(&info, std::ptr::null_mut()); + if me.is_null() { + pyo3::ffi::PyErr_SetString( + pyo3::ffi::PyExc_TypeError, + "operator is null\0" + .as_ptr() + .cast::(), + ); + return std::ptr::null_mut(); + } + let py_op = { + let me = cxx::plugin_cast(me); + let me = me.as_plugin_mut().innerMut(); + &mut *(me as *mut #struct_name) + }; + let res = py_op.#fn_name(args, nargs as usize); + let mut ctx = std::pin::Pin::new_unchecked(&mut*cxx::getPyContext(py_struct));; + ctx.makeNodeDirty(std::ptr::null_mut()); + res + } + } + }) + } else { + None + } + } else { + None + } + }).collect(); + + let methods: Vec<_> = generated_functions.iter().map(|gf| &gf.py_meth).collect(); + let fns: Vec<_> = generated_functions.iter().map(|gf| &gf.fn_body).collect(); + let size = generated_functions.len() + 1; + + let gen = quote! { + #input + + impl PyMethods for #struct_name { + fn get_methods() -> &'static [pyo3::ffi::PyMethodDef] { + &METHODS + } + } + + pub const METHODS: [pyo3::ffi::PyMethodDef; #size] = [ + #( #methods )* + pyo3::ffi::PyMethodDef::zeroed() + ]; + + #( #fns )* + }; + gen.into() +} + +#[proc_macro_attribute] +pub fn py_meth(_attrs: TokenStream, input: TokenStream) -> TokenStream { + input // just return the input unchanged +} diff --git a/td-rs-derive-py/tests/parameter_macro/pass.rs b/td-rs-derive-py/tests/parameter_macro/pass.rs index 12a255a..913570a 100644 --- a/td-rs-derive-py/tests/parameter_macro/pass.rs +++ b/td-rs-derive-py/tests/parameter_macro/pass.rs @@ -1,35 +1,35 @@ -#![allow(unused)] - -use td_rs_base::*; -use td_rs_derive_py::*; - -enum TestEnum { - Hi, - Hello, - Goodbye, -} - -#[py_op] -struct TestParameter { - float2: f32, - float3: f64, - int: i16, - int2: u32, - int3: i64, - hi: String, - menu: TestEnum, - // rgb: rgb::RGB, -} - -fn main() { - let mut param = TestParameter { - // Initialize fields - float2: 0.0, - float3: 0.0, - int: 0, - int2: 0, - int3: 0, - hi: "".to_string(), - menu: TestEnum::Hi, - }; -} +#![allow(unused)] + +use td_rs_base::*; +use td_rs_derive_py::*; + +enum TestEnum { + Hi, + Hello, + Goodbye, +} + +#[py_op] +struct TestParameter { + float2: f32, + float3: f64, + int: i16, + int2: u32, + int3: i64, + hi: String, + menu: TestEnum, + // rgb: rgb::RGB, +} + +fn main() { + let mut param = TestParameter { + // Initialize fields + float2: 0.0, + float3: 0.0, + int: 0, + int2: 0, + int3: 0, + hi: "".to_string(), + menu: TestEnum::Hi, + }; +} diff --git a/td-rs-derive-py/tests/parameter_macro_test.rs b/td-rs-derive-py/tests/parameter_macro_test.rs index c97e843..5c8c0de 100644 --- a/td-rs-derive-py/tests/parameter_macro_test.rs +++ b/td-rs-derive-py/tests/parameter_macro_test.rs @@ -1,12 +1,12 @@ -use trybuild::TestCases; - -#[test] -fn parameter_macro_tests() { - let t = TestCases::new(); - - // Test case for successful expansion - t.pass("tests/parameter_macro/pass.rs"); - - // Test case for expected error - // t.compile_fail("tests/parameter_macro/fail.rs"); -} +use trybuild::TestCases; + +#[test] +fn parameter_macro_tests() { + let t = TestCases::new(); + + // Test case for successful expansion + t.pass("tests/parameter_macro/pass.rs"); + + // Test case for expected error + // t.compile_fail("tests/parameter_macro/fail.rs"); +} diff --git a/td-rs-derive/Cargo.toml b/td-rs-derive/Cargo.toml index 3ba3862..adc0eec 100644 --- a/td-rs-derive/Cargo.toml +++ b/td-rs-derive/Cargo.toml @@ -1,17 +1,17 @@ -[package] -name = "td-rs-derive" -version = "0.1.0" -edition = "2021" - -[lib] -proc-macro = true - -[dependencies] -td-rs-base = { path = "../td-rs-base" } -syn = { version = "1.0", features = ["full"] } -quote = "1.0" -proc-macro2 = "1.0" - -[dev-dependencies] -trybuild = "1.0" -rgb = "0.8.36" +[package] +name = "td-rs-derive" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +td-rs-base = { path = "../td-rs-base" } +syn = { version = "1.0", features = ["full"] } +quote = "1.0" +proc-macro2 = "1.0" + +[dev-dependencies] +trybuild = "1.0" +rgb = "0.8.36" diff --git a/td-rs-derive/src/lib.rs b/td-rs-derive/src/lib.rs index ef18111..ee1e383 100644 --- a/td-rs-derive/src/lib.rs +++ b/td-rs-derive/src/lib.rs @@ -1,259 +1,259 @@ -extern crate proc_macro; - -use proc_macro::TokenStream; - -use quote::quote; - -use syn::{ - parse_macro_input, Data, DeriveInput, Fields, Lit, Meta, MetaNameValue, NestedMeta, Variant, -}; - -#[proc_macro_derive(Param)] -pub fn derive_param(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - - let enum_ident = input.ident; - let enum_data = if let Data::Enum(data) = input.data { - data - } else { - panic!("`Param` can only be derived for enums"); - }; - - let variant_names = enum_data - .variants - .iter() - .map(|variant| variant.ident.to_string()) - .collect::>(); - - let variant_labels = variant_names - .iter() - .map(|name| camel_case_to_words(name)) - .collect::>(); - - let variants = enum_data.variants.into_iter().collect::>(); - let try_from_i32_match_arms = try_from_i32_match_arms(&variants); - - let output = quote! { - impl MenuParam for #enum_ident { - fn names() -> Vec { - vec![ - #(String::from(#variant_names)),* - ] - } - - fn labels() -> Vec { - vec![ - #(String::from(#variant_labels)),* - ] - } - } - - impl std::convert::TryFrom for #enum_ident { - type Error = String; - - fn try_from(value: i32) -> Result { - match value { - #try_from_i32_match_arms - _ => Err(format!("Invalid value for {}: {}", stringify!(#enum_ident), value)), - } - } - } - - impl Param for #enum_ident { - fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { - let param: StringParameter = options.into(); - let names = #enum_ident::names(); - let labels = #enum_ident::labels(); - parameter_manager.append_menu(param, &names, &labels); - } - - fn update(&mut self, name: &str, inputs: &ParamInputs) { - let idx = inputs.get_int(name, 0); - let value = #enum_ident::try_from(idx).unwrap(); - *self = value; - } - } - }; - - output.into() -} - -fn try_from_i32_match_arms(variants: &[Variant]) -> proc_macro2::TokenStream { - let arms = variants.iter().enumerate().map(|(idx, variant)| { - let ident = &variant.ident; - let index = idx as i32; - quote! { - #index => Ok(Self::#ident), - } - }); - - quote! { - #( #arms )* - } -} - -fn camel_case_to_words(s: &str) -> String { - let mut words = String::new(); - - for (i, c) in s.char_indices() { - if i != 0 && c.is_uppercase() { - words.push(' '); - } - words.push(c); - } - - words -} - -#[proc_macro_derive(Params, attributes(param))] -pub fn params_derive(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - impl_params(&input) -} - -fn impl_params(input: &DeriveInput) -> TokenStream { - let struct_name = &input.ident; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - - let mut register_code = Vec::new(); - let mut update_code = Vec::new(); // Add this line to store update code - - if let Data::Struct(data_struct) = &input.data { - if let Fields::Named(named_fields) = &data_struct.fields { - for field in named_fields.named.iter() { - let field_name = field.ident.as_ref().unwrap(); - let _field_type = &field.ty; - - let mut label = None; - let mut page = None; - let mut min = None; - let mut max = None; - let mut min_slider = None; - let mut max_slider = None; - let mut clamp = None; - let mut default = None; - - for attr in &field.attrs { - if attr.path.is_ident("param") { - if let Ok(Meta::List(meta_list)) = attr.parse_meta() { - for nested_meta in meta_list.nested.iter() { - if let NestedMeta::Meta(Meta::NameValue(MetaNameValue { - path, - lit, - .. - })) = nested_meta - { - if path.is_ident("label") { - if let Lit::Str(lit_str) = lit { - label = Some(lit_str.value()); - } - } else if path.is_ident("page") { - if let Lit::Str(lit_str) = lit { - page = Some(lit_str.value()); - } - } else if path.is_ident("min") { - if let Lit::Float(lit_float) = lit { - min = Some(lit_float.base10_parse().unwrap()); - } - } else if path.is_ident("max") { - if let Lit::Float(lit_float) = lit { - max = Some(lit_float.base10_parse().unwrap()); - } - } else if path.is_ident("min_slider") { - if let Lit::Float(lit_float) = lit { - min_slider = Some(lit_float.base10_parse().unwrap()); - } - } else if path.is_ident("max_slider") { - if let Lit::Float(lit_float) = lit { - max_slider = Some(lit_float.base10_parse().unwrap()); - } - } else if path.is_ident("clamp") { - if let Lit::Bool(lit_bool) = lit { - clamp = Some(lit_bool.value); - } - } else if path.is_ident("default") { - if let Lit::Float(lit_float) = lit { - default = Some(lit_float.base10_parse().unwrap()); - } - if let Lit::Int(lit_int) = lit { - default = Some(lit_int.base10_parse().unwrap()); - } - } - } - } - } - } - } - - let field_name_upper = format_name(&field_name.to_string()); - let default_label = format!("{}", field_name); - let label = label.unwrap_or(default_label); - let default_page = "Custom".to_string(); - let page = page.unwrap_or(default_page); - let min = min.unwrap_or(0.0); - let max = max.unwrap_or(1.0); - let min_slider = min_slider.unwrap_or(min); - let max_slider = max_slider.unwrap_or(max); - let clamp = clamp.unwrap_or(false); - let default = default.unwrap_or(0.0); - - let register_field_code = quote! { - { - let options = ParamOptions { - name: #field_name_upper.to_string(), - label: #label.to_string(), - page: #page.to_string(), - min: #min, - max: #max, - min_slider: #min_slider, - max_slider: #max_slider, - clamp: #clamp, - default: #default, - }; - Param::register(&self.#field_name, options, parameter_manager); - } - }; - register_code.push(register_field_code); - - let update_field_code = quote! { - // TODO: Field name should be null terminated - Param::update(&mut self.#field_name, &(#field_name_upper.to_string()), inputs); - }; - - update_code.push(update_field_code); - } - } - } - - let register_code = quote! { #(#register_code)* }; - - let gen = quote! { - impl #impl_generics OperatorParams for #struct_name #ty_generics #where_clause { - fn register(&mut self, parameter_manager: &mut ParameterManager) { - #register_code - } - - fn update(&mut self, inputs: &ParamInputs) { - #(#update_code)* - } - } - }; - gen.into() -} - -fn format_name(name: &str) -> String { - let name = remove_underscores(name); - capitalize_first(&name) -} - -fn capitalize_first(s: &str) -> String { - let mut chars = s.chars(); - match chars.next() { - None => String::new(), - Some(first) => first.to_uppercase().chain(chars).collect(), - } -} - -fn remove_underscores(s: &str) -> String { - s.replace('_', "") -} +extern crate proc_macro; + +use proc_macro::TokenStream; + +use quote::quote; + +use syn::{ + parse_macro_input, Data, DeriveInput, Fields, Lit, Meta, MetaNameValue, NestedMeta, Variant, +}; + +#[proc_macro_derive(Param)] +pub fn derive_param(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + + let enum_ident = input.ident; + let enum_data = if let Data::Enum(data) = input.data { + data + } else { + panic!("`Param` can only be derived for enums"); + }; + + let variant_names = enum_data + .variants + .iter() + .map(|variant| variant.ident.to_string()) + .collect::>(); + + let variant_labels = variant_names + .iter() + .map(|name| camel_case_to_words(name)) + .collect::>(); + + let variants = enum_data.variants.into_iter().collect::>(); + let try_from_i32_match_arms = try_from_i32_match_arms(&variants); + + let output = quote! { + impl MenuParam for #enum_ident { + fn names() -> Vec { + vec![ + #(String::from(#variant_names)),* + ] + } + + fn labels() -> Vec { + vec![ + #(String::from(#variant_labels)),* + ] + } + } + + impl std::convert::TryFrom for #enum_ident { + type Error = String; + + fn try_from(value: i32) -> Result { + match value { + #try_from_i32_match_arms + _ => Err(format!("Invalid value for {}: {}", stringify!(#enum_ident), value)), + } + } + } + + impl Param for #enum_ident { + fn register(&self, options: ParamOptions, parameter_manager: &mut ParameterManager) { + let param: StringParameter = options.into(); + let names = #enum_ident::names(); + let labels = #enum_ident::labels(); + parameter_manager.append_menu(param, &names, &labels); + } + + fn update(&mut self, name: &str, inputs: &ParamInputs) { + let idx = inputs.get_int(name, 0); + let value = #enum_ident::try_from(idx).unwrap(); + *self = value; + } + } + }; + + output.into() +} + +fn try_from_i32_match_arms(variants: &[Variant]) -> proc_macro2::TokenStream { + let arms = variants.iter().enumerate().map(|(idx, variant)| { + let ident = &variant.ident; + let index = idx as i32; + quote! { + #index => Ok(Self::#ident), + } + }); + + quote! { + #( #arms )* + } +} + +fn camel_case_to_words(s: &str) -> String { + let mut words = String::new(); + + for (i, c) in s.char_indices() { + if i != 0 && c.is_uppercase() { + words.push(' '); + } + words.push(c); + } + + words +} + +#[proc_macro_derive(Params, attributes(param))] +pub fn params_derive(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + impl_params(&input) +} + +fn impl_params(input: &DeriveInput) -> TokenStream { + let struct_name = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + + let mut register_code = Vec::new(); + let mut update_code = Vec::new(); // Add this line to store update code + + if let Data::Struct(data_struct) = &input.data { + if let Fields::Named(named_fields) = &data_struct.fields { + for field in named_fields.named.iter() { + let field_name = field.ident.as_ref().unwrap(); + let _field_type = &field.ty; + + let mut label = None; + let mut page = None; + let mut min = None; + let mut max = None; + let mut min_slider = None; + let mut max_slider = None; + let mut clamp = None; + let mut default = None; + + for attr in &field.attrs { + if attr.path.is_ident("param") { + if let Ok(Meta::List(meta_list)) = attr.parse_meta() { + for nested_meta in meta_list.nested.iter() { + if let NestedMeta::Meta(Meta::NameValue(MetaNameValue { + path, + lit, + .. + })) = nested_meta + { + if path.is_ident("label") { + if let Lit::Str(lit_str) = lit { + label = Some(lit_str.value()); + } + } else if path.is_ident("page") { + if let Lit::Str(lit_str) = lit { + page = Some(lit_str.value()); + } + } else if path.is_ident("min") { + if let Lit::Float(lit_float) = lit { + min = Some(lit_float.base10_parse().unwrap()); + } + } else if path.is_ident("max") { + if let Lit::Float(lit_float) = lit { + max = Some(lit_float.base10_parse().unwrap()); + } + } else if path.is_ident("min_slider") { + if let Lit::Float(lit_float) = lit { + min_slider = Some(lit_float.base10_parse().unwrap()); + } + } else if path.is_ident("max_slider") { + if let Lit::Float(lit_float) = lit { + max_slider = Some(lit_float.base10_parse().unwrap()); + } + } else if path.is_ident("clamp") { + if let Lit::Bool(lit_bool) = lit { + clamp = Some(lit_bool.value); + } + } else if path.is_ident("default") { + if let Lit::Float(lit_float) = lit { + default = Some(lit_float.base10_parse().unwrap()); + } + if let Lit::Int(lit_int) = lit { + default = Some(lit_int.base10_parse().unwrap()); + } + } + } + } + } + } + } + + let field_name_upper = format_name(&field_name.to_string()); + let default_label = format!("{}", field_name); + let label = label.unwrap_or(default_label); + let default_page = "Custom".to_string(); + let page = page.unwrap_or(default_page); + let min = min.unwrap_or(0.0); + let max = max.unwrap_or(1.0); + let min_slider = min_slider.unwrap_or(min); + let max_slider = max_slider.unwrap_or(max); + let clamp = clamp.unwrap_or(false); + let default = default.unwrap_or(0.0); + + let register_field_code = quote! { + { + let options = ParamOptions { + name: #field_name_upper.to_string(), + label: #label.to_string(), + page: #page.to_string(), + min: #min, + max: #max, + min_slider: #min_slider, + max_slider: #max_slider, + clamp: #clamp, + default: #default, + }; + Param::register(&self.#field_name, options, parameter_manager); + } + }; + register_code.push(register_field_code); + + let update_field_code = quote! { + // TODO: Field name should be null terminated + Param::update(&mut self.#field_name, &(#field_name_upper.to_string()), inputs); + }; + + update_code.push(update_field_code); + } + } + } + + let register_code = quote! { #(#register_code)* }; + + let gen = quote! { + impl #impl_generics OperatorParams for #struct_name #ty_generics #where_clause { + fn register(&mut self, parameter_manager: &mut ParameterManager) { + #register_code + } + + fn update(&mut self, inputs: &ParamInputs) { + #(#update_code)* + } + } + }; + gen.into() +} + +fn format_name(name: &str) -> String { + let name = remove_underscores(name); + capitalize_first(&name) +} + +fn capitalize_first(s: &str) -> String { + let mut chars = s.chars(); + match chars.next() { + None => String::new(), + Some(first) => first.to_uppercase().chain(chars).collect(), + } +} + +fn remove_underscores(s: &str) -> String { + s.replace('_', "") +} diff --git a/td-rs-derive/tests/parameter_macro/pass.rs b/td-rs-derive/tests/parameter_macro/pass.rs index 2dd1967..d2f0dc3 100644 --- a/td-rs-derive/tests/parameter_macro/pass.rs +++ b/td-rs-derive/tests/parameter_macro/pass.rs @@ -1,46 +1,46 @@ -#![allow(unused)] - -use td_rs_base::*; -use td_rs_derive::*; - -#[derive(Param)] -enum TestEnum { - Hi, - Hello, - Goodbye, -} - -#[derive(Params)] -struct TestParameter { - #[param(label = "Hi")] - float2: f32, - float3: f64, - int: i16, - int2: u32, - int3: i64, - hi: String, - menu: TestEnum, - // rgb: rgb::RGB, -} - -fn main() { - let mut param = TestParameter { - // Initialize fields - float2: 0.0, - float3: 0.0, - int: 0, - int2: 0, - int3: 0, - hi: "".to_string(), - menu: TestEnum::Hi, - }; - - assert_eq!( - TestEnum::names(), - [ - String::from("Hi"), - String::from("Hello"), - String::from("Goodbye") - ] - ); -} +#![allow(unused)] + +use td_rs_base::*; +use td_rs_derive::*; + +#[derive(Param)] +enum TestEnum { + Hi, + Hello, + Goodbye, +} + +#[derive(Params)] +struct TestParameter { + #[param(label = "Hi")] + float2: f32, + float3: f64, + int: i16, + int2: u32, + int3: i64, + hi: String, + menu: TestEnum, + // rgb: rgb::RGB, +} + +fn main() { + let mut param = TestParameter { + // Initialize fields + float2: 0.0, + float3: 0.0, + int: 0, + int2: 0, + int3: 0, + hi: "".to_string(), + menu: TestEnum::Hi, + }; + + assert_eq!( + TestEnum::names(), + [ + String::from("Hi"), + String::from("Hello"), + String::from("Goodbye") + ] + ); +} diff --git a/td-rs-derive/tests/parameter_macro_test.rs b/td-rs-derive/tests/parameter_macro_test.rs index c97e843..5c8c0de 100644 --- a/td-rs-derive/tests/parameter_macro_test.rs +++ b/td-rs-derive/tests/parameter_macro_test.rs @@ -1,12 +1,12 @@ -use trybuild::TestCases; - -#[test] -fn parameter_macro_tests() { - let t = TestCases::new(); - - // Test case for successful expansion - t.pass("tests/parameter_macro/pass.rs"); - - // Test case for expected error - // t.compile_fail("tests/parameter_macro/fail.rs"); -} +use trybuild::TestCases; + +#[test] +fn parameter_macro_tests() { + let t = TestCases::new(); + + // Test case for successful expansion + t.pass("tests/parameter_macro/pass.rs"); + + // Test case for expected error + // t.compile_fail("tests/parameter_macro/fail.rs"); +} diff --git a/td-rs-sop/Cargo.toml b/td-rs-sop/Cargo.toml index 8f90fb8..5bf0c47 100644 --- a/td-rs-sop/Cargo.toml +++ b/td-rs-sop/Cargo.toml @@ -1,28 +1,28 @@ -[package] -name = "td-rs-sop" -version = "0.1.0" -edition = "2021" - -[lib] -name = "td_rs_sop" -crate-type = ["lib", "staticlib"] - -[dependencies] -autocxx = { git = "https://github.com/tychedelia/autocxx.git" } -cxx = "1.0.78" -td-rs-base = { path = "../td-rs-base" } -ref-cast = "1.0" -tracing-base = { package = "tracing", version = "0.1", optional = true } -tracing-subscriber = { version = "0.2", optional = true } -pyo3 = { git = "https://github.com/tychedelia/pyo3", branch = "td-rs", features = ["abi3-py311"], optional = true } - -[build-dependencies] -td-rs-autocxx-build = { path = "../td-rs-autocxx-build" } -autocxx-build = { git = "https://github.com/tychedelia/autocxx.git" } -miette = { version="5", features = [ "fancy" ] } - -[features] -default = [] -python = ["td-rs-base/python", "dep:pyo3"] -tracing = ["td-rs-base/tracing", "tracing-base", "tracing-subscriber"] -tokio = ["td-rs-base/tokio"] +[package] +name = "td-rs-sop" +version = "0.1.0" +edition = "2021" + +[lib] +name = "td_rs_sop" +crate-type = ["lib", "staticlib"] + +[dependencies] +autocxx = { git = "https://github.com/tychedelia/autocxx.git" } +cxx = "1.0.78" +td-rs-base = { path = "../td-rs-base" } +ref-cast = "1.0" +tracing-base = { package = "tracing", version = "0.1", optional = true } +tracing-subscriber = { version = "0.2", optional = true } +pyo3 = { git = "https://github.com/tychedelia/pyo3", branch = "td-rs", features = ["abi3-py311"], optional = true } + +[build-dependencies] +td-rs-autocxx-build = { path = "../td-rs-autocxx-build" } +autocxx-build = { git = "https://github.com/tychedelia/autocxx.git" } +miette = { version="5", features = [ "fancy" ] } + +[features] +default = [] +python = ["td-rs-base/python", "dep:pyo3"] +tracing = ["td-rs-base/tracing", "tracing-base", "tracing-subscriber"] +tokio = ["td-rs-base/tokio"] diff --git a/td-rs-sop/build.rs b/td-rs-sop/build.rs index fd012f8..59f7f8a 100644 --- a/td-rs-sop/build.rs +++ b/td-rs-sop/build.rs @@ -1,3 +1,3 @@ -fn main() -> miette::Result<()> { - td_rs_autocxx_build::build("td-rs-sop", true) -} +fn main() -> miette::Result<()> { + td_rs_autocxx_build::build("td-rs-sop", true) +} diff --git a/td-rs-sop/src/RustSopPlugin.cpp b/td-rs-sop/src/RustSopPlugin.cpp index fc53032..0e0a19b 100644 --- a/td-rs-sop/src/RustSopPlugin.cpp +++ b/td-rs-sop/src/RustSopPlugin.cpp @@ -1,33 +1,33 @@ -#include "CPlusPlus_Common.h" -#include "RustSopPlugin.h" -#include -#ifdef PYTHON_ENABLED -#include -#endif - -extern "C" { - -RustSopPlugin *sop_new(const OP_NodeInfo &info); -void sop_get_plugin_info_impl(OP_CustomOPInfo &opInfo); - -DLLEXPORT -void FillSOPPluginInfo(SOP_PluginInfo *info) { - info->apiVersion = SOPCPlusPlusAPIVersion; - auto opInfo = &info->customOPInfo; - sop_get_plugin_info_impl(*opInfo); -#ifdef PYTHON_ENABLED - opInfo->pythonVersion->setString(PY_VERSION); -#endif -} - -DLLEXPORT -SOP_CPlusPlusBase *CreateSOPInstance(const OP_NodeInfo *info) { - return sop_new(*info); -} - -DLLEXPORT -void DestroySOPInstance(SOP_CPlusPlusBase *instance) { - delete (RustSopPlugin *) instance; -} - +#include "CPlusPlus_Common.h" +#include "RustSopPlugin.h" +#include +#ifdef PYTHON_ENABLED +#include +#endif + +extern "C" { + +RustSopPlugin *sop_new(const OP_NodeInfo &info); +void sop_get_plugin_info_impl(OP_CustomOPInfo &opInfo); + +DLLEXPORT +void FillSOPPluginInfo(SOP_PluginInfo *info) { + info->apiVersion = SOPCPlusPlusAPIVersion; + auto opInfo = &info->customOPInfo; + sop_get_plugin_info_impl(*opInfo); +#ifdef PYTHON_ENABLED + opInfo->pythonVersion->setString(PY_VERSION); +#endif +} + +DLLEXPORT +SOP_CPlusPlusBase *CreateSOPInstance(const OP_NodeInfo *info) { + return sop_new(*info); +} + +DLLEXPORT +void DestroySOPInstance(SOP_CPlusPlusBase *instance) { + delete (RustSopPlugin *) instance; +} + } \ No newline at end of file diff --git a/td-rs-sop/src/RustSopPlugin.h b/td-rs-sop/src/RustSopPlugin.h index 650e80d..bde956e 100644 --- a/td-rs-sop/src/RustSopPlugin.h +++ b/td-rs-sop/src/RustSopPlugin.h @@ -1,151 +1,151 @@ -#include -#include "SOP_CPlusPlusBase.h" -#include "CPlusPlus_Common.h" -#include - -#ifndef TD_RS_RUSTSOP_H -#define TD_RS_RUSTSOP_H - -using namespace TD; - -class SopPlugin : public SOP_CPlusPlusBase { -public: - virtual ~SopPlugin() {}; - - void getGeneralInfo(SOP_GeneralInfo *info, const OP_Inputs *inputs, void *reserved1) override { - this->getGeneralInfo(*info, *inputs); - } - - virtual void getGeneralInfo(SOP_GeneralInfo &info, const OP_Inputs &inputs) {} - - - void execute(SOP_Output *outputs, const OP_Inputs *inputs, void *reserved1) override { - this->execute(*outputs, *inputs); - } - - virtual void execute(SOP_Output &outputs, const OP_Inputs &inputs) {} - - void executeVBO(SOP_VBOOutput *output, const OP_Inputs *inputs, void *reserved1) override { - if (output == nullptr) { - return; - } - this->executeVBO(*output, *inputs); - }; - - virtual void executeVBO(SOP_VBOOutput &output, const OP_Inputs &inputs) {} - - - int32_t getNumInfoCHOPChans(void *reserved1) override { - return this->getNumInfoCHOPChans(); - } - - virtual int32_t getNumInfoCHOPChans() { - return 0; - } - - void getInfoCHOPChan(int32_t index, OP_InfoCHOPChan *chan, void *reserved1) override { - OP_String *name = chan->name; - float v = 0.f; - float *value = &v; - this->getInfoCHOPChan(index, *name, *value); - chan->name = name; - chan->value = *value; - } - - virtual void getInfoCHOPChan(int32_t index, OP_String &name, float &value) {} - - bool getInfoDATSize(OP_InfoDATSize *infoSize, void *reserved1) override { - return this->getInfoDATSize(*infoSize); - } - - virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) { - return false; - } - - void getInfoDATEntries(int32_t index, int32_t nEntries, OP_InfoDATEntries *entries, void *reserved1) override { - for (int i = 0; i < nEntries; i++) { - auto entry = entries->values[i]; - this->getInfoDATEntry(index, i, *entry); - } - } - - virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, OP_String &entry) {} - - void getWarningString(OP_String *warning, void *reserved1) override { - this->getWarningString(*warning); - }; - - virtual void getWarningString(OP_String &warning) {} - - void getErrorString(OP_String *error, void *reserved1) override { - this->getErrorString(*error); - }; - - virtual void getErrorString(OP_String &error) {} - - void getInfoPopupString(OP_String *popup, void *reserved1) override { - this->getInfoPopupString(*popup); - }; - - virtual void getInfoPopupString(OP_String &popup) {} - - void setupParameters(OP_ParameterManager *manager, void *reserved1) override { - this->setupParameters(*manager); - }; - - virtual void setupParameters(OP_ParameterManager &manager) {} - - void pulsePressed(const char *name, void *reserved1) override { - this->pulsePressed(name); - }; - - virtual void pulsePressed(const char *name) {} - - virtual void buildDynamicMenu(const OP_Inputs *inputs, - OP_BuildDynamicMenuInfo *info, - void *reserved1) { - this->buildDynamicMenu(*inputs, *info); - } - - virtual void buildDynamicMenu(const OP_Inputs &inputs, - OP_BuildDynamicMenuInfo &info) {} -}; - -class RustSopPlugin : public SopPlugin { -public: - virtual ~RustSopPlugin() {}; - - virtual void* inner() const = 0; - - virtual void* innerMut() = 0; - - virtual void getGeneralInfo(SOP_GeneralInfo &info, const OP_Inputs &inputs) = 0; - - virtual void execute(SOP_Output &outputs, const OP_Inputs &inputs) = 0; - - virtual void executeVBO(SOP_VBOOutput &output, const OP_Inputs &inputs) = 0; - - virtual int32_t getNumInfoCHOPChans() = 0; - - virtual void getInfoCHOPChan(int32_t index, OP_String &name, float &value) = 0; - - virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) = 0; - - virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, OP_String &entry) = 0; - - virtual void getWarningString(OP_String &warning) = 0; - - virtual void getErrorString(OP_String &error) = 0; - - virtual void getInfoPopupString(OP_String &popup) = 0; - - virtual void setupParameters(OP_ParameterManager &manager) = 0; - - virtual void pulsePressed(const char *name) = 0; - - virtual void buildDynamicMenu(const OP_Inputs &inputs, - OP_BuildDynamicMenuInfo &info) = 0; - -}; - -#endif //TD_RS_RUSTSOP_H +#include +#include "SOP_CPlusPlusBase.h" +#include "CPlusPlus_Common.h" +#include + +#ifndef TD_RS_RUSTSOP_H +#define TD_RS_RUSTSOP_H + +using namespace TD; + +class SopPlugin : public SOP_CPlusPlusBase { +public: + virtual ~SopPlugin() {}; + + void getGeneralInfo(SOP_GeneralInfo *info, const OP_Inputs *inputs, void *reserved1) override { + this->getGeneralInfo(*info, *inputs); + } + + virtual void getGeneralInfo(SOP_GeneralInfo &info, const OP_Inputs &inputs) {} + + + void execute(SOP_Output *outputs, const OP_Inputs *inputs, void *reserved1) override { + this->execute(*outputs, *inputs); + } + + virtual void execute(SOP_Output &outputs, const OP_Inputs &inputs) {} + + void executeVBO(SOP_VBOOutput *output, const OP_Inputs *inputs, void *reserved1) override { + if (output == nullptr) { + return; + } + this->executeVBO(*output, *inputs); + }; + + virtual void executeVBO(SOP_VBOOutput &output, const OP_Inputs &inputs) {} + + + int32_t getNumInfoCHOPChans(void *reserved1) override { + return this->getNumInfoCHOPChans(); + } + + virtual int32_t getNumInfoCHOPChans() { + return 0; + } + + void getInfoCHOPChan(int32_t index, OP_InfoCHOPChan *chan, void *reserved1) override { + OP_String *name = chan->name; + float v = 0.f; + float *value = &v; + this->getInfoCHOPChan(index, *name, *value); + chan->name = name; + chan->value = *value; + } + + virtual void getInfoCHOPChan(int32_t index, OP_String &name, float &value) {} + + bool getInfoDATSize(OP_InfoDATSize *infoSize, void *reserved1) override { + return this->getInfoDATSize(*infoSize); + } + + virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) { + return false; + } + + void getInfoDATEntries(int32_t index, int32_t nEntries, OP_InfoDATEntries *entries, void *reserved1) override { + for (int i = 0; i < nEntries; i++) { + auto entry = entries->values[i]; + this->getInfoDATEntry(index, i, *entry); + } + } + + virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, OP_String &entry) {} + + void getWarningString(OP_String *warning, void *reserved1) override { + this->getWarningString(*warning); + }; + + virtual void getWarningString(OP_String &warning) {} + + void getErrorString(OP_String *error, void *reserved1) override { + this->getErrorString(*error); + }; + + virtual void getErrorString(OP_String &error) {} + + void getInfoPopupString(OP_String *popup, void *reserved1) override { + this->getInfoPopupString(*popup); + }; + + virtual void getInfoPopupString(OP_String &popup) {} + + void setupParameters(OP_ParameterManager *manager, void *reserved1) override { + this->setupParameters(*manager); + }; + + virtual void setupParameters(OP_ParameterManager &manager) {} + + void pulsePressed(const char *name, void *reserved1) override { + this->pulsePressed(name); + }; + + virtual void pulsePressed(const char *name) {} + + virtual void buildDynamicMenu(const OP_Inputs *inputs, + OP_BuildDynamicMenuInfo *info, + void *reserved1) { + this->buildDynamicMenu(*inputs, *info); + } + + virtual void buildDynamicMenu(const OP_Inputs &inputs, + OP_BuildDynamicMenuInfo &info) {} +}; + +class RustSopPlugin : public SopPlugin { +public: + virtual ~RustSopPlugin() {}; + + virtual void* inner() const = 0; + + virtual void* innerMut() = 0; + + virtual void getGeneralInfo(SOP_GeneralInfo &info, const OP_Inputs &inputs) = 0; + + virtual void execute(SOP_Output &outputs, const OP_Inputs &inputs) = 0; + + virtual void executeVBO(SOP_VBOOutput &output, const OP_Inputs &inputs) = 0; + + virtual int32_t getNumInfoCHOPChans() = 0; + + virtual void getInfoCHOPChan(int32_t index, OP_String &name, float &value) = 0; + + virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) = 0; + + virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, OP_String &entry) = 0; + + virtual void getWarningString(OP_String &warning) = 0; + + virtual void getErrorString(OP_String &error) = 0; + + virtual void getInfoPopupString(OP_String &popup) = 0; + + virtual void setupParameters(OP_ParameterManager &manager) = 0; + + virtual void pulsePressed(const char *name) = 0; + + virtual void buildDynamicMenu(const OP_Inputs &inputs, + OP_BuildDynamicMenuInfo &info) = 0; + +}; + +#endif //TD_RS_RUSTSOP_H diff --git a/td-rs-sop/src/cxx.rs b/td-rs-sop/src/cxx.rs index 91a8d41..1d9271f 100644 --- a/td-rs-sop/src/cxx.rs +++ b/td-rs-sop/src/cxx.rs @@ -1,232 +1,232 @@ -#![allow(non_snake_case)] -#![allow(ambiguous_glob_reexports)] - -use crate::{Sop, SopOutput, SopVboOutput, Unalloc}; -use autocxx::prelude::*; -use autocxx::subclass::*; - -use std::ffi::CString; - -use std::pin::Pin; -use td_rs_base::{param::ParameterManager, DynamicMenuInfo, NodeInfo, OperatorInputs}; - -include_cpp! { - #include "SOP_CPlusPlusBase.h" - #include "RustSopPlugin.h" - safety!(unsafe) - extern_cpp_type!("TD::OP_ParameterManager", td_rs_base::cxx::OP_ParameterManager) - extern_cpp_type!("TD::OP_String", td_rs_base::cxx::OP_String) - extern_cpp_type!("TD::OP_InfoDATSize", td_rs_base::cxx::OP_InfoDATSize) - extern_cpp_type!("TD::OP_InfoCHOPChan", td_rs_base::cxx::OP_InfoCHOPChan) - extern_cpp_type!("TD::OP_Inputs", td_rs_base::cxx::OP_Inputs) - generate_pod!("TD::SOP_GeneralInfo") - generate_pod!("TD::SOP_PluginInfo") - generate!("TD::SOP_Output") - generate!("TD::SOP_VBOOutput") - extern_cpp_type!("TD::Vector", td_rs_base::cxx::Vector) - extern_cpp_type!("TD::Position", td_rs_base::cxx::Position) - extern_cpp_type!("TD::Color", td_rs_base::cxx::Color) - extern_cpp_type!("TD::TexCoord", td_rs_base::cxx::TexCoord) - extern_cpp_type!("TD::BoundingBox", td_rs_base::cxx::BoundingBox) - extern_cpp_type!("TD::SOP_CustomAttribData", td_rs_base::cxx::SOP_CustomAttribData) - extern_cpp_type!("TD::SOP_CustomAttribInfo", td_rs_base::cxx::SOP_CustomAttribInfo) - extern_cpp_type!("TD::OP_CustomOPInfo", td_rs_base::cxx::OP_CustomOPInfo) - extern_cpp_type!("TD::OP_BuildDynamicMenuInfo", td_rs_base::cxx::OP_BuildDynamicMenuInfo) - pod!("TD::OP_CustomOPInfo") - generate_pod!("TD::SOP_GroupType") - generate_pod!("TD::SOP_Winding") -} - -pub use autocxx::c_void; -pub use ffi::TD::*; -pub use ffi::*; -pub use td_rs_base::cxx::*; - -extern "C" { - // SAFETY: `sop_new_impl` is only ever called from Rust compiled - // at the same time as the plugin, so the types are guaranteed to - // match - #[allow(improper_ctypes)] - fn sop_new_impl(info: NodeInfo) -> Box; -} - -#[subclass(superclass("RustSopPlugin"))] -pub struct RustSopPluginImpl { - inner: Box, -} - -// SAFETY: This can only be used with pointers returned from getNodeInstance() and -// should not be used in plugin code. -pub unsafe fn plugin_cast(plugin: *mut c_void) -> &'static mut RustSopPluginImplCpp { - &mut *(plugin as *mut RustSopPluginImplCpp) -} - -impl AsPlugin for RustSopPluginImplCpp { - type Plugin = RustSopPlugin; - - fn as_plugin(&self) -> &Self::Plugin { - self.As_RustSopPlugin() - } - - fn as_plugin_mut(&mut self) -> Pin<&mut Self::Plugin> { - // Safety: self can't be moved during the lifetime of 'cook. - unsafe { Pin::new_unchecked(self).As_RustSopPlugin_mut() } - } -} - -#[no_mangle] -extern "C" fn sop_new(info: &'static OP_NodeInfo) -> *mut RustSopPluginImplCpp { - unsafe { - let info = NodeInfo::new(info); - RustSopPluginImpl::new_cpp_owned(RustSopPluginImpl { - inner: sop_new_impl(info), - cpp_peer: CppSubclassCppPeerHolder::Empty, - }) - .into_raw() - } -} - -impl RustSopPlugin_methods for RustSopPluginImpl { - fn inner(&self) -> *mut c_void { - self.inner.as_ref() as *const dyn Sop as *mut c_void - } - - fn innerMut(&mut self) -> *mut c_void { - self.inner.as_mut() as *mut dyn Sop as *mut c_void - } - - fn getGeneralInfo(&mut self, mut info: Pin<&mut SOP_GeneralInfo>, inputs: &OP_Inputs) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getGeneralInfo").entered() }; - let input = OperatorInputs::new(inputs); - if let Some(params) = self.inner.params_mut() { - params.update(&input.params()); - } - let gen_info = self.inner.general_info(&input); - info.cookEveryFrame = gen_info.cook_every_frame; - info.cookEveryFrameIfAsked = gen_info.cook_every_frame_if_asked; - info.directToGPU = gen_info.direct_to_gpu; - info.winding = SOP_Winding::CCW; - } - - fn execute(&mut self, outputs: Pin<&mut SOP_Output>, inputs: &OP_Inputs) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("execute").entered() }; - let input = OperatorInputs::new(inputs); - let mut output = SopOutput::new(outputs); - if let Some(params) = self.inner.params_mut() { - params.update(&input.params()); - } - self.inner.execute(&mut output, &input); - } - - fn executeVBO(&mut self, output: Pin<&mut SOP_VBOOutput>, inputs: &OP_Inputs) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("executeVBO").entered() }; - let input = OperatorInputs::new(inputs); - let output = SopVboOutput::::new(output); - self.inner.execute_vbo(output, &input); - } - - fn getNumInfoCHOPChans(&mut self) -> i32 { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getNumInfoCHOPChans").entered() }; - if let Some(info_chop) = self.inner.info_chop() { - info_chop.size() as i32 - } else { - 0 - } - } - - fn getInfoCHOPChan(&mut self, index: i32, name: Pin<&mut OP_String>, mut value: Pin<&mut f32>) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getInfoCHOPChan").entered() }; - if let Some(info_chop) = self.inner.info_chop() { - let (info_name, info_value) = info_chop.channel(index as usize); - unsafe { - let new_string = CString::new(info_name.as_str()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - name.setString(new_string_ptr); - } - value.set(info_value); - } - } - - fn getInfoDATSize(&mut self, mut info: Pin<&mut OP_InfoDATSize>) -> bool { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getInfoDATSize").entered() }; - if let Some(info_dat) = self.inner.info_dat() { - let (rows, cols) = info_dat.size(); - info.rows = rows as i32; - info.cols = cols as i32; - true - } else { - false - } - } - - fn getInfoDATEntry(&mut self, index: i32, entryIndex: i32, entry: Pin<&mut OP_String>) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("getInfoDATEntry").entered() }; - if let Some(info_dat) = self.inner.info_dat() { - let entry_str = info_dat.entry(index as usize, entryIndex as usize); - if entry_str.is_empty() { - return; - } - unsafe { - let new_string = CString::new(entry_str.as_str()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - entry.setString(new_string_ptr); - } - } - } - - fn getWarningString(&mut self, warning: Pin<&mut OP_String>) { - unsafe { - let new_string = CString::new(self.inner.warning()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - warning.setString(new_string_ptr); - } - } - - fn getErrorString(&mut self, error: Pin<&mut OP_String>) { - unsafe { - let new_string = CString::new(self.inner.error()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - error.setString(new_string_ptr); - } - } - - fn getInfoPopupString(&mut self, info: Pin<&mut OP_String>) { - unsafe { - let new_string = CString::new(self.inner.info()).unwrap(); - let new_string_ptr = new_string.as_ptr(); - info.setString(new_string_ptr); - } - } - - fn setupParameters(&mut self, manager: Pin<&mut OP_ParameterManager>) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("setupParameters").entered() }; - let params = self.inner.params_mut(); - if let Some(params) = params { - let mut manager = ParameterManager::new(manager); - params.register(&mut manager); - } - } - - unsafe fn pulsePressed(&mut self, name: *const std::ffi::c_char) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("pulsePressed").entered() }; - self.inner - .pulse_pressed(std::ffi::CStr::from_ptr(name).to_str().unwrap()); - } - - fn buildDynamicMenu(&mut self, inputs: &OP_Inputs, info: Pin<&mut OP_BuildDynamicMenuInfo>) { - #[cfg(feature = "tracing")] - let _span = { tracing_base::trace_span!("buildDynamicMenu").entered() }; - let input = OperatorInputs::new(inputs); - let mut info = DynamicMenuInfo::new(info); - self.inner.build_dynamic_menu(&input, &mut info); - } -} +#![allow(non_snake_case)] +#![allow(ambiguous_glob_reexports)] + +use crate::{Sop, SopOutput, SopVboOutput, Unalloc}; +use autocxx::prelude::*; +use autocxx::subclass::*; + +use std::ffi::CString; + +use std::pin::Pin; +use td_rs_base::{param::ParameterManager, DynamicMenuInfo, NodeInfo, OperatorInputs}; + +include_cpp! { + #include "SOP_CPlusPlusBase.h" + #include "RustSopPlugin.h" + safety!(unsafe) + extern_cpp_type!("TD::OP_ParameterManager", td_rs_base::cxx::OP_ParameterManager) + extern_cpp_type!("TD::OP_String", td_rs_base::cxx::OP_String) + extern_cpp_type!("TD::OP_InfoDATSize", td_rs_base::cxx::OP_InfoDATSize) + extern_cpp_type!("TD::OP_InfoCHOPChan", td_rs_base::cxx::OP_InfoCHOPChan) + extern_cpp_type!("TD::OP_Inputs", td_rs_base::cxx::OP_Inputs) + generate_pod!("TD::SOP_GeneralInfo") + generate_pod!("TD::SOP_PluginInfo") + generate!("TD::SOP_Output") + generate!("TD::SOP_VBOOutput") + extern_cpp_type!("TD::Vector", td_rs_base::cxx::Vector) + extern_cpp_type!("TD::Position", td_rs_base::cxx::Position) + extern_cpp_type!("TD::Color", td_rs_base::cxx::Color) + extern_cpp_type!("TD::TexCoord", td_rs_base::cxx::TexCoord) + extern_cpp_type!("TD::BoundingBox", td_rs_base::cxx::BoundingBox) + extern_cpp_type!("TD::SOP_CustomAttribData", td_rs_base::cxx::SOP_CustomAttribData) + extern_cpp_type!("TD::SOP_CustomAttribInfo", td_rs_base::cxx::SOP_CustomAttribInfo) + extern_cpp_type!("TD::OP_CustomOPInfo", td_rs_base::cxx::OP_CustomOPInfo) + extern_cpp_type!("TD::OP_BuildDynamicMenuInfo", td_rs_base::cxx::OP_BuildDynamicMenuInfo) + pod!("TD::OP_CustomOPInfo") + generate_pod!("TD::SOP_GroupType") + generate_pod!("TD::SOP_Winding") +} + +pub use autocxx::c_void; +pub use ffi::TD::*; +pub use ffi::*; +pub use td_rs_base::cxx::*; + +extern "C" { + // SAFETY: `sop_new_impl` is only ever called from Rust compiled + // at the same time as the plugin, so the types are guaranteed to + // match + #[allow(improper_ctypes)] + fn sop_new_impl(info: NodeInfo) -> Box; +} + +#[subclass(superclass("RustSopPlugin"))] +pub struct RustSopPluginImpl { + inner: Box, +} + +// SAFETY: This can only be used with pointers returned from getNodeInstance() and +// should not be used in plugin code. +pub unsafe fn plugin_cast(plugin: *mut c_void) -> &'static mut RustSopPluginImplCpp { + &mut *(plugin as *mut RustSopPluginImplCpp) +} + +impl AsPlugin for RustSopPluginImplCpp { + type Plugin = RustSopPlugin; + + fn as_plugin(&self) -> &Self::Plugin { + self.As_RustSopPlugin() + } + + fn as_plugin_mut(&mut self) -> Pin<&mut Self::Plugin> { + // Safety: self can't be moved during the lifetime of 'cook. + unsafe { Pin::new_unchecked(self).As_RustSopPlugin_mut() } + } +} + +#[no_mangle] +extern "C" fn sop_new(info: &'static OP_NodeInfo) -> *mut RustSopPluginImplCpp { + unsafe { + let info = NodeInfo::new(info); + RustSopPluginImpl::new_cpp_owned(RustSopPluginImpl { + inner: sop_new_impl(info), + cpp_peer: CppSubclassCppPeerHolder::Empty, + }) + .into_raw() + } +} + +impl RustSopPlugin_methods for RustSopPluginImpl { + fn inner(&self) -> *mut c_void { + self.inner.as_ref() as *const dyn Sop as *mut c_void + } + + fn innerMut(&mut self) -> *mut c_void { + self.inner.as_mut() as *mut dyn Sop as *mut c_void + } + + fn getGeneralInfo(&mut self, mut info: Pin<&mut SOP_GeneralInfo>, inputs: &OP_Inputs) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getGeneralInfo").entered() }; + let input = OperatorInputs::new(inputs); + if let Some(params) = self.inner.params_mut() { + params.update(&input.params()); + } + let gen_info = self.inner.general_info(&input); + info.cookEveryFrame = gen_info.cook_every_frame; + info.cookEveryFrameIfAsked = gen_info.cook_every_frame_if_asked; + info.directToGPU = gen_info.direct_to_gpu; + info.winding = SOP_Winding::CCW; + } + + fn execute(&mut self, outputs: Pin<&mut SOP_Output>, inputs: &OP_Inputs) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("execute").entered() }; + let input = OperatorInputs::new(inputs); + let mut output = SopOutput::new(outputs); + if let Some(params) = self.inner.params_mut() { + params.update(&input.params()); + } + self.inner.execute(&mut output, &input); + } + + fn executeVBO(&mut self, output: Pin<&mut SOP_VBOOutput>, inputs: &OP_Inputs) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("executeVBO").entered() }; + let input = OperatorInputs::new(inputs); + let output = SopVboOutput::::new(output); + self.inner.execute_vbo(output, &input); + } + + fn getNumInfoCHOPChans(&mut self) -> i32 { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getNumInfoCHOPChans").entered() }; + if let Some(info_chop) = self.inner.info_chop() { + info_chop.size() as i32 + } else { + 0 + } + } + + fn getInfoCHOPChan(&mut self, index: i32, name: Pin<&mut OP_String>, mut value: Pin<&mut f32>) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getInfoCHOPChan").entered() }; + if let Some(info_chop) = self.inner.info_chop() { + let (info_name, info_value) = info_chop.channel(index as usize); + unsafe { + let new_string = CString::new(info_name.as_str()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + name.setString(new_string_ptr); + } + value.set(info_value); + } + } + + fn getInfoDATSize(&mut self, mut info: Pin<&mut OP_InfoDATSize>) -> bool { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getInfoDATSize").entered() }; + if let Some(info_dat) = self.inner.info_dat() { + let (rows, cols) = info_dat.size(); + info.rows = rows as i32; + info.cols = cols as i32; + true + } else { + false + } + } + + fn getInfoDATEntry(&mut self, index: i32, entryIndex: i32, entry: Pin<&mut OP_String>) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("getInfoDATEntry").entered() }; + if let Some(info_dat) = self.inner.info_dat() { + let entry_str = info_dat.entry(index as usize, entryIndex as usize); + if entry_str.is_empty() { + return; + } + unsafe { + let new_string = CString::new(entry_str.as_str()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + entry.setString(new_string_ptr); + } + } + } + + fn getWarningString(&mut self, warning: Pin<&mut OP_String>) { + unsafe { + let new_string = CString::new(self.inner.warning()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + warning.setString(new_string_ptr); + } + } + + fn getErrorString(&mut self, error: Pin<&mut OP_String>) { + unsafe { + let new_string = CString::new(self.inner.error()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + error.setString(new_string_ptr); + } + } + + fn getInfoPopupString(&mut self, info: Pin<&mut OP_String>) { + unsafe { + let new_string = CString::new(self.inner.info()).unwrap(); + let new_string_ptr = new_string.as_ptr(); + info.setString(new_string_ptr); + } + } + + fn setupParameters(&mut self, manager: Pin<&mut OP_ParameterManager>) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("setupParameters").entered() }; + let params = self.inner.params_mut(); + if let Some(params) = params { + let mut manager = ParameterManager::new(manager); + params.register(&mut manager); + } + } + + unsafe fn pulsePressed(&mut self, name: *const std::ffi::c_char) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("pulsePressed").entered() }; + self.inner + .pulse_pressed(std::ffi::CStr::from_ptr(name).to_str().unwrap()); + } + + fn buildDynamicMenu(&mut self, inputs: &OP_Inputs, info: Pin<&mut OP_BuildDynamicMenuInfo>) { + #[cfg(feature = "tracing")] + let _span = { tracing_base::trace_span!("buildDynamicMenu").entered() }; + let input = OperatorInputs::new(inputs); + let mut info = DynamicMenuInfo::new(info); + self.inner.build_dynamic_menu(&input, &mut info); + } +} diff --git a/td-rs-sop/src/lib.rs b/td-rs-sop/src/lib.rs index c1a8fb2..56cea81 100644 --- a/td-rs-sop/src/lib.rs +++ b/td-rs-sop/src/lib.rs @@ -1,719 +1,719 @@ -use crate::cxx::{SOP_CustomAttribData, VBOBufferMode, Vector}; - -use std::pin::Pin; - -use td_rs_base::chop::ChopInput; -pub use td_rs_base::sop::*; -pub use td_rs_base::*; - -pub mod cxx; -pub mod prelude; - -#[derive(Debug, Default)] -pub struct SopGeneralInfo { - pub cook_every_frame: bool, - pub cook_every_frame_if_asked: bool, - pub direct_to_gpu: bool, -} - -pub struct SopOutput<'cook> { - output: Pin<&'cook mut cxx::SOP_Output>, -} - -impl<'cook> SopOutput<'cook> { - /// Create a new `SopOutput` from a pinning reference to a - /// `SopOutput`. - pub fn new(output: Pin<&'cook mut cxx::SOP_Output>) -> SopOutput<'cook> { - Self { output } - } - - pub fn add_point(&mut self, pos: impl Into) -> usize { - self.output.as_mut().addPoint(&pos.into()) as usize - } - - pub fn add_points(&mut self, positions: &[Position]) { - unsafe { - self.output.as_mut().addPoints( - positions.as_ptr() as *const cxx::Position, - positions.len() as i32, - ); - } - } - - pub fn num_points(&mut self) -> usize { - self.output.as_mut().getNumPoints() as usize - } - - pub fn set_normal(&mut self, normal: impl Into, start_idx: usize) { - self.output - .as_mut() - .setNormal(normal.into().as_ref(), start_idx as i32); - } - - pub fn set_normals(&mut self, normals: &[Vec3], start_idx: usize) { - unsafe { - self.output.as_mut().setNormals( - normals.as_ptr() as *const Vector, - normals.len() as i32, - start_idx as i32, - ); - } - } - - pub fn has_normals(&mut self) -> bool { - self.output.as_mut().hasNormal() - } - - pub fn set_color(&mut self, color: impl Into, start_idx: usize) { - unsafe { - self.output.as_mut().setColor( - &*(color.into().as_ref() as *const cxx::Color), - start_idx as i32, - ); - } - } - - pub fn set_colors(&mut self, colors: &[Color], start_idx: usize) { - unsafe { - self.output.as_mut().setColors( - colors.as_ptr() as *const cxx::Color, - colors.len() as i32, - start_idx as i32, - ); - } - } - - pub fn has_color(&mut self) -> bool { - self.output.as_mut().hasColor() - } - - pub fn set_tex_coord( - &mut self, - texture: impl Into, - num_layers: usize, - start_idx: usize, - ) { - unsafe { - self.output.as_mut().setTexCoord( - &*(texture.into().as_ref() as *const cxx::TexCoord), - num_layers as i32, - start_idx as i32, - ); - } - } - - pub fn set_tex_coord2(&mut self, texture: &TexCoord, num_layers: usize, start_idx: usize) { - unsafe { - self.output.as_mut().setTexCoord( - texture.as_ref() as *const cxx::TexCoord, - num_layers as i32, - start_idx as i32, - ); - } - } - - pub fn set_tex_coords(&mut self, textures: &[TexCoord], num_layers: usize, start_idx: usize) { - unsafe { - let textures = textures - .iter() - .map(|t| cxx::TexCoord { - u: t.u, - v: t.v, - w: t.w, - }) - .collect::>() - .into_boxed_slice(); - let num_points = self.num_points() as i32; - self.output.as_mut().setTexCoords( - textures.as_ptr() as *const cxx::TexCoord, - num_points, - num_layers as i32, - start_idx as i32, - ); - Box::leak(textures); - } - } - - pub fn has_tex_coord(&mut self) -> bool { - self.output.as_mut().hasTexCoord() - } - - pub fn num_tex_coord_layers(&mut self) -> usize { - self.output.as_mut().getNumTexCoordLayers() as usize - } - - pub fn set_custom_attribute( - &mut self, - info: CustomAttributeInfo, - data: CustomAttributeData, - num_pts: usize, - ) { - unsafe { - let name = std::ffi::CString::new(info.name).unwrap(); - let info = cxx::SOP_CustomAttribInfo { - name: name.as_ptr(), - numComponents: info.num_components as i32, - attribType: (&info.attr_type).into(), - }; - let attr = match data { - CustomAttributeData::Float(mut data) => cxx::SOP_CustomAttribData { - _base: info, - floatData: data.as_mut_ptr(), - intData: std::ptr::null_mut(), - }, - CustomAttributeData::Int(mut data) => cxx::SOP_CustomAttribData { - _base: info, - floatData: std::ptr::null_mut(), - intData: data.as_mut_ptr(), - }, - }; - self.output - .as_mut() - .setCustomAttribute(&attr as *const SOP_CustomAttribData, num_pts as i32); - } - } - - pub fn has_custom_attribute(&mut self) -> bool { - self.output.as_mut().hasCustomAttibutes() - } - - pub fn add_triangle(&mut self, x: u32, y: u32, z: u32) { - self.output - .as_mut() - .addTriangle(x as i32, y as i32, z as i32); - } - - pub fn add_triangles(&mut self, indices: &[u32]) { - unsafe { - self.output - .as_mut() - .addTriangles(indices.as_ptr() as *const i32, (indices.len() / 3) as i32); - } - } - - pub fn add_particle_system(&mut self, num_pts: usize, start_idx: usize) { - self.output - .as_mut() - .addParticleSystem(num_pts as i32, start_idx as i32); - } - - pub fn add_line(&mut self, indices: &[u32]) { - unsafe { - self.output - .as_mut() - .addLine(indices.as_ptr() as *const i32, indices.len() as i32); - } - } - - pub fn add_lines(&mut self, indices: &[u32], sizes: &[u32]) { - unsafe { - self.output.as_mut().addLines( - indices.as_ptr() as *const i32, - sizes.as_ptr() as *const i32 as *mut i32, - sizes.len() as i32, - ); - } - } - - pub fn num_primitives(&mut self) -> usize { - self.output.as_mut().getNumPrimitives() as usize - } - - pub fn set_bounding_box(&mut self, b: impl Into) { - self.output.as_mut().setBoundingBox(&b.into()); - } - - pub fn add_group(&mut self, type_: GroupType, name: &str) { - let name = std::ffi::CString::new(name).unwrap(); - unsafe { - self.output.as_mut().addGroup(&type_.into(), name.as_ptr()); - } - } - - pub fn destroy_group(&mut self, type_: GroupType, name: &str) { - let name = std::ffi::CString::new(name).unwrap(); - unsafe { - self.output - .as_mut() - .destroyGroup(type_.into(), name.as_ptr()); - } - } - - pub fn add_point_to_group(&mut self, point: usize, group: &str) { - let group = std::ffi::CString::new(group).unwrap(); - unsafe { - self.output - .as_mut() - .addPointToGroup(autocxx::c_int(point as std::ffi::c_int), group.as_ptr()); - } - } - - pub fn add_prim_to_group(&mut self, prim: usize, group: &str) { - let group = std::ffi::CString::new(group).unwrap(); - unsafe { - self.output - .as_mut() - .addPrimToGroup(autocxx::c_int(prim as std::ffi::c_int), group.as_ptr()); - } - } - - pub fn add_to_group(&mut self, idx: usize, type_: GroupType, group: &str) { - let group = std::ffi::CString::new(group).unwrap(); - unsafe { - self.output.as_mut().addToGroup( - autocxx::c_int(idx as std::ffi::c_int), - type_.into(), - group.as_ptr(), - ); - } - } - - pub fn discard_from_point_group(&mut self, idx: usize, name: &str) { - let name = std::ffi::CString::new(name).unwrap(); - unsafe { - self.output - .as_mut() - .discardFromPointGroup(autocxx::c_int(idx as std::ffi::c_int), name.as_ptr()); - } - } - - pub fn discard_from_prim_group(&mut self, idx: usize, name: &str) { - let name = std::ffi::CString::new(name).unwrap(); - unsafe { - self.output - .as_mut() - .discardFromPrimGroup(autocxx::c_int(idx as std::ffi::c_int), name.as_ptr()); - } - } - - pub fn discard_from_group(&mut self, idx: usize, type_: GroupType, name: &str) { - let name = std::ffi::CString::new(name).unwrap(); - unsafe { - self.output.as_mut().discardFromGroup( - autocxx::c_int(idx as std::ffi::c_int), - type_.into(), - name.as_ptr(), - ); - } - } -} - -#[derive(Debug)] -pub enum GroupType { - Point, - Primitive, -} - -impl From for &cxx::SOP_GroupType { - fn from(t: GroupType) -> Self { - match t { - GroupType::Point => &cxx::SOP_GroupType::Point, - GroupType::Primitive => &cxx::SOP_GroupType::Primitive, - } - } -} - -impl From for cxx::SOP_GroupType { - fn from(t: GroupType) -> Self { - match t { - GroupType::Point => cxx::SOP_GroupType::Point, - GroupType::Primitive => cxx::SOP_GroupType::Primitive, - } - } -} - -impl From for GroupType { - fn from(t: cxx::SOP_GroupType) -> Self { - match t { - cxx::SOP_GroupType::Point => GroupType::Point, - cxx::SOP_GroupType::Primitive => GroupType::Primitive, - } - } -} - -pub struct Unalloc; - -pub struct ColorEnabled; -pub struct NormalEnabled; -pub struct TexCoordEnabled; - -pub struct Alloc { - pub vertices: usize, - pub indices: usize, - pub buffer_mode: BufferMode, - _normal: std::marker::PhantomData, - _color: std::marker::PhantomData, - _tex_coords: std::marker::PhantomData, -} - -pub struct Complete; - -pub type AllocAll = Alloc; - -pub struct SopVboOutput<'cook, State> { - pub state: State, - output: Pin<&'cook mut cxx::SOP_VBOOutput>, -} - -impl<'cook, State> SopVboOutput<'cook, State> { - /// Create a new `SopOutput` from a pinning reference to a - /// `SopOutput`. - pub fn new(output: Pin<&'cook mut cxx::SOP_VBOOutput>) -> SopVboOutput<'cook, Unalloc> { - SopVboOutput { - state: Unalloc, - output, - } - } - - pub fn has_custom_attributes(&mut self) -> bool { - self.output.as_mut().hasCustomAttibutes() - } - - pub fn has_normal(&mut self) -> bool { - self.output.as_mut().hasNormal() - } - - pub fn has_color(&mut self) -> bool { - self.output.as_mut().hasColor() - } - - pub fn has_tex_coord(&mut self) -> bool { - self.output.as_mut().hasTexCoord() - } -} - -impl<'cook> SopVboOutput<'cook, Unalloc> { - pub fn add_custom_attribute(&mut self, attr: CustomAttributeInfo) { - let name = std::ffi::CString::new(attr.name).unwrap(); - let attr = cxx::SOP_CustomAttribInfo { - name: name.as_ptr(), - numComponents: attr.num_components as i32, - attribType: attr.attr_type.into(), - }; - self.output.as_mut().addCustomAttribute(&attr); - } - - fn alloc_inner( - &mut self, - vertices: usize, - indices: usize, - enable_normal: bool, - enable_color: bool, - tex_coords: usize, - buffer_mode: BufferMode, - ) { - if enable_color { - self.output.as_mut().enableColor(); - } - if enable_normal { - self.output.as_mut().enableNormal(); - } - if tex_coords > 0 { - assert!(tex_coords <= 8); - self.output.as_mut().enableTexCoord(tex_coords as i32); - } - - self.output - .as_mut() - .allocVBO(vertices as i32, indices as i32, buffer_mode.into()); - } - - pub fn alloc_none( - mut self, - vertices: usize, - indices: usize, - buffer_mode: BufferMode, - ) -> SopVboOutput<'cook, Alloc<(), (), ()>> { - self.alloc_inner(vertices, indices, false, false, 0, buffer_mode); - SopVboOutput { - state: Alloc { - vertices, - indices, - buffer_mode, - _color: Default::default(), - _normal: Default::default(), - _tex_coords: Default::default(), - }, - output: self.output, - } - } - - pub fn alloc_all( - mut self, - vertices: usize, - indices: usize, - tex_coords: usize, - buffer_mode: BufferMode, - ) -> SopVboOutput<'cook, Alloc> { - self.alloc_inner(vertices, indices, true, true, tex_coords, buffer_mode); - SopVboOutput { - state: Alloc { - vertices, - indices, - buffer_mode, - _color: Default::default(), - _normal: Default::default(), - _tex_coords: Default::default(), - }, - output: self.output, - } - } - - pub fn alloc_normals( - mut self, - vertices: usize, - indices: usize, - buffer_mode: BufferMode, - ) -> SopVboOutput<'cook, Alloc> { - self.alloc_inner(vertices, indices, true, false, 0, buffer_mode); - SopVboOutput { - state: Alloc { - vertices, - indices, - buffer_mode, - _color: Default::default(), - _normal: Default::default(), - _tex_coords: Default::default(), - }, - output: self.output, - } - } - - pub fn alloc_colors( - mut self, - vertices: usize, - indices: usize, - buffer_mode: BufferMode, - ) -> SopVboOutput<'cook, Alloc<(), ColorEnabled, ()>> { - self.alloc_inner(vertices, indices, false, true, 0, buffer_mode); - SopVboOutput { - state: Alloc { - vertices, - indices, - buffer_mode, - _color: Default::default(), - _normal: Default::default(), - _tex_coords: Default::default(), - }, - output: self.output, - } - } - - pub fn alloc_tex_coords( - mut self, - vertices: usize, - indices: usize, - tex_coords: usize, - buffer_mode: BufferMode, - ) -> SopVboOutput<'cook, Alloc<(), (), TexCoordEnabled>> { - self.alloc_inner(vertices, indices, false, false, tex_coords, buffer_mode); - SopVboOutput { - state: Alloc { - vertices, - indices, - buffer_mode, - _color: Default::default(), - _normal: Default::default(), - _tex_coords: Default::default(), - }, - output: self.output, - } - } - - pub fn alloc_normal_and_colors( - mut self, - vertices: usize, - indices: usize, - buffer_mode: BufferMode, - ) -> SopVboOutput<'cook, Alloc> { - self.alloc_inner(vertices, indices, true, true, 0, buffer_mode); - SopVboOutput { - state: Alloc { - vertices, - indices, - buffer_mode, - _color: Default::default(), - _normal: Default::default(), - _tex_coords: Default::default(), - }, - output: self.output, - } - } - - pub fn alloc_normal_and_tex_coords( - mut self, - vertices: usize, - indices: usize, - tex_coords: usize, - buffer_mode: BufferMode, - ) -> SopVboOutput<'cook, Alloc> { - self.alloc_inner(vertices, indices, true, false, tex_coords, buffer_mode); - SopVboOutput { - state: Alloc { - vertices, - indices, - buffer_mode, - _color: Default::default(), - _normal: Default::default(), - _tex_coords: Default::default(), - }, - output: self.output, - } - } - - pub fn alloc_colors_and_tex_coords( - mut self, - vertices: usize, - indices: usize, - tex_coords: usize, - buffer_mode: BufferMode, - ) -> SopVboOutput<'cook, Alloc<(), ColorEnabled, TexCoordEnabled>> { - self.alloc_inner(vertices, indices, false, true, tex_coords, buffer_mode); - SopVboOutput { - state: Alloc { - vertices, - indices, - buffer_mode, - _color: Default::default(), - _normal: Default::default(), - _tex_coords: Default::default(), - }, - output: self.output, - } - } -} - -impl<'cook, C, T> SopVboOutput<'cook, Alloc> { - pub fn normals(&mut self) -> &'cook mut [Vec3] { - let normals = self.output.as_mut().getNormals(); - if normals.is_null() { - panic!("normals is null") - } - unsafe { std::slice::from_raw_parts_mut(normals as *mut Vec3, self.state.vertices) } - } -} - -impl<'cook, N, T> SopVboOutput<'cook, Alloc> { - pub fn colors(&mut self) -> &'cook mut [Color] { - let colors = self.output.as_mut().getColors(); - if colors.is_null() { - panic!("colors is null") - } - unsafe { std::slice::from_raw_parts_mut(colors as *mut Color, self.state.vertices) } - } -} - -impl<'cook, N, C> SopVboOutput<'cook, Alloc> { - pub fn tex_coords(&mut self) -> &'cook mut [TexCoord] { - let tex_coords = self.output.as_mut().getTexCoords(); - if tex_coords.is_null() { - println!("tex_coords is null") - } - unsafe { std::slice::from_raw_parts_mut(tex_coords as *mut TexCoord, self.state.vertices) } - } - pub fn get_num_text_coord_layers(&mut self) -> usize { - self.output.as_mut().getNumTexCoordLayers() as usize - } -} - -impl<'cook, N, C, T> SopVboOutput<'cook, Alloc> { - pub fn positions(&mut self) -> &'cook mut [Position] { - let positions = self.output.as_mut().getPos(); - if positions.is_null() { - panic!("positions is null") - } - unsafe { std::slice::from_raw_parts_mut(positions as *mut Position, self.state.vertices) } - } - pub fn add_triangles(&mut self, num_triangles: usize) -> &'cook mut [u32] { - let triangles = self.output.as_mut().addTriangles(num_triangles as i32); - unsafe { std::slice::from_raw_parts_mut(triangles as *mut u32, num_triangles * 3) } - } - pub fn add_particle_system(&mut self, num_particles: usize) -> &'cook mut [u32] { - let particles = self.output.as_mut().addParticleSystem(num_particles as i32); - unsafe { std::slice::from_raw_parts_mut(particles as *mut u32, num_particles) } - } - pub fn add_lines(&mut self, num_lines: usize) -> &'cook mut [u32] { - let lines = self.output.as_mut().addLines(num_lines as i32); - unsafe { std::slice::from_raw_parts_mut(lines as *mut u32, num_lines) } - } - pub fn update_complete(mut self) -> SopVboOutput<'cook, Complete> { - self.output.as_mut().updateComplete(); - SopVboOutput { - state: Complete, - output: self.output, - } - } - pub fn set_bounding_box(&mut self, bounds: impl Into) { - self.output.as_mut().setBoundingBox(&bounds.into()); - } -} - -#[derive(Debug, Copy, Clone)] -pub enum BufferMode { - Static, - Dynamic, -} - -impl From for BufferMode { - fn from(value: VBOBufferMode) -> Self { - match value { - VBOBufferMode::Static => BufferMode::Static, - VBOBufferMode::Dynamic => BufferMode::Dynamic, - } - } -} - -impl From for VBOBufferMode { - fn from(value: BufferMode) -> Self { - match value { - BufferMode::Static => VBOBufferMode::Static, - BufferMode::Dynamic => VBOBufferMode::Dynamic, - } - } -} - -/// Trait for defining a custom operator. -pub trait Sop: Op { - fn general_info(&self, _input: &OperatorInputs) -> SopGeneralInfo { - SopGeneralInfo::default() - } - - fn execute(&mut self, _output: &mut SopOutput, _inputs: &OperatorInputs) { - // Do nothing by default. - } - - fn execute_vbo(&mut self, _output: SopVboOutput, _inputs: &OperatorInputs) { - // Do nothing by default. - } - - fn build_dynamic_menu( - &mut self, - inputs: &OperatorInputs, - menu_info: &mut DynamicMenuInfo, - ) { - } -} - -#[macro_export] -macro_rules! sop_plugin { - ($plugin_ty:ty) => { - use td_rs_sop::cxx::c_void; - use td_rs_sop::cxx::OP_CustomOPInfo; - use td_rs_sop::NodeInfo; - - #[no_mangle] - pub extern "C" fn sop_get_plugin_info_impl( - mut op_info: std::pin::Pin<&mut OP_CustomOPInfo>, - ) { - unsafe { - td_rs_sop::op_info::<$plugin_ty>(op_info); - } - } - - #[no_mangle] - pub extern "C" fn sop_new_impl(info: NodeInfo) -> Box { - op_init(); - Box::new(<$plugin_ty>::new(info)) - } - }; -} +use crate::cxx::{SOP_CustomAttribData, VBOBufferMode, Vector}; + +use std::pin::Pin; + +use td_rs_base::chop::ChopInput; +pub use td_rs_base::sop::*; +pub use td_rs_base::*; + +pub mod cxx; +pub mod prelude; + +#[derive(Debug, Default)] +pub struct SopGeneralInfo { + pub cook_every_frame: bool, + pub cook_every_frame_if_asked: bool, + pub direct_to_gpu: bool, +} + +pub struct SopOutput<'cook> { + output: Pin<&'cook mut cxx::SOP_Output>, +} + +impl<'cook> SopOutput<'cook> { + /// Create a new `SopOutput` from a pinning reference to a + /// `SopOutput`. + pub fn new(output: Pin<&'cook mut cxx::SOP_Output>) -> SopOutput<'cook> { + Self { output } + } + + pub fn add_point(&mut self, pos: impl Into) -> usize { + self.output.as_mut().addPoint(&pos.into()) as usize + } + + pub fn add_points(&mut self, positions: &[Position]) { + unsafe { + self.output.as_mut().addPoints( + positions.as_ptr() as *const cxx::Position, + positions.len() as i32, + ); + } + } + + pub fn num_points(&mut self) -> usize { + self.output.as_mut().getNumPoints() as usize + } + + pub fn set_normal(&mut self, normal: impl Into, start_idx: usize) { + self.output + .as_mut() + .setNormal(normal.into().as_ref(), start_idx as i32); + } + + pub fn set_normals(&mut self, normals: &[Vec3], start_idx: usize) { + unsafe { + self.output.as_mut().setNormals( + normals.as_ptr() as *const Vector, + normals.len() as i32, + start_idx as i32, + ); + } + } + + pub fn has_normals(&mut self) -> bool { + self.output.as_mut().hasNormal() + } + + pub fn set_color(&mut self, color: impl Into, start_idx: usize) { + unsafe { + self.output.as_mut().setColor( + &*(color.into().as_ref() as *const cxx::Color), + start_idx as i32, + ); + } + } + + pub fn set_colors(&mut self, colors: &[Color], start_idx: usize) { + unsafe { + self.output.as_mut().setColors( + colors.as_ptr() as *const cxx::Color, + colors.len() as i32, + start_idx as i32, + ); + } + } + + pub fn has_color(&mut self) -> bool { + self.output.as_mut().hasColor() + } + + pub fn set_tex_coord( + &mut self, + texture: impl Into, + num_layers: usize, + start_idx: usize, + ) { + unsafe { + self.output.as_mut().setTexCoord( + &*(texture.into().as_ref() as *const cxx::TexCoord), + num_layers as i32, + start_idx as i32, + ); + } + } + + pub fn set_tex_coord2(&mut self, texture: &TexCoord, num_layers: usize, start_idx: usize) { + unsafe { + self.output.as_mut().setTexCoord( + texture.as_ref() as *const cxx::TexCoord, + num_layers as i32, + start_idx as i32, + ); + } + } + + pub fn set_tex_coords(&mut self, textures: &[TexCoord], num_layers: usize, start_idx: usize) { + unsafe { + let textures = textures + .iter() + .map(|t| cxx::TexCoord { + u: t.u, + v: t.v, + w: t.w, + }) + .collect::>() + .into_boxed_slice(); + let num_points = self.num_points() as i32; + self.output.as_mut().setTexCoords( + textures.as_ptr() as *const cxx::TexCoord, + num_points, + num_layers as i32, + start_idx as i32, + ); + Box::leak(textures); + } + } + + pub fn has_tex_coord(&mut self) -> bool { + self.output.as_mut().hasTexCoord() + } + + pub fn num_tex_coord_layers(&mut self) -> usize { + self.output.as_mut().getNumTexCoordLayers() as usize + } + + pub fn set_custom_attribute( + &mut self, + info: CustomAttributeInfo, + data: CustomAttributeData, + num_pts: usize, + ) { + unsafe { + let name = std::ffi::CString::new(info.name).unwrap(); + let info = cxx::SOP_CustomAttribInfo { + name: name.as_ptr(), + numComponents: info.num_components as i32, + attribType: (&info.attr_type).into(), + }; + let attr = match data { + CustomAttributeData::Float(mut data) => cxx::SOP_CustomAttribData { + _base: info, + floatData: data.as_mut_ptr(), + intData: std::ptr::null_mut(), + }, + CustomAttributeData::Int(mut data) => cxx::SOP_CustomAttribData { + _base: info, + floatData: std::ptr::null_mut(), + intData: data.as_mut_ptr(), + }, + }; + self.output + .as_mut() + .setCustomAttribute(&attr as *const SOP_CustomAttribData, num_pts as i32); + } + } + + pub fn has_custom_attribute(&mut self) -> bool { + self.output.as_mut().hasCustomAttibutes() + } + + pub fn add_triangle(&mut self, x: u32, y: u32, z: u32) { + self.output + .as_mut() + .addTriangle(x as i32, y as i32, z as i32); + } + + pub fn add_triangles(&mut self, indices: &[u32]) { + unsafe { + self.output + .as_mut() + .addTriangles(indices.as_ptr() as *const i32, (indices.len() / 3) as i32); + } + } + + pub fn add_particle_system(&mut self, num_pts: usize, start_idx: usize) { + self.output + .as_mut() + .addParticleSystem(num_pts as i32, start_idx as i32); + } + + pub fn add_line(&mut self, indices: &[u32]) { + unsafe { + self.output + .as_mut() + .addLine(indices.as_ptr() as *const i32, indices.len() as i32); + } + } + + pub fn add_lines(&mut self, indices: &[u32], sizes: &[u32]) { + unsafe { + self.output.as_mut().addLines( + indices.as_ptr() as *const i32, + sizes.as_ptr() as *const i32 as *mut i32, + sizes.len() as i32, + ); + } + } + + pub fn num_primitives(&mut self) -> usize { + self.output.as_mut().getNumPrimitives() as usize + } + + pub fn set_bounding_box(&mut self, b: impl Into) { + self.output.as_mut().setBoundingBox(&b.into()); + } + + pub fn add_group(&mut self, type_: GroupType, name: &str) { + let name = std::ffi::CString::new(name).unwrap(); + unsafe { + self.output.as_mut().addGroup(&type_.into(), name.as_ptr()); + } + } + + pub fn destroy_group(&mut self, type_: GroupType, name: &str) { + let name = std::ffi::CString::new(name).unwrap(); + unsafe { + self.output + .as_mut() + .destroyGroup(type_.into(), name.as_ptr()); + } + } + + pub fn add_point_to_group(&mut self, point: usize, group: &str) { + let group = std::ffi::CString::new(group).unwrap(); + unsafe { + self.output + .as_mut() + .addPointToGroup(autocxx::c_int(point as std::ffi::c_int), group.as_ptr()); + } + } + + pub fn add_prim_to_group(&mut self, prim: usize, group: &str) { + let group = std::ffi::CString::new(group).unwrap(); + unsafe { + self.output + .as_mut() + .addPrimToGroup(autocxx::c_int(prim as std::ffi::c_int), group.as_ptr()); + } + } + + pub fn add_to_group(&mut self, idx: usize, type_: GroupType, group: &str) { + let group = std::ffi::CString::new(group).unwrap(); + unsafe { + self.output.as_mut().addToGroup( + autocxx::c_int(idx as std::ffi::c_int), + type_.into(), + group.as_ptr(), + ); + } + } + + pub fn discard_from_point_group(&mut self, idx: usize, name: &str) { + let name = std::ffi::CString::new(name).unwrap(); + unsafe { + self.output + .as_mut() + .discardFromPointGroup(autocxx::c_int(idx as std::ffi::c_int), name.as_ptr()); + } + } + + pub fn discard_from_prim_group(&mut self, idx: usize, name: &str) { + let name = std::ffi::CString::new(name).unwrap(); + unsafe { + self.output + .as_mut() + .discardFromPrimGroup(autocxx::c_int(idx as std::ffi::c_int), name.as_ptr()); + } + } + + pub fn discard_from_group(&mut self, idx: usize, type_: GroupType, name: &str) { + let name = std::ffi::CString::new(name).unwrap(); + unsafe { + self.output.as_mut().discardFromGroup( + autocxx::c_int(idx as std::ffi::c_int), + type_.into(), + name.as_ptr(), + ); + } + } +} + +#[derive(Debug)] +pub enum GroupType { + Point, + Primitive, +} + +impl From for &cxx::SOP_GroupType { + fn from(t: GroupType) -> Self { + match t { + GroupType::Point => &cxx::SOP_GroupType::Point, + GroupType::Primitive => &cxx::SOP_GroupType::Primitive, + } + } +} + +impl From for cxx::SOP_GroupType { + fn from(t: GroupType) -> Self { + match t { + GroupType::Point => cxx::SOP_GroupType::Point, + GroupType::Primitive => cxx::SOP_GroupType::Primitive, + } + } +} + +impl From for GroupType { + fn from(t: cxx::SOP_GroupType) -> Self { + match t { + cxx::SOP_GroupType::Point => GroupType::Point, + cxx::SOP_GroupType::Primitive => GroupType::Primitive, + } + } +} + +pub struct Unalloc; + +pub struct ColorEnabled; +pub struct NormalEnabled; +pub struct TexCoordEnabled; + +pub struct Alloc { + pub vertices: usize, + pub indices: usize, + pub buffer_mode: BufferMode, + _normal: std::marker::PhantomData, + _color: std::marker::PhantomData, + _tex_coords: std::marker::PhantomData, +} + +pub struct Complete; + +pub type AllocAll = Alloc; + +pub struct SopVboOutput<'cook, State> { + pub state: State, + output: Pin<&'cook mut cxx::SOP_VBOOutput>, +} + +impl<'cook, State> SopVboOutput<'cook, State> { + /// Create a new `SopOutput` from a pinning reference to a + /// `SopOutput`. + pub fn new(output: Pin<&'cook mut cxx::SOP_VBOOutput>) -> SopVboOutput<'cook, Unalloc> { + SopVboOutput { + state: Unalloc, + output, + } + } + + pub fn has_custom_attributes(&mut self) -> bool { + self.output.as_mut().hasCustomAttibutes() + } + + pub fn has_normal(&mut self) -> bool { + self.output.as_mut().hasNormal() + } + + pub fn has_color(&mut self) -> bool { + self.output.as_mut().hasColor() + } + + pub fn has_tex_coord(&mut self) -> bool { + self.output.as_mut().hasTexCoord() + } +} + +impl<'cook> SopVboOutput<'cook, Unalloc> { + pub fn add_custom_attribute(&mut self, attr: CustomAttributeInfo) { + let name = std::ffi::CString::new(attr.name).unwrap(); + let attr = cxx::SOP_CustomAttribInfo { + name: name.as_ptr(), + numComponents: attr.num_components as i32, + attribType: attr.attr_type.into(), + }; + self.output.as_mut().addCustomAttribute(&attr); + } + + fn alloc_inner( + &mut self, + vertices: usize, + indices: usize, + enable_normal: bool, + enable_color: bool, + tex_coords: usize, + buffer_mode: BufferMode, + ) { + if enable_color { + self.output.as_mut().enableColor(); + } + if enable_normal { + self.output.as_mut().enableNormal(); + } + if tex_coords > 0 { + assert!(tex_coords <= 8); + self.output.as_mut().enableTexCoord(tex_coords as i32); + } + + self.output + .as_mut() + .allocVBO(vertices as i32, indices as i32, buffer_mode.into()); + } + + pub fn alloc_none( + mut self, + vertices: usize, + indices: usize, + buffer_mode: BufferMode, + ) -> SopVboOutput<'cook, Alloc<(), (), ()>> { + self.alloc_inner(vertices, indices, false, false, 0, buffer_mode); + SopVboOutput { + state: Alloc { + vertices, + indices, + buffer_mode, + _color: Default::default(), + _normal: Default::default(), + _tex_coords: Default::default(), + }, + output: self.output, + } + } + + pub fn alloc_all( + mut self, + vertices: usize, + indices: usize, + tex_coords: usize, + buffer_mode: BufferMode, + ) -> SopVboOutput<'cook, Alloc> { + self.alloc_inner(vertices, indices, true, true, tex_coords, buffer_mode); + SopVboOutput { + state: Alloc { + vertices, + indices, + buffer_mode, + _color: Default::default(), + _normal: Default::default(), + _tex_coords: Default::default(), + }, + output: self.output, + } + } + + pub fn alloc_normals( + mut self, + vertices: usize, + indices: usize, + buffer_mode: BufferMode, + ) -> SopVboOutput<'cook, Alloc> { + self.alloc_inner(vertices, indices, true, false, 0, buffer_mode); + SopVboOutput { + state: Alloc { + vertices, + indices, + buffer_mode, + _color: Default::default(), + _normal: Default::default(), + _tex_coords: Default::default(), + }, + output: self.output, + } + } + + pub fn alloc_colors( + mut self, + vertices: usize, + indices: usize, + buffer_mode: BufferMode, + ) -> SopVboOutput<'cook, Alloc<(), ColorEnabled, ()>> { + self.alloc_inner(vertices, indices, false, true, 0, buffer_mode); + SopVboOutput { + state: Alloc { + vertices, + indices, + buffer_mode, + _color: Default::default(), + _normal: Default::default(), + _tex_coords: Default::default(), + }, + output: self.output, + } + } + + pub fn alloc_tex_coords( + mut self, + vertices: usize, + indices: usize, + tex_coords: usize, + buffer_mode: BufferMode, + ) -> SopVboOutput<'cook, Alloc<(), (), TexCoordEnabled>> { + self.alloc_inner(vertices, indices, false, false, tex_coords, buffer_mode); + SopVboOutput { + state: Alloc { + vertices, + indices, + buffer_mode, + _color: Default::default(), + _normal: Default::default(), + _tex_coords: Default::default(), + }, + output: self.output, + } + } + + pub fn alloc_normal_and_colors( + mut self, + vertices: usize, + indices: usize, + buffer_mode: BufferMode, + ) -> SopVboOutput<'cook, Alloc> { + self.alloc_inner(vertices, indices, true, true, 0, buffer_mode); + SopVboOutput { + state: Alloc { + vertices, + indices, + buffer_mode, + _color: Default::default(), + _normal: Default::default(), + _tex_coords: Default::default(), + }, + output: self.output, + } + } + + pub fn alloc_normal_and_tex_coords( + mut self, + vertices: usize, + indices: usize, + tex_coords: usize, + buffer_mode: BufferMode, + ) -> SopVboOutput<'cook, Alloc> { + self.alloc_inner(vertices, indices, true, false, tex_coords, buffer_mode); + SopVboOutput { + state: Alloc { + vertices, + indices, + buffer_mode, + _color: Default::default(), + _normal: Default::default(), + _tex_coords: Default::default(), + }, + output: self.output, + } + } + + pub fn alloc_colors_and_tex_coords( + mut self, + vertices: usize, + indices: usize, + tex_coords: usize, + buffer_mode: BufferMode, + ) -> SopVboOutput<'cook, Alloc<(), ColorEnabled, TexCoordEnabled>> { + self.alloc_inner(vertices, indices, false, true, tex_coords, buffer_mode); + SopVboOutput { + state: Alloc { + vertices, + indices, + buffer_mode, + _color: Default::default(), + _normal: Default::default(), + _tex_coords: Default::default(), + }, + output: self.output, + } + } +} + +impl<'cook, C, T> SopVboOutput<'cook, Alloc> { + pub fn normals(&mut self) -> &'cook mut [Vec3] { + let normals = self.output.as_mut().getNormals(); + if normals.is_null() { + panic!("normals is null") + } + unsafe { std::slice::from_raw_parts_mut(normals as *mut Vec3, self.state.vertices) } + } +} + +impl<'cook, N, T> SopVboOutput<'cook, Alloc> { + pub fn colors(&mut self) -> &'cook mut [Color] { + let colors = self.output.as_mut().getColors(); + if colors.is_null() { + panic!("colors is null") + } + unsafe { std::slice::from_raw_parts_mut(colors as *mut Color, self.state.vertices) } + } +} + +impl<'cook, N, C> SopVboOutput<'cook, Alloc> { + pub fn tex_coords(&mut self) -> &'cook mut [TexCoord] { + let tex_coords = self.output.as_mut().getTexCoords(); + if tex_coords.is_null() { + println!("tex_coords is null") + } + unsafe { std::slice::from_raw_parts_mut(tex_coords as *mut TexCoord, self.state.vertices) } + } + pub fn get_num_text_coord_layers(&mut self) -> usize { + self.output.as_mut().getNumTexCoordLayers() as usize + } +} + +impl<'cook, N, C, T> SopVboOutput<'cook, Alloc> { + pub fn positions(&mut self) -> &'cook mut [Position] { + let positions = self.output.as_mut().getPos(); + if positions.is_null() { + panic!("positions is null") + } + unsafe { std::slice::from_raw_parts_mut(positions as *mut Position, self.state.vertices) } + } + pub fn add_triangles(&mut self, num_triangles: usize) -> &'cook mut [u32] { + let triangles = self.output.as_mut().addTriangles(num_triangles as i32); + unsafe { std::slice::from_raw_parts_mut(triangles as *mut u32, num_triangles * 3) } + } + pub fn add_particle_system(&mut self, num_particles: usize) -> &'cook mut [u32] { + let particles = self.output.as_mut().addParticleSystem(num_particles as i32); + unsafe { std::slice::from_raw_parts_mut(particles as *mut u32, num_particles) } + } + pub fn add_lines(&mut self, num_lines: usize) -> &'cook mut [u32] { + let lines = self.output.as_mut().addLines(num_lines as i32); + unsafe { std::slice::from_raw_parts_mut(lines as *mut u32, num_lines) } + } + pub fn update_complete(mut self) -> SopVboOutput<'cook, Complete> { + self.output.as_mut().updateComplete(); + SopVboOutput { + state: Complete, + output: self.output, + } + } + pub fn set_bounding_box(&mut self, bounds: impl Into) { + self.output.as_mut().setBoundingBox(&bounds.into()); + } +} + +#[derive(Debug, Copy, Clone)] +pub enum BufferMode { + Static, + Dynamic, +} + +impl From for BufferMode { + fn from(value: VBOBufferMode) -> Self { + match value { + VBOBufferMode::Static => BufferMode::Static, + VBOBufferMode::Dynamic => BufferMode::Dynamic, + } + } +} + +impl From for VBOBufferMode { + fn from(value: BufferMode) -> Self { + match value { + BufferMode::Static => VBOBufferMode::Static, + BufferMode::Dynamic => VBOBufferMode::Dynamic, + } + } +} + +/// Trait for defining a custom operator. +pub trait Sop: Op { + fn general_info(&self, _input: &OperatorInputs) -> SopGeneralInfo { + SopGeneralInfo::default() + } + + fn execute(&mut self, _output: &mut SopOutput, _inputs: &OperatorInputs) { + // Do nothing by default. + } + + fn execute_vbo(&mut self, _output: SopVboOutput, _inputs: &OperatorInputs) { + // Do nothing by default. + } + + fn build_dynamic_menu( + &mut self, + inputs: &OperatorInputs, + menu_info: &mut DynamicMenuInfo, + ) { + } +} + +#[macro_export] +macro_rules! sop_plugin { + ($plugin_ty:ty) => { + use td_rs_sop::cxx::c_void; + use td_rs_sop::cxx::OP_CustomOPInfo; + use td_rs_sop::NodeInfo; + + #[no_mangle] + pub extern "C" fn sop_get_plugin_info_impl( + mut op_info: std::pin::Pin<&mut OP_CustomOPInfo>, + ) { + unsafe { + td_rs_sop::op_info::<$plugin_ty>(op_info); + } + } + + #[no_mangle] + pub extern "C" fn sop_new_impl(info: NodeInfo) -> Box { + op_init(); + Box::new(<$plugin_ty>::new(info)) + } + }; +} diff --git a/td-rs-sop/src/prelude.rs b/td-rs-sop/src/prelude.rs index dd44555..c36e0d9 100644 --- a/td-rs-sop/src/prelude.rs +++ b/td-rs-sop/src/prelude.rs @@ -1,9 +1,9 @@ -pub use crate::cxx::AsPlugin; -pub use crate::*; - -#[cfg(feature = "python")] -pub use pyo3::impl_::pyclass::PyClassImpl; -#[cfg(feature = "python")] -pub use pyo3::prelude::*; -#[cfg(feature = "python")] -pub use std::pin::Pin; +pub use crate::cxx::AsPlugin; +pub use crate::*; + +#[cfg(feature = "python")] +pub use pyo3::impl_::pyclass::PyClassImpl; +#[cfg(feature = "python")] +pub use pyo3::prelude::*; +#[cfg(feature = "python")] +pub use std::pin::Pin; diff --git a/td-rs-top/Cargo.toml b/td-rs-top/Cargo.toml index 78caec5..96917c3 100644 --- a/td-rs-top/Cargo.toml +++ b/td-rs-top/Cargo.toml @@ -1,28 +1,31 @@ -[package] -name = "td-rs-top" -version = "0.1.0" -edition = "2021" - -[lib] -name = "td_rs_top" -crate-type = ["lib", "staticlib"] - -[dependencies] -autocxx = { git = "https://github.com/tychedelia/autocxx.git" } -cxx = "1.0.78" -td-rs-base = { path = "../td-rs-base" } -ref-cast = "1.0" -tracing-base = { package = "tracing", version = "0.1", optional = true } -tracing-subscriber = { version = "0.2", optional = true } -pyo3 = { git = "https://github.com/tychedelia/pyo3", branch = "td-rs", features = ["abi3-py311"], optional = true } - -[build-dependencies] -td-rs-autocxx-build = { path = "../td-rs-autocxx-build" } -autocxx-build = { git = "https://github.com/tychedelia/autocxx.git" } -miette = { version="5", features = [ "fancy" ] } - -[features] -default = [] -python = ["td-rs-base/python", "dep:pyo3"] -tracing = ["td-rs-base/tracing", "tracing-base", "tracing-subscriber"] -tokio = ["td-rs-base/tokio"] +[package] +name = "td-rs-top" +version = "0.1.0" +edition = "2021" + +[lib] +name = "td_rs_top" +crate-type = ["lib", "staticlib"] + +[dependencies] +autocxx = { git = "https://github.com/tychedelia/autocxx.git" } +cxx = "1.0.78" +td-rs-base = { path = "../td-rs-base" } +ref-cast = "1.0" +tracing-base = { package = "tracing", version = "0.1", optional = true } +tracing-subscriber = { version = "0.2", optional = true } +pyo3 = { git = "https://github.com/tychedelia/pyo3", branch = "td-rs", features = ["abi3-py311"], optional = true } +cudarc = { version = "0.16.4", optional = true, features = ["runtime", "nvrtc", "driver", "cuda-12080", "dynamic-linking"], default-features = false } +anyhow = "1.0" + +[build-dependencies] +td-rs-autocxx-build = { path = "../td-rs-autocxx-build" } +autocxx-build = { git = "https://github.com/tychedelia/autocxx.git" } +miette = { version="5", features = [ "fancy" ] } + +[features] +default = [] +python = ["td-rs-base/python", "dep:pyo3"] +tracing = ["td-rs-base/tracing", "tracing-base", "tracing-subscriber"] +tokio = ["td-rs-base/tokio"] +cuda = ["cudarc", "td-rs-base/cuda"] \ No newline at end of file diff --git a/td-rs-top/build.rs b/td-rs-top/build.rs index ee94ac3..630340d 100644 --- a/td-rs-top/build.rs +++ b/td-rs-top/build.rs @@ -1,3 +1,3 @@ -fn main() -> miette::Result<()> { - td_rs_autocxx_build::build("td-rs-chop", true) -} +fn main() -> miette::Result<()> { + td_rs_autocxx_build::build("td-rs-chop", true) +} diff --git a/td-rs-top/src/RustTopPlugin.cpp b/td-rs-top/src/RustTopPlugin.cpp index b274012..292e3f9 100644 --- a/td-rs-top/src/RustTopPlugin.cpp +++ b/td-rs-top/src/RustTopPlugin.cpp @@ -1,57 +1,106 @@ -#include "RustTopPlugin.h" -#include "CPlusPlus_Common.h" -#include -#ifdef PYTHON_ENABLED -#include -#endif - - -extern "C" { - -RustTopPlugin *top_new(const OP_NodeInfo &info, TOP_Context &context); -TOP_ExecuteMode top_get_plugin_info_impl(OP_CustomOPInfo &opInfo); - -DLLEXPORT -void FillTOPPluginInfo(TOP_PluginInfo *info) { - info->apiVersion = TOPCPlusPlusAPIVersion; - auto opInfo = &info->customOPInfo; - auto mode = top_get_plugin_info_impl(*opInfo); - info->executeMode = mode; -#ifdef PYTHON_ENABLED - opInfo->pythonVersion->setString(PY_VERSION); -#endif -} - -DLLEXPORT -TOP_CPlusPlusBase *CreateTOPInstance(const OP_NodeInfo *info, TOP_Context *context) { - return top_new(*info, *context); -} - -DLLEXPORT -void DestroyTOPInstance(TOP_CPlusPlusBase *instance) { - delete (RustTopPlugin *)instance; -} -} - -void* getBufferData(TD::OP_SmartRef &buffer) { - void* data = buffer->data; - return data; -} - -uint64_t getBufferSize(const TD::OP_SmartRef &buffer) { - uint64_t size = buffer->size; - return size; -} - -TD::TOP_BufferFlags getBufferFlags(const TD::OP_SmartRef &buffer) { - TD::TOP_BufferFlags flags = buffer->flags; - return flags; -} - -void releaseBuffer(TD::OP_SmartRef &buffer) { - // buffer may have been moved, so we need to check if it's valid - if (buffer) { - buffer.release(); - } -} - +#include "RustTopPlugin.h" +#include "CPlusPlus_Common.h" +#include +#ifdef PYTHON_ENABLED +#include +#endif + + +extern "C" { + +RustTopPlugin *top_new(const OP_NodeInfo &info, TOP_Context &context); +TOP_ExecuteMode top_get_plugin_info_impl(OP_CustomOPInfo &opInfo); + +DLLEXPORT +void FillTOPPluginInfo(TOP_PluginInfo *info) { + info->apiVersion = TOPCPlusPlusAPIVersion; + auto opInfo = &info->customOPInfo; + auto mode = top_get_plugin_info_impl(*opInfo); + info->executeMode = mode; +#ifdef PYTHON_ENABLED + opInfo->pythonVersion->setString(PY_VERSION); +#endif +} + +DLLEXPORT +TOP_CPlusPlusBase *CreateTOPInstance(const OP_NodeInfo *info, TOP_Context *context) { + return top_new(*info, *context); +} + +DLLEXPORT +void DestroyTOPInstance(TOP_CPlusPlusBase *instance) { + delete (RustTopPlugin *)instance; +} +} + +void* getBufferData(TD::OP_SmartRef &buffer) { + void* data = buffer->data; + return data; +} + +uint64_t getBufferSize(const TD::OP_SmartRef &buffer) { + uint64_t size = buffer->size; + return size; +} + +TD::TOP_BufferFlags getBufferFlags(const TD::OP_SmartRef &buffer) { + TD::TOP_BufferFlags flags = buffer->flags; + return flags; +} + +void releaseBuffer(TD::OP_SmartRef &buffer) { + // buffer may have been moved, so we need to check if it's valid + if (buffer) { + buffer.release(); + } +} + +// CUDA helper functions (TOP-specific only) + +TD::OP_TextureDesc getCUDAOutputInfoTextureDesc(const TD::TOP_CUDAOutputInfo &info) { + return info.textureDesc; +} + +void* getCUDAOutputInfoStream(const TD::TOP_CUDAOutputInfo &info) { + return info.stream; +} + +uint32_t getCUDAOutputInfoColorBufferIndex(const TD::TOP_CUDAOutputInfo &info) { + return info.colorBufferIndex; +} + +// Helper to create TOP_CUDAOutputInfo from primitive parameters +TD::TOP_CUDAOutputInfo createCUDAOutputInfo(void* stream, + uint32_t width, uint32_t height, uint32_t depth, + int32_t texDim, int32_t pixelFormat, + float aspectX, float aspectY, + uint32_t colorBufferIndex) { + TD::TOP_CUDAOutputInfo info; + info.stream = static_cast(stream); + + info.textureDesc.width = width; + info.textureDesc.height = height; + info.textureDesc.depth = depth; + info.textureDesc.texDim = static_cast(texDim); + info.textureDesc.pixelFormat = static_cast(pixelFormat); + info.textureDesc.aspectX = aspectX; + info.textureDesc.aspectY = aspectY; + + info.colorBufferIndex = colorBufferIndex; + + return info; +} + + +// Helper for CUDA context operations +bool beginCUDAOperations(TD::TOP_Context* context) { + if (!context) return false; + return context->beginCUDAOperations(nullptr); +} + +void endCUDAOperations(TD::TOP_Context* context) { + if (context) { + context->endCUDAOperations(nullptr); + } +} + diff --git a/td-rs-top/src/RustTopPlugin.h b/td-rs-top/src/RustTopPlugin.h index 59b5cbf..9ab4a14 100644 --- a/td-rs-top/src/RustTopPlugin.h +++ b/td-rs-top/src/RustTopPlugin.h @@ -1,146 +1,161 @@ -#include "CPlusPlus_Common.h" -#include "TOP_CPlusPlusBase.h" - -#ifndef TD_RS_RUSTTOPPLUGIN_H -#define TD_RS_RUSTTOPPLUGIN_H - -void* getBufferData(TD::OP_SmartRef &buffer); - -uint64_t getBufferSize(const TD::OP_SmartRef &buffer); - -TD::TOP_BufferFlags getBufferFlags(const TD::OP_SmartRef &buffer); - -void releaseBuffer(TD::OP_SmartRef &buffer); - -using namespace TD; - -class TopPlugin : public TOP_CPlusPlusBase { -public: - virtual ~TopPlugin() {}; - - void getGeneralInfo(TOP_GeneralInfo *info, const OP_Inputs *inputs, - void *reserved1) override { - this->getGeneralInfo(*info, *inputs); - } - - virtual void getGeneralInfo(TOP_GeneralInfo &info, const OP_Inputs &inputs) {} - - virtual void execute(TOP_Output* output, const OP_Inputs* inputs, void* reserved1) override { - this->execute(*output, *inputs); - } - - virtual void execute(TOP_Output &output, const OP_Inputs &inputs) {} - - int32_t getNumInfoCHOPChans(void *reserved1) override { - return this->getNumInfoCHOPChans(); - } - - virtual int32_t getNumInfoCHOPChans() { return 0; } - - void getInfoCHOPChan(int32_t index, OP_InfoCHOPChan *chan, - void *reserved1) override { - OP_String *name = chan->name; - float v = 0.f; - float *value = &v; - this->getInfoCHOPChan(index, *name, *value); - chan->name = name; - chan->value = *value; - } - - virtual void getInfoCHOPChan(int32_t index, OP_String &name, float &value) {} - - bool getInfoDATSize(OP_InfoDATSize *infoSize, void *reserved1) override { - return this->getInfoDATSize(*infoSize); - } - - virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) { return false; } - - void getInfoDATEntries(int32_t index, int32_t nEntries, - OP_InfoDATEntries *entries, void *reserved1) override { - for (int i = 0; i < nEntries; i++) { - auto entry = entries->values[i]; - this->getInfoDATEntry(index, i, *entry); - } - } - - virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, - OP_String &entry) {} - - void getWarningString(OP_String *warning, void *reserved1) override { - this->getWarningString(*warning); - }; - - virtual void getWarningString(OP_String &warning) {} - - void getErrorString(OP_String *error, void *reserved1) override { - this->getErrorString(*error); - }; - - virtual void getErrorString(OP_String &error) {} - - void getInfoPopupString(OP_String *popup, void *reserved1) override { - this->getInfoPopupString(*popup); - }; - - virtual void getInfoPopupString(OP_String &popup) {} - - void setupParameters(OP_ParameterManager *manager, void *reserved1) override { - this->setupParameters(*manager); - }; - - virtual void setupParameters(OP_ParameterManager &manager) {} - - void pulsePressed(const char *name, void *reserved1) override { - this->pulsePressed(name); - }; - - virtual void pulsePressed(const char *name) {} - - virtual void buildDynamicMenu(const OP_Inputs *inputs, - OP_BuildDynamicMenuInfo *info, - void *reserved1) { - this->buildDynamicMenu(*inputs, *info); - } - - virtual void buildDynamicMenu(const OP_Inputs &inputs, - OP_BuildDynamicMenuInfo &info) {} -}; - -class RustTopPlugin : public TopPlugin { -public: - virtual ~RustTopPlugin() {}; - - virtual void* inner() const = 0; - - virtual void* innerMut() = 0; - - virtual void getGeneralInfo(TOP_GeneralInfo &info, - const OP_Inputs &inputs) = 0; - - virtual int32_t getNumInfoCHOPChans() = 0; - - virtual void execute(TOP_Output &output, const OP_Inputs &inputs) = 0; - - virtual void getInfoCHOPChan(int32_t index, OP_String &name, - float &value) = 0; - - virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) = 0; - - virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, - OP_String &entry) = 0; - - virtual void getWarningString(OP_String &warning) = 0; - - virtual void getErrorString(OP_String &error) = 0; - - virtual void getInfoPopupString(OP_String &popup) = 0; - - virtual void setupParameters(OP_ParameterManager &manager) = 0; - - virtual void pulsePressed(const char *name) = 0; - - virtual void buildDynamicMenu(const OP_Inputs &inputs, - OP_BuildDynamicMenuInfo &info) = 0; -}; - -#endif //TD_RS_RUSTTOPPLUGIN_H +#include "CPlusPlus_Common.h" +#include "TOP_CPlusPlusBase.h" + +#ifndef TD_RS_RUSTTOPPLUGIN_H +#define TD_RS_RUSTTOPPLUGIN_H + +void* getBufferData(TD::OP_SmartRef &buffer); + +uint64_t getBufferSize(const TD::OP_SmartRef &buffer); + +TD::TOP_BufferFlags getBufferFlags(const TD::OP_SmartRef &buffer); + +void releaseBuffer(TD::OP_SmartRef &buffer); + +// CUDA helper functions (TOP-specific) +TD::OP_TextureDesc getCUDAOutputInfoTextureDesc(const TD::TOP_CUDAOutputInfo &info); +void* getCUDAOutputInfoStream(const TD::TOP_CUDAOutputInfo &info); +uint32_t getCUDAOutputInfoColorBufferIndex(const TD::TOP_CUDAOutputInfo &info); +TD::TOP_CUDAOutputInfo createCUDAOutputInfo(void* stream, + uint32_t width, uint32_t height, uint32_t depth, + int32_t texDim, int32_t pixelFormat, + float aspectX, float aspectY, + uint32_t colorBufferIndex); + + +// Helper for CUDA context operations +bool beginCUDAOperations(TD::TOP_Context* context); +void endCUDAOperations(TD::TOP_Context* context); + +using namespace TD; + +class TopPlugin : public TOP_CPlusPlusBase { +public: + virtual ~TopPlugin() {}; + + void getGeneralInfo(TOP_GeneralInfo *info, const OP_Inputs *inputs, + void *reserved1) override { + this->getGeneralInfo(*info, *inputs); + } + + virtual void getGeneralInfo(TOP_GeneralInfo &info, const OP_Inputs &inputs) {} + + virtual void execute(TOP_Output* output, const OP_Inputs* inputs, void* reserved1) override { + this->execute(*output, *inputs); + } + + virtual void execute(TOP_Output &output, const OP_Inputs &inputs) {} + + int32_t getNumInfoCHOPChans(void *reserved1) override { + return this->getNumInfoCHOPChans(); + } + + virtual int32_t getNumInfoCHOPChans() { return 0; } + + void getInfoCHOPChan(int32_t index, OP_InfoCHOPChan *chan, + void *reserved1) override { + OP_String *name = chan->name; + float v = 0.f; + float *value = &v; + this->getInfoCHOPChan(index, *name, *value); + chan->name = name; + chan->value = *value; + } + + virtual void getInfoCHOPChan(int32_t index, OP_String &name, float &value) {} + + bool getInfoDATSize(OP_InfoDATSize *infoSize, void *reserved1) override { + return this->getInfoDATSize(*infoSize); + } + + virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) { return false; } + + void getInfoDATEntries(int32_t index, int32_t nEntries, + OP_InfoDATEntries *entries, void *reserved1) override { + for (int i = 0; i < nEntries; i++) { + auto entry = entries->values[i]; + this->getInfoDATEntry(index, i, *entry); + } + } + + virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, + OP_String &entry) {} + + void getWarningString(OP_String *warning, void *reserved1) override { + this->getWarningString(*warning); + }; + + virtual void getWarningString(OP_String &warning) {} + + void getErrorString(OP_String *error, void *reserved1) override { + this->getErrorString(*error); + }; + + virtual void getErrorString(OP_String &error) {} + + void getInfoPopupString(OP_String *popup, void *reserved1) override { + this->getInfoPopupString(*popup); + }; + + virtual void getInfoPopupString(OP_String &popup) {} + + void setupParameters(OP_ParameterManager *manager, void *reserved1) override { + this->setupParameters(*manager); + }; + + virtual void setupParameters(OP_ParameterManager &manager) {} + + void pulsePressed(const char *name, void *reserved1) override { + this->pulsePressed(name); + }; + + virtual void pulsePressed(const char *name) {} + + virtual void buildDynamicMenu(const OP_Inputs *inputs, + OP_BuildDynamicMenuInfo *info, + void *reserved1) { + this->buildDynamicMenu(*inputs, *info); + } + + virtual void buildDynamicMenu(const OP_Inputs &inputs, + OP_BuildDynamicMenuInfo &info) {} +}; + +class RustTopPlugin : public TopPlugin { +public: + virtual ~RustTopPlugin() {}; + + virtual void* inner() const = 0; + + virtual void* innerMut() = 0; + + virtual void getGeneralInfo(TOP_GeneralInfo &info, + const OP_Inputs &inputs) = 0; + + virtual int32_t getNumInfoCHOPChans() = 0; + + virtual void execute(TOP_Output &output, const OP_Inputs &inputs) = 0; + + virtual void getInfoCHOPChan(int32_t index, OP_String &name, + float &value) = 0; + + virtual bool getInfoDATSize(OP_InfoDATSize &infoSize) = 0; + + virtual void getInfoDATEntry(int32_t index, int32_t entryIndex, + OP_String &entry) = 0; + + virtual void getWarningString(OP_String &warning) = 0; + + virtual void getErrorString(OP_String &error) = 0; + + virtual void getInfoPopupString(OP_String &popup) = 0; + + virtual void setupParameters(OP_ParameterManager &manager) = 0; + + virtual void pulsePressed(const char *name) = 0; + + virtual void buildDynamicMenu(const OP_Inputs &inputs, + OP_BuildDynamicMenuInfo &info) = 0; +}; + +#endif //TD_RS_RUSTTOPPLUGIN_H diff --git a/td-rs-top/src/TOP_CPlusPlusBase.h b/td-rs-top/src/TOP_CPlusPlusBase.h index a0eb838..6cbbca0 100644 --- a/td-rs-top/src/TOP_CPlusPlusBase.h +++ b/td-rs-top/src/TOP_CPlusPlusBase.h @@ -238,8 +238,11 @@ class TOP_Context : public OP_Context { // for another option potentially, avoiding a re-allocation. virtual void returnBuffer(OP_SmartRef *buf) = 0; + // Returns the CUDA device index the process is currently using. Returns -1 if + // this node is not using CUDA execution mode. + virtual int getCUDADeviceIndex(void *reserved) = 0; + protected: - virtual void reserved0() = 0; virtual void reserved1() = 0; virtual void reserved2() = 0; virtual void reserved3() = 0; @@ -352,7 +355,9 @@ class TOP_Output { /*** DO NOT EDIT THIS CLASS, MAKE A SUBCLASS OF IT INSTEAD ***/ class TOP_CPlusPlusBase { protected: - TOP_CPlusPlusBase() { memset(reserved, 0, sizeof(reserved)); } + TOP_CPlusPlusBase() { + memset(reservedDataPadding, 0, sizeof(reservedDataPadding)); + } public: virtual ~TOP_CPlusPlusBase() {} @@ -437,7 +442,7 @@ class TOP_CPlusPlusBase { virtual int32_t reservedFunc19() { return 0; } virtual int32_t reservedFunc20() { return 0; } - int32_t reserved[400]; + int32_t reservedDataPadding[400]; }; #pragma pack(pop) diff --git a/td-rs-top/src/cuda.rs b/td-rs-top/src/cuda.rs new file mode 100644 index 0000000..657157f --- /dev/null +++ b/td-rs-top/src/cuda.rs @@ -0,0 +1,119 @@ +use crate::cxx; +#[cfg(feature = "cuda")] +use cudarc::runtime::sys; +use std::sync::Arc; + +// Re-export CudaArrayInfo from td-rs-base +#[cfg(feature = "cuda")] +pub use td_rs_base::top::CudaArrayInfo; + +#[derive(Debug)] +pub struct CudaAcquireInfo { + pub stream: sys::cudaStream_t, +} + +impl Default for CudaAcquireInfo { + fn default() -> Self { + Self { + stream: std::ptr::null_mut(), + } + } +} + +#[derive(Debug)] +pub struct CudaOutputInfo { + pub stream: sys::cudaStream_t, + pub texture_desc: crate::TextureDesc, + pub color_buffer_index: u32, +} + +impl Default for CudaOutputInfo { + fn default() -> Self { + Self { + stream: std::ptr::null_mut(), + texture_desc: crate::TextureDesc::default(), + color_buffer_index: 0, + } + } +} + +#[derive(Debug)] +pub struct CudaSurface { + surface: sys::cudaSurfaceObject_t, + _marker: std::marker::PhantomData<()>, +} + +impl CudaSurface { + pub unsafe fn from_external_array(array: *mut sys::cudaArray) -> Result { + if array.is_null() { + return Err(anyhow::anyhow!("Invalid CUDA array pointer")); + } + + let mut surface = 0; + let desc = sys::cudaResourceDesc { + resType: sys::cudaResourceType::cudaResourceTypeArray, + res: sys::cudaResourceDesc__bindgen_ty_1 { + array: sys::cudaResourceDesc__bindgen_ty_1__bindgen_ty_1 { array }, + }, + }; + + let result = sys::cudaCreateSurfaceObject(&mut surface, &desc); + if result != sys::cudaError::cudaSuccess { + return Err(anyhow::anyhow!( + "CUDA surface creation failed: {:?}", + result + )); + } + + Ok(Self { + surface, + _marker: std::marker::PhantomData, + }) + } + + pub fn handle(&self) -> sys::cudaSurfaceObject_t { + self.surface + } +} + +impl Drop for CudaSurface { + fn drop(&mut self) { + if self.surface != 0 { + unsafe { + sys::cudaDestroySurfaceObject(self.surface); + } + } + } +} + +#[derive(Debug, Default)] +pub struct SurfaceCache { + surfaces: std::collections::HashMap<*mut sys::cudaArray, CudaSurface>, +} + +impl SurfaceCache { + pub fn new() -> Self { + Self { + surfaces: std::collections::HashMap::new(), + } + } + + pub unsafe fn get_or_create( + &mut self, + array: *mut sys::cudaArray, + ) -> Result<&CudaSurface, anyhow::Error> { + if !self.surfaces.contains_key(&array) { + let surface = CudaSurface::from_external_array(array)?; + self.surfaces.insert(array, surface); + } + Ok(self.surfaces.get(&array).unwrap()) + } + + pub fn cleanup_invalid(&mut self, valid_arrays: &[*mut sys::cudaArray]) { + self.surfaces.retain(|&k, _| valid_arrays.contains(&k)); + } + + pub fn clear(&mut self) { + self.surfaces.clear(); + } +} diff --git a/td-rs-top/src/cxx.rs b/td-rs-top/src/cxx.rs index 3a97d29..ac21f30 100644 --- a/td-rs-top/src/cxx.rs +++ b/td-rs-top/src/cxx.rs @@ -25,11 +25,14 @@ include_cpp! { extern_cpp_type!("TD::OP_TOPInput", td_rs_base::cxx::OP_TOPInput) extern_cpp_type!("TD::OP_TOPInputDownloadOptions", td_rs_base::cxx::OP_TOPInputDownloadOptions) extern_cpp_type!("TD::OP_PixelFormat", td_rs_base::cxx::OP_PixelFormat) + extern_cpp_type!("TD::OP_TexDim", td_rs_base::cxx::OP_TexDim) extern_cpp_type!("TD::OP_TextureDesc", td_rs_base::cxx::OP_TextureDesc) pod!("TD::OP_TextureDesc") extern_cpp_type!("TD::OP_CPUMemPixelType", td_rs_base::cxx::OP_CPUMemPixelType) extern_cpp_type!("TD::OP_CUDAArrayInfo", td_rs_base::cxx::OP_CUDAArrayInfo) + extern_cpp_type!("TD::OP_CUDAAcquireInfo", td_rs_base::cxx::OP_CUDAAcquireInfo) extern_cpp_type!("TD::OP_BuildDynamicMenuInfo", td_rs_base::cxx::OP_BuildDynamicMenuInfo) + generate!("TD::TOP_CUDAOutputInfo") generate_pod!("TD::TOP_UploadInfo") generate_pod!("TD::TOP_GeneralInfo") generate_pod!("TD::TOP_PluginInfo") @@ -43,6 +46,14 @@ include_cpp! { generate!("getBufferSize") generate!("getBufferFlags") generate!("releaseBuffer") + + // CUDA helper functions (TOP-specific only) + generate!("getCUDAOutputInfoTextureDesc") + generate!("getCUDAOutputInfoStream") + generate!("getCUDAOutputInfoColorBufferIndex") + generate!("createCUDAOutputInfo") + generate!("beginCUDAOperations") + generate!("endCUDAOperations") } pub use autocxx::c_void; diff --git a/td-rs-top/src/lib.rs b/td-rs-top/src/lib.rs index da6e9c1..fc26c1f 100644 --- a/td-rs-top/src/lib.rs +++ b/td-rs-top/src/lib.rs @@ -1,12 +1,20 @@ pub mod cxx; +#[cfg(feature = "cuda")] +pub mod cuda; + pub use ::cxx::UniquePtr; +pub use autocxx::prelude::*; use std::pin::Pin; use td_rs_base::chop::ChopInput; pub use td_rs_base::top::*; pub use td_rs_base::*; +#[cfg(feature = "cuda")] +pub use cuda::*; +use td_rs_base::cxx::{OP_PixelFormat, OP_TexDim}; + pub mod prelude; pub struct TopOutput<'cook> { @@ -18,6 +26,7 @@ impl<'cook> TopOutput<'cook> { Self { output } } + /// Upload a CPU buffer for CPU execution mode pub fn upload_buffer(&mut self, buffer: &mut TopBuffer, info: &UploadInfo) { let info = crate::cxx::TOP_UploadInfo { bufferOffset: info.buffer_offset as u64, @@ -27,13 +36,7 @@ impl<'cook> TopOutput<'cook> { depth: info.texture_desc.depth as u32, height: info.texture_desc.height as u32, width: info.texture_desc.width as u32, - texDim: match info.texture_desc.tex_dim { - TexDim::EInvalid => cxx::OP_TexDim::eInvalid, - TexDim::E2D => cxx::OP_TexDim::e2D, - TexDim::E2DArray => cxx::OP_TexDim::e2DArray, - TexDim::E3D => cxx::OP_TexDim::e3D, - TexDim::ECube => cxx::OP_TexDim::eCube, - }, + texDim: OP_TexDim::from(&info.texture_desc.tex_dim), pixelFormat: (&info.texture_desc.pixel_format).into(), reserved: Default::default(), }, @@ -53,6 +56,37 @@ impl<'cook> TopOutput<'cook> { .uploadBuffer(buf.into_raw(), &info, std::ptr::null_mut()) }; } + + /// Create a CUDA array for CUDA execution mode + #[cfg(feature = "cuda")] + pub fn create_cuda_array( + &mut self, + info: &crate::cuda::CudaOutputInfo, + ) -> Result { + use crate::cxx; + + // Use C++ helper to construct TOP_CUDAOutputInfo from primitive parameters + moveit! { let mut cuda_info = unsafe { cxx::createCUDAOutputInfo( + info.stream as *mut cxx::c_void, + info.texture_desc.width as u32, + info.texture_desc.height as u32, + info.texture_desc.depth as u32, + OP_TexDim::from(&info.texture_desc.tex_dim) as i32, + OP_PixelFormat::from(&info.texture_desc.pixel_format) as i32, + info.texture_desc.aspect_x, + info.texture_desc.aspect_y, + info.color_buffer_index + ) } }; + + let array_info = unsafe { + self.output + .as_mut() + .createCUDAArray(cuda_info.as_ref().get_ref(), std::ptr::null_mut()) + }; + + // Convert to our safe wrapper + td_rs_base::top::CudaArrayInfo::new(array_info) + } } pub trait TopNew { @@ -95,6 +129,18 @@ impl TopContext { }; TopBuffer::new(buf) } + + /// Begin CUDA operations - makes CUDA array pointers valid + #[cfg(feature = "cuda")] + pub fn begin_cuda_operations(&mut self) -> bool { + unsafe { cxx::beginCUDAOperations(self.context.as_mut().get_unchecked_mut()) } + } + + /// End CUDA operations - invalidates CUDA array pointers + #[cfg(feature = "cuda")] + pub fn end_cuda_operations(&mut self) { + unsafe { cxx::endCUDAOperations(self.context.as_mut().get_unchecked_mut()) } + } } #[derive(Debug, Default, Eq, PartialEq)] @@ -186,7 +232,7 @@ macro_rules! top_plugin { unsafe { td_rs_top::op_info::<$plugin_ty>(op_info); match <$plugin_ty>::EXECUTE_MODE { - td_rs_top::ExecuteMode::Cuda => panic!("Cuda is not supported yet"), + td_rs_top::ExecuteMode::Cuda => cxx::TOP_ExecuteMode::CUDA, td_rs_top::ExecuteMode::Cpu => cxx::TOP_ExecuteMode::CPUMem, } } diff --git a/td-rs-top/src/prelude.rs b/td-rs-top/src/prelude.rs index dd44555..c36e0d9 100644 --- a/td-rs-top/src/prelude.rs +++ b/td-rs-top/src/prelude.rs @@ -1,9 +1,9 @@ -pub use crate::cxx::AsPlugin; -pub use crate::*; - -#[cfg(feature = "python")] -pub use pyo3::impl_::pyclass::PyClassImpl; -#[cfg(feature = "python")] -pub use pyo3::prelude::*; -#[cfg(feature = "python")] -pub use std::pin::Pin; +pub use crate::cxx::AsPlugin; +pub use crate::*; + +#[cfg(feature = "python")] +pub use pyo3::impl_::pyclass::PyClassImpl; +#[cfg(feature = "python")] +pub use pyo3::prelude::*; +#[cfg(feature = "python")] +pub use std::pin::Pin; diff --git a/td-rs-xtask/Cargo.toml b/td-rs-xtask/Cargo.toml index 76b0116..7509118 100644 --- a/td-rs-xtask/Cargo.toml +++ b/td-rs-xtask/Cargo.toml @@ -1,15 +1,15 @@ -[package] -name = "td-rs-xtask" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -anyhow = "1" -fs_extra = "1" -serde = { version = "1", features = ["derive"] } -serde_json = "1" -toml = "0.8" -cargo_metadata = "0.15.4" +[package] +name = "td-rs-xtask" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1" +fs_extra = "1" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +toml = "0.8" +cargo_metadata = "0.15.4" homedir = "0.2" \ No newline at end of file diff --git a/td-rs-xtask/msvc/RustOp.sln b/td-rs-xtask/msvc/RustOp.sln index f3769c4..52732ee 100644 --- a/td-rs-xtask/msvc/RustOp.sln +++ b/td-rs-xtask/msvc/RustOp.sln @@ -1,25 +1,25 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.1.32319.34 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RustOp", "RustOp.vcxproj", "{3F5BEECD-FA36-459F-91B8-BB481A67EF44}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Debug|x64.ActiveCfg = Release|x64 - {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Debug|x64.Build.0 = Release|x64 - {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Release|x64.ActiveCfg = Release|x64 - {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {24D28F69-BD3C-4E02-8720-07536D0DC619} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32319.34 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RustOp", "RustOp.vcxproj", "{3F5BEECD-FA36-459F-91B8-BB481A67EF44}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Debug|x64.ActiveCfg = Release|x64 + {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Debug|x64.Build.0 = Release|x64 + {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Release|x64.ActiveCfg = Release|x64 + {3F5BEECD-FA36-459F-91B8-BB481A67EF44}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {24D28F69-BD3C-4E02-8720-07536D0DC619} + EndGlobalSection +EndGlobal diff --git a/td-rs-xtask/msvc/RustOp.vcxproj b/td-rs-xtask/msvc/RustOp.vcxproj index 4387695..92b3bf9 100644 --- a/td-rs-xtask/msvc/RustOp.vcxproj +++ b/td-rs-xtask/msvc/RustOp.vcxproj @@ -1,104 +1,106 @@ - - - - - Debug - x64 - - - Release - x64 - - - - - - - - - - - - - - {3F5BEECD-FA36-459F-91B8-BB481A67EF44} - RustOp - Win32Proj - 10.0 - RustOp - - - - DynamicLibrary - Unicode - true - v143 - - - DynamicLibrary - Unicode - v143 - - - - - - - - - - - - - <_ProjectFileVersion>10.0.40219.1 - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - - - - Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;$(PreprocessorDefinitions);%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - ProgramDatabase - stdcpp17 - false - .\td-rs-base\src;$(AdditionalIncludeDirectories) - - - true - Windows - $(AdditionalLibraryDirectories) - synchronization.lib;python311.lib;bcrypt.lib;UserEnv.Lib;Ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;msvcrt.lib;ntdll.lib;.\target\x86_64-pc-windows-msvc\release\{{ OP_LIB_NAME }};$(PLUGIN);%(AdditionalDependencies) - - - - - WIN32;NDEBUG;_WINDOWS;_USRDLL;$(PreprocessorDefinitions);%(PreprocessorDefinitions) - MultiThreadedDLL - - - Level3 - ProgramDatabase - .\td-rs-base\src;$(AdditionalIncludeDirectories) - - - true - Windows - true - true - $(AdditionalLibraryDirectories) - synchronization.lib;python311.lib;bcrypt.lib;UserEnv.Lib;Ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;msvcrt.lib;ntdll.lib;.\target\x86_64-pc-windows-msvc\release\{{ OP_LIB_NAME }};$(PLUGIN);%(AdditionalDependencies) - - - - - - + + + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + {3F5BEECD-FA36-459F-91B8-BB481A67EF44} + RustOp + Win32Proj + 10.0 + RustOp + + + + DynamicLibrary + Unicode + true + v143 + + + DynamicLibrary + Unicode + v143 + + + +{{ CUDA_IMPORT_PROPS }} + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;$(PreprocessorDefinitions);%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + stdcpp17 + false + .\td-rs-base\src;{{ CUDA_INCLUDE_DIRS }};$(AdditionalIncludeDirectories) + + + true + Windows + {{ CUDA_LIB_DIRS }};$(AdditionalLibraryDirectories) + {{ CUDA_LIBS }};synchronization.lib;python311.lib;bcrypt.lib;UserEnv.Lib;Ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;msvcrt.lib;ntdll.lib;.\target\x86_64-pc-windows-msvc\release\{{ OP_LIB_NAME }};$(PLUGIN);%(AdditionalDependencies) + + + + + WIN32;NDEBUG;_WINDOWS;_USRDLL;$(PreprocessorDefinitions);%(PreprocessorDefinitions) + MultiThreadedDLL + + + Level3 + ProgramDatabase + .\td-rs-base\src;{{ CUDA_INCLUDE_DIRS }};$(AdditionalIncludeDirectories) + + + true + Windows + true + true + {{ CUDA_LIB_DIRS }};$(AdditionalLibraryDirectories) + {{ CUDA_LIBS }};synchronization.lib;python311.lib;bcrypt.lib;UserEnv.Lib;Ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;msvcrt.lib;ntdll.lib;opengl32.lib;dwmapi.lib;uxtheme.lib;dinput8.lib;dxguid.lib;setupapi.lib;winmm.lib;imm32.lib;oleacc.lib;version.lib;xinput.lib;hid.lib;d3d12.lib;dxgi.lib;d3dcompiler.lib;pdh.lib;psapi.lib;powrprof.lib;uiautomationcore.lib;windowsapp.lib;propsys.lib;.\target\x86_64-pc-windows-msvc\release\{{ OP_LIB_NAME }};$(PLUGIN);%(AdditionalDependencies) + + + + +{{ CUDA_IMPORT_TARGETS }} + + diff --git a/td-rs-xtask/msvc/RustOp.vcxproj.user b/td-rs-xtask/msvc/RustOp.vcxproj.user index 88a5509..0f14913 100644 --- a/td-rs-xtask/msvc/RustOp.vcxproj.user +++ b/td-rs-xtask/msvc/RustOp.vcxproj.user @@ -1,4 +1,4 @@ - - - + + + \ No newline at end of file diff --git a/td-rs-xtask/src/config.rs b/td-rs-xtask/src/config.rs index a9fcbee..4b6c6ff 100644 --- a/td-rs-xtask/src/config.rs +++ b/td-rs-xtask/src/config.rs @@ -1,61 +1,61 @@ -#[cfg(target_os = "windows")] -#[derive(serde::Deserialize, Debug)] -pub struct WindowsConfig { - pub(crate) plugin_folder: String, - pub(crate) python_include_dir: String, - pub(crate) python_lib_dir: String, -} - -#[cfg(target_os = "macos")] -#[derive(serde::Deserialize, Debug)] -pub struct MacOsConfig { - pub(crate) python_include_dir: String, - pub(crate) plugin_folder: String, -} - -#[derive(serde::Deserialize, Debug)] -pub struct Config { - #[cfg(target_os = "windows")] - pub(crate) windows: WindowsConfig, - #[cfg(target_os = "macos")] - pub(crate) macos: MacOsConfig, -} - -pub(crate) fn read_config() -> Config { - let config_path = std::path::Path::new("td-rs.toml"); - let config_file = std::fs::read_to_string(config_path).expect("Could not read td-rs.toml"); - let config = toml::from_str(&config_file).expect("Could not parse td-rs.toml"); - process_config(config) -} - -fn process_config(mut config: Config) -> Config { - // special handling for $HOME in path - #[cfg(target_os = "windows")] - if config.windows.plugin_folder.contains("$HOME") { - let home_dir = homedir::get_my_home() - .expect("Could not get home directory") - .expect("Could not get home directory"); - let plugin_folder = config.windows.plugin_folder.replace( - "$HOME", - home_dir - .to_str() - .expect("Could not convert home directory to string"), - ); - config.windows.plugin_folder = plugin_folder; - } - #[cfg(target_os = "macos")] - if config.macos.plugin_folder.contains("$HOME") { - let home_dir = homedir::get_my_home() - .expect("Could not get home directory") - .expect("Could not get home directory"); - let plugin_folder = config.macos.plugin_folder.replace( - "$HOME", - home_dir - .to_str() - .expect("Could not convert home directory to string"), - ); - config.macos.plugin_folder = plugin_folder; - } - - config -} +#[cfg(target_os = "windows")] +#[derive(serde::Deserialize, Debug)] +pub struct WindowsConfig { + pub(crate) plugin_folder: String, + pub(crate) python_include_dir: String, + pub(crate) python_lib_dir: String, +} + +#[cfg(target_os = "macos")] +#[derive(serde::Deserialize, Debug)] +pub struct MacOsConfig { + pub(crate) python_include_dir: String, + pub(crate) plugin_folder: String, +} + +#[derive(serde::Deserialize, Debug)] +pub struct Config { + #[cfg(target_os = "windows")] + pub(crate) windows: WindowsConfig, + #[cfg(target_os = "macos")] + pub(crate) macos: MacOsConfig, +} + +pub(crate) fn read_config() -> Config { + let config_path = std::path::Path::new("td-rs.toml"); + let config_file = std::fs::read_to_string(config_path).expect("Could not read td-rs.toml"); + let config = toml::from_str(&config_file).expect("Could not parse td-rs.toml"); + process_config(config) +} + +fn process_config(mut config: Config) -> Config { + // special handling for $HOME in path + #[cfg(target_os = "windows")] + if config.windows.plugin_folder.contains("$HOME") { + let home_dir = homedir::get_my_home() + .expect("Could not get home directory") + .expect("Could not get home directory"); + let plugin_folder = config.windows.plugin_folder.replace( + "$HOME", + home_dir + .to_str() + .expect("Could not convert home directory to string"), + ); + config.windows.plugin_folder = plugin_folder; + } + #[cfg(target_os = "macos")] + if config.macos.plugin_folder.contains("$HOME") { + let home_dir = homedir::get_my_home() + .expect("Could not get home directory") + .expect("Could not get home directory"); + let plugin_folder = config.macos.plugin_folder.replace( + "$HOME", + home_dir + .to_str() + .expect("Could not convert home directory to string"), + ); + config.macos.plugin_folder = plugin_folder; + } + + config +} diff --git a/td-rs-xtask/src/lib.rs b/td-rs-xtask/src/lib.rs index eacd03e..712aaee 100644 --- a/td-rs-xtask/src/lib.rs +++ b/td-rs-xtask/src/lib.rs @@ -1,71 +1,71 @@ -mod config; -#[cfg(target_os = "macos")] -mod macos; -mod metadata; -mod util; -#[cfg(target_os = "windows")] -mod windows; - -#[cfg(target_os = "macos")] -use crate::macos::{build_plugin, install_plugin}; -#[cfg(target_os = "windows")] -use crate::windows::{build_plugin, install_plugin}; -use anyhow::Context; -use std::env; - -use std::process::Command; - -pub use anyhow::Result; - -const PLUGIN_HOME: &str = "target/plugin"; - -pub fn build(packages: &[&str], args: &[&str]) -> Result<()> { - let package_args = packages.iter().flat_map(|package| ["-p", package]); - let mut cmd = Command::new("cargo") - .arg("build") - .args(package_args) - .args(args) - .spawn() - .with_context(|| format!("Could not call cargo to build {}", packages.join(", ")))?; - let status = cmd.wait()?; - if !status.success() { - anyhow::bail!("Could not build {}", packages.join(", ")); - } else { - Ok(()) - } -} - -pub fn main() -> anyhow::Result<()> { - let cmd = env::args() - .nth(1) - .with_context(|| "must provide command as first argument")?; - - let config = config::read_config(); - - match cmd.as_str() { - "build" | "install" => { - let plugin = env::args() - .nth(2) - .with_context(|| "must provide plugin as second argument")?; - let plugin_type = metadata::plugin_type(&plugin); - - match cmd.as_str() { - "build" => build_plugin(&config, &plugin, plugin_type)?, - "install" => install_plugin(&config, &plugin, plugin_type)?, - _ => {} - } - } - "list-plugins" => { - let plugins = metadata::list_plugins()?; - println!("Available Plugins:"); - for plugin in plugins { - println!(" - {}", plugin); - } - } - _ => { - return Err(anyhow::anyhow!("command must be 'build'")); - } - } - - Ok(()) -} +mod config; +#[cfg(target_os = "macos")] +mod macos; +mod metadata; +mod util; +#[cfg(target_os = "windows")] +mod windows; + +#[cfg(target_os = "macos")] +use crate::macos::{build_plugin, install_plugin}; +#[cfg(target_os = "windows")] +use crate::windows::{build_plugin, install_plugin}; +use anyhow::Context; +use std::env; + +use std::process::Command; + +pub use anyhow::Result; + +const PLUGIN_HOME: &str = "target/plugin"; + +pub fn build(packages: &[&str], args: &[&str]) -> Result<()> { + let package_args = packages.iter().flat_map(|package| ["-p", package]); + let mut cmd = Command::new("cargo") + .arg("build") + .args(package_args) + .args(args) + .spawn() + .with_context(|| format!("Could not call cargo to build {}", packages.join(", ")))?; + let status = cmd.wait()?; + if !status.success() { + anyhow::bail!("Could not build {}", packages.join(", ")); + } else { + Ok(()) + } +} + +pub fn main() -> anyhow::Result<()> { + let cmd = env::args() + .nth(1) + .with_context(|| "must provide command as first argument")?; + + let config = config::read_config(); + + match cmd.as_str() { + "build" | "install" => { + let plugin = env::args() + .nth(2) + .with_context(|| "must provide plugin as second argument")?; + let plugin_type = metadata::plugin_type(&plugin); + + match cmd.as_str() { + "build" => build_plugin(&config, &plugin, plugin_type)?, + "install" => install_plugin(&config, &plugin, plugin_type)?, + _ => {} + } + } + "list-plugins" => { + let plugins = metadata::list_plugins()?; + println!("Available Plugins:"); + for plugin in plugins { + println!(" - {}", plugin); + } + } + _ => { + return Err(anyhow::anyhow!("command must be 'build'")); + } + } + + Ok(()) +} diff --git a/td-rs-xtask/src/macos/mod.rs b/td-rs-xtask/src/macos/mod.rs index afe1c92..4f502cf 100644 --- a/td-rs-xtask/src/macos/mod.rs +++ b/td-rs-xtask/src/macos/mod.rs @@ -1,167 +1,167 @@ -use crate::config::Config; -use crate::metadata::PluginType; -use crate::util::ToTitleCase; -use crate::{build, PLUGIN_HOME}; -use anyhow::Context; -use fs_extra::dir::CopyOptions; -use std::path::{Path, PathBuf}; -use std::process::Command; - -pub(crate) fn install_plugin( - config: &Config, - plugin: &str, - _plugin_type: PluginType, -) -> anyhow::Result<()> { - let plugin = &plugin.replace('-', "_"); - let plugin_target_path = plugin_target_path(plugin).join(format!("{plugin}.plugin")); - let td_plugin_folder = &config.macos.plugin_folder; - std::fs::create_dir_all(&td_plugin_folder).context("Could not create plugin directory")?; - println!( - "Installing plugin {:?} to {}", - plugin_target_path, td_plugin_folder - ); - fs_extra::dir::copy( - &plugin_target_path, - td_plugin_folder, - &CopyOptions::new().overwrite(true), - ) - .context("Could not move plugin to TouchDesigner plugin directory")?; - Ok(()) -} - -pub(crate) fn build_plugin( - config: &Config, - plugin: &str, - plugin_type: PluginType, -) -> anyhow::Result<()> { - let target = if cfg!(target_arch = "x86_64") { - "x86_64-apple-darwin" - } else { - "aarch64-apple-darwin" - }; - build( - &[plugin, plugin_type.to_plugin_name()], - &["--release", &format!("--target={target}")], - )?; - - let is_python_enabled = crate::metadata::is_python_enabled(plugin, &plugin_type); - let plugin = &plugin.replace('-', "_"); - let path = pbxproj_path(plugin); - - println!("Writing xcode project to {:?}", path); - write_xcodeproj(target, plugin, &plugin_type, &path)?; - println!("Building xcode project"); - build_xcode(config, plugin, is_python_enabled)?; - println!("Moving plugin to {:?}", PLUGIN_HOME); - move_plugin(plugin, &path)?; - Ok(()) -} - -fn move_plugin(plugin: &str, path: &PathBuf) -> anyhow::Result<()> { - fs_extra::dir::remove(path.parent().unwrap()) - .context("Could not remove xcode project directory")?; - let plugin_build_path = format!("build/Release/{plugin}.plugin"); - let plugin_target_path = plugin_target_path(plugin); - std::fs::create_dir_all(&plugin_target_path).context("Could not create plugin directory")?; - fs_extra::dir::remove(plugin_target_path.join(format!("{plugin}.plugin"))) - .context("Could not remove plugin directory")?; - fs_extra::dir::move_dir(plugin_build_path, &plugin_target_path, &CopyOptions::new()) - .context("Could not move plugin to target directory")?; - Ok(()) -} - -fn plugin_target_path(plugin: &str) -> PathBuf { - let plugin_target_path = Path::new(PLUGIN_HOME).join(plugin); - plugin_target_path -} - -fn pbxproj_path(plugin: &str) -> PathBuf { - let mut path = PathBuf::from(format!("{plugin}.xcodeproj")); - path.push("project.pbxproj"); - path -} - -fn build_xcode(config: &Config, plugin: &str, is_python_enabled: bool) -> anyhow::Result<()> { - let mut cmd = Command::new("xcodebuild") - .arg("-project") - .arg(format!("./{plugin}.xcodeproj")) - .arg("clean") - .arg("build") - .arg(format!( - "PYTHON_INCLUDE_DIR={}", - config.macos.python_include_dir - )) - .arg(if is_python_enabled { - "EXTRA_CFLAGS=-DPYTHON_ENABLED" - } else { - "FOO=BAR" - }) - .spawn() - .expect("ls command failed to start"); - if !cmd.wait()?.success() { - anyhow::bail!("Could not build xcode project"); - } - Ok(()) -} - -fn write_xcodeproj( - target: &str, - plugin: &str, - plugin_type: &PluginType, - path: &PathBuf, -) -> anyhow::Result<()> { - std::fs::create_dir_all(path.parent().unwrap()) - .context("Could not create xcode project directory")?; - let short_title = plugin_type.to_short_name().to_title_case(); - let short_upper = plugin_type.to_short_name().to_uppercase(); - let op_path = plugin_type.to_plugin_name(); - - let project = std::fs::read_to_string("td-rs-xtask/xcode/project.pbxproj") - .expect("Could not read xcode project") - .replace("{{ LIB_NAME }}", &format!("lib{plugin}.a")) - .replace( - "{{ LIB_PATH }}", - &format!("target/{}/release/lib{plugin}.a", target), - ) - .replace("{{ PLUGIN_FILE_NAME }}", &format!("{plugin}.plugin")) - .replace("{{ PLUGIN_NAME }}", &plugin) - .replace("{{ PLUGIN_PRODUCT_NAME }}", &plugin) - .replace( - "{{ TD_OP_H_PATH }}", - &format!("{}/src/{}_CPlusPlusBase.h", op_path, short_upper), - ) - .replace( - "{{ TD_OP_H_NAME }}", - &format!("{}_CPlusPlusBase.h", short_upper), - ) - .replace( - "{{ PLUGIN_CPP_NAME }}", - &format!("Rust{}Plugin.cpp", short_title), - ) - .replace( - "{{ PLUGIN_CPP_PATH }}", - &format!("{}/src/Rust{}Plugin.cpp", op_path, short_title), - ) - .replace( - "{{ PLUGIN_H_NAME }}", - &format!("Rust{}Plugin.h", short_title), - ) - .replace( - "{{ PLUGIN_H_PATH }}", - &format!("{}/src/Rust{}Plugin.h", op_path, short_title), - ) - .replace( - "{{ OP_LIB_NAME }}", - &format!("lib{}.a", op_path.replace("-", "_")), - ) - .replace( - "{{ OP_LIB_PATH }}", - &format!( - "target/{}/release/lib{}.a", - target, - op_path.replace("-", "_") - ), - ); - std::fs::write(path, project)?; - Ok(()) -} +use crate::config::Config; +use crate::metadata::PluginType; +use crate::util::ToTitleCase; +use crate::{build, PLUGIN_HOME}; +use anyhow::Context; +use fs_extra::dir::CopyOptions; +use std::path::{Path, PathBuf}; +use std::process::Command; + +pub(crate) fn install_plugin( + config: &Config, + plugin: &str, + _plugin_type: PluginType, +) -> anyhow::Result<()> { + let plugin = &plugin.replace('-', "_"); + let plugin_target_path = plugin_target_path(plugin).join(format!("{plugin}.plugin")); + let td_plugin_folder = &config.macos.plugin_folder; + std::fs::create_dir_all(&td_plugin_folder).context("Could not create plugin directory")?; + println!( + "Installing plugin {:?} to {}", + plugin_target_path, td_plugin_folder + ); + fs_extra::dir::copy( + &plugin_target_path, + td_plugin_folder, + &CopyOptions::new().overwrite(true), + ) + .context("Could not move plugin to TouchDesigner plugin directory")?; + Ok(()) +} + +pub(crate) fn build_plugin( + config: &Config, + plugin: &str, + plugin_type: PluginType, +) -> anyhow::Result<()> { + let target = if cfg!(target_arch = "x86_64") { + "x86_64-apple-darwin" + } else { + "aarch64-apple-darwin" + }; + build( + &[plugin, plugin_type.to_plugin_name()], + &["--release", &format!("--target={target}")], + )?; + + let is_python_enabled = crate::metadata::is_python_enabled(plugin, &plugin_type); + let plugin = &plugin.replace('-', "_"); + let path = pbxproj_path(plugin); + + println!("Writing xcode project to {:?}", path); + write_xcodeproj(target, plugin, &plugin_type, &path)?; + println!("Building xcode project"); + build_xcode(config, plugin, is_python_enabled)?; + println!("Moving plugin to {:?}", PLUGIN_HOME); + move_plugin(plugin, &path)?; + Ok(()) +} + +fn move_plugin(plugin: &str, path: &PathBuf) -> anyhow::Result<()> { + fs_extra::dir::remove(path.parent().unwrap()) + .context("Could not remove xcode project directory")?; + let plugin_build_path = format!("build/Release/{plugin}.plugin"); + let plugin_target_path = plugin_target_path(plugin); + std::fs::create_dir_all(&plugin_target_path).context("Could not create plugin directory")?; + fs_extra::dir::remove(plugin_target_path.join(format!("{plugin}.plugin"))) + .context("Could not remove plugin directory")?; + fs_extra::dir::move_dir(plugin_build_path, &plugin_target_path, &CopyOptions::new()) + .context("Could not move plugin to target directory")?; + Ok(()) +} + +fn plugin_target_path(plugin: &str) -> PathBuf { + let plugin_target_path = Path::new(PLUGIN_HOME).join(plugin); + plugin_target_path +} + +fn pbxproj_path(plugin: &str) -> PathBuf { + let mut path = PathBuf::from(format!("{plugin}.xcodeproj")); + path.push("project.pbxproj"); + path +} + +fn build_xcode(config: &Config, plugin: &str, is_python_enabled: bool) -> anyhow::Result<()> { + let mut cmd = Command::new("xcodebuild") + .arg("-project") + .arg(format!("./{plugin}.xcodeproj")) + .arg("clean") + .arg("build") + .arg(format!( + "PYTHON_INCLUDE_DIR={}", + config.macos.python_include_dir + )) + .arg(if is_python_enabled { + "EXTRA_CFLAGS=-DPYTHON_ENABLED" + } else { + "FOO=BAR" + }) + .spawn() + .expect("ls command failed to start"); + if !cmd.wait()?.success() { + anyhow::bail!("Could not build xcode project"); + } + Ok(()) +} + +fn write_xcodeproj( + target: &str, + plugin: &str, + plugin_type: &PluginType, + path: &PathBuf, +) -> anyhow::Result<()> { + std::fs::create_dir_all(path.parent().unwrap()) + .context("Could not create xcode project directory")?; + let short_title = plugin_type.to_short_name().to_title_case(); + let short_upper = plugin_type.to_short_name().to_uppercase(); + let op_path = plugin_type.to_plugin_name(); + + let project = std::fs::read_to_string("td-rs-xtask/xcode/project.pbxproj") + .expect("Could not read xcode project") + .replace("{{ LIB_NAME }}", &format!("lib{plugin}.a")) + .replace( + "{{ LIB_PATH }}", + &format!("target/{}/release/lib{plugin}.a", target), + ) + .replace("{{ PLUGIN_FILE_NAME }}", &format!("{plugin}.plugin")) + .replace("{{ PLUGIN_NAME }}", &plugin) + .replace("{{ PLUGIN_PRODUCT_NAME }}", &plugin) + .replace( + "{{ TD_OP_H_PATH }}", + &format!("{}/src/{}_CPlusPlusBase.h", op_path, short_upper), + ) + .replace( + "{{ TD_OP_H_NAME }}", + &format!("{}_CPlusPlusBase.h", short_upper), + ) + .replace( + "{{ PLUGIN_CPP_NAME }}", + &format!("Rust{}Plugin.cpp", short_title), + ) + .replace( + "{{ PLUGIN_CPP_PATH }}", + &format!("{}/src/Rust{}Plugin.cpp", op_path, short_title), + ) + .replace( + "{{ PLUGIN_H_NAME }}", + &format!("Rust{}Plugin.h", short_title), + ) + .replace( + "{{ PLUGIN_H_PATH }}", + &format!("{}/src/Rust{}Plugin.h", op_path, short_title), + ) + .replace( + "{{ OP_LIB_NAME }}", + &format!("lib{}.a", op_path.replace("-", "_")), + ) + .replace( + "{{ OP_LIB_PATH }}", + &format!( + "target/{}/release/lib{}.a", + target, + op_path.replace("-", "_") + ), + ); + std::fs::write(path, project)?; + Ok(()) +} diff --git a/td-rs-xtask/src/metadata.rs b/td-rs-xtask/src/metadata.rs index f0faa60..f08d73c 100644 --- a/td-rs-xtask/src/metadata.rs +++ b/td-rs-xtask/src/metadata.rs @@ -1,121 +1,135 @@ -use cargo_metadata::{Metadata, MetadataCommand, Package}; -use std::path::Path; - -pub enum PluginType { - Chop, - Sop, - Dat, - Top, -} - -impl PluginType { - pub(crate) fn to_plugin_name(&self) -> &str { - match self { - Self::Chop => "td-rs-chop", - Self::Sop => "td-rs-sop", - Self::Dat => "td-rs-dat", - Self::Top => "td-rs-top", - } - } - - pub(crate) fn to_short_name(&self) -> &str { - match self { - Self::Chop => "chop", - Self::Sop => "sop", - Self::Dat => "dat", - Self::Top => "top", - } - } -} - -pub fn plugin_type(plugin: &str) -> PluginType { - let package_name = plugin; - let metadata = fetch_cargo_metadata(); - let package = metadata - .packages - .into_iter() - .find(|package| package.name == package_name); - - if let Some(package) = package { - let plugin_type = package - .metadata - .get("td-rs") - .expect("Didn't find td-rs metadata in Cargo.toml. Please add [package.metadata.td-rs] to your cargo manifest to specify the type of plugin.") - .get("type") - .expect("Could not find type in td-rs metadata. Please add [package.metadata.td-rs.type] to your cargo manifest to specify the type of plugin.") - .as_str() - .expect("Could not parse type in td-rs metadata. Please add [package.metadata.td-rs.type] as a string to your cargo manifest to specify the type of plugin."); - match plugin_type { - "chop" => PluginType::Chop, - "sop" => PluginType::Sop, - "dat" => PluginType::Dat, - "top" => PluginType::Top, - _ => panic!("Unknown plugin type: {}", plugin_type), - } - } else { - panic!("Package not found: {}", package_name); - } -} - -fn fetch_cargo_metadata() -> Metadata { - MetadataCommand::new() - .exec() - .expect("Failed to fetch cargo metadata") -} - -pub(crate) fn fetch_cargo_workspace_package(package: &str) -> anyhow::Result { - let package_name = package; - let metadata = fetch_cargo_metadata(); - let package = metadata - .packages - .into_iter() - .find(|package| package.name == package_name); - package.ok_or(anyhow::anyhow!("Package not found: {}", package_name)) -} - -#[cfg(not(target_os = "windows"))] -fn adjust_canonicalization>(p: P) -> String { - p.as_ref().display().to_string() -} - -#[cfg(target_os = "windows")] -fn adjust_canonicalization>(p: P) -> String { - const VERBATIM_PREFIX: &str = r#"\\?\"#; - let p = p.as_ref().display().to_string(); - if p.starts_with(VERBATIM_PREFIX) { - p[VERBATIM_PREFIX.len()..].to_string() - } else { - p - } -} - -pub(crate) fn list_plugins() -> anyhow::Result> { - let meta = fetch_cargo_metadata(); - let plugin_dir = adjust_canonicalization( - Path::new("./plugins") - .canonicalize() - .expect("Could not canonicalize plugin dir"), - ); - println!("Plugin dir: {:?}\n", plugin_dir); - let ws_members = meta - .workspace_packages() - .iter() - .filter(|package| package.manifest_path.starts_with(&plugin_dir)) - .map(|package| package.name.clone()) - .collect::>(); - Ok(ws_members) -} - -pub fn is_python_enabled(plugin: &str, plugin_type: &PluginType) -> bool { - let pkg = crate::metadata::fetch_cargo_workspace_package(plugin).unwrap(); - let parent_dep = pkg - .dependencies - .iter() - .find(|dep| dep.name == plugin_type.to_plugin_name()) - .expect("Could not find plugin dependency"); - parent_dep - .features - .iter() - .find(|feature| feature == &"python") - .is_some() -} +use cargo_metadata::{Metadata, MetadataCommand, Package}; +use std::path::Path; + +pub enum PluginType { + Chop, + Sop, + Dat, + Top, +} + +impl PluginType { + pub(crate) fn to_plugin_name(&self) -> &str { + match self { + Self::Chop => "td-rs-chop", + Self::Sop => "td-rs-sop", + Self::Dat => "td-rs-dat", + Self::Top => "td-rs-top", + } + } + + pub(crate) fn to_short_name(&self) -> &str { + match self { + Self::Chop => "chop", + Self::Sop => "sop", + Self::Dat => "dat", + Self::Top => "top", + } + } +} + +pub fn plugin_type(plugin: &str) -> PluginType { + let package_name = plugin; + let metadata = fetch_cargo_metadata(); + let package = metadata + .packages + .into_iter() + .find(|package| package.name == package_name); + + if let Some(package) = package { + let plugin_type = package + .metadata + .get("td-rs") + .expect("Didn't find td-rs metadata in Cargo.toml. Please add [package.metadata.td-rs] to your cargo manifest to specify the type of plugin.") + .get("type") + .expect("Could not find type in td-rs metadata. Please add [package.metadata.td-rs.type] to your cargo manifest to specify the type of plugin.") + .as_str() + .expect("Could not parse type in td-rs metadata. Please add [package.metadata.td-rs.type] as a string to your cargo manifest to specify the type of plugin."); + match plugin_type { + "chop" => PluginType::Chop, + "sop" => PluginType::Sop, + "dat" => PluginType::Dat, + "top" => PluginType::Top, + _ => panic!("Unknown plugin type: {}", plugin_type), + } + } else { + panic!("Package not found: {}", package_name); + } +} + +fn fetch_cargo_metadata() -> Metadata { + MetadataCommand::new() + .exec() + .expect("Failed to fetch cargo metadata") +} + +pub(crate) fn fetch_cargo_workspace_package(package: &str) -> anyhow::Result { + let package_name = package; + let metadata = fetch_cargo_metadata(); + let package = metadata + .packages + .into_iter() + .find(|package| package.name == package_name); + package.ok_or(anyhow::anyhow!("Package not found: {}", package_name)) +} + +#[cfg(not(target_os = "windows"))] +fn adjust_canonicalization>(p: P) -> String { + p.as_ref().display().to_string() +} + +#[cfg(target_os = "windows")] +fn adjust_canonicalization>(p: P) -> String { + const VERBATIM_PREFIX: &str = r#"\\?\"#; + let p = p.as_ref().display().to_string(); + if p.starts_with(VERBATIM_PREFIX) { + p[VERBATIM_PREFIX.len()..].to_string() + } else { + p + } +} + +pub(crate) fn list_plugins() -> anyhow::Result> { + let meta = fetch_cargo_metadata(); + let plugin_dir = adjust_canonicalization( + Path::new("./plugins") + .canonicalize() + .expect("Could not canonicalize plugin dir"), + ); + println!("Plugin dir: {:?}\n", plugin_dir); + let ws_members = meta + .workspace_packages() + .iter() + .filter(|package| package.manifest_path.starts_with(&plugin_dir)) + .map(|package| package.name.clone()) + .collect::>(); + Ok(ws_members) +} + +pub fn is_python_enabled(plugin: &str, plugin_type: &PluginType) -> bool { + let pkg = crate::metadata::fetch_cargo_workspace_package(plugin).unwrap(); + let parent_dep = pkg + .dependencies + .iter() + .find(|dep| dep.name == plugin_type.to_plugin_name()) + .expect("Could not find plugin dependency"); + parent_dep + .features + .iter() + .find(|feature| feature == &"python") + .is_some() +} + +pub fn is_cuda_enabled(plugin: &str, plugin_type: &PluginType) -> bool { + let pkg = crate::metadata::fetch_cargo_workspace_package(plugin).unwrap(); + let parent_dep = pkg + .dependencies + .iter() + .find(|dep| dep.name == plugin_type.to_plugin_name()) + .expect("Could not find plugin dependency"); + parent_dep + .features + .iter() + .find(|feature| feature == &"cuda") + .is_some() +} diff --git a/td-rs-xtask/src/util.rs b/td-rs-xtask/src/util.rs index 820b024..7e8c5d2 100644 --- a/td-rs-xtask/src/util.rs +++ b/td-rs-xtask/src/util.rs @@ -1,13 +1,13 @@ -pub trait ToTitleCase { - fn to_title_case(&self) -> String; -} - -impl ToTitleCase for str { - fn to_title_case(&self) -> String { - let mut c = self.chars(); - match c.next() { - None => String::new(), - Some(f) => f.to_uppercase().collect::() + c.as_str(), - } - } -} +pub trait ToTitleCase { + fn to_title_case(&self) -> String; +} + +impl ToTitleCase for str { + fn to_title_case(&self) -> String { + let mut c = self.chars(); + match c.next() { + None => String::new(), + Some(f) => f.to_uppercase().collect::() + c.as_str(), + } + } +} diff --git a/td-rs-xtask/src/windows/mod.rs b/td-rs-xtask/src/windows/mod.rs index 603ea4c..38a3a74 100644 --- a/td-rs-xtask/src/windows/mod.rs +++ b/td-rs-xtask/src/windows/mod.rs @@ -11,7 +11,7 @@ use std::process::{Command, Stdio}; pub(crate) fn install_plugin( config: &Config, plugin: &str, - plugin_type: PluginType, + _plugin_type: PluginType, ) -> anyhow::Result<()> { let plugin_target_path = plugin_target_path(plugin); let td_plugin_folder = &config.windows.plugin_folder; @@ -57,6 +57,22 @@ pub(crate) fn build_plugin( let short_title = plugin_type.to_short_name().to_title_case(); let short_upper = plugin_type.to_short_name().to_uppercase(); let op_path = plugin_type.to_plugin_name(); + let is_cuda_enabled = crate::metadata::is_cuda_enabled(plugin, &plugin_type); + + // Configure CUDA settings + let (cuda_import_props, cuda_import_targets, cuda_include_dirs, cuda_lib_dirs, cuda_libs) = + if is_cuda_enabled { + ( + "", + "", + "$(CudaToolkitIncludeDir)", + "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v12.8\\lib\\x64", + "cuda.lib;cudart.lib;nvrtc.lib", + ) + } else { + ("", "", "", "", "") + }; + let vcxproj = std::fs::read_to_string(format!("./{solution_name}.vcxproj"))? .replace( "{{ OP_LIB_NAME }}", @@ -73,7 +89,12 @@ pub(crate) fn build_plugin( .replace( "{{ PLUGIN_CPP_PATH }}", &format!("{}/src/Rust{}Plugin.cpp", op_path, short_title), - ); + ) + .replace("{{ CUDA_IMPORT_PROPS }}", cuda_import_props) + .replace("{{ CUDA_IMPORT_TARGETS }}", cuda_import_targets) + .replace("{{ CUDA_INCLUDE_DIRS }}", cuda_include_dirs) + .replace("{{ CUDA_LIB_DIRS }}", cuda_lib_dirs) + .replace("{{ CUDA_LIBS }}", cuda_libs); std::fs::write(format!("./{solution_name}.vcxproj"), vcxproj)?; let is_python_enabled = crate::metadata::is_python_enabled(plugin, &plugin_type); @@ -86,7 +107,7 @@ pub(crate) fn build_plugin( Ok(()) } -fn move_plugin(plugin: &str, plugin_type: &PluginType) -> anyhow::Result<()> { +fn move_plugin(plugin: &str, _plugin_type: &PluginType) -> anyhow::Result<()> { let dll_name = "RustOp"; let plugin_build_path = format!("./Release/{dll_name}.dll"); diff --git a/td-rs-xtask/xcode/project.pbxproj b/td-rs-xtask/xcode/project.pbxproj index f246f26..a37fded 100644 --- a/td-rs-xtask/xcode/project.pbxproj +++ b/td-rs-xtask/xcode/project.pbxproj @@ -1,729 +1,729 @@ - - - - - archiveVersion - 1 - classes - - objectVersion - 46 - objects - - 6A7F74C12D40EA7500969072 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - SystemConfiguration.framework - path - System/Library/Frameworks/SystemConfiguration.framework - sourceTree - SDKROOT - - 6A7F74C22D40EA7500969072 - - fileRef - 6A7F74C12D40EA7500969072 - isa - PBXBuildFile - - 6A99B73F29FD8AD100197036 - - fileEncoding - 4 - isa - PBXFileReference - lastKnownFileType - sourcecode.cpp.cpp - name - {{ PLUGIN_CPP_NAME }} - path - {{ PLUGIN_CPP_PATH }} - sourceTree - <group> - - 6A99B74029FD8AD100197036 - - fileEncoding - 4 - isa - PBXFileReference - lastKnownFileType - sourcecode.c.h - name - {{ PLUGIN_H_NAME }} - path - {{ PLUGIN_H_PATH }} - sourceTree - <group> - - 6A99B74129FD8AD100197036 - - fileRef - 6A99B73F29FD8AD100197036 - isa - PBXBuildFile - - 6A99B74229FD9B9700197036 - - isa - PBXGroup - name - Products - sourceTree - <group> - - 6AD906B42AE10A9400997BA1 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - Python.framework - path - /Applications/TouchDesigner.app/Contents/Frameworks/Python.framework - sourceTree - <absolute> - - 6AD906B42AE10A9400997BA2 - - isa - PBXFileReference - lastKnownFileType - wrapper.framework - name - Python.framework - path - /System/Library/Frameworks/CoreFoundation.framework - sourceTree - <absolute> - - 6AD906B52AE10A9400997BA1 - - fileRef - 6AD906B42AE10A9400997BA1 - isa - PBXBuildFile - - 6AD906B52AE10A9400997BA2 - - fileRef - 6AD906B42AE10A9400997BA2 - isa - PBXBuildFile - - 9E4ACB8B299AC54200A2B1CE - - isa - PBXFileReference - lastKnownFileType - archive.ar - name - {{ LIB_NAME }} - path - {{ LIB_PATH }} - sourceTree - <group> - - 9E4ACB8C299AC54200A2B1CE - - fileRef - 9E4ACB8B299AC54200A2B1CE - isa - PBXBuildFile - - 9ED7E4DF2999F4C9001F2445 - - isa - PBXFileReference - lastKnownFileType - archive.ar - name - {{ OP_LIB_NAME }} - path - {{ OP_LIB_PATH }} - sourceTree - <group> - - 9ED7E4E02999F4C9001F2445 - - fileRef - 9ED7E4DF2999F4C9001F2445 - isa - PBXBuildFile - - B9369E722741736D00EA7D98 - - children - - 6A7F74C12D40EA7500969072 - 6AD906B42AE10A9400997BA1 - 6AD906B42AE10A9400997BA2 - 9E4ACB8B299AC54200A2B1CE - 9ED7E4DF2999F4C9001F2445 - - isa - PBXGroup - name - Frameworks - sourceTree - <group> - - E23329CD1DF092AD0002B4FE - - children - - 6A99B73F29FD8AD100197036 - 6A99B74029FD8AD100197036 - E23329DF1DF092C90002B4FE - E23329E01DF092C90002B4FE - E23329D91DF092AD0002B4FE - E23329D71DF092AD0002B4FE - B9369E722741736D00EA7D98 - - isa - PBXGroup - sourceTree - <group> - - E23329CE1DF092AD0002B4FE - - attributes - - LastUpgradeCheck - 1420 - ORGANIZATIONNAME - Derivative - TargetAttributes - - E23329D51DF092AD0002B4FE - - CreatedOnToolsVersion - 8.0 - ProvisioningStyle - Automatic - - - - buildConfigurationList - E23329D11DF092AD0002B4FE - compatibilityVersion - Xcode 3.2 - developmentRegion - en - hasScannedForEncodings - 0 - isa - PBXProject - knownRegions - - en - Base - - mainGroup - E23329CD1DF092AD0002B4FE - productRefGroup - E23329D71DF092AD0002B4FE - projectDirPath - - projectReferences - - - ProductGroup - 6A99B74229FD9B9700197036 - ProjectRef - E23329D91DF092AD0002B4FE - - - projectRoot - - targets - - E23329D51DF092AD0002B4FE - - - E23329D11DF092AD0002B4FE - - buildConfigurations - - E23329DA1DF092AD0002B4FE - E23329DB1DF092AD0002B4FE - - defaultConfigurationIsVisible - 0 - defaultConfigurationName - Release - isa - XCConfigurationList - - E23329D21DF092AD0002B4FE - - buildActionMask - 2147483647 - files - - 6A99B74129FD8AD100197036 - - isa - PBXSourcesBuildPhase - runOnlyForDeploymentPostprocessing - 0 - - E23329D31DF092AD0002B4FE - - buildActionMask - 2147483647 - files - - 6A7F74C22D40EA7500969072 - 6AD906B52AE10A9400997BA1 - 6AD906B52AE10A9400997BA2 - 9E4ACB8C299AC54200A2B1CE - 9ED7E4E02999F4C9001F2445 - - isa - PBXFrameworksBuildPhase - runOnlyForDeploymentPostprocessing - 0 - - E23329D41DF092AD0002B4FE - - buildActionMask - 2147483647 - files - - isa - PBXResourcesBuildPhase - runOnlyForDeploymentPostprocessing - 0 - - E23329D51DF092AD0002B4FE - - buildConfigurationList - E23329DC1DF092AD0002B4FE - buildPhases - - E23329D21DF092AD0002B4FE - E23329D31DF092AD0002B4FE - E23329D41DF092AD0002B4FE - - buildRules - - dependencies - - isa - PBXNativeTarget - name - {{ PLUGIN_NAME }} - productName - {{ PLUGIN_PRODUCT_NAME }} - productReference - E23329D61DF092AD0002B4FE - productType - com.apple.product-type.bundle - - E23329D61DF092AD0002B4FE - - explicitFileType - wrapper.cfbundle - includeInIndex - 0 - isa - PBXFileReference - path - {{ PLUGIN_FILE_NAME }} - sourceTree - BUILT_PRODUCTS_DIR - - E23329D71DF092AD0002B4FE - - children - - E23329D61DF092AD0002B4FE - - isa - PBXGroup - name - Products - sourceTree - <group> - - E23329D91DF092AD0002B4FE - - isa - PBXFileReference - lastKnownFileType - wrapper.pb-project - path - sin.xcodeproj - sourceTree - SOURCE_ROOT - - E23329DA1DF092AD0002B4FE - - buildSettings - - ALWAYS_SEARCH_USER_PATHS - NO - ARCHS - arm64 - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED - YES - CLANG_ANALYZER_NONNULL - YES - CLANG_CXX_LANGUAGE_STANDARD - gnu++0x - CLANG_CXX_LIBRARY - libc++ - CLANG_ENABLE_MODULES - YES - CLANG_ENABLE_OBJC_ARC - YES - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING - YES - CLANG_WARN_BOOL_CONVERSION - YES - CLANG_WARN_COMMA - YES - CLANG_WARN_CONSTANT_CONVERSION - YES - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS - YES - CLANG_WARN_DIRECT_OBJC_ISA_USAGE - YES_ERROR - CLANG_WARN_DOCUMENTATION_COMMENTS - YES - CLANG_WARN_EMPTY_BODY - YES - CLANG_WARN_ENUM_CONVERSION - YES - CLANG_WARN_INFINITE_RECURSION - YES - CLANG_WARN_INT_CONVERSION - YES - CLANG_WARN_NON_LITERAL_NULL_CONVERSION - YES - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF - YES - CLANG_WARN_OBJC_LITERAL_CONVERSION - YES - CLANG_WARN_OBJC_ROOT_CLASS - YES_ERROR - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER - YES - CLANG_WARN_RANGE_LOOP_ANALYSIS - YES - CLANG_WARN_STRICT_PROTOTYPES - YES - CLANG_WARN_SUSPICIOUS_MOVE - YES - CLANG_WARN_SUSPICIOUS_MOVES - YES - CLANG_WARN_UNREACHABLE_CODE - YES - CLANG_WARN__DUPLICATE_METHOD_MATCH - YES - CODE_SIGN_IDENTITY - - - COPY_PHASE_STRIP - NO - DEAD_CODE_STRIPPING - YES - DEBUG_INFORMATION_FORMAT - dwarf - ENABLE_STRICT_OBJC_MSGSEND - YES - ENABLE_TESTABILITY - YES - GCC_C_LANGUAGE_STANDARD - gnu99 - GCC_DYNAMIC_NO_PIC - NO - GCC_NO_COMMON_BLOCKS - YES - GCC_OPTIMIZATION_LEVEL - 0 - GCC_PREPROCESSOR_DEFINITIONS - - DEBUG=1 - $(inherited) - - GCC_WARN_64_TO_32_BIT_CONVERSION - YES - GCC_WARN_ABOUT_RETURN_TYPE - YES_ERROR - GCC_WARN_UNDECLARED_SELECTOR - YES - GCC_WARN_UNINITIALIZED_AUTOS - YES_AGGRESSIVE - GCC_WARN_UNUSED_FUNCTION - YES - GCC_WARN_UNUSED_VARIABLE - YES - MACOSX_DEPLOYMENT_TARGET - 12.0 - MTL_ENABLE_DEBUG_INFO - YES - ONLY_ACTIVE_ARCH - YES - SDKROOT - macosx - - isa - XCBuildConfiguration - name - Debug - - E23329DB1DF092AD0002B4FE - - buildSettings - - ALWAYS_SEARCH_USER_PATHS - NO - ARCHS - arm64 - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED - YES - CLANG_ANALYZER_NONNULL - YES - CLANG_CXX_LANGUAGE_STANDARD - gnu++0x - CLANG_CXX_LIBRARY - libc++ - CLANG_ENABLE_MODULES - YES - CLANG_ENABLE_OBJC_ARC - YES - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING - YES - CLANG_WARN_BOOL_CONVERSION - YES - CLANG_WARN_COMMA - YES - CLANG_WARN_CONSTANT_CONVERSION - YES - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS - YES - CLANG_WARN_DIRECT_OBJC_ISA_USAGE - YES_ERROR - CLANG_WARN_DOCUMENTATION_COMMENTS - YES - CLANG_WARN_EMPTY_BODY - YES - CLANG_WARN_ENUM_CONVERSION - YES - CLANG_WARN_INFINITE_RECURSION - YES - CLANG_WARN_INT_CONVERSION - YES - CLANG_WARN_NON_LITERAL_NULL_CONVERSION - YES - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF - YES - CLANG_WARN_OBJC_LITERAL_CONVERSION - YES - CLANG_WARN_OBJC_ROOT_CLASS - YES_ERROR - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER - YES - CLANG_WARN_RANGE_LOOP_ANALYSIS - YES - CLANG_WARN_STRICT_PROTOTYPES - YES - CLANG_WARN_SUSPICIOUS_MOVE - YES - CLANG_WARN_SUSPICIOUS_MOVES - YES - CLANG_WARN_UNREACHABLE_CODE - YES - CLANG_WARN__DUPLICATE_METHOD_MATCH - YES - CODE_SIGN_IDENTITY - - - COPY_PHASE_STRIP - NO - DEAD_CODE_STRIPPING - YES - DEBUG_INFORMATION_FORMAT - dwarf-with-dsym - ENABLE_NS_ASSERTIONS - NO - ENABLE_STRICT_OBJC_MSGSEND - YES - GCC_C_LANGUAGE_STANDARD - gnu99 - GCC_NO_COMMON_BLOCKS - YES - GCC_WARN_64_TO_32_BIT_CONVERSION - YES - GCC_WARN_ABOUT_RETURN_TYPE - YES_ERROR - GCC_WARN_UNDECLARED_SELECTOR - YES - GCC_WARN_UNINITIALIZED_AUTOS - YES_AGGRESSIVE - GCC_WARN_UNUSED_FUNCTION - YES - GCC_WARN_UNUSED_VARIABLE - YES - MACOSX_DEPLOYMENT_TARGET - 12.0 - MTL_ENABLE_DEBUG_INFO - NO - ONLY_ACTIVE_ARCH - NO - SDKROOT - macosx - - isa - XCBuildConfiguration - name - Release - - E23329DC1DF092AD0002B4FE - - buildConfigurations - - E23329DD1DF092AD0002B4FE - E23329DE1DF092AD0002B4FE - - defaultConfigurationIsVisible - 0 - defaultConfigurationName - Release - isa - XCConfigurationList - - E23329DD1DF092AD0002B4FE - - buildSettings - - ALWAYS_SEARCH_USER_PATHS - YES - ARCHS - arm64 - CLANG_CXX_LANGUAGE_STANDARD - c++17 - COMBINE_HIDPI_IMAGES - YES - DEAD_CODE_STRIPPING - YES - FRAMEWORK_SEARCH_PATHS - /Applications/TouchDesigner.app/Contents/Frameworks - INFOPLIST_FILE - $(SRCROOT)/Info.plist - INSTALL_PATH - / - LIBRARY_SEARCH_PATHS - - $(inherited) - $(PROJECT_DIR) - $(PROJECT_DIR)/target/aarch64-apple-darwin/cxxbridge/** - $(PROJECT_DIR)/target/aarch64-apple-darwin/release - $(PYTHON_INCLUDE_DIR) - - OTHER_CFLAGS - - -I$(PROJECT_DIR)/target/aarch64-apple-darwin/cxxbridge - -I$(PROJECT_DIR)/td-rs-base/src - -I$(PYTHON_INCLUDE_DIR) - $(EXTRA_CFLAGS) - - PRODUCT_BUNDLE_IDENTIFIER - io.github.tychedelia - PRODUCT_NAME - $(TARGET_NAME) - WRAPPER_EXTENSION - plugin - - isa - XCBuildConfiguration - name - Debug - - E23329DE1DF092AD0002B4FE - - buildSettings - - ALWAYS_SEARCH_USER_PATHS - YES - ARCHS - arm64 - CLANG_CXX_LANGUAGE_STANDARD - c++17 - COMBINE_HIDPI_IMAGES - YES - DEAD_CODE_STRIPPING - YES - FRAMEWORK_SEARCH_PATHS - /Applications/TouchDesigner.app/Contents/Frameworks - INFOPLIST_FILE - $(SRCROOT)/Info.plist - INSTALL_PATH - / - LIBRARY_SEARCH_PATHS - - $(inherited) - $(PROJECT_DIR) - $(PROJECT_DIR)/target/aarch64-apple-darwin/cxxbridge/** - $(PROJECT_DIR)/target/aarch64-apple-darwin/release - $(PYTHON_INCLUDE_DIR) - - OTHER_CFLAGS - - -I$(PROJECT_DIR)/target/aarch64-apple-darwin/cxxbridge - -I$(PROJECT_DIR)/td-rs-base/src - -I$(PYTHON_INCLUDE_DIR) - $(EXTRA_CFLAGS) - - PRODUCT_BUNDLE_IDENTIFIER - io.github.tychedelia - PRODUCT_NAME - $(TARGET_NAME) - WRAPPER_EXTENSION - plugin - - isa - XCBuildConfiguration - name - Release - - E23329DF1DF092C90002B4FE - - fileEncoding - 4 - isa - PBXFileReference - lastKnownFileType - sourcecode.c.h - name - {{ TD_OP_H_NAME }} - path - {{ TD_OP_H_PATH }} - sourceTree - SOURCE_ROOT - - E23329E01DF092C90002B4FE - - fileEncoding - 4 - isa - PBXFileReference - lastKnownFileType - sourcecode.c.h - name - CPlusPlus_Common.h - path - td-rs-base/src/CPlusPlus_Common.h - sourceTree - SOURCE_ROOT - - - rootObject - E23329CE1DF092AD0002B4FE - - + + + + + archiveVersion + 1 + classes + + objectVersion + 46 + objects + + 6A7F74C12D40EA7500969072 + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + SystemConfiguration.framework + path + System/Library/Frameworks/SystemConfiguration.framework + sourceTree + SDKROOT + + 6A7F74C22D40EA7500969072 + + fileRef + 6A7F74C12D40EA7500969072 + isa + PBXBuildFile + + 6A99B73F29FD8AD100197036 + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.cpp.cpp + name + {{ PLUGIN_CPP_NAME }} + path + {{ PLUGIN_CPP_PATH }} + sourceTree + <group> + + 6A99B74029FD8AD100197036 + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + {{ PLUGIN_H_NAME }} + path + {{ PLUGIN_H_PATH }} + sourceTree + <group> + + 6A99B74129FD8AD100197036 + + fileRef + 6A99B73F29FD8AD100197036 + isa + PBXBuildFile + + 6A99B74229FD9B9700197036 + + isa + PBXGroup + name + Products + sourceTree + <group> + + 6AD906B42AE10A9400997BA1 + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + Python.framework + path + /Applications/TouchDesigner.app/Contents/Frameworks/Python.framework + sourceTree + <absolute> + + 6AD906B42AE10A9400997BA2 + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + Python.framework + path + /System/Library/Frameworks/CoreFoundation.framework + sourceTree + <absolute> + + 6AD906B52AE10A9400997BA1 + + fileRef + 6AD906B42AE10A9400997BA1 + isa + PBXBuildFile + + 6AD906B52AE10A9400997BA2 + + fileRef + 6AD906B42AE10A9400997BA2 + isa + PBXBuildFile + + 9E4ACB8B299AC54200A2B1CE + + isa + PBXFileReference + lastKnownFileType + archive.ar + name + {{ LIB_NAME }} + path + {{ LIB_PATH }} + sourceTree + <group> + + 9E4ACB8C299AC54200A2B1CE + + fileRef + 9E4ACB8B299AC54200A2B1CE + isa + PBXBuildFile + + 9ED7E4DF2999F4C9001F2445 + + isa + PBXFileReference + lastKnownFileType + archive.ar + name + {{ OP_LIB_NAME }} + path + {{ OP_LIB_PATH }} + sourceTree + <group> + + 9ED7E4E02999F4C9001F2445 + + fileRef + 9ED7E4DF2999F4C9001F2445 + isa + PBXBuildFile + + B9369E722741736D00EA7D98 + + children + + 6A7F74C12D40EA7500969072 + 6AD906B42AE10A9400997BA1 + 6AD906B42AE10A9400997BA2 + 9E4ACB8B299AC54200A2B1CE + 9ED7E4DF2999F4C9001F2445 + + isa + PBXGroup + name + Frameworks + sourceTree + <group> + + E23329CD1DF092AD0002B4FE + + children + + 6A99B73F29FD8AD100197036 + 6A99B74029FD8AD100197036 + E23329DF1DF092C90002B4FE + E23329E01DF092C90002B4FE + E23329D91DF092AD0002B4FE + E23329D71DF092AD0002B4FE + B9369E722741736D00EA7D98 + + isa + PBXGroup + sourceTree + <group> + + E23329CE1DF092AD0002B4FE + + attributes + + LastUpgradeCheck + 1420 + ORGANIZATIONNAME + Derivative + TargetAttributes + + E23329D51DF092AD0002B4FE + + CreatedOnToolsVersion + 8.0 + ProvisioningStyle + Automatic + + + + buildConfigurationList + E23329D11DF092AD0002B4FE + compatibilityVersion + Xcode 3.2 + developmentRegion + en + hasScannedForEncodings + 0 + isa + PBXProject + knownRegions + + en + Base + + mainGroup + E23329CD1DF092AD0002B4FE + productRefGroup + E23329D71DF092AD0002B4FE + projectDirPath + + projectReferences + + + ProductGroup + 6A99B74229FD9B9700197036 + ProjectRef + E23329D91DF092AD0002B4FE + + + projectRoot + + targets + + E23329D51DF092AD0002B4FE + + + E23329D11DF092AD0002B4FE + + buildConfigurations + + E23329DA1DF092AD0002B4FE + E23329DB1DF092AD0002B4FE + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + E23329D21DF092AD0002B4FE + + buildActionMask + 2147483647 + files + + 6A99B74129FD8AD100197036 + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + E23329D31DF092AD0002B4FE + + buildActionMask + 2147483647 + files + + 6A7F74C22D40EA7500969072 + 6AD906B52AE10A9400997BA1 + 6AD906B52AE10A9400997BA2 + 9E4ACB8C299AC54200A2B1CE + 9ED7E4E02999F4C9001F2445 + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + E23329D41DF092AD0002B4FE + + buildActionMask + 2147483647 + files + + isa + PBXResourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + E23329D51DF092AD0002B4FE + + buildConfigurationList + E23329DC1DF092AD0002B4FE + buildPhases + + E23329D21DF092AD0002B4FE + E23329D31DF092AD0002B4FE + E23329D41DF092AD0002B4FE + + buildRules + + dependencies + + isa + PBXNativeTarget + name + {{ PLUGIN_NAME }} + productName + {{ PLUGIN_PRODUCT_NAME }} + productReference + E23329D61DF092AD0002B4FE + productType + com.apple.product-type.bundle + + E23329D61DF092AD0002B4FE + + explicitFileType + wrapper.cfbundle + includeInIndex + 0 + isa + PBXFileReference + path + {{ PLUGIN_FILE_NAME }} + sourceTree + BUILT_PRODUCTS_DIR + + E23329D71DF092AD0002B4FE + + children + + E23329D61DF092AD0002B4FE + + isa + PBXGroup + name + Products + sourceTree + <group> + + E23329D91DF092AD0002B4FE + + isa + PBXFileReference + lastKnownFileType + wrapper.pb-project + path + sin.xcodeproj + sourceTree + SOURCE_ROOT + + E23329DA1DF092AD0002B4FE + + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + ARCHS + arm64 + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED + YES + CLANG_ANALYZER_NONNULL + YES + CLANG_CXX_LANGUAGE_STANDARD + gnu++0x + CLANG_CXX_LIBRARY + libc++ + CLANG_ENABLE_MODULES + YES + CLANG_ENABLE_OBJC_ARC + YES + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING + YES + CLANG_WARN_BOOL_CONVERSION + YES + CLANG_WARN_COMMA + YES + CLANG_WARN_CONSTANT_CONVERSION + YES + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS + YES + CLANG_WARN_DIRECT_OBJC_ISA_USAGE + YES_ERROR + CLANG_WARN_DOCUMENTATION_COMMENTS + YES + CLANG_WARN_EMPTY_BODY + YES + CLANG_WARN_ENUM_CONVERSION + YES + CLANG_WARN_INFINITE_RECURSION + YES + CLANG_WARN_INT_CONVERSION + YES + CLANG_WARN_NON_LITERAL_NULL_CONVERSION + YES + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF + YES + CLANG_WARN_OBJC_LITERAL_CONVERSION + YES + CLANG_WARN_OBJC_ROOT_CLASS + YES_ERROR + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER + YES + CLANG_WARN_RANGE_LOOP_ANALYSIS + YES + CLANG_WARN_STRICT_PROTOTYPES + YES + CLANG_WARN_SUSPICIOUS_MOVE + YES + CLANG_WARN_SUSPICIOUS_MOVES + YES + CLANG_WARN_UNREACHABLE_CODE + YES + CLANG_WARN__DUPLICATE_METHOD_MATCH + YES + CODE_SIGN_IDENTITY + - + COPY_PHASE_STRIP + NO + DEAD_CODE_STRIPPING + YES + DEBUG_INFORMATION_FORMAT + dwarf + ENABLE_STRICT_OBJC_MSGSEND + YES + ENABLE_TESTABILITY + YES + GCC_C_LANGUAGE_STANDARD + gnu99 + GCC_DYNAMIC_NO_PIC + NO + GCC_NO_COMMON_BLOCKS + YES + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_WARN_64_TO_32_BIT_CONVERSION + YES + GCC_WARN_ABOUT_RETURN_TYPE + YES_ERROR + GCC_WARN_UNDECLARED_SELECTOR + YES + GCC_WARN_UNINITIALIZED_AUTOS + YES_AGGRESSIVE + GCC_WARN_UNUSED_FUNCTION + YES + GCC_WARN_UNUSED_VARIABLE + YES + MACOSX_DEPLOYMENT_TARGET + 12.0 + MTL_ENABLE_DEBUG_INFO + YES + ONLY_ACTIVE_ARCH + YES + SDKROOT + macosx + + isa + XCBuildConfiguration + name + Debug + + E23329DB1DF092AD0002B4FE + + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + ARCHS + arm64 + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED + YES + CLANG_ANALYZER_NONNULL + YES + CLANG_CXX_LANGUAGE_STANDARD + gnu++0x + CLANG_CXX_LIBRARY + libc++ + CLANG_ENABLE_MODULES + YES + CLANG_ENABLE_OBJC_ARC + YES + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING + YES + CLANG_WARN_BOOL_CONVERSION + YES + CLANG_WARN_COMMA + YES + CLANG_WARN_CONSTANT_CONVERSION + YES + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS + YES + CLANG_WARN_DIRECT_OBJC_ISA_USAGE + YES_ERROR + CLANG_WARN_DOCUMENTATION_COMMENTS + YES + CLANG_WARN_EMPTY_BODY + YES + CLANG_WARN_ENUM_CONVERSION + YES + CLANG_WARN_INFINITE_RECURSION + YES + CLANG_WARN_INT_CONVERSION + YES + CLANG_WARN_NON_LITERAL_NULL_CONVERSION + YES + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF + YES + CLANG_WARN_OBJC_LITERAL_CONVERSION + YES + CLANG_WARN_OBJC_ROOT_CLASS + YES_ERROR + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER + YES + CLANG_WARN_RANGE_LOOP_ANALYSIS + YES + CLANG_WARN_STRICT_PROTOTYPES + YES + CLANG_WARN_SUSPICIOUS_MOVE + YES + CLANG_WARN_SUSPICIOUS_MOVES + YES + CLANG_WARN_UNREACHABLE_CODE + YES + CLANG_WARN__DUPLICATE_METHOD_MATCH + YES + CODE_SIGN_IDENTITY + - + COPY_PHASE_STRIP + NO + DEAD_CODE_STRIPPING + YES + DEBUG_INFORMATION_FORMAT + dwarf-with-dsym + ENABLE_NS_ASSERTIONS + NO + ENABLE_STRICT_OBJC_MSGSEND + YES + GCC_C_LANGUAGE_STANDARD + gnu99 + GCC_NO_COMMON_BLOCKS + YES + GCC_WARN_64_TO_32_BIT_CONVERSION + YES + GCC_WARN_ABOUT_RETURN_TYPE + YES_ERROR + GCC_WARN_UNDECLARED_SELECTOR + YES + GCC_WARN_UNINITIALIZED_AUTOS + YES_AGGRESSIVE + GCC_WARN_UNUSED_FUNCTION + YES + GCC_WARN_UNUSED_VARIABLE + YES + MACOSX_DEPLOYMENT_TARGET + 12.0 + MTL_ENABLE_DEBUG_INFO + NO + ONLY_ACTIVE_ARCH + NO + SDKROOT + macosx + + isa + XCBuildConfiguration + name + Release + + E23329DC1DF092AD0002B4FE + + buildConfigurations + + E23329DD1DF092AD0002B4FE + E23329DE1DF092AD0002B4FE + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + E23329DD1DF092AD0002B4FE + + buildSettings + + ALWAYS_SEARCH_USER_PATHS + YES + ARCHS + arm64 + CLANG_CXX_LANGUAGE_STANDARD + c++17 + COMBINE_HIDPI_IMAGES + YES + DEAD_CODE_STRIPPING + YES + FRAMEWORK_SEARCH_PATHS + /Applications/TouchDesigner.app/Contents/Frameworks + INFOPLIST_FILE + $(SRCROOT)/Info.plist + INSTALL_PATH + / + LIBRARY_SEARCH_PATHS + + $(inherited) + $(PROJECT_DIR) + $(PROJECT_DIR)/target/aarch64-apple-darwin/cxxbridge/** + $(PROJECT_DIR)/target/aarch64-apple-darwin/release + $(PYTHON_INCLUDE_DIR) + + OTHER_CFLAGS + + -I$(PROJECT_DIR)/target/aarch64-apple-darwin/cxxbridge + -I$(PROJECT_DIR)/td-rs-base/src + -I$(PYTHON_INCLUDE_DIR) + $(EXTRA_CFLAGS) + + PRODUCT_BUNDLE_IDENTIFIER + io.github.tychedelia + PRODUCT_NAME + $(TARGET_NAME) + WRAPPER_EXTENSION + plugin + + isa + XCBuildConfiguration + name + Debug + + E23329DE1DF092AD0002B4FE + + buildSettings + + ALWAYS_SEARCH_USER_PATHS + YES + ARCHS + arm64 + CLANG_CXX_LANGUAGE_STANDARD + c++17 + COMBINE_HIDPI_IMAGES + YES + DEAD_CODE_STRIPPING + YES + FRAMEWORK_SEARCH_PATHS + /Applications/TouchDesigner.app/Contents/Frameworks + INFOPLIST_FILE + $(SRCROOT)/Info.plist + INSTALL_PATH + / + LIBRARY_SEARCH_PATHS + + $(inherited) + $(PROJECT_DIR) + $(PROJECT_DIR)/target/aarch64-apple-darwin/cxxbridge/** + $(PROJECT_DIR)/target/aarch64-apple-darwin/release + $(PYTHON_INCLUDE_DIR) + + OTHER_CFLAGS + + -I$(PROJECT_DIR)/target/aarch64-apple-darwin/cxxbridge + -I$(PROJECT_DIR)/td-rs-base/src + -I$(PYTHON_INCLUDE_DIR) + $(EXTRA_CFLAGS) + + PRODUCT_BUNDLE_IDENTIFIER + io.github.tychedelia + PRODUCT_NAME + $(TARGET_NAME) + WRAPPER_EXTENSION + plugin + + isa + XCBuildConfiguration + name + Release + + E23329DF1DF092C90002B4FE + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + {{ TD_OP_H_NAME }} + path + {{ TD_OP_H_PATH }} + sourceTree + SOURCE_ROOT + + E23329E01DF092C90002B4FE + + fileEncoding + 4 + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + name + CPlusPlus_Common.h + path + td-rs-base/src/CPlusPlus_Common.h + sourceTree + SOURCE_ROOT + + + rootObject + E23329CE1DF092AD0002B4FE + + diff --git a/td-rs.toml b/td-rs.toml index d921866..8ae84a8 100644 --- a/td-rs.toml +++ b/td-rs.toml @@ -1,8 +1,8 @@ -[windows] -plugin_folder = "$HOME\\OneDrive\\Documents\\Derivative\\Plugins\\" -python_include_dir = "\"C:\\Program Files\\Derivative\\TouchDesigner\\Samples\\CPlusPlus\\3rdParty\\Python\\Include\";\"C:\\Program Files\\Derivative\\TouchDesigner\\Samples\\CPlusPlus\\3rdParty\\Python\\Include\\PC\"" -python_lib_dir = "C:\\Program Files\\Derivative\\TouchDesigner\\Samples\\CPlusPlus\\3rdParty\\Python\\lib\\x64" - -[macos] -plugin_folder = "$HOME/Library/Application Support/Derivative/TouchDesigner099/Plugins" +[windows] +plugin_folder = "$HOME\\Documents\\Derivative\\Plugins\\" +python_include_dir = "\"C:\\Program Files\\Derivative\\TouchDesigner\\Samples\\CPlusPlus\\3rdParty\\Python\\Include\";\"C:\\Program Files\\Derivative\\TouchDesigner\\Samples\\CPlusPlus\\3rdParty\\Python\\Include\\PC\"" +python_lib_dir = "C:\\Program Files\\Derivative\\TouchDesigner\\Samples\\CPlusPlus\\3rdParty\\Python\\lib\\x64" + +[macos] +plugin_folder = "$HOME/Library/Application Support/Derivative/TouchDesigner099/Plugins" python_include_dir = "/Applications/TouchDesigner.app/Contents/Frameworks/Python.framework/Headers" \ No newline at end of file diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 3d7e09a..92db04c 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -1,7 +1,7 @@ -[package] -name = "xtask" -version = "0.1.0" -edition = "2021" - -[dependencies] -td-rs-xtask = { path = "../td-rs-xtask" } +[package] +name = "xtask" +version = "0.1.0" +edition = "2021" + +[dependencies] +td-rs-xtask = { path = "../td-rs-xtask" } diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 120a996..90715dd 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -1,3 +1,3 @@ -fn main() -> td_rs_xtask::Result<()> { - td_rs_xtask::main() -} +fn main() -> td_rs_xtask::Result<()> { + td_rs_xtask::main() +}