From ea5332e4a1a035e888709bee278fcafb182f7922 Mon Sep 17 00:00:00 2001 From: LLLL Colonq Date: Fri, 31 Jul 2026 05:00:49 -0400 Subject: Update --- .../rpc2dot0/vendor/teleia/.dir-locals.el | 7 + .../rpc2dot0/vendor/teleia/.envrc | 1 + .../rpc2dot0/vendor/teleia/.gitignore | 5 + .../rpc2dot0/vendor/teleia/.gitmodules | 0 .../rpc2dot0/vendor/teleia/Cargo.lock | 3344 ++++++++++++++++++++ .../rpc2dot0/vendor/teleia/Cargo.toml | 19 + .../vendor/teleia/crates/teleia/Cargo.toml | 53 + .../rpc2dot0/vendor/teleia/crates/teleia/build.rs | 15 + .../crates/teleia/src/assets/fonts/default.png | Bin 0 -> 1042 bytes .../crates/teleia/src/assets/fonts/small.png | Bin 0 -> 904 bytes .../crates/teleia/src/assets/meshes/square.obj | 15 + .../teleia/src/assets/shaders/bitmap/frag.glsl | 15 + .../teleia/src/assets/shaders/bitmap/vert.glsl | 20 + .../teleia/src/assets/shaders/common/frag.glsl | 160 + .../teleia/src/assets/shaders/common/vert.glsl | 30 + .../teleia/src/assets/shaders/flat/frag.glsl | 12 + .../teleia/src/assets/shaders/flat/vert.glsl | 4 + .../teleia/src/assets/shaders/scale/frag.glsl | 12 + .../teleia/src/assets/shaders/scale/vert.glsl | 22 + .../teleia/src/assets/shaders/scene/frag.glsl | 11 + .../teleia/src/assets/shaders/scene/vert.glsl | 18 + .../teleia/src/assets/shaders/test/frag.glsl | 23 + .../teleia/src/assets/shaders/test/vert.glsl | 4 + .../teleia/src/assets/shaders/tiled/frag.glsl | 12 + .../teleia/src/assets/shaders/tiled/vert.glsl | 14 + .../teleia/src/assets/shaders/truetype/frag.glsl | 16 + .../teleia/src/assets/shaders/truetype/vert.glsl | 17 + .../teleia/src/assets/shaders/uber/frag.glsl | 193 ++ .../teleia/src/assets/shaders/uber/vert.glsl | 41 + .../vendor/teleia/crates/teleia/src/audio.rs | 341 ++ .../vendor/teleia/crates/teleia/src/context.rs | 302 ++ .../vendor/teleia/crates/teleia/src/font.rs | 194 ++ .../vendor/teleia/crates/teleia/src/framebuffer.rs | 158 + .../vendor/teleia/crates/teleia/src/helpers.js | 21 + .../vendor/teleia/crates/teleia/src/js/module.js | 7 + .../vendor/teleia/crates/teleia/src/level2d.rs | 1 + .../teleia/crates/teleia/src/level2d/tiled.rs | 301 ++ .../vendor/teleia/crates/teleia/src/lib.rs | 355 +++ .../vendor/teleia/crates/teleia/src/mesh.rs | 197 ++ .../vendor/teleia/crates/teleia/src/net.rs | 4 + .../vendor/teleia/crates/teleia/src/net/fig.rs | 100 + .../vendor/teleia/crates/teleia/src/net/ws.rs | 10 + .../teleia/crates/teleia/src/net/ws/client.rs | 9 + .../crates/teleia/src/net/ws/client/native.rs | 124 + .../teleia/crates/teleia/src/net/ws/client/wasm.rs | 73 + .../teleia/crates/teleia/src/net/ws/server.rs | 140 + .../vendor/teleia/crates/teleia/src/physics.rs | 0 .../vendor/teleia/crates/teleia/src/renderer.rs | 337 ++ .../vendor/teleia/crates/teleia/src/save.rs | 47 + .../vendor/teleia/crates/teleia/src/scene.rs | 401 +++ .../vendor/teleia/crates/teleia/src/shader.rs | 260 ++ .../vendor/teleia/crates/teleia/src/shadow.rs | 127 + .../vendor/teleia/crates/teleia/src/state.rs | 735 +++++ .../vendor/teleia/crates/teleia/src/texture.rs | 156 + .../rpc2dot0/vendor/teleia/crates/teleia/src/ui.rs | 169 + .../vendor/teleia/crates/teleia/src/utils.rs | 147 + .../vendor/teleia/crates/teleia_macros/Cargo.toml | 14 + .../vendor/teleia/crates/teleia_macros/src/lib.rs | 231 ++ .../examples/assets/fonts/ComicNeue-Regular.ttf | Bin 0 -> 54848 bytes .../vendor/teleia/examples/assets/meshes/cube.obj | 38 + .../vendor/teleia/examples/assets/scenes/fox.glb | Bin 0 -> 162852 bytes .../teleia/examples/assets/textures/test.png | Bin 0 -> 125 bytes .../rpc2dot0/vendor/teleia/examples/fox.rs | 72 + .../rpc2dot0/vendor/teleia/flake.lock | 153 + .../rpc2dot0/vendor/teleia/flake.nix | 250 ++ 65 files changed, 9557 insertions(+) create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/.dir-locals.el create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/.envrc create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/.gitignore create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/.gitmodules create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/Cargo.lock create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/Cargo.toml create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/Cargo.toml create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/build.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/fonts/default.png create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/fonts/small.png create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/meshes/square.obj create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/bitmap/frag.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/bitmap/vert.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/common/frag.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/common/vert.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/flat/frag.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/flat/vert.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scale/frag.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scale/vert.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scene/frag.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scene/vert.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/test/frag.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/test/vert.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/tiled/frag.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/tiled/vert.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/truetype/frag.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/truetype/vert.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/uber/frag.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/uber/vert.glsl create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/audio.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/context.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/font.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/framebuffer.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/helpers.js create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/js/module.js create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/level2d.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/level2d/tiled.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/lib.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/mesh.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/fig.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/client.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/client/native.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/client/wasm.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/server.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/physics.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/renderer.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/save.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/scene.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/shader.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/shadow.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/state.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/texture.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/ui.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/utils.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia_macros/Cargo.toml create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia_macros/src/lib.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/fonts/ComicNeue-Regular.ttf create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/meshes/cube.obj create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/scenes/fox.glb create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/textures/test.png create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/examples/fox.rs create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/flake.lock create mode 100644 2026/games_submissions/rpc2dot0/vendor/teleia/flake.nix (limited to '2026/games_submissions/rpc2dot0/vendor') diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/.dir-locals.el b/2026/games_submissions/rpc2dot0/vendor/teleia/.dir-locals.el new file mode 100644 index 0000000..45e0286 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/.dir-locals.el @@ -0,0 +1,7 @@ +((rust-ts-mode . + ((eglot-workspace-configuration . + (:rust-analyzer + ( :check (:command "clippy") + :cargo (;; :target "wasm32-unknown-unknown" + :targetDir t) + :hover (:show (:fields 10)))))))) diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/.envrc b/2026/games_submissions/rpc2dot0/vendor/teleia/.envrc new file mode 100644 index 0000000..063b56f --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/.envrc @@ -0,0 +1 @@ +use_flake diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/.gitignore b/2026/games_submissions/rpc2dot0/vendor/teleia/.gitignore new file mode 100644 index 0000000..2049df0 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/.gitignore @@ -0,0 +1,5 @@ +/.direnv +/target +/.cargo +/dist +/result \ No newline at end of file diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/.gitmodules b/2026/games_submissions/rpc2dot0/vendor/teleia/.gitmodules new file mode 100644 index 0000000..e69de29 diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/Cargo.lock b/2026/games_submissions/rpc2dot0/vendor/teleia/Cargo.lock new file mode 100644 index 0000000..71d423b --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/Cargo.lock @@ -0,0 +1,3344 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ab_glyph" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80179d7dd5d7e8c285d67c4a1e652972a92de7475beddfb92028c76463b13225" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b79b82693f705137f8fb9b37871d99e4f9a7df12b917eed79c3d3954830a60b" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "alsa" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" +dependencies = [ + "alsa-sys", + "bitflags 2.6.0", + "cfg-if", + "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.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" +dependencies = [ + "android-properties", + "bitflags 2.6.0", + "cc", + "cesu8", + "jni", + "jni-sys", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum", + "thiserror 1.0.57", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[package]] +name = "anstream" +version = "0.6.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bimap" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" + +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn", +] + +[[package]] +name = "bit-vec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" +dependencies = [ + "objc-sys", +] + +[[package]] +name = "block2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" +dependencies = [ + "block-sys", + "objc2 0.4.1", +] + +[[package]] +name = "bumpalo" +version = "3.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" + +[[package]] +name = "bytemuck" +version = "1.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +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 = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" + +[[package]] +name = "calloop" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" +dependencies = [ + "bitflags 2.6.0", + "log", + "polling", + "rustix 0.38.31", + "slab", + "thiserror 1.0.57", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" +dependencies = [ + "calloop", + "rustix 0.38.31", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "cc" +version = "1.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "core-graphics" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "970a29baf4110c26fedbc7f82107d42c23f7e88e404c4577ed73fe99ff85a212" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "coreaudio-rs" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" +dependencies = [ + "bitflags 1.3.2", + "core-foundation-sys", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ce857aa0b77d77287acc1ac3e37a05a8c95a2af3647d23b15f263bdaeb7562b" +dependencies = [ + "bindgen", +] + +[[package]] +name = "cpal" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" +dependencies = [ + "alsa", + "core-foundation-sys", + "coreaudio-rs", + "dasp_sample", + "jni", + "js-sys", + "libc", + "mach2", + "ndk", + "ndk-context", + "oboe", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +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]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cursor-icon" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" +dependencies = [ + "serde", +] + +[[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.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" + +[[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" +version = "6.0.0" +source = "git+https://github.com/lcolonq/directories-rs#164536daab2c07265167715934081cb1942387b0" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "ena" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" +dependencies = [ + "log", +] + +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-map" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" +dependencies = [ + "enum-map-derive", +] + +[[package]] +name = "enum-map-derive" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "env" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc95de49ad098572c02d3fbf368c9a020bfff5ae78483685b77f51d8a7e9486d" +dependencies = [ + "num_threads", +] + +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "extended" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af9673d8203fcb076b19dfd17e38b3d4ae9f44959416ea532ce72415a6020365" + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + +[[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 0.3.1", +] + +[[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", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[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.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "glam" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677" +dependencies = [ + "mint", +] + +[[package]] +name = "glfw" +version = "0.59.0" +source = "git+https://github.com/lcolonq/glfw-rs#1ce13a2bcf3ef3bf6184bcb4c2a90d9034956841" +dependencies = [ + "bitflags 1.3.2", + "objc2 0.5.2", + "raw-window-handle", + "serde", + "winapi", +] + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "glow" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gltf" +version = "1.4.1" +source = "git+https://github.com/lcolonq/gltf#9763a5abe8c168eb1282a037ff16668542fe2a6d" +dependencies = [ + "base64 0.13.1", + "byteorder", + "gltf-json", + "image", + "lazy_static", + "serde_json", + "urlencoding", +] + +[[package]] +name = "gltf-derive" +version = "1.4.1" +source = "git+https://github.com/lcolonq/gltf#9763a5abe8c168eb1282a037ff16668542fe2a6d" +dependencies = [ + "inflections", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "gltf-json" +version = "1.4.1" +source = "git+https://github.com/lcolonq/gltf#9763a5abe8c168eb1282a037ff16668542fe2a6d" +dependencies = [ + "gltf-derive", + "serde", + "serde_derive", + "serde_json", +] + +[[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.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + +[[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]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "icrate" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" +dependencies = [ + "block2", + "dispatch", + "objc2 0.4.1", +] + +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "moxcms", + "num-traits", + "png", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.0", +] + +[[package]] +name = "inflections" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.57", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "kira" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a9f9dff5e262540b628b00d5e1a772270a962d6869f8695bb24832ff3b394" +dependencies = [ + "cpal", + "glam", + "mint", + "paste", + "ringbuf", + "send_wrapper", + "symphonia", + "triple_buffer", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.184" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" + +[[package]] +name = "libloading" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2caa5afb8bf9f3a2652760ce7d4f62d21c4d5a423e68466fca30df82f2330164" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[package]] +name = "libredox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall 0.4.1", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "mach2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +dependencies = [ + "libc", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "memmap2" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +dependencies = [ + "libc", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mint" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff" + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "nalgebra" +version = "0.33.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b" +dependencies = [ + "approx", + "glam", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "254a5372af8fc138e36684761d3c0cdb758a4410e938babcff1c860ce14ddbfc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ndk" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +dependencies = [ + "bitflags 2.6.0", + "jni-sys", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror 1.0.57", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[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]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "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]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_enum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" +dependencies = [ + "objc-sys", + "objc2-encode 3.0.0", +] + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode 4.1.0", +] + +[[package]] +name = "objc2-encode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "oboe" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" +dependencies = [ + "jni", + "ndk", + "ndk-context", + "num-derive", + "num-traits", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d" +dependencies = [ + "cc", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "orbclient" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166" +dependencies = [ + "libredox 0.0.2", +] + +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4586edfe4c648c71797a74c84bacb32b52b212eff5dfe2bb9f2c599844023e7" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "parry3d" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecb572cea5c76b06bc744aaefdbb9e6ea9e5695f50f79c0227bddecd6ec925a4" +dependencies = [ + "approx", + "arrayvec", + "bitflags 2.6.0", + "downcast-rs", + "either", + "ena", + "log", + "nalgebra", + "num-derive", + "num-traits", + "ordered-float", + "rstar", + "rustc-hash 2.1.1", + "simba", + "slab", + "smallvec", + "spade", + "thiserror 1.0.57", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.6.0", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix 1.1.4", + "windows-sys 0.61.2", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "pxfm" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" + +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rapier3d" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d84644f385b81f065576058bc8f7e3d64e56a66f2f5fc40bfd917774659e12" +dependencies = [ + "approx", + "arrayvec", + "bit-vec", + "bitflags 2.6.0", + "crossbeam", + "downcast-rs", + "log", + "nalgebra", + "num-derive", + "num-traits", + "ordered-float", + "parry3d", + "profiling", + "rustc-hash 2.1.1", + "simba", + "thiserror 1.0.57", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544" + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[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_users" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +dependencies = [ + "getrandom", + "libredox 0.1.3", + "thiserror 2.0.11", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "ringbuf" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79abed428d1fd2a128201cec72c5f6938e2da607c6f3745f769fabea399d950a" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "robust" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf4a6aa5f6d6888f39e980649f3ad6b666acdce1d78e95b8a2cb076e687ae30" + +[[package]] +name = "rstar" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "421400d13ccfd26dfa5858199c30a5d76f9c54e0dba7575273025b43c5175dbb" +dependencies = [ + "heapless", + "num-traits", + "smallvec", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustix" +version = "0.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys 0.4.13", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys 0.12.1", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "safe_arch" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "sctk-adwaita" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b2eaf3a5b264a521b988b2e73042e742df700c4f962cde845d1541adb46550" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit", + "tiny-skia", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[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.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simba" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simple-eyre" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b561532e8ffe7ecf09108c4f662896a9ec3eac4999eba84015ec3dcb8cc630a" +dependencies = [ + "eyre", + "indenter", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[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 = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "smithay-client-toolkit" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" +dependencies = [ + "bitflags 2.6.0", + "calloop", + "calloop-wayland-source", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix 0.38.31", + "thiserror 1.0.57", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smol_str" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6845563ada680337a52d43bb0b29f396f2d911616f6573012645b9e3d048a49" +dependencies = [ + "serde", +] + +[[package]] +name = "spade" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ece03ff43cd2a9b57ebf776ea5e78bd30b3b4185a619f041079f4109f385034" +dependencies = [ + "hashbrown 0.15.2", + "num-traits", + "robust", + "smallvec", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + +[[package]] +name = "strum" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "symphonia" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "815c942ae7ee74737bb00f965fa5b5a2ac2ce7b6c01c0cc169bbeaf7abd5f5a9" +dependencies = [ + "lazy_static", + "symphonia-bundle-mp3", + "symphonia-codec-pcm", + "symphonia-codec-vorbis", + "symphonia-core", + "symphonia-format-ogg", + "symphonia-format-riff", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-bundle-mp3" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c01c2aae70f0f1fb096b6f0ff112a930b1fb3626178fba3ae68b09dce71706d4" +dependencies = [ + "lazy_static", + "log", + "symphonia-core", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-codec-pcm" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f395a67057c2ebc5e84d7bb1be71cce1a7ba99f64e0f0f0e303a03f79116f89b" +dependencies = [ + "log", + "symphonia-core", +] + +[[package]] +name = "symphonia-codec-vorbis" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a98765fb46a0a6732b007f7e2870c2129b6f78d87db7987e6533c8f164a9f30" +dependencies = [ + "log", + "symphonia-core", + "symphonia-utils-xiph", +] + +[[package]] +name = "symphonia-core" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "798306779e3dc7d5231bd5691f5a813496dc79d3f56bf82e25789f2094e022c3" +dependencies = [ + "arrayvec", + "bitflags 1.3.2", + "bytemuck", + "lazy_static", + "log", +] + +[[package]] +name = "symphonia-format-ogg" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ada3505789516bcf00fc1157c67729eded428b455c27ca370e41f4d785bfa931" +dependencies = [ + "log", + "symphonia-core", + "symphonia-metadata", + "symphonia-utils-xiph", +] + +[[package]] +name = "symphonia-format-riff" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f7be232f962f937f4b7115cbe62c330929345434c834359425e043bfd15f50" +dependencies = [ + "extended", + "log", + "symphonia-core", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-metadata" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc622b9841a10089c5b18e99eb904f4341615d5aa55bbf4eedde1be721a4023c" +dependencies = [ + "encoding_rs", + "lazy_static", + "log", + "symphonia-core", +] + +[[package]] +name = "symphonia-utils-xiph" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "484472580fa49991afda5f6550ece662237b00c6f562c7d9638d1b086ed010fe" +dependencies = [ + "symphonia-core", + "symphonia-metadata", +] + +[[package]] +name = "syn" +version = "2.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "teleia" +version = "0.1.0" +dependencies = [ + "ahash", + "base64 0.22.1", + "bimap", + "bincode", + "bitflags 2.6.0", + "byteorder", + "bytes", + "console_error_panic_hook", + "console_log", + "directories", + "enum-map", + "env_logger", + "getrandom", + "glam", + "glfw", + "glow", + "gltf", + "image", + "js-sys", + "kira", + "log", + "nalgebra", + "parry3d", + "polling", + "rand", + "rapier3d", + "serde", + "serde_json", + "simple-eyre", + "strum", + "tobj", + "tracing-wasm", + "tungstenite", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winit", +] + +[[package]] +name = "teleia_macros" +version = "0.1.0" +dependencies = [ + "env", + "heck", + "litrs", + "walkdir", +] + +[[package]] +name = "tempfile" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix 0.38.31", + "windows-sys 0.59.0", +] + +[[package]] +name = "thiserror" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +dependencies = [ + "thiserror-impl 1.0.57", +] + +[[package]] +name = "thiserror" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl 2.0.11", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tobj" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7ca3ec0405b0f2f95e0dbcced28882190dc79b0dac63ff82533d256d770223" +dependencies = [ + "ahash", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + +[[package]] +name = "tracing-wasm" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" +dependencies = [ + "tracing", + "tracing-subscriber", + "wasm-bindgen", +] + +[[package]] +name = "triple_buffer" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e66931c8eca6381f0d34656a9341f09bd462010488c1a3bc0acd3f2d08dffce" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "ttf-parser" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" + +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "native-tls", + "rand", + "sha1", + "thiserror 1.0.57", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + +[[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]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wayland-backend" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40" +dependencies = [ + "cc", + "downcast-rs", + "rustix 0.38.31", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f" +dependencies = [ + "bitflags 2.6.0", + "rustix 0.38.31", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-csd-frame" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" +dependencies = [ + "bitflags 2.6.0", + "cursor-icon", + "wayland-backend", +] + +[[package]] +name = "wayland-cursor" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71ce5fa868dd13d11a0d04c5e2e65726d0897be8de247c0c5a65886e283231ba" +dependencies = [ + "rustix 0.38.31", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wide" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b5576b9a81633f3e8df296ce0063042a73507636cbe956c61133dd7034ab22" +dependencies = [ + "bytemuck", + "safe_arch", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" +dependencies = [ + "windows-core", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[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]] +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "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]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "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_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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[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_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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winit" +version = "0.29.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" +dependencies = [ + "ahash", + "android-activity", + "atomic-waker", + "bitflags 2.6.0", + "bytemuck", + "calloop", + "cfg_aliases", + "core-foundation", + "core-graphics", + "cursor-icon", + "icrate", + "js-sys", + "libc", + "log", + "memmap2", + "ndk", + "ndk-sys", + "objc2 0.4.1", + "once_cell", + "orbclient", + "percent-encoding", + "raw-window-handle", + "redox_syscall 0.3.5", + "rustix 0.38.31", + "sctk-adwaita", + "serde", + "smithay-client-toolkit", + "smol_str", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "web-sys", + "web-time", + "windows-sys 0.48.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading", + "once_cell", + "rustix 0.38.31", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34" + +[[package]] +name = "xcursor" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a0ccd7b4a5345edfcd0c3535718a4e9ff7798ffc536bb5b5a0e26ff84732911" + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.6.0", + "dlib", + "log", + "once_cell", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054a8e68b76250b253f671d1268cb7f1ae089ec35e195b2efb2a4e9a836d0621" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zune-core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" + +[[package]] +name = "zune-jpeg" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/Cargo.toml b/2026/games_submissions/rpc2dot0/vendor/teleia/Cargo.toml new file mode 100644 index 0000000..f5037ea --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/Cargo.toml @@ -0,0 +1,19 @@ +[workspace] +resolver = "2" +members = ["crates/*"] + +[workspace.package] +version = "0.1.0" +edition = "2024" +authors = ["LLLL Colonq "] + +[workspace.metadata.crane] +name = "teleia" + +[profile.dev.package."*"] +opt-level = 2 + +[workspace.lints.clippy] +all = "deny" +pedantic = "deny" +nursery = "deny" \ No newline at end of file diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/Cargo.toml b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/Cargo.toml new file mode 100644 index 0000000..90a0cca --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/Cargo.toml @@ -0,0 +1,53 @@ +[package] +name = "teleia" +version.workspace = true +edition.workspace = true +authors.workspace = true + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +strum = { version = "0.27.1", features = ["derive"] } # utility macros for enums +glow = { version = "=0.13.1", features = [] } # rendering +tobj = "=4.0.1" # loader for .obj meshes loader +ahash = "=0.8.10" # dependency of tobj +gltf = { git = "https://github.com/lcolonq/gltf", features = ["extras", "import", "names", "utils"] } # loader for .gltf scenes +image = { version = "0.25.10", default-features = false, features = ["jpeg", "png"] } # texture loader +# cosmic-text = { version = "*", default-features = false, features = ["std", "swash"] } # advanced text rendering +glam = "0.29.2" # linear algebra +log = "0.4.21" # logging +rand = { version = "=0.8.5", features = ["small_rng"] } # rng +serde = { version = "1.0.228", features = ["derive"] } # serialization +serde_json = "1.0.128" # serialize JSON +bincode = { version = "2.0.1", features = ["serde"] } # binary serialization +enum-map = "2.7.3" # fast maps with enums as keys +bimap = "0.6.3" # bijective maps +# reqwest = "*" # http requests +bytes = "*" # bytes for http responses +bitflags = { version = "2.6.0", features = ["serde"] } # bitwise flags +simple-eyre = { version = "0.3.1", default-features = false } # error reporting and formatting +rapier3d = "0.23.1" # rigid-body physics +parry3d = "0.18.0" # collision detection +nalgebra = {version = "0.33.2", features = ["convert-glam029"]} # linear algebra library for rapier3d +byteorder = "1.5.0" # read numbers in particular endianness +base64 = "0.22.1" # encode/decode base64 + +[target.'cfg(target_arch = "wasm32")'.dependencies] +winit = {version = "=0.29.15", features = ["serde"]} # windowing and events +getrandom = {version = "*", features = ["js"]} # rng in the browser +console_log = "*" # log to browser console +console_error_panic_hook = "*" # log to browser console on panic +tracing-wasm = "*" # trace performance in browser +wasm-bindgen = "=0.2.100" # interface with javascript +wasm-bindgen-futures = "*" # interface with async javascript +js-sys = "*" # browser APIs to interact with JS runtime (e.g. run WASM) +web-sys = { version = "*", features = ["Document", "Window", "Element", "HtmlCanvasElement", "WebGl2RenderingContext", "Headers", "Request", "RequestInit", "RequestMode", "Response", "Performance", "PerformanceTiming", "AudioContext", "AudioNode", "GainNode", "AudioParam", "AudioDestinationNode", "AudioBuffer", "AudioBufferSourceNode", "BinaryType", "Blob", "CloseEvent", "ErrorEvent", "FileReader", "MessageEvent", "ProgressEvent", "WebSocket", "Storage"] } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +env_logger = "0.11.5" # configurable logging to stdout +glfw = { git = "https://github.com/lcolonq/glfw-rs", features = ["serde"] } # window management +kira = { version = "=0.9.6", default-features = false, features = ["cpal", "ogg", "mp3", "wav"] } # audio +directories = { git = "https://github.com/lcolonq/directories-rs" } # standard system directories +polling = "3.11.0" # interface to epoll +tungstenite = { version = "0.24.0", features = ["native-tls"] } # websockets \ No newline at end of file diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/build.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/build.rs new file mode 100644 index 0000000..42743ce --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/build.rs @@ -0,0 +1,15 @@ +fn main() { + /*println!("cargo::rerun-if-changed=../../flake.lock"); + match &*std::env::var("CARGO_CFG_TARGET_ARCH").unwrap() { + "x86_64" => if let Ok(p) = std::env::var("LIBCOLONQ_PIT_NATIVE") { + println!("cargo::rustc-link-search={}", p); + }, + "wasm32" => if let Ok(p) = std::env::var("LIBCOLONQ_PIT_WASM") { + + println!("cargo::rustc-link-search={}", p); + }, + _ => eprintln!("warning: building for unknown architecture!"), + } + println!("cargo::rustc-link-lib=static=colonq-pit");*/ + eprint!("we are not using pit at all, this is a fork of teleia where scripting is disabled"); +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/fonts/default.png b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/fonts/default.png new file mode 100644 index 0000000..7b1d2a3 Binary files /dev/null and b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/fonts/default.png differ diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/fonts/small.png b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/fonts/small.png new file mode 100644 index 0000000..1d020f7 Binary files /dev/null and b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/fonts/small.png differ diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/meshes/square.obj b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/meshes/square.obj new file mode 100644 index 0000000..7acdef6 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/meshes/square.obj @@ -0,0 +1,15 @@ +# Blender 3.6.2 +# www.blender.org +o Cube +v -1.000000 -1.000000 0.000000 +v 1.000000 -1.000000 0.000000 +v -1.000000 1.000000 0.000000 +v 1.000000 1.000000 0.000000 +vn -0.0000 -0.0000 -1.0000 +vt 0.0 1.0 +vt 1.0 0.0 +vt 0.0 0.0 +vt 1.0 1.0 +s 0 +f 3/1/1 2/2/1 1/3/1 +f 3/1/1 4/4/1 2/2/1 diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/bitmap/frag.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/bitmap/frag.glsl new file mode 100644 index 0000000..fbc8d71 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/bitmap/frag.glsl @@ -0,0 +1,15 @@ +#version 300 es +precision highp float; + +uniform sampler2D texture_data; + +in vec2 vertex_texcoord; +in vec3 vertex_color; +out vec4 frag_color; + +void main() { + vec4 texel = texture(texture_data, vertex_texcoord); + if (texel.rgb == vec3(0.0, 0.0, 0.0)) discard; + texel.rgb = vertex_color; + frag_color = texel; +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/bitmap/vert.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/bitmap/vert.glsl new file mode 100644 index 0000000..eee22fc --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/bitmap/vert.glsl @@ -0,0 +1,20 @@ +#version 300 es +precision highp float; + +in vec3 vertex; +in vec2 texcoord; +in vec3 color; + +uniform mat4 view; +uniform mat4 position; +uniform mat4 projection; + +out vec2 vertex_texcoord; +out vec3 vertex_color; + +void main() { + vertex_texcoord = texcoord; + vertex_color = color; + vec3 pos = (position * vec4(vertex, 1.0)).xyz; + gl_Position = projection * view * vec4(pos, 1.0); +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/common/frag.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/common/frag.glsl new file mode 100644 index 0000000..fee9b80 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/common/frag.glsl @@ -0,0 +1,160 @@ +#version 300 es +precision highp float; + +uniform vec3 camera_pos; +uniform float time; + +uniform vec3 light_ambient_color; +uniform vec3 light_dir; +uniform vec3 light_dir_color; +uniform int light_count; +uniform vec3 light_pos[5]; +uniform vec3 light_color[5]; +uniform vec2 light_attenuation[5]; +uniform highp sampler2DShadow light_shadowbuffer_dir; +uniform samplerCube light_shadowbuffer_point[5]; + +uniform int has_point_shadows; + +in vec2 vertex_texcoord; +in vec3 vertex_normal; +in vec3 vertex_fragpos; +in vec4 vertex_fragpos_shadow_dir; +in vec3 vertex_view_vector; + +out vec4 frag_color; + +mat3 compute_tbn() { + vec3 p = -vertex_view_vector; + vec3 normal = normalize(vertex_normal); + vec3 dpx = dFdx(p); + vec3 dpy = dFdy(p); + vec2 duvx = dFdx(vertex_texcoord); + vec2 duvy = dFdy(vertex_texcoord); + vec3 dpyperp = cross(dpy, normal); + vec3 dpxperp = cross(normal, dpx); + vec3 tangent = dpyperp * duvx.x + dpxperp * duvy.x; + vec3 bitangent = dpyperp * duvx.y + dpxperp * duvy.y; + float invmax = inversesqrt(max(dot(bitangent, bitangent), dot(bitangent, bitangent))); + return mat3(-tangent * invmax, -bitangent * invmax, normal); +} + +vec4 normal_as_color(vec3 n) { + float r = (128.0 + 127.0 * n.r) / 255.0; + float g = (128.0 + 127.0 * n.g) / 255.0; + float b = (128.0 + 127.0 * n.b) / 255.0; + return vec4(r, g, b, 1.0); +} + +vec3 dir_light(vec3 normal) { + return max(dot(normal, -normalize(light_dir)), 0.0) * light_dir_color; +} + +float dir_shadow(vec3 normal) { + vec3 proj = vertex_fragpos_shadow_dir.xyz / vertex_fragpos_shadow_dir.w; + float bias = 0.002; + // float current_depth = proj.z; + // float bias = max(0.05 * (1.0 - dot(normal, -normalize(light_dir))), 0.005); + proj.z -= bias; + proj *= 0.5; proj += 0.5; + if (proj.z > 1.0) return 0.0; + return 1.0 - texture(light_shadowbuffer_dir, proj.xyz); +} + +float point_shadow(vec3 normal, vec3 shadow_vector, float closest_depth) { + closest_depth *= 25.0; + float current_depth = length(shadow_vector); + float bias = max(0.1 * (1.0 - dot(normal, normalize(shadow_vector))), 0.005); + bias = min(bias + current_depth * 0.01, 0.2); + float shadow = current_depth - bias > closest_depth ? 1.0 : 0.0; + return shadow; +} + +vec3 point_light(vec3 normal, const int idx) { + vec3 pos = light_pos[idx]; + vec3 color = light_color[idx]; + float linear = light_attenuation[idx].x; + float quadratic = light_attenuation[idx].y; + vec3 light_vector = pos - vertex_fragpos; + float distance = length(light_vector); + float attenuation = 1.0 / (1.0 + distance * linear + distance * distance * quadratic); + + float directional = max(dot(normal.xyz, normalize(light_vector)), 0.0); + vec3 directional_light = color * directional; + + vec3 view_dir = normalize(camera_pos - vertex_fragpos); + vec3 reflect_dir = reflect(-normalize(light_vector), normalize(normal.xyz)); + float specular = pow(max(dot(view_dir, reflect_dir), 0.0), 32.0); + vec3 specular_light = 0.5 * specular * color; + // return (directional_light + specular_light) * attenuation; + return directional_light * attenuation; +} + +vec3 point_light_billboard(const int idx) { + vec3 pos = light_pos[idx]; + vec3 color = light_color[idx]; + float linear = light_attenuation[idx].x; + float quadratic = light_attenuation[idx].y; + vec3 light_vector = pos - vertex_fragpos; + float distance = length(light_vector); + float attenuation = 1.0 / (1.0 + distance * linear + distance * distance * quadratic); + + return color * attenuation; +} + +vec3 compute_lighting(vec3 normal) { + vec3 ambient_light = light_ambient_color; + + vec3 from_dir = dir_light(normal) * (1.0 - dir_shadow(normal)); + + vec3 shadow_vector[5]; + for (int i = 0; i < light_count; ++i) { + shadow_vector[i] = vertex_fragpos - light_pos[i]; + shadow_vector[i].x *= -1.0; + } + + // can only index array of samplers with a constant, hence the weird setup + #define SAMPLE_SHADOW(n) n < light_count ? texture(light_shadowbuffer_point[n], shadow_vector[n]).r : 1.0 + float shadow_depth[5]; + shadow_depth[0] = SAMPLE_SHADOW(0); + shadow_depth[1] = SAMPLE_SHADOW(1); + shadow_depth[2] = SAMPLE_SHADOW(2); + shadow_depth[3] = SAMPLE_SHADOW(3); + shadow_depth[4] = SAMPLE_SHADOW(4); + + vec3 from_points = vec3(0.0, 0.0, 0.0); + for (int i = 0; i < light_count; ++i) { + from_points += has_point_shadows != 0 + ? point_light(normal, i) * (1.0 - point_shadow(normal, shadow_vector[i], shadow_depth[i])) + : point_light(normal, i); + } + + return (ambient_light + from_dir + from_points); +} + +vec3 compute_lighting_noshadow(vec3 normal) { + vec3 ambient_light = light_ambient_color; + + vec3 from_dir = dir_light(normal); + + vec3 from_points = vec3(0.0, 0.0, 0.0); + for (int i = 0; i < light_count; ++i) { + from_points += point_light(normal, i); + } + + return (ambient_light + from_dir + from_points); +} + +vec3 compute_lighting_billboard(vec3 normal) { + vec3 ambient_light = light_ambient_color; + + vec3 from_dir = light_dir_color / 2.0; + + vec3 from_points = vec3(0.0, 0.0, 0.0); + for (int i = 0; i < light_count; ++i) { + from_points += point_light_billboard(i); + } + + return (ambient_light + from_dir + from_points); +} +#line 0 diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/common/vert.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/common/vert.glsl new file mode 100644 index 0000000..06f7e30 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/common/vert.glsl @@ -0,0 +1,30 @@ +#version 300 es +precision highp float; + +in vec3 vertex; +in vec3 normal; +in vec2 texcoord; + +uniform mat4 view; +uniform mat4 position; +uniform mat4 projection; +uniform mat4 normal_matrix; +uniform mat4 lightspace_matrix; +uniform vec3 camera_pos; + +out vec2 vertex_texcoord; +out vec3 vertex_normal; +out vec3 vertex_fragpos; +out vec4 vertex_fragpos_shadow_dir; +out vec3 vertex_view_vector; + +void default_main() +{ + vertex_texcoord = texcoord; + vertex_normal = (normal_matrix * vec4(normal, 1.0)).xyz; + vec3 pos = (position * vec4(vertex, 1.0)).xyz; + vertex_fragpos = pos; + vertex_fragpos_shadow_dir = lightspace_matrix * vec4(pos, 1.0); + vertex_view_vector = camera_pos - pos; + gl_Position = projection * view * vec4(pos, 1.0); +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/flat/frag.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/flat/frag.glsl new file mode 100644 index 0000000..fa305e6 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/flat/frag.glsl @@ -0,0 +1,12 @@ +uniform sampler2D texture_data; + +uniform float transparency; + +void main() +{ + float opacity = 1.0 - clamp(transparency, 0.0, 1.0); + vec2 tcfull = vec2(vertex_texcoord.x, 1.0 - vertex_texcoord.y); + vec4 texel = texture(texture_data, tcfull); + texel.a *= opacity; + frag_color = texel; +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/flat/vert.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/flat/vert.glsl new file mode 100644 index 0000000..6e796cc --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/flat/vert.glsl @@ -0,0 +1,4 @@ +void main() +{ + default_main(); +} \ No newline at end of file diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scale/frag.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scale/frag.glsl new file mode 100644 index 0000000..257c1b7 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scale/frag.glsl @@ -0,0 +1,12 @@ +#version 300 es +precision highp float; + +uniform sampler2D texture_data; + +in vec2 vertex_texcoord; +out vec4 frag_color; + +void main() { + vec4 texel = texture(texture_data, vertex_texcoord); + frag_color = texel; +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scale/vert.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scale/vert.glsl new file mode 100644 index 0000000..d48f78d --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scale/vert.glsl @@ -0,0 +1,22 @@ +#version 300 es +precision highp float; + +out vec2 vertex_texcoord; + +void main() { + const vec2 positions[4] = vec2[]( + vec2(-1, -1), + vec2(+1, -1), + vec2(-1, +1), + vec2(+1, +1) + ); + const vec2 coords[4] = vec2[]( + vec2(0, 0), + vec2(1, 0), + vec2(0, 1), + vec2(1, 1) + ); + + vertex_texcoord = coords[gl_VertexID]; + gl_Position = vec4(positions[gl_VertexID], 0.0, 1.0); +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scene/frag.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scene/frag.glsl new file mode 100644 index 0000000..554c25d --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scene/frag.glsl @@ -0,0 +1,11 @@ +uniform sampler2D texture_data; + +void main() +{ + vec4 texel = texture(texture_data, vertex_texcoord); + if (texel.a != 1.0) { + discard; + } + + frag_color = vec4(texel.rgb, texel.a); +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scene/vert.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scene/vert.glsl new file mode 100644 index 0000000..c66a816 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/scene/vert.glsl @@ -0,0 +1,18 @@ +in vec4 joint; +in vec4 weight; + +uniform mat4 joint_matrices[128]; + +void main() +{ + vertex_texcoord = texcoord; + vertex_normal = (normal_matrix * vec4(normal, 1.0)).xyz; + mat4 skin + = weight.x * joint_matrices[int(joint.x)] + + weight.y * joint_matrices[int(joint.y)] + + weight.z * joint_matrices[int(joint.z)] + + weight.w * joint_matrices[int(joint.w)]; + vec3 pos = (position * skin * vec4(vertex, 1.0)).xyz; + vertex_view_vector = camera_pos - pos; + gl_Position = projection * view * vec4(pos, 1.0); +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/test/frag.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/test/frag.glsl new file mode 100644 index 0000000..954a9d2 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/test/frag.glsl @@ -0,0 +1,23 @@ +// uniform int has_normal_map; +// uniform sampler2D normal_map; + +uniform sampler2D texture_data; + +void main() +{ + vec2 inverted_texcoord = vec2(vertex_texcoord.x, 1.0 - vertex_texcoord.y); + vec4 texel = texture(texture_data, inverted_texcoord); + if (texel.a != 1.0) { + discard; + } + + // mat3 tbn = compute_tbn(); + // vec3 normal = has_normal_map != 0 + // ? normalize(tbn * (texture(normal_map, inverted_texcoord).xyz * 2.0 - 1.0)) + // : normalize(vertex_normal); + vec3 normal = normalize(vertex_normal); + + vec3 lighting = compute_lighting_noshadow(normal); + + frag_color = vec4(texel.rgb * lighting, texel.a); +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/test/vert.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/test/vert.glsl new file mode 100644 index 0000000..6e796cc --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/test/vert.glsl @@ -0,0 +1,4 @@ +void main() +{ + default_main(); +} \ No newline at end of file diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/tiled/frag.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/tiled/frag.glsl new file mode 100644 index 0000000..257c1b7 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/tiled/frag.glsl @@ -0,0 +1,12 @@ +#version 300 es +precision highp float; + +uniform sampler2D texture_data; + +in vec2 vertex_texcoord; +out vec4 frag_color; + +void main() { + vec4 texel = texture(texture_data, vertex_texcoord); + frag_color = texel; +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/tiled/vert.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/tiled/vert.glsl new file mode 100644 index 0000000..a7567f4 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/tiled/vert.glsl @@ -0,0 +1,14 @@ +#version 300 es +precision highp float; + +in vec2 vertex; +in vec2 texcoord; + +uniform mat4 transform; + +out vec2 vertex_texcoord; + +void main() { + vertex_texcoord = texcoord; + gl_Position = transform * vec4(vertex, 0.0, 1.0); +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/truetype/frag.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/truetype/frag.glsl new file mode 100644 index 0000000..d472c09 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/truetype/frag.glsl @@ -0,0 +1,16 @@ +#version 300 es +precision highp float; + +uniform sampler2D texture_data; + +in vec2 vertex_texcoord; +in vec3 vertex_color; +out vec4 frag_color; + +void main() +{ + float val = texture(texture_data, vertex_texcoord).r; + if (val == 0.0) discard; + vec4 texel = vec4(vertex_color, val); + frag_color = texel; +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/truetype/vert.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/truetype/vert.glsl new file mode 100644 index 0000000..a501e0a --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/truetype/vert.glsl @@ -0,0 +1,17 @@ +#version 300 es +precision highp float; + +in vec2 vertex; +in vec2 texcoord; +in vec3 color; + +uniform mat4 transform; + +out vec2 vertex_texcoord; +out vec3 vertex_color; + +void main() { + vertex_texcoord = texcoord; + vertex_color = color; + gl_Position = transform * vec4(vertex, 0.0, 1.0); +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/uber/frag.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/uber/frag.glsl new file mode 100644 index 0000000..8e7b752 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/uber/frag.glsl @@ -0,0 +1,193 @@ +uniform highp int flags; + +uniform vec3 camera_pos; +uniform float time; + +uniform vec2 sprite_offset; +uniform vec2 sprite_dims; + +uniform vec4 color; +uniform sampler2D texture_color; +uniform sampler2D texture_normal; +uniform vec3 light_ambient_color; +uniform vec3 light_dir; +uniform vec3 light_dir_color; +uniform int light_count; +uniform vec3 light_pos[5]; +uniform vec3 light_color[5]; +uniform vec2 light_attenuation[5]; + +uniform int effect_flip; +uniform float effect_flash; +uniform float effect_hueshift; +uniform float effect_huescale; + +in vec2 vertex_texcoord; +in vec3 vertex_color; +in vec3 vertex_normal; +in vec3 vertex_fragpos; +in vec4 vertex_fragpos_shadow_dir; +in vec3 vertex_view_vector; + +out vec4 frag_color; + +bool flag(int mask) { + return (flags & mask) != 0; +} + +mat3 compute_tbn() { + vec3 p = -vertex_view_vector; + vec3 normal = normalize(vertex_normal); + vec3 dpx = dFdx(p); + vec3 dpy = dFdy(p); + vec2 duvx = dFdx(vertex_texcoord); + vec2 duvy = dFdy(vertex_texcoord); + vec3 dpyperp = cross(dpy, normal); + vec3 dpxperp = cross(normal, dpx); + vec3 tangent = dpyperp * duvx.x + dpxperp * duvy.x; + vec3 bitangent = dpyperp * duvx.y + dpxperp * duvy.y; + float invmax = inversesqrt(max(dot(bitangent, bitangent), dot(bitangent, bitangent))); + float flip = flag(FLIP_TEXTURE) ? 1.0 : -1.0; + return mat3(-tangent * invmax, flip * bitangent * invmax, normal); + +} + +vec4 normal_as_color(vec3 n) { + float r = (128.0 + 127.0 * n.r) / 255.0; + float g = (128.0 + 127.0 * n.g) / 255.0; + float b = (128.0 + 127.0 * n.b) / 255.0; + return vec4(r, g, b, 1.0); +} + +vec3 dir_light(vec3 normal) { + return max(dot(normal, -normalize(light_dir)), 0.0) * light_dir_color; +} + +vec3 point_light(vec3 normal, const int idx) { + vec3 pos = light_pos[idx]; + vec3 color = light_color[idx]; + float linear = light_attenuation[idx].x; + float quadratic = light_attenuation[idx].y; + vec3 light_vector = pos - vertex_fragpos; + float distance = length(light_vector); + float attenuation = 1.0 / (1.0 + distance * linear + distance * distance * quadratic); + + float directional = max(dot(normal.xyz, normalize(light_vector)), 0.0); + vec3 directional_light = color * directional; + + vec3 view_dir = normalize(camera_pos - vertex_fragpos); + vec3 reflect_dir = reflect(-normalize(light_vector), normalize(normal.xyz)); + float specular = pow(max(dot(view_dir, reflect_dir), 0.0), 32.0); + vec3 specular_light = 0.5 * specular * color; + // return (directional_light + specular_light) * attenuation; + return directional_light * attenuation; +} + +vec3 point_light_billboard(const int idx) { + vec3 pos = light_pos[idx]; + vec3 color = light_color[idx]; + float linear = light_attenuation[idx].x; + float quadratic = light_attenuation[idx].y; + vec3 light_vector = pos - vertex_fragpos; + float distance = length(light_vector); + float attenuation = 1.0 / (1.0 + distance * linear + distance * distance * quadratic); + + return color * attenuation; +} + +vec3 rgb_to_hsl(vec3 rgb) { + vec3 ret; + float min = min(min(rgb.r, rgb.g), rgb.b); + float max = max(max(rgb.r, rgb.g), rgb.b); + float lum = (max + min) / 2.0; + ret.z = lum; + if (max == min) { + ret.x = ret.y = 0.0; + } else { + float chroma = max - min; + ret.y = chroma / (1.0 - abs(2.0 * lum - 1.0)); + if (max == rgb.r) { + ret.x = (rgb.g - rgb.b) / chroma + (rgb.g < rgb.b ? 6.0 : 0.0); + } else if (max == rgb.g) { + ret.x = (rgb.b - rgb.r) / chroma + 2.0; + } else { + ret.x = (rgb.r - rgb.g) / chroma + 4.0; + } + ret.x /= 6.0; + } + return ret; +} + +float hue_to_rgb(float p, float q, float t) { + 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; + return p; +} + +vec3 hsl_to_rgb(vec3 hsl) { + vec3 ret; + if (hsl.y == 0.0) { + ret.r = ret.g = ret.b = hsl.z; + } else { + float q = hsl.z < 0.5 ? hsl.z * (1.0 + hsl.y) : hsl.z + hsl.y - hsl.z * hsl.y; + float p = 2.0 * hsl.z - q; + ret.r = hue_to_rgb(p, q, hsl.x + 1.0/3.0); + ret.g = hue_to_rgb(p, q, hsl.x); + ret.b = hue_to_rgb(p, q, hsl.x - 1.0/3.0); + } + return ret; +} + +void main() { + float tcy = flag(FLIP_TEXTURE) ? vertex_texcoord.y : 1.0 - vertex_texcoord.y; + vec2 tc = vec2(vertex_texcoord.x, tcy); + mat3 tbn = compute_tbn(); + if (flag(EFFECTS)) { + float fbase = float(effect_flip); + float fmul = 1.0 - 2.0 * fbase; + tc = vec2(fbase + fmul * vertex_texcoord.x, tcy); + } + if (flag(SPRITE)) { + tc *= sprite_dims; + tc += sprite_offset; + } + frag_color = color; + if (flag(TEXTURE_COLOR)) { + frag_color = texture(texture_color, tc); + } + if (flag(EFFECTS)) { + vec3 hsl = rgb_to_hsl(frag_color.rgb); + hsl.x = mod(hsl.x * effect_huescale + effect_hueshift, 1.0); + vec3 p = hsl_to_rgb(hsl); + frag_color.rgb = vec3(p.r + effect_flash, p.g + effect_flash, p.b + effect_flash); + } + vec3 normal = vertex_normal; + if (flag(TEXTURE_NORMAL)) { + normal = normalize(tbn * (texture(texture_normal, tc).xyz * 2.0 - 1.0)); + } + vec3 from_ambient = vec3(1.0, 1.0, 1.0); + if (flag(LIGHT_AMBIENT)) { + from_ambient = light_ambient_color; + } + vec3 from_dir = vec3(0.0, 0.0, 0.0); + if (flag(LIGHT_DIR)) { + from_dir = dir_light(normal); + } + vec3 from_points = vec3(0.0, 0.0, 0.0); + if (flag(LIGHT_POINT)) { + for (int i = 0; i < light_count; ++i) { + vec3 pl = point_light(normal, i); + from_points += pl; + } + } + frag_color.rgb *= (from_ambient + from_dir + from_points); + if (frag_color.a == 0.0) { + discard; + } + if (flag(VERTEX_COLOR)) { + frag_color.rgb = vertex_color; + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/uber/vert.glsl b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/uber/vert.glsl new file mode 100644 index 0000000..bd5ac60 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/assets/shaders/uber/vert.glsl @@ -0,0 +1,41 @@ +uniform highp int flags; + +in vec3 vertex; +in vec3 normal; +in vec2 texcoord; +in vec3 color; + +uniform mat4 view; +uniform mat4 position; +uniform mat4 projection; +uniform mat4 normal_matrix; +uniform mat4 lightspace_matrix; +uniform vec3 camera_pos; +uniform vec3 offset; +uniform float yskew; + +out vec2 vertex_texcoord; +out vec3 vertex_color; +out vec3 vertex_normal; +out vec3 vertex_fragpos; +out vec4 vertex_fragpos_shadow_dir; +out vec3 vertex_view_vector; + +bool flag(int mask) { + return (flags & mask) != 0; +} + +void main() { + vertex_texcoord = texcoord; + vertex_color = color; + vertex_normal = (normal_matrix * vec4(normal, 1.0)).xyz; + vec3 pos = (position * vec4(vertex, 1.0)).xyz; + vertex_fragpos = pos; + vertex_fragpos_shadow_dir = lightspace_matrix * vec4(pos, 1.0); + vertex_view_vector = camera_pos - pos; + gl_Position = projection * view * vec4(pos, 1.0); + gl_Position.xyz += offset; + if (flag(YSKEW)) { + gl_Position.y += yskew * pos.z; + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/audio.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/audio.rs new file mode 100644 index 0000000..431b010 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/audio.rs @@ -0,0 +1,341 @@ +use std::collections::HashMap; + +use std::sync::{Arc, Mutex}; + +#[cfg(target_arch = "wasm32")] +pub struct Context { + pub audio: web_sys::AudioContext, +} + +#[cfg(target_arch = "wasm32")] +impl Context { + pub fn new() -> Self { + let audio = web_sys::AudioContext::new().expect("failed to create audio context"); + Self { audio } + } +} + +#[cfg(target_arch = "wasm32")] +pub struct AudioPlayingHandle { + node: web_sys::AudioBufferSourceNode, + gain: web_sys::GainNode, +} + +#[cfg(target_arch = "wasm32")] +impl AudioPlayingHandle { + pub fn stop(&self, _ctx: &Context) { + self.node.stop().expect("failed to stop audio"); + } + pub fn fade_out(&self, ctx: &Context, time: f32) { + self.gain + .gain() + .set_target_at_time(0.0, ctx.audio.current_time(), time as f64) + .expect("failed to fade out audio"); + self.node + .stop_with_when(ctx.audio.current_time() + time as f64 + 1.0) + .expect("failed to stop audio while fading out"); + } +} + +#[cfg(target_arch = "wasm32")] +pub struct Audio { + pub buffer: Arc>>, +} + +#[cfg(target_arch = "wasm32")] +impl Audio { + pub fn new(ctx: &Context, bytes: &[u8]) -> Self { + let sbuffer = Arc::new(Mutex::new(None)); + let sclone = sbuffer.clone(); + let ret = Audio { buffer: sclone }; + let jsp = ctx + .audio + .decode_audio_data(&js_sys::Uint8Array::from(bytes).buffer()) + .expect("failed to decode audio"); + let promise = wasm_bindgen_futures::JsFuture::from(jsp); + wasm_bindgen_futures::spawn_local(async move { + if let Some(data) = promise.await.ok() { + *sbuffer.lock().unwrap() = Some(web_sys::AudioBuffer::from(data)); + } + () + }); + ret + } + + pub fn from_samples(ctx: &Context, sample_rate: f32, samples: &[f32]) -> Self { + let buf = ctx + .audio + .create_buffer(1, samples.len() as u32, sample_rate) + .expect("failed to create audio buffer"); + buf.copy_to_channel(samples, 0) + .expect("failed to populate audio samples"); + Audio { + buffer: Arc::new(Mutex::new(Some(buf))), + } + } + + pub fn play( + &self, + ctx: &mut Context, + looping: Option<(Option, Option)>, + ) -> Option { + let source = ctx.audio.create_buffer_source().ok()?; + if let Some(ab) = &*self.buffer.lock().unwrap() { + source.set_buffer(Some(&ab)); + } else { + return None; + }; + if let Some((ms, me)) = looping { + source.set_loop(true); + if let Some(s) = ms { + source.set_loop_start(s) + } + if let Some(e) = me { + source.set_loop_end(e) + } + } + let gain = ctx.audio.create_gain().ok()?; + gain.gain() + .set_value_at_time(0.5, ctx.audio.current_time()) + .ok()?; + gain.connect_with_audio_node(&ctx.audio.destination()) + .ok()?; + source.connect_with_audio_node(&gain).ok()?; + source.start().ok()?; + Some(AudioPlayingHandle { node: source, gain }) + } +} + +#[cfg(target_arch = "wasm32")] +pub struct Assets { + pub ctx: Context, + pub audio: HashMap, + pub music_node: Option, +} + +#[cfg(target_arch = "wasm32")] +impl Assets { + pub fn new(f: F) -> Self + where + F: Fn(&Context) -> HashMap, + { + let ctx = Context::new(); + + let audio = f(&ctx); + + Self { + ctx, + audio, + music_node: None, + } + } + + pub fn play_sfx(&mut self, name: &str) { + if let Some(a) = self.audio.get(name) { + a.play(&mut self.ctx, None); + } + } + + pub fn is_music_playing(&self) -> bool { + if let Some(ms) = &self.music_node { + ms.node.buffer().is_some() + } else { + false + } + } + + pub fn play_music(&mut self, name: &str, start: Option, end: Option) { + if let Some(s) = &self.music_node { + let _ = s.stop(&self.ctx); + } + if let Some(a) = self.audio.get(name) { + self.music_node = a.play(&mut self.ctx, Some((start, end))); + } + } + + pub fn stop_music(&mut self) { + if let Some(node) = &self.music_node { + let _ = node.stop(&self.ctx); + } + self.music_node = None; + } +} + +#[cfg(not(target_arch = "wasm32"))] +pub struct Context { + manager: kira::manager::AudioManager, +} + +#[cfg(not(target_arch = "wasm32"))] +impl Context { + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + Self { + manager: kira::manager::AudioManager::new( + kira::manager::AudioManagerSettings::default(), + ) + .expect("failed to create audio manager"), + } + } +} + +#[cfg(not(target_arch = "wasm32"))] +pub struct AudioPlayingHandle { + handle: Arc>, +} + +#[cfg(not(target_arch = "wasm32"))] +impl AudioPlayingHandle { + pub fn stop(&self, _ctx: &Context) { + self.handle + .lock() + .unwrap() + .stop(kira::tween::Tween::default()); + } + pub fn fade_out(&self, _ctx: &Context, time: f32) { + self.handle.lock().unwrap().stop(kira::tween::Tween { + duration: std::time::Duration::from_secs_f32(time + 0.5), + ..Default::default() + }); + } +} + +#[cfg(not(target_arch = "wasm32"))] +pub struct Audio { + data: kira::sound::static_sound::StaticSoundData, +} + +#[cfg(not(target_arch = "wasm32"))] +impl Audio { + pub fn new(_ctx: &Context, bytes: &[u8]) -> Self { + Self { + data: kira::sound::static_sound::StaticSoundData::from_cursor(std::io::Cursor::new( + bytes.to_owned(), + )) + .expect("failed to decode audio"), + } + } + + pub fn from_samples(_ctx: &Context, sample_rate: f32, samples: &[f32]) -> Self { + let frames: Vec = samples + .iter() + .map(|f| kira::Frame { + left: *f, + right: *f, + }) + .collect(); + Self { + data: kira::sound::static_sound::StaticSoundData { + sample_rate: sample_rate as u32, + frames: frames.into(), + settings: kira::sound::static_sound::StaticSoundSettings::default(), + slice: None, + }, + } + } + + pub fn play( + &self, + ctx: &mut Context, + looping: Option<(Option, Option)>, + ) -> Option { + let sd = if let Some((ss, se)) = looping { + let start = ss.unwrap_or(0.0); + if let Some(e) = se { + self.data.loop_region(start..e) + } else { + self.data.loop_region(start..) + } + } else { + self.data.clone() + }; + ctx.manager.play(sd).ok().map(|h| AudioPlayingHandle { + handle: Arc::new(Mutex::new(h)), + }) + } +} + +#[cfg(not(target_arch = "wasm32"))] +pub struct Assets { + pub ctx: Context, + pub audio: HashMap, + pub music_handle: Option, +} + +#[cfg(not(target_arch = "wasm32"))] +impl Assets { + pub fn new(f: F) -> Self + where + F: Fn(&Context) -> HashMap, + { + let ctx = Context::new(); + let audio = f(&ctx); + Self { + ctx, + audio, + music_handle: None, + } + } + + pub fn play_sfx(&mut self, name: &str) { + if let Some(a) = self.audio.get(name) { + if a.play(&mut self.ctx, None).is_none() { + log::warn!("failed to play sound {}", name); + } + } + } + + pub fn is_music_playing(&self) -> bool { + if let Some(mh) = &self.music_handle { + mh.handle.lock().unwrap().state() == kira::sound::PlaybackState::Playing + } else { + false + } + } + + pub fn play_music(&mut self, name: &str, start: Option, end: Option) { + if let Some(s) = &mut self.music_handle { + s.stop(&self.ctx); + } + if let Some(a) = self.audio.get(name) { + match a.play(&mut self.ctx, Some((start, end))) { + Some(h) => { + self.music_handle = Some(h); + } + _ => { + log::warn!("failed to play music {}", name); + } + } + } + } + + pub fn stop_music(&mut self) { + if let Some(h) = &mut self.music_handle { + h.stop(&self.ctx); + } + self.music_handle = None; + } +} + +pub trait AudioPlayback { + fn play_sfx(&mut self, name: &str); + fn play_music(&mut self, name: &str, start: Option, end: Option); + fn stop_music(&mut self); +} +impl AudioPlayback for Option { + fn play_sfx(&mut self, name: &str) { + if let Some(a) = self { + a.play_sfx(name); + } + } + fn play_music(&mut self, name: &str, start: Option, end: Option) { + if let Some(a) = self { + a.play_music(name, start, end); + } + } + fn stop_music(&mut self) { + if let Some(a) = self { + a.stop_music(); + } + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/context.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/context.rs new file mode 100644 index 0000000..34e0ad3 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/context.rs @@ -0,0 +1,302 @@ +use crate::Options; + +use glow::HasContext; + +#[cfg(not(target_arch = "wasm32"))] +use glfw::Context as _; + +#[cfg(target_arch = "wasm32")] +use wasm_bindgen::prelude::*; + +#[cfg(target_arch = "wasm32")] +use winit::platform::web::WindowExtWebSys; + +#[cfg(target_arch = "wasm32")] +#[wasm_bindgen(module = "/src/helpers.js")] +extern { + fn js_track_resized_setup(); + fn js_poll_resized() -> bool; + fn js_bundt_api_server() -> String; + fn js_bundt_secure_api_server() -> String; +} + +#[cfg(not(target_arch = "wasm32"))] +pub struct Context { + pub render_width: f32, + pub render_height: f32, + pub options: Options, + pub glfw: std::cell::RefCell, + pub window: std::cell::RefCell, + pub gl: glow::Context, + pub emptyvao: glow::VertexArray, + pub start_instant: std::time::Instant, +} + + +#[cfg(target_arch = "wasm32")] +pub struct Context { + pub render_width: f32, + pub render_height: f32, + pub options: Options, + pub window: winit::window::Window, + pub gl: glow::Context, + pub emptyvao: glow::VertexArray, + pub performance: web_sys::Performance, +} + +impl Context { + pub fn compute_upscale(&self, windoww: u32, windowh: u32) -> u32 { + let mut ratio = 1; + loop { + if (self.render_width as u32) * ratio > windoww + || (self.render_height as u32) * ratio > windowh + { + break; + } + ratio += 1; + } + (ratio - 1).max(1) + } + + #[cfg(not(target_arch = "wasm32"))] + pub fn new(glfw: std::cell::RefCell, window: std::cell::RefCell, gl: glow::Context, render_width: f32, render_height: f32, options: Options) -> Self { + let emptyvao = unsafe { + gl.create_vertex_array().expect("failed to initialize vao") + }; + let ret = Self { + render_width, render_height, + options, + glfw, window, + gl, + emptyvao, + start_instant: std::time::Instant::now(), + }; + ret.init(); + ret + } + + #[cfg(target_arch = "wasm32")] + pub fn new(window: winit::window::Window, gl: glow::Context, render_width: f32, render_height: f32, options: Options) -> Self { + let emptyvao = unsafe { + gl.create_vertex_array().expect("failed to initialize vao") + }; + + #[cfg(target_arch = "wasm32")] + js_track_resized_setup(); + + let ret = Self { + render_width, render_height, + options, + window, + gl, + emptyvao, + + #[cfg(target_arch = "wasm32")] + performance: web_sys::window().expect("failed to find window") + .performance().expect("failed to get performance"), + }; + ret.init(); + ret + } + + pub fn init(&self) { + unsafe { + self.gl.clear_color(0.1, 0.1, 0.1, 1.0); + self.gl.clear_depth_f32(1.0); + + #[cfg(all(debug_assertions, not(target_arch = "wasm32")))] + self.gl.enable(glow::DEBUG_OUTPUT); + + self.gl.enable(glow::DEPTH_TEST); + self.gl.depth_func(glow::LEQUAL); + + self.gl.enable(glow::BLEND); + self.gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA); + + self.gl.enable(glow::STENCIL_TEST); + + self.gl.cull_face(glow::FRONT); + } + } + + #[cfg(target_arch = "wasm32")] + pub fn maximize_canvas(&self) { + if !self.options.contains(Options::NORESIZE) { + web_sys::window() + .and_then(|win| win.document()) + .and_then(|doc| { + let inner_size = { + let browser_window = doc.default_view() + .or_else(web_sys::window) + .unwrap(); + winit::dpi::PhysicalSize::new( + browser_window.inner_width().unwrap().as_f64().unwrap(), + browser_window.inner_height().unwrap().as_f64().unwrap(), + ) + }; + self.window.canvas().unwrap().set_width(inner_size.width as _); + self.window.canvas().unwrap().set_height(inner_size.height as _); + let _ = self.window.request_inner_size(inner_size); + Some(()) + }) + .expect("failed to resize canvas"); + } + } + + #[cfg(target_arch = "wasm32")] + pub fn resize_necessary(&self) -> bool { js_poll_resized() } + #[cfg(not(target_arch = "wasm32"))] + pub fn resize_necessary(&self) -> bool { false } + + #[cfg(target_arch = "wasm32")] + pub fn bundt_api_server(&self) -> String { js_bundt_api_server() } + #[cfg(all(not(target_arch = "wasm32"), debug_assertions))] + pub fn bundt_api_server(&self) -> String { "http://localhost:8000/api".to_owned() } + #[cfg(all(not(target_arch = "wasm32"), not(debug_assertions)))] + pub fn bundt_api_server(&self) -> String { "https://api.colonq.computer/api".to_owned() } + + #[cfg(target_arch = "wasm32")] + pub fn bundt_secure_api_server(&self) -> String { js_bundt_secure_api_server() } + #[cfg(all(not(target_arch = "wasm32"), debug_assertions))] + pub fn bundt_secure_api_server(&self) -> String { "http://localhost:8000/api".to_owned() } + #[cfg(all(not(target_arch = "wasm32"), not(debug_assertions)))] + pub fn bundt_secure_api_server(&self) -> String { "https://secure.colonq.computer/api".to_owned() } + + pub fn clear_color(&self, color: glam::Vec4) { + unsafe { + self.gl.clear_color(color.x, color.y, color.z, color.w); + } + } + + pub fn clear_depth(&self) { + unsafe { + self.gl.clear(glow::DEPTH_BUFFER_BIT); + } + } + + pub fn clear(&self) { + unsafe { + self.gl.stencil_mask(0xff); + self.gl.clear(glow::COLOR_BUFFER_BIT | glow::DEPTH_BUFFER_BIT | glow::STENCIL_BUFFER_BIT); + } + } + + pub fn depth_mask(&self, m: bool) { + unsafe { + self.gl.depth_mask(m); + } + } + + pub fn begin_stencil(&self) { + unsafe { + self.gl.stencil_func(glow::ALWAYS, 1, 0xff); + self.gl.stencil_op(glow::KEEP, glow::KEEP, glow::REPLACE); + } + } + + pub fn use_stencil(&self) { + unsafe { + self.gl.stencil_func(glow::EQUAL, 1, 0xff); + self.gl.stencil_op(glow::KEEP, glow::KEEP, glow::KEEP); + } + } + + pub fn write_and_use_stencil(&self) { + unsafe { + self.gl.stencil_func(glow::EQUAL, 1, 0xff); + self.gl.stencil_op(glow::KEEP, glow::KEEP, glow::REPLACE); + } + } + + pub fn use_inverse_stencil(&self) { + unsafe { + self.gl.stencil_func(glow::NOTEQUAL, 1, 0xff); + self.gl.stencil_op(glow::KEEP, glow::KEEP, glow::KEEP); + } + } + + pub fn write_and_use_inverse_stencil(&self) { + unsafe { + self.gl.stencil_func(glow::NOTEQUAL, 1, 0xff); + self.gl.stencil_op(glow::KEEP, glow::KEEP, glow::REPLACE); + } + } + + pub fn end_stencil(&self) { + unsafe { + self.gl.stencil_func(glow::ALWAYS, 1, 0xff); + self.gl.stencil_op(glow::KEEP, glow::KEEP, glow::KEEP); + } + } + + pub fn render_no_geometry(&self) { + unsafe { + self.gl.bind_vertex_array(Some(self.emptyvao)); + self.gl.draw_arrays(glow::TRIANGLE_STRIP, 0, 4); + } + } + + pub fn reset_blend(&self) { + unsafe { + self.gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA); + } + } + + pub fn inverse_blend(&self) { + unsafe { + self.gl.blend_func( + glow::ONE_MINUS_DST_COLOR, + glow::ZERO, + ); + } + } + + pub fn flip_colors_blend(&self) { + unsafe { + self.gl.blend_func_separate( + glow::ONE_MINUS_DST_COLOR, + glow::ZERO, + glow::ZERO, + glow::ONE, + ); + } + } + + pub fn enable_culling(&self) { + unsafe { + self.gl.enable(glow::CULL_FACE); + } + } + + pub fn disable_culling(&self) { + unsafe { + self.gl.disable(glow::CULL_FACE); + } + } + + #[cfg(target_arch = "wasm32")] + pub fn lock_mouse(&self) { + let _ = self.window.set_cursor_grab(winit::window::CursorGrabMode::Locked); + self.window.set_cursor_visible(false); + } + + #[cfg(not(target_arch = "wasm32"))] + pub fn lock_mouse(&self) { + unsafe { + glfw::ffi::glfwSetInputMode( + self.window.borrow_mut().window_ptr(), + glfw::ffi::CURSOR, + glfw::ffi::CURSOR_DISABLED, + ); + } + } + + pub fn check_error(&self) { + unsafe { + let err = self.gl.get_error(); + if err != 0 { + log::warn!("gl error: {}", err); + } + } + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/font.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/font.rs new file mode 100644 index 0000000..648bb47 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/font.rs @@ -0,0 +1,194 @@ +use crate::{context, mesh, state, texture}; +use glow::HasContext; + +pub struct BitmapParams<'color> { + pub color: &'color [glam::Vec3], + pub scale: glam::Vec2, + pub offset: glam::Vec2, +} +impl<'color> Default for BitmapParams<'color> { + fn default() -> Self { + Self { + color: &[], + scale: glam::Vec2::ONE, + offset: glam::Vec2::ZERO, + } + } +} +pub struct Bitmap { + pub char_width: i32, + pub char_height: i32, + pub font_width: i32, + pub font_height: i32, + pub font: texture::Texture, + pub vao: glow::VertexArray, + pub vertex_buf: glow::Buffer, + pub texcoords_buf: glow::Buffer, + pub colors_buf: glow::Buffer, + pub index_buf: glow::Buffer, +} + +impl Bitmap { + pub fn from_image( + ctx: &context::Context, + char_width: i32, char_height: i32, + font_width: i32, font_height: i32, + data: &[u8], + ) -> Self { + let font = texture::Texture::new(ctx, data); + unsafe { + let vao = ctx.gl.create_vertex_array().expect("failed to initialize vao"); + ctx.gl.bind_vertex_array(Some(vao)); + let vertex_buf = ctx.gl.create_buffer().expect("failed to create buffer object"); + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(vertex_buf)); + ctx.gl.vertex_attrib_pointer_f32(mesh::ATTRIB_VERTEX, 2, glow::FLOAT, false, 0, 0); + ctx.gl.enable_vertex_attrib_array(mesh::ATTRIB_VERTEX); + let texcoords_buf = ctx.gl.create_buffer().expect("failed to create buffer object"); + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(texcoords_buf)); + ctx.gl.vertex_attrib_pointer_f32(mesh::ATTRIB_TEXCOORD, 2, glow::FLOAT, false, 0, 0); + ctx.gl.enable_vertex_attrib_array(mesh::ATTRIB_TEXCOORD); + let colors_buf = ctx.gl.create_buffer().expect("failed to create buffer object"); + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(colors_buf)); + ctx.gl.vertex_attrib_pointer_f32(mesh::ATTRIB_COLOR, 3, glow::FLOAT, false, 0, 0); + ctx.gl.enable_vertex_attrib_array(mesh::ATTRIB_COLOR); + let index_buf = ctx.gl.create_buffer().expect("failed to create buffer object"); + ctx.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(index_buf)); + Self { + char_width, char_height, + font_width, font_height, + font, + vao, + vertex_buf, + texcoords_buf, + colors_buf, + index_buf, + } + } + } + + pub fn default(ctx: &context::Context) -> Self { + Self::from_image(ctx, 7, 9, 112, 54, include_bytes!("assets/fonts/default.png")) + } + + pub fn small(ctx: &context::Context) -> Self { + Self::from_image(ctx, 6, 7, 96, 42, include_bytes!("assets/fonts/small.png")) + } + + pub fn render_text_parameterized(&self, + ctx: &context::Context, _st: &state::State, + text: &str, + params: BitmapParams, + ) { + let mut cur = params.offset; + let mut vertices = Vec::new(); + let mut texcoords = Vec::new(); + let mut colors = Vec::new(); + let mut indices = Vec::new(); + let cwidth = self.char_width as f32 / self.font_width as f32; + let cheight = self.char_height as f32 / self.font_height as f32; + let sdims = glam::Vec2::new(2.0, 2.0) * params.scale; + let row_len = self.font_width as u32 / self.char_width as u32; + for (i, c) in text.chars().enumerate() { + if c == '\n' { + cur.x = 0.0; + cur.y -= sdims.y; + } else { + let idx = vertices.len() as u32; + vertices.push(cur); + vertices.push(cur + glam::Vec2::new(sdims.x, 0.0)); + vertices.push(cur + glam::Vec2::new(sdims.x, sdims.y)); + vertices.push(cur + glam::Vec2::new(0.0, sdims.y)); + let cidx = c as u32 - ' ' as u32; + let col = cidx % row_len; + let row = cidx / row_len; + let tcbase = glam::Vec2::new(col as f32 * cwidth, row as f32 * cheight); + texcoords.push(tcbase + glam::Vec2::new(0.0, cheight)); + texcoords.push(tcbase + glam::Vec2::new(cwidth, cheight)); + texcoords.push(tcbase + glam::Vec2::new(cwidth, 0.0)); + texcoords.push(tcbase); + let c = if let Some(c) = params.color.get(if params.color.is_empty() { 0 } else { i % params.color.len() }) { + *c + } else { + glam::Vec3::new(1.0, 1.0, 1.0) + }; + colors.push(c); colors.push(c); colors.push(c); colors.push(c); + indices.push(idx); indices.push(idx + 1); indices.push(idx + 2); + indices.push(idx); indices.push(idx + 3); indices.push(idx + 2); + cur.x += sdims.x; + } + } + let index_bytes: Vec = indices.iter().flat_map(|x| x.to_ne_bytes()).collect(); + self.font.bind(ctx); + unsafe { + ctx.gl.bind_vertex_array(Some(self.vao)); + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vertex_buf)); + ctx.gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + std::slice::from_raw_parts( + vertices.as_ptr() as _, + vertices.len() * std::mem::size_of::() * 2, + ), + glow::STATIC_DRAW, + ); + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.texcoords_buf)); + ctx.gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + std::slice::from_raw_parts( + texcoords.as_ptr() as _, + texcoords.len() * std::mem::size_of::() * 2, + ), + glow::STATIC_DRAW, + ); + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.colors_buf)); + ctx.gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + std::slice::from_raw_parts( + colors.as_ptr() as _, + colors.len() * std::mem::size_of::() * 3, + ), + glow::STATIC_DRAW, + ); + ctx.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.index_buf)); + ctx.gl.buffer_data_u8_slice( + glow::ELEMENT_ARRAY_BUFFER, + &index_bytes, + glow::STATIC_DRAW, + ); + ctx.gl.draw_elements(glow::TRIANGLES, indices.len() as _, glow::UNSIGNED_INT, 0); + } + } + + pub fn render_text_helper(&self, + ctx: &context::Context, st: &state::State, + text: &str, color: &[glam::Vec3] + ) { + self.render_text_parameterized( + ctx, st, + text, + BitmapParams { + color, + scale: glam::Vec2::ONE, + offset: glam::Vec2::ZERO, + } + ) + } + + pub fn render_text(&self, + ctx: &context::Context, st: &state::State, + text: &str + ) { + self.render_text_helper(ctx, st, text, &[]); + } + + pub fn render_text_at(&self, + ctx: &context::Context, st: &mut state::State, + pos: glam::Vec2, text: &str, + params: BitmapParams, + ) { + st.bind_2d(ctx, &st.shader_text_bitmap); + let dims = glam::Vec2::new(self.char_width as f32, self.char_height as f32); + let fpos = pos + glam::Vec2::new(-dims.x / 2.0, dims.y / 2.0); + st.shader_text_bitmap.set_position_text_bitmap(ctx, st, self, &fpos); + self.render_text_parameterized(ctx, st, text, params); + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/framebuffer.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/framebuffer.rs new file mode 100644 index 0000000..606fd6a --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/framebuffer.rs @@ -0,0 +1,158 @@ +use glow::HasContext; + +use crate::context; + +#[cfg(target_arch = "wasm32")] +use crate::Options; + +pub struct Framebuffer { + pub tex: Option, + pub fbo: Option, + pub dims: glam::Vec2, + pub offsets: glam::Vec2, +} + +impl Framebuffer { + pub fn screen(ctx: &context::Context) -> Self { + #[cfg(target_arch = "wasm32")] + let (windoww, windowh): (f32, f32) = if !ctx.options.contains(Options::NORESIZE) { + ctx.window.inner_size().into() + } else { + (ctx.render_width, ctx.render_height) + }; + #[cfg(not(target_arch = "wasm32"))] + let (windoww, windowh) = { + let (w, h) = ctx.window.borrow().get_size(); + (w as f32, h as f32) + }; + let ratio = ctx.compute_upscale(windoww as _, windowh as _) as f32; + let upscalew = ctx.render_width * ratio; + let upscaleh = ctx.render_height * ratio; + let offsetx = (windoww - upscalew) / 2.0; + let offsety = (windowh - upscaleh) / 2.0; + log::info!("resize window: {:?}, upscale: {:?}, offset: {:?}", (windoww, windowh), (upscalew, upscaleh), (offsetx, offsety)); + Self { + tex: None, + fbo: None, + dims: glam::Vec2::new(upscalew, upscaleh), + offsets: glam::Vec2::new(offsetx, offsety), + } + } + + pub fn new(ctx: &context::Context, dims: &glam::Vec2, offsets: &glam::Vec2) -> Self { + unsafe { + let fbo = ctx.gl.create_framebuffer() + .expect("failed to create framebuffer"); + ctx.gl.bind_framebuffer(glow::FRAMEBUFFER, Some(fbo)); + + let depth_buffer = ctx.gl.create_renderbuffer() + .expect("failed to create depth buffer"); + ctx.gl.bind_renderbuffer(glow::RENDERBUFFER, Some(depth_buffer)); + ctx.gl.renderbuffer_storage(glow::RENDERBUFFER, glow::DEPTH_COMPONENT32F, dims.x as _, dims.y as _); + ctx.gl.framebuffer_renderbuffer(glow::FRAMEBUFFER, glow::DEPTH_ATTACHMENT, glow::RENDERBUFFER, Some(depth_buffer)); + + let stencil_buffer = ctx.gl.create_renderbuffer() + .expect("failed to create stencil buffer"); + ctx.gl.bind_renderbuffer(glow::RENDERBUFFER, Some(stencil_buffer)); + ctx.gl.renderbuffer_storage(glow::RENDERBUFFER, glow::DEPTH_STENCIL, dims.x as _, dims.y as _); + ctx.gl.framebuffer_renderbuffer(glow::FRAMEBUFFER, glow::DEPTH_STENCIL_ATTACHMENT, glow::RENDERBUFFER, Some(stencil_buffer)); + + let tex = ctx.gl.create_texture() + .expect("failed to create framebuffer texture"); + ctx.gl.bind_texture(glow::TEXTURE_2D, Some(tex)); + ctx.gl.tex_image_2d( + glow::TEXTURE_2D, + 0, + glow::RGBA as _, + dims.x as _, + dims.y as _, + 0, + glow::RGBA, + glow::UNSIGNED_BYTE, + None, + ); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_EDGE as _); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as _); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::NEAREST as _); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::NEAREST as _); + ctx.gl.framebuffer_texture_2d(glow::FRAMEBUFFER, glow::COLOR_ATTACHMENT0, glow::TEXTURE_2D, Some(tex), 0); + ctx.gl.draw_buffer(glow::COLOR_ATTACHMENT0); + + let status = ctx.gl.check_framebuffer_status(glow::FRAMEBUFFER); + if status != glow::FRAMEBUFFER_COMPLETE { + panic!("error initializing framebuffer:\n{}", status); + } + + Self { + tex: Some(tex), + fbo: Some(fbo), + dims: *dims, + offsets: *offsets, + } + } + } + + pub fn bind_texture(&self, ctx: &context::Context) { + unsafe { + ctx.gl.active_texture(glow::TEXTURE0); + ctx.gl.bind_texture(glow::TEXTURE_2D, self.tex); + } + } + + pub fn bind(&self, ctx: &context::Context) { + unsafe { + ctx.gl.bind_framebuffer(glow::FRAMEBUFFER, self.fbo); + ctx.gl.viewport( + self.offsets.x as _, + self.offsets.y as _, + self.dims.x as _, + self.dims.y as _, + ); + } + } + + pub fn blit(&self, ctx: &context::Context, dest: &Self, pos: &glam::Vec2, scale: &glam::Vec2) { + unsafe { + ctx.gl.bind_framebuffer(glow::READ_FRAMEBUFFER, self.fbo); + ctx.gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, dest.fbo); + ctx.gl.blit_framebuffer( + 0, 0, self.dims.x as _, self.dims.y as _, + pos.x as _, pos.y as _, (pos.x + scale.x) as _, (pos.y + scale.y) as _, + glow::COLOR_BUFFER_BIT, glow::NEAREST + ); + } + } + + pub fn get_pixels(&self, ctx: &context::Context, buf: &mut [glam::Vec3]) { + let w = self.dims.x as usize; + let h = self.dims.y as usize; + let tmp = vec![glam::Vec3::default(); w * h]; + unsafe { + ctx.gl.bind_texture(glow::TEXTURE_2D, self.tex); + ctx.gl.get_tex_image( + glow::TEXTURE_2D, 0, glow::RGB, glow::FLOAT, + glow::PixelPackData::Slice( + std::slice::from_raw_parts_mut( + tmp.as_ptr() as *mut u8, + tmp.len() * std::mem::size_of::() + ) + ), + ); + } + for y in 0..h { + for x in 0..w { + buf[x + (h - 1 - y) * w] = tmp[x + y * w]; + } + } + } + + pub fn get_pixels_raw(&self, ctx: &context::Context, buf: &mut [u8]) { + unsafe { + ctx.gl.bind_texture(glow::TEXTURE_2D, self.tex); + ctx.gl.get_tex_image( + glow::TEXTURE_2D, 0, glow::RGBA, glow::UNSIGNED_BYTE, + glow::PixelPackData::Slice(buf), + ); + } + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/helpers.js b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/helpers.js new file mode 100644 index 0000000..d1b74b6 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/helpers.js @@ -0,0 +1,21 @@ +let resized = false; + +export async function js_track_resized_setup() { + window.addEventListener("resize", () => { + resized = true; + }); +} + +export function js_poll_resized() { + let ret = resized; + resized = false; + return ret; +} + +export function js_bundt_api_server() { + return globalThis.apiServer || "http://localhost:8000/api"; +} + +export function js_bundt_secure_api_server() { + return globalThis.secureApiServer || "http://localhost:8000/api"; +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/js/module.js b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/js/module.js new file mode 100644 index 0000000..03d0047 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/js/module.js @@ -0,0 +1,7 @@ +export function js_build_interface() { + return { + env: { + log_info: window.wasmBindings.log_info, + }, + }; +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/level2d.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/level2d.rs new file mode 100644 index 0000000..b64213a --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/level2d.rs @@ -0,0 +1 @@ +pub mod tiled; diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/level2d/tiled.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/level2d/tiled.rs new file mode 100644 index 0000000..2e8141e --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/level2d/tiled.rs @@ -0,0 +1,301 @@ +#![allow(dead_code)] + +use std::collections::HashMap; +use serde::Deserialize; +use glow::HasContext; + +use crate::{context, erm, mesh, shader, texture, Erm}; + +#[derive(Debug)] +pub enum Err { + LayerIndexOutOfBounds, + LayerDataTooSmall, + GIDNotFound(u32), + AssetNotFound(String), + GL(String), +} +impl std::error::Error for Err {} +impl std::fmt::Display for Err { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::LayerIndexOutOfBounds => write!(f, "layer index out of bounds"), + Self::LayerDataTooSmall => write!(f, "layer data too small for dimensions"), + Self::GIDNotFound(gid) => write!(f, "GID not found: {}", gid), + Self::AssetNotFound(ass) => write!(f, "asset not found: {}", ass), + Self::GL(msg) => write!(f, "GL error: {msg:}"), + } + } +} + +#[derive(Debug, Deserialize)] +pub enum LayerType { + #[serde(rename = "tilelayer")] + Tile, + #[serde(rename = "imagelayer")] + Image, + #[serde(rename = "objectgroup")] + ObjectGroup, + #[serde(rename = "group")] + Group, +} + +#[derive(Debug, Deserialize)] +pub struct Layer { + name: String, + id: i32, + #[serde(rename = "type")] ty: LayerType, + width: i32, height: i32, + x: i32, y: i32, + opacity: f32, + visible: bool, + data: Vec, +} + +#[derive(Debug, Deserialize)] +pub struct LevelTileset { + firstgid: i32, + source: String, +} + +#[derive(Debug, Deserialize)] +pub struct Level { + width: i32, height: i32, + tilewidth: i32, tileheight: i32, + layers: Vec, + tilesets: Vec, +} +impl Level { + pub fn new(bytes: &str) -> Erm { + Ok(serde_json::from_str(bytes)?) + } +} + +#[derive(Debug, Deserialize)] +pub struct Tileset { + name: String, + imagewidth: i32, imageheight: i32, + tilewidth: i32, tileheight: i32, + margin: i32, spacing: i32, +} +impl Tileset { + pub fn new(bytes: &str) -> Erm { + Ok(serde_json::from_str(bytes)?) + } +} + +// TODO +pub enum Flip { + None, +} + +pub struct Asset { + tileset: Tileset, + texture: texture::Texture, +} +#[derive(Default)] +pub struct Assets { + entries: HashMap, +} +impl Assets { + pub fn new() -> Self { Self::default() } + pub fn load(&mut self, ctx: &context::Context, nm: &str, ts: &str, img: &[u8]) -> Erm<()> { + let ass = Asset { + tileset: Tileset::new(ts)?, + texture: texture::Texture::new(ctx, img), + }; + if self.entries.insert(nm.to_string(), ass).is_some() { + log::warn!("duplicate tileset entry named: {}", nm); + } + Ok(()) + } + pub fn lookup_gid(&self, level: &Level, gid: u32) -> Erm<(i32, &Asset, Flip)> { + let offset = (gid & 0x0fffffff) as i32; + for lts in level.tilesets.iter().rev() { + if lts.firstgid <= offset { + return Ok(( + offset - lts.firstgid, + self.entries.get(<s.source).ok_or(Err::AssetNotFound(lts.source.clone()))?, + Flip::None + )) + } + } + erm(Err::GIDNotFound(gid)) + } +} + +pub struct LayerRenderer { + pub vao: glow::VertexArray, + pub vertex_buf: glow::Buffer, + pub texcoords_buf: glow::Buffer, + pub index_buf: glow::Buffer, + pub index_count: usize, +} +impl LayerRenderer { + pub fn new(ctx: &context::Context) -> Erm { + unsafe { + let vao = ctx.gl.create_vertex_array().map_err(Err::GL)?; + ctx.gl.bind_vertex_array(Some(vao)); + let vertex_buf = ctx.gl.create_buffer().map_err(Err::GL)?; + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(vertex_buf)); + ctx.gl.vertex_attrib_pointer_f32(mesh::ATTRIB_VERTEX, 2, glow::FLOAT, false, 0, 0); + ctx.gl.enable_vertex_attrib_array(mesh::ATTRIB_VERTEX); + let texcoords_buf = ctx.gl.create_buffer().map_err(Err::GL)?; + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(texcoords_buf)); + ctx.gl.vertex_attrib_pointer_f32(mesh::ATTRIB_TEXCOORD, 2, glow::FLOAT, false, 0, 0); + ctx.gl.enable_vertex_attrib_array(mesh::ATTRIB_TEXCOORD); + let index_buf = ctx.gl.create_buffer().map_err(Err::GL)?; + ctx.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(index_buf)); + Ok(Self { + vao, + vertex_buf, + texcoords_buf, + index_buf, + index_count: 0, + }) + } + } +} +pub struct LevelRenderer { + pub layers: Vec, + pub shader: shader::Shader, +} +impl LevelRenderer { + pub fn new(ctx: &context::Context, level: &Level) -> Erm { + let mut layers = Vec::new(); + for _ in level.layers.iter() { + layers.push(LayerRenderer::new(ctx)?); + } + let shader = shader::Shader::new_nolib( + ctx, + include_str!("../assets/shaders/tiled/vert.glsl"), + include_str!("../assets/shaders/tiled/frag.glsl"), + ); + Ok(Self { + layers, + shader, + }) + } + pub fn populate_layer( + &mut self, + ctx: &context::Context, + assets: &Assets, + level: &Level, + lidx: usize + ) -> Erm<()> { + let lr = self.layers.get_mut(lidx).ok_or(Err::LayerIndexOutOfBounds)?; + let layer = level.layers.get(lidx).ok_or(Err::LayerIndexOutOfBounds)?; + let mut vertices = Vec::new(); + let mut texcoords = Vec::new(); + let mut indices = Vec::new(); + for y in 0..layer.height { + for x in 0..layer.width { + let idx = x as usize + (y * layer.width) as usize; + let gid = *layer.data.get(idx).ok_or(Err::LayerDataTooSmall)?; + if gid == 0 { continue; } + let (lid, ass, _) = assets.lookup_gid(level, gid)?; + let cols = ass.tileset.imagewidth / ass.tileset.tilewidth; + let rows = ass.tileset.imageheight / ass.tileset.tileheight; + let col = lid % cols; + let row = lid / cols; + let twidth = 1.0 / cols as f32; + let theight = 1.0 / rows as f32; + + let i = vertices.len() as u32; + let v = glam::Vec2::new(x as _, y as _); + vertices.push(v); + vertices.push(v + glam::Vec2::new(1.0, 0.0)); + vertices.push(v + glam::Vec2::new(1.0, 1.0)); + vertices.push(v + glam::Vec2::new(0.0, 1.0)); + let uvbase = glam::Vec2::new(col as f32 / cols as f32, row as f32 / rows as f32); + texcoords.push(uvbase + glam::Vec2::new(0.0, theight)); + texcoords.push(uvbase + glam::Vec2::new(twidth, theight)); + texcoords.push(uvbase + glam::Vec2::new(twidth, 0.0)); + texcoords.push(uvbase); + indices.push(i); indices.push(i + 1); indices.push(i + 2); + indices.push(i); indices.push(i + 3); indices.push(i + 2); + } + } + let index_bytes: Vec = indices.iter().flat_map(|x| x.to_ne_bytes()).collect(); + unsafe { + ctx.gl.bind_vertex_array(Some(lr.vao)); + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(lr.vertex_buf)); + ctx.gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + std::slice::from_raw_parts( + vertices.as_ptr() as _, + vertices.len() * std::mem::size_of::() * 2, + ), + glow::STATIC_DRAW, + ); + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(lr.texcoords_buf)); + ctx.gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + std::slice::from_raw_parts( + texcoords.as_ptr() as _, + texcoords.len() * std::mem::size_of::() * 2, + ), + glow::STATIC_DRAW, + ); + ctx.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(lr.index_buf)); + ctx.gl.buffer_data_u8_slice( + glow::ELEMENT_ARRAY_BUFFER, + &index_bytes, + glow::STATIC_DRAW, + ); + lr.index_count = indices.len(); + } + Ok(()) + } + pub fn render_layer( + &self, + ctx: &context::Context, + assets: &Assets, + level: &Level, + lidx: usize, + ) -> Erm<()> { + let layer = level.layers.get(lidx).ok_or(Err::LayerIndexOutOfBounds)?; + let lr = self.layers.get(lidx).ok_or(Err::LayerIndexOutOfBounds)?; + // TODO: handle layers with multiple textures + let gid = *layer.data.iter().find(|g| **g > 0).unwrap(); + let (_, ass, _) = assets.lookup_gid(level, gid)?; + ass.texture.bind(ctx); + unsafe { + ctx.gl.bind_vertex_array(Some(lr.vao)); + ctx.gl.draw_elements(glow::TRIANGLES, lr.index_count as _, glow::UNSIGNED_INT, 0); + } + Ok(()) + } + pub fn populate( + &mut self, + ctx: &context::Context, + assets: &Assets, + level: &Level, + ) -> Erm<()> { + for lidx in 0..level.layers.len() { + self.populate_layer(ctx, assets, level, lidx)?; + } + Ok(()) + } + pub fn render( + &self, + ctx: &context::Context, + assets: &Assets, + level: &Level, + ) -> Erm<()> { + self.shader.bind(ctx); + let sx = 2.0 * level.tilewidth as f32 / ctx.render_width; + let sy = 2.0 * level.tileheight as f32 / ctx.render_height; + self.shader.set_mat4( + ctx, "transform", + &glam::Mat4::from_scale_rotation_translation( + glam::Vec3::new(sx, -sy, 1.0), + glam::Quat::IDENTITY, + glam::Vec3::new(0.0, 0.0, 0.0), + ), + ); + for lidx in 0..level.layers.len() { + self.render_layer(ctx, assets, level, lidx)?; + } + Ok(()) + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/lib.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/lib.rs new file mode 100644 index 0000000..6b1564e --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/lib.rs @@ -0,0 +1,355 @@ +#![feature(try_blocks)] + +pub mod audio; +pub mod context; +pub mod font; +pub mod framebuffer; +pub mod level2d; +pub mod mesh; +pub mod net; +pub mod physics; +pub mod renderer; +pub mod save; +pub mod scene; +pub mod shader; +pub mod shadow; +pub mod state; +pub mod texture; +pub mod ui; +pub mod utils; + +pub use audio::AudioPlayback; +pub use simple_eyre::eyre::WrapErr; +pub use state::Tick; +pub use utils::{Erm, erm, install_error_handler}; + +#[cfg(target_arch = "wasm32")] +use winit::platform::web::EventLoopExtWebSys; + +#[cfg(target_arch = "wasm32")] +use winit::platform::web::WindowExtWebSys; + +#[cfg(target_arch = "wasm32")] +use wasm_bindgen::JsCast; + +#[cfg(not(target_arch = "wasm32"))] +use glfw::Context; + +use bitflags::bitflags; +bitflags! { + pub struct Options: u32 { + const OVERLAY = 0b00000001; + const HIDDEN = 0b00000010; + const NORESIZE = 0b00000100; + const EGL = 0b00001000; + const FULLSCREEN_MOUSE = 0b00010000; + } +} + +static mut CTX: Option<*const context::Context> = None; +static mut ST: Option<*mut state::State> = None; +static mut G: Option<*mut std::ffi::c_void> = None; + +pub fn contextualize(mut f: F) -> X +where + G: state::Game + 'static, + F: FnMut(&context::Context, &mut state::State, &mut G) -> X, +{ + unsafe { + match (CTX, ST, G) { + (Some(c), Some(s), Some(g)) => f(&*c, &mut *s, &mut *(g as *mut G)), + _ => panic!("context not set"), + } + } +} + +#[cfg(not(target_arch = "wasm32"))] +pub fn run<'a, F, G>(title: &str, w: u32, h: u32, options: Options, gnew: F) -> Erm<()> +where + G: state::Game + 'static, + F: (FnOnce(&'a context::Context) -> G), +{ + env_logger::Builder::new() + .filter(None, log::LevelFilter::Info) + .init(); + install_error_handler(); + + log::info!("hello computer, starting up..."); + + let (rglfw, rwindow, gl, events) = { + use glfw::fail_on_errors; + let mut glfw = glfw::init(glfw::fail_on_errors!()).expect("failed to initialize GLFW"); + + if options.contains(Options::EGL) { + glfw.window_hint(glfw::WindowHint::ContextCreationApi( + glfw::ContextCreationApi::Egl, + )); + } + // let gl_attr = video.gl_attr(); + // gl_attr.set_context_profile(sdl2::video::GLProfile::Core); + // gl_attr.set_context_version(3, 0); + let (mut window, events) = glfw.with_primary_monitor(|glfw, primary| { + if options.contains(Options::HIDDEN) { + glfw.window_hint(glfw::WindowHint::Visible(false)); + glfw.create_window(w as _, h as _, title, glfw::WindowMode::Windowed) + .expect("failed to create window") + } else if options.contains(Options::OVERLAY) { + let mon = primary.expect("failed to get monitor"); + let mode = mon.get_video_mode().expect("failed to get video mode"); + glfw.window_hint(glfw::WindowHint::RedBits(Some(mode.red_bits))); + glfw.window_hint(glfw::WindowHint::GreenBits(Some(mode.green_bits))); + glfw.window_hint(glfw::WindowHint::BlueBits(Some(mode.blue_bits))); + glfw.window_hint(glfw::WindowHint::RefreshRate(Some(mode.refresh_rate))); + glfw.window_hint(glfw::WindowHint::Resizable(false)); + glfw.window_hint(glfw::WindowHint::Decorated(false)); + glfw.window_hint(glfw::WindowHint::Floating(true)); + glfw.window_hint(glfw::WindowHint::TransparentFramebuffer(true)); + unsafe { + // glfw.window_hint(glfw::WindowHint::MousePassthrough(true)); + glfw::ffi::glfwWindowHint(0x0002000D, 1); // mouse passthrough + } + glfw.create_window( + mode.width, + mode.height, + title, + glfw::WindowMode::FullScreen(mon), + ) + .expect("failed to create window") + } else { + glfw.create_window(w as _, h as _, title, glfw::WindowMode::Windowed) + .expect("failed to create window") + } + }); + window.make_current(); + window.set_key_polling(true); + window.set_mouse_button_polling(true); + window.set_size_polling(true); + window.set_focus_polling(true); + window.set_cursor_pos_polling(true); + let gl = unsafe { + glow::Context::from_loader_function(|s| window.get_proc_address(s) as *const _) + }; + glfw.set_swap_interval(glfw::SwapInterval::Sync(1)); + (glfw, window, gl, events) + }; + let glfw = std::cell::RefCell::new(rglfw); + let window = std::cell::RefCell::new(rwindow); + + let ctx = Box::leak(Box::new(context::Context::new( + glfw, window, gl, w as f32, h as f32, options, + ))); + let game = Box::leak(Box::new(gnew(ctx))); + let st = Box::leak(Box::new(state::State::new(ctx))); + + unsafe { + CTX = Some(ctx as _); + ST = Some(st as _); + G = Some(game as *mut G as *mut std::ffi::c_void); + } + + game.initialize(ctx, st)?; + st.initialize_audio(ctx, game)?; + 'running: loop { + if ctx.window.borrow().should_close() { + game.finalize(ctx, st)?; + log::info!("bye!"); + break 'running; + } + ctx.glfw.borrow_mut().poll_events(); + for (_, event) in glfw::flush_messages(&events) { + match event { + glfw::WindowEvent::Size(_, _) => st.handle_resize(ctx), + glfw::WindowEvent::Focus(false) => { + st.keys = state::Keys::new(); + } + glfw::WindowEvent::CursorPos(x, y) => { + st.mouse_moved(ctx, x as f32, y as f32, game)?; + } + glfw::WindowEvent::MouseButton(_, glfw::Action::Press, _) => { + st.mouse_pressed(ctx, game)?; + } + glfw::WindowEvent::MouseButton(_, glfw::Action::Release, _) => { + st.mouse_released(ctx, game)?; + } + glfw::WindowEvent::Key(key, _, glfw::Action::Press, _) => { + st.key_pressed(ctx, game, state::Keycode::new(key))?; + } + glfw::WindowEvent::Key(key, _, glfw::Action::Release, _) => { + st.key_released(ctx, game, state::Keycode::new(key))?; + } + _ => {} + } + } + if ctx.resize_necessary() { + st.handle_resize(ctx); + } + // if let Some(f) = &mut st.request { + // match std::future::Future::poll(f.as_mut(), &mut st.waker_ctx) { + // std::task::Poll::Pending => {}, + // std::task::Poll::Ready(res) => { + // st.request = None; + // match res { + // Ok(r) => st.request_returned(&ctx, game, r), + // Err(e) => log::warn!("error during HTTP request: {}", e), + // } + // }, + // } + // } + st.run_update(ctx, game)?; + st.run_render(ctx, game)?; + ctx.window.borrow_mut().swap_buffers(); + } + Ok(()) +} + +#[cfg(target_arch = "wasm32")] +pub fn run<'a, F, G>(w: u32, h: u32, options: Options, gnew: F) +where + G: state::Game + 'static, + F: (Fn(&'a context::Context) -> G), +{ + console_log::init_with_level(log::Level::Debug).unwrap(); + console_error_panic_hook::set_once(); + tracing_wasm::set_as_global_default(); + // install_error_handler(); + + log::info!("hello computer, starting up..."); + + let event_loop = winit::event_loop::EventLoop::new().expect("failed to initialize event loop"); + + let resize = !options.contains(Options::NORESIZE); + let (window, gl) = { + let mut builder = winit::window::WindowBuilder::new() + .with_maximized(resize) + .with_decorations(false); + if options.contains(Options::OVERLAY) { + builder = builder.with_transparent(true); + } + let window = builder + .build(&event_loop) + .expect("failed to initialize window"); + let gl = web_sys::window() + .and_then(|win| win.document()) + .and_then(|doc| { + let dst = doc.get_element_by_id("teleia-parent")?; + let canvas = + web_sys::Element::from(window.canvas().expect("failed to find canvas")); + dst.append_child(&canvas).ok()?; + let c = canvas.dyn_into::().ok()?; + let webgl2_context = c + .get_context("webgl2") + .ok()?? + .dyn_into::() + .ok()?; + Some(glow::Context::from_webgl2_context(webgl2_context)) + }) + .expect("couldn't add canvas to document"); + (window, gl) + }; + + let ctx = Box::leak(Box::new(context::Context::new( + window, gl, w as f32, h as f32, options, + ))); + ctx.maximize_canvas(); + let game = Box::leak(Box::new(gnew(ctx))); + let st = Box::leak(Box::new(state::State::new(&ctx))); + + unsafe { + CTX = Some(ctx as _); + ST = Some(st as _); + G = Some(game as *mut G as *mut std::ffi::c_void); + } + + let _ = game.initialize(ctx, st); + let _ = st.initialize_audio(ctx, game); + let res = std::rc::Rc::new(std::cell::RefCell::new(Ok(()))); + let result = res.clone(); + event_loop.set_control_flow(winit::event_loop::ControlFlow::Wait); + event_loop.spawn(move |event, elwt| { + let res: Erm<()> = contextualize(|ctx, st, game: &mut G| { + match &event { + winit::event::Event::WindowEvent { + event: wev, + window_id, + .. + } => match wev { + winit::event::WindowEvent::CloseRequested if *window_id == ctx.window.id() => { + elwt.exit() + } + winit::event::WindowEvent::Resized { .. } => { + #[cfg(target_arch = "wasm32")] + ctx.maximize_canvas(); + st.handle_resize(&ctx); + } + winit::event::WindowEvent::Focused(false) => { + st.keys = state::Keys::new(); + } + winit::event::WindowEvent::CursorMoved { position, .. } => { + st.mouse_moved(&ctx, position.x as f32, position.y as f32, game)?; + } + winit::event::WindowEvent::MouseInput { state, .. } => match state { + winit::event::ElementState::Pressed => { + st.mouse_pressed(&ctx, game)?; + } + winit::event::ElementState::Released => { + st.mouse_released(&ctx, game)?; + } + }, + winit::event::WindowEvent::KeyboardInput { + event: + winit::event::KeyEvent { + physical_key: winit::keyboard::PhysicalKey::Code(key), + state, + repeat: false, + .. + }, + .. + } => match state { + winit::event::ElementState::Pressed => { + st.key_pressed(&ctx, game, state::Keycode { kc: *key })?; + } + winit::event::ElementState::Released => { + st.key_released(&ctx, game, state::Keycode { kc: *key })?; + } + }, + _ => {} + }, + + winit::event::Event::AboutToWait => { + if ctx.resize_necessary() { + #[cfg(target_arch = "wasm32")] + ctx.maximize_canvas(); + st.handle_resize(&ctx); + } + // if let Some(f) = &mut st.request { + // match std::future::Future::poll(f.as_mut(), &mut st.waker_ctx) { + // std::task::Poll::Pending => {}, + // std::task::Poll::Ready(res) => { + // st.request = None; + // match res { + // Ok(r) => st.request_returned(&ctx, game, r), + // Err(e) => log::warn!("error during HTTP request: {}", e), + // } + // }, + // } + // // f.poll(); + // } + st.run_update(&ctx, game)?; + st.run_render(&ctx, game)?; + ctx.window.request_redraw(); + } + + _ => {} + } + Ok(()) + }); + if let Err(e) = res { + *result.borrow_mut() = Err(e); + elwt.exit(); + } + }); + let _ = game.finalize(ctx, st); + if let Err(e) = res.replace(Ok(())) { + panic!("{}", e); + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/mesh.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/mesh.rs new file mode 100644 index 0000000..ce34de4 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/mesh.rs @@ -0,0 +1,197 @@ +use glow::HasContext; + +use crate::context; + +pub const ATTRIB_VERTEX: u32 = 0; +pub const ATTRIB_NORMAL: u32 = 1; +pub const ATTRIB_TEXCOORD: u32 = 2; +pub const ATTRIB_JOINT: u32 = 3; +pub const ATTRIB_WEIGHT: u32 = 4; +pub const ATTRIB_COLOR: u32 = 5; + +type Buffer = ::Buffer; + +pub struct Mesh { + pub vao: glow::VertexArray, + pub vbo_vertex: Buffer, + pub vbo_index: Buffer, + pub vbo_normal: Option, + pub vbo_texcoord: Option, + pub mode: u32, // glow::TRIANGLES, etc. + pub index_count: usize, + pub index_type: u32, // glow::BYTE, glow::FLOAT, etc. + pub index_offset: i32, +} + +impl Mesh { + pub fn new_empty(ctx: &context::Context, normals: bool, texcoords: bool) -> Self { + unsafe { + let vao = ctx.gl.create_vertex_array().expect("failed to initialize vao"); + ctx.gl.bind_vertex_array(Some(vao)); + + let vbo_vertex = ctx.gl.create_buffer().expect("failed to create buffer object"); + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo_vertex)); + ctx.gl.vertex_attrib_pointer_f32(ATTRIB_VERTEX, 3, glow::FLOAT, false, 0, 0); + ctx.gl.enable_vertex_attrib_array(ATTRIB_VERTEX); + + let vbo_index = ctx.gl.create_buffer().expect("failed to create buffer object"); + ctx.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(vbo_index)); + + let vbo_normal = if normals { + let vbo_normal = ctx.gl.create_buffer().expect("failed to create buffer object"); + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo_normal)); + ctx.gl.vertex_attrib_pointer_f32(ATTRIB_NORMAL, 3, glow::FLOAT, false, 0, 0); + ctx.gl.enable_vertex_attrib_array(ATTRIB_NORMAL); + Some(vbo_normal) + } else { None }; + + let vbo_texcoord = if texcoords { + let vbo_texcoord = ctx.gl.create_buffer().expect("failed to create buffer object"); + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo_texcoord)); + ctx.gl.vertex_attrib_pointer_f32(ATTRIB_TEXCOORD, 2, glow::FLOAT, false, 0, 0); + ctx.gl.enable_vertex_attrib_array(ATTRIB_TEXCOORD); + Some(vbo_texcoord) + } else { None }; + + Self { + vao, + vbo_vertex, + vbo_index, + vbo_normal, + vbo_texcoord, + mode: glow::TRIANGLES, + index_count: 0, + index_type: glow::UNSIGNED_INT, + index_offset: 0, + } + } + } + pub fn upload( + &mut self, + ctx: &context::Context, + vertices: &[f32], + indices: &[u32], + snormals: Option<&[f32]>, + stexcoords: Option<&[f32]>, + ) { + unsafe { + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vbo_vertex)); + ctx.gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + std::slice::from_raw_parts( + vertices.as_ptr() as _, + std::mem::size_of_val(vertices), + ), + glow::STATIC_DRAW, + ); + ctx.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.vbo_index)); + ctx.gl.buffer_data_u8_slice( + glow::ELEMENT_ARRAY_BUFFER, + std::slice::from_raw_parts( + indices.as_ptr() as _, + std::mem::size_of_val(indices), + ), + glow::STATIC_DRAW, + ); + + if let Some(vbo_normal) = self.vbo_normal && let Some(normals) = snormals { + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo_normal)); + ctx.gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + std::slice::from_raw_parts( + normals.as_ptr() as _, + std::mem::size_of_val(normals), + ), + glow::STATIC_DRAW, + ); + Some(vbo_normal) + } else { None }; + + if let Some(vbo_texcoord) = self.vbo_texcoord && let Some(texcoords) = stexcoords { + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(vbo_texcoord)); + ctx.gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + std::slice::from_raw_parts( + texcoords.as_ptr() as _, + std::mem::size_of_val(texcoords), + ), + glow::STATIC_DRAW, + ); + Some(vbo_texcoord) + } else { None }; + self.index_count = indices.len(); + } + } + + pub fn build( + ctx: &context::Context, + vertices: &[f32], + indices: &[u32], + snormals: Option<&[f32]>, + stexcoords: Option<&[f32]>, + ) -> Self { + let mut ret = Self::new_empty(ctx, snormals.is_some(), stexcoords.is_some()); + ret.upload(ctx, vertices, indices, snormals, stexcoords); + ret + } + + pub fn upload_obj(&mut self, ctx: &context::Context, mut bytes: &[u8]) { + let lopts = tobj::LoadOptions { + triangulate: true, + single_index: true, + ..Default::default() + }; + let (meshes, _materials) = tobj::load_obj_buf( + &mut bytes, + &lopts, + |_| Err(tobj::LoadError::GenericFailure) + ).expect("failed to load mesh"); + let mesh = meshes.into_iter().next() + .expect("failed to load mesh") + .mesh; + self.upload( + ctx, + &mesh.positions, + &mesh.indices, + Some(&mesh.normals), + Some(&mesh.texcoords), + ) + } + + pub fn from_obj(ctx: &context::Context, mut bytes: &[u8]) -> Self { + let lopts = tobj::LoadOptions { + triangulate: true, + single_index: true, + ..Default::default() + }; + let (meshes, _materials) = tobj::load_obj_buf( + &mut bytes, + &lopts, + |_| Err(tobj::LoadError::GenericFailure) + ).expect("failed to load mesh"); + let mesh = meshes.into_iter().next() + .expect("failed to load mesh") + .mesh; + Self::build( + ctx, + &mesh.positions, + &mesh.indices, + Some(&mesh.normals), + Some(&mesh.texcoords), + ) + } + + pub fn render(&self, ctx: &context::Context) { + unsafe { + ctx.gl.bind_vertex_array(Some(self.vao)); + ctx.gl.draw_elements(self.mode, self.index_count as _, self.index_type, self.index_offset); + } + } + + pub fn render_instanced(&self, ctx: &context::Context, count: u64) { + unsafe { + ctx.gl.bind_vertex_array(Some(self.vao)); + ctx.gl.draw_elements_instanced(self.mode, self.index_count as _, self.index_type, self.index_offset, count as _); + } + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net.rs new file mode 100644 index 0000000..8758968 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net.rs @@ -0,0 +1,4 @@ +pub mod ws; + +#[cfg(not(target_arch = "wasm32"))] +pub mod fig; diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/fig.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/fig.rs new file mode 100644 index 0000000..916cdc1 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/fig.rs @@ -0,0 +1,100 @@ +use std::io::{Read, Write}; +use byteorder::{LE, ReadBytesExt, WriteBytesExt}; + +use crate::{Erm, WrapErr}; + +const KEY: usize = 42; + +pub fn read_length_prefixed_utf8(r: &mut R) -> Erm where R: std::io::Read { + let len = r.read_u32::()?; + let mut bs = vec![0; len as usize]; + r.read_exact(&mut bs)?; + Ok(String::from_utf8(bs)?) +} + +#[derive(Debug, Clone)] +pub struct BinaryMessage { + pub event: Vec, + pub data: Vec +} + +pub struct BinaryClient { + in_buf: Vec, + out_buf: Vec, + socket: std::net::TcpStream, + poller: polling::Poller, +} +impl BinaryClient { + pub fn new(addr: &str, subs: &[&[u8]]) -> Erm { + let mut socket = std::net::TcpStream::connect(addr).wrap_err("failed to connect to message bus")?; + for s in subs { + write!(socket, "s").wrap_err("failed to send subscribe message to bus")?; + socket.write_u32::(s.len() as u32).wrap_err("failed to send subscribe message length to bus")?; + socket.write_all(s).wrap_err("failed to send subscribe message to bus")?; + } + socket.set_nonblocking(true).wrap_err("failed to set message bus socket nonblocking")?; + socket.flush().wrap_err("failed to flush bus connection")?; + let in_buf = Vec::new(); + let out_buf = Vec::new(); + let poller = polling::Poller::new()?; + unsafe { + poller.add(&socket, polling::Event::all(KEY)).wrap_err("failed to add event to poll")?; + } + Ok(Self { + in_buf, out_buf, + socket, + poller, + }) + } + fn write_length_prefixed(&mut self, buf: &[u8]) -> Erm<()> { + self.out_buf.write_u32::(buf.len() as u32).wrap_err("failed to send message")?; + self.out_buf.write_all(buf).wrap_err("failed to send message")?; + Ok(()) + + } + pub fn publish(&mut self, ev: &[u8], data: &[u8]) -> Erm<()> { + write!(self.out_buf, "p").wrap_err("failed to send publish message to bus")?; + self.write_length_prefixed(ev)?; + self.write_length_prefixed(data)?; + Ok(()) + } + fn pop_incoming_message(&mut self) -> Option { + let mut reader = std::io::Cursor::new(&self.in_buf); + let event_len = reader.read_u32::().ok()?; + let mut event = vec![0; event_len as usize]; + reader.read_exact(&mut event).ok()?; + let data_len = reader.read_u32::().ok()?; + let mut data = vec![0; data_len as usize]; + reader.read_exact(&mut data).ok()?; + let len = reader.position() as usize; + self.in_buf.drain(..len); + Some(BinaryMessage { event, data }) + } + pub fn pump(&mut self) -> Erm> { + let mut events = polling::Events::new(); + events.clear(); + self.poller.wait(&mut events, Some(std::time::Duration::from_secs(0))) + .wrap_err("failed to poll message bus")?; + for ev in events.iter() { + if ev.key == KEY { + if ev.readable { + let mut buf = [0; 1024]; + match self.socket.read(&mut buf) { + Ok(sz) => self.in_buf.extend_from_slice(&buf[..sz]), + Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {}, + e => { e.wrap_err("failed to read from bus socket")?; }, + } + } + if ev.writable && !self.out_buf.is_empty() { + match self.socket.write(&self.out_buf) { + Ok(sz) => { self.out_buf.drain(..sz); }, + Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {}, + e => { e.wrap_err("failed to write to bus socket")?; }, + } + } + self.poller.modify(&self.socket, polling::Event::all(KEY)).wrap_err("failed to update event to poll")?; + } + } + Ok(self.pop_incoming_message()) + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws.rs new file mode 100644 index 0000000..b11df40 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws.rs @@ -0,0 +1,10 @@ +pub mod client; + +#[cfg(not(target_arch = "wasm32"))] +pub mod server; + +#[derive(Debug, Clone)] +pub enum Message { + Binary(Vec), + Text(String), +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/client.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/client.rs new file mode 100644 index 0000000..fe9f957 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/client.rs @@ -0,0 +1,9 @@ +#[cfg(target_arch = "wasm32")] +pub mod wasm; +#[cfg(target_arch = "wasm32")] +pub use wasm::*; + +#[cfg(not(target_arch = "wasm32"))] +pub mod native; +#[cfg(not(target_arch = "wasm32"))] +pub use native::*; diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/client/native.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/client/native.rs new file mode 100644 index 0000000..eb94093 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/client/native.rs @@ -0,0 +1,124 @@ +use std::sync::mpsc::{Sender, Receiver, channel}; +use std::sync::{Arc, Mutex}; +use std::thread::spawn; + +use crate::net::ws::Message; +use crate::{utils, Erm, WrapErr}; + +const KEY: usize = 42; + +type ClientChannels = (Sender, Receiver); +#[derive(Default)] +pub struct Client { + channels: Arc>>, +} + +impl Client { + pub fn new() -> Self { Self::default() } + pub fn connect(&mut self, url: &str) { + let (mut socket, _resp) = if let Ok(v) = tungstenite::connect(url) { v } else { + log::warn!("failed to connect to websocket: {}", url); + return; + }; + let poller = match polling::Poller::new() { + Ok(v) => v, + Err(e) => { log::warn!("failed to create poller: {}", e); return; } + }; + let res: Erm<()> = try { match socket.get_ref() { + tungstenite::stream::MaybeTlsStream::Plain(s) => unsafe { + s.set_nonblocking(true).wrap_err("failed to set socket nonblocking")?; + poller.add(s, polling::Event::readable(KEY)).wrap_err("failed to add event to poll")?; + }, + tungstenite::stream::MaybeTlsStream::NativeTls(s) => unsafe { + s.get_ref().set_nonblocking(true).wrap_err("failed to set socket nonblocking")?; + poller.add(s.get_ref(), polling::Event::readable(KEY)).wrap_err("failed to add event to poll")?; + }, + _ => utils::erm_msg("unknown socket type; cannot poll!")?, + }}; + if let Err(e) = res { + log::warn!("failed to add event to poll: {}", e); + let _ = socket.close(None); + return; + }; + let (outgoing_sender, outgoing_receiver) = channel(); + let (incoming_sender, incoming_receiver) = channel(); + *self.channels.lock().unwrap() = Some((outgoing_sender, incoming_receiver)); + let send_channels_ref = self.channels.clone(); + let recv_channels_ref = self.channels.clone(); + let send_socket_ref = Arc::new(Mutex::new(socket)); + let recv_socket_ref = send_socket_ref.clone(); + let mut events = polling::Events::new(); + spawn(move || loop { + // write all outgoing messages + let res: Erm<()> = try { + while let Ok(msg) = outgoing_receiver.recv() { + match msg { + Message::Text(txt) => send_socket_ref.lock().unwrap() + .send(tungstenite::Message::Text(txt)) + .wrap_err("failed to send websocket text")?, + Message::Binary(bytes) => send_socket_ref.lock().unwrap() + .send(tungstenite::Message::Binary(bytes)) + .wrap_err("failed to send websocket bytes")?, + } + } + }; + if let Err(e) = res { + log::warn!("error in websocket send thread: {}", e); + *send_channels_ref.lock().unwrap() = None; + return; + } + }); + spawn(move || loop { + // wait for and receive all incoming messages + let res: Erm<()> = try { + events.clear(); + poller.wait(&mut events, None).wrap_err("failed to wait on websocket poller")?; + for ev in events.iter() { + if ev.key == KEY { + if ev.readable { match recv_socket_ref.lock().unwrap().read().wrap_err("failed to recv on websocket")? { + tungstenite::Message::Text(txt) => incoming_sender.send(Message::Text(txt)) + .wrap_err("failed to send incoming websocket message on channel")?, + tungstenite::Message::Binary(bytes) => incoming_sender.send(Message::Binary(bytes)) + .wrap_err("failed to send incoming websocket message on channel")?, + tungstenite::Message::Ping(bs) => recv_socket_ref.lock().unwrap() + .send(tungstenite::Message::Pong(bs)) + .wrap_err("failed to send websocket pong")?, + m => log::warn!("unhandled incoming websocket message: {}", m), + }} + match recv_socket_ref.lock().unwrap().get_ref() { + tungstenite::stream::MaybeTlsStream::Plain(s) => + poller.modify(s, polling::Event::readable(KEY)) + .wrap_err("failed to modify event to poll")?, + tungstenite::stream::MaybeTlsStream::NativeTls(s) => + poller.modify(s.get_ref(), polling::Event::readable(KEY)) + .wrap_err("failed to modify event to poll")?, + _ => log::warn!("unknown socket type; cannot modify polling!"), + } + } + } + }; + if let Err(e) = res { + log::warn!("error in websocket recv thread: {}", e); + *recv_channels_ref.lock().unwrap() = None; + return; + } + }); + } + pub fn is_connected(&self) -> bool { + self.channels.lock().unwrap().is_some() + } + pub fn poll(&mut self) -> Option { + if let Some((_, incoming)) = &*self.channels.lock().unwrap() { + incoming.try_recv().ok() + } else { None } + } + pub fn send(&self, msg: Message) { + if let Some((outgoing, _)) = &mut *self.channels.lock().unwrap() { + if let Err(e) = outgoing.send(msg) { + log::warn!("failed to send websocket message on channel: {}", e); + } + } else { + log::warn!("tried to send message, but websocket is not connected"); + } + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/client/wasm.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/client/wasm.rs new file mode 100644 index 0000000..f4faff7 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/client/wasm.rs @@ -0,0 +1,73 @@ +use std::{collections::VecDeque, sync::{Arc, Mutex}}; + +use wasm_bindgen::prelude::*; + +use crate::net::ws::Message; + +impl Message { + fn from_messageevent(e: web_sys::MessageEvent) -> Self { + if let Ok(abuf) = e.data().dyn_into::() { + let array = js_sys::Uint8Array::new(&abuf).to_vec(); + Message::Binary(array) + } else if let Ok(txt) = e.data().dyn_into::() { + Message::Text(txt.into()) + } else { + panic!("received weird websocket message: {:?}", e); + } + } +} + +pub struct Client { + ws: Arc>>, + messages: Arc>>, +} + +impl Client { + pub fn new() -> Self { + Self { + ws: Arc::new(Mutex::new(None)), + messages: Arc::new(Mutex::new(VecDeque::new())), + } + } + pub fn connect(&mut self, url: &str) { + let ws_ref = self.ws.clone(); + let messages_ref = self.messages.clone(); + let cb: Closure = Closure::new(move |e: web_sys::MessageEvent| { + let msg = Message::from_messageevent(e); + log::info!("incoming: {:?}", msg); + messages_ref.lock().unwrap().push_back(msg); + }); + let close_cb: Closure = Closure::new(move |_: web_sys::MessageEvent| { + log::info!("closed!"); + *ws_ref.lock().unwrap() = None; + }); + let ws = web_sys::WebSocket::new(url).expect("failed to open websocket"); + ws.set_onmessage(Some(cb.as_ref().unchecked_ref())); + ws.set_onclose(Some(close_cb.as_ref().unchecked_ref())); + cb.forget(); + close_cb.forget(); + *self.ws.lock().unwrap() = Some(ws); + } + pub fn is_connected(&self) -> bool { + self.ws.lock().unwrap().is_some() + } + pub fn poll(&mut self) -> Option { + self.messages.lock().unwrap().pop_front() + } + pub fn send(&self, msg: Message) { + if let Some(ws) = &*self.ws.lock().unwrap() { + match msg { + Message::Text(txt) => { + if let Err(e) = ws.send_with_str(&txt) { + log::warn!("failed to send string: {:?}", e); + } + }, + Message::Binary(bytes) => { + if let Err(e) = ws.send_with_u8_array(&bytes) { + log::warn!("failed to send bytes: {:?}", e); + } + }, + } + } + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/server.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/server.rs new file mode 100644 index 0000000..9422aec --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/net/ws/server.rs @@ -0,0 +1,140 @@ +use std::collections::HashMap; +use std::net::{TcpListener, TcpStream}; +use std::sync::mpsc::{Sender, Receiver, channel}; +use std::sync::{Arc, Mutex}; +use std::thread::spawn; + +use crate::net::ws::Message; +use crate::{utils, Erm, WrapErr}; + +const ACCEPT_KEY: usize = 1; + +type ClientId = usize; +type ClientMessage = (ClientId, Message); + +type ServerChannels = (Sender, Receiver); +#[derive(Default)] +pub struct Server { + clients: Arc>>>, + channels: Arc>>, +} + +impl Server { + pub fn new() -> Self { Self::default() } + pub fn start(&mut self, addr: &str) { + let recv_clients_ref = self.clients.clone(); + let send_clients_ref = self.clients.clone(); + let (outgoing_sender, outgoing_receiver) = channel(); + let (incoming_sender, incoming_receiver) = channel(); + *self.channels.lock().unwrap() = Some((outgoing_sender, incoming_receiver)); + let channels_ref = self.channels.clone(); + let listener = TcpListener::bind(addr).expect("failed to bind server socket"); + let poller = polling::Poller::new().expect("failed to create poller for websocket server"); + unsafe { + poller.add(&listener, polling::Event::readable(ACCEPT_KEY)) + .expect("failed to add poll server socket"); + } + let mut events = polling::Events::new(); + let mut next_id = ACCEPT_KEY + 1; + spawn(move || loop { + // write all outgoing messages + while let Ok((cid, msg)) = outgoing_receiver.recv() { + let res: Erm<()> = try { + if let Some(sock) = send_clients_ref.lock().unwrap().get_mut(&cid) { + let res = match msg { + Message::Text(txt) => sock.send(tungstenite::Message::Text(txt)), + Message::Binary(bytes) => sock.send(tungstenite::Message::Binary(bytes)) + }; + match res { + Ok(_) => {}, + Err(tungstenite::Error::Io(e)) if e.kind() == std::io::ErrorKind::WouldBlock => { + log::info!("client {} receive send block", cid); + }, + Err(e) => utils::erm(e)?, + } + } + }; + if let Err(e) = res { + log::warn!("error when sending to client {}, disconnecting: {}", cid, e); + send_clients_ref.lock().unwrap().remove(&cid); + } + } + }); + spawn(move || loop { + // wait for and receive all new connections and incoming messages + let res: Erm<()> = try { + events.clear(); + poller.wait(&mut events, None).wrap_err("failed to wait on websocket server poller")?; + for ev in events.iter() { + if ev.key == ACCEPT_KEY { + let (sock, client_addr) = listener.accept().wrap_err("failed to accept on socket")?; + let id = next_id; next_id += 1; + let res: Erm<()> = try { + unsafe { poller.add(&sock, polling::Event::readable(id)) + .wrap_err("failed to add socket to poller")?; } + let conn = tungstenite::accept(sock).wrap_err("failed to upgrade to websocket")?; + recv_clients_ref.lock().unwrap().insert(id, conn); + log::info!("new connected client! {}", id); + }; + if let Err(e) = res { + log::warn!("error during connection from {}: {}", client_addr, e); + }; + poller.modify(&listener, polling::Event::readable(ACCEPT_KEY)) + .wrap_err("failed to modify event to poll")?; + } else { + let res: Erm<()> = try { + if let Some(sock) = recv_clients_ref.lock().unwrap().get_mut(&ev.key) { + match sock.read() { + Ok(tungstenite::Message::Text(t)) => + incoming_sender.send((ev.key, Message::Text(t))) + .wrap_err("failed to send incoming message on channel")?, + Ok(tungstenite::Message::Binary(b)) => + incoming_sender.send((ev.key, Message::Binary(b))) + .wrap_err("failed to send incoming message on channel")?, + Ok(tungstenite::Message::Ping(x)) => + sock.write(tungstenite::Message::Pong(x)) + .wrap_err("failed to reply with pong")?, + Ok(m) => log::info!("received unhandled websocket message: {}", m), + Err(tungstenite::Error::Io(e)) if e.kind() == std::io::ErrorKind::WouldBlock => { + log::info!("client {} receive would block", ev.key); + }, + Err(e) => utils::erm(e)?, + } + poller.modify(sock.get_ref(), polling::Event::readable(ev.key)) + .wrap_err("failed to modify event to poll")?; + } else { + log::warn!("poller indicated event for unknown client: {}", ev.key); + } + }; + if let Err(e) = res { + log::warn!("error on client {} connection, disconnecting: {}", ev.key, e); + recv_clients_ref.lock().unwrap().remove(&ev.key); + } + } + } + }; + if let Err(e) = res { + log::warn!("unhandled error in websocket thread, stopping server: {}", e); + *channels_ref.lock().unwrap() = None; + return; + } + }); + } + pub fn clients(&self) -> Vec { + self.clients.lock().unwrap().keys().copied().collect() + } + pub fn poll(&mut self) -> Option<(ClientId, Message)> { + if let Some((_, incoming)) = &*self.channels.lock().unwrap() { + incoming.try_recv().ok() + } else { None } + } + pub fn send(&self, client: ClientId, msg: Message) { + if let Some((outgoing, _)) = &mut *self.channels.lock().unwrap() { + if let Err(e) = outgoing.send((client, msg)) { + log::warn!("failed to send websocket message to client {} on channel: {}", client, e); + } + } else { + log::warn!("tried to send message to client {}, but websocket is not connected", client); + } + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/physics.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/physics.rs new file mode 100644 index 0000000..e69de29 diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/renderer.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/renderer.rs new file mode 100644 index 0000000..c22c973 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/renderer.rs @@ -0,0 +1,337 @@ +use crate::{context, state, shader, texture, mesh}; + +use bitflags::bitflags; + +bitflags! { + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub struct UberFlags: u32 { + const TEXTURE_COLOR = 0b0000000001; + const TEXTURE_NORMAL = 0b0000000010; + const FLIP_TEXTURE = 0b0000000100; + const LIGHT_AMBIENT = 0b0000001000; + const LIGHT_DIR = 0b0000010000; + const LIGHT_POINT = 0b0000100000; + const SPRITE = 0b0001000000; + const EFFECTS = 0b0010000000; + const YSKEW = 0b0100000000; + const VERTEX_COLOR = 0b1000000000; + } +} +impl UberFlags { + fn prelude() -> String { + let mut s = String::new(); + s += "#version 300 es\nprecision highp float;"; + for (nm, f) in Self::all().iter_names() { + s += &format!("const int {} = {};\n", nm, f.bits()); + } + s + } + fn set_flags(self, ctx: &context::Context, shader: &shader::Shader) { + shader.set_i32(ctx, "flags", self.bits() as i32); + } +} + +pub trait Assets { + type Shader: PartialEq + Eq + Clone + Copy; + fn shader(&self, i: Self::Shader) -> &shader::Shader; + type Texture: PartialEq + Eq + Clone + Copy; + fn texture(&self, i: Self::Texture) -> &texture::Texture; + type Mesh: PartialEq + Eq + Clone + Copy; + fn mesh(&self, i: Self::Mesh) -> &mesh::Mesh; + type Material: PartialEq + Eq + Clone + Copy; + fn material(&self, i: Self::Material) -> &texture::Material; +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum ShaderMode { TwoDimension, ThreeDimension, ThreeDimensionOrth } +#[derive(Debug, Clone, Copy)] +enum BoundShader { None, Uber(UberFlags, ShaderMode), Shader(A::Shader, ShaderMode) } +impl PartialEq for BoundShader { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::None, Self::None) => true, + (Self::Uber(sf, sm), Self::Uber(of, om)) => sf == of && sm == om, + (Self::Shader(ss, sm), Self::Shader(os, om)) => ss == os && sm == om, + _ => false, + } + } +} +#[derive(Debug, Clone, Copy)] +enum BoundTexture { None, Texture(A::Texture), Material(A::Material) } +impl PartialEq for BoundTexture { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::None, Self::None) => true, + (Self::Texture(s), Self::Texture(o)) => s == o, + (Self::Material(s), Self::Material(o)) => s == o, + _ => false, + } + } +} +pub struct Renderer { + pub assets: A, + shader_uber: shader::Shader, + shader: BoundShader, + texture: BoundTexture, +} +impl Renderer { + pub fn new(ctx: &context::Context, f: F) -> Self + where F: FnOnce(&context::Context) -> A { + let shader_uber = shader::Shader::new_nolib(ctx, + &format!("{}{}", UberFlags::prelude(), include_str!("assets/shaders/uber/vert.glsl")), + &format!("{}{}", UberFlags::prelude(), include_str!("assets/shaders/uber/frag.glsl")), + ); + shader_uber.bind(ctx); + shader_uber.set_i32(ctx, "texture_normal", 1); + Self { + assets: f(ctx), + shader_uber, + shader: BoundShader::None, + texture: BoundTexture::None, + } + } + pub fn font_char_width(&self, st: &state::State) -> f32 { st.font_default.char_width as f32 } + pub fn font_char_height(&self, st: &state::State) -> f32 { st.font_default.char_height as f32 } + pub fn unbind_texture(&mut self, _ctx: &context::Context, _st: &mut state::State) { + self.texture = BoundTexture::None; + } + pub fn bind_texture(&mut self, ctx: &context::Context, _st: &mut state::State, texture: A::Texture) { + if self.texture != BoundTexture::Texture(texture) { + self.assets.texture(texture).bind(ctx); + self.texture = BoundTexture::Texture(texture); + } + } + pub fn bind_material(&mut self, ctx: &context::Context, _st: &mut state::State, mat: A::Material) { + if self.texture != BoundTexture::Material(mat) { + self.assets.material(mat).bind(ctx); + self.texture = BoundTexture::Material(mat); + } + } + fn shader(&self) -> Option<(&shader::Shader, ShaderMode)> { + match self.shader { + BoundShader::Uber(_, sm) => Some((&self.shader_uber, sm)), + BoundShader::Shader(s, sm) => Some((self.assets.shader(s), sm)), + _ => None, + } + } + fn bind_uber(&mut self, + ctx: &context::Context, st: &mut state::State, + flags: UberFlags, mode: ShaderMode, + ) { + if let BoundShader::Uber(f, sm) = self.shader && f == flags && sm == mode { return } + match mode { + ShaderMode::TwoDimension => st.bind_2d(ctx, &self.shader_uber), + ShaderMode::ThreeDimension => st.bind_3d(ctx, &self.shader_uber), + ShaderMode::ThreeDimensionOrth => st.bind_3d_orth(ctx, &self.shader_uber), + } + flags.set_flags(ctx, &self.shader_uber); + self.shader = BoundShader::Uber(flags, mode) + } + fn bind_shader(&mut self, + ctx: &context::Context, st: &mut state::State, + shader: A::Shader, mode: ShaderMode, + ) { + if let BoundShader::Shader(s, sm) = self.shader && s == shader && sm == mode { return } + match mode { + ShaderMode::TwoDimension => st.bind_2d(ctx, self.assets.shader(shader)), + ShaderMode::ThreeDimension => st.bind_3d(ctx, self.assets.shader(shader)), + ShaderMode::ThreeDimensionOrth => st.bind_3d_orth(ctx, self.assets.shader(shader)), + } + self.shader = BoundShader::Shader(shader, mode) + } + pub fn bind_uber_2d(&mut self, ctx: &context::Context, st: &mut state::State, flags: UberFlags) { + self.bind_uber(ctx, st, flags, ShaderMode::TwoDimension); + } + pub fn bind_uber_3d(&mut self, ctx: &context::Context, st: &mut state::State, flags: UberFlags) { + self.bind_uber(ctx, st, flags, ShaderMode::ThreeDimension); + } + pub fn bind_uber_3d_orth(&mut self, ctx: &context::Context, st: &mut state::State, flags: UberFlags) { + self.bind_uber(ctx, st, flags, ShaderMode::ThreeDimensionOrth); + } + pub fn bind_shader_2d(&mut self, ctx: &context::Context, st: &mut state::State, shader: A::Shader) { + self.bind_shader(ctx, st, shader, ShaderMode::TwoDimension); + } + pub fn bind_shader_3d(&mut self, ctx: &context::Context, st: &mut state::State, shader: A::Shader) { + self.bind_shader(ctx, st, shader, ShaderMode::ThreeDimension); + } + pub fn render(&self, ctx: &context::Context, _st: &state::State, mesh: A::Mesh) { + self.assets.mesh(mesh).render(ctx) + } + pub fn render_square(&self, ctx: &context::Context, st: &state::State) { + st.mesh_square.render(ctx) + } + pub fn set_position_2d_mat(&self, ctx: &context::Context, st: &state::State, pos: glam::Mat4) { + if let Some((s, sm)) = self.shader() { + debug_assert!(sm == ShaderMode::TwoDimension, "attempted to set_position_2d in wrong mode"); + s.set_position_2d_mat(ctx, st, &pos); + } + } + pub fn set_position_2d_rotate(&self, ctx: &context::Context, st: &state::State, pos: glam::Vec2, dims: glam::Vec2, rot: glam::Quat) { + if let Some((s, sm)) = self.shader() { + debug_assert!(sm == ShaderMode::TwoDimension, "attempted to set_position_2d in wrong mode"); + s.set_position_2d_helper(ctx, st, &pos, &dims, &rot) + } + } + pub fn set_position_2d(&self, ctx: &context::Context, st: &state::State, pos: glam::Vec2, dims: glam::Vec2) { + if let Some((s, sm)) = self.shader() { + debug_assert!(sm == ShaderMode::TwoDimension, "attempted to set_position_2d in wrong mode"); + s.set_position_2d(ctx, st, &pos, &dims) + } + } + pub fn set_position_3d(&self, ctx: &context::Context, st: &state::State, pos: glam::Mat4) { + if let Some((s, sm)) = self.shader() { + debug_assert!(sm == ShaderMode::ThreeDimension || sm == ShaderMode::ThreeDimensionOrth, + "attempted to set_position_3d in wrong mode" + ); + s.set_position_3d(ctx, st, &pos) + } + } + pub fn set_i32(&self, ctx: &context::Context, _st: &state::State, nm: &str, val: i32) { + if let Some((s, _)) = self.shader() { s.set_i32(ctx, nm, val) } + } + pub fn set_f32(&self, ctx: &context::Context, _st: &state::State, nm: &str, val: f32) { + if let Some((s, _)) = self.shader() { s.set_f32(ctx, nm, val) } + } + pub fn set_vec2(&self, ctx: &context::Context, _st: &state::State, nm: &str, val: glam::Vec2) { + if let Some((s, _)) = self.shader() { s.set_vec2(ctx, nm, &val) } + } + pub fn set_vec3(&self, ctx: &context::Context, _st: &state::State, nm: &str, val: glam::Vec3) { + if let Some((s, _)) = self.shader() { s.set_vec3(ctx, nm, &val) } + } + pub fn set_vec4(&self, ctx: &context::Context, _st: &state::State, nm: &str, val: glam::Vec4) { + if let Some((s, _)) = self.shader() { s.set_vec4(ctx, nm, &val) } + } + pub fn set_mat4(&self, ctx: &context::Context, _st: &state::State, nm: &str, val: glam::Mat4) { + if let Some((s, _)) = self.shader() { s.set_mat4(ctx, nm, &val) } + } + pub fn set_texture_offset(&self, + ctx: &context::Context, st: &state::State, + xinc: i32, yinc: i32, + x: i32, y: i32 + ) { + let xcount = xinc as f32; let xratio = 1.0 / xcount; + let ycount = yinc as f32; let yratio = 1.0 / ycount; + self.set_vec2( + ctx, st, "sprite_dims", + glam::Vec2::new(xratio, yratio), + ); + self.set_vec2( + ctx, st, "sprite_offset", + glam::Vec2::new((x % xinc) as f32 * xratio, (y % yinc) as f32 * yratio), + ); + } + + /// Common case: draw the given textured mesh in the world (units are world tiles) + pub fn textured_mesh_world(&mut self, + ctx: &context::Context, st: &mut state::State, + shader: A::Shader, + texture: A::Texture, + mesh: A::Mesh, + pos: glam::Mat4, + ) { + self.bind_shader_3d(ctx, st, shader); + self.bind_texture(ctx, st, texture); + self.set_position_3d(ctx, st, pos); + self.render(ctx, st, mesh); + } + + /// Common case: draw the given color in a rectangle on the screen (units are pixels, pos is top left) + pub fn color_screen(&mut self, + ctx: &context::Context, st: &mut state::State, + color: glam::Vec4, + pos: glam::Vec2, + dims: glam::Vec2, + ) { + self.bind_uber_2d(ctx, st, UberFlags::empty()); + self.set_vec4(ctx, st, "color", color); + self.set_position_2d(ctx, st, pos, dims); + self.render_square(ctx, st); + } + + /// Common case: draw the given texture on the screen (units are pixels, pos is top left) + pub fn texture_screen(&mut self, + ctx: &context::Context, st: &mut state::State, + texture: A::Texture, + pos: glam::Vec2, + dims: glam::Vec2, + ) { + self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR); + self.bind_texture(ctx, st, texture); + self.set_position_2d(ctx, st, pos, dims); + self.render_square(ctx, st); + } + + pub fn texture_screen_rotate(&mut self, + ctx: &context::Context, st: &mut state::State, + texture: A::Texture, + pos: glam::Vec2, + dims: glam::Vec2, + rot: glam::Quat, + ) { + self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR); + self.bind_texture(ctx, st, texture); + self.set_position_2d_rotate(ctx, st, pos, dims, rot); + self.render_square(ctx, st); + } + + pub fn texture_screen_recolor(&mut self, + ctx: &context::Context, st: &mut state::State, + texture: A::Texture, hue: f32, + pos: glam::Vec2, + dims: glam::Vec2, + ) { + self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::EFFECTS); + self.bind_texture(ctx, st, texture); + self.set_f32(ctx, st, "effect_huescale", 0.0); + self.set_f32(ctx, st, "effect_hueshift", hue); + self.set_position_2d(ctx, st, pos, dims); + self.render_square(ctx, st); + self.set_f32(ctx, st, "effect_huescale", 1.0); + self.set_f32(ctx, st, "effect_hueshift", 0.0); + } + + /// Common case: text in the default font (units are pixels, pos is top left) + pub fn text_screen(&mut self, + ctx: &context::Context, st: &mut state::State, + pos: glam::Vec2, + s: &str, + ) { + // drawing text might bind the texture + self.texture = BoundTexture::None; + self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::VERTEX_COLOR | UberFlags::FLIP_TEXTURE); + let dims = glam::Vec2::new(st.font_default.char_width as f32, st.font_default.char_height as f32); + let fpos = pos + glam::Vec2::new(-dims.x / 2.0, dims.y / 2.0); + self.set_position_2d(ctx, st, fpos, dims); + st.font_default.render_text(ctx, st, s); + } + + /// Common case: text in the default font, with a color (units are pixels, pos is top left) + pub fn text_colored_screen(&mut self, + ctx: &context::Context, st: &mut state::State, + pos: glam::Vec2, + col: glam::Vec3, + s: &str, + ) { + self.texture = BoundTexture::None; + self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::VERTEX_COLOR | UberFlags::FLIP_TEXTURE); + let dims = glam::Vec2::new(st.font_default.char_width as f32, st.font_default.char_height as f32); + let fpos = pos + glam::Vec2::new(-dims.x / 2.0, st.font_default.char_height as f32 / 2.0); + self.set_position_2d(ctx, st, fpos, dims); + st.font_default.render_text_helper(ctx, st, s, &[col]); + } + + /// Common case: text in the default font (units are pixels, pos is center) + pub fn text_centered_screen(&mut self, + ctx: &context::Context, st: &mut state::State, + pos: glam::Vec2, + s: &str, + ) { + self.texture = BoundTexture::None; + self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::VERTEX_COLOR | UberFlags::FLIP_TEXTURE); + let width = s.len() as f32 * st.font_default.char_width as f32; + let dims = glam::Vec2::new(st.font_default.char_width as f32, st.font_default.char_height as f32); + let fpos = pos + glam::Vec2::new(-dims.x / 2.0 - (width / 2.0).round(), st.font_default.char_height as f32 / 2.0); + self.set_position_2d(ctx, st, fpos, dims); + st.font_default.render_text(ctx, st, s); + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/save.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/save.rs new file mode 100644 index 0000000..1297a1b --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/save.rs @@ -0,0 +1,47 @@ +#[cfg(target_arch = "wasm32")] +use base64::prelude::*; + +#[cfg(target_arch = "wasm32")] +pub fn save(id: &str, data: &W) where W: serde::Serialize { + let window = web_sys::window().expect("failed to get window object"); + let storage = window.local_storage() + .expect("failed to get local storage") + .expect("local storage not present"); + let key = format!("{}_save", id); + let val = bincode::serde::encode_to_vec(data, bincode::config::standard()).expect("failed to serialize save"); + let str = BASE64_STANDARD.encode(&val); + storage.set_item(&key, &str).expect("failed to set save"); +} + +#[cfg(target_arch = "wasm32")] +pub fn load(id: &str) -> Option where W: serde::de::DeserializeOwned { + let window = web_sys::window().expect("failed to get window object"); + let storage = window.local_storage() + .expect("failed to get local storage") + .expect("local storage not present"); + let key = format!("{}_save", id); + let s = storage.get_item(&key).expect("failed to get save").expect("save not present"); + let bytes = BASE64_STANDARD.decode(&s).expect("failed to decode base64 for save"); + let (ret, _) = bincode::serde::decode_from_slice(&bytes, bincode::config::standard()) + .expect("failed to deserialize save"); + Some(ret) +} + +#[cfg(not(target_arch = "wasm32"))] +pub fn save(id: &str, data: &W) where W: serde::Serialize { + let pd = directories::ProjectDirs::from("", "milkfat", id).expect("failed to get save directory"); + let _ = std::fs::create_dir_all(pd.data_dir()); + let path = pd.data_dir().join("teleia.save"); + let mut file = std::fs::File::create(&path).expect("failed to open save file"); + bincode::serde::encode_into_std_write(data, &mut file, bincode::config::standard()) + .expect("failed to write save file"); +} + +#[cfg(not(target_arch = "wasm32"))] +pub fn load(id: &str) -> Option where W: serde::de::DeserializeOwned { + let pd = directories::ProjectDirs::from("", "milkfat", id).expect("failed to get save directory"); + let _ = std::fs::create_dir_all(pd.data_dir()); + let path = pd.data_dir().join("teleia.save"); + let mut file = std::fs::File::open(&path).ok()?; + bincode::serde::decode_from_std_read(&mut file, bincode::config::standard()).ok() +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/scene.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/scene.rs new file mode 100644 index 0000000..a904bf1 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/scene.rs @@ -0,0 +1,401 @@ +use std::{collections::{HashMap, VecDeque}, mem::offset_of}; + +use glow::HasContext; +use image::EncodableLayout; + +use crate::{context, mesh, shader, texture}; + +pub type Index = usize; + +pub struct Primitive { + pub mesh: mesh::Mesh, + pub material: Index, +} + +pub struct Object { + pub primitives: Vec, +} + +pub struct Material { + pub base_color_factor: glam::Vec4, + pub base_color_texture: Option, + + pub metallic_factor: f32, + pub roughness_factor: f32, + pub metallic_roughness_texture: Option, + + pub normal_texture: Option, + + pub occlusion_texture: Option, + + pub emissive_factor: glam::Vec3, + pub emissive_texture: Option, +} + +pub struct Skin { + pub inverse_bind_matrices: Vec, + pub joints: Vec, +} + +pub enum ChannelValues { + Translation(Vec), + Rotation(Vec), + Scale(Vec), +} + +pub enum Interpolation { + Linear, + Step, + CubicSpline, +} + +pub struct Channel { + pub target: Index, + pub interpolation: Interpolation, + pub keyframes: Vec, + pub values: ChannelValues, +} + +pub struct Animation { + pub channels: Vec, +} + +pub struct Node { + pub children: Vec, + pub object: Option, + pub skin: Option, + pub transform: glam::Mat4, +} + +pub struct Scene { + pub objects: Vec, + pub textures: Vec, + pub materials: Vec, + pub skins: Vec, + pub animations: HashMap, + pub nodes: Vec, + pub nodes_by_name: HashMap, + pub scene_nodes: Vec, +} + +impl Scene { + pub fn load_default_shader(ctx: &context::Context) -> shader::Shader { + shader::Shader::new( + ctx, + include_str!("assets/shaders/scene/vert.glsl"), + include_str!("assets/shaders/scene/frag.glsl") + ) + } + pub fn from_gltf(ctx: &context::Context, bytes: &[u8]) -> Self { + let (gltf, buffers, images) = gltf::import_slice(bytes).expect("failed to parse GLTF"); + let get_buffer_data = |b: gltf::Buffer| { + buffers.get(b.index()).map(|gltf::buffer::Data(bytes)| bytes.as_slice()) + }; + let objects = gltf.meshes().map(|m| { + let primitives = m.primitives().map(|p| { + let mode = match p.mode() { + gltf::mesh::Mode::Points => glow::POINTS, + gltf::mesh::Mode::Lines => glow::LINES, + gltf::mesh::Mode::LineLoop => glow::LINE_LOOP, + gltf::mesh::Mode::LineStrip => glow::LINE_STRIP, + gltf::mesh::Mode::Triangles => glow::TRIANGLES, + gltf::mesh::Mode::TriangleStrip => glow::TRIANGLE_STRIP, + gltf::mesh::Mode::TriangleFan => glow::TRIANGLE_FAN, + }; + unsafe { + let vao = ctx.gl.create_vertex_array().expect("failed to initialize vao"); + ctx.gl.bind_vertex_array(Some(vao)); + + // in the past, I've been lazy and just uploaded whole buffers to the GPU. + // this is certainly not the right thing to do in general. + // perhaps I am misunderstanding, but it feels like GLTF makes it pretty difficult to do + // that in general, on account of things like sparse accessors. + // instead, we'll use the gltf crate's handy "reader" abstraction to iterate over all of the + // data in the buffers, assemble it ourselves, and then upload that. + let reader = p.reader(get_buffer_data); + + // on to the actual vertex data. + // this is the layout of a single vertex in the buffer we send to the GPU. + struct Vertex { + pos: glam::Vec3, + normal: glam::Vec3, + texcoord: glam::Vec2, + joints: glam::Vec4, + weights: glam::Vec4, + } + + // vertices always have positions + let mut vertices = Vec::new(); + for pos in reader.read_positions().expect("primitive has no positions") { + vertices.push(Vertex { + pos: glam::Vec3::from_array(pos), + normal: glam::Vec3::default(), + texcoord: glam::Vec2::default(), + joints: glam::Vec4::default(), + weights: glam::Vec4::default(), + }); + } + + // if we find indices, use those. otherwise generate indices + let indices: Vec = if let Some(ri) = reader.read_indices() { + ri.into_u32().collect() + } else { + vertices.iter().enumerate().map(|(i, _)| i as u32).collect() + }; + let indices_bytes: Vec = indices.iter().flat_map(|x| x.to_ne_bytes()).collect(); + let indices_buf = ctx.gl.create_buffer().expect("failed to create index buffer object"); + ctx.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(indices_buf)); + ctx.gl.buffer_data_u8_slice( + glow::ELEMENT_ARRAY_BUFFER, + &indices_bytes, + glow::STATIC_DRAW, + ); + + // optionally, we might have some other vertex attributes too + if let Some(iter) = reader.read_normals() { + for (i, n) in iter.enumerate() { + vertices[i].normal = glam::Vec3::from_array(n) + } + } + if let Some(iter) = reader.read_tex_coords(0) { + for (i, uv) in iter.into_f32().enumerate() { + vertices[i].texcoord = glam::Vec2::from_array(uv) + } + } + if let Some(iter) = reader.read_joints(0) { + for (i, j) in iter.into_u16().enumerate() { + vertices[i].joints = glam::Vec4::from_slice(&j.into_iter().map(|x| x as f32).collect::>()) + } + } + if let Some(iter) = reader.read_weights(0) { + for (i, w) in iter.into_f32().enumerate() { + vertices[i].weights = glam::Vec4::from_array(w) + } + } + + let vertex_size = std::mem::size_of::() as i32; + let vertices_buf = ctx.gl.create_buffer().expect("failed to create buffer object"); + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(vertices_buf)); + ctx.gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + std::slice::from_raw_parts( + vertices.as_ptr() as _, + vertices.len() * (vertex_size as usize), + ), + glow::STATIC_DRAW, + ); + ctx.gl.enable_vertex_attrib_array(mesh::ATTRIB_VERTEX); + ctx.gl.vertex_attrib_pointer_f32(mesh::ATTRIB_VERTEX, 3, glow::FLOAT, false, vertex_size, offset_of!(Vertex, pos) as _); + ctx.gl.enable_vertex_attrib_array(mesh::ATTRIB_NORMAL); + ctx.gl.vertex_attrib_pointer_f32(mesh::ATTRIB_NORMAL, 3, glow::FLOAT, false, vertex_size, offset_of!(Vertex, normal) as _); + ctx.gl.enable_vertex_attrib_array(mesh::ATTRIB_TEXCOORD); + ctx.gl.vertex_attrib_pointer_f32(mesh::ATTRIB_TEXCOORD, 2, glow::FLOAT, false, vertex_size, offset_of!(Vertex, texcoord) as _); + ctx.gl.enable_vertex_attrib_array(mesh::ATTRIB_JOINT); + ctx.gl.vertex_attrib_pointer_f32(mesh::ATTRIB_JOINT, 4, glow::FLOAT, false, vertex_size, offset_of!(Vertex, joints) as _); + ctx.gl.enable_vertex_attrib_array(mesh::ATTRIB_WEIGHT); + ctx.gl.vertex_attrib_pointer_f32(mesh::ATTRIB_WEIGHT, 4, glow::FLOAT, false, vertex_size, offset_of!(Vertex, weights) as _); + + + Primitive { + mesh: mesh::Mesh { + vao, + vbo_vertex: vertices_buf, + vbo_index: indices_buf, + vbo_normal: None, + vbo_texcoord: None, + mode, + index_count: indices.len(), + index_type: glow::UNSIGNED_INT, + index_offset: 0, + }, + material: p.material().index().unwrap(), + } + } + }).collect(); + Object { + primitives, + } + }).collect(); + let textures: Vec = images.into_iter().map(|bi| { + unsafe { + let i = bi.image.into_rgba8(); + let tex = ctx.gl.create_texture().expect("failed to create texture"); + ctx.gl.bind_texture(glow::TEXTURE_2D, Some(tex)); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_EDGE as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::NEAREST as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::NEAREST as i32); + ctx.gl.tex_image_2d( + glow::TEXTURE_2D, + 0, + glow::RGBA as i32, + i.width() as i32, + i.height() as i32, + 0, + glow::RGBA, + glow::UNSIGNED_BYTE, + Some(i.as_bytes()), + ); + ctx.gl.generate_mipmap(glow::TEXTURE_2D); + texture::Texture { tex, width: i.width() as i32, height: i.height() as i32 } + } + }).collect(); + let materials: Vec = gltf.materials().map(|m| { + let pbr = m.pbr_metallic_roughness(); + let [bcr, bcg, bcb, bca] = pbr.base_color_factor(); + let [emx, emy, emz] = m.emissive_factor(); + Material { + base_color_factor: glam::Vec4::new(bcr, bcg, bcb, bca), + base_color_texture: pbr.base_color_texture().map(|tex| tex.texture().source().index()), + metallic_factor: pbr.metallic_factor(), + roughness_factor: pbr.roughness_factor(), + metallic_roughness_texture: pbr.metallic_roughness_texture().map(|tex| tex.texture().source().index()), + normal_texture: m.normal_texture().map(|tex| tex.texture().source().index()), + occlusion_texture: m.occlusion_texture().map(|tex| tex.texture().source().index()), + emissive_factor: glam::Vec3::new(emx, emy, emz), + emissive_texture: m.emissive_texture().map(|tex| tex.texture().source().index()), + } + }).collect(); + + let skins = gltf.skins().map(|s| { + let ibm = s.reader(get_buffer_data).read_inverse_bind_matrices() + .expect("missing read inverse bind matrices") + .map(|m| glam::Mat4::from_cols_array_2d(&m)).collect(); + Skin { + inverse_bind_matrices: ibm, + joints: s.joints().map(|j| j.index()).collect(), + } + }).collect(); + + let animations = HashMap::from_iter(gltf.animations().filter_map(|a| { + let channels = a.channels().map(|c| { + let read = c.reader(get_buffer_data); + Channel { + target: c.target().node().index(), + interpolation: match c.sampler().interpolation() { + gltf::animation::Interpolation::Linear => Interpolation::Linear, + gltf::animation::Interpolation::Step => Interpolation::Step, + gltf::animation::Interpolation::CubicSpline => Interpolation::CubicSpline, + }, + keyframes: read.read_inputs().expect("channel has no inputs").collect(), + values: match read.read_outputs().expect("channel has no outputs") { + gltf::animation::util::ReadOutputs::Translations(ts) => + ChannelValues::Translation(ts.map(glam::Vec3::from_array).collect()), + gltf::animation::util::ReadOutputs::Rotations(ts) => + ChannelValues::Rotation(ts.into_f32().map(glam::Quat::from_array).collect()), + gltf::animation::util::ReadOutputs::Scales(ts) => + ChannelValues::Scale(ts.map(glam::Vec3::from_array).collect()), + _ => panic!("unsupport channel outputs"), + }, + } + }).collect(); + a.name().map(|nm| (nm.to_owned(), Animation { channels })) + })); + + let nodes = gltf.nodes().map(|n| { + Node { + children: n.children().map(|c| c.index()).collect(), + object: n.mesh().map(|m| m.index()), + skin: n.skin().map(|s| s.index()), + transform: glam::Mat4::from_cols_array_2d(&n.transform().matrix()), + } + }).collect(); + + let mut nodes_by_name = HashMap::new(); + for n in gltf.nodes() { + if let Some(nm) = n.name() { + nodes_by_name.insert(nm.to_owned(), n.index()); + } + } + + let scene_nodes = gltf.default_scene().unwrap().nodes().map(|n| n.index()).collect(); + + Self { + objects, + textures, + materials, + skins, + animations, + nodes, + nodes_by_name, + scene_nodes, + } + } + + pub fn compute_joint_matrices(&self, skin: &Skin) -> Vec { + let mut q: VecDeque<(Index, glam::Mat4)> = VecDeque::new(); + q.push_back((skin.joints[0], glam::Mat4::IDENTITY)); + let mut transforms = vec![glam::Mat4::IDENTITY; self.nodes.len()]; + while let Some((ni, m)) = q.pop_front() { + let n = &self.nodes[ni]; + transforms[ni] = m.mul_mat4(&n.transform); + for ci in &n.children { + q.push_back((*ci, transforms[ni])); + } + } + let mut ret = vec![glam::Mat4::IDENTITY; skin.joints.len()]; + for (idx, ni) in skin.joints.iter().enumerate() { + ret[idx] = transforms[*ni].mul_mat4(&skin.inverse_bind_matrices[idx]); + } + ret + } + + fn render_node(&self, ctx: &context::Context, shader: &shader::Shader, n: &Node) { + if let Some(o) = n.object.and_then(|i| self.objects.get(i)) { + if let Some(s) = n.skin.and_then(|i| self.skins.get(i)) { + let jms = self.compute_joint_matrices(s); + shader.set_mat4_array(ctx, "joint_matrices[0]", &jms); + } + for p in &o.primitives { + if let Some(tex) = self.materials.get(p.material) + .and_then(|m| m.base_color_texture) + .and_then(|t| self.textures.get(t)) { + tex.bind(ctx); + } else { + texture::Texture::bind_initial(ctx); + } + p.mesh.render(ctx); + } + } + } + + pub fn render(&self, ctx: &context::Context, shader: &shader::Shader) { + let mut q: VecDeque = VecDeque::new(); + for sn in &self.scene_nodes { + q.push_back(*sn); + } + while let Some(ni) = q.pop_front() { + let n = &self.nodes[ni]; + self.render_node(ctx, shader, n); + for ci in &n.children { + q.push_back(*ci); + } + } + } + + pub fn reflect_animation(&mut self, nm: &str, time: f32) { + if let Some(anim) = self.animations.get(nm) { + for c in &anim.channels { + let (previ, nexti) = if let Some(nexti) = c.keyframes.iter().position(|x| *x > time) { + let previ = if nexti > 0 { nexti - 1 } else { c.keyframes.len() - 1 }; + (previ, nexti) + } else { + (c.keyframes.len() - 1, 0) + }; + if let ChannelValues::Rotation(vs) = &c.values { + let prevt = c.keyframes[previ]; + let nextt = c.keyframes[nexti]; + let prev = vs[previ]; + let next = vs[nexti]; + let new = prev.slerp(next, (time - prevt) / (nextt - prevt)); + let (scale, _, trans) = self.nodes[c.target].transform.to_scale_rotation_translation(); + self.nodes[c.target].transform = glam::Mat4::from_scale_rotation_translation( + scale, + new, + trans, + ); + } + } + } + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/shader.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/shader.rs new file mode 100644 index 0000000..d18ba27 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/shader.rs @@ -0,0 +1,260 @@ +use std::collections::HashMap; + +use glow::HasContext; + +use crate::{context, font, mesh, state}; + +const COMMON_VERT: &str = include_str!("assets/shaders/common/vert.glsl"); +const COMMON_FRAG: &str = include_str!("assets/shaders/common/frag.glsl"); + +#[derive(Clone)] +pub struct Shader { + pub program: glow::Program, + pub uniforms: std::rc::Rc> +} + +impl Shader { + pub fn new_helper(ctx: &context::Context, vsrc: &str, fsrc: &str) -> Result { + unsafe { + let program = ctx.gl.create_program()?; + + let vert = ctx.gl.create_shader(glow::VERTEX_SHADER)?; + ctx.gl.shader_source(vert, vsrc); + ctx.gl.compile_shader(vert); + if !ctx.gl.get_shader_compile_status(vert) { + return Err(format!( + "failed to compile vertex shader:\n{}", + ctx.gl.get_shader_info_log(vert) + )); + } + ctx.gl.attach_shader(program, vert); + + let frag = ctx.gl.create_shader(glow::FRAGMENT_SHADER)?; + ctx.gl.shader_source(frag, fsrc); + ctx.gl.compile_shader(frag); + if !ctx.gl.get_shader_compile_status(frag) { + return Err(format!( + "failed to compile fragment shader:\n{}", + ctx.gl.get_shader_info_log(frag) + )); + } + ctx.gl.attach_shader(program, frag); + + ctx.gl.bind_attrib_location(program, mesh::ATTRIB_VERTEX, "vertex"); + ctx.gl.bind_attrib_location(program, mesh::ATTRIB_NORMAL, "normal"); + ctx.gl.bind_attrib_location(program, mesh::ATTRIB_TEXCOORD, "texcoord"); + ctx.gl.bind_attrib_location(program, mesh::ATTRIB_JOINT, "joint"); + ctx.gl.bind_attrib_location(program, mesh::ATTRIB_WEIGHT, "weight"); + ctx.gl.bind_attrib_location(program, mesh::ATTRIB_COLOR, "color"); + + ctx.gl.link_program(program); + if !ctx.gl.get_program_link_status(program) { + return Err(format!( + "failed to link shader program:\n{}", + ctx.gl.get_program_info_log(program), + )); + } + + ctx.gl.detach_shader(program, vert); + ctx.gl.delete_shader(vert); + ctx.gl.detach_shader(program, frag); + ctx.gl.delete_shader(frag); + + ctx.gl.use_program(Some(program)); + + let mut uniforms = HashMap::new(); + for index in 0..ctx.gl.get_active_uniforms(program) { + if let Some(active) = ctx.gl.get_active_uniform(program, index) { + if let Some(loc) = ctx.gl.get_uniform_location(program, &active.name) { + uniforms.insert(active.name, loc); + } else { + log::warn!("failed to get location for uniform: {}", active.name); + } + } else { + log::warn!("failed to get active uniform for index: {}", index); + } + } + + Ok(Self { + program, + uniforms: std::rc::Rc::new(uniforms), + }) + } + } + + pub fn new_nolib(ctx: &context::Context, vsrc: &str, fsrc: &str) -> Self { + match Self::new_helper(ctx, vsrc, fsrc) { + Ok(x) => x, + Err(e) => panic!("failed to load no-library shader: {}", e) + } + } + + pub fn new(ctx: &context::Context, vsrcstr: &str, fsrcstr: &str) -> Self { + let vsrc = format!("{}\n{}\n", COMMON_VERT, vsrcstr); + let fsrc = format!("{}\n{}\n", COMMON_FRAG, fsrcstr); + Self::new_nolib(ctx, &vsrc, &fsrc) + } + + pub fn delete(&mut self, ctx: &context::Context) { + unsafe { ctx.gl.delete_program(self.program); } + } + + pub fn replace(&mut self, ctx: &context::Context, vsrc: &str, fsrc: &str) -> Result<(), String> { + self.delete(ctx); + *self = Self::new_helper(ctx, vsrc, fsrc)?; + Ok(()) + } + + pub fn set_i32(&self, ctx: &context::Context, name: &str, val: i32) { + if let Some(loc) = self.uniforms.get(name) { + unsafe { ctx.gl.uniform_1_i32(Some(loc), val) } + } + } + + pub fn set_i32_array(&self, ctx: &context::Context, name: &str, val: &[i32]) { + if let Some(loc) = self.uniforms.get(name) { + unsafe { + ctx.gl.uniform_1_i32_slice(Some(loc), val) + } + } + } + + pub fn set_f32(&self, ctx: &context::Context, name: &str, val: f32) { + if let Some(loc) = self.uniforms.get(name) { + unsafe { ctx.gl.uniform_1_f32(Some(loc), val) } + } + } + + pub fn set_vec2(&self, ctx: &context::Context, name: &str, val: &glam::Vec2) { + if let Some(loc) = self.uniforms.get(name) { + unsafe { + ctx.gl.uniform_2_f32( + Some(loc), + val.x, + val.y, + ); + } + } + } + + pub fn set_vec2_array(&self, ctx: &context::Context, name: &str, val: &[glam::Vec2]) { + if let Some(loc) = self.uniforms.get(name) { + let vs: Vec = val.iter().flat_map(|v| [v.x, v.y]).collect(); + unsafe { + ctx.gl.uniform_2_f32_slice( + Some(loc), + &vs, + ); + } + } + } + + pub fn set_vec3(&self, ctx: &context::Context, name: &str, val: &glam::Vec3) { + if let Some(loc) = self.uniforms.get(name) { + unsafe { + ctx.gl.uniform_3_f32( + Some(loc), + val.x, + val.y, + val.z, + ); + } + } + } + + pub fn set_vec3_array(&self, ctx: &context::Context, name: &str, val: &[glam::Vec3]) { + if let Some(loc) = self.uniforms.get(name) { + let vs: Vec = val.iter().flat_map(|v| [v.x, v.y, v.z]).collect(); + unsafe { + ctx.gl.uniform_3_f32_slice( + Some(loc), + &vs, + ); + } + } + } + + pub fn set_vec4(&self, ctx: &context::Context, name: &str, val: &glam::Vec4) { + if let Some(loc) = self.uniforms.get(name) { + unsafe { + ctx.gl.uniform_4_f32( + Some(loc), + val.x, + val.y, + val.z, + val.w, + ); + } + } + } + + pub fn set_mat4(&self, ctx: &context::Context, name: &str, val: &glam::Mat4) { + if let Some(loc) = self.uniforms.get(name) { + unsafe { + ctx.gl.uniform_matrix_4_f32_slice( + Some(loc), + false, + &val.to_cols_array(), + ); + } + } + } + + pub fn set_mat4_array(&self, ctx: &context::Context, name: &str, val: &[glam::Mat4]) { + if let Some(loc) = self.uniforms.get(name) { + let vs: Vec = val.iter().flat_map(|m| m.to_cols_array()).collect(); + unsafe { + ctx.gl.uniform_matrix_4_f32_slice( + Some(loc), + false, + &vs, + ); + } + } + } + + pub fn set_position_3d(&self, ctx: &context::Context, _st: &state::State, position: &glam::Mat4) { + self.set_mat4(ctx, "position", position); + self.set_mat4(ctx, "normal_matrix", &position.inverse().transpose()); + } + + pub fn set_position_2d_mat(&self, ctx: &context::Context, st: &state::State, position: &glam::Mat4) { + self.set_mat4(ctx, "position", position); + } + + pub fn set_position_2d_helper(&self, ctx: &context::Context, st: &state::State, pos: &glam::Vec2, dims: &glam::Vec2, rot: &glam::Quat) { + let halfwidth = dims.x / 2.0; + let halfheight = dims.y / 2.0; + self.set_mat4( + ctx, "position", + &glam::Mat4::from_scale_rotation_translation( + glam::Vec3::new(halfwidth, halfheight, 1.0), + *rot, + glam::Vec3::new( + -st.render_dims.x / 2.0 + pos.x + halfwidth, + st.render_dims.y / 2.0 - pos.y - halfheight, + 0.0, + ), + ) + ); + } + + pub fn set_position_2d(&self, ctx: &context::Context, st: &state::State, pos: &glam::Vec2, dims: &glam::Vec2) { + self.set_position_2d_helper(ctx, st, pos, dims, &glam::Quat::IDENTITY) + } + + pub fn set_position_text_bitmap(&self, + ctx: &context::Context, st: &state::State, + font: &font::Bitmap, + pos: &glam::Vec2 + ) { + let dims = glam::Vec2::new(font.char_width as f32, font.char_height as f32); + self.set_position_2d_helper(ctx, st, pos, &dims, &glam::Quat::IDENTITY) + } + + pub fn bind(&self, ctx: &context::Context) { + unsafe { + ctx.gl.use_program(Some(self.program)); + } + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/shadow.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/shadow.rs new file mode 100644 index 0000000..8482179 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/shadow.rs @@ -0,0 +1,127 @@ +use glow::HasContext; + +use crate::context; + +pub struct ShadowBuffer { + pub fbo: glow::Framebuffer, + pub depth_tex: glow::Texture, + pub width: i32, + pub height: i32, +} + +impl ShadowBuffer { + pub fn new(ctx: &context::Context, w: i32, h: i32) -> Self { + unsafe { + // generate and bind FBO + let fbo = ctx.gl.create_framebuffer().expect("failed to create framebuffer"); + ctx.gl.bind_framebuffer(glow::FRAMEBUFFER, Some(fbo)); + + // generate and attach depth buffer + let depth_tex = ctx.gl.create_texture().expect("failed to create texture"); + ctx.gl.bind_texture(glow::TEXTURE_2D, Some(depth_tex)); + ctx.gl.tex_image_2d( + glow::TEXTURE_2D, + 0, + glow::DEPTH_COMPONENT as i32, + w, + h, + 0, + glow::DEPTH_COMPONENT, + glow::FLOAT, + None, + ); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::LINEAR as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::LINEAR as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_BORDER as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_BORDER as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_COMPARE_MODE, glow::COMPARE_REF_TO_TEXTURE as i32); + ctx.gl.tex_parameter_f32_slice(glow::TEXTURE_2D, glow::TEXTURE_BORDER_COLOR, &[1.0, 1.0, 1.0, 1.0]); + ctx.gl.framebuffer_texture_2d(glow::FRAMEBUFFER, glow::DEPTH_ATTACHMENT, glow::TEXTURE_2D, Some(depth_tex), 0); + ctx.gl.draw_buffer(glow::NONE); + ctx.gl.read_buffer(glow::NONE); + + let status = ctx.gl.check_framebuffer_status(glow::FRAMEBUFFER); + if status != glow::FRAMEBUFFER_COMPLETE { + panic!("error initializing framebuffer: {}", status); + } + Self { + fbo, + depth_tex, + width: w, + height: h, + } + } + } + + pub fn bind(&self, ctx: &context::Context) { + unsafe { + ctx.gl.bind_framebuffer(glow::FRAMEBUFFER, Some(self.fbo)); + ctx.gl.viewport(0, 0, self.width as _, self.height as _); + ctx.gl.clear(glow::DEPTH_BUFFER_BIT); + + } + } +} + +pub struct ShadowBuffer3D { + pub fbo: glow::Framebuffer, + pub depth_cubemap: glow::Texture, + pub width: i32, + pub height: i32, +} + +impl ShadowBuffer3D { + pub fn new(ctx: &context::Context, w: i32, h: i32) -> Self { + unsafe { + // generate and bind FBO + let fbo = ctx.gl.create_framebuffer().expect("failed to create framebuffer"); + ctx.gl.bind_framebuffer(glow::FRAMEBUFFER, Some(fbo)); + + // generate and attach depth buffer + let depth_cubemap = ctx.gl.create_texture().expect("failed to create texture"); + ctx.gl.bind_texture(glow::TEXTURE_CUBE_MAP, Some(depth_cubemap)); + for i in 0..6 { + ctx.gl.tex_image_2d( + glow::TEXTURE_CUBE_MAP_POSITIVE_X + i, + 0, + glow::DEPTH_COMPONENT as i32, + w, + h, + 0, + glow::DEPTH_COMPONENT, + glow::FLOAT, + None, + ); + ctx.gl.tex_parameter_i32(glow::TEXTURE_CUBE_MAP, glow::TEXTURE_MIN_FILTER, glow::LINEAR as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_CUBE_MAP, glow::TEXTURE_MAG_FILTER, glow::LINEAR as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_CUBE_MAP, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_EDGE as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_CUBE_MAP, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_CUBE_MAP, glow::TEXTURE_WRAP_R, glow::CLAMP_TO_EDGE as i32); + } + + ctx.gl.framebuffer_texture(glow::FRAMEBUFFER, glow::DEPTH_ATTACHMENT, Some(depth_cubemap), 0); + ctx.gl.draw_buffer(glow::NONE); + ctx.gl.read_buffer(glow::NONE); + + let status = ctx.gl.check_framebuffer_status(glow::FRAMEBUFFER); + if status != glow::FRAMEBUFFER_COMPLETE { + panic!("error initializing framebuffer: {}", status); + } + Self { + fbo, + depth_cubemap, + width: w, + height: h, + } + } + } + + pub fn bind(&self, ctx: &context::Context) { + unsafe { + ctx.gl.bind_framebuffer(glow::FRAMEBUFFER, Some(self.fbo)); + ctx.gl.viewport(0, 0, self.width as _, self.height as _); + ctx.gl.clear(glow::DEPTH_BUFFER_BIT); + + } + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/state.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/state.rs new file mode 100644 index 0000000..3353f33 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/state.rs @@ -0,0 +1,735 @@ +#![allow(dead_code, unused_variables)] +use bimap::BiHashMap; +use enum_map::{Enum, EnumMap, enum_map}; +use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, fmt::Display}; +use strum::EnumIter; + +#[cfg(not(target_arch = "wasm32"))] +use glow::HasContext; + +use crate::{audio, context, font, framebuffer, mesh, shader, utils}; + +pub type Tick = u64; + +const DELTA_TIME: f64 = 0.016; // todo + +pub const ORTH_WIDTH: f32 = 7.55869; +pub const ORTH_HEIGHT: f32 = 5.03913; + +pub trait Game { + fn initialize(&mut self, ctx: &context::Context, st: &mut State) -> utils::Erm<()> { + Ok(()) + } + fn finalize(&mut self, ctx: &context::Context, st: &mut State) -> utils::Erm<()> { + Ok(()) + } + fn initialize_audio( + &self, + ctx: &context::Context, + st: &State, + actx: &audio::Context, + ) -> HashMap { + HashMap::new() + } + fn keybindings_were_reset(&mut self, ctx: &context::Context, st: &mut State) -> utils::Erm<()> { + Ok(()) + } + fn mouse_move( + &mut self, + ctx: &context::Context, + st: &mut State, + x: i32, + y: i32, + ) -> utils::Erm<()> { + Ok(()) + } + fn mouse_press(&mut self, ctx: &context::Context, st: &mut State) -> utils::Erm<()> { + Ok(()) + } + fn mouse_released(&mut self, ctx: &context::Context, st: &mut State) -> utils::Erm<()> { + Ok(()) + } + fn update(&mut self, ctx: &context::Context, st: &mut State) -> utils::Erm<()> { + Ok(()) + } + fn render(&mut self, ctx: &context::Context, st: &mut State) -> utils::Erm<()> { + Ok(()) + } +} + +#[derive(Debug, Enum, EnumIter, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Key { + Up, + Down, + Left, + Right, + A, + B, + X, + Y, + L, + R, + Start, + Select, + Debug, +} +#[derive(Default)] +pub struct Keys { + pub pressed: EnumMap, + pub new: EnumMap, +} +impl Keys { + pub fn new() -> Self { + Self::default() + } + pub fn up(&self) -> bool { + self.pressed[Key::Up] + } + pub fn down(&self) -> bool { + self.pressed[Key::Down] + } + pub fn left(&self) -> bool { + self.pressed[Key::Left] + } + pub fn right(&self) -> bool { + self.pressed[Key::Right] + } + pub fn a(&self) -> bool { + self.pressed[Key::A] + } + pub fn b(&self) -> bool { + self.pressed[Key::B] + } + pub fn x(&self) -> bool { + self.pressed[Key::X] + } + pub fn y(&self) -> bool { + self.pressed[Key::Y] + } + pub fn l(&self) -> bool { + self.pressed[Key::L] + } + pub fn r(&self) -> bool { + self.pressed[Key::R] + } + pub fn start(&self) -> bool { + self.pressed[Key::Start] + } + pub fn select(&self) -> bool { + self.pressed[Key::Select] + } + pub fn debug(&self) -> bool { + self.pressed[Key::Debug] + } + pub fn new_up(&mut self) -> bool { + let ret = self.new[Key::Up]; + self.new[Key::Up] = false; + ret + } + pub fn new_down(&mut self) -> bool { + let ret = self.new[Key::Down]; + self.new[Key::Down] = false; + ret + } + pub fn new_left(&mut self) -> bool { + let ret = self.new[Key::Left]; + self.new[Key::Left] = false; + ret + } + pub fn new_right(&mut self) -> bool { + let ret = self.new[Key::Right]; + self.new[Key::Right] = false; + ret + } + pub fn new_a(&mut self) -> bool { + let ret = self.new[Key::A]; + self.new[Key::A] = false; + ret + } + pub fn new_b(&mut self) -> bool { + let ret = self.new[Key::B]; + self.new[Key::B] = false; + ret + } + pub fn new_x(&mut self) -> bool { + let ret = self.new[Key::X]; + self.new[Key::X] = false; + ret + } + pub fn new_y(&mut self) -> bool { + let ret = self.new[Key::Y]; + self.new[Key::Y] = false; + ret + } + pub fn new_l(&mut self) -> bool { + let ret = self.new[Key::L]; + self.new[Key::L] = false; + ret + } + pub fn new_r(&mut self) -> bool { + let ret = self.new[Key::R]; + self.new[Key::R] = false; + ret + } + pub fn new_start(&mut self) -> bool { + let ret = self.new[Key::Start]; + self.new[Key::Start] = false; + ret + } + pub fn new_select(&mut self) -> bool { + let ret = self.new[Key::Select]; + self.new[Key::Select] = false; + ret + } + pub fn new_debug(&mut self) -> bool { + let ret = self.new[Key::Debug]; + self.new[Key::Debug] = false; + ret + } +} + +pub struct PointLight { + pub pos: glam::Vec3, + pub color: glam::Vec3, + pub attenuation: glam::Vec2, +} + +type Timestamp = f64; + +#[cfg(target_arch = "wasm32")] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Keycode { + pub kc: winit::keyboard::KeyCode, +} +#[cfg(target_arch = "wasm32")] +impl Keycode { + pub fn new(kc: winit::keyboard::KeyCode) -> Self { + Self { kc } + } +} +#[cfg(target_arch = "wasm32")] +impl Display for Keycode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.kc) + } +} +#[cfg(target_arch = "wasm32")] +impl Serialize for Keycode { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.kc.serialize(serializer) + } +} +#[cfg(target_arch = "wasm32")] +impl<'de> Deserialize<'de> for Keycode { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let kc = winit::keyboard::KeyCode::deserialize(deserializer)?; + Ok(Self { kc }) + } +} + +#[cfg(not(target_arch = "wasm32"))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Keycode { + pub kc: glfw::Key, +} +#[cfg(not(target_arch = "wasm32"))] +impl Keycode { + pub fn new(kc: glfw::Key) -> Self { + Self { kc } + } +} +#[cfg(not(target_arch = "wasm32"))] +impl Display for Keycode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.kc) + } +} +#[cfg(not(target_arch = "wasm32"))] +impl Serialize for Keycode { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + (self.kc as i32).serialize(serializer) + } +} +#[cfg(not(target_arch = "wasm32"))] +impl<'de> Deserialize<'de> for Keycode { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + i32::deserialize(deserializer).map(|x| unsafe { std::mem::transmute(x) }) + } +} + +pub struct State { + pub tick: Tick, + pub nextframe: Timestamp, + pub fps: u32, + pub frames_this_second: u32, + pub start_this_second: Timestamp, + + pub rebinding: Option, + pub keybindings: BiHashMap, + pub keys: Keys, + + pub screen: framebuffer::Framebuffer, + pub render_framebuffer: framebuffer::Framebuffer, + pub render_dims: glam::Vec2, + pub shader_upscale: shader::Shader, + pub shader_text_bitmap: shader::Shader, + pub mesh_square: mesh::Mesh, + pub font_default: font::Bitmap, + pub font_small: font::Bitmap, + pub audio: Option, + + pub projection: glam::Mat4, + pub projection_orth: glam::Mat4, + pub camera: (glam::Vec3, glam::Vec3, glam::Vec3), + pub lighting: (glam::Vec3, glam::Vec3, glam::Vec3), + pub point_lights: Vec, +} + +#[cfg(target_arch = "wasm32")] +pub fn now(ctx: &context::Context) -> Timestamp { + ctx.performance.now() / 1000.0 +} + +#[cfg(not(target_arch = "wasm32"))] +pub fn now(ctx: &context::Context) -> Timestamp { + let elapsed = ctx.start_instant.elapsed(); + let ms = elapsed.as_millis(); + (ms as f64) / 1000.0 +} + +#[cfg(target_arch = "wasm32")] +pub fn default_keybindings() -> BiHashMap { + BiHashMap::from_iter(vec![ + (Keycode::new(winit::keyboard::KeyCode::KeyW), Key::Up), + (Keycode::new(winit::keyboard::KeyCode::KeyS), Key::Down), + (Keycode::new(winit::keyboard::KeyCode::KeyA), Key::Left), + (Keycode::new(winit::keyboard::KeyCode::KeyD), Key::Right), + (Keycode::new(winit::keyboard::KeyCode::Digit1), Key::A), + (Keycode::new(winit::keyboard::KeyCode::Digit2), Key::B), + (Keycode::new(winit::keyboard::KeyCode::Digit3), Key::X), + (Keycode::new(winit::keyboard::KeyCode::Digit4), Key::Y), + (Keycode::new(winit::keyboard::KeyCode::KeyQ), Key::L), + (Keycode::new(winit::keyboard::KeyCode::KeyE), Key::R), + (Keycode::new(winit::keyboard::KeyCode::Tab), Key::Start), + (Keycode::new(winit::keyboard::KeyCode::Space), Key::Select), + ( + Keycode::new(winit::keyboard::KeyCode::Backquote), + Key::Debug, + ), + ]) +} + +#[cfg(not(target_arch = "wasm32"))] +pub fn default_keybindings() -> BiHashMap { + BiHashMap::from_iter(vec![ + (Keycode::new(glfw::Key::W), Key::Up), + (Keycode::new(glfw::Key::S), Key::Down), + (Keycode::new(glfw::Key::A), Key::Left), + (Keycode::new(glfw::Key::D), Key::Right), + (Keycode::new(glfw::Key::Num1), Key::A), + (Keycode::new(glfw::Key::Num2), Key::B), + (Keycode::new(glfw::Key::Num3), Key::X), + (Keycode::new(glfw::Key::Num4), Key::Y), + (Keycode::new(glfw::Key::Q), Key::L), + (Keycode::new(glfw::Key::E), Key::R), + (Keycode::new(glfw::Key::Tab), Key::Start), + (Keycode::new(glfw::Key::Space), Key::Select), + (Keycode::new(glfw::Key::GraveAccent), Key::Debug), + ]) +} + +impl State { + pub fn new(ctx: &context::Context) -> Self { + let screen = framebuffer::Framebuffer::screen(ctx); + let render_framebuffer = framebuffer::Framebuffer::new( + ctx, + &glam::Vec2::new(ctx.render_width, ctx.render_height), + &glam::Vec2::new(0.0, 0.0), + ); + let shader_upscale = shader::Shader::new_nolib( + ctx, + include_str!("assets/shaders/scale/vert.glsl"), + include_str!("assets/shaders/scale/frag.glsl"), + ); + let shader_text_bitmap = shader::Shader::new_nolib( + ctx, + include_str!("assets/shaders/bitmap/vert.glsl"), + include_str!("assets/shaders/bitmap/frag.glsl"), + ); + let mesh_square = mesh::Mesh::from_obj(ctx, include_bytes!("assets/meshes/square.obj")); + + let nextframe = now(ctx); + + Self { + // we initialize the tick to 1000, which allows us to use "0" as the default time for + // various animation starts on entities without having them all play at game start + tick: 1000, + + nextframe, + fps: 0, + frames_this_second: 0, + start_this_second: nextframe, + + rebinding: None, + keybindings: default_keybindings(), + keys: Keys::new(), + + screen, + render_framebuffer, + render_dims: glam::Vec2::new(ctx.render_width, ctx.render_height), + shader_upscale, + shader_text_bitmap, + mesh_square, + font_default: font::Bitmap::default(ctx), + font_small: font::Bitmap::small(ctx), + audio: None, + + projection: glam::Mat4::perspective_lh( + std::f32::consts::PI / 4.0, + ctx.render_width / ctx.render_height, + // 0.1, + 0.5, + 50.0, + ), + projection_orth: glam::Mat4::orthographic_lh( + -ORTH_WIDTH, + ORTH_WIDTH, + -ORTH_HEIGHT, + ORTH_HEIGHT, + 0.5, + 50.0, + ), + camera: ( + glam::Vec3::new(0.0, 0.0, 0.0), + glam::Vec3::new(0.0, 0.0, 1.0), + glam::Vec3::new(0.0, 1.0, 0.0), + ), + lighting: ( + glam::Vec3::new(1.0, 1.0, 1.0), + glam::Vec3::new(1.0, 1.0, 1.0), + glam::Vec3::new(1.0, -1.0, 1.0), + ), + point_lights: Vec::new(), + // waker_ctx, + // http_client: reqwest::Client::new(), + // request: None, + } + } + + pub fn handle_resize(&mut self, ctx: &context::Context) { + self.screen = framebuffer::Framebuffer::screen(ctx); + } + + pub fn move_camera( + &mut self, + _ctx: &context::Context, + pos: &glam::Vec3, + dir: &glam::Vec3, + up: &glam::Vec3, + ) { + self.camera = (*pos, *dir, *up); + } + + pub fn bind_framebuffer(&mut self, ctx: &context::Context, fb: &framebuffer::Framebuffer) { + fb.bind(ctx); + self.render_dims = fb.dims; + } + + pub fn bind_render_framebuffer(&mut self, ctx: &context::Context) { + self.render_framebuffer.bind(ctx); + self.render_dims = self.render_framebuffer.dims; + } + + pub fn bind_screen(&mut self, ctx: &context::Context) { + self.screen.bind(ctx); + self.render_dims = self.screen.dims; + } + + pub fn set_lighting( + &mut self, + _ctx: &context::Context, + ambient: &glam::Vec3, + color: &glam::Vec3, + dir: &glam::Vec3, + ) { + self.lighting = (*ambient, *color, *dir); + } + + pub fn add_point_light( + &mut self, + _ctx: &context::Context, + pos: &glam::Vec3, + color: &glam::Vec3, + attenuation: &glam::Vec2, + ) { + self.point_lights.push(PointLight { + pos: *pos, + color: *color, + attenuation: *attenuation, + }); + } + + pub fn clear_point_lights(&mut self, _ctx: &context::Context) { + self.point_lights.clear(); + } + + pub fn view(&self) -> glam::Mat4 { + glam::Mat4::look_to_lh(self.camera.0, self.camera.1, self.camera.2) + } + + pub fn bind_3d_helper( + &self, + ctx: &context::Context, + shader: &shader::Shader, + plc: usize, + orth: bool, + ) { + shader.bind(ctx); + shader.set_mat4( + ctx, + "projection", + if orth { + &self.projection_orth + } else { + &self.projection + }, + ); + shader.set_mat4(ctx, "view", &self.view()); + shader.set_vec3(ctx, "light_ambient_color", &self.lighting.0); + shader.set_vec3(ctx, "light_dir_color", &self.lighting.1); + shader.set_vec3(ctx, "light_dir", &self.lighting.2.normalize()); + shader.set_i32(ctx, "light_count", plc as _); + } + + pub fn bind_3d_no_point_lights(&self, ctx: &context::Context, shader: &shader::Shader) { + self.bind_3d_helper(ctx, shader, 0, false); + } + + pub fn bind_3d_with_point_lights( + &self, + ctx: &context::Context, + shader: &shader::Shader, + orth: bool, + ) { + let plc = self.point_lights.len().min(5); + self.bind_3d_helper(ctx, shader, plc, orth); + if plc > 0 { + let lpos: Vec<_> = self.point_lights.iter().take(plc).map(|l| l.pos).collect(); + shader.set_vec3_array(ctx, "light_pos[0]", &lpos); + let lcolor: Vec<_> = self + .point_lights + .iter() + .take(plc) + .map(|l| l.color) + .collect(); + shader.set_vec3_array(ctx, "light_color[0]", &lcolor); + let lattenuation: Vec<_> = self + .point_lights + .iter() + .take(plc) + .map(|l| l.attenuation) + .collect(); + shader.set_vec2_array(ctx, "light_attenuation[0]", &lattenuation); + } + } + + pub fn bind_3d(&self, ctx: &context::Context, shader: &shader::Shader) { + self.bind_3d_with_point_lights(ctx, shader, false) + } + + pub fn bind_3d_orth(&self, ctx: &context::Context, shader: &shader::Shader) { + self.bind_3d_with_point_lights(ctx, shader, true) + } + + pub fn bind_2d(&self, ctx: &context::Context, shader: &shader::Shader) { + shader.bind(ctx); + shader.set_mat4(ctx, "projection", &glam::Mat4::IDENTITY); + shader.set_mat4( + ctx, + "view", + &glam::Mat4::from_scale(glam::Vec3::new( + 2.0 / ctx.render_width, + 2.0 / ctx.render_height, + 1.0, + )), + ); + } + + pub fn initialize_audio(&mut self, ctx: &context::Context, game: &mut G) -> utils::Erm<()> + where + G: Game, + { + if self.audio.is_none() { + self.audio = Some(audio::Assets::new(|actx| { + game.initialize_audio(ctx, self, actx) + })); + } + Ok(()) + } + + pub fn mouse_moved( + &mut self, + ctx: &context::Context, + x: f32, + y: f32, + game: &mut G, + ) -> utils::Erm<()> + where + G: Game, + { + if ctx.options.contains(crate::Options::FULLSCREEN_MOUSE) { + game.mouse_move( + ctx, + self, + (x * ctx.render_width / self.screen.dims.x) as i32, + (y * ctx.render_height / self.screen.dims.y) as i32, + )?; + } else { + let rx = ((x - self.screen.offsets.x) * ctx.render_width / self.screen.dims.x) as i32; + let ry = ((y - self.screen.offsets.y) * ctx.render_height / self.screen.dims.y) as i32; + if !(rx < 0 + || rx >= ctx.render_width as i32 + || ry < 0 + || ry >= ctx.render_height as i32) + { + game.mouse_move(ctx, self, rx, ry)?; + } + } + Ok(()) + } + + pub fn mouse_pressed(&mut self, ctx: &context::Context, game: &mut G) -> utils::Erm<()> + where + G: Game, + { + self.initialize_audio(ctx, game)?; + game.mouse_press(ctx, self)?; + Ok(()) + } + + pub fn mouse_released(&mut self, ctx: &context::Context, game: &mut G) -> utils::Erm<()> + where + G: Game, + { + game.mouse_released(ctx, self)?; + Ok(()) + } + + pub fn key_pressed( + &mut self, + ctx: &context::Context, + game: &mut G, + key: Keycode, + ) -> utils::Erm<()> + where + G: Game, + { + #[cfg(target_arch = "wasm32")] + let rebind = key.kc == winit::keyboard::KeyCode::F12; + #[cfg(not(target_arch = "wasm32"))] + let rebind = key.kc == glfw::Key::F12; + if rebind { + self.keybindings = default_keybindings(); + self.rebinding = None; + game.keybindings_were_reset(ctx, self)?; + } else if let Some(k) = self.rebinding { + self.keybindings.insert(key, k); + self.rebinding = None; + } else if let Some(k) = self.keybindings.get_by_left(&key) { + self.keys.pressed[*k] = true; + self.keys.new[*k] = true; + } + Ok(()) + } + + pub fn key_released( + &mut self, + _ctx: &context::Context, + _game: &mut G, + key: Keycode, + ) -> utils::Erm<()> + where + G: Game, + { + if let Some(k) = self.keybindings.get_by_left(&key) { + self.keys.pressed[*k] = false; + } + Ok(()) + } + + /// Return the first keybinding for the given virtual key + pub fn keybinding_for(&self, k: Key) -> Option { + self.keybindings + .get_by_right(&k) + .map(|kc| format!("{}", kc)) + } + + pub fn rebind_key(&mut self, k: Key) { + self.rebinding = Some(k); + } + + pub fn run_update(&mut self, ctx: &context::Context, game: &mut G) -> utils::Erm<()> + where + G: Game, + { + let now = now(ctx); + if now > self.nextframe { + while self.nextframe < now { + // find the next target frame that isn't in the past + self.nextframe += DELTA_TIME; + } + self.tick += 1; + self.frames_this_second += 1; + game.update(ctx, self)?; + self.keys.new = enum_map! { _ => false }; + } + if now - self.start_this_second > 1.0 { + // track FPS + self.start_this_second = now; + self.fps = self.frames_this_second; + self.frames_this_second = 0; + } + Ok(()) + } + + pub fn run_render(&mut self, ctx: &context::Context, game: &mut G) -> utils::Erm<()> + where + G: Game, + { + self.bind_screen(ctx); + ctx.clear_color(if ctx.options.contains(crate::Options::OVERLAY) { + glam::Vec4::new(0.0, 0.0, 0.0, 0.0) + } else { + glam::Vec4::new(0.0, 0.0, 0.0, 1.0) + }); + ctx.clear(); + + game.render(ctx, self)?; + + #[cfg(all(debug_assertions, not(target_arch = "wasm32")))] + { + let err = unsafe { ctx.gl.get_error() }; + if err != glow::NO_ERROR { + log::warn!("opengl error: {}", err); + } + // let log = unsafe { ctx.gl.get_debug_message_log(5) }; + // for m in log { + // log::warn!("opengl debug message: {:?}", m); + // } + } + Ok(()) + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/texture.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/texture.rs new file mode 100644 index 0000000..b9749a2 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/texture.rs @@ -0,0 +1,156 @@ +use glow::HasContext; +use image::EncodableLayout; + +use crate::context; + +pub struct Texture { + pub tex: glow::Texture, + pub width: i32, + pub height: i32, +} + +impl Texture { + pub fn new_empty(ctx: &context::Context) -> Self { + unsafe { + let tex = ctx.gl.create_texture().expect("failed to create texture"); + ctx.gl.bind_texture(glow::TEXTURE_2D, Some(tex)); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_EDGE as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::NEAREST as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::NEAREST as i32); + Self { + tex, + width: 0, height: 0, + } + } + } + + pub fn new(ctx: &context::Context, bytes: &[u8]) -> Self { + let rgba = image::ImageReader::new(std::io::Cursor::new(bytes)) + .with_guessed_format() + .expect("failed to guess image format") + .decode() + .expect("failed to decode image") + .into_rgba8(); + let pixels = rgba.as_bytes(); + unsafe { + let tex = ctx.gl.create_texture().expect("failed to create texture"); + ctx.gl.bind_texture(glow::TEXTURE_2D, Some(tex)); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_EDGE as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::NEAREST as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::NEAREST as i32); + ctx.gl.tex_image_2d( + glow::TEXTURE_2D, + 0, + glow::RGBA as i32, + rgba.width() as i32, + rgba.height() as i32, + 0, + glow::RGBA, + glow::UNSIGNED_BYTE, + Some(pixels), + ); + ctx.gl.generate_mipmap(glow::TEXTURE_2D); + + Self { + tex, + width: rgba.width() as i32, + height: rgba.height() as i32, + } + } + } + + pub fn upload(&mut self, ctx: &context::Context, bytes: &[u8]) { + let rgba = image::ImageReader::new(std::io::Cursor::new(bytes)) + .with_guessed_format() + .expect("failed to guess image format") + .decode() + .expect("failed to decode image") + .into_rgba8(); + let pixels = rgba.as_bytes(); + self.upload_rgba8(ctx, rgba.width() as i32, rgba.height() as i32, pixels); + } + + pub fn upload_rgba8(&mut self, ctx: &context::Context, width: i32, height: i32, data: &[u8]) { + unsafe { + ctx.gl.bind_texture(glow::TEXTURE_2D, Some(self.tex)); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_EDGE as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::NEAREST as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::NEAREST as i32); + ctx.gl.tex_image_2d( + glow::TEXTURE_2D, + 0, + glow::RGBA as i32, + width, + height, + 0, + glow::RGBA, + glow::UNSIGNED_BYTE, + Some(data), + ); + ctx.gl.generate_mipmap(glow::TEXTURE_2D); + } + self.width = width; + self.height = height; + } + + pub fn set_repeat(&self, ctx: &context::Context) { + unsafe { + ctx.gl.bind_texture(glow::TEXTURE_2D, Some(self.tex)); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::REPEAT as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::REPEAT as i32); + } + } + + pub fn set_anisotropic_filtering(&self, ctx: &context::Context) { + unsafe { + ctx.gl.bind_texture(glow::TEXTURE_2D, Some(self.tex)); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::REPEAT as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::REPEAT as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::LINEAR_MIPMAP_LINEAR as i32); + ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::LINEAR as i32); + ctx.gl.tex_parameter_f32(glow::TEXTURE_2D, glow::TEXTURE_MAX_ANISOTROPY_EXT, 4.0); + } + } + + pub fn bind(&self, ctx: &context::Context) { + unsafe { + ctx.gl.active_texture(glow::TEXTURE0); + ctx.gl.bind_texture(glow::TEXTURE_2D, Some(self.tex)); + } + } + + pub fn bind_initial(ctx: &context::Context) { + unsafe { + ctx.gl.active_texture(glow::TEXTURE0); + ctx.gl.bind_texture(glow::TEXTURE_2D, None); + } + } + + pub fn bind_index(&self, ctx: &context::Context, idx: u32) { + unsafe { + ctx.gl.active_texture(glow::TEXTURE0 + idx); + ctx.gl.bind_texture(glow::TEXTURE_2D, Some(self.tex)); + } + } +} + +pub struct Material { + pub color: Texture, + pub normal: Texture, +} +impl Material { + pub fn new(ctx: &context::Context, color_bytes: &[u8], normal_bytes: &[u8]) -> Self { + let color = Texture::new(ctx, color_bytes); + let normal = Texture::new(ctx, normal_bytes); + color.set_anisotropic_filtering(ctx); + normal.set_anisotropic_filtering(ctx); + Self { color, normal } + } + pub fn bind(&self, ctx: &context::Context) { + self.color.bind(ctx); + self.normal.bind_index(ctx, 1); + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/ui.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/ui.rs new file mode 100644 index 0000000..8607fb6 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/ui.rs @@ -0,0 +1,169 @@ +use crate::{state, utils}; +use crate::state::Tick; + +fn compute_reverse(frames: Tick, tick: Tick, start: Tick) -> Tick { + let leftover = frames - (tick - start) + .clamp(0, frames); + tick - leftover +} + +pub enum ModeToggle { + Inactive { start: Tick }, + Active { start: Tick }, +} + +pub struct Mode { + frames: Tick, + toggle: ModeToggle, +} + +impl Mode { + pub fn new(frames: Tick) -> Self { + Self { + frames, + toggle: ModeToggle::Inactive { start: 0 }, + } + } + + /// Is the current state active? + pub fn is_active(&self) -> bool { + match self.toggle { + ModeToggle::Inactive {..} => false, + ModeToggle::Active {..} => true, + } + } + + /// Has the current transition finished? + pub fn is_ready(&self, tick: Tick) -> bool { + let started = match self.toggle { + ModeToggle::Inactive { start } => start, + ModeToggle::Active { start } => start, + }; + tick - started > self.frames + } + + pub fn progress(&self, tick: Tick) -> f32 { + match self.toggle { + ModeToggle::Inactive { start } => { + 1.0 - (((tick - start) as f32) / self.frames as f32) + .clamp(0.0, 1.0) + }, + ModeToggle::Active { start } => { + (((tick - start) as f32) / self.frames as f32) + .clamp(0.0, 1.0) + } + } + } + + pub fn reset(&mut self) { + self.toggle = ModeToggle::Inactive { start: 0 }; + } + + pub fn toggle(&mut self, tick: Tick) { + match self.toggle { + ModeToggle::Inactive { start } => { + self.toggle = ModeToggle::Active { + start: compute_reverse(self.frames, tick, start) + }; + }, + ModeToggle::Active { start } => { + self.toggle = ModeToggle::Inactive { + start: compute_reverse(self.frames, tick, start) + }; + }, + } + } +} + +pub struct Cursor { + pub index: i32, + pub prev_index: i32, + pub change_started: Tick, + pub bound: i32, + pub frames: Tick, +} + +impl Cursor { + pub fn new(bound: i32, frames: Tick) -> Self { + Self { + index: 0, + prev_index: 0, + change_started: 0, + bound, + frames, + } + } + + pub fn animation_index(&self, tick: Tick) -> f32 { + let progress = ((tick - self.change_started) as f32) + / (self.frames as f32 / 2.0); + utils::lerp( + self.prev_index as f32, + self.index as f32, + progress + ) + } + + pub fn is_ready(&self, tick: Tick) -> bool { + tick - self.change_started > self.frames + } + + pub fn set(&mut self, val: i32, tick: Tick) -> bool { + if self.is_ready(tick) { + self.change_started = tick; + self.prev_index = self.index; + self.index = val; + self.index %= self.bound; + true + } else { false } + } + pub fn increment(&mut self, tick: Tick) -> bool { self.set(self.index + 1, tick) } + pub fn decrement(&mut self, tick: Tick) -> bool { self.set(self.index + self.bound - 1, tick) } + + pub fn set_unlocked(&mut self, val: i32, tick: Tick) { + self.change_started = tick; + self.prev_index = self.index; + self.index = val; + self.index %= self.bound; + } + pub fn increment_unlocked(&mut self, tick: Tick) -> bool { self.set_unlocked(self.index + 1, tick); true } + pub fn decrement_unlocked(&mut self, tick: Tick) -> bool { self.set_unlocked(self.index + self.bound - 1, tick); true } + + /// Read keypresses to update this cursor (assuming that the left/right keys decrement/increment) + /// Returns true if an update was performed (e.g. to determine whether to play a sound). + pub fn update_horizontal(&mut self, st: &mut state::State) -> bool { + if st.keys.new_left() { + self.decrement_unlocked(st.tick) + } else if st.keys.new_right() { + self.increment_unlocked(st.tick) + } else if st.keys.left() { + self.decrement(st.tick) + } else if st.keys.right() { + self.increment(st.tick) + } else { false } + } + + pub fn update_vertical(&mut self, st: &mut state::State) -> bool { + if st.keys.new_up() { + self.decrement_unlocked(st.tick) + } else if st.keys.new_down() { + self.increment_unlocked(st.tick) + } else if st.keys.up() { + self.decrement(st.tick) + } else if st.keys.down() { + self.increment(st.tick) + } else { false } + } + + pub fn update_lr(&mut self, st: &mut state::State) -> bool { + if st.keys.new_l() { + self.decrement_unlocked(st.tick) + } else if st.keys.new_r() { + self.increment_unlocked(st.tick) + } else if st.keys.l() { + self.decrement(st.tick) + } else if st.keys.r() { + self.increment(st.tick) + } else { false } + } +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/utils.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/utils.rs new file mode 100644 index 0000000..14a7fdf --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia/src/utils.rs @@ -0,0 +1,147 @@ +use std::f32::consts::PI; + +use enum_map::Enum; +use serde::{Serialize, Deserialize}; +use strum::EnumIter; + +pub type Erm = simple_eyre::Result; + +pub fn erm(e: E) -> Erm where E: std::error::Error + std::marker::Send + std::marker::Sync + 'static { + Err(e.into()) +} + +#[derive(Debug)] +pub struct Error { + pub msg: String +} +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "teleia error: {}", self.msg) + } +} +impl std::error::Error for Error {} + +pub fn erm_msg(msg: &str) -> Erm { + Err(Error { + msg: msg.to_owned(), + }.into()) +} + +pub struct ErrorHandler; +impl simple_eyre::eyre::EyreHandler for ErrorHandler { + fn debug( + &self, + error: &(dyn std::error::Error + 'static), + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + if f.alternate() { + return core::fmt::Debug::fmt(error, f); + } + let mut first = true; + if let Some(s) = error.source() { + let errors: Vec<_> = std::iter::successors(Some(s), |e| (*e).source()).collect(); + for err in errors.iter().rev() { + writeln!(f)?; write!(f, "{}{}", if first {""} else {" - "}, err)?; + first = false; + } + } + writeln!(f)?; write!(f, "{}{}", if first {""} else {" - "}, error)?; + Ok(()) + } +} + +pub fn install_error_handler() { + simple_eyre::eyre::set_hook(Box::new(move |_| Box::new(ErrorHandler))).expect("failed to install error handler"); +} + +#[derive(Clone, Copy, Debug, Enum, EnumIter, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +pub enum Cardinal { + North, + South, + West, + East, +} + +impl Cardinal { + pub fn to_string(&self) -> &'static str { + match self { + Self::North => "north", + Self::South => "south", + Self::West => "west", + Self::East => "east", + } + } + + pub fn turn_cw(&self) -> Self { + match self { + Self::North => Self::East, + Self::South => Self::West, + Self::West => Self::North, + Self::East => Self::South, + } + } + + pub fn turn_ccw(&self) -> Self { + match self { + Self::North => Self::West, + Self::South => Self::East, + Self::West => Self::South, + Self::East => Self::North, + } + } + + pub fn dir(&self) -> glam::Vec3 { + match self { + Self::North => glam::Vec3::new(0.0, 1.0, 0.0), + Self::South => glam::Vec3::new(0.0, -1.0, 0.0), + Self::West => glam::Vec3::new(-1.0, 0.0, 0.0), + Self::East => glam::Vec3::new(1.0, 0.0, 0.0), + } + } + + pub fn offsets(&self) -> (i32, i32) { + match self { + Self::North => (0, 1), + Self::South => (0, -1), + Self::West => (-1, 0), + Self::East => (1, 0), + } + } + + pub fn angle(&self) -> f32 { + match self { + Self::North => 0.0, + Self::South => PI, + Self::West => PI / 2.0, + Self::East => 3.0 * PI / 2.0, + } + } + + pub fn turn_by(&self, o: Self) -> Self { + match o { + Self::North => *self, + Self::South => self.turn_cw().turn_cw(), + Self::West => self.turn_cw(), + Self::East => self.turn_ccw(), + } + } + + pub fn angle_between(&self, o: &Self) -> f32 { + if o == &self.turn_cw() { -PI / 2.0 } + else if o == &self.turn_ccw() { PI / 2.0 } + else if o == &self.turn_cw().turn_cw() { PI } + else { 0.0 } + } +} + +pub fn lerp(a: f32, b: f32, t: f32) -> f32 { + a + t.clamp(0.0, 1.0) * (b - a) +} + +pub fn dir_lerp(a: glam::Vec3, b: glam::Vec3, t: f32) -> glam::Vec3 { + let dirrotaxis = a.cross(b).normalize(); + let dirrotangle = a.angle_between(b); + let dirrotfull = glam::Quat::from_axis_angle(dirrotaxis, dirrotangle); + let dirrot = glam::Quat::IDENTITY.slerp(dirrotfull, t); + dirrot.mul_vec3(a) +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia_macros/Cargo.toml b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia_macros/Cargo.toml new file mode 100644 index 0000000..3ef969e --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia_macros/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "teleia_macros" +version.workspace = true +edition.workspace = true +authors.workspace = true + +[lib] +proc-macro = true + +[dependencies] +env = "1.0.1" +walkdir = "2.5.0" +heck = "0.5.0" +litrs = "1.0.0" \ No newline at end of file diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia_macros/src/lib.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia_macros/src/lib.rs new file mode 100644 index 0000000..5b6c0b9 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/crates/teleia_macros/src/lib.rs @@ -0,0 +1,231 @@ +use heck::ToUpperCamelCase; +use proc_macro::TokenStream; +use std::collections::HashSet; +use std::path::Path; +use walkdir::WalkDir; + +#[derive(Debug, Hash, PartialEq, Eq)] +struct Designator { + path: String, + parts: Vec, +} +impl Designator { + fn new(fbase: &str, mut path: &Path, shorten: bool) -> Self { + let mut parts: Vec<_> = path + .strip_prefix(fbase) + .unwrap() + .with_extension("") + .components() + .filter_map(|c| match c { + std::path::Component::Normal(o) => Some(o.to_str().unwrap().to_owned()), + _ => None, + }) + .collect(); + if shorten { + parts.pop(); + path = path.parent().expect("path has no parent"); + } + Self { + path: path + .to_str() + .expect("path is not a string") + .replace("\\", "/"), + parts, + } + } + fn enum_entry(&self, fnm: &str) -> String { + let singular = match fnm { + "meshes" => "mesh", + "textures" => "texture", + "materials" => "material", + "shaders" => "shader", + _ => fnm, + }; + let mut ret = format!("\n#[doc=\"newton-{}: {}\"]\n", singular, self.path); + ret += &self.parts.join(" ").to_upper_camel_case(); + ret + } + fn enum_element(&self, _fnm: &str) -> String { + self.parts.join(" ").to_upper_camel_case() + } + fn load_expr(&self, fnm: &str) -> Option { + let i = format!("assets/{}/{}", fnm, self.parts.join("/")); + match fnm { + "meshes" => Some(format!( + "teleia::mesh::Mesh::from_obj(ctx, include_bytes!(\"{}.obj\"))", + i + )), + "textures" => Some(format!( + "teleia::texture::Texture::new(ctx, include_bytes!(\"{}.png\"))", + i + )), + "materials" => Some(format!( + "teleia::texture::Material::new(ctx, include_bytes!(\"{}/color.jpg\"), include_bytes!(\"{}/normal.jpg\"))", + i, i + )), + "shaders" => { + if self.parts.contains(&"nolib".to_owned()) { + Some(format!( + "teleia::shader::Shader::new_nolib(ctx, include_str!(\"{}/vert.glsl\"), include_str!(\"{}/frag.glsl\"))", + i, i + )) + } else { + Some(format!( + "teleia::shader::Shader::new(ctx, include_str!(\"{}/vert.glsl\"), include_str!(\"{}/frag.glsl\"))", + i, i + )) + } + } + _ => None, + } + } +} + +#[derive(Debug)] +struct Field { + nm: String, + entries: HashSet, +} +impl Field { + fn new(base: &str, nm: &str) -> Self { + let mut entries = HashSet::new(); + let fbase = format!("{}{}", base, nm); + for f in WalkDir::new(&fbase).into_iter().flatten() { + if f.file_type().is_file() { + entries.insert(Designator::new( + &fbase, + f.path(), + nm == "shaders" || nm == "materials", + )); + } + } + Self { + nm: nm.to_owned(), + entries, + } + } + fn generate(&self) -> Option<(String, String, String)> { + let mut ents = Vec::new(); + for d in self.entries.iter() { + if let Some(exp) = d.load_expr(&self.nm) { + ents.push((d.enum_entry(&self.nm), d.enum_element(&self.nm), exp)); + } + } + let (enm, ty) = match self.nm.as_str() { + "meshes" => ("Mesh", "teleia::mesh::Mesh"), + "textures" => ("Texture", "teleia::texture::Texture"), + "materials" => ("Material", "teleia::texture::Material"), + "shaders" => ("Shader", "teleia::shader::Shader"), + _ => return None, + }; + let enums: Vec<_> = ents.iter().map(|(e, _, _)| e.clone()).collect(); + let edecl = format!("#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, enum_map::Enum)] +pub enum {} {{ {} }}", enm, enums.join(", ")); + let decl = format!("pub {}: enum_map::EnumMap<{}, {}>", self.nm, enm, ty); + let inits: Vec<_> = ents + .into_iter() + .map(|(_, e, exp)| format!("{}::{} => {}", enm, e, exp)) + .collect(); + let init = format!("{}: enum_map::enum_map!({})", self.nm, inits.join(", ")); + Some((edecl, decl, init)) + } +} + +#[derive(Debug)] +struct AssetData { + fields: Vec, +} +impl AssetData { + fn new(base: &str) -> Self { + let mut fields = Vec::new(); + let dirs = std::fs::read_dir(base) + .unwrap_or_else(|_| panic!("failed to read assets directory: {}", base)); + let (mut has_meshes, mut has_textures, mut has_materials, mut has_shaders) = + (false, false, false, false); + for d in dirs.flatten() { + let nm = d.file_name().into_string().unwrap(); + fields.push(Field::new(base, &nm)); + match &*nm { + "meshes" => has_meshes = true, + "textures" => has_textures = true, + "materials" => has_materials = true, + "shaders" => has_shaders = true, + _ => {} + }; + } + if !has_meshes { + fields.push(Field { + nm: "meshes".to_owned(), + entries: HashSet::new(), + }); + } + if !has_textures { + fields.push(Field { + nm: "textures".to_owned(), + entries: HashSet::new(), + }); + } + if !has_materials { + fields.push(Field { + nm: "materials".to_owned(), + entries: HashSet::new(), + }); + } + if !has_shaders { + fields.push(Field { + nm: "shaders".to_owned(), + entries: HashSet::new(), + }); + } + Self { fields } + } + fn generate(&self) -> String { + let mut res = String::new(); + let fdata: Vec<_> = self.fields.iter().filter_map(|f| f.generate()).collect(); + for (edecl, _, _) in fdata.iter() { + res += edecl; + res += "\n"; + } + res += "pub struct Assets {\n"; + for (_, decl, _) in fdata.iter() { + res += decl; + res += ",\n"; + } + res += "}\nimpl Assets {\npub fn new(ctx: &teleia::context::Context) -> Self {\nSelf {\n"; + for (_, _, init) in fdata.iter() { + res += init; + res += ",\n"; + } + res += "}\n}\n}\n"; + res += "impl teleia::renderer::Assets for Assets {\n"; + res += "type Shader = Shader;\n"; + res += + "fn shader(&self, i: Self::Shader) -> &teleia::shader::Shader { &self.shaders[i] }\n"; + res += "type Texture = Texture;\n"; + res += "fn texture(&self, i: Self::Texture) -> &teleia::texture::Texture { &self.textures[i] }\n"; + res += "type Material = Material;\n"; + res += "fn material(&self, i: Self::Material) -> &teleia::texture::Material { &self.materials[i] }\n"; + res += "type Mesh = Mesh;\n"; + res += "fn mesh(&self, i: Self::Mesh) -> &teleia::mesh::Mesh { &self.meshes[i] }\n"; + res += "}\n"; + res + } +} + +#[proc_macro] +pub fn generate_assets(s: TokenStream) -> TokenStream { + let token = s + .into_iter() + .next() + .expect("must pass asset base path as a string literal"); + let lit = litrs::StringLit::try_from(token).expect("argument was not a string literal"); + let base = lit.value(); + let manifest = env::var("CARGO_MANIFEST_DIR").expect("failed to get manifest path"); + let assets = AssetData::new(&format!("{}/{}", manifest, base)); + // println!("{}", assets.generate()); + assets + .generate() + .to_string() + .parse() + .expect("failed to parse generate_assets result") +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/fonts/ComicNeue-Regular.ttf b/2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/fonts/ComicNeue-Regular.ttf new file mode 100644 index 0000000..d454f46 Binary files /dev/null and b/2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/fonts/ComicNeue-Regular.ttf differ diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/meshes/cube.obj b/2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/meshes/cube.obj new file mode 100644 index 0000000..02851e8 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/meshes/cube.obj @@ -0,0 +1,38 @@ +# Blender 4.1.1 +# www.blender.org +o Cube +v 1.000000 1.000000 -1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 1.000000 1.000000 +v 1.000000 -1.000000 1.000000 +v -1.000000 1.000000 -1.000000 +v -1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 1.000000 +v -1.000000 -1.000000 1.000000 +vn -0.0000 1.0000 -0.0000 +vn -0.0000 -0.0000 1.0000 +vn -1.0000 -0.0000 -0.0000 +vn -0.0000 -1.0000 -0.0000 +vn 1.0000 -0.0000 -0.0000 +vn -0.0000 -0.0000 -1.0000 +vt 0.625000 0.500000 +vt 0.875000 0.500000 +vt 0.875000 0.750000 +vt 0.625000 0.750000 +vt 0.375000 0.750000 +vt 0.625000 1.000000 +vt 0.375000 1.000000 +vt 0.375000 0.000000 +vt 0.625000 0.000000 +vt 0.625000 0.250000 +vt 0.375000 0.250000 +vt 0.125000 0.500000 +vt 0.375000 0.500000 +vt 0.125000 0.750000 +s 0 +f 1/1/1 5/2/1 7/3/1 3/4/1 +f 4/5/2 3/4/2 7/6/2 8/7/2 +f 8/8/3 7/9/3 5/10/3 6/11/3 +f 6/12/4 2/13/4 4/5/4 8/14/4 +f 2/13/5 1/1/5 3/4/5 4/5/5 +f 6/11/6 5/10/6 1/1/6 2/13/6 diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/scenes/fox.glb b/2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/scenes/fox.glb new file mode 100644 index 0000000..1ef5c0d Binary files /dev/null and b/2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/scenes/fox.glb differ diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/textures/test.png b/2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/textures/test.png new file mode 100644 index 0000000..0752be0 Binary files /dev/null and b/2026/games_submissions/rpc2dot0/vendor/teleia/examples/assets/textures/test.png differ diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/examples/fox.rs b/2026/games_submissions/rpc2dot0/vendor/teleia/examples/fox.rs new file mode 100644 index 0000000..eff9345 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/examples/fox.rs @@ -0,0 +1,72 @@ +use teleia::*; + +use std::ops::Rem; + +pub struct TestGame { + font: font::Bitmap, + tt: font::TrueType, + // cube: mesh::Mesh, + fox: scene::Scene, + tex: texture::Texture, + shader: shader::Shader, +} + +impl TestGame { + pub async fn new(ctx: &context::Context) -> Self { + Self { + font: font::Bitmap::new(ctx), + tt: font::TrueType::new(ctx, 12.0, include_bytes!("assets/fonts/ComicNeue-Regular.ttf")), + // cube: mesh::Mesh::from_obj(ctx, include_bytes!("assets/meshes/cube.obj")), + fox: scene::Scene::from_gltf(ctx, include_bytes!("assets/scenes/fox.glb")), + // fox: scene::Scene::from_gltf(ctx, include_bytes!("/home/llll/src/colonq/assets/lcolonq_flat.vrm")), + tex: texture::Texture::new(ctx, include_bytes!("assets/textures/test.png")), + shader: scene::Scene::load_default_shader(ctx), + } + } +} + +impl state::Game for TestGame { + fn update(&mut self, ctx: &context::Context, st: &mut state::State) -> Erm<()> { + st.move_camera( + ctx, + &glam::Vec3::new(0.0, 0.0, -1.0), + &glam::Vec3::new(0.0, 0.0, 1.0), + &glam::Vec3::new(0.0, 1.0, 0.0), + ); + Ok(()) + } + fn render(&mut self, ctx: &context::Context, st: &mut state::State) -> Erm<()> { + // if let Some(n) = self.fox.nodes_by_name.get("J_Bip_C_Neck").and_then(|i| self.fox.nodes.get_mut(*i)) { + // n.transform *= glam::Mat4::from_rotation_z(0.05); + // } + ctx.clear(); + self.fox.reflect_animation("Run", (st.tick as f32 / 60.0).rem(3.0)); + st.bind_3d(ctx, &self.shader); + self.shader.set_position_3d( + ctx, + &glam::Mat4::from_scale_rotation_translation( + glam::Vec3::new(0.005, 0.005, 0.005), + // glam::Vec3::new(1.0, 1.0, 1.0), + glam::Quat::from_rotation_y(st.tick as f32 / 60.0), + glam::Vec3::new(0.0, -0.2, 0.0), + ), + ); + self.tex.bind(ctx); + self.fox.render(ctx, &self.shader); + self.font.render_text(ctx, &glam::Vec2::new(0.0, 10.0), "he's all FIXED up"); + self.tt.render_text_helper( + ctx, &glam::Vec2::new(10.0, 60.0), &glam::Vec2::new(20.0, 30.0), + "tESTge", + &[ + glam::Vec3::new(1.0, 0.0, 0.0), + glam::Vec3::new(0.0, 1.0, 0.0), + ], + ); + Ok(()) + } +} + +#[tokio::main] +pub async fn main() { + run("teleia test", 240, 160, Options::empty(), TestGame::new).await; +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/flake.lock b/2026/games_submissions/rpc2dot0/vendor/teleia/flake.lock new file mode 100644 index 0000000..687db1d --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/flake.lock @@ -0,0 +1,153 @@ +{ + "nodes": { + "crane": { + "locked": { + "lastModified": 1754269165, + "narHash": "sha256-0tcS8FHd4QjbCVoxN9jI+PjHgA4vc/IjkUSp+N3zy0U=", + "owner": "ipetkov", + "repo": "crane", + "rev": "444e81206df3f7d92780680e45858e31d2f07a08", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1777425547, + "narHash": "sha256-d57AbflkNfZNoFaZDzssEq1RfPoM9dLtOGI2O+N/68Q=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ebc08544afa77957cc348ba72dc490ec73b87f68", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "pit": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1778890311, + "narHash": "sha256-JZx/jh/E16SlAATrzQvB7kZcbBBfXX0zCqpwgw+Qlfc=", + "owner": "lcolonq", + "repo": "pit", + "rev": "48ab2cb8e3de88dbd0722337bd4617ad22de1a12", + "type": "github" + }, + "original": { + "owner": "lcolonq", + "repo": "pit", + "type": "github" + } + }, + "root": { + "inputs": { + "crane": "crane", + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "pit": "pit", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1766717007, + "narHash": "sha256-ZjLiHCHgoH2maP5ZAKn0anrHymbjGOS5/PZqfJUK8Ik=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "a18efe8a9112175e43397cf870fb6bc1ca480548", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/2026/games_submissions/rpc2dot0/vendor/teleia/flake.nix b/2026/games_submissions/rpc2dot0/vendor/teleia/flake.nix new file mode 100644 index 0000000..878d687 --- /dev/null +++ b/2026/games_submissions/rpc2dot0/vendor/teleia/flake.nix @@ -0,0 +1,250 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + crane.url = "github:ipetkov/crane"; + flake-utils.url = "github:numtide/flake-utils"; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs = { + nixpkgs.follows = "nixpkgs"; + }; + }; + pit = { + url = "github:lcolonq/pit"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = inputs@{ self, nixpkgs, ... }: + let + system = "x86_64-linux"; + pkgs = import nixpkgs { + inherit system; + overlays = [ (import inputs.rust-overlay) ]; + }; + inherit (pkgs) lib; + + rustToolchainFor = p: p.rust-bin.nightly.latest.default.override { + targets = [ + "wasm32-unknown-unknown" + "x86_64-unknown-linux-gnu" + "x86_64-pc-windows-gnu" + ]; + }; + craneLib = (inputs.crane.mkLib pkgs).overrideToolchain rustToolchainFor; + + glfw = pkgs.glfw.overrideAttrs (cur: prev: { + cmakeFlags = []; # by default, static linking is disabled here + # for some reason, the default glfw package hardcodes a nix store path to libGL + # see: https://github.com/NixOS/nixpkgs/pull/47175 + # this makes it impossible to run the binary on another system + # I'd much rather just load whatever we find on LD_LIBRARY_PATH etc, since this is much easier to control + env = {}; + postPatch = "true"; + }); + + LIBCOLONQ_PIT_NATIVE="${inputs.pit.packages.x86_64-linux.default}/lib"; + LIBCOLONQ_PIT_WASM="${inputs.pit.packages.x86_64-linux.wasm}/lib"; + LIBCOLONQ_PIT_WINDOWS="${inputs.pit.packages.x86_64-linux.windows}/lib"; + + native = rec { + nativeBuildInputs = [ + pkgs.pkg-config + ]; + buildInputs = [ + pkgs.openssl.dev + glfw + pkgs.libX11 + pkgs.libXcursor + pkgs.libXi + pkgs.libXrandr + pkgs.libXinerama + pkgs.libxkbcommon + pkgs.libxcb + pkgs.libglvnd + pkgs.alsa-lib + ]; + deps = path: nm: + let + src = lib.cleanSourceWith { + src = path; + filter = path: type: + (lib.hasSuffix "\.html" path) || + (lib.hasSuffix "\.js" path) || + (lib.hasSuffix "\.css" path) || + (lib.hasInfix "/assets/" path) || + (craneLib.filterCargoSources path type) + ; + }; + commonArgs = { + inherit src nativeBuildInputs buildInputs; + inherit LIBCOLONQ_PIT_NATIVE; + strictDeps = true; + CARGO_BUILD_TARGET = "x86_64-unknown-linux-gnu"; + CARGO_BUILD_RUSTFLAGS="-L ${glfw}/lib -L ${LIBCOLONQ_PIT_NATIVE}"; + inherit (craneLib.crateNameFromCargoToml { inherit src; }) version; + }; + cargoArtifacts = craneLib.buildDepsOnly (commonArgs // { + doCheck = false; + }); + in + cargoArtifacts; + build = path: nm: + let + src = lib.cleanSourceWith { + src = path; + filter = path: type: + (lib.hasSuffix "\.html" path) || + (lib.hasSuffix "\.js" path) || + (lib.hasSuffix "\.css" path) || + (lib.hasInfix "/assets/" path) || + (craneLib.filterCargoSources path type) + ; + }; + commonArgs = { + inherit src nativeBuildInputs buildInputs; + inherit LIBCOLONQ_PIT_NATIVE; + strictDeps = true; + CARGO_BUILD_TARGET = "x86_64-unknown-linux-gnu"; + CARGO_BUILD_RUSTFLAGS="-L ${glfw}/lib -L ${LIBCOLONQ_PIT_NATIVE}"; + inherit (craneLib.crateNameFromCargoToml { inherit src; }) version; + }; + cargoArtifacts = craneLib.buildDepsOnly (commonArgs // { + doCheck = false; + cargoExtraArgs = "-p ${nm}"; + }); + in + craneLib.buildPackage (commonArgs // { + inherit cargoArtifacts; + pname = nm; + cargoExtraArgs = "-p ${nm}"; + }); + }; + + wasm = rec { + buildAtUrlInDir = path: nm: url: dir: + let + src = lib.cleanSourceWith { + src = path; + filter = path: type: + (lib.hasSuffix "\.html" path) || + (lib.hasSuffix "\.js" path) || + (lib.hasSuffix "\.css" path) || + (lib.hasInfix "/assets/" path) || + (craneLib.filterCargoSources path type) + ; + }; + commonArgs = { + inherit src; + inherit LIBCOLONQ_PIT_WASM; + strictDeps = true; + CARGO_BUILD_TARGET = "wasm32-unknown-unknown"; + CARGO_BUILD_RUSTFLAGS="-L ${LIBCOLONQ_PIT_WASM}"; + buildInputs = []; + inherit (craneLib.crateNameFromCargoToml { inherit src; }) version; + wasm-bindgen-cli = pkgs.buildWasmBindgenCli rec { + src = pkgs.fetchCrate { + pname = "wasm-bindgen-cli"; + version = "0.2.100"; + hash = "sha256-3RJzK7mkYFrs7C/WkhW9Rr4LdP5ofb2FdYGz1P7Uxog="; + }; + cargoDeps = pkgs.rustPlatform.fetchCargoVendor { + inherit src; + inherit (src) pname version; + hash = "sha256-qsO12332HSjWCVKtf1cUePWWb9IdYUmT+8OPj/XP2WE="; + }; + }; + }; + in + craneLib.buildTrunkPackage (commonArgs // rec { + pname = nm; + cargoExtraArgs = "-p ${nm}"; + trunkExtraBuildArgs = "--public-url ${url}"; + cargoArtifacts = craneLib.buildDepsOnly (commonArgs // { + inherit cargoExtraArgs; + doCheck = false; + }); + preBuild = '' + pushd ${dir} + ''; + postBuild = '' + popd + mv ${dir}/dist . + ''; + }); + buildAtUrl = path: nm: url: buildAtUrlInDir path nm url "."; + build = path: nm: buildAtUrl path nm ""; + }; + + windows = rec { + glfw = pkgs.pkgsCross.mingwW64.glfw.overrideAttrs (cur: prev: { + cmakeFlags = []; + env = {}; + postPatch = "true"; + }); + rustflags = "-L ${glfw}/lib -L ${LIBCOLONQ_PIT_WINDOWS} -L ${pkgs.pkgsCross.mingwW64.windows.pthreads}/lib"; + shell = craneLib.devShell { + packages = [ + pkgs.pkgsCross.mingwW64.buildPackages.gcc + ]; + RUSTFLAGS = rustflags; + }; + build = path: nm: + let + src = lib.cleanSourceWith { + src = path; + filter = path: type: + (lib.hasSuffix "\.html" path) || + (lib.hasSuffix "\.js" path) || + (lib.hasSuffix "\.css" path) || + (lib.hasInfix "/assets/" path) || + (craneLib.filterCargoSources path type) + ; + }; + commonArgs = { + inherit src; + strictDeps = true; + CARGO_BUILD_TARGET = "x86_64-pc-windows-gnu"; + CARGO_BUILD_RUSTFLAGS = rustflags; + CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER = "${pkgs.pkgsCross.mingwW64.stdenv.cc}/bin/${pkgs.pkgsCross.mingwW64.stdenv.cc.targetPrefix}cc"; + depsBuildBuild = with pkgs; [ + pkgsCross.mingwW64.buildPackages.gcc + ]; + inherit (craneLib.crateNameFromCargoToml { inherit src; }) version; + }; + cargoArtifacts = craneLib.buildDepsOnly (commonArgs // { + doCheck = false; + }); + in + craneLib.buildPackage (commonArgs // { + inherit cargoArtifacts; + pname = nm; + cargoExtraArgs = "-p ${nm}"; + doCheck = false; + }); + }; + + shell = craneLib.devShell { + packages = [ + pkgs.trunk + pkgs.rust-analyzer + pkgs.cargo-flamegraph + pkgs.cmake + pkgs.mold + ] ++ native.nativeBuildInputs ++ native.buildInputs; + LIBRARY_PATH = "$LIBRARY_PATH:${pkgs.lib.makeLibraryPath native.buildInputs}"; + RUSTFLAGS="-L ${glfw}/lib"; + LD_LIBRARY_PATH = "$LD_LIBRARY_PATH:${pkgs.lib.makeLibraryPath native.buildInputs}"; + inherit LIBCOLONQ_PIT_NATIVE LIBCOLONQ_PIT_WASM; + }; + in { + inherit shell native wasm windows; + devShells.${system} = { + default = shell; + windows = windows.shell; + }; + packages.${system} = { + default = native.deps ./. "teleia"; + }; + }; +} -- cgit v1.3.1