diff --git a/.gitignore b/.gitignore index f868fe4..4117f23 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,10 @@ _visualizer.json *.so *.dylib *.rlib + +#but keep the dxcompiler.dll/dxil.dll +!dxcompiler.dll +!dxil.dll + +# blender backup files +*.blend1 diff --git a/Cargo.lock b/Cargo.lock index ef609d4..098f774 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,15 +18,6 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - [[package]] name = "adler" version = "1.0.2" @@ -63,9 +54,9 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "android-activity" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", "bitflags 2.5.0", @@ -77,7 +68,7 @@ dependencies = [ "log", "ndk", "ndk-context", - "ndk-sys", + "ndk-sys 0.6.0+11769913", "num_enum", "thiserror", ] @@ -145,6 +136,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" +[[package]] +name = "ash" +version = "0.37.3+1.3.251" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" +dependencies = [ + "libloading 0.7.4", +] + [[package]] name = "atomic" version = "0.6.0" @@ -171,30 +171,15 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" - -[[package]] -name = "backtrace" -version = "0.3.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "base64" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bincode" @@ -205,6 +190,21 @@ dependencies = [ "serde", ] +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -218,21 +218,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] -name = "block-sys" -version = "0.2.1" +name = "block" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" -dependencies = [ - "objc-sys", -] +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "block2" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" +checksum = "43ff7d91d3c1d568065b06c899777d1e48dcf76103a672a0adbc238a7f247f1e" dependencies = [ - "block-sys", "objc2", ] @@ -253,9 +249,9 @@ dependencies = [ [[package]] name = "bytemuck_derive" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" +checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" dependencies = [ "proc-macro2", "quote", @@ -302,9 +298,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.95" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" +checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd" dependencies = [ "jobserver", "libc", @@ -330,13 +326,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] -name = "cgl" -version = "0.3.2" +name = "cfg_aliases" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" -dependencies = [ - "libc", -] +checksum = "77e53693616d3075149f4ead59bdeecd204ac6b8192d8969757601b74bddf00f" [[package]] name = "chrono" @@ -357,6 +350,47 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "com" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6" +dependencies = [ + "com_macros", +] + +[[package]] +name = "com_macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5" +dependencies = [ + "com_macros_support", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "com_macros_support" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "combine" version = "4.6.7" @@ -369,9 +403,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] @@ -468,6 +502,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" +[[package]] +name = "d3d12" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b28bfe653d79bd16c77f659305b195b82bb5ce0c0eb2a4846b82ddbd77586813" +dependencies = [ + "bitflags 2.5.0", + "libloading 0.8.3", + "winapi", +] + [[package]] name = "darling" version = "0.20.8" @@ -550,7 +595,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading", + "libloading 0.8.3", ] [[package]] @@ -568,6 +613,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "dpi" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" + [[package]] name = "either" version = "1.11.0" @@ -629,9 +680,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -661,7 +712,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9099a2f86b8e674b75d03ff154b3fe4c5208ed249ced8d69cc313a9fa40bb488" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", "ttf-parser", ] @@ -729,9 +780,9 @@ dependencies = [ [[package]] name = "gilrs" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "499067aa54af19f88732dc418f61f23d5912de1518665bb0eca034ca0d07574c" +checksum = "b54e5e39844ab5cddaf3bbbdfdc2923a6cb34e36818b95618da4e3f26302c24c" dependencies = [ "fnv", "gilrs-core", @@ -762,12 +813,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - [[package]] name = "gl_generator" version = "0.14.0" @@ -789,77 +834,15 @@ dependencies = [ ] [[package]] -name = "glium" -version = "0.34.0" -source = "git+https://github.com/glium/glium?rev=a352c667#a352c667c145e2dda1f5fe1fc2482cbe99de23be" -dependencies = [ - "backtrace", - "fnv", - "gl_generator", - "glutin", - "glutin-winit", - "lazy_static", - "memoffset", - "raw-window-handle 0.5.2", - "smallvec", - "takeable-option", - "winit", -] - -[[package]] -name = "glutin" -version = "0.31.3" +name = "glow" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fcd4ae4e86d991ad1300b8f57166e5be0c95ef1f63f3f5b827f8a164548746" +checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" dependencies = [ - "bitflags 2.5.0", - "cfg_aliases", - "cgl", - "core-foundation", - "dispatch", - "glutin_egl_sys", - "glutin_glx_sys", - "glutin_wgl_sys", - "icrate", - "libloading", - "objc2", - "once_cell", - "raw-window-handle 0.5.2", - "wayland-sys", - "windows-sys 0.48.0", - "x11-dl", -] - -[[package]] -name = "glutin-winit" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebcdfba24f73b8412c5181e56f092b5eff16671c514ce896b258a0a64bd7735" -dependencies = [ - "cfg_aliases", - "glutin", - "raw-window-handle 0.5.2", - "winit", -] - -[[package]] -name = "glutin_egl_sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77cc5623f5309ef433c3dd4ca1223195347fe62c413da8e2fdd0eb76db2d9bcd" -dependencies = [ - "gl_generator", - "windows-sys 0.48.0", -] - -[[package]] -name = "glutin_glx_sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a165fd686c10dcc2d45380b35796e577eacfd43d4660ee741ec8ebe2201b3b4f" -dependencies = [ - "gl_generator", - "x11-dl", + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -871,6 +854,58 @@ dependencies = [ "gl_generator", ] +[[package]] +name = "gpu-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.5.0", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.5.0", +] + +[[package]] +name = "gpu-allocator" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884" +dependencies = [ + "log", + "presser", + "thiserror", + "winapi", + "windows", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c08c1f623a8d0b722b8b99f821eb0ba672a1618f0d3b16ddbee1cedd2dd8557" +dependencies = [ + "bitflags 2.5.0", + "gpu-descriptor-types", + "hashbrown 0.14.5", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "hash32" version = "0.2.1" @@ -888,15 +923,30 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", "serde", ] +[[package]] +name = "hassle-rs" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" +dependencies = [ + "bitflags 2.5.0", + "com", + "libc", + "libloading 0.8.3", + "thiserror", + "widestring", + "winapi", +] + [[package]] name = "heapless" version = "0.7.17" @@ -929,49 +979,57 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + [[package]] name = "hui" -version = "0.1.0-alpha.4" -source = "git+https://github.com/griffi-gh/hui?rev=dd5af8b9e2#dd5af8b9e2dc4cb2beb0b130d82167258ea2bd4e" +version = "0.1.0-alpha.5" +source = "git+https://github.com/griffi-gh/hui?rev=6eb3d98ad4#6eb3d98ad4747b34a366d6d92ba6f1df3bec4ba4" dependencies = [ "derive_more", "derive_setters", "document-features", "fontdue", "glam", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "hui-derive", "image", "log", "nohash-hasher", "rect_packer", + "rustc-hash", "tinyset", ] [[package]] name = "hui-derive" -version = "0.1.0-alpha.4" -source = "git+https://github.com/griffi-gh/hui?rev=dd5af8b9e2#dd5af8b9e2dc4cb2beb0b130d82167258ea2bd4e" +version = "0.1.0-alpha.5" +source = "git+https://github.com/griffi-gh/hui?rev=6eb3d98ad4#6eb3d98ad4747b34a366d6d92ba6f1df3bec4ba4" dependencies = [ "quote", "syn 2.0.60", ] [[package]] -name = "hui-glium" -version = "0.1.0-alpha.4" -source = "git+https://github.com/griffi-gh/hui?rev=dd5af8b9e2#dd5af8b9e2dc4cb2beb0b130d82167258ea2bd4e" +name = "hui-wgpu" +version = "0.1.0-alpha.5" +source = "git+https://github.com/griffi-gh/hui?rev=6eb3d98ad4#6eb3d98ad4747b34a366d6d92ba6f1df3bec4ba4" dependencies = [ + "bytemuck", "glam", - "glium", "hui", "log", + "wgpu", ] [[package]] name = "hui-winit" -version = "0.1.0-alpha.4" -source = "git+https://github.com/griffi-gh/hui?rev=dd5af8b9e2#dd5af8b9e2dc4cb2beb0b130d82167258ea2bd4e" +version = "0.1.0-alpha.5" +source = "git+https://github.com/griffi-gh/hui?rev=6eb3d98ad4#6eb3d98ad4747b34a366d6d92ba6f1df3bec4ba4" dependencies = [ "glam", "hui", @@ -1008,17 +1066,6 @@ dependencies = [ "cc", ] -[[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 = "ident_case" version = "1.0.1" @@ -1055,7 +1102,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "serde", ] @@ -1146,6 +1193,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading 0.8.3", + "pkg-config", +] + [[package]] name = "khronos_api" version = "3.1.0" @@ -1159,15 +1217,13 @@ dependencies = [ "android-activity", "anyhow", "atomic", + "bytemuck", "flume", "gilrs", "glam", - "glium", - "glutin", - "glutin-winit", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "hui", - "hui-glium", + "hui-wgpu", "hui-winit", "image", "kubi-logging", @@ -1176,16 +1232,19 @@ dependencies = [ "lz4_flex", "ndk", "nohash-hasher", + "pollster", "postcard", "rand", - "raw-window-handle 0.5.2", + "raw-window-handle", "rayon", "serde_json", "shipyard", "static_assertions", "strum", "tinyset", + "tobj", "uflow", + "wgpu", "winapi", "winit", ] @@ -1206,7 +1265,7 @@ dependencies = [ "anyhow", "flume", "glam", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "kubi-logging", "kubi-shared", "log", @@ -1231,7 +1290,7 @@ dependencies = [ "bytemuck", "fastnoise-lite", "glam", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "nohash-hasher", "num_enum", "nz", @@ -1253,9 +1312,19 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] [[package]] name = "libloading" @@ -1308,9 +1377,9 @@ checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1337,6 +1406,15 @@ dependencies = [ "libc", ] +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + [[package]] name = "memchr" version = "2.7.2" @@ -1353,12 +1431,18 @@ dependencies = [ ] [[package]] -name = "memoffset" -version = "0.9.1" +name = "metal" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +checksum = "5637e166ea14be6063a3f8ba5ccb9a4159df7d8f6d61c02fc3d480b1f90dcfcb" dependencies = [ - "autocfg", + "bitflags 2.5.0", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", + "paste", ] [[package]] @@ -1371,6 +1455,27 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "naga" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e536ae46fcab0876853bd4a632ede5df4b1c2527a58f6c5a4150fe86be858231" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags 2.5.0", + "codespan-reporting", + "hexf-parse", + "indexmap 2.2.6", + "log", + "num-traits", + "rustc-hash", + "spirv", + "termcolor", + "thiserror", + "unicode-xid", +] + [[package]] name = "nanorand" version = "0.7.0" @@ -1382,17 +1487,16 @@ dependencies = [ [[package]] name = "ndk" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ "bitflags 2.5.0", "jni-sys", "log", - "ndk-sys", + "ndk-sys 0.6.0+11769913", "num_enum", - "raw-window-handle 0.5.2", - "raw-window-handle 0.6.1", + "raw-window-handle", "thiserror", ] @@ -1411,6 +1515,15 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + [[package]] name = "nix" version = "0.28.0" @@ -1419,7 +1532,7 @@ checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ "bitflags 2.5.0", "cfg-if", - "cfg_aliases", + "cfg_aliases 0.1.1", "libc", ] @@ -1437,9 +1550,9 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -1467,9 +1580,18 @@ dependencies = [ [[package]] name = "nz" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb749eec2b3be2f169dd4facfec40a28cc40f2b02ad3c4d2c51ce578c3f635b0" +checksum = "d1e9655df3f51323812726b25a00d787562c5fa64177d286603429787b4386a9" + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] [[package]] name = "objc-sys" @@ -1479,27 +1601,52 @@ checksum = "da284c198fb9b7b0603f8635185e85fbd5b64ee154b1ed406d489077de2d6d60" [[package]] name = "objc2" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" +checksum = "b4b25e1034d0e636cd84707ccdaa9f81243d399196b8a773946dcffec0401659" dependencies = [ "objc-sys", "objc2-encode", ] [[package]] -name = "objc2-encode" -version = "3.0.0" +name = "objc2-app-kit" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" +checksum = "fb79768a710a9a1798848179edb186d1af7e8a8679f369e4b8d201dd2a034047" +dependencies = [ + "block2", + "objc2", + "objc2-core-data", + "objc2-foundation", +] [[package]] -name = "object" -version = "0.32.2" +name = "objc2-core-data" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "6e092bc42eaf30a08844e6a076938c60751225ec81431ab89f5d1ccd9f958d6c" dependencies = [ - "memchr", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-encode" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88658da63e4cc2c8adb1262902cd6af51094df0488b760d6fd27194269c0950a" + +[[package]] +name = "objc2-foundation" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfaefe14254871ea16c7d88968c0ff14ba554712a20d76421eec52f0a7fb8904" +dependencies = [ + "block2", + "dispatch", + "objc2", ] [[package]] @@ -1536,12 +1683,61 @@ dependencies = [ "libm", ] +[[package]] +name = "parking_lot" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.1", + "smallvec", + "windows-targets 0.52.5", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.60", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1582,6 +1778,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "pollster" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" + [[package]] name = "postcard" version = "1.0.8" @@ -1606,6 +1808,12 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + [[package]] name = "proc-macro-crate" version = "3.1.0" @@ -1624,6 +1832,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" + [[package]] name = "quick-xml" version = "0.31.0" @@ -1683,10 +1897,10 @@ dependencies = [ ] [[package]] -name = "raw-window-handle" -version = "0.5.2" +name = "range-alloc" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" +checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" [[package]] name = "raw-window-handle" @@ -1722,20 +1936,20 @@ checksum = "d8ffb4dfda4b01cc420847665dc480760d596ce186f2772a66ed32fe9acb1c45" [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", ] [[package]] @@ -1768,10 +1982,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] -name = "rustc-demangle" -version = "0.1.23" +name = "renderdoc-sys" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" @@ -1841,9 +2061,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sctk-adwaita" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b2eaf3a5b264a521b988b2e73042e742df700c4f962cde845d1541adb46550" +checksum = "7de61fa7334ee8ee1f5c3c58dcc414fb9361e7e8f5bff9d45f4d69eeb89a7169" dependencies = [ "ab_glyph", "log", @@ -1860,18 +2080,18 @@ checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.198" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.198" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" dependencies = [ "proc-macro2", "quote", @@ -1900,9 +2120,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c85f8e96d1d6857f13768fcbd895fcb06225510022a2774ed8b5150581847b0" +checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" dependencies = [ "base64", "chrono", @@ -1918,9 +2138,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8b3a576c4eb2924262d5951a3b737ccaf16c931e39a2810c36f9a7e25575557" +checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" dependencies = [ "darling", "proc-macro2", @@ -1933,7 +2153,7 @@ name = "shipyard" version = "0.6.0" source = "git+https://github.com/leudz/shipyard?rev=aacf3b1df5#aacf3b1df540c7d9d384830d7431ba618eee75c9" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", "lock_api", "rayon", "serde", @@ -1972,6 +2192,15 @@ 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.2" @@ -2021,6 +2250,15 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -2089,12 +2327,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "takeable-option" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ae8932fcfea38b7d3883ae2ab357b0d57a02caaa18ebb4f5ece08beaec4aa0" - [[package]] name = "termcolor" version = "1.4.1" @@ -2189,6 +2421,15 @@ dependencies = [ "rand", ] +[[package]] +name = "tobj" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3bd4ba05f29e4c65b6c0c11a58b6465ffa820bac890d76ad407b4e81d8372e8" +dependencies = [ + "ahash", +] + [[package]] name = "toml" version = "0.8.12" @@ -2231,7 +2472,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.6", + "winnow 0.6.7", ] [[package]] @@ -2277,6 +2518,18 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +[[package]] +name = "unicode-width" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "uuid" version = "1.8.0" @@ -2498,14 +2751,129 @@ dependencies = [ [[package]] name = "web-time" -version = "0.2.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", ] +[[package]] +name = "wgpu" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32ff1bfee408e1028e2e3acbf6d32d98b08a5a059ccbf5f33305534453ba5d3e" +dependencies = [ + "arrayvec", + "cfg-if", + "cfg_aliases 0.1.1", + "document-features", + "js-sys", + "log", + "naga", + "parking_lot", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac6a86eaa5e763e59c73cf9e97d55fffd4dfda69fd8bda19589fcf851ddfef1f" +dependencies = [ + "arrayvec", + "bit-vec", + "bitflags 2.5.0", + "cfg_aliases 0.1.1", + "codespan-reporting", + "document-features", + "indexmap 2.2.6", + "log", + "naga", + "once_cell", + "parking_lot", + "profiling", + "raw-window-handle", + "rustc-hash", + "smallvec", + "thiserror", + "web-sys", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d71c8ae05170583049b65ee562fd839fdc0b3e9ddb84f4e40c9d5f8ea0d4c8c" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags 2.5.0", + "block", + "cfg_aliases 0.1.1", + "core-graphics-types", + "d3d12", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-allocator", + "gpu-descriptor", + "hassle-rs", + "js-sys", + "khronos-egl", + "libc", + "libloading 0.8.3", + "log", + "metal", + "naga", + "ndk-sys 0.5.0+25.2.9519653", + "objc", + "once_cell", + "parking_lot", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "rustc-hash", + "smallvec", + "thiserror", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "winapi", +] + +[[package]] +name = "wgpu-types" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1353d9a46bff7f955a680577f34c69122628cc2076e1d6f3a9be6ef00ae793ef" +dependencies = [ + "bitflags 2.5.0", + "js-sys", + "web-sys", +] + +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + [[package]] name = "winapi" version = "0.3.9" @@ -2537,6 +2905,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets 0.52.5", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -2555,15 +2933,6 @@ 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" @@ -2753,9 +3122,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winit" -version = "0.29.15" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" +checksum = "ea9e6d5d66cbf702e0dd820302144f51b69a95acdc495dd98ca280ff206562b1" dependencies = [ "ahash", "android-activity", @@ -2763,28 +3132,29 @@ dependencies = [ "bitflags 2.5.0", "bytemuck", "calloop", - "cfg_aliases", + "cfg_aliases 0.2.0", + "concurrent-queue", "core-foundation", "core-graphics", "cursor-icon", - "icrate", + "dpi", "js-sys", "libc", - "log", "memmap2", "ndk", - "ndk-sys", "objc2", - "once_cell", + "objc2-app-kit", + "objc2-foundation", "orbclient", "percent-encoding", - "raw-window-handle 0.5.2", - "raw-window-handle 0.6.1", - "redox_syscall 0.3.5", + "pin-project", + "raw-window-handle", + "redox_syscall 0.4.1", "rustix", "sctk-adwaita", "smithay-client-toolkit", "smol_str", + "tracing", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", @@ -2794,7 +3164,7 @@ dependencies = [ "wayland-protocols-plasma", "web-sys", "web-time", - "windows-sys 0.48.0", + "windows-sys 0.52.0", "x11-dl", "x11rb", "xkbcommon-dl", @@ -2811,9 +3181,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352" +checksum = "14b9415ee827af173ebb3f15f9083df5a122eb93572ec28741fb153356ea2578" dependencies = [ "memchr", ] @@ -2831,14 +3201,14 @@ dependencies = [ [[package]] name = "x11rb" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" dependencies = [ "as-raw-xcb-connection", "gethostname", "libc", - "libloading", + "libloading 0.8.3", "once_cell", "rustix", "x11rb-protocol", @@ -2846,9 +3216,9 @@ dependencies = [ [[package]] name = "x11rb-protocol" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] name = "xcursor" diff --git a/Cargo.toml b/Cargo.toml index ae628a0..8e1cac3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,10 +21,13 @@ opt-level = 1 [profile.dev.package.uflow] opt-level = 3 -[profile.dev.package.glium] +[profile.dev.package.wgpu] opt-level = 3 -[profile.dev.package.bracket-noise] +[profile.dev.package.wgpu-core] +opt-level = 3 + +[profile.dev.package.wgpu-hal] opt-level = 3 [profile.dev.package.fastnoise-lite] @@ -38,5 +41,7 @@ opt-level = 3 [profile.dev.package.android-activity] debug-assertions = false -[patch.crates-io] -glium = { git = "https://github.com/glium/glium", rev = "a352c667" } +# [patch.'https://github.com/griffi-gh/hui'] +# hui = { path = "X:/Projects/hui/hui" } +# hui-winit = { path = "X:/Projects/hui/hui-winit" } +# hui-wgpu = { path = "X:/Projects/hui/hui-wgpu" } diff --git a/assets-src/playermodel1.blend b/assets-src/playermodel1.blend new file mode 100644 index 0000000..1f49949 Binary files /dev/null and b/assets-src/playermodel1.blend differ diff --git a/assets/playermodel1.obj b/assets/playermodel1.obj new file mode 100644 index 0000000..34c1973 --- /dev/null +++ b/assets/playermodel1.obj @@ -0,0 +1,64 @@ +# Blender 4.0.0 Beta +# www.blender.org +o Cube +v -0.500000 0.708333 -0.666667 +v -0.500000 -0.291667 -0.666667 +v 0.500000 0.708333 -0.666667 +v 0.500000 -0.291667 -0.666667 +v -0.500000 0.708333 0.333333 +v -0.500000 -0.291667 0.333333 +v 0.500000 0.708333 0.333333 +v 0.500000 -0.291667 0.333333 +v -0.500000 0.958333 -0.666667 +v 0.500000 0.958333 -0.666667 +v -0.166667 0.708333 -0.666667 +v 0.166667 0.708333 -0.666667 +vn -0.0000 1.0000 -0.0000 +vn 1.0000 -0.0000 -0.0000 +vn -0.0000 -0.0000 1.0000 +vn -0.0000 -1.0000 -0.0000 +vn -0.0000 -0.0000 -1.0000 +vn -1.0000 -0.0000 -0.0000 +vt 0.204555 0.291387 +vt 0.043204 0.462923 +vt 0.043204 0.291387 +vt 0.259623 0.207472 +vt 0.024467 0.457472 +vt 0.024467 0.207472 +vt 0.177715 0.183914 +vt 0.010921 0.538561 +vt 0.010921 0.183914 +vt 0.246583 0.218979 +vt 0.011426 0.468979 +vt 0.011426 0.218979 +vt 0.896961 0.811182 +vt 0.168955 0.037222 +vt 0.896961 0.037221 +vt 0.177715 0.538561 +vt 0.010921 0.361238 +vt 0.168955 0.811182 +vt 0.411624 0.811182 +vt 0.204555 0.462923 +vt 0.259623 0.457472 +vt 0.246583 0.468979 +vt 0.177715 0.361238 +vt 0.896961 0.990308 +vt 0.654292 0.811182 +vt 0.168955 0.990308 +s 0 +f 5/1/1 3/2/1 1/3/1 +f 3/4/2 8/5/2 4/6/2 +f 7/7/3 6/8/3 8/9/3 +f 2/10/4 8/11/4 6/12/4 +f 1/13/5 4/14/5 2/15/5 +f 5/16/6 2/17/6 6/8/6 +f 3/18/3 1/13/3 12/19/3 +f 5/1/1 7/20/1 3/2/1 +f 3/4/2 7/21/2 8/5/2 +f 7/7/3 5/16/3 6/8/3 +f 2/10/4 4/22/4 8/11/4 +f 1/13/5 3/18/5 4/14/5 +f 5/16/6 1/23/6 2/17/6 +f 1/13/5 9/24/5 11/25/5 +f 12/19/5 10/26/5 3/18/5 +f 1/13/5 11/25/5 12/19/5 diff --git a/assets/playermodel1.png b/assets/playermodel1.png new file mode 100644 index 0000000..227ee44 Binary files /dev/null and b/assets/playermodel1.png differ diff --git a/kubi-logging/src/lib.rs b/kubi-logging/src/lib.rs index 34b8a89..0b03e77 100644 --- a/kubi-logging/src/lib.rs +++ b/kubi-logging/src/lib.rs @@ -1,64 +1,64 @@ -//! Custom env_logger options and styling - -/// Custom env_logger options and styling -#[inline] -#[cfg(not(target_os = "android"))] -pub fn init() { - use log::Level; - use std::io::Write; - use env_logger::{fmt::Color, Builder, Env}; - - let env = Env::default() - .filter_or("RUST_LOG", "trace,gilrs=warn,rusty_xinput=warn"); - Builder::from_env(env) - .format(|buf, record| { - let mut level_style = buf.style(); - level_style.set_color(match record.level() { - Level::Error => Color::Red, - Level::Warn => Color::Yellow, - Level::Debug | Level::Trace => Color::Cyan, - _ => Color::Blue - }).set_bold(true); - - let mut bold_style = buf.style(); - bold_style.set_bold(true); - - let mut location_style = buf.style(); - location_style.set_bold(true); - location_style.set_dimmed(true); - - let mut location_line_style = buf.style(); - location_line_style.set_dimmed(true); - - let text = format!("{}", record.args()); - - writeln!( - buf, - "{} {:<50}\t{}{}{}{}", - level_style.value(match record.level() { - Level::Error => "[e]", - Level::Warn => "[w]", - Level::Info => "[i]", - Level::Debug => "[d]", - Level::Trace => "[t]", - }), - text, - bold_style.value((text.len() > 50).then_some("\n ╰─ ").unwrap_or_default()), - location_style.value(record.target()), - location_line_style.value(" :"), - location_line_style.value(record.line().unwrap_or(0)) - ) - }) - .init(); -} - -/// Custom env_logger options and styling -#[inline] -#[cfg(target_os = "android")] -pub fn init() { - use log::LevelFilter; - use android_logger::Config; - android_logger::init_once( - Config::default().with_max_level(LevelFilter::Trace), - ); -} +//! Custom env_logger options and styling + +/// Custom env_logger options and styling +#[inline] +#[cfg(not(target_os = "android"))] +pub fn init() { + use log::Level; + use std::io::Write; + use env_logger::{fmt::Color, Builder, Env}; + + let env = Env::default() + .filter_or("RUST_LOG", "trace,gilrs=warn,rusty_xinput=warn,wgpu=warn,wgpu_core=warn,wgpu_hal=warn,hui=info,hui-winit=info,hui-glium=info,hui-wgpu=info,naga=warn"); + Builder::from_env(env) + .format(|buf, record| { + let mut level_style = buf.style(); + level_style.set_color(match record.level() { + Level::Error => Color::Red, + Level::Warn => Color::Yellow, + Level::Debug | Level::Trace => Color::Cyan, + _ => Color::Blue + }).set_bold(true); + + let mut bold_style = buf.style(); + bold_style.set_bold(true); + + let mut location_style = buf.style(); + location_style.set_bold(true); + location_style.set_dimmed(true); + + let mut location_line_style = buf.style(); + location_line_style.set_dimmed(true); + + let text = format!("{}", record.args()); + + writeln!( + buf, + "{} {:<50}\t{}{}{}{}", + level_style.value(match record.level() { + Level::Error => "[e]", + Level::Warn => "[w]", + Level::Info => "[i]", + Level::Debug => "[d]", + Level::Trace => "[t]", + }), + text, + bold_style.value((text.len() > 50).then_some("\n ╰─ ").unwrap_or_default()), + location_style.value(record.target()), + location_line_style.value(" :"), + location_line_style.value(record.line().unwrap_or(0)) + ) + }) + .init(); +} + +/// Custom env_logger options and styling +#[inline] +#[cfg(target_os = "android")] +pub fn init() { + use log::LevelFilter; + use android_logger::Config; + android_logger::init_once( + Config::default().with_max_level(LevelFilter::Trace), + ); +} diff --git a/kubi-server/Cargo.toml b/kubi-server/Cargo.toml index 075eced..51a4f43 100644 --- a/kubi-server/Cargo.toml +++ b/kubi-server/Cargo.toml @@ -15,7 +15,7 @@ glam = { version = "0.27", features = ["debug-glam-assert", "fast-math"] } hashbrown = "0.14" nohash-hasher = "0.2" anyhow = "1.0" -rayon = "1.7" +rayon = "1.10" flume = "0.11" rand = "0.8" uflow = "0.7" diff --git a/kubi-shared/src/worldgen/steps/_04_layers.rs b/kubi-shared/src/worldgen/steps/_04_layers.rs index f6d873d..52204b9 100644 --- a/kubi-shared/src/worldgen/steps/_04_layers.rs +++ b/kubi-shared/src/worldgen/steps/_04_layers.rs @@ -1,4 +1,3 @@ -use fastnoise_lite::FastNoiseLite; use glam::ivec3; use crate::{block::Block, chunk::CHUNK_SIZE, worldgen::SeedThingy}; use super::{ diff --git a/kubi/Cargo.toml b/kubi/Cargo.toml index ed59a2c..b08759c 100644 --- a/kubi/Cargo.toml +++ b/kubi/Cargo.toml @@ -11,21 +11,21 @@ crate-type = ["lib", "cdylib"] [dependencies] kubi-shared = { path = "../kubi-shared" } kubi-logging = { path = "../kubi-logging" } -hui = { version = "0.1.0-alpha.4", git = "https://github.com/griffi-gh/hui", rev = "dd5af8b9e2" } -hui-glium = { version = "0.1.0-alpha.4", git = "https://github.com/griffi-gh/hui", rev = "dd5af8b9e2" } -hui-winit = { version = "0.1.0-alpha.4", git = "https://github.com/griffi-gh/hui", rev = "dd5af8b9e2" } +hui = { git = "https://github.com/griffi-gh/hui", rev = "6eb3d98ad4" } +hui-wgpu = { git = "https://github.com/griffi-gh/hui", rev = "6eb3d98ad4" } +hui-winit = { git = "https://github.com/griffi-gh/hui", rev = "6eb3d98ad4", features = ["winit_30"] } log = "0.4" -glium = { git = "https://github.com/glium/glium", rev = "a352c667" } -glutin = "0.31" -winit = { version = "0.29", features = ["android-native-activity"] } -glutin-winit = "0.4" -raw-window-handle = "=0.5.*" +wgpu = { version = "0.20", features = ["webgl"] } +pollster = "0.3" +bytemuck = { version = "1.15", features = ["derive"] } +winit = { version = "0.30", features = ["android-native-activity"] } +raw-window-handle = "0.6" glam = { version = "0.27", features = ["debug-glam-assert", "fast-math"] } image = { version = "0.25", default_features = false, features = ["png"] } strum = { version = "0.26", features = ["derive"] } hashbrown = "0.14" nohash-hasher = "0.2" -rayon = "1.7" +rayon = "1.10" shipyard = { git = "https://github.com/leudz/shipyard", rev = "aacf3b1df5", default-features = false, features = ["std", "proc", "thread_local"] } anyhow = "1.0" flume = "0.11" @@ -38,10 +38,11 @@ tinyset = "0.4" serde_json = { version = "1.0", optional = true } #only used for `generate_visualizer_data` rand = { version = "0.8", features = ["alloc", "small_rng"]} atomic = "0.6" +tobj = "4.0" [target.'cfg(target_os = "android")'.dependencies] -android-activity = "^0.5.2" -ndk = "0.8" +android-activity = "0.6" +ndk = "0.9" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3", features = ["wincon"] } diff --git a/kubi/shaders/c2d.wgsl b/kubi/shaders/c2d.wgsl new file mode 100644 index 0000000..c6fce2e --- /dev/null +++ b/kubi/shaders/c2d.wgsl @@ -0,0 +1,14 @@ +@group(0) @binding(0) +var color: vec4; + +@vertex +fn vs_main( + @location(0) position: vec2, +) -> @builtin(position) vec4 { + return vec4(position, 0.0, 1.0); +} + +@fragment +fn fs_main() -> @location(0) vec4 { + return color; +} diff --git a/kubi/shaders/colored.frag b/kubi/shaders/colored.frag deleted file mode 100644 index 7ab85c6..0000000 --- a/kubi/shaders/colored.frag +++ /dev/null @@ -1,12 +0,0 @@ -#version 300 es - -precision highp float; - -out vec4 out_color; -uniform vec4 color; - -void main() { - // discard fully transparent pixels - if (color.w <= 0.) discard; - out_color = color; -} diff --git a/kubi/shaders/colored.vert b/kubi/shaders/colored.vert deleted file mode 100644 index c6b3ef8..0000000 --- a/kubi/shaders/colored.vert +++ /dev/null @@ -1,13 +0,0 @@ -#version 300 es - -precision highp float; - -in vec3 position; -uniform mat4 model; -uniform mat4 perspective; -uniform mat4 view; - -void main() { - mat4 modelview = view * model; - gl_Position = perspective * modelview * vec4(position, 1.); -} diff --git a/kubi/shaders/colored2.frag b/kubi/shaders/colored2.frag deleted file mode 100644 index cddd0d4..0000000 --- a/kubi/shaders/colored2.frag +++ /dev/null @@ -1,10 +0,0 @@ -#version 300 es - -precision highp float; - -out vec4 out_color; -uniform vec4 color; - -void main() { - out_color = color; -} diff --git a/kubi/shaders/colored2.vert b/kubi/shaders/colored2.vert deleted file mode 100644 index db908de..0000000 --- a/kubi/shaders/colored2.vert +++ /dev/null @@ -1,9 +0,0 @@ -#version 300 es - -precision highp float; - -in vec2 position; - -void main() { - gl_Position = vec4(position, 0.0, 1.0); -} diff --git a/kubi/shaders/entities.wgsl b/kubi/shaders/entities.wgsl new file mode 100644 index 0000000..2a0526f --- /dev/null +++ b/kubi/shaders/entities.wgsl @@ -0,0 +1,50 @@ +struct CameraUniform { + view_proj: mat4x4, +}; + +@group(1) @binding(0) +var camera: CameraUniform; + +struct VertexInput { + @location(0) uv: vec2, + @location(1) position: vec3, + @location(2) normal: vec3, + @location(3) mat_row0: vec4, + @location(4) mat_row1: vec4, + @location(5) mat_row2: vec4, + @location(6) mat_row3: vec4, +} + +struct VertexOutput { + @builtin(position) clip_position: vec4, + @location(0) uv: vec2, + @location(1) normal: vec3, +}; + +@vertex +fn vs_main( + in: VertexInput, +) -> VertexOutput { + let inst_mat = mat4x4( + in.mat_row0, + in.mat_row1, + in.mat_row2, + in.mat_row3, + ); + var out: VertexOutput; + out.clip_position = camera.view_proj * (inst_mat * vec4(in.position, 1.0)); + out.uv = in.uv; + out.normal = in.normal; + return out; +} + +@group(0) @binding(0) +var t_diffuse: texture_2d; + +@group(0) @binding(1) +var s_diffuse: sampler; + +@fragment +fn fs_main(in: VertexOutput) -> @location(0) vec4 { + return textureSample(t_diffuse, s_diffuse, in.uv); +} diff --git a/kubi/shaders/selection_box.wgsl b/kubi/shaders/selection_box.wgsl new file mode 100644 index 0000000..09a097e --- /dev/null +++ b/kubi/shaders/selection_box.wgsl @@ -0,0 +1,27 @@ +struct CameraUniform { + view_proj: mat4x4, +}; + +@group(0) @binding(0) +var camera: CameraUniform; + +struct SboxUniform { + position: vec3, +}; + +@group(1) @binding(0) +var sbox: SboxUniform; + +@vertex +fn vs_main( + @location(0) position: vec3, +) -> @builtin(position) vec4 { + return camera.view_proj * vec4(position + sbox.position, 1.0); +} + +@fragment +fn fs_main( + @builtin(position) in: vec4, +) -> @location(0) vec4 { + return vec4(0.0, 0.0, 0.0, 0.5); +} diff --git a/kubi/shaders/world.frag b/kubi/shaders/world.frag deleted file mode 100644 index 48d2df0..0000000 --- a/kubi/shaders/world.frag +++ /dev/null @@ -1,26 +0,0 @@ -#version 300 es - -precision highp float; -precision lowp sampler2DArray; - -in vec3 v_normal; -in vec2 v_uv; -flat in uint v_tex_index; -out vec4 color; -uniform sampler2DArray tex; -uniform bool discard_alpha; - -void main() { - // base color from texture - color = texture(tex, vec3(v_uv, v_tex_index)); - - // discard fully transparent pixels - if (discard_alpha ? (color.w < 0.5) : (color.w == 0.)) discard; - - //basic "lighting" - float light = abs(v_normal.x) + .8 * abs(v_normal.y) + .6 * abs(v_normal.z); - color *= vec4(vec3(light), 1.); - - //discard alpha - if (discard_alpha) color.w = 1.; -} diff --git a/kubi/shaders/world.vert b/kubi/shaders/world.vert deleted file mode 100644 index 996a1ec..0000000 --- a/kubi/shaders/world.vert +++ /dev/null @@ -1,27 +0,0 @@ -#version 300 es - -precision highp float; - -//TODO pack this data: -// uint position_normal_uv -// XXYYZZNU -// wehere Normal and Uv are enums -// maybe somehow pack in tex index too - -in vec3 position; -in vec3 normal; -in vec2 uv; -in uint tex_index; -out vec2 v_uv; -out vec3 v_normal; -flat out uint v_tex_index; -uniform vec3 position_offset; -uniform mat4 perspective; -uniform mat4 view; - -void main() { - v_normal = normal; - v_tex_index = tex_index; - v_uv = uv; - gl_Position = perspective * view * vec4(position + position_offset, 1.); -} diff --git a/kubi/shaders/world.wgsl b/kubi/shaders/world.wgsl new file mode 100644 index 0000000..96b54a7 --- /dev/null +++ b/kubi/shaders/world.wgsl @@ -0,0 +1,62 @@ +struct CameraUniform { + view_proj: mat4x4, +}; + +@group(1) @binding(0) +var camera: CameraUniform; + +struct VertexInput { + @location(0) position: vec3, + @location(1) normal: vec3, + @location(2) uv: vec2, + @location(3) tex_index: u32, +} + +struct VertexOutput { + @builtin(position) clip_position: vec4, + @location(0) uv: vec2, + @location(1) normal: vec3, + @location(2) @interpolate(flat)tex_index: u32, +}; + +@vertex +fn vs_main( + in: VertexInput, +) -> VertexOutput { + var out: VertexOutput; + out.uv = in.uv; + out.normal = in.normal; + out.tex_index = in.tex_index; + out.clip_position = camera.view_proj * vec4(in.position, 1.0); + return out; +} + +@group(0) @binding(0) +var t_diffuse: texture_2d_array; + +@group(0) @binding(1) +var s_diffuse: sampler; + +@fragment +fn fs_main(in: VertexOutput) -> @location(0) vec4 { + // not actual lighting; makes it easier to distinguish unlit faces + let light: f32 = + abs(in.normal.x) + .85 * + abs(in.normal.y) + .65 * + abs(in.normal.z); + + let color: vec4 = + textureSample(t_diffuse, s_diffuse, in.uv, in.tex_index) + * vec4(light, light, light, 1.0); + + if (color.a < 0.5) { + discard; + } + + return color; +} + +@fragment +fn fs_main_trans(in: VertexOutput) -> @location(0) vec4 { + return textureSample(t_diffuse, s_diffuse, in.uv, in.tex_index); +} diff --git a/kubi/src/camera/matrices.rs b/kubi/src/camera/matrices.rs index 44c359f..6230447 100644 --- a/kubi/src/camera/matrices.rs +++ b/kubi/src/camera/matrices.rs @@ -1,6 +1,6 @@ use glam::{Vec3, Mat4}; use shipyard::{ViewMut, View, IntoIter, Workload, IntoWorkload, track, UniqueView, SystemModificator}; -use crate::{transform::Transform, rendering::WindowSize, events::WindowResizedEvent}; +use crate::{transform::Transform, rendering::Renderer, events::WindowResizedEvent}; use super::Camera; //maybe parallelize these two? @@ -18,14 +18,15 @@ fn update_view_matrix( fn update_perspective_matrix( mut vm_camera: ViewMut, - size: UniqueView, + ren: UniqueView, ) { + let sz = ren.size_vec2(); for mut camera in (&mut vm_camera).iter() { - camera.perspective_matrix = Mat4::perspective_rh_gl( + camera.perspective_matrix = Mat4::perspective_rh( camera.fov, - size.0.x as f32 / size.0.y as f32, + sz.x / sz.y, camera.z_near, - camera.z_far, + camera.z_far, ) } } diff --git a/kubi/src/chat.rs b/kubi/src/chat.rs index 24b1949..90f4ee1 100644 --- a/kubi/src/chat.rs +++ b/kubi/src/chat.rs @@ -1,5 +1,5 @@ use kubi_shared::networking::client::ClientId; -use shipyard::{AllStoragesView, Unique, UniqueViewMut}; +use shipyard::{AllStoragesView, Unique}; pub enum ChatMessage { PlayerMessage { diff --git a/kubi/src/client_physics.rs b/kubi/src/client_physics.rs index ac79175..f6ef9e6 100644 --- a/kubi/src/client_physics.rs +++ b/kubi/src/client_physics.rs @@ -1,7 +1,7 @@ //TODO client-side physics //TODO move this to shared -use glam::{vec3, IVec3, Mat4, Vec3, Vec3Swizzles}; -use shipyard::{track, AllStoragesView, Component, IntoIter, Unique, UniqueView, View, ViewMut}; +use glam::{vec3, Mat4, Vec3, Vec3Swizzles}; +use shipyard::{track, AllStoragesView, Component, IntoIter, Unique, UniqueView, ViewMut}; use kubi_shared::{block::{Block, CollisionType}, transform::Transform}; use crate::{delta_time::DeltaTime, world::ChunkStorage}; diff --git a/kubi/src/cursor_lock.rs b/kubi/src/cursor_lock.rs index 11c572a..e8a1a43 100644 --- a/kubi/src/cursor_lock.rs +++ b/kubi/src/cursor_lock.rs @@ -1,5 +1,5 @@ -use shipyard::{AllStoragesView, IntoIter, NonSendSync, Unique, UniqueView, UniqueViewMut, View}; -use crate::{events::InputDeviceEvent, rendering::{Renderer, WindowSize}}; +use shipyard::{AllStoragesView, IntoIter, Unique, UniqueView, UniqueViewMut, View}; +use crate::{events::InputDeviceEvent, rendering::Renderer}; use winit::{ dpi::PhysicalPosition, event::{DeviceEvent, ElementState, RawKeyEvent}, keyboard::{KeyCode, PhysicalKey}, window::CursorGrabMode }; @@ -9,14 +9,14 @@ pub struct CursorLock(pub bool); pub fn update_cursor_lock_state( lock: UniqueView, - display: NonSendSync> + display: UniqueView ) { if cfg!(target_os = "android") { return } if lock.is_inserted_or_modified() { //TODO MIGRATION - let window = &display.window; + let window = display.window(); window.set_cursor_grab(match lock.0 { true => CursorGrabMode::Confined, false => CursorGrabMode::None, @@ -41,8 +41,7 @@ pub fn lock_cursor_now( pub fn debug_toggle_lock( mut lock: UniqueViewMut, device_events: View, - ren: NonSendSync>, - size: UniqueView, + ren: UniqueView, ) { for evt in device_events.iter() { if let DeviceEvent::Key(RawKeyEvent { @@ -51,8 +50,8 @@ pub fn debug_toggle_lock( }) = evt.event { lock.0 = !lock.0; if !lock.0 { - let center = PhysicalPosition::new(size.0.x as f64 / 2., size.0.y as f64 / 2.); - let _ = ren.window.set_cursor_position(center); + let center = PhysicalPosition::new(ren.size().width as f64 / 2., ren.size().height as f64 / 2.); + let _ = ren.window().set_cursor_position(center); } } } diff --git a/kubi/src/events.rs b/kubi/src/events.rs index fe03a7b..0e8324f 100644 --- a/kubi/src/events.rs +++ b/kubi/src/events.rs @@ -41,7 +41,7 @@ pub fn process_winit_events(world: &mut World, event: &Event<()>) { EventComponent, InputDeviceEvent { device_id: *device_id, - event: DeviceEvent::Key(RawKeyEvent { + event: DeviceEvent::Key(winit::event::RawKeyEvent { physical_key: event.physical_key, state: event.state, }) @@ -86,18 +86,18 @@ pub fn process_winit_events(world: &mut World, event: &Event<()>) { } } -pub fn initial_resize_event( - mut storages: AllStoragesViewMut, -) { - let (w, h) = { - let renderer = storages.borrow::>>().unwrap(); - renderer.display.get_framebuffer_dimensions() - }; - storages.add_entity(( - EventComponent, - WindowResizedEvent(UVec2::new(w, h)) - )); -} +// pub fn initial_resize_event( +// mut storages: AllStoragesViewMut, +// ) { +// let (w, h) = { +// let renderer = storages.borrow::>().unwrap(); +// (renderer.size().width, renderer.size().height) +// }; +// storages.add_entity(( +// EventComponent, +// WindowResizedEvent(UVec2::new(w, h)) +// )); +// } pub fn clear_events( mut all_storages: AllStoragesViewMut, diff --git a/kubi/src/hui_integration.rs b/kubi/src/hui_integration.rs index 28a8583..90cdd30 100644 --- a/kubi/src/hui_integration.rs +++ b/kubi/src/hui_integration.rs @@ -1,21 +1,22 @@ use hui::UiInstance; -use hui_glium::GliumUiRenderer; +use hui_wgpu::WgpuUiRenderer; +//use hui_glium::GliumUiRenderer; use shipyard::{AllStoragesView, Unique, UniqueView, NonSendSync, UniqueViewMut}; -use crate::rendering::{RenderTarget, Renderer, WindowSize}; +use crate::rendering::{RenderCtx, Renderer}; #[derive(Unique)] pub struct UiState { pub hui: UiInstance, - pub renderer: GliumUiRenderer + pub renderer: WgpuUiRenderer, } pub fn kubi_ui_init( storages: AllStoragesView ) { - let renderer = storages.borrow::>>().unwrap(); + let renderer = storages.borrow::>().unwrap(); storages.add_unique_non_send_sync(UiState { hui: UiInstance::new(), - renderer: GliumUiRenderer::new(&renderer.display), + renderer: WgpuUiRenderer::new(renderer.device(), renderer.surface_config().format), }); } @@ -26,20 +27,20 @@ pub fn kubi_ui_begin( } pub fn kubi_ui_end( - mut ui: NonSendSync> + mut ui: NonSendSync>, + renderer: UniqueView, ) { let ui: &mut UiState = &mut ui; - let UiState { hui, renderer, .. } = ui; + let UiState { hui, renderer: ui_renderer } = ui; hui.end(); - renderer.update(hui); + ui_renderer.update(hui, renderer.queue(), renderer.device(), renderer.size_vec2()); } pub fn kubi_ui_draw( + ctx: &mut RenderCtx, ui: NonSendSync>, - mut target: NonSendSync>, - size: UniqueView ) { - ui.renderer.draw(&mut target.0, size.0.as_vec2()); + ui.renderer.draw(ctx.encoder, ctx.surface_view); } pub fn hui_process_winit_events( diff --git a/kubi/src/input.rs b/kubi/src/input.rs index c24081e..1cfcf57 100644 --- a/kubi/src/input.rs +++ b/kubi/src/input.rs @@ -10,7 +10,7 @@ use nohash_hasher::BuildNoHashHasher; use shipyard::{AllStoragesView, Unique, View, IntoIter, UniqueViewMut, Workload, IntoWorkload, UniqueView, NonSendSync}; use crate::{ events::{InputDeviceEvent, TouchEvent}, - rendering::WindowSize + rendering::Renderer, }; #[derive(Unique, Clone, Copy, Default, Debug)] @@ -211,10 +211,10 @@ fn update_input_state_gamepad ( fn update_input_state_touch ( touch_state: UniqueView, - win_size: UniqueView, + renderer: UniqueView, mut inputs: UniqueViewMut, ) { - let w = win_size.0.as_dvec2(); + let w = renderer.size_uvec2().as_dvec2(); //Movement if let Some(finger) = touch_state.query_area( diff --git a/kubi/src/lib.rs b/kubi/src/lib.rs index a401cf7..c5f1c15 100644 --- a/kubi/src/lib.rs +++ b/kubi/src/lib.rs @@ -13,7 +13,7 @@ use shipyard::{ World, Workload, IntoWorkload, UniqueView, UniqueViewMut, - NonSendSync, WorkloadModificator, + WorkloadModificator, SystemModificator }; use winit::{ @@ -58,36 +58,19 @@ pub(crate) mod chat; use world::{ init_game_world, - loading::update_loaded_world_around_player, + loading::update_loaded_world_around_player, raycast::update_raycasts, - queue::apply_queued_blocks, + queue::apply_queued_blocks, tasks::ChunkTaskManager, }; use player::{spawn_player, MainPlayer}; use prefabs::load_prefabs; use settings::{load_settings, GameSettings}; use camera::compute_cameras; -use events::{ - clear_events, - process_winit_events, - initial_resize_event, - player_actions::generate_move_events, -}; +use events::{clear_events, process_winit_events, player_actions::generate_move_events}; use input::{init_input, process_inputs}; use player_controller::{debug_switch_ctl_type, update_player_controllers}; -use rendering::{ - Renderer, - RenderTarget, - BackgroundColor, - clear_background, - init_window_size, - update_window_size, - primitives::init_primitives, - world::{init_trans_chunk_queue, draw_world, draw_world_trans, draw_current_chunk_border}, - selection_box::render_selection_box, - entities::render_entities, - sumberge::render_submerged_view, -}; +use rendering::{BackgroundColor, Renderer, init_rendering, render_master, update_rendering_early, update_rendering_late}; use block_placement::update_block_placement; use delta_time::{DeltaTime, init_delta_time}; use cursor_lock::{debug_toggle_lock, insert_lock_state, lock_cursor_now, update_cursor_lock_state}; @@ -95,7 +78,7 @@ use control_flow::{exit_on_esc, insert_control_flow_unique, RequestExit}; use state::{is_ingame, is_ingame_or_loading, is_loading, init_state, update_state, is_connecting}; use networking::{update_networking, update_networking_late, is_multiplayer, disconnect_on_exit, is_singleplayer}; use init::initialize_from_args; -use hui_integration::{kubi_ui_begin, kubi_ui_draw, kubi_ui_end, kubi_ui_init}; +use hui_integration::{kubi_ui_begin, /*kubi_ui_draw,*/ kubi_ui_end, kubi_ui_init}; use loading_screen::update_loading_screen; use connecting_screen::update_connecting_screen; use fixed_timestamp::init_fixed_timestamp_storage; @@ -105,8 +88,7 @@ use chat_ui::render_chat; use chat::init_chat_manager; use crosshair_ui::{init_crosshair_image, draw_crosshair}; use settings_ui::render_settings_ui; - -use crate::hui_integration::hui_process_winit_events; +use hui_integration::hui_process_winit_events; /// stuff required to init the renderer and other basic systems fn pre_startup() -> Workload { @@ -118,11 +100,9 @@ fn pre_startup() -> Workload { fn startup() -> Workload { ( init_fixed_timestamp_storage, - initial_resize_event, - init_window_size, kubi_ui_init, load_prefabs, - init_primitives, + init_rendering, insert_lock_state, init_state, initialize_from_args, @@ -133,14 +113,13 @@ fn startup() -> Workload { init_client_physics, init_chat_manager, init_crosshair_image, - init_trans_chunk_queue, ).into_sequential_workload() } fn update() -> Workload { ( + update_rendering_early, debug_toggle_lock, - update_window_size, update_cursor_lock_state, process_inputs, kubi_ui_begin, @@ -179,25 +158,26 @@ fn update() -> Workload { update_state, exit_on_esc, disconnect_on_exit.run_if(is_multiplayer), + update_rendering_late, ).into_sequential_workload() } -fn render() -> Workload { - ( - clear_background, - ( - draw_world, - draw_current_chunk_border, - render_selection_box, - render_entities, - draw_world_trans, - render_submerged_view, - ).into_sequential_workload().run_if(is_ingame), - kubi_ui_draw, - ).into_sequential_workload() -} +// fn render() -> Workload { +// ( +// clear_background, +// ( +// draw_world, +// draw_current_chunk_border, +// render_selection_box, +// render_entities, +// draw_world_trans, +// render_submerged_view, +// ).into_sequential_workload().run_if(is_ingame), +// kubi_ui_draw, +// ).into_sequential_workload() +// } -fn after_frame_end() -> Workload { +fn after_render() -> Workload { ( clear_events, ).into_sequential_workload() @@ -245,8 +225,8 @@ pub fn kubi_main( world.add_workload(pre_startup); world.add_workload(startup); world.add_workload(update); - world.add_workload(render); - world.add_workload(after_frame_end); + //world.add_workload(render); + world.add_workload(after_render); //Save _visualizer.json #[cfg(feature = "generate_visualizer_data")] @@ -286,7 +266,7 @@ pub fn kubi_main( let settings = world.borrow::>().unwrap(); world.add_unique_non_send_sync(Renderer::init(window_target, &settings)); } - world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.))); + world.add_unique(BackgroundColor(vec3(0.21, 0.21, 1.))); //Run startup systems world.run_workload(startup).unwrap(); @@ -326,22 +306,24 @@ pub fn kubi_main( //Run update workflows world.run_workload(update).unwrap(); + world.run(render_master); + //Start rendering (maybe use custom views for this?) - let target = { - let renderer = world.borrow::>>().unwrap(); - renderer.display.draw() - }; - world.add_unique_non_send_sync(RenderTarget(target)); + // let target = { + // let renderer = world.borrow::>().unwrap(); + // renderer.display.draw() + // }; + // world.add_unique_non_send_sync(RenderTarget(target)); //Run render workflow - world.run_workload(render).unwrap(); + //world.run_workload(render).unwrap(); //Finish rendering - let target = world.remove_unique::().unwrap(); - target.0.finish().unwrap(); + // let target = world.remove_unique::().unwrap(); + // target.0.finish().unwrap(); //After frame end - world.run_workload(after_frame_end).unwrap(); + world.run_workload(after_render).unwrap(); //Process control flow changes if world.borrow::>().unwrap().0 { diff --git a/kubi/src/prefabs.rs b/kubi/src/prefabs.rs index ac7669e..49b0eac 100644 --- a/kubi/src/prefabs.rs +++ b/kubi/src/prefabs.rs @@ -1,15 +1,35 @@ -use std::{io::{BufReader, Read}, path::Path}; +use std::{io::{BufReader, Read}, path::{Path, PathBuf}}; +use bytemuck::{Pod, Zeroable}; use hui::text::FontHandle; use shipyard::{AllStoragesView, NonSendSync, Unique, UniqueView, UniqueViewMut}; -use glium::{texture::{SrgbTexture2dArray, MipmapsOption}, Program}; use kubi_shared::block::BlockTexture; -use crate::{filesystem::AssetManager, hui_integration::UiState, rendering::Renderer}; +use crate::{filesystem::AssetManager, hui_integration::UiState, rendering::{BufferPair, Renderer}}; -mod texture; -mod shaders; +//TODO move to rendering module -use texture::load_texture2darray_prefab; -use shaders::include_shader_prefab; +mod loader; +use loader::{load_texture2darray_prefab, load_texture2d_prefab, load_obj_prefab}; + +#[derive(Clone, Copy, Default, Pod, Zeroable)] +#[repr(C, packed)] +pub struct ModelVertex { + pub tex_coords: [f32; 2], + pub position: [f32; 3], + pub _padding: u32, + pub normal: [f32; 3], +} + +impl ModelVertex { + pub const LAYOUT: wgpu::VertexBufferLayout<'static> = wgpu::VertexBufferLayout { + array_stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &wgpu::vertex_attr_array![ + 0 => Float32x2, + 1 => Float32x3, + 2 => Float32x3, + ], + }; +} pub trait AssetPaths { fn file_name(self) -> &'static str; @@ -40,20 +60,15 @@ impl AssetPaths for BlockTexture { } #[derive(Unique)] -#[repr(transparent)] -pub struct BlockTexturesPrefab(pub SrgbTexture2dArray); - -#[derive(Unique)] -#[repr(transparent)] -pub struct ChunkShaderPrefab(pub Program); - -#[derive(Unique)] -#[repr(transparent)] -pub struct ColoredShaderPrefab(pub Program); - -#[derive(Unique)] -#[repr(transparent)] -pub struct Colored2ShaderPrefab(pub Program); +pub struct GpuPrefabs { + pub block_diffuse_texture: wgpu::Texture, + pub block_diffuse_bind_group_layout: wgpu::BindGroupLayout, + pub block_diffuse_bind_group: wgpu::BindGroup, + pub player_model_diffuse_texture: wgpu::Texture, + pub player_model_diffuse_bind_group_layout: wgpu::BindGroupLayout, + pub player_model_diffuse_bind_group: wgpu::BindGroup, + pub player_model: BufferPair, +} #[derive(Unique)] #[repr(transparent)] @@ -61,19 +76,132 @@ pub struct UiFontPrefab(pub FontHandle); pub fn load_prefabs( storages: AllStoragesView, - renderer: NonSendSync>, + renderer: UniqueView, mut ui: NonSendSync>, assman: UniqueView ) { log::info!("Loading textures..."); - storages.add_unique_non_send_sync(BlockTexturesPrefab( - load_texture2darray_prefab::( - &assman, - "blocks".into(), - &renderer.display, - MipmapsOption::AutoGeneratedMipmaps - ) - )); + let block_diffuse_texture = load_texture2darray_prefab::( + &renderer, + &assman, + "blocks".into(), + ); + + log::info!("Creating bing groups"); + let block_diffuse_view = block_diffuse_texture.create_view(&wgpu::TextureViewDescriptor { + label: Some("block_texture_view"), + ..Default::default() + }); + let block_diffuse_sampler = renderer.device().create_sampler(&wgpu::SamplerDescriptor { + label: Some("block_diffuse_sampler"), + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Nearest, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::FilterMode::Nearest, + ..Default::default() + }); + let block_diffuse_bind_group_layout = renderer.device() + .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("block_diffuse_bind_group_layout"), + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2Array, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + } + ] + }); + let block_diffuse_bind_group = renderer.device().create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("block_diffuse_bind_group"), + layout: &block_diffuse_bind_group_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&block_diffuse_view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&block_diffuse_sampler), + } + ] + }); + + let player_model_diffuse_texture = load_texture2d_prefab(&renderer, &assman, &PathBuf::from("playermodel1.png")); + let player_model_diffuse_view = player_model_diffuse_texture.create_view(&wgpu::TextureViewDescriptor { + label: Some("player_model_texture_view"), + ..Default::default() + }); + let player_model_diffuse_sampler = renderer.device().create_sampler(&wgpu::SamplerDescriptor { + label: Some("player_model_sampler"), + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::FilterMode::Nearest, + ..Default::default() + }); + let player_model_diffuse_bind_group_layout = renderer.device() + .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("player_model_bind_group_layout"), + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + } + ] + }); + let player_model_diffuse_bind_group = renderer.device().create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("player_model_bind_group"), + layout: &player_model_diffuse_bind_group_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&player_model_diffuse_view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&player_model_diffuse_sampler), + } + ] + }); + + let player_model = load_obj_prefab(&renderer, &assman, &PathBuf::from("playermodel1.obj")); + + storages.add_unique_non_send_sync(GpuPrefabs { + block_diffuse_texture, + block_diffuse_bind_group_layout, + block_diffuse_bind_group, + player_model_diffuse_texture, + player_model_diffuse_bind_group_layout, + player_model_diffuse_bind_group, + player_model, + }); log::info!("Loading the UI stuff..."); { @@ -85,33 +213,33 @@ pub fn load_prefabs( storages.add_unique(UiFontPrefab(font_handle)); } - log::info!("Compiling shaders..."); - storages.add_unique_non_send_sync(ChunkShaderPrefab( - include_shader_prefab!( - "world", - "../shaders/world.vert", - "../shaders/world.frag", - &renderer.display - ) - )); - storages.add_unique_non_send_sync(ColoredShaderPrefab( - include_shader_prefab!( - "colored", - "../shaders/colored.vert", - "../shaders/colored.frag", - &renderer.display - ) - )); - storages.add_unique_non_send_sync(Colored2ShaderPrefab( - include_shader_prefab!( - "colored", - "../shaders/colored2.vert", - "../shaders/colored2.frag", - &renderer.display - ) - )); + //log::info!("Compiling shaders..."); + // storages.add_unique_non_send_sync(ChunkShaderPrefab( + // include_shader_prefab!( + // "world", + // "../shaders/world.vert", + // "../shaders/world.frag", + // &renderer.display + // ) + // )); + // storages.add_unique_non_send_sync(ColoredShaderPrefab( + // include_shader_prefab!( + // "colored", + // "../shaders/colored.vert", + // "../shaders/colored.frag", + // &renderer.display + // ) + // )); + // storages.add_unique_non_send_sync(Colored2ShaderPrefab( + // include_shader_prefab!( + // "colored", + // "../shaders/colored2.vert", + // "../shaders/colored2.frag", + // &renderer.display + // ) + // )); - log::info!("releasing shader compiler"); + //log::info!("releasing shader compiler"); - renderer.display.release_shader_compiler(); + //renderer.display.release_shader_compiler(); } diff --git a/kubi/src/prefabs/loader.rs b/kubi/src/prefabs/loader.rs new file mode 100644 index 0000000..ab11b32 --- /dev/null +++ b/kubi/src/prefabs/loader.rs @@ -0,0 +1,168 @@ +use glam::UVec2; +use strum::IntoEnumIterator; +use rayon::prelude::*; +use wgpu::util::{DeviceExt, TextureDataOrder}; +use std::{io::{BufReader, Read}, path::{Path, PathBuf}}; +use crate::{filesystem::AssetManager, prefabs::ModelVertex, rendering::{BufferPair, Renderer}}; +use super::AssetPaths; + +pub fn load_texture2darray_prefab( + renderer: &Renderer, + assman: &AssetManager, + directory: PathBuf, +) -> wgpu::Texture { + log::info!("started loading {}", directory.as_os_str().to_str().unwrap()); + + //Load raw images + let tex_files: Vec<&'static str> = T::iter().map(|x| x.file_name()).collect(); + let raw_images: Vec<(Vec, UVec2)> = tex_files.par_iter().map(|&file_name| { + log::info!("loading texture {}", file_name); + + //Get path to the image and open the file + let reader = { + let path = directory.join(file_name); + BufReader::new(assman.open_asset(&path).expect("Failed to open texture file")) + }; + + //Parse image data + let (image_data, dimensions) = { + let image = image::load( + reader, + image::ImageFormat::Png + ).unwrap().to_rgba8(); + let dimensions = image.dimensions(); + (image.into_raw(), dimensions) + }; + (image_data, UVec2::from(dimensions)) + }).collect(); + + assert!(!raw_images.is_empty(), "no images loaded"); + //TODO: check same size + + log::info!("done loading texture files, uploading to the gpu"); + + let size = raw_images[0].1; + let layers = raw_images.len() as u32; + + //Concat data into a single vec + let mut data = Vec::with_capacity((size.x * size.y * layers * 4) as usize); + for (layer_data, _) in raw_images { + data.extend_from_slice(&layer_data); + } + + //Upload images to the GPU + let label = format!("texture2darray_prefab_{}", directory.as_os_str().to_str().unwrap()); + let desc = &wgpu::TextureDescriptor { + label: Some(&label), + size: wgpu::Extent3d { + width: size.x, + height: size.y, + depth_or_array_layers: layers, + }, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8UnormSrgb, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, + mip_level_count: 1, + sample_count: 1, + view_formats: &[], + }; + + renderer.device().create_texture_with_data( + renderer.queue(), + desc, + TextureDataOrder::MipMajor, + &data + ) +} + +pub fn load_texture2d_prefab( + renderer: &Renderer, + assman: &AssetManager, + path: &Path, +) -> wgpu::Texture { + log::info!("loading texture2d: {path:?}"); + + let image = image::load( + BufReader::new(assman.open_asset(path).expect("Failed to open texture file")), + image::ImageFormat::Png + ).unwrap().to_rgba8(); + let size = image.dimensions(); + let data = image.into_raw(); + + let label = format!("texture2d_prefab_{}", path.file_name().unwrap().to_str().unwrap()); + let desc = wgpu::TextureDescriptor { + label: Some(&label), + size: wgpu::Extent3d { + width: size.0, + height: size.1, + depth_or_array_layers: 1, + }, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8UnormSrgb, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, + mip_level_count: 1, + sample_count: 1, + view_formats: &[], + }; + + renderer.device().create_texture_with_data( + renderer.queue(), + &desc, + TextureDataOrder::MipMajor, + &data + ) +} + +pub fn load_obj_prefab( + renderer: &Renderer, + assman: &AssetManager, + path: &Path, +) -> BufferPair { + log::info!("loading obj prefab: {path:?}"); + + let mut reader = BufReader::new( + assman.open_asset(path).expect("Failed to open texture file") + ); + + let (model, _) = tobj::load_obj_buf( + &mut reader, + &tobj::GPU_LOAD_OPTIONS, + |_| unimplemented!() + ).unwrap(); + + assert_eq!(model.len(), 1, "only single model supported at the moment, sowwy :3"); + let mesh = &model[0].mesh; + debug_assert!(mesh.normal_indices.is_empty() && mesh.texcoord_indices.is_empty(), "forgor single_index"); + + let tex_coords = bytemuck::cast_slice::(&mesh.texcoords); + let positions = bytemuck::cast_slice::(&mesh.positions); + let normals = bytemuck::cast_slice::(&mesh.normals); + + let vertex_buffer: Vec<_> = (0..positions.len()).map(|i| { + ModelVertex { + tex_coords: [tex_coords[i][0], 1. - tex_coords[i][1]], + position: positions[i], + _padding: 0, + normal: normals[i], + } + }).collect(); + + let vertex_buffer = renderer.device().create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("obj_vertex_buffer"), + contents: bytemuck::cast_slice(&vertex_buffer), + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::VERTEX, + }); + + let index_buffer = renderer.device().create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("obj_index_buffer"), + contents: bytemuck::cast_slice(&mesh.indices), + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::INDEX, + }); + + BufferPair { + vertex: vertex_buffer, + vertex_len: positions.len() as u32, + index: index_buffer, + index_len: mesh.indices.len() as u32, + } +} diff --git a/kubi/src/prefabs/shaders.rs b/kubi/src/prefabs/shaders.rs deleted file mode 100644 index 7496a2f..0000000 --- a/kubi/src/prefabs/shaders.rs +++ /dev/null @@ -1,19 +0,0 @@ -macro_rules! include_shader_prefab { - ($name: literal, $vert: literal, $frag: literal, $facade: expr) => { - { - use ::glium::{Program, program::ProgramCreationInput}; - log::info!("compiling shader {}", $name); - Program::new(&*$facade, ProgramCreationInput::SourceCode { - vertex_shader: include_str!($vert), - fragment_shader: include_str!($frag), - geometry_shader: None, - tessellation_control_shader: None, - tessellation_evaluation_shader: None, - transform_feedback_varyings: None, - outputs_srgb: false, - uses_point_size: false, - }).expect("Failed to compile gpu program") - } - }; -} -pub(crate) use include_shader_prefab; diff --git a/kubi/src/prefabs/texture.rs b/kubi/src/prefabs/texture.rs deleted file mode 100644 index 0bd7e8d..0000000 --- a/kubi/src/prefabs/texture.rs +++ /dev/null @@ -1,46 +0,0 @@ -use strum::IntoEnumIterator; -use rayon::prelude::*; -use std::{path::PathBuf, io::BufReader}; -use glium::{texture::{SrgbTexture2dArray, RawImage2d, MipmapsOption}, backend::Facade}; -use crate::filesystem::AssetManager; -use super::AssetPaths; - -pub fn load_texture2darray_prefab< - T: AssetPaths + IntoEnumIterator, - E: Facade ->( - assman: &AssetManager, - directory: PathBuf, - facade: &E, - mipmaps: MipmapsOption, -) -> SrgbTexture2dArray { - log::info!("started loading {}", directory.as_os_str().to_str().unwrap()); - //Load raw images - let tex_files: Vec<&'static str> = T::iter().map(|x| x.file_name()).collect(); - let raw_images: Vec> = tex_files.par_iter().map(|&file_name| { - log::info!("loading texture {}", file_name); - //Get path to the image and open the file - let reader = { - let path = directory.join(file_name); - BufReader::new(assman.open_asset(&path).expect("Failed to open texture file")) - }; - //Parse image data - let (image_data, dimensions) = { - let image = image::load( - reader, - image::ImageFormat::Png - ).unwrap().to_rgba8(); - let dimensions = image.dimensions(); - (image.into_raw(), dimensions) - }; - //Create a glium RawImage - RawImage2d::from_raw_rgba_reversed( - &image_data, - dimensions - ) - }).collect(); - log::info!("done loading texture files, uploading to the gpu"); - //Upload images to the GPU - SrgbTexture2dArray::with_mipmaps(facade, raw_images, mipmaps) - .expect("Failed to upload texture array to GPU") -} diff --git a/kubi/src/rendering.rs b/kubi/src/rendering.rs index 7ad278b..288627b 100644 --- a/kubi/src/rendering.rs +++ b/kubi/src/rendering.rs @@ -1,191 +1,106 @@ -use std::num::NonZeroU32; -use raw_window_handle::HasRawWindowHandle; -use shipyard::{Unique, NonSendSync, UniqueView, UniqueViewMut, View, IntoIter, AllStoragesView}; -use winit::{ - event_loop::EventLoopWindowTarget, - window::{WindowBuilder, Fullscreen, Window}, - dpi::PhysicalSize -}; -use glium::{Display, Surface, Version, Api as GlApiTy}; -use glutin::{ - config::{Api, ConfigTemplateBuilder}, context::{ContextAttributesBuilder, GlProfile}, display::GetGlDisplay, prelude::*, surface::{SurfaceAttributesBuilder, WindowSurface} -}; -use glutin_winit::DisplayBuilder; -use glam::{Vec3, UVec2}; -use crate::{events::WindowResizedEvent, settings::{GameSettings, FullscreenMode}}; +use shipyard::{AllStoragesViewMut, IntoIter, IntoWorkload, SystemModificator, Unique, UniqueView, UniqueViewMut, View, Workload, WorkloadModificator}; +use winit::dpi::PhysicalSize; +use glam::Vec3; +use crate::{events::WindowResizedEvent, hui_integration::kubi_ui_draw, state::is_ingame}; -pub mod primitives; +mod renderer; +mod primitives; +mod selection_box; +mod entities; +pub use renderer::Renderer; + +pub mod background; pub mod world; -pub mod selection_box; -pub mod entities; -pub mod sumberge; +pub mod camera_uniform; +pub mod depth; +pub mod smoverlay; + +pub struct BufferPair { + pub index: wgpu::Buffer, + pub index_len: u32, + pub vertex: wgpu::Buffer, + pub vertex_len: u32, +} #[derive(Unique)] -#[repr(transparent)] -pub struct RenderTarget(pub glium::Frame); - -#[derive(Unique)] -#[repr(transparent)] pub struct BackgroundColor(pub Vec3); -#[derive(Unique, Clone, Copy)] -#[repr(transparent)] -pub struct WindowSize(pub UVec2); - -#[derive(Unique)] -pub struct Renderer { - pub window: Window, - pub display: Display, +pub struct RenderCtx<'a> { + //pub renderer: &'a Renderer, + pub encoder: &'a mut wgpu::CommandEncoder, + pub surface_view: &'a wgpu::TextureView, } -impl Renderer { - pub fn init(event_loop: &EventLoopWindowTarget<()>, settings: &GameSettings) -> Self { - log::info!("initializing display"); +//TODO run init_world_render_state, init_selection_box_state, etc. only once ingame? - let wb = WindowBuilder::new() - .with_title("kubi") - .with_maximized(true) - .with_min_inner_size(PhysicalSize::new(640, 480)) - .with_fullscreen({ - //this has no effect on android, so skip this pointless stuff - #[cfg(target_os = "android")] { - None - } - #[cfg(not(target_os = "android"))] - if let Some(fs_settings) = &settings.fullscreen { - let monitor = event_loop.primary_monitor().or_else(|| { - event_loop.available_monitors().next() - }); - if let Some(monitor) = monitor { - log::info!("monitor: {}", monitor.name().unwrap_or_else(|| "generic".into())); - match fs_settings.mode { - FullscreenMode::Borderless => { - log::info!("starting in borderless fullscreen mode"); - Some(Fullscreen::Borderless(Some(monitor))) - }, - FullscreenMode::Exclusive => { - log::warn!("exclusive fullscreen mode is experimental"); - log::info!("starting in exclusive fullscreen mode"); - //TODO: grabbing the first video mode is probably not the best idea... - monitor.video_modes().next() - .map(|vmode| { - log::info!("video mode: {}", vmode.to_string()); - Some(Fullscreen::Exclusive(vmode)) - }) - .unwrap_or_else(|| { - log::warn!("no valid video modes found, falling back to windowed mode instead"); - None - }) - } - } - } else { - log::warn!("no monitors found, falling back to windowed mode"); - None - } - } else { - log::info!("starting in windowed mode"); - None - } - }); +pub fn init_rendering() -> Workload { + ( + depth::init_depth_texture, + camera_uniform::init_camera_uniform_buffer, + primitives::init_primitives, + world::init_world_render_state, //req: depth, camera + entities::init_entities_render_state, //req: depth, camera + selection_box::init_selection_box_render_state, //req: depth, camera, primitives + smoverlay::init_smoverlay_render_state, //req: primitives + ).into_sequential_workload() +} - let display_builder = DisplayBuilder::new() - .with_window_builder(Some(wb)); +pub fn update_rendering_early() -> Workload { + ( + resize_renderer, + depth::resize_depth_texture, + ).into_sequential_workload() +} - let config_template_builder = ConfigTemplateBuilder::new() - .with_api(Api::GLES3) - .prefer_hardware_accelerated(Some(true)) - .with_depth_size(24) - .with_multisampling(settings.msaa.unwrap_or_default()); +pub fn update_rendering_late() -> Workload { + ( + camera_uniform::update_camera_uniform_buffer, + ( + selection_box::update_selection_box_render_state, + entities::update_entities_render_state, + smoverlay::update_smoverlay_render_state, + ).into_workload().run_if(is_ingame), + ).into_workload() +} - let (window, gl_config) = display_builder - .build(event_loop, config_template_builder, |mut configs| { - configs.next().unwrap() - }) - .unwrap(); +pub fn render_master(storages: AllStoragesViewMut) { + let renderer = storages.borrow::>().unwrap(); - let window = window.expect("no window"); + let mut encoder = renderer.device().create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("main_encoder"), + }); + let surface_texture = renderer.surface().get_current_texture().unwrap(); + let surface_view = surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default()); - // Now we get the window size to use as the initial size of the Surface - let (width, height): (u32, u32) = window.inner_size().into(); - let attrs = SurfaceAttributesBuilder::::new().build( - window.raw_window_handle(), - NonZeroU32::new(width).unwrap(), - NonZeroU32::new(height).unwrap(), - ); + let mut data = RenderCtx { + encoder: &mut encoder, + surface_view: &surface_view, + }; - // Finally we can create a Surface, use it to make a PossiblyCurrentContext and create the glium Display - let surface = unsafe { - gl_config.display().create_window_surface(&gl_config, &attrs).unwrap() - }; + storages.run_with_data(background::clear_bg, &mut data); + if storages.run(is_ingame) { + storages.run_with_data(world::draw_world, &mut data); + storages.run_with_data(selection_box::draw_selection_box, &mut data); + storages.run_with_data(entities::render_entities, &mut data); + storages.run_with_data(world::rpass_submit_trans_bundle, &mut data); + storages.run_with_data(smoverlay::render_submerged_view, &mut data); + } + storages.run_with_data(kubi_ui_draw, &mut data); - let context_attributes = ContextAttributesBuilder::new() - .with_debug(cfg!(debug_assertions)) - .with_context_api(glutin::context::ContextApi::Gles(None)) - .with_profile(GlProfile::Core) - .build(Some(window.raw_window_handle())); + renderer.queue().submit([encoder.finish()]); + surface_texture.present(); +} - let current_context = unsafe { - gl_config.display() - .create_context(&gl_config, &context_attributes) - .expect("failed to create context") - }.make_current(&surface).unwrap(); - - let display = Display::from_context_surface(current_context, surface).unwrap(); - - //TODO MIGRATION - // let cb = ContextBuilder::new() - // //.with_srgb(false) - // .with_depth_buffer(24) - // .with_multisampling(settings.msaa.unwrap_or_default()) - // .with_vsync(settings.vsync) - // .with_gl_profile(GlProfile::Core) - // .with_gl(GlRequest::Latest); - - // let display = Display::new(wb, cb) - // .expect("Failed to create a glium Display"); - - log::info!("Vendor: {}", display.get_opengl_vendor_string()); - log::info!("Renderer: {}", display.get_opengl_renderer_string()); - log::info!("OpenGL: {}", display.get_opengl_version_string()); - log::info!("Supports GLSL: {:?}", display.get_supported_glsl_version()); - log::info!("Framebuffer dimensions: {:?}", display.get_framebuffer_dimensions()); - if display.is_context_loss_possible() { log::warn!("OpenGL context loss possible") } - if display.is_robust() { log::warn!("OpenGL implementation is not robust") } - if display.is_debug() { log::info!("OpenGL context is in debug mode") } - - assert!(display.is_glsl_version_supported(&Version(GlApiTy::GlEs, 3, 0)), "GLSL ES 3.0 is not supported"); - - Self { window, display } +/// Resize the renderer when the window is resized +pub fn resize_renderer( + mut renderer: UniqueViewMut, + resize: View, +) { + if let Some(size) = resize.iter().last() { + renderer.resize(PhysicalSize::new(size.0.x, size.0.y)); } } -pub fn clear_background( - mut target: NonSendSync>, - color: UniqueView, -) { - target.0.clear_color_srgb_and_depth((color.0.x, color.0.y, color.0.z, 1.), 1.); -} - -//not sure if this belongs here - -pub fn init_window_size( - storages: AllStoragesView, -) { - let size = storages.borrow::>().unwrap().iter().next().unwrap().0; - storages.add_unique(WindowSize(size)) -} - -pub fn update_window_size( - mut win_size: UniqueViewMut, - resize: View, -) { - if let Some(resize) = resize.iter().next() { - win_size.0 = resize.0; - } -} - -pub fn if_resized ( - resize: View, -) -> bool { - resize.len() > 0 -} +// pub fn if_resized (resize: View,) -> bool { +// resize.len() > 0 +// } diff --git a/kubi/src/rendering/background.rs b/kubi/src/rendering/background.rs new file mode 100644 index 0000000..29240d2 --- /dev/null +++ b/kubi/src/rendering/background.rs @@ -0,0 +1,25 @@ +use shipyard::UniqueView; +use super::{BackgroundColor, RenderCtx}; + +pub fn clear_bg( + ctx: &mut RenderCtx, + bg: UniqueView, +) { + let _rpass = ctx.encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("clear_bg"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: ctx.surface_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: bg.0.x as f64, + g: bg.0.y as f64, + b: bg.0.z as f64, + a: 1.0, + }), + store: wgpu::StoreOp::Store, + }, + })], + ..Default::default() + }); +} diff --git a/kubi/src/rendering/camera_uniform.rs b/kubi/src/rendering/camera_uniform.rs new file mode 100644 index 0000000..1d18bcd --- /dev/null +++ b/kubi/src/rendering/camera_uniform.rs @@ -0,0 +1,81 @@ +use bytemuck::{Pod, Zeroable}; +use shipyard::{AllStoragesView, IntoIter, Unique, UniqueView, View}; +use wgpu::util::DeviceExt; +use crate::camera::Camera; +use super::Renderer; + +#[derive(Debug, Clone, Copy, Default, Pod, Zeroable)] +#[repr(C, packed)] +pub struct CameraUniformData { + pub view_proj: [f32; 4 * 4], +} + +//TODO if multiple cameras, buffer per camera +#[derive(Unique)] +pub struct CameraUniformBuffer { + pub camera_uniform_buffer: wgpu::Buffer, + pub camera_bind_group_layout: wgpu::BindGroupLayout, + pub camera_bind_group: wgpu::BindGroup, +} + +impl CameraUniformBuffer { + pub fn init(renderer: &Renderer, data: CameraUniformData) -> Self { + let camera_uniform_buffer = renderer.device().create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("camera_uniform_buffer"), + contents: bytemuck::cast_slice(&[data]), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }); + + let camera_bind_group_layout = renderer.device().create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("camera_bind_group_layout"), + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, + ], + }); + + let camera_bind_group = renderer.device().create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("camera_bind_group"), + layout: &camera_bind_group_layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: camera_uniform_buffer.as_entire_binding(), + }, + ], + }); + + Self { camera_uniform_buffer, camera_bind_group_layout, camera_bind_group } + } + + pub fn init_default(renderer: &Renderer) -> Self { + Self::init(renderer, CameraUniformData::default()) + } + + pub fn update(&self, renderer: &Renderer, data: CameraUniformData) { + renderer.queue().write_buffer(&self.camera_uniform_buffer, 0, bytemuck::cast_slice(&[data])); + } +} + +pub fn init_camera_uniform_buffer(storages: AllStoragesView) { + let renderer = storages.borrow::>().unwrap(); + storages.add_unique(CameraUniformBuffer::init_default(&renderer)); +} + +pub fn update_camera_uniform_buffer( + renderer: UniqueView, + camera_uniform_buffer: UniqueView, + camera: View, +) { + let Some(camera) = camera.iter().next() else { return }; + let proj = camera.perspective_matrix * camera.view_matrix; + camera_uniform_buffer.update(&renderer, CameraUniformData { view_proj: proj.to_cols_array() }); +} diff --git a/kubi/src/rendering/depth.rs b/kubi/src/rendering/depth.rs new file mode 100644 index 0000000..830b10c --- /dev/null +++ b/kubi/src/rendering/depth.rs @@ -0,0 +1,72 @@ +use glam::{uvec2, UVec2}; +use shipyard::{AllStoragesView, Unique, UniqueView, UniqueViewMut}; + +use super::Renderer; + +#[derive(Unique)] +pub struct DepthTexture { + pub depth_texture: wgpu::Texture, + pub depth_view: wgpu::TextureView, + pub depth_sampler: wgpu::Sampler, +} + +impl DepthTexture { + fn desc(size: UVec2) -> wgpu::TextureDescriptor<'static> { + wgpu::TextureDescriptor { + label: Some("depth_texture"), + size: wgpu::Extent3d { + width: size.x, + height: size.y, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Depth32Float, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[wgpu::TextureFormat::Depth32Float], + } + } + + pub fn init(renderer: &Renderer) -> Self { + let size = uvec2(renderer.size().width, renderer.size().height); + let depth_texture_desc = Self::desc(size); + let depth_texture = renderer.device().create_texture(&depth_texture_desc); + let depth_view = depth_texture.create_view(&wgpu::TextureViewDescriptor::default()); + let depth_sampler = renderer.device().create_sampler(&wgpu::SamplerDescriptor { + label: Some("depth_sampler"), + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Nearest, + min_filter: wgpu::FilterMode::Nearest, + mipmap_filter: wgpu::FilterMode::Nearest, + compare: Some(wgpu::CompareFunction::LessEqual), + ..Default::default() + }); + Self { depth_texture, depth_view, depth_sampler } + } + + pub fn resize(&mut self, renderer: &Renderer) { + let old_size = uvec2(self.depth_texture.size().width, self.depth_texture.size().height); + let new_size = uvec2(renderer.size().width, renderer.size().height); + if old_size == new_size { return } + let depth_texture_desc = Self::desc(new_size); + self.depth_texture = renderer.device().create_texture(&depth_texture_desc); + self.depth_view = self.depth_texture.create_view(&wgpu::TextureViewDescriptor::default()); + } +} + +pub fn init_depth_texture( + storages: AllStoragesView, +) { + let renderer = storages.borrow::>().unwrap(); + storages.add_unique(DepthTexture::init(&renderer)); +} + +pub fn resize_depth_texture( + mut depth_texture: UniqueViewMut, + renderer: UniqueView, +) { + depth_texture.resize(&renderer); +} diff --git a/kubi/src/rendering/entities.rs b/kubi/src/rendering/entities.rs index 0135edf..84865cf 100644 --- a/kubi/src/rendering/entities.rs +++ b/kubi/src/rendering/entities.rs @@ -1,58 +1,67 @@ -use shipyard::{NonSendSync, UniqueViewMut, UniqueView, View, IntoIter, IntoWithId}; -use glium::{DepthTest, Depth, PolygonMode, BackfaceCullingMode, DrawParameters, Surface, uniform}; -use kubi_shared::{entity::Entity, transform::Transform}; -use crate::{ - prefabs::ColoredShaderPrefab, - camera::Camera, - settings::GameSettings -}; -use super::{ - RenderTarget, - primitives::cube::CenteredCubePrimitive -}; - -// TODO: entity models -pub fn render_entities( - mut target: NonSendSync>, - buffers: NonSendSync>, - program: NonSendSync>, - camera: View, - settings: UniqueView, - entities: View, - transform: View, -) { - let (camera_id, camera) = camera.iter().with_id().next().expect("No cameras in the scene"); - - let draw_parameters = DrawParameters { - depth: Depth { - test: DepthTest::IfLess, - write: true, - ..Default::default() - }, - multisampling: settings.msaa.is_some(), - polygon_mode: PolygonMode::Fill, - backface_culling: BackfaceCullingMode::CullClockwise, - ..Default::default() - }; - let view = camera.view_matrix.to_cols_array_2d(); - let perspective = camera.perspective_matrix.to_cols_array_2d(); - - for (entity_id, (_, trans)) in (&entities, &transform).iter().with_id() { - //skip rendering camera holder (as the entity would block the view) - if entity_id == camera_id { continue } - - //render entity - target.0.draw( - &buffers.0, - &buffers.1, - &program.0, - &uniform! { - color: [1.0, 1.0, 1.0, 1.0_f32], - model: trans.0.to_cols_array_2d(), - view: view, - perspective: perspective, - }, - &draw_parameters - ).unwrap(); - } -} +use shipyard::{AllStoragesView, IntoIter, IntoWithId, Unique, UniqueView, View}; +use kubi_shared::{entity::Entity, transform::Transform}; +use crate::{ + camera::Camera, prefabs::GpuPrefabs, settings::GameSettings +}; + +use super::{camera_uniform::CameraUniformBuffer, depth::DepthTexture, RenderCtx}; + +mod instance; +mod pipeline; + +#[derive(Unique)] +pub struct EntitiesRenderState { + pub pipeline: wgpu::RenderPipeline, + pub instance_buffer: instance::InstanceBuffer, +} + +pub fn init_entities_render_state(storages: AllStoragesView) { + storages.add_unique(EntitiesRenderState { + pipeline: storages.run(pipeline::init_entities_pipeline), + instance_buffer: storages.run(instance::create_instance_buffer), + }); +} + +pub use instance::update_instance_buffer as update_entities_render_state; + +// TODO: entity models +pub fn render_entities( + ctx: &mut RenderCtx, + state: UniqueView, + depth: UniqueView, + prefabs: UniqueView, + camera_ubo: UniqueView, +) { + if state.instance_buffer.count == 0 { + return + } + + let mut rpass = ctx.encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("rpass_draw_entities"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: ctx.surface_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &depth.depth_view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, + }), + stencil_ops: None, + }), + ..Default::default() + }); + + rpass.set_pipeline(&state.pipeline); + rpass.set_bind_group(0, &prefabs.player_model_diffuse_bind_group, &[]); + rpass.set_bind_group(1, &camera_ubo.camera_bind_group, &[]); + rpass.set_vertex_buffer(0, prefabs.player_model.vertex.slice(..)); + rpass.set_vertex_buffer(1, state.instance_buffer.buffer.slice(..)); + rpass.set_index_buffer(prefabs.player_model.index.slice(..), wgpu::IndexFormat::Uint32); + rpass.draw_indexed(0..prefabs.player_model.index_len, 0, 0..state.instance_buffer.count); +} diff --git a/kubi/src/rendering/entities/instance.rs b/kubi/src/rendering/entities/instance.rs new file mode 100644 index 0000000..6ad7226 --- /dev/null +++ b/kubi/src/rendering/entities/instance.rs @@ -0,0 +1,78 @@ +use bytemuck::{Pod, Zeroable}; +use kubi_shared::{entity::Entity, transform::Transform}; +use renderer::Renderer; +use shipyard::{EntityId, IntoIter, IntoWithId, UniqueView, UniqueViewMut, View}; + +use crate::{camera::Camera, rendering::renderer}; + +use super::EntitiesRenderState; + +#[derive(Clone, Copy, Pod, Zeroable)] +#[repr(C, packed)] +pub struct InstanceData { + pub mat: [f32; 4 * 4], +} + +impl InstanceData { + pub const LAYOUT: wgpu::VertexBufferLayout<'static> = wgpu::VertexBufferLayout { + array_stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Instance, + attributes: &wgpu::vertex_attr_array![ + 3 => Float32x4, + 4 => Float32x4, + 5 => Float32x4, + 6 => Float32x4, + ], + }; +} + +pub struct InstanceBuffer { + pub count: u32, + pub buffer: wgpu::Buffer, +} + +pub fn create_instance_buffer( + renderer: UniqueView, +) -> InstanceBuffer { + log::info!("entities: create_instance_buffer"); + let buffer = renderer.device().create_buffer(&wgpu::BufferDescriptor { + label: Some("instance_buffer"), + size: 255 * std::mem::size_of::() as u64, + usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + InstanceBuffer { count: 0, buffer } +} + +pub fn update_instance_buffer( + renderer: UniqueView, + mut state: UniqueViewMut, + entities: View, + transforms: View, + camera: View, +) { + //Get id of the camera entity (this assumes a single camera entity) + let cam_id = (&camera) + .iter().with_id().next() + .map(|(x, _)| x) + .unwrap_or(EntityId::dead()); + + // Create a list of instance data for all entities except ones that have camera attached + let mut instances = Vec::with_capacity(entities.len() - 1); + for (id, (_, trans)) in (&entities, &transforms).iter().with_id() { + if id == cam_id { continue } + instances.push(InstanceData { + mat: trans.0.to_cols_array(), + }); + } + + state.instance_buffer.count = instances.len() as u32; + + if !instances.is_empty() { + renderer.queue().write_buffer( + &state.instance_buffer.buffer, + 0, + bytemuck::cast_slice(&instances) + ); + } +} diff --git a/kubi/src/rendering/entities/pipeline.rs b/kubi/src/rendering/entities/pipeline.rs new file mode 100644 index 0000000..bacc587 --- /dev/null +++ b/kubi/src/rendering/entities/pipeline.rs @@ -0,0 +1,66 @@ +use shipyard::UniqueView; +use wgpu::include_wgsl; +use crate::{prefabs::{GpuPrefabs, ModelVertex}, rendering::{camera_uniform::CameraUniformBuffer, Renderer}}; + +use super::instance::InstanceData; + +pub fn init_entities_pipeline( + renderer: UniqueView, + prefabs: UniqueView, + camera_ubo: UniqueView, +) -> wgpu::RenderPipeline { + log::info!("init_entities_pipeline"); + + let module = renderer.device().create_shader_module(include_wgsl!("../../../shaders/entities.wgsl")); + + let pipeline_layout = renderer.device().create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("entities_pipeline_layout"), + bind_group_layouts: &[ + &prefabs.player_model_diffuse_bind_group_layout, + &camera_ubo.camera_bind_group_layout, + ], + push_constant_ranges: &[], + }); + + renderer.device().create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("entities_pipeline"), + layout: Some(&pipeline_layout), + vertex: wgpu::VertexState { + module: &module, + compilation_options: wgpu::PipelineCompilationOptions::default(), + entry_point: "vs_main", + buffers: &[ + ModelVertex::LAYOUT, + InstanceData::LAYOUT, + ], + }, + fragment: Some(wgpu::FragmentState { + module: &module, + compilation_options: wgpu::PipelineCompilationOptions::default(), + entry_point: "fs_main", + targets: &[Some(wgpu::ColorTargetState { + format: renderer.surface_config().format, + blend: Some(wgpu::BlendState::REPLACE), + write_mask: wgpu::ColorWrites::COLOR, + })], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: None, // Some(wgpu::Face::Back), //XXX: this culls their majestic ears! :( + polygon_mode: wgpu::PolygonMode::Fill, + conservative: false, + unclipped_depth: false, + }, + depth_stencil: Some(wgpu::DepthStencilState { + format: wgpu::TextureFormat::Depth32Float, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::Less, + bias: wgpu::DepthBiasState::default(), + stencil: wgpu::StencilState::default(), + }), + multisample: wgpu::MultisampleState::default(), + multiview: None, + }) +} diff --git a/kubi/src/rendering/primitives.rs b/kubi/src/rendering/primitives.rs index 26666bd..457bace 100644 --- a/kubi/src/rendering/primitives.rs +++ b/kubi/src/rendering/primitives.rs @@ -1,30 +1,42 @@ -use shipyard::{Workload, IntoWorkload}; -use glium::implement_vertex; +use bytemuck::{Pod, Zeroable}; +use shipyard::{IntoWorkload, Workload}; -pub mod cube; -pub mod rect; -pub mod stri; - -use cube::init_cube_primitive; -use rect::init_rect_primitive; -use stri::init_stri_primitive; - -#[derive(Clone, Copy, Default)] -pub struct PositionOnlyVertex { - pub position: [f32; 3], -} -implement_vertex!(PositionOnlyVertex, position); - -#[derive(Clone, Copy, Default)] -pub struct PositionOnlyVertex2d { - pub position: [f32; 2], -} -implement_vertex!(PositionOnlyVertex2d, position); +mod cube; +mod fstri; +pub use cube::CubePrimitive; +pub use fstri::FstriPrimitive; pub fn init_primitives() -> Workload { ( - init_cube_primitive, - init_rect_primitive, - init_stri_primitive, + cube::init_cube_primitive, + fstri::init_fstri_primitive, ).into_workload() } + +#[derive(Clone, Copy, Default, Pod, Zeroable)] +#[repr(C, packed)] +pub struct PrimitiveVertex { + pub position: [f32; 3], +} + +impl PrimitiveVertex { + pub const LAYOUT: wgpu::VertexBufferLayout<'static> = wgpu::VertexBufferLayout { + array_stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &wgpu::vertex_attr_array![0 => Float32x3], + }; +} + +#[derive(Clone, Copy, Default, Pod, Zeroable)] +#[repr(C, packed)] +pub struct PrimitiveVertex2 { + pub position: [f32; 2], +} + +impl PrimitiveVertex2 { + pub const LAYOUT: wgpu::VertexBufferLayout<'static> = wgpu::VertexBufferLayout { + array_stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &wgpu::vertex_attr_array![0 => Float32x2], + }; +} diff --git a/kubi/src/rendering/primitives/cube.rs b/kubi/src/rendering/primitives/cube.rs index 20f8616..ff74e96 100644 --- a/kubi/src/rendering/primitives/cube.rs +++ b/kubi/src/rendering/primitives/cube.rs @@ -1,85 +1,50 @@ -use shipyard::{AllStoragesView, NonSendSync, UniqueView, Unique}; -use glium::{VertexBuffer, IndexBuffer, index::PrimitiveType}; -use crate::rendering::Renderer; -use super::PositionOnlyVertex; - -#[derive(Unique)] -pub struct CubePrimitive(pub VertexBuffer, pub IndexBuffer); - -#[derive(Unique)] -pub struct CenteredCubePrimitive(pub VertexBuffer, pub IndexBuffer); - -const CENTERED_CUBE_VERTICES: &[PositionOnlyVertex] = &[ - // front - PositionOnlyVertex { position: [-0.5, -0.5, 0.5] }, - PositionOnlyVertex { position: [ 0.5, -0.5, 0.5] }, - PositionOnlyVertex { position: [ 0.5, 0.5, 0.5] }, - PositionOnlyVertex { position: [-0.5, 0.5, 0.5] }, - // back - PositionOnlyVertex { position: [-0.5, -0.5, -0.5] }, - PositionOnlyVertex { position: [ 0.5, -0.5, -0.5] }, - PositionOnlyVertex { position: [ 0.5, 0.5, -0.5] }, - PositionOnlyVertex { position: [-0.5, 0.5, -0.5] }, -]; -const CUBE_VERTICES: &[PositionOnlyVertex] = &[ - // front - PositionOnlyVertex { position: [0.0, 0.0, 1.0] }, - PositionOnlyVertex { position: [1.0, 0.0, 1.0] }, - PositionOnlyVertex { position: [1.0, 1.0, 1.0] }, - PositionOnlyVertex { position: [0.0, 1.0, 1.0] }, - // back - PositionOnlyVertex { position: [0.0, 0.0, 0.0] }, - PositionOnlyVertex { position: [1.0, 0.0, 0.0] }, - PositionOnlyVertex { position: [1.0, 1.0, 0.0] }, - PositionOnlyVertex { position: [0.0, 1.0, 0.0] }, -]; -const CUBE_INDICES: &[u16] = &[ - // front - 0, 1, 2, - 2, 3, 0, - // right - 1, 5, 6, - 6, 2, 1, - // back - 7, 6, 5, - 5, 4, 7, - // left - 4, 0, 3, - 3, 7, 4, - // bottom - 4, 5, 1, - 1, 0, 4, - // top - 3, 2, 6, - 6, 7, 3 -]; - -pub(super) fn init_cube_primitive( - storages: AllStoragesView, - display: NonSendSync> -) { - { - let vert = VertexBuffer::immutable( - &display.display, - CUBE_VERTICES - ).unwrap(); - let index = IndexBuffer::immutable( - &display.display, - PrimitiveType::TrianglesList, - CUBE_INDICES - ).unwrap(); - storages.add_unique_non_send_sync(CubePrimitive(vert, index)); - } - { - let vert = VertexBuffer::immutable( - &display.display, - CENTERED_CUBE_VERTICES - ).unwrap(); - let index = IndexBuffer::immutable( - &display.display, - PrimitiveType::TrianglesList, - CUBE_INDICES - ).unwrap(); - storages.add_unique_non_send_sync(CenteredCubePrimitive(vert, index)); - } -} +use shipyard::{AllStoragesView, Unique, UniqueView}; +use wgpu::util::DeviceExt; +use crate::rendering::{BufferPair, Renderer}; +use super::PrimitiveVertex; + +#[derive(Unique)] +pub struct CubePrimitive(pub BufferPair); + +/// Vertices for a centered cube with a side length of 1 +const CUBE_VERTICES: &[PrimitiveVertex] = &[ + // front + PrimitiveVertex { position: [-0.5, -0.5, 0.5] }, + PrimitiveVertex { position: [ 0.5, -0.5, 0.5] }, + PrimitiveVertex { position: [ 0.5, 0.5, 0.5] }, + PrimitiveVertex { position: [-0.5, 0.5, 0.5] }, + // back + PrimitiveVertex { position: [-0.5, -0.5, -0.5] }, + PrimitiveVertex { position: [ 0.5, -0.5, -0.5] }, + PrimitiveVertex { position: [ 0.5, 0.5, -0.5] }, + PrimitiveVertex { position: [-0.5, 0.5, -0.5] }, +]; + +/// Indices for a cube primitive +const CUBE_INDICES: &[u16] = &[ + 0, 1, 2, 2, 3, 0, // front + 1, 5, 6, 6, 2, 1, // right + 7, 6, 5, 5, 4, 7, // back + 4, 0, 3, 3, 7, 4, // left + 4, 5, 1, 1, 0, 4, // bottom + 3, 2, 6, 6, 7, 3, // top +]; + +pub fn init_cube_primitive(storages: AllStoragesView) { + log::info!("init_cube_primitive"); + let renderer = storages.borrow::>().unwrap(); + storages.add_unique(CubePrimitive(BufferPair { + index: renderer.device().create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("cube_index_buffer"), + contents: bytemuck::cast_slice(CUBE_INDICES), + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::INDEX, + }), + index_len: CUBE_INDICES.len() as u32, + vertex: renderer.device().create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("cube_vertex_buffer"), + contents: bytemuck::cast_slice(CUBE_VERTICES), + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::VERTEX, + }), + vertex_len: CUBE_VERTICES.len() as u32, + })); +} diff --git a/kubi/src/rendering/primitives/fstri.rs b/kubi/src/rendering/primitives/fstri.rs new file mode 100644 index 0000000..7e22d5f --- /dev/null +++ b/kubi/src/rendering/primitives/fstri.rs @@ -0,0 +1,24 @@ +use shipyard::{AllStoragesView, Unique, UniqueView}; +use wgpu::util::DeviceExt; +use crate::rendering::Renderer; +use super::PrimitiveVertex2; + +pub const FSTRI_VERTICES: &[PrimitiveVertex2] = &[ + PrimitiveVertex2 { position: [-1.0, -1.0] }, + PrimitiveVertex2 { position: [ 3.0, -1.0] }, + PrimitiveVertex2 { position: [-1.0, 3.0] }, +]; + +#[derive(Unique)] +pub struct FstriPrimitive(pub wgpu::Buffer); + +pub fn init_fstri_primitive(storages: AllStoragesView) { + log::info!("init_fstri_primitive"); + let renderer = storages.borrow::>().unwrap(); + let buffer = renderer.device().create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("fstri_vertex_buffer"), + contents: bytemuck::cast_slice(FSTRI_VERTICES), + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::VERTEX, + }); + storages.add_unique(FstriPrimitive(buffer)); +} diff --git a/kubi/src/rendering/primitives/rect.rs b/kubi/src/rendering/primitives/rect.rs deleted file mode 100644 index 3a30575..0000000 --- a/kubi/src/rendering/primitives/rect.rs +++ /dev/null @@ -1,31 +0,0 @@ -use shipyard::{Unique, AllStoragesView, NonSendSync, UniqueView}; -use glium::{VertexBuffer, IndexBuffer, index::PrimitiveType}; -use crate::rendering::Renderer; -use super::PositionOnlyVertex2d; - -#[derive(Unique)] -pub struct RectPrimitive(pub VertexBuffer, pub IndexBuffer); - -const RECT_VERTEX: &[PositionOnlyVertex2d] = &[ - PositionOnlyVertex2d { position: [0., 0.] }, - PositionOnlyVertex2d { position: [1., 0.] }, - PositionOnlyVertex2d { position: [0., 1.] }, - PositionOnlyVertex2d { position: [1., 1.] }, -]; -const RECT_INDEX: &[u16] = &[0, 1, 2, 1, 3, 2]; - -pub(super) fn init_rect_primitive( - storages: AllStoragesView, - display: NonSendSync> -) { - let vert = VertexBuffer::immutable( - &display.display, - RECT_VERTEX - ).unwrap(); - let index = IndexBuffer::immutable( - &display.display, - PrimitiveType::TrianglesList, - RECT_INDEX - ).unwrap(); - storages.add_unique_non_send_sync(RectPrimitive(vert, index)); -} diff --git a/kubi/src/rendering/primitives/stri.rs b/kubi/src/rendering/primitives/stri.rs deleted file mode 100644 index dbc5c40..0000000 --- a/kubi/src/rendering/primitives/stri.rs +++ /dev/null @@ -1,30 +0,0 @@ -use shipyard::{Unique, AllStoragesView, NonSendSync, UniqueView}; -use glium::{VertexBuffer, IndexBuffer, index::PrimitiveType}; -use crate::rendering::Renderer; -use super::PositionOnlyVertex2d; - -#[derive(Unique)] -pub struct STriPrimitive(pub VertexBuffer, pub IndexBuffer); - -const STRI_VERTEX: &[PositionOnlyVertex2d] = &[ - PositionOnlyVertex2d { position: [-1., -1.] }, - PositionOnlyVertex2d { position: [ 3., -1.] }, - PositionOnlyVertex2d { position: [-1., 3.] }, -]; -const STRI_INDEX: &[u16] = &[0, 1, 2]; - -pub(super) fn init_stri_primitive( - storages: AllStoragesView, - display: NonSendSync> -) { - let vert = VertexBuffer::immutable( - &display.display, - STRI_VERTEX - ).unwrap(); - let index = IndexBuffer::immutable( - &display.display, - PrimitiveType::TrianglesList, - STRI_INDEX - ).unwrap(); - storages.add_unique_non_send_sync(STriPrimitive(vert, index)); -} diff --git a/kubi/src/rendering/renderer.rs b/kubi/src/rendering/renderer.rs new file mode 100644 index 0000000..2da1be3 --- /dev/null +++ b/kubi/src/rendering/renderer.rs @@ -0,0 +1,177 @@ +use std::sync::Arc; +use pollster::FutureExt; +use shipyard::Unique; +use winit::{ + event_loop::ActiveEventLoop, + window::{Fullscreen, Window}, + dpi::PhysicalSize +}; +use crate::settings::{GameSettings, FullscreenMode}; + +#[derive(Unique)] +pub struct Renderer { + window: Arc, + instance: wgpu::Instance, + surface: wgpu::Surface<'static>, + device: wgpu::Device, + queue: wgpu::Queue, + surface_config: wgpu::SurfaceConfiguration, + size: PhysicalSize, + // pub depth_texture: wgpu::Texture, +} + +impl Renderer { + pub fn init(event_loop: &ActiveEventLoop, settings: &GameSettings) -> Self { + log::info!("initializing display"); + + let window_attributes = Window::default_attributes() + .with_title("kubi") + .with_maximized(true) + .with_min_inner_size(PhysicalSize::new(640, 480)) + .with_fullscreen({ + //this has no effect on android, so skip this pointless stuff + #[cfg(target_os = "android")] { + None + } + #[cfg(not(target_os = "android"))] + if let Some(fs_settings) = &settings.fullscreen { + let monitor = event_loop.primary_monitor().or_else(|| { + event_loop.available_monitors().next() + }); + + if let Some(monitor) = monitor { + log::info!("monitor: {}", monitor.name().unwrap_or_else(|| "generic".into())); + match fs_settings.mode { + FullscreenMode::Borderless => { + log::info!("starting in borderless fullscreen mode"); + Some(Fullscreen::Borderless(Some(monitor))) + }, + FullscreenMode::Exclusive => { + log::warn!("exclusive fullscreen mode is experimental"); + log::info!("starting in exclusive fullscreen mode"); + //TODO: grabbing the first video mode is probably not the best idea... + monitor.video_modes().next() + .map(|vmode| { + log::info!("video mode: {}", vmode.to_string()); + Some(Fullscreen::Exclusive(vmode)) + }) + .unwrap_or_else(|| { + log::warn!("no valid video modes found, falling back to windowed mode instead"); + None + }) + } + } + } else { + log::warn!("no monitors found, falling back to windowed mode"); + None + } + } else { + log::info!("starting in windowed mode"); + None + } + }); + let window = Arc::new(event_loop.create_window(window_attributes).unwrap()); + + let size = window.inner_size(); + + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { + backends: wgpu::Backends::all(), + //Disable validation layer + flags: wgpu::InstanceFlags::default() & !wgpu::InstanceFlags::VALIDATION, + //we're using vulkan on windows + // #[cfg(all(target_os = "windows", target_arch = "x86_64"))] + // dx12_shader_compiler: wgpu::Dx12Compiler::Dxc { + // dxil_path: Some("./dxil.dll".into()), + // dxc_path: Some("./dxcompiler.dll".into()), + // }, + ..Default::default() + }); + + // Create a surface with `create_surface_unsafe` to get a surface with 'static lifetime + // It should never outlive the window it's created from + // let surface = unsafe { + // let target = wgpu::SurfaceTargetUnsafe::from_window(&window).unwrap(); + // instance.create_surface_unsafe(target).unwrap() + // }; + let surface = instance.create_surface(Arc::clone(&window)).unwrap(); + + let adapter = instance.request_adapter( + &wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::HighPerformance, + compatible_surface: Some(&surface), + force_fallback_adapter: false, + }, + ).block_on().unwrap(); + + log::info!("Adapter: {:?}", adapter.get_info()); + log::info!("Features: {:?}", adapter.features()); + log::info!("Limits: {:?}", adapter.limits()); + + let (device, queue) = adapter.request_device( + &wgpu::DeviceDescriptor { + label: None, + required_features: wgpu::Features::empty(), + required_limits: wgpu::Limits::downlevel_webgl2_defaults().using_resolution(adapter.limits()), + }, + None, + ).block_on().unwrap(); + + let surface_config = surface.get_default_config(&adapter, size.width, size.height).unwrap(); + surface.configure(&device, &surface_config); + + Self { window, instance, surface, device, queue, surface_config, size } + } + + pub fn resize(&mut self, size: PhysicalSize) { + if size.width == 0 || size.height == 0 { + log::warn!("Ignoring resize event with zero width or height"); + return + } + if self.size == size { + log::warn!("Ignoring resize event with same size"); + return + } + log::debug!("resizing surface to {:?}", size); + self.size = size; + self.surface_config.width = size.width; + self.surface_config.height = size.height; + self.surface.configure(&self.device, &self.surface_config); + } + + pub fn reconfigure(&self) { + self.surface.configure(&self.device, &self.surface_config); + } + + //getters: + pub fn size(&self) -> PhysicalSize { + self.size + } + + pub fn size_uvec2(&self) -> glam::UVec2 { + glam::UVec2::new(self.size.width, self.size.height) + } + + pub fn size_vec2(&self) -> glam::Vec2 { + glam::Vec2::new(self.size.width as f32, self.size.height as f32) + } + + pub fn window(&self) -> &Window { + &self.window + } + + pub fn surface(&self) -> &wgpu::Surface<'static> { + &self.surface + } + + pub fn device(&self) -> &wgpu::Device { + &self.device + } + + pub fn queue(&self) -> &wgpu::Queue { + &self.queue + } + + pub fn surface_config(&self) -> &wgpu::SurfaceConfiguration { + &self.surface_config + } +} diff --git a/kubi/src/rendering/selection_box.rs b/kubi/src/rendering/selection_box.rs index 8f0e2eb..ae6a0ce 100644 --- a/kubi/src/rendering/selection_box.rs +++ b/kubi/src/rendering/selection_box.rs @@ -1,59 +1,65 @@ -use glam::{Mat4, Vec3, Quat}; -use shipyard::{View, IntoIter, NonSendSync, UniqueViewMut, UniqueView}; -use glium::{ - Surface, - DrawParameters, - BackfaceCullingMode, - Blend, Depth, DepthTest, - uniform, -}; -use crate::{ - world::raycast::LookingAtBlock, - camera::Camera, - prefabs::ColoredShaderPrefab -}; -use super::{ - RenderTarget, - primitives::cube::CubePrimitive, -}; - -const SMOL: f32 = 0.0025; - -pub fn render_selection_box( - lookat: View, - camera: View, - mut target: NonSendSync>, - program: NonSendSync>, - buffers: NonSendSync>, -) { - let camera = camera.iter().next().unwrap(); - let Some(lookat) = lookat.iter().next() else { return }; - let Some(lookat) = lookat.0 else { return }; - - //Darken block - target.0.draw( - &buffers.0, - &buffers.1, - &program.0, - &uniform! { - color: [0., 0., 0., 0.5_f32], - model: Mat4::from_scale_rotation_translation( - Vec3::splat(1. + SMOL * 2.), - Quat::default(), - lookat.block_position.as_vec3() - Vec3::splat(SMOL) - ).to_cols_array_2d(), - perspective: camera.perspective_matrix.to_cols_array_2d(), - view: camera.view_matrix.to_cols_array_2d(), - }, - &DrawParameters { - backface_culling: BackfaceCullingMode::CullClockwise, - blend: Blend::alpha_blending(), - depth: Depth { - //this may be unreliable... unless scale is applied! hacky... - test: DepthTest::IfLessOrEqual, - ..Default::default() - }, - ..Default::default() - } - ).unwrap(); -} +use shipyard::{AllStoragesView, IntoIter, Unique, UniqueView, View}; +use wgpu::RenderPassDescriptor; +use crate::{player::MainPlayer, world::raycast::LookingAtBlock}; +use super::{camera_uniform::CameraUniformBuffer, depth::DepthTexture, primitives::CubePrimitive, RenderCtx}; + +mod pipeline; +mod uniform; + +use uniform::SelectionBoxUniform; + +#[derive(Unique)] +pub struct SboxRenderState { + pipeline: wgpu::RenderPipeline, + uniform: SelectionBoxUniform, +} + +pub fn init_selection_box_render_state(storages: AllStoragesView) { + let uniform = storages.run(uniform::init_selection_box_uniform); + let pipeline = storages.run_with_data(pipeline::init_selection_box_pipeline, &uniform); + storages.add_unique(SboxRenderState { pipeline, uniform }); +} + +pub use uniform::update_selection_box_uniform + as update_selection_box_render_state; + +pub fn draw_selection_box( + ctx: &mut RenderCtx, + state: UniqueView, + depth: UniqueView, + cube: UniqueView, + camera_ubo: UniqueView, + lookat: View, + player: View, +) { + let Some((LookingAtBlock(Some(_)), _)) = (&lookat, &player).iter().next() else { + return + }; + let mut rpass = ctx.encoder.begin_render_pass(&RenderPassDescriptor { + label: Some("rpass_selection_box"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: ctx.surface_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &depth.depth_view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, + }), + stencil_ops: None, + }), + ..Default::default() + }); + + rpass.set_pipeline(&state.pipeline); + rpass.set_bind_group(0, &camera_ubo.camera_bind_group, &[]); + rpass.set_bind_group(1, &state.uniform.bind_group, &[]); + rpass.set_index_buffer(cube.0.index.slice(..), wgpu::IndexFormat::Uint16); + rpass.set_vertex_buffer(0, cube.0.vertex.slice(..)); + rpass.draw_indexed(0..cube.0.index_len, 0, 0..1); +} diff --git a/kubi/src/rendering/selection_box/pipeline.rs b/kubi/src/rendering/selection_box/pipeline.rs new file mode 100644 index 0000000..ab15dcd --- /dev/null +++ b/kubi/src/rendering/selection_box/pipeline.rs @@ -0,0 +1,70 @@ +use shipyard::UniqueView; +use crate::rendering::{ + camera_uniform::CameraUniformBuffer, + depth::DepthTexture, + primitives::PrimitiveVertex, + Renderer +}; + +pub fn init_selection_box_pipeline( + uniform: &super::uniform::SelectionBoxUniform, + ren: UniqueView, + depth: UniqueView, + camera_ubo: UniqueView, +) -> wgpu::RenderPipeline { + log::info!("init_selection_box_pipeline"); + + let shader = ren.device().create_shader_module( + wgpu::include_wgsl!("../../../shaders/selection_box.wgsl") + ); + + let selection_box_pipeline_layout = ren.device().create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("selection_box_pipeline_layout"), + bind_group_layouts: &[ + &camera_ubo.camera_bind_group_layout, + &uniform.bind_group_layout, + ], + push_constant_ranges: &[], + }); + + ren.device().create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("selection_box_pipeline"), + layout: Some(&selection_box_pipeline_layout), + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + compilation_options: wgpu::PipelineCompilationOptions::default(), + targets: &[Some(wgpu::ColorTargetState { + format: ren.surface_config().format, + blend: Some(wgpu::BlendState::ALPHA_BLENDING), + write_mask: wgpu::ColorWrites::COLOR, + })], + }), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + compilation_options: wgpu::PipelineCompilationOptions::default(), + buffers: &[ + PrimitiveVertex::LAYOUT, + ], + }, + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + cull_mode: Some(wgpu::Face::Back), + front_face: wgpu::FrontFace::Ccw, + unclipped_depth: false, + polygon_mode: wgpu::PolygonMode::Fill, + conservative: false, + }, + depth_stencil: Some(wgpu::DepthStencilState { + format: depth.depth_texture.format(), + depth_write_enabled: false, + depth_compare: wgpu::CompareFunction::LessEqual, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + }), + multisample: wgpu::MultisampleState::default(), + multiview: None, + }) +} diff --git a/kubi/src/rendering/selection_box/uniform.rs b/kubi/src/rendering/selection_box/uniform.rs new file mode 100644 index 0000000..cf551ad --- /dev/null +++ b/kubi/src/rendering/selection_box/uniform.rs @@ -0,0 +1,83 @@ +use glam::Vec3; +use shipyard::{IntoIter, UniqueView, View}; +use bytemuck::{Pod, Zeroable}; +use crate::{ + player::MainPlayer, + rendering::Renderer, + world::raycast::LookingAtBlock, +}; +use super::SboxRenderState; + +#[derive(Clone, Copy, Pod, Zeroable)] +#[repr(C, packed)] +pub struct SelectionBoxUniformData { + pub position: [f32; 3], + pub _padding: u32, +} + +pub struct SelectionBoxUniform { + pub buffer: wgpu::Buffer, + pub bind_group_layout: wgpu::BindGroupLayout, + pub bind_group: wgpu::BindGroup, +} + +pub fn init_selection_box_uniform( + renderer: UniqueView +) -> SelectionBoxUniform { + log::info!("init_selection_box_uniform"); + + let buffer = renderer.device().create_buffer(&wgpu::BufferDescriptor { + label: Some("selection_box_uniform"), + size: std::mem::size_of::() as u64, + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + let bind_group_layout = renderer.device().create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("selection_box_bind_group_layout"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + }); + + let bind_group = renderer.device().create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("selection_box_bind_group"), + layout: &bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: buffer.as_entire_binding(), + }], + }); + + SelectionBoxUniform { + buffer, + bind_group_layout, + bind_group, + } +} + +pub fn update_selection_box_uniform( + renderer: UniqueView, + state: UniqueView, + lookat: View, + player: View, +) { + //TODO: only update if changed + if let Some((LookingAtBlock(Some(lookat)), _)) = (&lookat, &player).iter().next() { + renderer.queue().write_buffer( + &state.uniform.buffer, + 0, + bytemuck::cast_slice(&[SelectionBoxUniformData { + position: (lookat.position.floor() + Vec3::splat(0.5)).to_array(), + _padding: 0, + }]), + ); + }; +} diff --git a/kubi/src/rendering/smoverlay.rs b/kubi/src/rendering/smoverlay.rs new file mode 100644 index 0000000..e0e66fc --- /dev/null +++ b/kubi/src/rendering/smoverlay.rs @@ -0,0 +1,48 @@ +use shipyard::{AllStoragesView, Unique, UniqueView}; +use super::{primitives::FstriPrimitive, RenderCtx, Renderer}; + +mod uniform; +mod pipeline; +use uniform::SmUniform; + +#[derive(Unique)] +pub struct SmOverlayRenderState { + pub uniform: SmUniform, + pub pipeline: wgpu::RenderPipeline, +} + +pub fn init_smoverlay_render_state(storages: AllStoragesView) { + let uniform = storages.run(uniform::init_sm_uniform); + let pipeline = storages.run_with_data(pipeline::init_smoverlay_pipeline, &uniform); + storages.add_unique(SmOverlayRenderState { uniform, pipeline }); +} + +pub use uniform::update_sm_uniform as update_smoverlay_render_state; + +pub fn render_submerged_view( + ctx: &mut RenderCtx, + state: UniqueView, + buf: UniqueView, +) { + if state.uniform.stored_data.is_none() { return } + + let mut rpass = ctx.encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("smoverlay_render_pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: ctx.surface_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + + rpass.set_pipeline(&state.pipeline); + rpass.set_bind_group(0, &state.uniform.bind_group, &[]); + rpass.set_vertex_buffer(0, buf.0.slice(..)); + rpass.draw(0..3, 0..1); +} diff --git a/kubi/src/rendering/smoverlay/pipeline.rs b/kubi/src/rendering/smoverlay/pipeline.rs new file mode 100644 index 0000000..df35e3e --- /dev/null +++ b/kubi/src/rendering/smoverlay/pipeline.rs @@ -0,0 +1,57 @@ +use shipyard::UniqueView; +use crate::rendering::{primitives::PrimitiveVertex2, Renderer}; +use super::uniform::SmUniform; + +pub fn init_smoverlay_pipeline( + uniform: &SmUniform, + renderer: UniqueView +) -> wgpu::RenderPipeline { + let module = renderer.device().create_shader_module( + wgpu::include_wgsl!("../../../shaders/c2d.wgsl") + ); + + let rp_layout = renderer.device().create_pipeline_layout( + &wgpu::PipelineLayoutDescriptor { + label: Some("smoverlay_pipeline_layout"), + bind_group_layouts: &[ + &uniform.bind_group_layout, + ], + push_constant_ranges: &[], + } + ); + + renderer.device().create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("smoverlay_pipeline"), + layout: Some(&rp_layout), + vertex: wgpu::VertexState { + module: &module, + compilation_options: wgpu::PipelineCompilationOptions::default(), + entry_point: "vs_main", + buffers: &[ + PrimitiveVertex2::LAYOUT, + ], + }, + fragment: Some(wgpu::FragmentState { + module: &module, + compilation_options: wgpu::PipelineCompilationOptions::default(), + entry_point: "fs_main", + targets: &[Some(wgpu::ColorTargetState { + format: renderer.surface_config().format, + blend: Some(wgpu::BlendState::ALPHA_BLENDING), + write_mask: wgpu::ColorWrites::ALL, + })], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: Some(wgpu::Face::Back), + polygon_mode: wgpu::PolygonMode::Fill, + conservative: false, + unclipped_depth: false, + }, + depth_stencil: None, + multisample: wgpu::MultisampleState::default(), + multiview: None, + }) +} diff --git a/kubi/src/rendering/smoverlay/uniform.rs b/kubi/src/rendering/smoverlay/uniform.rs new file mode 100644 index 0000000..c859739 --- /dev/null +++ b/kubi/src/rendering/smoverlay/uniform.rs @@ -0,0 +1,94 @@ +use bytemuck::{Pod, Zeroable}; +use kubi_shared::transform::Transform; +use shipyard::{IntoIter, UniqueView, UniqueViewMut, View}; +use crate::{player::MainPlayer, rendering::Renderer, world::ChunkStorage}; +use super::SmOverlayRenderState; + +#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] +#[repr(C, packed)] +pub struct SmUniformData { + pub color: [f32; 4], +} + +pub struct SmUniform { + pub stored_data: Option, + pub buffer: wgpu::Buffer, + pub bind_group_layout: wgpu::BindGroupLayout, + pub bind_group: wgpu::BindGroup, +} + +pub fn init_sm_uniform( + renderer: UniqueView +) -> SmUniform { + log::info!("init_sm_uniform"); + + let buffer = renderer.device().create_buffer(&wgpu::BufferDescriptor { + label: Some("smoverlay_uniform"), + size: std::mem::size_of::() as u64, + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + let bind_group_layout = renderer.device().create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("smoverlay_bind_group_layout"), + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + }); + + let bind_group = renderer.device().create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("smoverlay_bind_group"), + layout: &bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: buffer.as_entire_binding(), + }], + }); + + SmUniform { + stored_data: None, + buffer, + bind_group_layout, + bind_group, + } +} + +pub fn update_sm_uniform( + mut state: UniqueViewMut, + renderer: UniqueView, + plr: View, + trans: View, + world: UniqueView, +) { + state.uniform.stored_data = None; + + let (_, plr_trans) = (&plr, &trans).iter().next().expect("Main player MIA"); + let plr_pos = plr_trans.0.to_scale_rotation_translation().2; + let block_at_pos = world.get_block(plr_pos.floor().as_ivec3()); + let Some(block_at_pos) = block_at_pos else { return }; + let Some(color) = block_at_pos.descriptor().submerge else { return }; + + let new_data = SmUniformData { + color: color.to_array() + }; + + if state.uniform.stored_data == Some(new_data) { + return + } + state.uniform.stored_data = Some(new_data); + + log::debug!("update_sm_uniform: {:?}", new_data); + + renderer.queue().write_buffer( + &state.uniform.buffer, + 0, + bytemuck::cast_slice(&[new_data]), + ); +} diff --git a/kubi/src/rendering/sumberge.rs b/kubi/src/rendering/sumberge.rs deleted file mode 100644 index b947b9c..0000000 --- a/kubi/src/rendering/sumberge.rs +++ /dev/null @@ -1,39 +0,0 @@ -use glium::{uniform, Blend, DrawParameters, Surface}; -use kubi_shared::transform::Transform; -use shipyard::{IntoIter, NonSendSync, UniqueView, UniqueViewMut, View}; -use crate::{ - player::MainPlayer, - prefabs::Colored2ShaderPrefab, - rendering::primitives::stri::STriPrimitive, - world::ChunkStorage, -}; -use super::RenderTarget; - -pub fn render_submerged_view( - mut target: NonSendSync>, - primitive: NonSendSync>, - program: NonSendSync>, - plr: View, - trans: View, - world: UniqueView, -) { - let (_, plr_trans) = (&plr, &trans).iter().next().expect("Main player MIA"); - let plr_pos = plr_trans.0.to_scale_rotation_translation().2; - let block_at_pos = world.get_block(plr_pos.floor().as_ivec3()); - let Some(block_at_pos) = block_at_pos else { return }; - let Some(color) = block_at_pos.descriptor().submerge else { return }; - - let draw_parameters = DrawParameters { - blend: Blend::alpha_blending(), - ..Default::default() - }; - target.0.draw( - &primitive.0, - &primitive.1, - &program.0, - &uniform! { - color: color.to_array(), - }, - &draw_parameters, - ).unwrap(); -} diff --git a/kubi/src/rendering/world.rs b/kubi/src/rendering/world.rs index 3deb600..772e1bb 100644 --- a/kubi/src/rendering/world.rs +++ b/kubi/src/rendering/world.rs @@ -1,248 +1,161 @@ -use glam::{ivec3, IVec3, Mat4, Quat, Vec3}; -use shipyard::{track, AllStoragesView, IntoIter, NonSendSync, Unique, UniqueView, UniqueViewMut, View}; -use glium::{ - draw_parameters::{ - BackfaceCullingMode, Depth, DepthTest, PolygonMode - }, implement_vertex, uniform, uniforms::{ - MagnifySamplerFilter, MinifySamplerFilter, Sampler, SamplerBehavior, SamplerWrapFunction - }, Blend, DrawParameters, Smooth, Surface -}; +use glam::Vec3; +use shipyard::{AllStoragesView, IntoIter, NonSendSync, Unique, UniqueView, UniqueViewMut, View}; +use kubi_shared::chunk::CHUNK_SIZE; use crate::{ camera::Camera, - player::MainPlayer, - transform::Transform, - prefabs::{ - ChunkShaderPrefab, - BlockTexturesPrefab, - ColoredShaderPrefab, - }, - world::{ - ChunkStorage, - ChunkMeshStorage, - chunk::CHUNK_SIZE, - }, settings::GameSettings, + prefabs::GpuPrefabs, + world::{ChunkMeshStorage, ChunkStorage}, }; -use super::{RenderTarget, primitives::cube::CubePrimitive}; +use super::{camera_uniform::CameraUniformBuffer, depth::DepthTexture, RenderCtx, Renderer}; -#[derive(Clone, Copy)] -#[repr(C)] -pub struct ChunkVertex { - pub position: [f32; 3], - pub normal: [f32; 3], - pub uv: [f32; 2], - pub tex_index: u8, -} -implement_vertex!(ChunkVertex, position, normal, uv, tex_index); +mod pipeline; +mod vertex; +pub use vertex::ChunkVertex; #[derive(Unique)] -pub struct TransChunkQueue(pub Vec); - -pub fn init_trans_chunk_queue(storages: AllStoragesView) { - storages.add_unique(TransChunkQueue(Vec::with_capacity(512))); +pub struct WorldRenderState { + pub pipeline: wgpu::RenderPipeline, + pub pipeline_trans: wgpu::RenderPipeline, + pub trans_bundle: Option, } -fn draw_params(settings: &GameSettings) -> DrawParameters { - DrawParameters { - depth: Depth { - test: DepthTest::IfLess, - write: true, - ..Default::default() - }, - multisampling: settings.msaa.is_some(), - polygon_mode: PolygonMode::Fill, //Change to Line for wireframe - backface_culling: BackfaceCullingMode::CullClockwise, - ..Default::default() - } -} - -fn texture_sampler<'a, T>(texture: &'a T, settings: &GameSettings) -> Sampler<'a, T> { - Sampler(texture, SamplerBehavior { - minify_filter: MinifySamplerFilter::LinearMipmapLinear, - magnify_filter: MagnifySamplerFilter::Nearest, - max_anisotropy: settings.max_anisotropy.unwrap_or_default(), - wrap_function: (SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp, SamplerWrapFunction::Clamp), - depth_texture_comparison: None, +pub fn init_world_render_state(storages: AllStoragesView) { + let (pipeline, pipeline_trans) = storages.run(pipeline::init_world_pipeline); + storages.add_unique(WorldRenderState { + pipeline, pipeline_trans, + trans_bundle: None, }) } pub fn draw_world( - mut target: NonSendSync>, + ctx: &mut RenderCtx, + mut state: UniqueViewMut, + renderer: UniqueView, + camera_ubo: UniqueView, + depth: UniqueView, + textures: UniqueView, + camera: View, chunks: UniqueView, meshes: NonSendSync>, - program: NonSendSync>, - texture: NonSendSync>, - transform: View, - camera: View, - settings: UniqueView, - mut trans_queue: UniqueViewMut, + //settings: UniqueView, ) { - // let (camera, transform) = (&camera, &transform).iter().next().expect("No cameras in the scene"); - // let camera_position = transform.0.to_scale_rotation_translation().2; - let camera = camera.iter().next().expect("No cameras in the scene"); - let view = camera.view_matrix.to_cols_array_2d(); - let perspective = camera.perspective_matrix.to_cols_array_2d(); - let draw_parameters = draw_params(&settings); - let texture_sampler = texture_sampler(&texture.0, &settings); + let mut render_pass = ctx.encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("rpass_draw_world"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: ctx.surface_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &depth.depth_view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: wgpu::StoreOp::Store, + }), + stencil_ops: None, + }), + ..Default::default() + }); + + render_pass.set_pipeline(&state.pipeline); + render_pass.set_bind_group(0, &textures.block_diffuse_bind_group, &[]); + render_pass.set_bind_group(1, &camera_ubo.camera_bind_group, &[]); + + let mut trans_bundle_used = false; + let mut trans_bundle = renderer.device().create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor { + label: Some("trans_bundle_encoder"), + color_formats: &[Some(renderer.surface_config().format)], + depth_stencil: Some(wgpu::RenderBundleDepthStencil { + format: depth.depth_texture.format(), + depth_read_only: true, + stencil_read_only: true, + }), + sample_count: 1, + multiview: None, + }); + + trans_bundle.set_pipeline(&state.pipeline_trans); + trans_bundle.set_bind_group(0, &textures.block_diffuse_bind_group, &[]); + trans_bundle.set_bind_group(1, &camera_ubo.camera_bind_group, &[]); for (&position, chunk) in &chunks.chunks { if let Some(key) = chunk.mesh_index { let mesh = meshes.get(key).expect("Mesh index pointing to nothing"); let world_position = position.as_vec3() * CHUNK_SIZE as f32; - //Skip mesh if its empty - if mesh.index_buffer.len() == 0 && mesh.trans_index_buffer.len() == 0 { + //Skip if mesh is empty + if mesh.main.index.size() == 0 && mesh.trans.index.size() == 0 { continue } //Frustum culling - { - let minp = world_position; - let maxp = world_position + Vec3::splat(CHUNK_SIZE as f32); - if !camera.frustum.is_box_visible(minp, maxp) { - continue - } + let minp = world_position; + let maxp = world_position + Vec3::splat(CHUNK_SIZE as f32); + if !camera.frustum.is_box_visible(minp, maxp) { + continue } //Draw chunk mesh - if mesh.index_buffer.len() > 0 { - target.0.draw( - &mesh.vertex_buffer, - &mesh.index_buffer, - &program.0, - &uniform! { - position_offset: world_position.to_array(), - view: view, - perspective: perspective, - tex: texture_sampler, - discard_alpha: true, - }, - &draw_parameters - ).unwrap(); + if mesh.main.index_len > 0 { + render_pass.set_index_buffer(mesh.main.index.slice(..), wgpu::IndexFormat::Uint32); + render_pass.set_vertex_buffer(0, mesh.main.vertex.slice(..)); + render_pass.draw_indexed(0..mesh.main.index_len, 0, 0..1); } - if mesh.trans_index_buffer.len() > 0 { - trans_queue.0.push(position); + //Draw transparent chunk mesh + if mesh.trans.index_len > 0 { + trans_bundle_used = true; + trans_bundle.set_index_buffer(mesh.trans.index.slice(..), wgpu::IndexFormat::Uint32); + trans_bundle.set_vertex_buffer(0, mesh.trans.vertex.slice(..)); + trans_bundle.draw_indexed(0..mesh.trans.index_len, 0, 0..1); } } } - // const HALF_CHUNK_SIZE: IVec3 = IVec3::splat((CHUNK_SIZE >> 1) as i32); - // trans_queue.0.sort_by_cached_key(|&pos| -( - // (pos + HALF_CHUNK_SIZE).distance_squared(camera_position.as_ivec3()) - // )); + drop(render_pass); + + if trans_bundle_used { + let bundle = trans_bundle.finish(&wgpu::RenderBundleDescriptor { + label: Some("trans_bundle"), + }); + state.trans_bundle = Some(bundle); + } else { + state.trans_bundle = None; + } } -pub fn draw_world_trans( - mut target: NonSendSync>, - chunks: UniqueView, - meshes: NonSendSync>, - program: NonSendSync>, - texture: NonSendSync>, - camera: View, - settings: UniqueView, - mut trans_queue: UniqueViewMut, +pub fn rpass_submit_trans_bundle( + ctx: &mut RenderCtx, + state: UniqueView, + depth: UniqueView, ) { - let camera = camera.iter().next().expect("No cameras in the scene"); - let view = camera.view_matrix.to_cols_array_2d(); - let perspective = camera.perspective_matrix.to_cols_array_2d(); - - let mut draw_parameters = draw_params(&settings); - draw_parameters.blend = Blend::alpha_blending(); - draw_parameters.backface_culling = BackfaceCullingMode::CullingDisabled; - draw_parameters.smooth = Some(Smooth::Fastest); - - let texture_sampler = texture_sampler(&texture.0, &settings); - - for position in trans_queue.0.drain(..).rev() { - let world_position = position.as_vec3() * CHUNK_SIZE as f32; - let mesh_idx = chunks.chunks[&position].mesh_index.expect("No mesh index"); - let mesh = meshes.get(mesh_idx).expect("Mesh index pointing to nothing"); - target.0.draw( - &mesh.trans_vertex_buffer, - &mesh.trans_index_buffer, - &program.0, - &uniform! { - position_offset: world_position.to_array(), - view: view, - perspective: perspective, - tex: texture_sampler, - discard_alpha: false, - }, - &draw_parameters - ).unwrap(); - } -} - -pub fn draw_current_chunk_border( - mut target: NonSendSync>, - player: View, - transforms: View, - buffers: NonSendSync>, - program: NonSendSync>, - camera: View, - settings: UniqueView, -) { - if cfg!(target_os = "android") { + let Some(bundle) = state.trans_bundle.as_ref() else { return - } - if !settings.debug_draw_current_chunk_border { - return - } - let camera = camera.iter().next().expect("No cameras in the scene"); - let view = camera.view_matrix.to_cols_array_2d(); - let perspective = camera.perspective_matrix.to_cols_array_2d(); - let (_, &player_transform) = (&player, &transforms).iter().next().expect("No player"); - let (_, _, player_position) = player_transform.0.to_scale_rotation_translation(); - let player_in_chunk = ivec3( - (player_position.x as i32).div_euclid(CHUNK_SIZE as i32), - (player_position.y as i32).div_euclid(CHUNK_SIZE as i32), - (player_position.z as i32).div_euclid(CHUNK_SIZE as i32), - ); - let world_position = player_in_chunk.as_vec3() * CHUNK_SIZE as f32; - target.0.draw( - &buffers.0, - &buffers.1, - &program.0, - &uniform! { - model: Mat4::from_scale_rotation_translation( - Vec3::splat(CHUNK_SIZE as f32), - Quat::default(), - world_position - ).to_cols_array_2d(), - color: [0.25f32; 4], - view: view, - perspective: perspective, - }, - &DrawParameters { - depth: Depth { - test: DepthTest::IfLess, - ..Default::default() + }; + let mut rpass = ctx.encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("rpass_submit_trans_bundle"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: ctx.surface_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, }, - blend: Blend::alpha_blending(), - ..Default::default() - } - ).unwrap(); - target.0.draw( - &buffers.0, - &buffers.1, - &program.0, - &uniform! { - model: Mat4::from_scale_rotation_translation( - Vec3::splat(CHUNK_SIZE as f32), - Quat::default(), - world_position - ).to_cols_array_2d(), - color: [0.0f32; 4], - view: view, - perspective: perspective, - }, - &DrawParameters { - polygon_mode: PolygonMode::Point, - line_width: Some(2.), - point_size: Some(5.), - ..Default::default() - } - ).unwrap(); + })], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &depth.depth_view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, + }), + stencil_ops: None, + }), + ..Default::default() + }); + rpass.execute_bundles(Some(bundle)); } diff --git a/kubi/src/rendering/world/pipeline.rs b/kubi/src/rendering/world/pipeline.rs new file mode 100644 index 0000000..6d960c6 --- /dev/null +++ b/kubi/src/rendering/world/pipeline.rs @@ -0,0 +1,117 @@ +use shipyard::UniqueView; +use crate::{ + prefabs::GpuPrefabs, + rendering::{camera_uniform::CameraUniformBuffer, depth::DepthTexture, world::ChunkVertex, Renderer} +}; + +pub fn init_world_pipeline( + ren: UniqueView, + depth: UniqueView, + textures: UniqueView, + camera_ubo: UniqueView, +) -> (wgpu::RenderPipeline, wgpu::RenderPipeline) { + log::info!("init_world_pipeline: creating shader module"); + + let shader = ren.device().create_shader_module( + wgpu::include_wgsl!("../../../shaders/world.wgsl") + ); + + log::info!("init_world_pipeline: creating pipeline layout"); + + let world_pipeline_layout = ren.device().create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("world_pipeline_layout"), + bind_group_layouts: &[ + &textures.block_diffuse_bind_group_layout, + &camera_ubo.camera_bind_group_layout, + ], + push_constant_ranges: &[], + }); + + log::info!("init_world_pipeline: create main pipeline"); + + let pipeline_main = ren.device().create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("world_pipeline"), + layout: Some(&world_pipeline_layout), + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + compilation_options: wgpu::PipelineCompilationOptions::default(), + targets: &[Some(wgpu::ColorTargetState { + format: ren.surface_config().format, + blend: Some(wgpu::BlendState::REPLACE), + write_mask: wgpu::ColorWrites::COLOR, + })], + }), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + compilation_options: wgpu::PipelineCompilationOptions::default(), + buffers: &[ + ChunkVertex::LAYOUT, + ], + }, + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + cull_mode: Some(wgpu::Face::Back), + front_face: wgpu::FrontFace::Ccw, + unclipped_depth: false, + polygon_mode: wgpu::PolygonMode::Fill, + conservative: false, + }, + depth_stencil: Some(wgpu::DepthStencilState { + format: depth.depth_texture.format(), + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::Less, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + }), + multisample: wgpu::MultisampleState::default(), + multiview: None, + }); + + log::info!("init_world_pipeline: create trans pipeline"); + + let pipeline_trans = ren.device().create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("world_pipeline_trans"), + layout: Some(&world_pipeline_layout), + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main_trans", + compilation_options: wgpu::PipelineCompilationOptions::default(), + targets: &[Some(wgpu::ColorTargetState { + format: ren.surface_config().format, + blend: Some(wgpu::BlendState::ALPHA_BLENDING), + write_mask: wgpu::ColorWrites::COLOR, + })], + }), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + compilation_options: wgpu::PipelineCompilationOptions::default(), + buffers: &[ + ChunkVertex::LAYOUT, + ], + }, + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + cull_mode: None, + front_face: wgpu::FrontFace::Ccw, + unclipped_depth: false, + polygon_mode: wgpu::PolygonMode::Fill, + conservative: false, + }, + depth_stencil: Some(wgpu::DepthStencilState { + format: depth.depth_texture.format(), + depth_write_enabled: false, + depth_compare: wgpu::CompareFunction::Less, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + }), + multisample: wgpu::MultisampleState::default(), + multiview: None, + }); + + (pipeline_main, pipeline_trans) +} diff --git a/kubi/src/rendering/world/vertex.rs b/kubi/src/rendering/world/vertex.rs new file mode 100644 index 0000000..ad1544c --- /dev/null +++ b/kubi/src/rendering/world/vertex.rs @@ -0,0 +1,23 @@ +use bytemuck::{Pod, Zeroable}; + +#[derive(Clone, Copy, Pod, Zeroable)] +#[repr(C, packed)] +pub struct ChunkVertex { + pub position: [f32; 3], + pub normal: [f32; 3], + pub uv: [f32; 2], + pub tex_index: u32, +} + +impl ChunkVertex { + pub const LAYOUT: wgpu::VertexBufferLayout<'static> = wgpu::VertexBufferLayout { + array_stride: std::mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &wgpu::vertex_attr_array![ + 0 => Float32x3, + 1 => Float32x3, + 2 => Float32x2, + 3 => Uint32, + ], + }; +} diff --git a/kubi/src/settings.rs b/kubi/src/settings.rs index a0abbbe..9a83be3 100644 --- a/kubi/src/settings.rs +++ b/kubi/src/settings.rs @@ -11,10 +11,10 @@ pub struct FullscreenSettings { #[derive(Unique)] pub struct GameSettings { - pub vsync: bool, + // pub vsync: bool, pub fullscreen: Option, - pub msaa: Option, - pub max_anisotropy: Option, + // pub msaa: Option, + // pub max_anisotropy: Option, /// there's a 1 chunk border of loaded but invisible around this pub render_distance: u8, pub mouse_sensitivity: f32, @@ -24,10 +24,10 @@ pub struct GameSettings { impl Default for GameSettings { fn default() -> Self { Self { - vsync: false, + // vsync: false, fullscreen: None, - msaa: Some(4), - max_anisotropy: Some(16), + // msaa: Some(4), + // max_anisotropy: Some(16), render_distance: match true { cfg!(debug_assertions) => 5, cfg!(target_os = "android") => 6, diff --git a/kubi/src/ui/chat_ui.rs b/kubi/src/ui/chat_ui.rs index d419ed6..0c34131 100644 --- a/kubi/src/ui/chat_ui.rs +++ b/kubi/src/ui/chat_ui.rs @@ -1,10 +1,10 @@ use hui::{color, element::{container::Container, text::Text, UiElementExt}, layout::Alignment, size}; use shipyard::{NonSendSync, UniqueView, UniqueViewMut}; -use crate::{chat::{ChatHistory, ChatMessage}, hui_integration::UiState, rendering::WindowSize}; +use crate::{chat::{ChatHistory, ChatMessage}, hui_integration::UiState, rendering::Renderer}; pub fn render_chat( mut hui: NonSendSync>, - size: UniqueView, + ren: UniqueView, chat: UniqueView, ) { let messages = chat.get_messages(); @@ -39,5 +39,5 @@ pub fn render_chat( .add_child(ui); } }) - .add_root(&mut hui.hui, size.0.as_vec2()); + .add_root(&mut hui.hui, ren.size_vec2()); } diff --git a/kubi/src/ui/connecting_screen.rs b/kubi/src/ui/connecting_screen.rs index 0ceab5f..d01ad5d 100644 --- a/kubi/src/ui/connecting_screen.rs +++ b/kubi/src/ui/connecting_screen.rs @@ -5,7 +5,7 @@ use crate::{ hui_integration::UiState, loading_screen::loading_screen_base, networking::{ConnectionRejectionReason, ServerAddress}, - rendering::WindowSize, + rendering::Renderer, state::{GameState, NextState} }; @@ -14,7 +14,7 @@ fn render_connecting_ui( rejection: Option>, join_state: UniqueView, mut ui: NonSendSync>, - size: UniqueView, + ren: UniqueView, ) { let text = match (rejection, *join_state) { (Some(err), _) => { @@ -32,7 +32,7 @@ fn render_connecting_ui( Text::new(text) .with_text_size(16) .add_child(ui); - }).add_root(&mut ui.hui, size.0.as_vec2()) + }).add_root(&mut ui.hui, ren.size_vec2()) } fn switch_to_loading_if_connected( diff --git a/kubi/src/ui/crosshair_ui.rs b/kubi/src/ui/crosshair_ui.rs index 353429e..39df924 100644 --- a/kubi/src/ui/crosshair_ui.rs +++ b/kubi/src/ui/crosshair_ui.rs @@ -6,7 +6,7 @@ use hui::{ size }; use shipyard::{AllStoragesViewMut, IntoIter, NonSendSync, Unique, UniqueView, UniqueViewMut, View}; -use crate::{hui_integration::UiState, player::MainPlayer, rendering::WindowSize, settings::GameSettings, world::raycast::LookingAtBlock}; +use crate::{hui_integration::UiState, player::MainPlayer, rendering::Renderer, settings::GameSettings, world::raycast::LookingAtBlock}; const CROSSHAIR_SIZE: usize = 9; const CROSSHAIR: &[u8] = &[ @@ -45,7 +45,7 @@ pub fn init_crosshair_image(storages: AllStoragesViewMut) { pub fn draw_crosshair( mut ui: NonSendSync>, crosshair: UniqueView, - size: UniqueView, + ren: UniqueView, player: View, raycast: View, settings: UniqueView, @@ -57,6 +57,9 @@ pub fn draw_crosshair( } } + let size = ren.size_uvec2(); + let size_rounded = uvec2(size.x & !1, size.y & !1).as_vec2(); + Container::default() .with_size(size!(100%)) .with_align(Alignment::Center) @@ -66,5 +69,5 @@ pub fn draw_crosshair( .with_size(size!((CROSSHAIR_SIZE * 2))) .add_child(ui); }) - .add_root(&mut ui.hui, uvec2(size.0.x & !1, size.0.y & !1).as_vec2()); + .add_root(&mut ui.hui, size_rounded); } diff --git a/kubi/src/ui/loading_screen.rs b/kubi/src/ui/loading_screen.rs index 805c641..df03aec 100644 --- a/kubi/src/ui/loading_screen.rs +++ b/kubi/src/ui/loading_screen.rs @@ -7,7 +7,7 @@ use hui::{ UiElementExt, }, layout::{Alignment, Direction}, - frame_rect, size, + rect_frame, size, }; use shipyard::{UniqueView, UniqueViewMut, Workload, NonSendSync, IntoWorkload}; use winit::keyboard::KeyCode; @@ -15,7 +15,7 @@ use crate::{ hui_integration::UiState, input::RawKbmInputState, networking::ServerAddress, - rendering::WindowSize, + rendering::Renderer, state::{GameState, NextState}, world::ChunkStorage, }; @@ -28,7 +28,7 @@ pub fn loading_screen_base(bg_alpha: f32, xui: impl FnOnce(&mut ElementList)) -> .with_children(|ui| { Container::default() .with_size(size!(400, auto)) - .with_background(frame_rect! { + .with_background(rect_frame! { color: (0.2, 0.2, 0.2), corner_radius: 8. }) @@ -43,7 +43,7 @@ fn render_loading_ui( addr: Option>, world: UniqueView, mut ui: NonSendSync>, - size: UniqueView + ren: UniqueView, ) { let loaded = world.chunks.iter().fold(0, |acc, (&_, chunk)| { acc + chunk.desired_state.matches_current(chunk.current_state) as usize @@ -63,11 +63,11 @@ fn render_loading_ui( ProgressBar::default() .with_value(value) .with_size(size!(100%, 15)) - .with_background(frame_rect! { + .with_background(rect_frame! { color: (0.1, 0.1, 0.1), corner_radius: 2. }) - .with_foreground(frame_rect! { + .with_foreground(rect_frame! { color: (0.4, 0.4, 1.0), corner_radius: 2. }) @@ -83,7 +83,7 @@ fn render_loading_ui( .add_child(ui) }) .add_child(ui); - }).add_root(&mut ui.hui, size.0.as_vec2()); + }).add_root(&mut ui.hui, ren.size_vec2()); } fn switch_to_ingame_if_loaded( diff --git a/kubi/src/ui/settings_ui.rs b/kubi/src/ui/settings_ui.rs index 640e393..6211c6d 100644 --- a/kubi/src/ui/settings_ui.rs +++ b/kubi/src/ui/settings_ui.rs @@ -2,11 +2,11 @@ use hui::{ element::{br::Break, container::Container, slider::Slider, text::Text, UiElementExt}, layout::{Alignment, Direction}, signal::Signal, - frame_rect, size, + rect_frame, size, }; use shipyard::{NonSendSync, UniqueView, UniqueViewMut}; use winit::keyboard::KeyCode; -use crate::{hui_integration::UiState, input::RawKbmInputState, rendering::WindowSize, settings::GameSettings}; +use crate::{hui_integration::UiState, input::RawKbmInputState, rendering::Renderer, settings::GameSettings}; #[derive(Signal)] enum SettingsSignal { @@ -18,7 +18,7 @@ enum SettingsSignal { pub fn render_settings_ui( mut ui: NonSendSync>, - size: UniqueView, + ren: UniqueView, mut settings: UniqueViewMut, kbd: UniqueView, ) { @@ -34,7 +34,7 @@ pub fn render_settings_ui( .with_align(Alignment::Center) .with_children(|ui| { Container::default() - .with_background(frame_rect! { + .with_background(rect_frame! { color: (0.2, 0.2, 0.2), corner_radius: 8. }) @@ -99,7 +99,7 @@ pub fn render_settings_ui( }) .add_child(ui); }) - .add_root(&mut ui.hui, size.0.as_vec2()); + .add_root(&mut ui.hui, ren.size_vec2()); ui.hui.process_signals(|signal: SettingsSignal| match signal { SettingsSignal::SetRenderDistance(value) => settings.render_distance = value, diff --git a/kubi/src/world.rs b/kubi/src/world.rs index 50664d2..1626d17 100644 --- a/kubi/src/world.rs +++ b/kubi/src/world.rs @@ -102,6 +102,7 @@ impl ChunkMeshStorage { pub fn init_game_world( storages: AllStoragesView, ) { + log::info!("init_game_world called"); storages.add_unique_non_send_sync(ChunkMeshStorage::new()); storages.add_unique(ChunkStorage::new()); storages.add_unique(ChunkTaskManager::new()); diff --git a/kubi/src/world/chunk.rs b/kubi/src/world/chunk.rs index e8ddd3a..27c52a9 100644 --- a/kubi/src/world/chunk.rs +++ b/kubi/src/world/chunk.rs @@ -1,9 +1,8 @@ use std::sync::Arc; use glam::IVec3; use atomic::Atomic; -use glium::{VertexBuffer, IndexBuffer}; use kubi_shared::worldgen::AbortState; -use crate::rendering::world::ChunkVertex; +use crate::rendering::{world::ChunkVertex, BufferPair}; pub use kubi_shared::chunk::{CHUNK_SIZE, BlockData}; @@ -18,10 +17,8 @@ impl ChunkData { } pub struct ChunkMesh { - pub vertex_buffer: VertexBuffer, - pub index_buffer: IndexBuffer, - pub trans_vertex_buffer: VertexBuffer, - pub trans_index_buffer: IndexBuffer, + pub main: BufferPair, + pub trans: BufferPair, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] diff --git a/kubi/src/world/loading.rs b/kubi/src/world/loading.rs index aa0d774..7ee4313 100644 --- a/kubi/src/world/loading.rs +++ b/kubi/src/world/loading.rs @@ -1,17 +1,17 @@ use std::sync::Arc; use atomic::{Atomic, Ordering}; use glam::{IVec3, ivec3}; -use glium::{VertexBuffer, IndexBuffer, index::PrimitiveType}; use kubi_shared::{networking::{channels::Channel, messages::ClientToServerMessage}, worldgen::AbortState}; use shipyard::{View, UniqueView, UniqueViewMut, IntoIter, Workload, IntoWorkload, NonSendSync, track}; use uflow::SendMode; +use wgpu::util::DeviceExt; use crate::{ - player::MainPlayer, - transform::Transform, - settings::GameSettings, - rendering::Renderer, - state::GameState, networking::UdpClient, + player::MainPlayer, + rendering::{world::ChunkVertex, BufferPair, Renderer}, + settings::GameSettings, + state::GameState, + transform::Transform, }; use super::{ ChunkStorage, ChunkMeshStorage, @@ -266,7 +266,7 @@ fn process_completed_tasks( task_manager: UniqueView, mut world: UniqueViewMut, mut meshes: NonSendSync>, - renderer: NonSendSync>, + renderer: UniqueView, state: UniqueView, mut queue: UniqueViewMut, ) { @@ -327,12 +327,51 @@ fn process_completed_tasks( //apply the mesh //TODO: Skip if mesh is empty? (i.e. set to None) - let mesh = ChunkMesh { - vertex_buffer: VertexBuffer::immutable(&renderer.display, &vertices).unwrap(), - index_buffer: IndexBuffer::immutable(&renderer.display, PrimitiveType::TrianglesList, &indices).unwrap(), - trans_vertex_buffer: VertexBuffer::immutable(&renderer.display, &trans_vertices).unwrap(), - trans_index_buffer: IndexBuffer::immutable(&renderer.display, PrimitiveType::TrianglesList, &trans_indices).unwrap(), + //TODO + + let vtx_buffer = renderer.device().create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("chunk_vertex_buffer"), + contents: bytemuck::cast_slice(&vertices), + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::VERTEX, + }); + + let idx_buffer = renderer.device().create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("chunk_vertex_buffer"), + contents: bytemuck::cast_slice(&indices), + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::INDEX, + }); + + let vtx_buffer_trans = renderer.device().create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("chunk_trans_vertex_buffer"), + contents: bytemuck::cast_slice(&trans_vertices), + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::VERTEX, + }); + + let idx_buffer_trans = renderer.device().create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("chunk_trans_index_buffer"), + contents: bytemuck::cast_slice(&trans_indices), + usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::INDEX, + }); + + let main_buffer_pair = BufferPair { + vertex: vtx_buffer, + vertex_len: vertices.len() as u32, + index: idx_buffer, + index_len: indices.len() as u32, }; + + let trans_buffer_pair = BufferPair { + vertex: vtx_buffer_trans, + vertex_len: trans_vertices.len() as u32, + index: idx_buffer_trans, + index_len: trans_indices.len() as u32, + }; + + let mesh = ChunkMesh { + main: main_buffer_pair, + trans: trans_buffer_pair, + }; + if let Some(index) = chunk.mesh_index { meshes.update(index, mesh).expect("Mesh update failed"); } else { diff --git a/kubi/src/world/mesh.rs b/kubi/src/world/mesh.rs index 24e2f2d..98d1ec6 100644 --- a/kubi/src/world/mesh.rs +++ b/kubi/src/world/mesh.rs @@ -1,4 +1,4 @@ -use glam::{IVec3, ivec3}; +use glam::{ivec3, IVec3, Vec3}; use strum::IntoEnumIterator; use kubi_shared::block::{Block, RenderType, Transparency}; use crate::world::chunk::CHUNK_SIZE; @@ -10,7 +10,7 @@ mod builder; use data::MeshGenData; use builder::{MeshBuilder, CubeFace, DiagonalFace}; -pub fn generate_mesh(data: MeshGenData) -> ( +pub fn generate_mesh(position: IVec3, data: MeshGenData) -> ( (Vec, Vec), (Vec, Vec), ) { @@ -32,8 +32,8 @@ pub fn generate_mesh(data: MeshGenData) -> ( } }; - let mut builder = MeshBuilder::new(); - let mut trans_builder = MeshBuilder::new(); + let mut builder = MeshBuilder::new_with_offset((position * CHUNK_SIZE as i32).as_vec3()); + let mut trans_builder = MeshBuilder::new_with_offset((position * CHUNK_SIZE as i32).as_vec3()); for x in 0..CHUNK_SIZE as i32 { for y in 0..CHUNK_SIZE as i32 { diff --git a/kubi/src/world/mesh/builder.rs b/kubi/src/world/mesh/builder.rs index 561342c..708d5f3 100644 --- a/kubi/src/world/mesh/builder.rs +++ b/kubi/src/world/mesh/builder.rs @@ -1,176 +1,182 @@ -use strum::EnumIter; -use glam::{Vec3, vec3, IVec3, ivec3}; -use std::f32::consts::FRAC_1_SQRT_2; -use crate::rendering::world::ChunkVertex; - -#[repr(usize)] -#[derive(Clone, Copy, Debug, EnumIter)] -pub enum CubeFace { - Top = 0, - Front = 4, - Left = 2, - Right = 3, - Back = 1, - Bottom = 5, -} -impl CubeFace { - pub const fn normal(self) -> IVec3 { - CUBE_FACE_NORMALS_IVEC3[self as usize] - } -} - -const CUBE_FACE_VERTICES: [[Vec3; 4]; 6] = [ - [vec3(0., 1., 0.), vec3(0., 1., 1.), vec3(1., 1., 0.), vec3(1., 1., 1.)], - [vec3(0., 0., 0.), vec3(0., 1., 0.), vec3(1., 0., 0.), vec3(1., 1., 0.)], - [vec3(0., 0., 1.), vec3(0., 1., 1.), vec3(0., 0., 0.), vec3(0., 1., 0.)], - [vec3(1., 0., 0.), vec3(1., 1., 0.), vec3(1., 0., 1.), vec3(1., 1., 1.)], - [vec3(1., 0., 1.), vec3(1., 1., 1.), vec3(0., 0., 1.), vec3(0., 1., 1.)], - [vec3(0., 0., 1.), vec3(0., 0., 0.), vec3(1., 0., 1.), vec3(1., 0., 0.)], -]; -const CUBE_FACE_NORMALS_IVEC3: [IVec3; 6] = [ - ivec3( 0, 1, 0), - ivec3( 0, 0, -1), - ivec3(-1, 0, 0), - ivec3( 1, 0, 0), - ivec3( 0, 0, 1), - ivec3( 0, -1, 0) -]; -const CUBE_FACE_NORMALS: [Vec3; 6] = [ - vec3(0., 1., 0.), - vec3(0., 0., -1.), - vec3(-1.,0., 0.), - vec3(1., 0., 0.), - vec3(0., 0., 1.), - vec3(0., -1.,0.) -]; -const CUBE_FACE_INDICES: [u32; 6] = [0, 1, 2, 2, 1, 3]; - -#[repr(usize)] -pub enum DiagonalFace { - RigthZ = 0, - LeftZ = 1, -} -const CROSS_FACES: [[Vec3; 4]; 2] = [ - [ - vec3(0., 0., 0.), - vec3(0., 1., 0.), - vec3(1., 0., 1.), - vec3(1., 1., 1.), - ], - [ - vec3(0., 0., 1.), - vec3(0., 1., 1.), - vec3(1., 0., 0.), - vec3(1., 1., 0.), - ] -]; -const CROSS_FACE_NORMALS: [Vec3; 2] = [ - vec3(-FRAC_1_SQRT_2, 0., FRAC_1_SQRT_2), - vec3( FRAC_1_SQRT_2, 0., FRAC_1_SQRT_2), -]; -const CROSS_FACE_NORMALS_BACK: [Vec3; 2] = [ - vec3( FRAC_1_SQRT_2, 0., -FRAC_1_SQRT_2), - vec3(-FRAC_1_SQRT_2, 0., -FRAC_1_SQRT_2), -]; -const CROSS_FACE_INDICES: [u32; 12] = [ - 0, 1, 2, 2, 1, 3, //Front side - 6, 5, 4, 7, 5, 6, //Back side -]; - - -const UV_COORDS: [[f32; 2]; 4] = [ - [0., 0.], - [0., 1.], - [1., 0.], - [1., 1.], -]; - -#[derive(Default)] -pub struct MeshBuilder { - vertex_buffer: Vec, - index_buffer: Vec, - idx_counter: u32, -} -impl MeshBuilder { - pub fn new() -> Self { - Self::default() - } - - pub fn add_face(&mut self, face: CubeFace, coord: IVec3, texture: u8) { - let coord = coord.as_vec3(); - let face_index = face as usize; - - //Push vertices - let norm = CUBE_FACE_NORMALS[face_index]; - let vert = CUBE_FACE_VERTICES[face_index]; - self.vertex_buffer.reserve(4); - for i in 0..4 { - self.vertex_buffer.push(ChunkVertex { - position: (coord + vert[i]).to_array(), - normal: norm.to_array(), - uv: UV_COORDS[i], - tex_index: texture - }); - } - - //Push indices - self.index_buffer.extend_from_slice(&CUBE_FACE_INDICES.map(|x| x + self.idx_counter)); - - //Increment idx counter - self.idx_counter += 4; - } - - pub fn add_diagonal_face(&mut self, coord: IVec3, face_type: DiagonalFace, front_texture: u8, back_texture: u8) { - //Push vertices - let face_type = face_type as usize; - let vertices = CROSS_FACES[face_type]; - let normal_front = CROSS_FACE_NORMALS[face_type].to_array(); - let normal_back = CROSS_FACE_NORMALS_BACK[face_type].to_array(); - self.vertex_buffer.reserve(8); - for i in 0..4 { //push front vertices - self.vertex_buffer.push(ChunkVertex { - position: (coord.as_vec3() + vertices[i]).to_array(), - normal: normal_front, - uv: UV_COORDS[i], - tex_index: front_texture - }) - } - for i in 0..4 { //push back vertices - self.vertex_buffer.push(ChunkVertex { - position: (coord.as_vec3() + vertices[i]).to_array(), - normal: normal_back, - uv: UV_COORDS[i], - tex_index: back_texture - }) - } - - //Push indices - self.index_buffer.extend_from_slice(&CROSS_FACE_INDICES.map(|x| x + self.idx_counter)); - - //Increment idx counter - self.idx_counter += 8; - } - - pub fn add_model(&mut self, position: Vec3, vertices: &[ChunkVertex], indices: Option<&[u32]>) { - //push vertices - self.vertex_buffer.extend(vertices.iter().map(|vertex| { - let mut vertex = *vertex; - vertex.position[0] += position.x; - vertex.position[0] += position.y; - vertex.position[0] += position.z; - vertex - })); - //push indices - if let Some(indices) = indices { - self.index_buffer.extend(indices.iter().map(|x| x + self.idx_counter)); - } else { - self.index_buffer.extend(0..(self.vertex_buffer.len() as u32)); - } - //increment idx counter - self.idx_counter += vertices.len() as u32; - } - - pub fn finish(self) -> (Vec, Vec) { - (self.vertex_buffer, self.index_buffer) - } -} +use strum::EnumIter; +use glam::{ivec3, vec3, IVec3, Vec3}; +use std::f32::consts::FRAC_1_SQRT_2; +use crate::rendering::world::ChunkVertex; + +#[repr(usize)] +#[derive(Clone, Copy, Debug, EnumIter)] +pub enum CubeFace { + Top = 0, + Front = 4, + Left = 2, + Right = 3, + Back = 1, + Bottom = 5, +} +impl CubeFace { + pub const fn normal(self) -> IVec3 { + CUBE_FACE_NORMALS_IVEC3[self as usize] + } +} + +const CUBE_FACE_VERTICES: [[Vec3; 4]; 6] = [ + [vec3(0., 1., 0.), vec3(0., 1., 1.), vec3(1., 1., 0.), vec3(1., 1., 1.)], + [vec3(0., 0., 0.), vec3(0., 1., 0.), vec3(1., 0., 0.), vec3(1., 1., 0.)], + [vec3(0., 0., 1.), vec3(0., 1., 1.), vec3(0., 0., 0.), vec3(0., 1., 0.)], + [vec3(1., 0., 0.), vec3(1., 1., 0.), vec3(1., 0., 1.), vec3(1., 1., 1.)], + [vec3(1., 0., 1.), vec3(1., 1., 1.), vec3(0., 0., 1.), vec3(0., 1., 1.)], + [vec3(0., 0., 1.), vec3(0., 0., 0.), vec3(1., 0., 1.), vec3(1., 0., 0.)], +]; +const CUBE_FACE_NORMALS_IVEC3: [IVec3; 6] = [ + ivec3( 0, 1, 0), + ivec3( 0, 0, -1), + ivec3(-1, 0, 0), + ivec3( 1, 0, 0), + ivec3( 0, 0, 1), + ivec3( 0, -1, 0) +]; +const CUBE_FACE_NORMALS: [Vec3; 6] = [ + vec3(0., 1., 0.), + vec3(0., 0., -1.), + vec3(-1.,0., 0.), + vec3(1., 0., 0.), + vec3(0., 0., 1.), + vec3(0., -1.,0.) +]; +const CUBE_FACE_INDICES: [u32; 6] = [0, 1, 2, 2, 1, 3]; + +#[repr(usize)] +pub enum DiagonalFace { + RigthZ = 0, + LeftZ = 1, +} +const CROSS_FACES: [[Vec3; 4]; 2] = [ + [ + vec3(0., 0., 0.), + vec3(0., 1., 0.), + vec3(1., 0., 1.), + vec3(1., 1., 1.), + ], + [ + vec3(0., 0., 1.), + vec3(0., 1., 1.), + vec3(1., 0., 0.), + vec3(1., 1., 0.), + ] +]; +const CROSS_FACE_NORMALS: [Vec3; 2] = [ + vec3(-FRAC_1_SQRT_2, 0., FRAC_1_SQRT_2), + vec3( FRAC_1_SQRT_2, 0., FRAC_1_SQRT_2), +]; +const CROSS_FACE_NORMALS_BACK: [Vec3; 2] = [ + vec3( FRAC_1_SQRT_2, 0., -FRAC_1_SQRT_2), + vec3(-FRAC_1_SQRT_2, 0., -FRAC_1_SQRT_2), +]; +const CROSS_FACE_INDICES: [u32; 12] = [ + 0, 1, 2, 2, 1, 3, //Front side + 6, 5, 4, 7, 5, 6, //Back side +]; + + +const UV_COORDS: [[f32; 2]; 4] = [ + [0., 1.], + [0., 0.], + [1., 1.], + [1., 0.], +]; + +#[derive(Default)] +pub struct MeshBuilder { + offset: Vec3, + vertex_buffer: Vec, + index_buffer: Vec, + idx_counter: u32, +} +impl MeshBuilder { + pub fn new() -> Self { + Self::default() + } + + pub fn new_with_offset(offset: Vec3) -> Self { + Self { offset, ..Self::new() } + } + + pub fn add_face(&mut self, face: CubeFace, coord: IVec3, texture: u8) { + let coord = coord.as_vec3(); + let face_index = face as usize; + + //Push vertices + let norm = CUBE_FACE_NORMALS[face_index]; + let vert = CUBE_FACE_VERTICES[face_index]; + self.vertex_buffer.reserve(4); + for i in 0..4 { + self.vertex_buffer.push(ChunkVertex { + position: (coord + vert[i] + self.offset).to_array(), + normal: norm.to_array(), + uv: UV_COORDS[i], + tex_index: texture as u32 + }); + } + + //Push indices + self.index_buffer.extend_from_slice(&CUBE_FACE_INDICES.map(|x| x + self.idx_counter)); + + //Increment idx counter + self.idx_counter += 4; + } + + pub fn add_diagonal_face(&mut self, coord: IVec3, face_type: DiagonalFace, front_texture: u8, back_texture: u8) { + //Push vertices + let face_type = face_type as usize; + let vertices = CROSS_FACES[face_type]; + let normal_front = CROSS_FACE_NORMALS[face_type].to_array(); + let normal_back = CROSS_FACE_NORMALS_BACK[face_type].to_array(); + self.vertex_buffer.reserve(8); + for i in 0..4 { //push front vertices + self.vertex_buffer.push(ChunkVertex { + position: (coord.as_vec3() + vertices[i] + self.offset).to_array(), + normal: normal_front, + uv: UV_COORDS[i], + tex_index: front_texture as u32 + }) + } + for i in 0..4 { //push back vertices + self.vertex_buffer.push(ChunkVertex { + position: (coord.as_vec3() + vertices[i] + self.offset).to_array(), + normal: normal_back, + uv: UV_COORDS[i], + tex_index: back_texture as u32 + }) + } + + //Push indices + self.index_buffer.extend_from_slice(&CROSS_FACE_INDICES.map(|x| x + self.idx_counter)); + + //Increment idx counter + self.idx_counter += 8; + } + + //XXX: needs offset supprt + // pub fn add_model(&mut self, position: Vec3, vertices: &[ChunkVertex], indices: Option<&[u32]>) { + // //push vertices + // self.vertex_buffer.extend(vertices.iter().map(|vertex| { + // let mut vertex = *vertex; + // vertex.position[0] += position.x; + // vertex.position[0] += position.y; + // vertex.position[0] += position.z; + // vertex + // })); + // //push indices + // if let Some(indices) = indices { + // self.index_buffer.extend(indices.iter().map(|x| x + self.idx_counter)); + // } else { + // self.index_buffer.extend(0..(self.vertex_buffer.len() as u32)); + // } + // //increment idx counter + // self.idx_counter += vertices.len() as u32; + // } + + pub fn finish(self) -> (Vec, Vec) { + (self.vertex_buffer, self.index_buffer) + } +} diff --git a/kubi/src/world/tasks.rs b/kubi/src/world/tasks.rs index 87bda90..a481f5f 100644 --- a/kubi/src/world/tasks.rs +++ b/kubi/src/world/tasks.rs @@ -63,7 +63,7 @@ impl ChunkTaskManager { let ( (vertices, indices), (trans_vertices, trans_indices), - ) = generate_mesh(data); + ) = generate_mesh(position, data); ChunkTaskResponse::GeneratedMesh { position, vertices, indices,