Compare commits

..

9 Commits

Author SHA1 Message Date
b05f29da23 runnable without vr 2026-02-24 03:04:00 +01:00
17a0de5903 hasn't been that in a while 2026-02-23 22:16:55 +01:00
485ea056a7 lets use embedded_graphics lol 2026-02-23 22:14:22 +01:00
4296a6488c crosshair is nice 2026-02-23 01:54:44 +01:00
b82a0eb7d4 feat: drawing and stuff 2026-02-22 20:39:23 +01:00
bb05dc5161 head lookat move mouse test 2026-02-21 19:08:35 +01:00
a152eeadc6 no need for this 2026-02-21 14:34:43 +01:00
99c06d3419 window size and color 2026-02-21 14:28:47 +01:00
a727ce60ca remove avian, we don't actually need it 2026-02-21 14:23:09 +01:00
11 changed files with 1302 additions and 572 deletions

622
Cargo.lock generated
View File

@@ -103,12 +103,6 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "allocator-api2"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]] [[package]]
name = "alsa" name = "alsa"
version = "0.9.1" version = "0.9.1"
@@ -225,9 +219,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.101" version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]] [[package]]
name = "approx" name = "approx"
@@ -389,42 +383,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]] [[package]]
name = "avian3d" name = "az"
version = "0.5.0" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b82608b43397affac139547dfa9beb3208034c53e1a3cfe5d4079db1af362104" checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
dependencies = [
"approx",
"avian_derive",
"bevy",
"bevy_heavy",
"bevy_math",
"bevy_transform_interpolation",
"bitflags 2.11.0",
"derive_more",
"disqualified",
"glam_matrix_extras",
"itertools 0.13.0",
"nalgebra",
"parry3d",
"parry3d-f64",
"slab",
"smallvec",
"thiserror 2.0.18",
"thread_local",
]
[[package]]
name = "avian_derive"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12b257f601a1535e0d4a7a7796f535e3a13de62fd422b16dff7c14d27f0d4048"
dependencies = [
"proc-macro-error2",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "base64" name = "base64"
@@ -942,17 +904,6 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "bevy_heavy"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc496d1d43b890896cf561d8ce3dcf7b7b8e4c03c4e837a49a83a530abccbc5e"
dependencies = [
"bevy_math",
"bevy_reflect",
"glam_matrix_extras",
]
[[package]] [[package]]
name = "bevy_image" name = "bevy_image"
version = "0.18.0" version = "0.18.0"
@@ -1131,7 +1082,7 @@ dependencies = [
"arrayvec", "arrayvec",
"bevy_reflect", "bevy_reflect",
"derive_more", "derive_more",
"glam 0.30.10", "glam",
"itertools 0.14.0", "itertools 0.14.0",
"libm", "libm",
"rand", "rand",
@@ -1175,7 +1126,6 @@ checksum = "7ef8e4b7e61dfe7719bb03c884dc270cd46a82efb40f93e9933b990c5c190c59"
[[package]] [[package]]
name = "bevy_mod_openxr" name = "bevy_mod_openxr"
version = "0.5.0" version = "0.5.0"
source = "git+https://git.avii.nl/Avii/bevy_oxr.git#7936b53a024b993c53fc7427b5b290bf210978a9"
dependencies = [ dependencies = [
"android_system_properties", "android_system_properties",
"ash", "ash",
@@ -1200,7 +1150,6 @@ dependencies = [
[[package]] [[package]]
name = "bevy_mod_xr" name = "bevy_mod_xr"
version = "0.5.0" version = "0.5.0"
source = "git+https://git.avii.nl/Avii/bevy_oxr.git#7936b53a024b993c53fc7427b5b290bf210978a9"
dependencies = [ dependencies = [
"bevy_app", "bevy_app",
"bevy_camera", "bevy_camera",
@@ -1366,7 +1315,7 @@ dependencies = [
"downcast-rs 2.0.2", "downcast-rs 2.0.2",
"erased-serde", "erased-serde",
"foldhash 0.2.0", "foldhash 0.2.0",
"glam 0.30.10", "glam",
"indexmap", "indexmap",
"inventory", "inventory",
"petgraph", "petgraph",
@@ -1451,7 +1400,7 @@ dependencies = [
"downcast-rs 2.0.2", "downcast-rs 2.0.2",
"encase", "encase",
"fixedbitset", "fixedbitset",
"glam 0.30.10", "glam",
"image", "image",
"indexmap", "indexmap",
"js-sys", "js-sys",
@@ -1619,7 +1568,7 @@ dependencies = [
"crossbeam-queue", "crossbeam-queue",
"derive_more", "derive_more",
"futures-lite", "futures-lite",
"heapless 0.9.2", "heapless",
"pin-project", "pin-project",
] ]
@@ -1682,15 +1631,6 @@ dependencies = [
"thiserror 2.0.18", "thiserror 2.0.18",
] ]
[[package]]
name = "bevy_transform_interpolation"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88545c8b0fa8f3502b9a439c71fa6b596ee9e808bfb16f27a51c8c6f7405a657"
dependencies = [
"bevy",
]
[[package]] [[package]]
name = "bevy_ui" name = "bevy_ui"
version = "0.18.0" version = "0.18.0"
@@ -2518,25 +2458,6 @@ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]]
name = "crossbeam-deque"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]] [[package]]
name = "crossbeam-queue" name = "crossbeam-queue"
version = "0.3.12" version = "0.3.12"
@@ -2589,9 +2510,9 @@ checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
[[package]] [[package]]
name = "deranged" name = "deranged"
version = "0.5.6" version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
dependencies = [ dependencies = [
"powerfmt", "powerfmt",
] ]
@@ -2619,6 +2540,12 @@ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]]
name = "deunicode"
version = "1.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04"
[[package]] [[package]]
name = "directories" name = "directories"
version = "6.0.0" version = "6.0.0"
@@ -2628,6 +2555,15 @@ dependencies = [
"dirs-sys", "dirs-sys",
] ]
[[package]]
name = "dirs"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
dependencies = [
"dirs-sys",
]
[[package]] [[package]]
name = "dirs-sys" name = "dirs-sys"
version = "0.5.0" version = "0.5.0"
@@ -2735,12 +2671,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]] [[package]]
name = "ena" name = "embedded-graphics"
version = "0.14.4" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabffdaee24bd1bf95c5ef7cec31260444317e72ea56c4c91750e8b7ee58d5f1" checksum = "4e8da660bb0c829b34a56a965490597f82a55e767b91f9543be80ce8ccb416fe"
dependencies = [ dependencies = [
"log", "az",
"byteorder",
"embedded-graphics-core",
"float-cmp",
"micromath",
]
[[package]]
name = "embedded-graphics-core"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95743bef3ff70fcba3930246c4e6872882bbea0dcc6da2ca860112e0cd4bd09f"
dependencies = [
"az",
"byteorder",
] ]
[[package]] [[package]]
@@ -2918,6 +2868,15 @@ dependencies = [
"miniz_oxide", "miniz_oxide",
] ]
[[package]]
name = "float-cmp"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@@ -3174,103 +3133,12 @@ dependencies = [
"xml-rs", "xml-rs",
] ]
[[package]]
name = "glam"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "333928d5eb103c5d4050533cec0384302db6be8ef7d3cebd30ec6a35350353da"
[[package]]
name = "glam"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3abb554f8ee44336b72d522e0a7fe86a29e09f839a36022fa869a7dfe941a54b"
[[package]]
name = "glam"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4126c0479ccf7e8664c36a2d719f5f2c140fbb4f9090008098d2c291fa5b3f16"
[[package]]
name = "glam"
version = "0.17.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01732b97afd8508eee3333a541b9f7610f454bb818669e66e90f5f57c93a776"
[[package]]
name = "glam"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "525a3e490ba77b8e326fb67d4b44b4bd2f920f44d4cc73ccec50adc68e3bee34"
[[package]]
name = "glam"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b8509e6791516e81c1a630d0bd7fbac36d2fa8712a9da8662e716b52d5051ca"
[[package]]
name = "glam"
version = "0.20.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f43e957e744be03f5801a55472f593d43fabdebf25a4585db250f04d86b1675f"
[[package]]
name = "glam"
version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "518faa5064866338b013ff9b2350dc318e14cc4fcd6cb8206d7e7c9886c98815"
[[package]]
name = "glam"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12f597d56c1bd55a811a1be189459e8fad2bbc272616375602443bdfb37fa774"
[[package]]
name = "glam"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e4afd9ad95555081e109fe1d21f2a30c691b5f0919c67dfa690a2e1eb6bd51c"
[[package]]
name = "glam"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945"
[[package]]
name = "glam"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3"
[[package]]
name = "glam"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e05e7e6723e3455f4818c7b26e855439f7546cf617ef669d1adedb8669e5cb9"
[[package]]
name = "glam"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "779ae4bf7e8421cf91c0b3b64e7e8b40b862fba4d393f59150042de7c4965a94"
[[package]]
name = "glam"
version = "0.29.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8babf46d4c1c9d92deac9f7be466f76dfc4482b6452fc5024b5e8daf6ffeb3ee"
[[package]] [[package]]
name = "glam" name = "glam"
version = "0.30.10" version = "0.30.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9" checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9"
dependencies = [ dependencies = [
"approx",
"bytemuck", "bytemuck",
"encase", "encase",
"libm", "libm",
@@ -3278,16 +3146,6 @@ dependencies = [
"serde_core", "serde_core",
] ]
[[package]]
name = "glam_matrix_extras"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4664468a60479272b880a8bfc00ad2915229b93d2b2d585556fb33f9ba80e72"
dependencies = [
"bevy_reflect",
"glam 0.30.10",
]
[[package]] [[package]]
name = "glob" name = "glob"
version = "0.3.3" version = "0.3.3"
@@ -3458,8 +3316,6 @@ version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [ dependencies = [
"allocator-api2",
"equivalent",
"foldhash 0.1.5", "foldhash 0.1.5",
] ]
@@ -3475,16 +3331,6 @@ dependencies = [
"serde_core", "serde_core",
] ]
[[package]]
name = "heapless"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
dependencies = [
"hash32",
"stable_deref_trait",
]
[[package]] [[package]]
name = "heapless" name = "heapless"
version = "0.9.2" version = "0.9.2"
@@ -3515,7 +3361,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29a164ceff4500f2a72b1d21beaa8aa8ad83aec2b641844c659b190cb3ea2e0b" checksum = "29a164ceff4500f2a72b1d21beaa8aa8ad83aec2b641844c659b190cb3ea2e0b"
dependencies = [ dependencies = [
"constgebra", "constgebra",
"glam 0.30.10", "glam",
"tinyvec", "tinyvec",
] ]
@@ -3861,9 +3707,9 @@ dependencies = [
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.85" version = "0.3.88"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" checksum = "c7e709f3e3d22866f9c25b3aff01af289b18422cc8b4262fb19103ee80fe513d"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"wasm-bindgen", "wasm-bindgen",
@@ -3890,15 +3736,19 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
name = "kneeboard" name = "kneeboard"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"avian3d",
"bevy", "bevy",
"bevy_cef", "bevy_cef",
"bevy_mod_openxr", "bevy_mod_openxr",
"bevy_mod_xr", "bevy_mod_xr",
"bevy_pkv", "bevy_pkv",
"crossbeam-channel",
"embedded-graphics",
"embedded-graphics-core",
"openxr", "openxr",
"otd-ipc",
"rdev", "rdev",
"serde", "serde",
"triple_buffer",
] ]
[[package]] [[package]]
@@ -4064,16 +3914,6 @@ dependencies = [
"regex-automata", "regex-automata",
] ]
[[package]]
name = "matrixmultiply"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08"
dependencies = [
"autocfg",
"rawpointer",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.8.0" version = "2.8.0"
@@ -4104,6 +3944,12 @@ dependencies = [
"paste", "paste",
] ]
[[package]]
name = "micromath"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815"
[[package]] [[package]]
name = "minimal-lexical" name = "minimal-lexical"
version = "0.2.1" version = "0.2.1"
@@ -4180,49 +4026,6 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "nalgebra"
version = "0.34.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4d5b3eff5cd580f93da45e64715e8c20a3996342f1e466599cf7a267a0c2f5f"
dependencies = [
"approx",
"glam 0.14.0",
"glam 0.15.2",
"glam 0.16.0",
"glam 0.17.3",
"glam 0.18.0",
"glam 0.19.0",
"glam 0.20.5",
"glam 0.21.3",
"glam 0.22.0",
"glam 0.23.0",
"glam 0.24.2",
"glam 0.25.0",
"glam 0.27.0",
"glam 0.28.0",
"glam 0.29.3",
"glam 0.30.10",
"matrixmultiply",
"nalgebra-macros",
"num-complex",
"num-rational",
"num-traits",
"simba",
"typenum",
]
[[package]]
name = "nalgebra-macros"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "973e7178a678cfd059ccec50887658d482ce16b0aa9da3888ddeab5cd5eb4889"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "ndk" name = "ndk"
version = "0.8.0" version = "0.8.0"
@@ -4334,25 +4137,6 @@ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.61.2",
] ]
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "num-conv" name = "num-conv"
version = "0.2.0" version = "0.2.0"
@@ -4370,26 +4154,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [
"num-bigint",
"num-integer",
"num-traits",
]
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.19" version = "0.2.19"
@@ -4765,6 +4529,17 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "otd-ipc"
version = "0.1.0"
dependencies = [
"bytes",
"dirs",
"serde",
"serde_bytes",
"slug",
]
[[package]] [[package]]
name = "owned_ttf_parser" name = "owned_ttf_parser"
version = "0.25.1" version = "0.25.1"
@@ -4803,64 +4578,6 @@ dependencies = [
"windows-link 0.2.1", "windows-link 0.2.1",
] ]
[[package]]
name = "parry3d"
version = "0.25.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e99471b7b6870f7fe406d5611dd4b4c9b07aa3e5436b1d27e1515f9832bb0c6b"
dependencies = [
"approx",
"arrayvec",
"bitflags 2.11.0",
"downcast-rs 2.0.2",
"either",
"ena",
"foldhash 0.2.0",
"glam 0.30.10",
"hashbrown 0.16.1",
"log",
"nalgebra",
"num-derive",
"num-traits",
"ordered-float",
"rayon",
"rstar",
"simba",
"slab",
"smallvec",
"spade",
"static_assertions",
"thiserror 2.0.18",
]
[[package]]
name = "parry3d-f64"
version = "0.25.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38fe282b81b60a2aee7f24db25ea73b3c82f6451888eeb5936b621adb87aa653"
dependencies = [
"approx",
"arrayvec",
"bitflags 2.11.0",
"downcast-rs 2.0.2",
"either",
"ena",
"foldhash 0.2.0",
"hashbrown 0.16.1",
"log",
"nalgebra",
"num-derive",
"num-traits",
"ordered-float",
"rayon",
"rstar",
"simba",
"slab",
"smallvec",
"spade",
"thiserror 2.0.18",
]
[[package]] [[package]]
name = "paste" name = "paste"
version = "1.0.15" version = "1.0.15"
@@ -5048,28 +4765,6 @@ dependencies = [
"toml_edit", "toml_edit",
] ]
[[package]]
name = "proc-macro-error-attr2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
name = "proc-macro-error2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
dependencies = [
"proc-macro-error-attr2",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.106" version = "1.0.106"
@@ -5181,32 +4876,6 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
[[package]]
name = "rawpointer"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
[[package]]
name = "rayon"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]] [[package]]
name = "rdev" name = "rdev"
version = "0.5.3" version = "0.5.3"
@@ -5368,12 +5037,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "robust"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e27ee8bb91ca0adcf0ecb116293afa12d393f9c2b9b9cd54d33e8078fe19839"
[[package]] [[package]]
name = "rodio" name = "rodio"
version = "0.20.1" version = "0.20.1"
@@ -5404,17 +5067,6 @@ version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
[[package]]
name = "rstar"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "421400d13ccfd26dfa5858199c30a5d76f9c54e0dba7575273025b43c5175dbb"
dependencies = [
"heapless 0.8.0",
"num-traits",
"smallvec",
]
[[package]] [[package]]
name = "rustc-hash" name = "rustc-hash"
version = "1.1.0" version = "1.1.0"
@@ -5446,7 +5098,7 @@ dependencies = [
"errno", "errno",
"libc", "libc",
"linux-raw-sys 0.4.15", "linux-raw-sys 0.4.15",
"windows-sys 0.59.0", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@@ -5512,15 +5164,6 @@ dependencies = [
"twox-hash", "twox-hash",
] ]
[[package]]
name = "safe_arch"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323"
dependencies = [
"bytemuck",
]
[[package]] [[package]]
name = "same-file" name = "same-file"
version = "1.0.6" version = "1.0.6"
@@ -5587,6 +5230,16 @@ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]]
name = "serde_bytes"
version = "0.11.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8"
dependencies = [
"serde",
"serde_core",
]
[[package]] [[package]]
name = "serde_core" name = "serde_core"
version = "1.0.228" version = "1.0.228"
@@ -5641,19 +5294,6 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "simba"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c99284beb21666094ba2b75bbceda012e610f5479dfcc2d6e2426f53197ffd95"
dependencies = [
"approx",
"num-complex",
"num-traits",
"paste",
"wide",
]
[[package]] [[package]]
name = "simd-adler32" name = "simd-adler32"
version = "0.3.8" version = "0.3.8"
@@ -5695,6 +5335,16 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "slug"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724"
dependencies = [
"deunicode",
"wasm-bindgen",
]
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.15.1" version = "1.15.1"
@@ -5759,18 +5409,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "spade"
version = "2.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb313e1c8afee5b5647e00ee0fe6855e3d529eb863a0fdae1d60006c4d1e9990"
dependencies = [
"hashbrown 0.15.5",
"num-traits",
"robust",
"smallvec",
]
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.10.0" version = "0.10.0"
@@ -5847,9 +5485,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.116" version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -6175,6 +5813,15 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "triple_buffer"
version = "8.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "420466259f9fa5decc654c490b9ab538400e5420df8237f84ecbe20368bcf72b"
dependencies = [
"crossbeam-utils",
]
[[package]] [[package]]
name = "ttf-parser" name = "ttf-parser"
version = "0.25.1" version = "0.25.1"
@@ -6196,12 +5843,6 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
[[package]]
name = "typenum"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
[[package]] [[package]]
name = "typewit" name = "typewit"
version = "1.14.2" version = "1.14.2"
@@ -6402,9 +6043,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.108" version = "0.2.111"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" checksum = "ec1adf1535672f5b7824f817792b1afd731d7e843d2d04ec8f27e8cb51edd8ac"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"once_cell", "once_cell",
@@ -6415,9 +6056,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-futures" name = "wasm-bindgen-futures"
version = "0.4.58" version = "0.4.61"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" checksum = "fe88540d1c934c4ec8e6db0afa536876c5441289d7f9f9123d4f065ac1250a6b"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"futures-util", "futures-util",
@@ -6429,9 +6070,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.108" version = "0.2.111"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" checksum = "19e638317c08b21663aed4d2b9a2091450548954695ff4efa75bff5fa546b3b1"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@@ -6439,9 +6080,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.108" version = "0.2.111"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" checksum = "2c64760850114d03d5f65457e96fc988f11f01d38fbaa51b254e4ab5809102af"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"proc-macro2", "proc-macro2",
@@ -6452,9 +6093,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.108" version = "0.2.111"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" checksum = "60eecd4fe26177cfa3339eb00b4a36445889ba3ad37080c2429879718e20ca41"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@@ -6603,9 +6244,9 @@ dependencies = [
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.85" version = "0.3.88"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" checksum = "9d6bb20ed2d9572df8584f6dc81d68a41a625cadc6f15999d649a70ce7e3597a"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
@@ -6792,16 +6433,6 @@ dependencies = [
"web-sys", "web-sys",
] ]
[[package]]
name = "wide"
version = "0.7.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03"
dependencies = [
"bytemuck",
"safe_arch",
]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@@ -7125,15 +6756,6 @@ dependencies = [
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets 0.52.6",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.61.2" version = "0.61.2"

View File

@@ -6,13 +6,21 @@ description = "Bevy powered Kneeboard OpenXR Overlay"
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
[dependencies] [dependencies]
avian3d = { version = "0.5.0", features = ["simd"] }
bevy = { version = "0.18", features = ["debug"] } bevy = { version = "0.18", features = ["debug"] }
bevy_cef = { path = "../bevy_cef" } bevy_cef = { path = "../bevy_cef" }
bevy_mod_xr = { git = "https://git.avii.nl/Avii/bevy_oxr.git", version = "0.5.0" } # bevy_mod_xr = { git = "https://git.avii.nl/Avii/bevy_oxr.git", version = "0.5.0" }
bevy_mod_openxr = { git = "https://git.avii.nl/Avii/bevy_oxr.git", version = "0.5.0" } # bevy_mod_openxr = { git = "https://git.avii.nl/Avii/bevy_oxr.git", version = "0.5.0" }
bevy_mod_xr = { path = "../bevy_oxr/crates/bevy_xr" }
bevy_mod_openxr = { path = "../bevy_oxr/crates/bevy_openxr" }
bevy_pkv = "0.15.0" bevy_pkv = "0.15.0"
# bevy_xr_utils.workspace = true # bevy_xr_utils.workspace = true
openxr = "0.21.1" openxr = "0.21.1"
rdev = { version = "0.5.3", features = ["unstable_grab"] } rdev = { version = "0.5.3", features = ["unstable_grab"] }
serde = { version = "1.0.228", features = ["derive"] } serde = { version = "1.0.228", features = ["derive"] }
otd-ipc = { path = "../../otd-ipc-client-rs" }
crossbeam-channel = "0.5.15"
triple_buffer = "8.1.1"
embedded-graphics = "0.8.2"
embedded-graphics-core = "0.4.1"

233
src/drawingplugin.rs Normal file
View File

@@ -0,0 +1,233 @@
mod drawtarget;
mod rgba;
mod uiplugin;
use bevy_cef::prelude::WebviewExtendStandardMaterial;
use bevy::{
asset::RenderAssetUsages,
color::palettes::css,
prelude::*,
render::render_resource::{Extent3d, TextureDimension, TextureFormat},
};
use embedded_graphics::prelude::DrawTarget;
use crate::{
drawingplugin::drawtarget::{DrawableLayer, Visible},
otdipcplugin::OtdIpcPlugin,
};
use crate::{
drawingplugin::uiplugin::UiPlugin,
otdipcplugin::{PenButtons, PenPosition, PenPressure},
};
const IMAGE_WIDTH: usize = (210.0 * 3.5) as usize;
const IMAGE_HEIGHT: usize = (279.0 * 3.5) as usize;
#[derive(Resource)]
pub struct MyProcGenImage(pub(crate) Handle<Image>);
#[derive(Component)]
struct CursorBuffer;
#[derive(Component)]
struct DrawingBuffer;
#[derive(Resource)]
struct PenSize(f32);
#[derive(Resource)]
struct PenColor(Color);
#[derive(Resource)]
pub struct LastPenPos(pub Option<(i32, i32)>);
pub struct DrawingPlugin;
impl Plugin for DrawingPlugin {
fn build(&self, app: &mut App) {
app.add_plugins(OtdIpcPlugin);
app.add_plugins(UiPlugin);
app.insert_resource(ClearColor(Color::NONE))
.insert_resource(LastPenPos(None))
.insert_resource(PenColor(css::BLACK.into()))
.insert_resource(PenSize(5.0));
app.add_systems(Startup, setup)
.add_systems(Update, (cursor, draw, plot));
}
}
pub fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
let image = Image::new_fill(
Extent3d {
width: IMAGE_WIDTH as u32,
height: IMAGE_HEIGHT as u32,
depth_or_array_layers: 1,
},
TextureDimension::D2,
&(Srgba::new(1.0, 1.0, 1.0, 0.0).to_u8_array()),
TextureFormat::Rgba8UnormSrgb,
RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD,
);
let handle = images.add(image);
commands.insert_resource(MyProcGenImage(handle));
commands.spawn((
CursorBuffer,
DrawableLayer::new(IMAGE_WIDTH, IMAGE_HEIGHT, drawtarget::Layer::Drawing),
Visible,
));
commands.spawn((
DrawingBuffer,
DrawableLayer::new(IMAGE_WIDTH, IMAGE_HEIGHT, drawtarget::Layer::Cursor),
Visible,
));
}
// fn color_changer(mut pen_color: ResMut<PenColor>, mut pen_buttons: MessageReader<PenButtons>) {
// let Some(buttons) = pen_buttons.read().next() else {
// return;
// };
// pen_color.0 = css::BLACK.into();
// if buttons.a() {
// let mut t = LinearRgba::from(pen_color.0);
// t.alpha = 0.0;
// pen_color.0 = t.into();
// }
// }
fn cursor(
pen_color: Res<PenColor>,
mut buffer: Query<&mut DrawableLayer, With<CursorBuffer>>,
mut pen_size: ResMut<PenSize>,
mut pen_buttons: MessageReader<PenButtons>,
mut pen_position: MessageReader<PenPosition>,
mut pen_pressure: MessageReader<PenPressure>,
) {
let Ok(mut buffer) = buffer.single_mut() else {
return;
};
let mut size: f32 = 1.0;
let mut offset = 20.0;
let c = pen_color.0;
if let Some(buttons) = pen_buttons.read().next()
&& buttons.a()
{
offset *= 4.;
};
for penpres in pen_pressure.read() {
let _in = penpres.pressure;
let _out = penpres.pressure.powi(4);
size *= 1. + (_out * offset);
}
pen_size.0 = size.clamp(1.0, 200.0);
let s = pen_size.0 as i32;
let b = css::BLACK.into();
let cs = 10;
let cd = 3;
for penpos in pen_position.read() {
let x = (penpos.x * (buffer.width as f32)) as i32;
let y = (penpos.y * (buffer.height as f32)) as i32;
buffer.clear(Srgba::new(0.0, 0.0, 0.0, 0.0).into()).ok();
buffer.draw_stroke(x - (cs + cd) - s, y, x - (cd) - s, y, 4.0, b);
buffer.draw_stroke(x - (cs + cd) - s, y, x - (cd) - s, y, 1.0, c);
buffer.draw_stroke(x + (cd) + s, y, x + (cs + cd) + s, y, 4.0, b);
buffer.draw_stroke(x + (cd) + s, y, x + (cs + cd) + s, y, 1.0, c);
buffer.draw_stroke(x, y - (cs + cd) - s, x, y - (cd) - s, 4.0, b);
buffer.draw_stroke(x, y - (cs + cd) - s, x, y - (cd) - s, 1.0, c);
buffer.draw_stroke(x, y + (cs + cd) + s, x, y + (cd) + s, 4.0, b);
buffer.draw_stroke(x, y + (cs + cd) + s, x, y + (cd) + s, 1.0, c);
}
}
fn draw(
pen_size: Res<PenSize>,
pen_color: Res<PenColor>,
ui: Query<&Visible, With<uiplugin::UiBuffer>>,
mut lastloc: ResMut<LastPenPos>,
mut buffer: Query<&mut DrawableLayer, With<DrawingBuffer>>,
mut pen_buttons: MessageReader<PenButtons>,
mut pen_position: MessageReader<PenPosition>,
) {
if ui.single().is_ok() {
lastloc.0 = None;
return; // if the ui layer is visible, dont draw
}
let Ok(mut buffer) = buffer.single_mut() else {
return;
};
let Some(buttons) = pen_buttons.read().next() else {
return;
};
for penpos in pen_position.read() {
let x = (penpos.x * (buffer.width as f32)) as i32;
let y = (penpos.y * (buffer.height as f32)) as i32;
let Some(ll) = lastloc.0 else {
lastloc.0 = Some((x, y));
return;
};
if buttons.tip() {
buffer.draw_stroke(ll.0, ll.1, x, y, pen_size.0, pen_color.0);
}
lastloc.0 = Some((x, y));
}
}
fn plot(
buffers: Query<&DrawableLayer, With<Visible>>,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<WebviewExtendStandardMaterial>>,
webviews: Query<&MeshMaterial3d<WebviewExtendStandardMaterial>>,
my_handle: Res<MyProcGenImage>,
) {
let image = images.get_mut(&my_handle.0).expect("Image not found");
image.clear(&[0, 0, 0, 0]);
let sorted = buffers
.iter()
.sort_by::<&DrawableLayer>(|a, b| b.order.cmp(&a.order));
for layer in sorted {
for (i, c) in layer.buffer.chunks(4).enumerate() {
let x = i % layer.width;
let y = i / layer.width;
let red: u8 = c[0];
let green = c[1];
let blue = c[2];
let alpha = c[3];
if alpha > 0 {
let color = Color::srgba_u8(red, green, blue, alpha);
image.set_color_at(x as u32, y as u32, color).unwrap();
}
}
}
// Poke redraw
for handle in webviews {
if let Some(material) = materials.get_mut(handle.id()) {
material.extension.overlay = Some(my_handle.0.clone());
}
}
}

View File

@@ -0,0 +1,342 @@
use bevy::{color::Color, ecs::component::Component};
use embedded_graphics::{pixelcolor::Rgb888, prelude::*, primitives::*};
use crate::drawingplugin::rgba::Rgba;
#[allow(unused)]
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Layer {
Drawing,
Ui,
Cursor,
}
#[derive(Component)]
pub struct Visible;
#[derive(Component)]
pub struct DrawableLayer {
pub order: Layer,
pub width: usize,
pub height: usize,
pub buffer: Vec<u8>,
}
impl DrawableLayer {
pub fn new(width: usize, height: usize, order: Layer) -> Self {
let buffer = vec![0; width * height * 4];
Self {
order,
width,
height,
buffer,
}
}
}
#[allow(unused)]
impl DrawableLayer {
pub fn draw_stroke(
&mut self,
x1: i32,
y1: i32,
x2: i32,
y2: i32,
thickness: f32,
color: Color,
) {
let (mut x0, mut y0) = (x1, y1);
let (x1, y1) = (x2, y2);
let dx = (x1 - x0).abs();
let dy = -(y1 - y0).abs();
let sx = if x0 < x1 { 1 } else { -1 };
let sy = if y0 < y1 { 1 } else { -1 };
let mut err = dx + dy;
let half_t = (thickness / 2.0).ceil() as i32;
loop {
self.draw_filled_circle(x0, y0, half_t, color);
if x0 == x1 && y0 == y1 {
break;
}
let e2 = 2 * err;
if e2 >= dy {
err += dy;
x0 += sx;
}
if e2 <= dx {
err += dx;
y0 += sy;
}
}
}
pub fn set_color_at(&mut self, x: i32, y: i32, color: Color) {
Pixel(Point::new(x, y), super::rgba::Rgba::from(color.to_srgba()))
.draw(self)
.ok();
}
pub fn draw_line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, thickness: f32, color: Color) {
Line::new(Point::new(x1, y1), Point::new(x2, y2))
.into_styled(PrimitiveStyle::with_stroke(
Rgba::from(color.to_srgba()),
thickness as u32,
))
.draw(self)
.ok();
}
pub fn draw_circle(&mut self, cx: i32, cy: i32, radius: i32, thickness: f32, color: Color) {
Circle::new(Point::new(cx - radius, cy - radius), (radius * 2) as u32)
.into_styled(PrimitiveStyle::with_stroke(
Rgba::from(color.to_srgba()),
thickness as u32,
))
.draw(self)
.ok();
}
pub fn draw_filled_circle(&mut self, cx: i32, cy: i32, radius: i32, color: Color) {
Circle::new(Point::new(cx - radius, cy - radius), (radius * 2) as u32)
.into_styled(PrimitiveStyle::with_fill(Rgba::from(color.to_srgba())))
.draw(self)
.ok();
}
pub fn draw_rectangle(&mut self, x: i32, y: i32, w: u32, h: u32, thickness: f32, color: Color) {
Rectangle::new(Point::new(x, y), Size::new(w, h))
.into_styled(PrimitiveStyle::with_stroke(
Rgba::from(color.to_srgba()),
thickness as u32,
))
.draw(self)
.ok();
}
pub fn draw_filled_rectangle(&mut self, x: i32, y: i32, w: u32, h: u32, color: Color) {
Rectangle::new(Point::new(x, y), Size::new(w, h))
.into_styled(PrimitiveStyle::with_fill(Rgba::from(color.to_srgba())))
.draw(self)
.ok();
}
}
impl Dimensions for DrawableLayer {
fn bounding_box(&self) -> embedded_graphics::primitives::Rectangle {
Rectangle::new(
Point::new(0, 0),
Size::new(self.width as u32, self.height as u32),
)
}
}
impl DrawTarget for DrawableLayer {
type Color = Rgba<Rgb888>;
type Error = Box<dyn std::error::Error>;
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = embedded_graphics::Pixel<Self::Color>>,
{
for p in pixels {
let x = p.0.x as usize;
let y = p.0.y as usize;
if !(0..=self.width).contains(&x) || !(0..=self.height).contains(&y) {
continue;
}
let index = (x + (self.width * y)) * 4;
if index >= self.buffer.len() {
continue;
}
self.buffer[index] = p.1.r();
self.buffer[index + 1] = p.1.g();
self.buffer[index + 2] = p.1.b();
self.buffer[index + 3] = p.1.a();
}
Ok(())
}
}
// pub fn set_color_at(&mut self, x: i32, y: i32, color: Color) {
// let x: usize = x as usize;
// let y: usize = y as usize;
// if !(0..=self.width).contains(&x) || !(0..=self.height).contains(&y) {
// return;
// }
// let index = (x + (self.width * y)) * 4;
// let srgba = Srgba::from(color);
// if index >= self.buffer.len() {
// return;
// }
// self.buffer[index] = (srgba.red * u8::MAX as f32) as u8;
// self.buffer[index + 1] = (srgba.green * u8::MAX as f32) as u8;
// self.buffer[index + 2] = (srgba.blue * u8::MAX as f32) as u8;
// self.buffer[index + 3] = (srgba.alpha * u8::MAX as f32) as u8;
// }
// pub fn clear(&mut self) {
// self.buffer.fill(0);
// }
// pub fn draw_line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, thickness: f32, color: Color) {
// let (mut x0, mut y0) = (x1, y1);
// let (x1, y1) = (x2, y2);
// let dx = (x1 - x0).abs();
// let dy = -(y1 - y0).abs();
// let sx = if x0 < x1 { 1 } else { -1 };
// let sy = if y0 < y1 { 1 } else { -1 };
// let mut err = dx + dy;
// let half_t = (thickness / 2.0).ceil() as i32;
// loop {
// self.draw_thick_point(x0, y0, half_t, color);
// if x0 == x1 && y0 == y1 {
// break;
// }
// let e2 = 2 * err;
// if e2 >= dy {
// err += dy;
// x0 += sx;
// }
// if e2 <= dx {
// err += dx;
// y0 += sy;
// }
// }
// }
// // Draw a small square brush (fast, branch-free inner loop)
// pub fn draw_thick_point(&mut self, cx: i32, cy: i32, radius: i32, color: Color) {
// self.draw_filled_circle(cx, cy, radius, color);
// }
// pub fn draw_filled_circle(&mut self, cx: i32, cy: i32, radius: i32, color: Color) {
// let r2 = radius * radius;
// for dy in -radius..=radius {
// let y = cy + dy;
// if y < 0 {
// continue;
// }
// let dx_limit = ((r2 - dy * dy) as f32).sqrt() as i32;
// let start_x = cx - dx_limit;
// let end_x = cx + dx_limit;
// for x in start_x..=end_x {
// if x >= 0 {
// self.set_color_at(x, y, color);
// }
// }
// }
// }
// pub fn draw_circle(&mut self, cx: i32, cy: i32, radius: i32, thickness: f32, color: Color) {
// if radius <= 0 {
// return;
// }
// let half_t = (thickness / 2.0).max(0.5);
// let outer_r = radius as f32 + half_t;
// let inner_r = (radius as f32 - half_t).max(0.0);
// let outer_r2 = (outer_r * outer_r) as i32;
// let inner_r2 = (inner_r * inner_r) as i32;
// let max_r = outer_r.ceil() as i32;
// for dy in -max_r..=max_r {
// let y = cy + dy;
// if y < 0 {
// continue;
// }
// let dy2 = dy * dy;
// if dy2 > outer_r2 {
// continue;
// }
// let outer_dx = ((outer_r2 - dy2) as f32).sqrt() as i32;
// let inner_dx = if dy2 < inner_r2 {
// ((inner_r2 - dy2) as f32).sqrt() as i32
// } else {
// -1
// };
// let left_outer = cx - outer_dx;
// let right_outer = cx + outer_dx;
// if inner_dx >= 0 {
// let left_inner = cx - inner_dx;
// let right_inner = cx + inner_dx;
// // left segment
// for x in left_outer..left_inner {
// if x >= 0 {
// self.set_color_at(x, y, color);
// }
// }
// // right segment
// for x in (right_inner + 1)..=right_outer {
// if x >= 0 {
// self.set_color_at(x, y, color);
// }
// }
// } else {
// // fully filled span (very thin or small radius)
// for x in left_outer..=right_outer {
// if x >= 0 {
// self.set_color_at(x, y, color);
// }
// }
// }
// }
// }
// pub fn draw_rectangle(&mut self, x: i32, y: i32, w: u32, h: u32, thickness: f32, color: Color) {
// let w = w as i32;
// let h = h as i32;
// self.draw_line(x, y, x + w, y, thickness, color);
// self.draw_line(x + w, y, x + w, y + h, thickness, color);
// self.draw_line(x, y + h, x + w, y + h, thickness, color);
// self.draw_line(x, y, x, y + h, thickness, color);
// }
// pub fn draw_filled_rectangle(
// &mut self,
// x: i32,
// y: i32,
// w: u32,
// h: u32,
// thickness: f32,
// color: Color,
// ) {
// let w = w as i32;
// let h = h as i32;
// for i in 0..h {
// self.draw_line(x, y + i, x + w, y + i, thickness, color);
// }
// }
// }

94
src/drawingplugin/rgba.rs Normal file
View File

@@ -0,0 +1,94 @@
use bevy::color::Srgba;
use embedded_graphics_core::pixelcolor::*;
/// Simple RGBA color wrapper.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Rgba<C: RgbColor>(C, u8);
#[allow(unused)]
#[inline(always)]
fn mul_blend_u8(delta: u32, a: u32) -> u32 {
// Exact (delta * a) / 255 using the div255 trick (no slow integer division).
// Valid for 0..=65535 inputs; see Hacker's Delight 10-16.
let t = delta * a + 128;
(t + (t >> 8)) >> 8
}
#[allow(unused)]
impl<C: RgbColor> Rgba<C> {
/// Create a new RGBA color.
pub const fn new(color: C, alpha: u8) -> Self {
Self(color, alpha)
}
/// Get the color component.
pub const fn rgb(&self) -> C {
self.0
}
pub fn r(&self) -> u8 {
self.0.r()
}
pub fn g(&self) -> u8 {
self.0.g()
}
pub fn b(&self) -> u8 {
self.0.b()
}
/// Get the alpha component (0..=255).
pub const fn a(&self) -> u8 {
self.1
}
}
impl<C: RgbColor> PixelColor for Rgba<C> {
type Raw = C::Raw;
}
#[allow(unused)]
pub trait Blend<T> {
fn blend(&self, bg: T) -> T;
}
impl Blend<Rgb888> for Rgba<Rgb888> {
#[inline(always)]
fn blend(&self, bg: Rgb888) -> Rgb888 {
let a = self.a() as u32;
if a == 0 {
return bg;
}
if a == 255 {
return self.rgb();
}
let fr = self.rgb().r() as u32;
let fg = self.rgb().g() as u32;
let fb = self.rgb().b() as u32;
let br = bg.r() as u32;
let bgc = bg.g() as u32;
let bb = bg.b() as u32;
let r = (br + mul_blend_u8(fr.wrapping_sub(br), a)) as u8;
let g = (bgc + mul_blend_u8(fg.wrapping_sub(bgc), a)) as u8;
let b = (bb + mul_blend_u8(fb.wrapping_sub(bb), a)) as u8;
Rgb888::new(r, g, b)
}
}
impl From<Srgba> for Rgba<Rgb888> {
fn from(value: Srgba) -> Self {
Self(
Rgb888::new(
(value.red * 255.) as u8,
(value.green * 255.) as u8,
(value.blue * 255.) as u8,
),
(value.alpha * 255.) as u8,
)
}
}

View File

@@ -0,0 +1,270 @@
use std::f32;
use bevy::{color::palettes::css, prelude::*};
use embedded_graphics::prelude::DrawTarget;
use crate::{
drawingplugin::{DrawingBuffer, IMAGE_HEIGHT, IMAGE_WIDTH, PenColor, drawtarget::Visible},
otdipcplugin::{PenButtons, PenPosition},
};
use super::drawtarget::{DrawableLayer, Layer};
#[derive(Component)]
pub struct UiBuffer;
#[derive(Component, Deref)]
pub struct UiPosition(Vec2);
pub struct UiPlugin;
impl Plugin for UiPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, setup).add_systems(
Update,
(
show_hide,
ui_on_show,
ui_on_hide,
color_changer,
clear,
color_picker,
),
);
}
}
fn setup(mut commands: Commands) {
commands.spawn((
UiBuffer,
DrawableLayer::new(IMAGE_WIDTH, IMAGE_HEIGHT, Layer::Ui),
));
}
fn show_hide(
mut commands: Commands,
mut pen_buttons: MessageReader<PenButtons>,
ent: Query<Entity, With<UiBuffer>>,
) {
let Ok(ent) = ent.single() else {
return;
};
let Some(buttons) = pen_buttons.read().next() else {
return;
};
if buttons.b() {
commands.entity(ent).insert(Visible);
} else {
commands.entity(ent).remove::<Visible>();
}
}
fn ui_on_show(
mut commands: Commands,
ent: Query<Entity, Added<Visible>>,
mut pen_position: MessageReader<PenPosition>,
) {
let Ok(ent) = ent.single() else {
return;
};
let Some(pos) = pen_position.read().next() else {
return;
};
commands.entity(ent).insert(UiPosition(**pos));
}
fn ui_on_hide(mut commands: Commands, mut removed: RemovedComponents<Visible>) {
let Some(ent) = removed.read().next() else {
return;
};
commands
.entity(ent)
.insert(UiPosition(Vec2::new(-1000., -1000.)));
}
fn color_picker(mut buffer: Query<(&mut DrawableLayer, &UiPosition), With<UiBuffer>>) {
let Ok((mut buffer, base_pos)) = buffer.single_mut() else {
return;
};
let w = buffer.width as f32;
let h = buffer.height as f32;
let x = (base_pos.x * w) as i32;
let y = (base_pos.y * h) as i32;
buffer.clear(Srgba::new(0.0, 0.0, 0.0, 0.0).into()).ok();
color_wheel(&mut buffer, x, y, 100);
buffer.draw_circle(x, y, 100, 5.0, css::BLACK.into());
buffer.draw_circle(x, y, 125, 3.0, css::BLACK.into());
}
#[allow(clippy::type_complexity)]
fn clear(
buffer: Query<
(&DrawableLayer, &UiPosition),
(With<UiBuffer>, With<Visible>, Without<DrawingBuffer>),
>,
mut draw_buffer: Query<&mut DrawableLayer, (With<DrawingBuffer>, Without<UiBuffer>)>,
mut pen_position: MessageReader<PenPosition>,
mut pen_buttons: MessageReader<PenButtons>,
) {
let Ok((buffer, base_pos)) = buffer.single() else {
return;
};
let Ok(mut draw_buffer) = draw_buffer.single_mut() else {
return;
};
let Some(pos) = pen_position.read().next() else {
return;
};
let Some(buttons) = pen_buttons.read().next() else {
return;
};
if !buttons.tip() {
return;
}
let w = buffer.width as f32;
let h = buffer.height as f32;
let ui_x = base_pos.x * w;
let ui_y = base_pos.y * h;
let pen_x = pos.x * w;
let pen_y = pos.y * h;
let delta = Vec2::new(pen_x - ui_x, pen_y - ui_y);
let radius = 100.;
let r_sq = radius * radius;
let dist_sq = delta.length_squared();
if dist_sq <= (r_sq * 1.5) {
return;
}
draw_buffer.clear(Srgba::rgba_u8(0, 0, 0, 0).into()).ok();
}
#[allow(clippy::type_complexity)]
fn color_changer(
buffer: Query<(&DrawableLayer, &UiPosition), (With<UiBuffer>, With<Visible>)>,
mut pen_color: ResMut<PenColor>,
mut pen_position: MessageReader<PenPosition>,
mut pen_buttons: MessageReader<PenButtons>,
) {
let Ok((buffer, base_pos)) = buffer.single() else {
return;
};
let Some(pos) = pen_position.read().next() else {
return;
};
let Some(buttons) = pen_buttons.read().next() else {
return;
};
if !buttons.tip() {
return;
}
let w = buffer.width as f32;
let h = buffer.height as f32;
let ui_x = base_pos.x * w;
let ui_y = base_pos.y * h;
let pen_x = pos.x * w;
let pen_y = pos.y * h;
let delta = Vec2::new(pen_x - ui_x, pen_y - ui_y);
let radius = 100.;
let r_sq = radius * radius;
let dist_sq = delta.length_squared();
if dist_sq > (r_sq * 1.5) {
return;
}
pen_color.0 = color_from_pos(delta.x, delta.y, radius);
}
fn color_wheel(buffer: &mut DrawableLayer, cx: i32, cy: i32, radius: i32) {
for dy in -radius..=radius {
for dx in -radius..=radius {
let x = cx + dx;
let y = cy + dy;
buffer.set_color_at(x, y, color_from_pos(dx as f32, dy as f32, radius as f32));
}
}
}
fn color_from_pos(x: f32, y: f32, radius: f32) -> Color {
let r_sq = radius * radius;
let dist_sq = x * x + y * y;
if dist_sq > r_sq {
return Color::srgba(0.0, 0.0, 0.0, 0.0);
}
// Distance normalized (0.0 → 1.0)
let dist = dist_sq.sqrt() / radius;
// Angle in radians → [0, 1]
let angle = y.atan2(x); // -PI..PI
let hue = (angle + std::f32::consts::PI) / (2.0 * std::f32::consts::PI);
let (r, g, b) = hsl_to_rgb(hue, 1.0, dist);
Color::srgba(r, g, b, 1.0)
}
fn hsl_to_rgb(h: f32, s: f32, l: f32) -> (f32, f32, f32) {
if s == 0.0 {
return (l, l, l);
}
fn hue_to_rgb(p: f32, q: f32, mut t: f32) -> f32 {
if t < 0.0 {
t += 1.0;
}
if t > 1.0 {
t -= 1.0;
}
if t < 1.0 / 6.0 {
return p + (q - p) * 6.0 * t;
}
if t < 1.0 / 2.0 {
return q;
}
if t < 2.0 / 3.0 {
return p + (q - p) * (2.0 / 3.0 - t) * 6.0;
}
p
}
let q = if l < 0.5 {
l * (1.0 + s)
} else {
l + s - l * s
};
let p = 2.0 * l - q;
let r = hue_to_rgb(p, q, h + 1.0 / 3.0);
let g = hue_to_rgb(p, q, h);
let b = hue_to_rgb(p, q, h - 1.0 / 3.0);
(r, g, b)
}

View File

@@ -1,21 +1,22 @@
use std::f32::consts::PI;
use avian3d::{math::FRAC_PI_2, prelude::*};
use bevy::prelude::*; use bevy::prelude::*;
use bevy_cef::prelude::*; use bevy_cef::prelude::*;
use bevy_mod_openxr::prelude::*; use bevy_mod_openxr::prelude::*;
use bevy_mod_xr::session::XrSessionCreated;
use bevy_pkv::{PersistentResourceAppExtensions, PkvStore}; use bevy_pkv::{PersistentResourceAppExtensions, PkvStore};
use openxr::Path; use openxr::Path;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::f32::consts::{FRAC_PI_2, PI};
use crate::{ use crate::{
MainCamera,
drawingplugin::{self, MyProcGenImage},
vrcontrollerplugin::{ vrcontrollerplugin::{
LeftController, LeftControllerActions, RightController, RightControllerActions, LeftController, LeftControllerActions, RightController, RightControllerActions,
}, },
vrplugin::{Headset, MainCamera, create_view_space}, vrplugin::Headset,
}; };
// use bevy_mod_xr::session::XrSessionCreated;
#[derive(Component)] #[derive(Component)]
pub struct LookedAt; pub struct LookedAt;
@@ -41,7 +42,6 @@ pub struct KneeboardPlugin;
impl Plugin for KneeboardPlugin { impl Plugin for KneeboardPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_plugins(PhysicsPlugins::default());
app.add_plugins(CefPlugin { app.add_plugins(CefPlugin {
command_line_config: CommandLineConfig { command_line_config: CommandLineConfig {
switches: ["--no-zygote", "--no-sandbox"].to_vec(), switches: ["--no-zygote", "--no-sandbox"].to_vec(),
@@ -51,7 +51,7 @@ impl Plugin for KneeboardPlugin {
}); });
app.insert_resource(PkvStore::new("Avii", "Kneeboard")) app.insert_resource(PkvStore::new("Avii", "Kneeboard"))
.init_persistent_resource::<KneeboardPosition>(); .init_persistent_resource::<KneeboardPosition>();
app.add_systems(XrSessionCreated, spawn_kneeboard.after(create_view_space)); app.add_systems(Startup, spawn_kneeboard.after(drawingplugin::setup));
app.add_systems(Update, gaze.run_if(openxr_session_running)); app.add_systems(Update, gaze.run_if(openxr_session_running));
app.add_systems(Update, move_keyboard.run_if(openxr_session_running)); app.add_systems(Update, move_keyboard.run_if(openxr_session_running));
app.add_systems(Update, position_kneeboard.after(move_keyboard)); app.add_systems(Update, position_kneeboard.after(move_keyboard));
@@ -108,7 +108,9 @@ fn position_kneeboard(
return; return;
}; };
let head = head.single().expect("a head to exist"); let Ok(head) = head.single() else {
return;
};
transform.translation = kneeboard.position; transform.translation = kneeboard.position;
transform.rotation = kneeboard.rotation; transform.rotation = kneeboard.rotation;
@@ -160,21 +162,22 @@ fn spawn_kneeboard(
mut commands: Commands, mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>, mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<WebviewExtendStandardMaterial>>, mut materials: ResMut<Assets<WebviewExtendStandardMaterial>>,
image_handle: Res<MyProcGenImage>,
position: Res<KneeboardPosition>, position: Res<KneeboardPosition>,
) { ) {
commands.spawn(( commands.spawn((
RigidBody::Static, // WebviewSource::new("http://localhost:7878/MOSRPRPETASPCLORWTSURDEP"),
WebviewSource::new("http://localhost:7878/"),
WebviewSize(Vec2::new(210.0 * 3.5, 279.0 * 3.5)), WebviewSize(Vec2::new(210.0 * 3.5, 279.0 * 3.5)),
Collider::cuboid(0.210, 0.279, 0.01),
CollidingEntities::default(),
Mesh3d(meshes.add(Cuboid::new(0.210, 0.279, 0.01))), Mesh3d(meshes.add(Cuboid::new(0.210, 0.279, 0.01))),
MeshMaterial3d(materials.add(WebviewExtendStandardMaterial { MeshMaterial3d(materials.add(WebviewExtendStandardMaterial {
base: StandardMaterial { base: StandardMaterial {
unlit: true, unlit: true,
..default() ..default()
}, },
..Default::default() extension: WebviewMaterial {
surface: None,
overlay: Some(image_handle.0.clone()),
},
})), })),
Transform::from_translation(position.position).rotate(position.rotation), Transform::from_translation(position.position).rotate(position.rotation),
Kneeboard, Kneeboard,

View File

@@ -1,25 +1,59 @@
//! A simple 3D scene with light shining over a cube sitting on a plane. mod drawingplugin;
mod kneeboardplugin; mod kneeboardplugin;
mod otdipcplugin;
#[allow(unused)]
mod vrcontrollerplugin; mod vrcontrollerplugin;
#[allow(unused)]
mod vrplugin; mod vrplugin;
#[allow(unused)]
use vrcontrollerplugin::VrControllersPlugin;
#[allow(unused)]
use vrplugin::VrPlugin; use vrplugin::VrPlugin;
use bevy::prelude::*; use bevy::{
prelude::*,
window::{PresentMode, WindowResolution},
};
use crate::{kneeboardplugin::KneeboardPlugin, vrcontrollerplugin::VrControllersPlugin}; use crate::{
drawingplugin::DrawingPlugin, kneeboardplugin::KneeboardPlugin, otdipcplugin::TabletRotation,
};
#[derive(Component)]
#[require(Camera3d)]
pub struct MainCamera;
fn main() { fn main() {
App::new() App::new()
.insert_resource(ClearColor(Color::linear_rgb(1.0, 0.0, 1.0))) // .add_plugins(VrPlugin)
.add_plugins(VrPlugin) // .add_plugins(VrControllersPlugin)
.add_plugins(VrControllersPlugin) .add_plugins(DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
title: "Kneeboard".into(),
resolution: WindowResolution::new(550, 720),
present_mode: PresentMode::AutoNoVsync,
fit_canvas_to_parent: true,
prevent_default_event_handling: false,
..default()
}),
..default()
}))
.add_systems(Startup, setup)
.add_plugins(DrawingPlugin)
.add_plugins(KneeboardPlugin) .add_plugins(KneeboardPlugin)
.insert_resource(ClearColor(Color::NONE)) .insert_resource(TabletRotation::CW)
// .insert_resource(GlobalAmbientLight {
// brightness: 1000.0,
// ..GlobalAmbientLight::default()
// })
.run(); .run();
} }
fn setup(mut commands: Commands) {
commands.spawn((
Camera {
clear_color: ClearColorConfig::Custom(Color::linear_rgb(0.3, 0.3, 0.3)),
..default()
},
MainCamera,
Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
));
}

131
src/otdipcplugin.rs Normal file
View File

@@ -0,0 +1,131 @@
use bevy::{
app::{App, Plugin, PreUpdate},
ecs::{
message::MessageWriter,
resource::Resource,
system::{Res, ResMut},
},
math::Vec2,
prelude::Deref,
};
use otd_ipc::{Message, OtdIpc};
use triple_buffer::{Output, triple_buffer};
#[derive(Resource)]
struct OtdChannel(Output<Option<Message>>);
#[derive(Resource)]
struct TabletSize(Option<Vec2>);
#[derive(Resource)]
struct MaxPenPressure(Option<u32>);
#[derive(bevy::ecs::message::Message, Deref)]
pub struct PenPosition(Vec2);
#[derive(bevy::ecs::message::Message, Deref)]
pub struct PenButtons(u32);
impl PenButtons {
pub fn tip(&self) -> bool {
self.0 & 1 == 1
}
pub fn a(&self) -> bool {
self.0 & 2 == 2
}
pub fn b(&self) -> bool {
self.0 & 4 == 4
}
}
#[derive(bevy::ecs::message::Message)]
pub struct PenPressure {
pub pressure: f32,
}
#[allow(clippy::upper_case_acronyms)]
#[allow(unused)]
#[derive(Resource)]
pub enum TabletRotation {
Default,
CW,
UpsideDown,
CCW,
}
pub struct OtdIpcPlugin;
impl Plugin for OtdIpcPlugin {
fn build(&self, app: &mut App) {
let (mut tx, rx) = triple_buffer(&None);
std::thread::spawn(move || {
let otd_ipc = OtdIpc::new("Kneeboard", "master").unwrap();
for msg in otd_ipc {
tx.write(Some(msg));
}
});
app.add_message::<PenPosition>();
app.add_message::<PenPressure>();
app.add_message::<PenButtons>();
app.insert_resource(TabletRotation::Default);
app.insert_resource(OtdChannel(rx));
app.insert_resource(MaxPenPressure(None));
app.insert_resource(TabletSize(None));
app.add_systems(PreUpdate, reader);
}
}
#[allow(clippy::too_many_arguments)]
fn reader(
rotation: Res<TabletRotation>,
mut channel: ResMut<OtdChannel>,
mut size: ResMut<TabletSize>,
mut pressure: ResMut<MaxPenPressure>,
mut pressure_writer: MessageWriter<PenPressure>,
mut position_writer: MessageWriter<PenPosition>,
mut button_writer: MessageWriter<PenButtons>,
) {
let Some(msg) = channel.0.read() else {
return;
};
match msg {
otd_ipc::Message::DeviceInfo(info) => {
size.0 = Some(Vec2::new(info.max_x, info.max_y));
pressure.0 = Some(info.max_pressure);
}
otd_ipc::Message::State(state) => {
let Some(size) = size.0 else {
return;
};
let Some(pressure) = pressure.0 else {
return;
};
button_writer.write(PenButtons(state.pen_buttons()));
let p = state.pressure() as f32 / pressure as f32;
pressure_writer.write(PenPressure { pressure: p });
let x = state.x();
let y = state.y();
let loc = match *rotation {
TabletRotation::Default => Vec2::new(x / size.x, y / size.y),
TabletRotation::CCW => Vec2::new(y / size.y, (size.x - x) / size.x),
TabletRotation::CW => Vec2::new((size.y - y) / size.y, x / size.x),
TabletRotation::UpsideDown => {
Vec2::new((size.x - x) / size.x, (size.y - y) / size.y)
}
};
position_writer.write(PenPosition(loc));
}
_ => {}
}
}

View File

@@ -46,11 +46,17 @@ impl Plugin for VrControllersPlugin {
.run_if(openxr_session_running), .run_if(openxr_session_running),
); );
app.add_systems(OxrSendActionBindings, suggest_action_bindings_left);
app.add_systems(OxrSendActionBindings, suggest_action_bindings_right);
app.add_systems(Startup, create_actions_left.run_if(session_available)); app.add_systems(Startup, create_actions_left.run_if(session_available));
app.add_systems(Startup, create_actions_right.run_if(session_available)); app.add_systems(Startup, create_actions_right.run_if(session_available));
app.add_systems(
OxrSendActionBindings,
suggest_action_bindings_left.after(create_actions_left),
);
app.add_systems(
OxrSendActionBindings,
suggest_action_bindings_right.after(create_actions_right),
);
} }
} }

View File

@@ -1,11 +1,11 @@
use bevy::prelude::*; use bevy::{
prelude::*,
render::render_resource::TextureFormat,
window::{PresentMode, WindowResolution},
};
use bevy_mod_openxr::prelude::*; use bevy_mod_openxr::prelude::*;
use bevy_mod_xr::session::XrSessionCreated; use bevy_mod_xr::session::XrSessionCreated;
#[derive(Component)]
#[require(Camera3d)]
pub struct MainCamera;
#[derive(Component)] #[derive(Component)]
pub struct Headset; pub struct Headset;
@@ -14,32 +14,36 @@ pub struct VrPlugin;
impl Plugin for VrPlugin { impl Plugin for VrPlugin {
fn build(&self, app: &mut bevy::app::App) { fn build(&self, app: &mut bevy::app::App) {
app.add_plugins( app.add_plugins(
add_xr_plugins(DefaultPlugins) add_xr_plugins(DefaultPlugins.set(WindowPlugin {
.disable::<HandTrackingPlugin>() primary_window: Some(Window {
.build() title: "Kneeboard".into(),
.set(OxrInitPlugin { resolution: WindowResolution::new(550, 720),
exts: { present_mode: PresentMode::AutoNoVsync,
let mut exts = OxrExtensions::default(); fit_canvas_to_parent: true,
exts.extx_overlay = true; prevent_default_event_handling: false,
exts ..default()
},
..Default::default()
}), }),
..default()
}))
.disable::<HandTrackingPlugin>()
.build()
.set(OxrInitPlugin {
exts: {
let mut exts = OxrExtensions::default();
exts.extx_overlay = true;
exts
},
..Default::default()
}),
); );
app.insert_resource(OxrSessionConfig { app.insert_resource(OxrSessionConfig {
blend_mode_preference: { blend_mode_preference: { vec![EnvironmentBlendMode::ALPHA_BLEND] },
vec![ formats: Some(vec![TextureFormat::Rgba8UnormSrgb]),
EnvironmentBlendMode::ALPHA_BLEND, ..Default::default()
EnvironmentBlendMode::ADDITIVE,
EnvironmentBlendMode::OPAQUE,
]
},
..OxrSessionConfig::default()
}); });
app.add_systems(XrSessionCreated, create_view_space); app.add_systems(XrSessionCreated, create_view_space);
// .add_systems(Update, sync_head_with_camera.run_if(openxr_session_running));
} }
} }
@@ -49,21 +53,4 @@ pub fn create_view_space(session: Res<OxrSession>, mut commands: Commands) {
.unwrap(); .unwrap();
commands.spawn((Headset, space.0)); commands.spawn((Headset, space.0));
commands.spawn((
Camera {
clear_color: ClearColorConfig::Custom(Color::linear_rgb(1.0, 0.0, 1.0)),
..default()
},
MainCamera,
Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
));
} }
// fn sync_head_with_camera(
// heads: Query<&Transform, With<Headset>>,
// cameras: Query<&mut Transform, (With<MainCamera>, Without<Headset>)>,
// ) {
// for mut camera in cameras {
// *camera = *heads.single().unwrap();
// }
// }