summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Cargo.lock1908
-rw-r--r--Cargo.toml52
-rw-r--r--helpers.js13
-rw-r--r--index.css54
-rw-r--r--index.html20
-rw-r--r--src/assets/fonts/font1.pngbin0 -> 1508 bytes
-rw-r--r--src/assets/fonts/font2.pngbin0 -> 1883 bytes
-rw-r--r--src/assets/fonts/simple.pngbin0 -> 1042 bytes
-rw-r--r--src/assets/shaders/common/frag.glsl158
-rw-r--r--src/assets/shaders/common/vert.glsl30
-rw-r--r--src/assets/shaders/scale/frag.glsl13
-rw-r--r--src/assets/shaders/scale/vert.glsl22
-rw-r--r--src/assets/shaders/test/frag.glsl23
-rw-r--r--src/assets/shaders/test/vert.glsl4
-rw-r--r--src/assets/shaders/text/frag.glsl55
-rw-r--r--src/assets/shaders/text/vert.glsl26
-rw-r--r--src/audio.rs96
-rw-r--r--src/context.rs156
-rw-r--r--src/font.rs82
-rw-r--r--src/framebuffer.rs100
-rw-r--r--src/lib.rs94
-rw-r--r--src/mesh.rs118
-rw-r--r--src/request.rs20
-rw-r--r--src/shader.rs171
-rw-r--r--src/state.rs262
-rw-r--r--src/texture.rs51
-rw-r--r--src/utils.rs58
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
new file mode 100644
index 0000000..ec06424
--- /dev/null
+++ b/src/assets/fonts/font1.png
Binary files differ
diff --git a/src/assets/fonts/font2.png b/src/assets/fonts/font2.png
new file mode 100644
index 0000000..8435cad
--- /dev/null
+++ b/src/assets/fonts/font2.png
Binary files differ
diff --git a/src/assets/fonts/simple.png b/src/assets/fonts/simple.png
new file mode 100644
index 0000000..7b1d2a3
--- /dev/null
+++ b/src/assets/fonts/simple.png
Binary files differ
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)
+}