diff options
| -rw-r--r-- | .gitignore | 3 | ||||
| -rw-r--r-- | Cargo.lock | 1908 | ||||
| -rw-r--r-- | Cargo.toml | 52 | ||||
| -rw-r--r-- | helpers.js | 13 | ||||
| -rw-r--r-- | index.css | 54 | ||||
| -rw-r--r-- | index.html | 20 | ||||
| -rw-r--r-- | src/assets/fonts/font1.png | bin | 0 -> 1508 bytes | |||
| -rw-r--r-- | src/assets/fonts/font2.png | bin | 0 -> 1883 bytes | |||
| -rw-r--r-- | src/assets/fonts/simple.png | bin | 0 -> 1042 bytes | |||
| -rw-r--r-- | src/assets/shaders/common/frag.glsl | 158 | ||||
| -rw-r--r-- | src/assets/shaders/common/vert.glsl | 30 | ||||
| -rw-r--r-- | src/assets/shaders/scale/frag.glsl | 13 | ||||
| -rw-r--r-- | src/assets/shaders/scale/vert.glsl | 22 | ||||
| -rw-r--r-- | src/assets/shaders/test/frag.glsl | 23 | ||||
| -rw-r--r-- | src/assets/shaders/test/vert.glsl | 4 | ||||
| -rw-r--r-- | src/assets/shaders/text/frag.glsl | 55 | ||||
| -rw-r--r-- | src/assets/shaders/text/vert.glsl | 26 | ||||
| -rw-r--r-- | src/audio.rs | 96 | ||||
| -rw-r--r-- | src/context.rs | 156 | ||||
| -rw-r--r-- | src/font.rs | 82 | ||||
| -rw-r--r-- | src/framebuffer.rs | 100 | ||||
| -rw-r--r-- | src/lib.rs | 94 | ||||
| -rw-r--r-- | src/mesh.rs | 118 | ||||
| -rw-r--r-- | src/request.rs | 20 | ||||
| -rw-r--r-- | src/shader.rs | 171 | ||||
| -rw-r--r-- | src/state.rs | 262 | ||||
| -rw-r--r-- | src/texture.rs | 51 | ||||
| -rw-r--r-- | src/utils.rs | 58 |
28 files changed, 3589 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0c257a3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +/.cargo +/dist
\ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..3ba0917 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1908 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[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 = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[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 = "android-activity" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" +dependencies = [ + "android-properties", + "bitflags 2.4.2", + "cc", + "cesu8", + "jni", + "jni-sys", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[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 = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[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", +] + +[[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 = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "calloop" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" +dependencies = [ + "bitflags 2.4.2", + "log", + "polling", + "rustix", + "slab", + "thiserror", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" +dependencies = [ + "calloop", + "rustix", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "cc" +version = "1.0.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" +dependencies = [ + "libc", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[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 = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[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", + "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 = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + +[[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-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "cursor-icon" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" + +[[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 = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "exr" +version = "1.72.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[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.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[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 = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "glam" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3" + +[[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 = "half" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "icrate" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" +dependencies = [ + "block2", + "dispatch", + "objc2", +] + +[[package]] +name = "image" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "jpeg-decoder", + "num-traits", + "png", + "qoi", + "tiff", +] + +[[package]] +name = "indexmap" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[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", + "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 = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" +dependencies = [ + "rayon", +] + +[[package]] +name = "js-sys" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[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.4", +] + +[[package]] +name = "libredox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" +dependencies = [ + "bitflags 2.4.2", + "libc", + "redox_syscall 0.4.1", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[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 = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "ndk" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +dependencies = [ + "bitflags 2.4.2", + "jni-sys", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror", +] + +[[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 = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[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 = "objc-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c71324e4180d0899963fc83d9d241ac39e699609fc1025a850aadac8257459" + +[[package]] +name = "objc2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "orbclient" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166" +dependencies = [ + "libredox", +] + +[[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 = "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.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9" +dependencies = [ + "cfg-if", + "concurrent-queue", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.52.0", +] + +[[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.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[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.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +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 = "raw-window-handle" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544" + +[[package]] +name = "rayon" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[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 = "rustix" +version = "0.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[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 = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[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 = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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 = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[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.4.2", + "calloop", + "calloop-wayland-source", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix", + "thiserror", + "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 = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + +[[package]] +name = "syn" +version = "2.0.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "teleia" +version = "0.1.0" +dependencies = [ + "console_error_panic_hook", + "console_log", + "getrandom", + "glam", + "glow", + "image", + "js-sys", + "log", + "rand", + "serde", + "tobj", + "tracing-wasm", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winit", +] + +[[package]] +name = "thiserror" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +dependencies = [ + "thiserror-impl", +] + +[[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 = "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 = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[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 = "ttf-parser" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" + +[[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 = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[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.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "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.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" + +[[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", + "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.4.2", + "rustix", + "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.4.2", + "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", + "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.4.2", + "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.4.2", + "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.4.2", + "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 = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + +[[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-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.4", +] + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "winit" +version = "0.29.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b9d7047a2a569d5a81e3be098dcd8153759909b127477f4397e03cf1006d90a" +dependencies = [ + "ahash", + "android-activity", + "atomic-waker", + "bitflags 2.4.2", + "bytemuck", + "calloop", + "cfg_aliases", + "core-foundation", + "core-graphics", + "cursor-icon", + "icrate", + "js-sys", + "libc", + "log", + "memmap2", + "ndk", + "ndk-sys", + "objc2", + "once_cell", + "orbclient", + "percent-encoding", + "raw-window-handle", + "redox_syscall 0.3.5", + "rustix", + "sctk-adwaita", + "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", + "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.4.2", + "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-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b74c31d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,52 @@ +[package] +name = "teleia" +version = "0.1.0" +authors = ["LLLL Colonq <llll@colonq.computer>"] +edition = "2021" + +[profile.release] +opt-level = 2 +codegen-units = 1 + +[profile.dev.package."*"] +opt-level = 2 + +[dependencies] +winit = "*" # windowing and events +glow = {version = "*", features = []} # rendering +tobj = "*" # model loader +# gltf = {version = "*", features = ["extras", "names"]} # model loader +image = "*" # texture loader +glam = "*" # linear algebra +log = "*" # logging +rand = {version = "*", features = ["small_rng"]} # rng +getrandom = {version = "*", features = ["js"]} # rng in the browser +serde = {version = "*", features = ["derive"]} # serialization +console_log = "*" # log to browser console +console_error_panic_hook = "*" # log to browser console on panic +tracing-wasm = "*" # trace performance in browser +wasm-bindgen = "*" # interface with javascript +wasm-bindgen-futures = "*" # interface with async javascript +js-sys = "*" + +[dependencies.web-sys] # common browser APIs +version = "*" +features = [ + "Document", + "Window", + "Element", + "HtmlCanvasElement", + "WebGl2RenderingContext", + "Headers", + "Request", + "RequestInit", + "RequestMode", + "Response", + "Performance", + "PerformanceTiming", + "AudioContext", + "AudioNode", + "AudioDestinationNode", + "AudioBuffer", + "AudioBufferSourceNode", +]
\ No newline at end of file diff --git a/helpers.js b/helpers.js new file mode 100644 index 0000000..20b86f4 --- /dev/null +++ b/helpers.js @@ -0,0 +1,13 @@ +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; +} diff --git a/index.css b/index.css new file mode 100644 index 0000000..c5219bc --- /dev/null +++ b/index.css @@ -0,0 +1,54 @@ +html { + /* Remove touch delay: */ + touch-action: manipulation; +} + +body { + /* Light mode background color for what is not covered by the egui canvas, + or where the egui canvas is translucent. */ + background: #909090; +} + +@media (prefers-color-scheme: dark) { + body { + /* Dark mode background color for what is not covered by the egui canvas, + or where the egui canvas is translucent. */ + background: #404040; + } +} + +/* Allow canvas to fill entire web page: */ +html, +body { + overflow: hidden; + margin: 0 !important; + padding: 0 !important; + height: 100%; + width: 100%; +} + +/* Position canvas in center-top: */ +canvas { + margin-right: auto; + margin-left: auto; + display: block; + position: absolute; + top: 0%; + left: 50%; + transform: translate(-50%, 0%); +} + +.centered { + margin-right: auto; + margin-left: auto; + display: block; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: #f0f0f0; + font-size: 24px; + font-family: Ubuntu-Light, Helvetica, sans-serif; + text-align: center; + image-transform: pixelated; +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..41126dc --- /dev/null +++ b/index.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> + <head> + <meta charset="UTF-8"> + <link data-trunk rel="copy-file" href="helpers.js" /> + <script type="module" src="helpers.js"></script> + <link data-trunk rel="rust" data-wasm-opt="2" /> + <base data-trunk-public-url /> + <meta name="theme-color" media="(prefers-color-scheme: light)" content="white"> + <meta name="theme-color" media="(prefers-color-scheme: dark)" content="#404040"> + <link rel="icon" href="data:;base64,iVBORw0KGgo="> + <link data-trunk rel="css" href="index.css" /> + <title>OUBLIETTE OF GENERAL</title> + </head> + <body> + <div id="oubliette-parent"></canvas> + </body> +</html> diff --git a/src/assets/fonts/font1.png b/src/assets/fonts/font1.png Binary files differnew file mode 100644 index 0000000..ec06424 --- /dev/null +++ b/src/assets/fonts/font1.png diff --git a/src/assets/fonts/font2.png b/src/assets/fonts/font2.png Binary files differnew file mode 100644 index 0000000..8435cad --- /dev/null +++ b/src/assets/fonts/font2.png diff --git a/src/assets/fonts/simple.png b/src/assets/fonts/simple.png Binary files differnew file mode 100644 index 0000000..7b1d2a3 --- /dev/null +++ b/src/assets/fonts/simple.png diff --git a/src/assets/shaders/common/frag.glsl b/src/assets/shaders/common/frag.glsl new file mode 100644 index 0000000..908e06c --- /dev/null +++ b/src/assets/shaders/common/frag.glsl @@ -0,0 +1,158 @@ +#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; +} + +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; + } + + // cannot 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); +} diff --git a/src/assets/shaders/common/vert.glsl b/src/assets/shaders/common/vert.glsl new file mode 100644 index 0000000..b8e11c5 --- /dev/null +++ b/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/src/assets/shaders/scale/frag.glsl b/src/assets/shaders/scale/frag.glsl new file mode 100644 index 0000000..2cd3c60 --- /dev/null +++ b/src/assets/shaders/scale/frag.glsl @@ -0,0 +1,13 @@ +#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; +}
\ No newline at end of file diff --git a/src/assets/shaders/scale/vert.glsl b/src/assets/shaders/scale/vert.glsl new file mode 100644 index 0000000..e05bbb6 --- /dev/null +++ b/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/src/assets/shaders/test/frag.glsl b/src/assets/shaders/test/frag.glsl new file mode 100644 index 0000000..a52aa15 --- /dev/null +++ b/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/src/assets/shaders/test/vert.glsl b/src/assets/shaders/test/vert.glsl new file mode 100644 index 0000000..e324f7e --- /dev/null +++ b/src/assets/shaders/test/vert.glsl @@ -0,0 +1,4 @@ +void main() +{ + default_main(); +}
\ No newline at end of file diff --git a/src/assets/shaders/text/frag.glsl b/src/assets/shaders/text/frag.glsl new file mode 100644 index 0000000..3a1694f --- /dev/null +++ b/src/assets/shaders/text/frag.glsl @@ -0,0 +1,55 @@ +#version 300 es +precision highp float; + +uniform sampler2D texture_data; +uniform int text_length; +uniform int text[256]; +uniform int char_width; +uniform int char_height; +uniform int font_width; +uniform int font_height; +uniform int text_width; +uniform int text_height; + +in vec2 vertex_texcoord; +out vec4 frag_color; + +void main() +{ + vec2 inverted_texcoord = vec2(vertex_texcoord.x, 1.0 - vertex_texcoord.y); + vec2 texcoord_pixels = inverted_texcoord * vec2(float(text_width), float(text_height)); + int texcoord_char_x = int(floor(texcoord_pixels.x)) / char_width; + int texcoord_char_y = int(floor(texcoord_pixels.y)) / char_height; + + int x = 0; + int y = 0; + int i = 0; + for (; i < text_length; ++i) { + if (x == texcoord_char_x && y == texcoord_char_y) { + break; + } + if (text[i] == 10) { + x = 0; + y += 1; + } else { + x += 1; + } + } + if (i == text_length || text[i] == 10) discard; + + int entry = text[i] - 32; + vec2 texcoord_base = vec2( + float(entry % (font_width / char_width)) * float(char_width), + float(entry / (font_width / char_width)) * float(char_height) + ); + // vec2 texcoord_base = vec2(8.0, 0.0); + vec2 texcoord_off = vec2( + mod(texcoord_pixels.x, float(char_width)), + mod(texcoord_pixels.y, float(char_height)) + ); + vec2 texcoord_final = (texcoord_base + texcoord_off) / vec2(float(font_width), float(font_height)); + + vec4 texel = texture(texture_data, texcoord_final); + if (texel.rgb == vec3(0.0, 0.0, 0.0)) discard; + frag_color = texel; +}
\ No newline at end of file diff --git a/src/assets/shaders/text/vert.glsl b/src/assets/shaders/text/vert.glsl new file mode 100644 index 0000000..4005d75 --- /dev/null +++ b/src/assets/shaders/text/vert.glsl @@ -0,0 +1,26 @@ +#version 300 es +precision highp float; + +uniform mat4 view; +uniform mat4 position; + +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) + ); + vec4 vertex = vec4(positions[gl_VertexID], 0.0, 1.0); + + vertex_texcoord = coords[gl_VertexID]; + gl_Position = view * position * vertex; +} diff --git a/src/audio.rs b/src/audio.rs new file mode 100644 index 0000000..2b190de --- /dev/null +++ b/src/audio.rs @@ -0,0 +1,96 @@ +use std::{cell::RefCell, collections::HashMap}; + +pub struct Context { + pub audio: web_sys::AudioContext, +} + +impl Context { + pub fn new() -> Self { + let audio = web_sys::AudioContext::new() + .expect("failed to create audio context"); + Self { + audio, + } + } +} + +pub struct Audio { + pub buffer: &'static RefCell<Option<web_sys::AudioBuffer>>, + //pub source: &'static web_sys::AudioBufferSourceNode, +} + +impl Audio { + pub fn new(ctx: &Context, bytes: &[u8]) -> Self { + let sbuffer: &_ = Box::leak(Box::new(RefCell::new(None))); + let sclone: &'static RefCell<Option<web_sys::AudioBuffer>> = + <&_>::clone(&sbuffer); + 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 { + if let Some(data) = promise.await.ok() { + *sbuffer.borrow_mut() = Some(web_sys::AudioBuffer::from(data)); + } + () + }); + ret + } + + pub fn play(&self, ctx: &Context, looping: Option<(Option<f64>, Option<f64>)>) -> Option<web_sys::AudioBufferSourceNode> { + let source = ctx.audio.create_buffer_source().ok()?; + source.set_buffer((&*self.buffer.borrow()).as_ref()); + 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) } + } + source.connect_with_audio_node(&ctx.audio.destination()).ok()?; + source.start().ok()?; + Some(source) + } +} + +pub struct Assets { + pub ctx: Context, + + pub audio: HashMap<String, Audio>, + + pub music_node: Option<web_sys::AudioBufferSourceNode>, +} + +impl Assets { + pub fn new<F>(f : F) -> Self where F: Fn(&Context) -> HashMap<String, Audio> { + 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(&self.ctx, None); + } + } + + pub fn is_music_playing(&self) -> bool { + if let Some(ms) = &self.music_node { + ms.buffer().is_some() + } else { false } + } + + pub fn play_music(&mut self, name: &str, start: Option<f64>, end: Option<f64>) { + if let Some(s) = &self.music_node { + let _ = s.stop(); + } + if let Some(a) = self.audio.get(name) { + self.music_node = a.play(&self.ctx, Some((start, end))); + } + } +} diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..5328d4d --- /dev/null +++ b/src/context.rs @@ -0,0 +1,156 @@ +use wasm_bindgen::JsCast; +use winit::platform::web::WindowExtWebSys; +use glow::HasContext; + +#[link(wasm_import_module = "./helpers.js")] +extern { + fn js_track_resized_setup(); + fn js_poll_resized() -> bool; +} + +// pub const RENDER_WIDTH: f32 = 640.0; +// pub const RENDER_HEIGHT: f32 = 360.0; +// pub const RENDER_WIDTH: f32 = 320.0; +// pub const RENDER_HEIGHT: f32 = 180.0; +pub const RENDER_WIDTH: f32 = 240.0; +pub const RENDER_HEIGHT: f32 = 160.0; + +pub fn compute_upscale(windoww: u32, windowh: u32) -> u32 { + let mut ratio = 1; + loop { + if (RENDER_WIDTH as u32) * ratio > windoww + || (RENDER_HEIGHT as u32) * ratio > windowh + { + break; + } + ratio += 1; + } + (ratio - 1).max(1) +} + +pub struct Context { + pub window: winit::window::Window, + pub gl: glow::Context, + pub emptyvao: glow::VertexArray, + pub performance: web_sys::Performance, +} + +impl Context { + pub fn new(window: winit::window::Window) -> Self { + let gl = web_sys::window() + .and_then(|win| win.document()) + .and_then(|doc| { + let dst = doc.get_element_by_id("oubliette-parent")?; + let canvas = web_sys::Element::from(window.canvas().expect("failed to find canvas")); + dst.append_child(&canvas).ok()?; + let c = canvas.dyn_into::<web_sys::HtmlCanvasElement>().ok()?; + let webgl2_context = c.get_context("webgl2").ok()?? + .dyn_into::<web_sys::WebGl2RenderingContext>().ok()?; + Some(glow::Context::from_webgl2_context(webgl2_context)) + }) + .expect("couldn't add canvas to document"); + unsafe { + gl.clear_color(0.1, 0.1, 0.1, 1.0); + gl.clear_depth_f32(1.0); + + gl.enable(glow::DEPTH_TEST); + gl.depth_func(glow::LEQUAL); + + gl.enable(glow::BLEND); + gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA); + + gl.enable(glow::STENCIL_TEST); + + gl.cull_face(glow::FRONT); + } + + let emptyvao = unsafe { + gl.create_vertex_array().expect("failed to initialize vao") + }; + + unsafe { js_track_resized_setup(); } + + + Self { + window, + gl, + emptyvao, + performance: web_sys::window().expect("failed to find window") + .performance().expect("failed to get performance"), + } + } + + pub fn maximize_canvas(&self) { + 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::LogicalSize::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"); + } + + pub fn resize_necessary(&self) -> bool { + unsafe { + js_poll_resized() + } + } + + 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 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 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); + } + } +} diff --git a/src/font.rs b/src/font.rs new file mode 100644 index 0000000..02d0a9f --- /dev/null +++ b/src/font.rs @@ -0,0 +1,82 @@ +use crate::{context, texture, shader}; + +const CHAR_WIDTH: i32 = 7; +const CHAR_HEIGHT: i32 = 9; +const FONT_WIDTH: i32 = 112; +const FONT_HEIGHT: i32 = 54; + +pub struct Font { + pub shader: shader::Shader, + pub font: texture::Texture, +} + +impl Font { + pub fn new(ctx: &context::Context) -> Self { + let shader = shader::Shader::new_nolib( + &ctx, + include_str!("assets/shaders/text/vert.glsl"), + include_str!("assets/shaders/text/frag.glsl"), + ); + let font = texture::Texture::new(ctx, include_bytes!("assets/fonts/simple.png")); + Self { + shader, + font, + } + } + + pub fn render_text(&self, ctx: &context::Context, pos: &glam::Vec2, text: &str) { + let mut width = 0; + let mut linewidth = 0; + let mut height = CHAR_HEIGHT; + for c in text.chars() { + if c == '\n' { + width = width.max(linewidth); + linewidth = 0; + height += CHAR_HEIGHT; + } else { + linewidth += CHAR_WIDTH; + } + } + width = width.max(linewidth); + + self.shader.bind(ctx); + let len = text.len().min(256); + self.shader.set_i32(ctx, "text_length", len as _); + let textvals: Vec<i32> = text.as_bytes().into_iter().take(len).map(|b| { + *b as i32 + }).collect(); + self.shader.set_i32_array(ctx, "text[0]", &textvals); + self.shader.set_i32(ctx, "char_width", CHAR_WIDTH as _); + self.shader.set_i32(ctx, "char_height", CHAR_HEIGHT as _); + self.shader.set_i32(ctx, "font_width", FONT_WIDTH as _); + self.shader.set_i32(ctx, "font_height", FONT_HEIGHT as _); + self.shader.set_i32(ctx, "text_width", width as _); + self.shader.set_i32(ctx, "text_height", height as _); + self.shader.set_mat4( + ctx, "view", + &glam::Mat4::from_scale( + glam::Vec3::new( + 2.0 / context::RENDER_WIDTH, + 2.0 / context::RENDER_HEIGHT, + 1.0, + ), + ), + ); + let halfwidth = width as f32 / 2.0; + let halfheight = height as f32 / 2.0; + self.shader.set_mat4( + ctx, "position", + &glam::Mat4::from_scale_rotation_translation( + glam::Vec3::new(halfwidth, halfheight, 1.0), + glam::Quat::IDENTITY, + glam::Vec3::new( + -context::RENDER_WIDTH / 2.0 + pos.x + halfwidth, + context::RENDER_HEIGHT / 2.0 - pos.y - halfheight, + 0.0, + ), + ) + ); + self.font.bind(ctx); + ctx.render_no_geometry(); + } +} diff --git a/src/framebuffer.rs b/src/framebuffer.rs new file mode 100644 index 0000000..c0ac72b --- /dev/null +++ b/src/framebuffer.rs @@ -0,0 +1,100 @@ +use glow::HasContext; + +use crate::context; + +pub struct Framebuffer { + pub tex: Option<glow::Texture>, + pub fbo: Option<glow::Framebuffer>, + pub dims: glam::Vec2, + pub offsets: glam::Vec2, +} + +impl Framebuffer { + pub fn screen(ctx: &context::Context) -> Self { + let (windoww, windowh): (f32, f32) = ctx.window.inner_size().into(); + let ratio = context::compute_upscale(windoww as _, windowh as _) as f32; + let upscalew = context::RENDER_WIDTH * ratio; + let upscaleh = context::RENDER_HEIGHT * ratio; + let offsetx = (windoww - upscalew) / 2.0; + let offsety = (windowh - upscaleh) / 2.0; + log::info!("{} {} {} {} {} {}", 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.clone(), + offsets: offsets.clone(), + } + } + } + + 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 _, + ); + } + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..df778a6 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,94 @@ +use winit::platform::web::EventLoopExtWebSys; + +pub mod utils; +pub mod request; +pub mod context; +pub mod state; +pub mod framebuffer; +pub mod shader; +pub mod mesh; +pub mod texture; +pub mod font; +pub mod audio; + +pub fn run<F, G>(gnew: F) where G: state::Game + 'static, F: (Fn(&context::Context) -> G) { + console_log::init_with_level(log::Level::Debug).unwrap(); + console_error_panic_hook::set_once(); + tracing_wasm::set_as_global_default(); + log::info!("HELLO COMPUTER HELLO CLONKHEAD :)"); + + let event_loop = winit::event_loop::EventLoop::new() + .expect("failed to initialize event loop"); + + let window = winit::window::WindowBuilder::new() + .with_maximized(true) + .with_decorations(false) + .build(&event_loop) + .expect("failed to initialize window"); + + let ctx = context::Context::new(window); + ctx.maximize_canvas(); + let mut game = gnew(&ctx); + let mut st = state::State::new(&ctx); + st.write_log("test"); + st.write_log("foo"); + st.write_log("bar"); + st.write_log("baz"); + + event_loop.set_control_flow(winit::event_loop::ControlFlow::Poll); + event_loop.spawn(move |event, elwt| { + 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{..} => { + ctx.maximize_canvas(); + st.handle_resize(&ctx); + }, + winit::event::WindowEvent::MouseInput { + button, + state, + .. + } => match state { + winit::event::ElementState::Pressed => { + st.mouse_pressed(&ctx, button, &mut game) + }, + winit::event::ElementState::Released => { + st.mouse_released(&ctx, button) + }, + } + winit::event::WindowEvent::KeyboardInput { + event: winit::event::KeyEvent { + physical_key: winit::keyboard::PhysicalKey::Code(key), + state, + .. + }, + .. + } => match state { + winit::event::ElementState::Pressed => { + st.key_pressed(&ctx, key) + }, + winit::event::ElementState::Released => { + st.key_released(&ctx, key) + }, + } + _ => {}, + }, + + winit::event::Event::AboutToWait => { + if ctx.resize_necessary() { + ctx.maximize_canvas(); + st.handle_resize(&ctx); + } + st.run_update(&ctx, &mut game); + st.run_render(&ctx, &mut game); + }, + + _ => {}, + } + }); +} diff --git a/src/mesh.rs b/src/mesh.rs new file mode 100644 index 0000000..2f54903 --- /dev/null +++ b/src/mesh.rs @@ -0,0 +1,118 @@ +use std::io::BufRead; + +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 struct Mesh { + pub vao: glow::VertexArray, + pub index_count: usize, +} + +impl Mesh { + pub fn build( + ctx: &context::Context, + vertices: &Vec<f32>, + indices: &Vec<u32>, + snormals: &Option<Vec<f32>>, + stexcoords: &Option<Vec<f32>>, + ) -> Self { + unsafe { + let vao = ctx.gl.create_vertex_array().expect("failed to initialize vao"); + ctx.gl.bind_vertex_array(Some(vao)); + + let vertices_vbo = ctx.gl.create_buffer().expect("failed to initialize vbo"); + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(vertices_vbo)); + ctx.gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + std::slice::from_raw_parts( + vertices.as_ptr() as _, + vertices.len() * std::mem::size_of::<f32>(), + ), + glow::STATIC_DRAW, + ); + ctx.gl.vertex_attrib_pointer_f32(ATTRIB_VERTEX, 3, glow::FLOAT, false, 0, 0); + ctx.gl.enable_vertex_attrib_array(ATTRIB_VERTEX); + + let indices_vbo = ctx.gl.create_buffer().expect("failed to initialize vbo"); + ctx.gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(indices_vbo)); + ctx.gl.buffer_data_u8_slice( + glow::ELEMENT_ARRAY_BUFFER, + std::slice::from_raw_parts( + indices.as_ptr() as _, + indices.len() * std::mem::size_of::<f32>(), + ), + glow::STATIC_DRAW, + ); + + if let Some(normals) = snormals { + let normals_vbo = ctx.gl.create_buffer().expect("failed to initialize vbo"); + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(normals_vbo)); + ctx.gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + std::slice::from_raw_parts( + normals.as_ptr() as _, + normals.len() * std::mem::size_of::<f32>(), + ), + glow::STATIC_DRAW, + ); + ctx.gl.vertex_attrib_pointer_f32(ATTRIB_NORMAL, 3, glow::FLOAT, false, 0, 0); + ctx.gl.enable_vertex_attrib_array(ATTRIB_NORMAL); + } + + if let Some(texcoords) = stexcoords { + let texcoords_vbo = ctx.gl.create_buffer().expect("failed to initialize vbo"); + ctx.gl.bind_buffer(glow::ARRAY_BUFFER, Some(texcoords_vbo)); + ctx.gl.buffer_data_u8_slice( + glow::ARRAY_BUFFER, + std::slice::from_raw_parts( + texcoords.as_ptr() as _, + texcoords.len() * std::mem::size_of::<f32>(), + ), + glow::STATIC_DRAW, + ); + ctx.gl.vertex_attrib_pointer_f32(ATTRIB_TEXCOORD, 2, glow::FLOAT, false, 0, 0); + ctx.gl.enable_vertex_attrib_array(ATTRIB_TEXCOORD); + } + + Self { + vao, + index_count: indices.len(), + } + } + } + + pub fn new(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(glow::TRIANGLES, self.index_count as _, glow::UNSIGNED_INT, 0); + } + } +} diff --git a/src/request.rs b/src/request.rs new file mode 100644 index 0000000..7f66f57 --- /dev/null +++ b/src/request.rs @@ -0,0 +1,20 @@ +use wasm_bindgen::JsCast; + +pub async fn get_store(key: &str) -> Option<String> { + let mut opts = web_sys::RequestInit::new(); + opts.method("GET"); + opts.mode(web_sys::RequestMode::Cors); + + let url = format!("https://colonq.computer/bullfrog/api/get/{}", key); + + let request = web_sys::Request::new_with_str_and_init(&url, &opts).ok()?; + + let window = web_sys::window().unwrap(); + let resp_value = wasm_bindgen_futures::JsFuture::from(window.fetch_with_request(&request)).await.ok()?; + + assert!(resp_value.is_instance_of::<web_sys::Response>()); + let resp: web_sys::Response = resp_value.dyn_into().unwrap(); + + let text = wasm_bindgen_futures::JsFuture::from(resp.text().ok()?).await.ok()?; + text.as_string() +} diff --git a/src/shader.rs b/src/shader.rs new file mode 100644 index 0000000..6bcae3c --- /dev/null +++ b/src/shader.rs @@ -0,0 +1,171 @@ +use std::collections::HashMap; + +use glow::HasContext; + +use crate::{context, mesh}; + +const COMMON_VERT: &'static str = include_str!("assets/shaders/common/vert.glsl"); +const COMMON_FRAG: &'static str = include_str!("assets/shaders/common/frag.glsl"); + +#[derive(Clone)] +pub struct Shader { + pub program: glow::Program, + pub uniforms: std::rc::Rc<HashMap<String, glow::UniformLocation>> +} + +impl Shader { + pub fn new_nolib(ctx: &context::Context, vsrc: &str, fsrc: &str) -> Self { + unsafe { + let program = ctx.gl.create_program() + .expect("cannot create shader program"); + + let vert = ctx.gl.create_shader(glow::VERTEX_SHADER) + .expect("cannot create shader"); + ctx.gl.shader_source(vert, &vsrc); + ctx.gl.compile_shader(vert); + if !ctx.gl.get_shader_compile_status(vert) { + panic!( + "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) + .expect("cannot create shader"); + ctx.gl.shader_source(frag, &fsrc); + ctx.gl.compile_shader(frag); + if !ctx.gl.get_shader_compile_status(frag) { + panic!( + "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.link_program(program); + if !ctx.gl.get_program_link_status(program) { + panic!( + "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); + + 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) { + let loc = ctx.gl.get_uniform_location(program, &active.name) + .expect(&format!("failed to get location for uniform: {}", active.name)); + uniforms.insert(active.name, loc); + } + } + + Self { + program, + uniforms: std::rc::Rc::new(uniforms), + } + } + } + + 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 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_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_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_position_3d(&self, ctx: &context::Context, position: &glam::Mat4) { + self.set_mat4(&ctx, "position", &position); + self.set_mat4(&ctx, "normal_matrix", &position.inverse().transpose()); + } + + pub fn set_position_2d(&self, ctx: &context::Context, pos: &glam::Vec2, dims: &glam::Vec2) { + 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), + glam::Quat::IDENTITY, + glam::Vec3::new( + -context::RENDER_WIDTH / 2.0 + pos.x + halfwidth, + context::RENDER_HEIGHT / 2.0 - pos.y - halfheight, + 0.0, + ), + ) + ); + } + + pub fn bind(&self, ctx: &context::Context) { + unsafe { + ctx.gl.use_program(Some(self.program)); + } + } +} diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..bb479c6 --- /dev/null +++ b/src/state.rs @@ -0,0 +1,262 @@ +use std::collections::HashMap; + +use crate::{context, framebuffer, shader, audio}; + +const DELTA_TIME: f64 = 1.0 / 60.0; + +pub trait Game { + fn initialize_audio(&self, ctx: &context::Context, st: &State, actx: &audio::Context) -> + HashMap<String, audio::Audio>; + fn finish_title(&mut self); + fn update(&mut self, ctx: &context::Context, st: &mut State) -> Option<()>; + fn render(&mut self, ctx: &context::Context, st: &mut State) -> Option<()>; +} + +pub struct Keys { + pub up: bool, + pub down: bool, + pub left: bool, + pub right: bool, + pub a: bool, + pub b: bool, + pub l: bool, + pub r: bool, + pub start: bool, + pub select: bool, +} + +impl Keys { + pub fn new() -> Self { + Self { + up: false, + down: false, + left: false, + right: false, + a: false, + b: false, + l: false, + r: false, + start: false, + select: false, + } + } +} + +pub struct State { + pub acc: f64, + pub last: f64, + pub tick: u64, + + pub keys: Keys, + + pub screen: framebuffer::Framebuffer, + pub render_framebuffer: framebuffer::Framebuffer, + pub shader_upscale: shader::Shader, + pub audio: Option<audio::Assets>, + + pub projection: glam::Mat4, + pub camera: glam::Mat4, + pub lighting: (glam::Vec3, glam::Vec3), + + pub log: Vec<(u64, String)>, +} + +pub fn now(ctx: &context::Context) -> f64 { + ctx.performance.now() / 1000.0 +} + +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(context::RENDER_WIDTH, context::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"), + ); + + Self { + acc: 0.0, + last: now(ctx), + tick: 0, + keys: Keys::new(), + screen, + render_framebuffer, + shader_upscale, + audio: None, + + projection: glam::Mat4::perspective_lh( + std::f32::consts::PI / 4.0, + context::RENDER_WIDTH / context::RENDER_HEIGHT, + 0.1, + 400.0, + ), + camera: glam::Mat4::IDENTITY, + lighting: ( + glam::Vec3::new(1.0, 0.0, 0.0), + glam::Vec3::new(1.0, -1.0, 1.0), + ), + + log: Vec::new(), + } + } + + pub fn write_log(&mut self, e: &str) { + self.log.push((self.tick, e.to_owned())); + } + + pub fn handle_resize(&mut self, ctx: &context::Context) { + self.screen = framebuffer::Framebuffer::screen(ctx); + } + + pub fn move_camera( + &mut self, + _ctx: &context::Context, + camera: &glam::Mat4, + ) { + self.camera = camera.clone(); + } + + pub fn set_lighting( + &mut self, + _ctx: &context::Context, + color: &glam::Vec3, + dir: &glam::Vec3, + ) { + self.lighting = (color.clone(), dir.clone()); + } + + pub fn view(&self) -> glam::Mat4 { + self.camera.clone() + } + + pub fn bind_3d(&mut self, ctx: &context::Context, shader: &shader::Shader) { + shader.bind(ctx); + shader.set_mat4(&ctx, "projection", &self.projection); + shader.set_mat4(ctx, "view", &self.view()); + shader.set_vec3( + ctx, "light_ambient_color", + &glam::Vec3::new(1.0, 1.0, 1.0)); + shader.set_vec3( + ctx, "light_dir_color", + &self.lighting.0, + ); + shader.set_vec3( + ctx, "light_dir", + &self.lighting.1, + ); + } + + pub fn bind_2d(&mut 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 / context::RENDER_WIDTH, + 2.0 / context::RENDER_HEIGHT, + 1.0, + ), + ), + ); + } + + pub fn mouse_pressed<G>( + &mut self, + ctx: &context::Context, + _button: winit::event::MouseButton, + game: &mut G + ) where G: Game { + log::info!("click"); + if self.audio.is_none() { + self.audio = Some(audio::Assets::new(|actx| { + game.initialize_audio(ctx, &self, actx) + })); + game.finish_title(); + } + } + + pub fn mouse_released( + &mut self, + _ctx: &context::Context, + _button: winit::event::MouseButton, + ) { + } + + pub fn key_pressed( + &mut self, + _ctx: &context::Context, + key: winit::keyboard::KeyCode, + ) { + match key { + winit::keyboard::KeyCode::KeyW => self.keys.up = true, + winit::keyboard::KeyCode::KeyS => self.keys.down = true, + winit::keyboard::KeyCode::KeyA => self.keys.left = true, + winit::keyboard::KeyCode::KeyD => self.keys.right = true, + winit::keyboard::KeyCode::Digit1 => self.keys.a = true, + winit::keyboard::KeyCode::Digit2 => self.keys.b = true, + winit::keyboard::KeyCode::KeyQ => self.keys.l = true, + winit::keyboard::KeyCode::KeyE => self.keys.r = true, + winit::keyboard::KeyCode::Tab => self.keys.start = true, + winit::keyboard::KeyCode::Space => self.keys.select = true, + _ => {}, + } + } + + pub fn key_released( + &mut self, + _ctx: &context::Context, + key: winit::keyboard::KeyCode, + ) { + match key { + winit::keyboard::KeyCode::KeyW => self.keys.up = false, + winit::keyboard::KeyCode::KeyS => self.keys.down = false, + winit::keyboard::KeyCode::KeyA => self.keys.left = false, + winit::keyboard::KeyCode::KeyD => self.keys.right = false, + winit::keyboard::KeyCode::Digit1 => self.keys.a = false, + winit::keyboard::KeyCode::Digit2 => self.keys.b = false, + winit::keyboard::KeyCode::KeyQ => self.keys.l = false, + winit::keyboard::KeyCode::KeyE => self.keys.r = false, + winit::keyboard::KeyCode::Tab => self.keys.start = false, + winit::keyboard::KeyCode::Space => self.keys.select = false, + _ => {}, + } + } + + pub fn run_update<G>(&mut self, ctx: &context::Context, game: &mut G) where G: Game { + let now = now(ctx); + self.acc += now - self.last; + self.last = now; + + // update, if enough time has accumulated since last update + if self.acc >= DELTA_TIME { + self.acc -= DELTA_TIME; + self.tick += 1; + game.update(ctx, self); + + // if a lot of time has elapsed (e.g. if window is unfocused and not + // running update loop), prevent "death spiral" + if self.acc >= DELTA_TIME { self.acc = 0.0 } + } + } + + pub fn run_render<G>(&mut self, ctx: &context::Context, game: &mut G) where G: Game { + self.render_framebuffer.bind(&ctx); + ctx.clear_color(glam::Vec4::new(0.1, 0.1, 0.1, 1.0)); + ctx.clear(); + + game.render(ctx, self); + + self.screen.bind(&ctx); + ctx.clear_color(glam::Vec4::new(0.0, 0.0, 0.0, 1.0)); + ctx.clear(); + self.shader_upscale.bind(&ctx); + self.render_framebuffer.bind_texture(&ctx); + ctx.render_no_geometry(); + } +} diff --git a/src/texture.rs b/src/texture.rs new file mode 100644 index 0000000..a7c9893 --- /dev/null +++ b/src/texture.rs @@ -0,0 +1,51 @@ +use glow::HasContext; +use image::EncodableLayout; + +use crate::context; + +pub struct Texture { + pub tex: glow::Texture, +} + +impl Texture { + pub fn new(ctx: &context::Context, bytes: &[u8]) -> Self { + let rgba = image::io::Reader::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, + } + } + } + + pub fn bind(&self, ctx: &context::Context) { + unsafe { + ctx.gl.active_texture(glow::TEXTURE0); + ctx.gl.bind_texture(glow::TEXTURE_2D, Some(self.tex)); + } + } +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..57ccf13 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,58 @@ +#[derive(Clone, Debug, PartialEq)] +pub enum Cardinal { + North, + South, + West, + East, +} + +impl Cardinal { + 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 => std::f32::consts::PI, + Self::West => 3.0 * std::f32::consts::PI / 2.0, + Self::East => std::f32::consts::PI / 2.0, + } + } +} + +pub fn lerp(a: f32, b: f32, t: f32) -> f32 { + a + t.clamp(0.0, 1.0) * (b - a) +} |
