diff --git a/Cargo.lock b/Cargo.lock index 7e5a25e..c152a5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,10 +40,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", + "getrandom 0.2.15", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", ] [[package]] @@ -60,30 +69,9 @@ dependencies = [ "jni-sys", "libc", "log", - "ndk 0.8.0", + "ndk", "ndk-context", - "ndk-sys 0.5.0+25.2.9519653", - "num_enum", - "thiserror 1.0.69", -] - -[[package]] -name = "android-activity" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" -dependencies = [ - "android-properties", - "bitflags 2.8.0", - "cc", - "cesu8", - "jni", - "jni-sys", - "libc", - "log", - "ndk 0.9.0", - "ndk-context", - "ndk-sys 0.6.0+11769913", + "ndk-sys", "num_enum", "thiserror 1.0.69", ] @@ -124,6 +112,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "arrayvec" version = "0.7.6" @@ -142,7 +136,7 @@ version = "0.38.0+1.3.281" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" dependencies = [ - "libloading", + "libloading 0.8.6", ] [[package]] @@ -172,15 +166,30 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec 0.6.3", +] + [[package]] name = "bit-set" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "bit-vec", + "bit-vec 0.8.0", ] +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bit-vec" version = "0.8.0" @@ -288,39 +297,13 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "calloop" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" -dependencies = [ - "bitflags 2.8.0", - "log", - "polling", - "rustix", - "slab", - "thiserror 1.0.69", -] - [[package]] name = "calloop-wayland-source" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" dependencies = [ - "calloop 0.12.4", - "rustix", - "wayland-backend", - "wayland-client", -] - -[[package]] -name = "calloop-wayland-source" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" -dependencies = [ - "calloop 0.13.0", + "calloop", "rustix", "wayland-backend", "wayland-client", @@ -523,12 +506,29 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + [[package]] name = "cursor-icon" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" +[[package]] +name = "d3d12" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2daefd788d1e96e0a9d66dee4b828b883509bc3ea9ce30665f04c3246372690c" +dependencies = [ + "bitflags 1.3.2", + "libloading 0.7.4", + "winapi", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -541,7 +541,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading", + "libloading 0.8.6", ] [[package]] @@ -559,50 +559,26 @@ 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 = "drm" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f" -dependencies = [ - "bitflags 2.8.0", - "bytemuck", - "drm-ffi", - "drm-fourcc", - "libc", - "rustix", -] - -[[package]] -name = "drm-ffi" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e41459d99a9b529845f6d2c909eb9adf3b6d2f82635ae40be8de0601726e8b" -dependencies = [ - "drm-sys", - "rustix", -] - [[package]] name = "drm-fourcc" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4" +dependencies = [ + "serde", +] [[package]] -name = "drm-sys" -version = "0.8.0" +name = "env_logger" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bafb66c8dbc944d69e15cfcc661df7e703beffbaec8bd63151368b06c5f9858c" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ - "libc", - "linux-raw-sys 0.6.5", + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", ] [[package]] @@ -621,6 +597,16 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "external-memory" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4dfe8d292b014422776a8c516862d2bff8a81b223a4461dfdc45f3862dc9d39" +dependencies = [ + "bitflags 1.3.2", + "drm-fourcc", +] + [[package]] name = "fdeflate" version = "0.3.7" @@ -673,6 +659,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "gethostname" version = "0.4.3" @@ -691,7 +686,100 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "gfx-auxil" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1694991b11d642680e82075a75c7c2bd75556b805efa7660b705689f05b1ab1c" +dependencies = [ + "fxhash", + "gfx-hal", + "spirv_cross", +] + +[[package]] +name = "gfx-backend-dx11" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f9e453baf3aaef2b0c354ce0b3d63d76402e406a59b64b7182d123cfa6635ae" +dependencies = [ + "arrayvec 0.5.2", + "bitflags 1.3.2", + "gfx-auxil", + "gfx-hal", + "gfx-renderdoc", + "libloading 0.7.4", + "log", + "parking_lot 0.11.2", + "range-alloc", + "raw-window-handle 0.3.4", + "smallvec", + "spirv_cross", + "thunderdome", + "winapi", + "wio", +] + +[[package]] +name = "gfx-backend-dx12" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21506399f64a3c4d389182a89a30073856ae33eb712315456b4fd8f39ee7682a" +dependencies = [ + "arrayvec 0.5.2", + "bit-set 0.5.3", + "bitflags 1.3.2", + "d3d12", + "gfx-auxil", + "gfx-hal", + "gfx-renderdoc", + "log", + "parking_lot 0.11.2", + "range-alloc", + "raw-window-handle 0.3.4", + "smallvec", + "spirv_cross", + "thunderdome", + "winapi", +] + +[[package]] +name = "gfx-hal" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fbb575ea793dd0507b3082f4f2cde62dc9f3cebd98f5cd49ba2a4da97a976fd" +dependencies = [ + "bitflags 1.3.2", + "external-memory", + "naga 0.5.0", + "raw-window-handle 0.3.4", + "thiserror 1.0.69", +] + +[[package]] +name = "gfx-renderdoc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8027995e247e2426d3a00d13f5191dd56c314bff02dc4b54cbf727f1ba9c40a" +dependencies = [ + "libloading 0.7.4", + "log", + "renderdoc-sys 0.7.1", ] [[package]] @@ -711,6 +799,34 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "glam" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677" + +[[package]] +name = "glfw" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8c61a3f08ac5eb93c8dc0e9f2e6b2c7a7d14da089db39d43d696bc4fd025d4c" +dependencies = [ + "bitflags 1.3.2", + "glfw-sys", + "objc2 0.5.2", + "raw-window-handle 0.6.2", + "winapi", +] + +[[package]] +name = "glfw-sys" +version = "5.0.0+3.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dfc32d45fb58ff38b112696907963a7d671e9cf742b16f882062169a053cf88" +dependencies = [ + "cmake", +] + [[package]] name = "glow" version = "0.16.0" @@ -737,29 +853,17 @@ dependencies = [ "glutin_egl_sys", "glutin_glx_sys", "glutin_wgl_sys", - "libloading", + "libloading 0.8.6", "objc2 0.5.2", "objc2-app-kit", "objc2-foundation", "once_cell", - "raw-window-handle", + "raw-window-handle 0.6.2", "wayland-sys", "windows-sys 0.52.0", "x11-dl", ] -[[package]] -name = "glutin-winit" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85edca7075f8fc728f28cb8fbb111a96c3b89e930574369e3e9c27eb75d3788f" -dependencies = [ - "cfg_aliases 0.2.1", - "glutin", - "raw-window-handle", - "winit 0.30.8", -] - [[package]] name = "glutin_egl_sys" version = "0.7.1" @@ -873,6 +977,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "icrate" version = "0.0.4" @@ -894,6 +1004,26 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "is-terminal" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" +dependencies = [ + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "jni" version = "0.21.1" @@ -942,7 +1072,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "libloading", + "libloading 0.8.6", "pkg-config", ] @@ -964,6 +1094,16 @@ version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +[[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" version = "0.8.6" @@ -991,12 +1131,6 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" -[[package]] -name = "linux-raw-sys" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7" - [[package]] name = "litrs" version = "0.4.1" @@ -1081,10 +1215,12 @@ dependencies = [ "cgmath", "concat-idents", "ctrlc", - "drm", + "gfx-backend-dx11", + "gfx-backend-dx12", "gl_generator", + "glam", + "glfw", "glutin", - "glutin-winit", "jobserver", "libc", "log", @@ -1092,9 +1228,11 @@ dependencies = [ "num_cpus", "objc", "png", + "pretty_env_logger", "rand", - "raw-window-handle", + "raw-window-handle 0.6.2", "shaderc", + "tbc", "thiserror 2.0.11", "tobj", "tokio", @@ -1103,8 +1241,7 @@ dependencies = [ "vitasdk-sys", "vulkanalia", "wgpu", - "winit 0.29.15", - "winit 0.30.8", + "winit", ] [[package]] @@ -1124,18 +1261,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] +[[package]] +name = "naga" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef670817eef03d356d5a509ea275e7dd3a78ea9e24261ea3cb2dfed1abb08f64" +dependencies = [ + "bit-set 0.5.3", + "bitflags 1.3.2", + "fxhash", + "log", + "num-traits", + "thiserror 1.0.69", +] + [[package]] name = "naga" version = "24.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e380993072e52eef724eddfcde0ed013b0c023c3f0417336ed041aa9f076994e" dependencies = [ - "arrayvec", - "bit-set", + "arrayvec 0.7.6", + "bit-set 0.8.0", "bitflags 2.8.0", "cfg_aliases 0.2.1", "codespan-reporting", @@ -1159,24 +1310,9 @@ dependencies = [ "bitflags 2.8.0", "jni-sys", "log", - "ndk-sys 0.5.0+25.2.9519653", + "ndk-sys", "num_enum", - "raw-window-handle", - "thiserror 1.0.69", -] - -[[package]] -name = "ndk" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" -dependencies = [ - "bitflags 2.8.0", - "jni-sys", - "log", - "ndk-sys 0.6.0+11769913", - "num_enum", - "raw-window-handle", + "raw-window-handle 0.6.2", "thiserror 1.0.69", ] @@ -1195,15 +1331,6 @@ 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.29.0" @@ -1318,30 +1445,6 @@ dependencies = [ "objc2-quartz-core", ] -[[package]] -name = "objc2-cloud-kit" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" -dependencies = [ - "bitflags 2.8.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-core-location", - "objc2-foundation", -] - -[[package]] -name = "objc2-contacts" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" -dependencies = [ - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation", -] - [[package]] name = "objc2-core-data" version = "0.2.2" @@ -1366,18 +1469,6 @@ dependencies = [ "objc2-metal", ] -[[package]] -name = "objc2-core-location" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" -dependencies = [ - "block2 0.5.1", - "objc2 0.5.2", - "objc2-contacts", - "objc2-foundation", -] - [[package]] name = "objc2-encode" version = "3.0.0" @@ -1403,18 +1494,6 @@ dependencies = [ "objc2 0.5.2", ] -[[package]] -name = "objc2-link-presentation" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" -dependencies = [ - "block2 0.5.1", - "objc2 0.5.2", - "objc2-app-kit", - "objc2-foundation", -] - [[package]] name = "objc2-metal" version = "0.2.2" @@ -1440,61 +1519,6 @@ dependencies = [ "objc2-metal", ] -[[package]] -name = "objc2-symbols" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" -dependencies = [ - "objc2 0.5.2", - "objc2-foundation", -] - -[[package]] -name = "objc2-ui-kit" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" -dependencies = [ - "bitflags 2.8.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-cloud-kit", - "objc2-core-data", - "objc2-core-image", - "objc2-core-location", - "objc2-foundation", - "objc2-link-presentation", - "objc2-quartz-core", - "objc2-symbols", - "objc2-uniform-type-identifiers", - "objc2-user-notifications", -] - -[[package]] -name = "objc2-uniform-type-identifiers" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" -dependencies = [ - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation", -] - -[[package]] -name = "objc2-user-notifications" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" -dependencies = [ - "bitflags 2.8.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-core-location", - "objc2-foundation", -] - [[package]] name = "objc_exception" version = "0.1.2" @@ -1552,6 +1576,17 @@ dependencies = [ "ttf-parser", ] +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -1559,7 +1594,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -1587,26 +1636,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "pin-project" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1653,7 +1682,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -1662,6 +1691,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" +[[package]] +name = "pretty_env_logger" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" +dependencies = [ + "env_logger", + "log", +] + [[package]] name = "proc-macro-crate" version = "3.2.0" @@ -1706,20 +1745,20 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.5" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ - "libc", "rand_chacha", "rand_core", + "zerocopy 0.8.14", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", "rand_core", @@ -1727,11 +1766,12 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" dependencies = [ - "getrandom", + "getrandom 0.3.1", + "zerocopy 0.8.14", ] [[package]] @@ -1740,12 +1780,40 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde" +[[package]] +name = "raw-window-handle" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28f55143d0548dad60bb4fbdc835a3d7ac6acc3324506450c5fdd6e42903a76" +dependencies = [ + "libc", + "raw-window-handle 0.4.3", +] + +[[package]] +name = "raw-window-handle" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" +dependencies = [ + "cty", +] + [[package]] name = "raw-window-handle" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.3.5" @@ -1755,15 +1823,6 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.5.8" @@ -1773,6 +1832,41 @@ dependencies = [ "bitflags 2.8.0", ] +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "renderdoc-sys" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157" + [[package]] name = "renderdoc-sys" version = "1.1.0" @@ -1809,7 +1903,7 @@ dependencies = [ "bitflags 2.8.0", "errno", "libc", - "linux-raw-sys 0.4.15", + "linux-raw-sys", "windows-sys 0.59.0", ] @@ -1849,20 +1943,7 @@ dependencies = [ "ab_glyph", "log", "memmap2", - "smithay-client-toolkit 0.18.1", - "tiny-skia", -] - -[[package]] -name = "sctk-adwaita" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" -dependencies = [ - "ab_glyph", - "log", - "memmap2", - "smithay-client-toolkit 0.19.2", + "smithay-client-toolkit", "tiny-skia", ] @@ -1968,8 +2049,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" dependencies = [ "bitflags 2.8.0", - "calloop 0.12.4", - "calloop-wayland-source 0.2.0", + "calloop", + "calloop-wayland-source", "cursor-icon", "libc", "log", @@ -1980,33 +2061,8 @@ dependencies = [ "wayland-client", "wayland-csd-frame", "wayland-cursor", - "wayland-protocols 0.31.2", - "wayland-protocols-wlr 0.2.0", - "wayland-scanner", - "xkeysym", -] - -[[package]] -name = "smithay-client-toolkit" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" -dependencies = [ - "bitflags 2.8.0", - "calloop 0.13.0", - "calloop-wayland-source 0.3.0", - "cursor-icon", - "libc", - "log", - "memmap2", - "rustix", - "thiserror 1.0.69", - "wayland-backend", - "wayland-client", - "wayland-csd-frame", - "wayland-cursor", - "wayland-protocols 0.32.5", - "wayland-protocols-wlr 0.3.5", + "wayland-protocols", + "wayland-protocols-wlr", "wayland-scanner", "xkeysym", ] @@ -2039,6 +2095,17 @@ dependencies = [ "bitflags 2.8.0", ] +[[package]] +name = "spirv_cross" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60647fadbf83c4a72f0d7ea67a7ca3a81835cf442b8deae5c134c3e0055b2e14" +dependencies = [ + "cc", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -2084,6 +2151,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tbc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5488807ecc13530932d661bc4ea7ea621080fdbf354b7f54506fcc46d4d63bf5" + [[package]] name = "termcolor" version = "1.4.1" @@ -2143,6 +2216,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "thunderdome" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f685624f172cd0bde6f3363412455e81c018f2379fdf5a218e0be003f1bba642" + [[package]] name = "tiny-skia" version = "0.11.4" @@ -2150,7 +2229,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" dependencies = [ "arrayref", - "arrayvec", + "arrayvec 0.7.6", "bytemuck", "cfg-if", "log", @@ -2188,7 +2267,7 @@ dependencies = [ "bytes", "libc", "mio", - "parking_lot", + "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", "socket2", @@ -2337,10 +2416,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb009d13f63b0cbabcf51fbfb62dfe8327d15a1cfdc689ee579989d20fb4ed76" dependencies = [ "cocoa", - "libloading", + "libloading 0.8.6", "metal 0.27.0", "objc", - "raw-window-handle", + "raw-window-handle 0.6.2", "vulkanalia-sys", ] @@ -2369,6 +2448,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -2500,18 +2588,6 @@ dependencies = [ "wayland-scanner", ] -[[package]] -name = "wayland-protocols" -version = "0.32.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e" -dependencies = [ - "bitflags 2.8.0", - "wayland-backend", - "wayland-client", - "wayland-scanner", -] - [[package]] name = "wayland-protocols-plasma" version = "0.2.0" @@ -2521,20 +2597,7 @@ dependencies = [ "bitflags 2.8.0", "wayland-backend", "wayland-client", - "wayland-protocols 0.31.2", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols-plasma" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b31cab548ee68c7eb155517f2212049dc151f7cd7910c2b66abfd31c3ee12bd" -dependencies = [ - "bitflags 2.8.0", - "wayland-backend", - "wayland-client", - "wayland-protocols 0.32.5", + "wayland-protocols", "wayland-scanner", ] @@ -2547,20 +2610,7 @@ dependencies = [ "bitflags 2.8.0", "wayland-backend", "wayland-client", - "wayland-protocols 0.31.2", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols-wlr" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "782e12f6cd923c3c316130d56205ebab53f55d6666b7faddfad36cecaeeb4022" -dependencies = [ - "bitflags 2.8.0", - "wayland-backend", - "wayland-client", - "wayland-protocols 0.32.5", + "wayland-protocols", "wayland-scanner", ] @@ -2607,32 +2657,22 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "wgpu" version = "24.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e41253fc7b660735e2a2d9a58c563f2a047d3cc3445293d8f4095538c9e8afbe" dependencies = [ - "arrayvec", + "arrayvec 0.7.6", "bitflags 2.8.0", "cfg_aliases 0.2.1", "document-features", "js-sys", "log", - "naga", - "parking_lot", + "naga 24.0.0", + "parking_lot 0.12.3", "profiling", - "raw-window-handle", + "raw-window-handle 0.6.2", "smallvec", "static_assertions", "wasm-bindgen", @@ -2649,18 +2689,18 @@ version = "24.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82a39b8842dc9ffcbe34346e3ab6d496b32a47f6497e119d762c97fcaae3cb37" dependencies = [ - "arrayvec", - "bit-vec", + "arrayvec 0.7.6", + "bit-vec 0.8.0", "bitflags 2.8.0", "cfg_aliases 0.2.1", "document-features", "indexmap", "log", - "naga", + "naga 24.0.0", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "profiling", - "raw-window-handle", + "raw-window-handle 0.6.2", "rustc-hash", "smallvec", "thiserror 2.0.11", @@ -2675,9 +2715,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a782e5056b060b0b4010881d1decddd059e44f2ecd01e2db2971b48ad3627e5" dependencies = [ "android_system_properties", - "arrayvec", + "arrayvec 0.7.6", "ash", - "bit-set", + "bit-set 0.8.0", "bitflags 2.8.0", "block", "bytemuck", @@ -2691,19 +2731,19 @@ dependencies = [ "js-sys", "khronos-egl", "libc", - "libloading", + "libloading 0.8.6", "log", "metal 0.31.0", - "naga", - "ndk-sys 0.5.0+25.2.9519653", + "naga 24.0.0", + "ndk-sys", "objc", "once_cell", "ordered-float", - "parking_lot", + "parking_lot 0.12.3", "profiling", "range-alloc", - "raw-window-handle", - "renderdoc-sys", + "raw-window-handle 0.6.2", + "renderdoc-sys 1.1.0", "rustc-hash", "smallvec", "thiserror 2.0.11", @@ -3042,11 +3082,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" dependencies = [ "ahash", - "android-activity 0.5.2", + "android-activity", "atomic-waker", "bitflags 2.8.0", "bytemuck", - "calloop 0.12.4", + "calloop", "cfg_aliases 0.1.1", "core-foundation", "core-graphics", @@ -3056,85 +3096,33 @@ dependencies = [ "libc", "log", "memmap2", - "ndk 0.8.0", - "ndk-sys 0.5.0+25.2.9519653", + "ndk", + "ndk-sys", "objc2 0.4.1", "once_cell", "orbclient", "percent-encoding", - "raw-window-handle", + "raw-window-handle 0.6.2", "redox_syscall 0.3.5", "rustix", - "sctk-adwaita 0.8.3", - "smithay-client-toolkit 0.18.1", + "sctk-adwaita", + "smithay-client-toolkit", "smol_str", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", "wayland-backend", "wayland-client", - "wayland-protocols 0.31.2", - "wayland-protocols-plasma 0.2.0", + "wayland-protocols", + "wayland-protocols-plasma", "web-sys", - "web-time 0.2.4", + "web-time", "windows-sys 0.48.0", "x11-dl", "x11rb", "xkbcommon-dl", ] -[[package]] -name = "winit" -version = "0.30.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d74280aabb958072864bff6cfbcf9025cf8bfacdde5e32b5e12920ef703b0f" -dependencies = [ - "ahash", - "android-activity 0.6.0", - "atomic-waker", - "bitflags 2.8.0", - "block2 0.5.1", - "bytemuck", - "calloop 0.13.0", - "cfg_aliases 0.2.1", - "concurrent-queue", - "core-foundation", - "core-graphics", - "cursor-icon", - "dpi", - "js-sys", - "libc", - "memmap2", - "ndk 0.9.0", - "objc2 0.5.2", - "objc2-app-kit", - "objc2-foundation", - "objc2-ui-kit", - "orbclient", - "percent-encoding", - "pin-project", - "raw-window-handle", - "redox_syscall 0.4.1", - "rustix", - "sctk-adwaita 0.10.1", - "smithay-client-toolkit 0.19.2", - "smol_str", - "tracing", - "unicode-segmentation", - "wasm-bindgen", - "wasm-bindgen-futures", - "wayland-backend", - "wayland-client", - "wayland-protocols 0.32.5", - "wayland-protocols-plasma 0.3.5", - "web-sys", - "web-time 1.1.0", - "windows-sys 0.52.0", - "x11-dl", - "x11rb", - "xkbcommon-dl", -] - [[package]] name = "winnow" version = "0.6.24" @@ -3144,6 +3132,24 @@ dependencies = [ "memchr", ] +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.8.0", +] + [[package]] name = "x11-dl" version = "2.21.0" @@ -3164,7 +3170,7 @@ dependencies = [ "as-raw-xcb-connection", "gethostname", "libc", - "libloading", + "libloading 0.8.6", "once_cell", "rustix", "x11rb-protocol", @@ -3220,7 +3226,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468" +dependencies = [ + "zerocopy-derive 0.8.14", ] [[package]] @@ -3233,3 +3248,14 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zerocopy-derive" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index e1d8096..83ca2a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "minemod" version = "0.1.0" edition = "2024" +default-run = "minemod" [package.metadata.vita] title_id = "PKDC10002" @@ -52,29 +53,46 @@ tracing = { version = "0.1.41", features = [ ] } tracing-subscriber = "0.3.19" log = "0.4.25" +pretty_env_logger = "0.5.0" anyhow = "1.0.95" thiserror = "2.0.11" cgmath = "0.18.0" -png = "0.17.16" +glam = "0.29.2" +#image_full = { package = "image", version = "0.25.5" } +#image = { version = "0.25.5", default-features = false } +#image_dds = "0.7.1" +tbc = "0.3.0" +png = "0.17.16" # temporary tobj = { version = "4.0.2", features = ["log"] } +rand = "0.9.0" [target.'cfg(any(target_os = "windows",target_os = "linux",target_os = "macos"))'.dependencies] +tokio = { version = "1.43.0", features = ["full"] } +glfw = "0.59.0" +#glfw = {version = "0.59.0", default-features = false, features = ["raw-window-handle-v0-6"]} # we literally just need the window management parts # nevermind this crashes immediately +## OPENGL glutin = "0.32.2" -glutin-winit = "0.5.0" +#glutin-winit = "0.5.0" # no winit >:( raw-window-handle = "0.6.2" -winit = { version = "0.30.0", features = ["rwh_06"] } -drm = "0.14.1" +# winit is hereby banished from this realm because it pissed me off >:( +# its designed around mobile and desktop, but its mobile side sticks around even when its only being used for desktop and theres no way to cut it out +# on top of its piss poor documentation around the breaking changes in update 0.3 +#winit = { version = "0.30.0", features = ["rwh_06"] } +#drm = "0.14.1" # unix only +## END OPENGL +## VULKAN vulkanalia = { version = "0.26.0", features = [ "libloading", "provisional", "window", ] } +# kept for now so the vulkan demo works (also the tutorial is using it so once the tutorial is done and i fully understand how vulkan works i will be tossing winit fully and reworking the vulkan structure to better suit the engine) old_winit = { package = "winit", version = "0.29" } # dont update, many many breaking changes with no guides ctrlc = "3.4.5" -tokio = { version = "1.43.0", features = ["full"] } +## END VULKAN [target.'cfg(target_family = "wasm")'.dependencies] wgpu = "24.0.0" @@ -83,7 +101,6 @@ wgpu = "24.0.0" vitasdk-sys = { version = "0.3.3", features = ["all-stubs"] } concat-idents = "1.1.5" libc = "0.2.153" -rand = "0.8.5" tokio = { version = "1.36.0", features = [ "fs", "macros", @@ -98,6 +115,8 @@ tokio = { version = "1.36.0", features = [ ] } [target.'cfg(target_os = "windows")'.dependencies] +gfx-backend-dx12 = "0.9.1" +gfx-backend-dx11 = "0.9.0" [target.'cfg(target_os = "linux")'.dependencies] diff --git a/src/bin/bcntool.rs b/src/bin/bcntool.rs new file mode 100644 index 0000000..efdce38 --- /dev/null +++ b/src/bin/bcntool.rs @@ -0,0 +1,9 @@ +use log::*; + +// This tool will be used to convert any common image format to BCn of a specified level or BC1 by default. +fn main() { + pretty_env_logger::formatted_timed_builder().filter_level(LevelFilter::Info).init(); + info!("We support BC1, BC3, and BC4 via the tbc crate."); + info!("Unfortunately this tool is not currently implemented."); + unimplemented!(); +} diff --git a/src/cataclysm/mod.rs b/src/cataclysm/mod.rs index 83fde03..c2f7a00 100644 --- a/src/cataclysm/mod.rs +++ b/src/cataclysm/mod.rs @@ -1,16 +1,104 @@ -pub(crate) trait GraphicsCommander {} +use std::collections::HashMap; + +use glam::Vec3; + +use crate::graphics_engines::Renderable; pub struct Cataclysm { - game_objects:Vec, + pub chunks:HashMap<(u32, u32, u32), CataclysmChunk>, } -pub struct GameObject { - pos:(f64, f64, f64), +pub struct CataclysmChunk { + pub simple_blocks:HashMap<(u8, u8, u8), SimpleBlock>, + pub fancy_blocks: HashMap, + pub smart_blocks: HashMap, + pub entities: Vec, } -pub enum ModelKind { - Cube, - Complex(), +impl Cataclysm { + pub const CHUNK_SIZE:u8 = 32; + pub const ENTITY_RUN_LIMIT:u8 = 5; + pub const WORLD_SIZE:(u8, u8) = (2, 2); + + pub fn new() -> Self { + Self { + chunks: HashMap::new() + } + } } -pub struct ResourceReference {} +impl CataclysmChunk { + pub fn new() -> Self { + Self { + simple_blocks: HashMap::new(), + fancy_blocks: HashMap::new(), + smart_blocks: HashMap::new(), + entities: vec![], + } + } +} + +pub struct SimpleBlock { + +} + +impl Renderable for SimpleBlock { + #[rustfmt::skip] + fn vertext_data<'a>() -> (&'a [f32], &'a [u32]) { + (&[ + -1.0, -1.0, 0.5, //0 + 1.0, -1.0, 0.5, //1 + -1.0, 1.0, 0.5, //2 + 1.0, 1.0, 0.5, //3 + -1.0, -1.0, -0.5, //4 + 1.0, -1.0, -0.5, //5 + -1.0, 1.0, -0.5, //6 + 1.0, 1.0, -0.5 //7 + ], + &[ + //Top + 2, 6, 7, + 2, 3, 7, + + //Bottom + 0, 4, 5, + 0, 1, 5, + + //Left + 0, 2, 6, + 0, 4, 6, + + //Right + 1, 3, 7, + 1, 5, 7, + + //Front + 0, 2, 3, + 0, 1, 3, + + //Back + 4, 6, 7, + 4, 5, 7 + ] + ) + } +} + +pub struct FancyBlock { + pub pos:Vec3, +} + +pub struct SmartBlock { + pub pos:Vec3, +} + +pub struct Entity { + pub pos:Vec3, +} + +//pub enum ModelKind { +// Cube, +// Complex(), +//} + +//pub struct ResourceReference {} diff --git a/src/graphics_engines/mod.rs b/src/graphics_engines/mod.rs index 2337c02..cc3a92c 100644 --- a/src/graphics_engines/mod.rs +++ b/src/graphics_engines/mod.rs @@ -1,6 +1,15 @@ +use anyhow::Result; + +use glfw::PWindow; + +use crate::cataclysm::Cataclysm; + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] pub mod vulkan; +#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] +pub mod vulkan_gc; + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] pub mod opengl; @@ -11,3 +20,45 @@ pub mod opengl; #[cfg(target_os = "windows")] pub mod directx; #[cfg(target_os = "vita")] pub mod gxm; + +pub trait Renderable { + fn vertext_data<'a>() -> (&'a [f32], &'a [u32]); +} + +#[repr(C)] +#[derive(Debug, Clone, Default)] +pub struct VertexData { + verts: Box<[f32]>, + indices:Box<[u32]>, +} + +#[allow(unused)] +pub trait GraphicsCommander { + fn suspend_rendering(&mut self); + fn resume_rendering(&mut self); + + // will need a reference to game engine objects + // replace with generic draw call? draw call will draw instructions to image, image may be framebuffer or not, allows gpu accelerated dynamic texture stuff + fn render(&mut self, window:&mut PWindow, cataclysm:&mut Cataclysm) -> Result<()>; + + /// This function will clear all existing vbos and replace them with its own. + fn register_vbos(&mut self, data:&[VertexData]); + // make generic for assets? + fn register_texture(&mut self); + fn destroy_texture(&mut self); + + // cleans up all data from memory, used when exiting or switching graphics backends + //fn cleanup(&mut self); + fn exit(&mut self); +} + +#[allow(unused)] +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +pub enum GMode { + Vulkan, + OpenGL, + #[cfg(target_os = "macos")] + Metal, + #[cfg(target_os = "windows")] + DirectX, +} diff --git a/src/graphics_engines/opengl/mod.rs b/src/graphics_engines/opengl/mod.rs index df0a2ec..37a6257 100644 --- a/src/graphics_engines/opengl/mod.rs +++ b/src/graphics_engines/opengl/mod.rs @@ -1,36 +1,18 @@ -use std::error::Error; -use std::ffi::CStr; -use std::ffi::CString; -use std::num::NonZeroU32; -use std::ops::Deref; +use crate::cataclysm::Cataclysm; -use gl::types::GLfloat; -use raw_window_handle::HasWindowHandle; -use winit::application::ApplicationHandler; -use winit::event::KeyEvent; -use winit::event::WindowEvent; -use winit::event_loop::ActiveEventLoop; -use winit::keyboard::Key; -use winit::keyboard::NamedKey; -use winit::window::Window; -use winit::window::WindowAttributes; +use super::GraphicsCommander; -use glutin::config::Config; -use glutin::config::ConfigTemplateBuilder; -use glutin::config::GetGlConfig; -use glutin::context::ContextApi; -use glutin::context::ContextAttributesBuilder; -use glutin::context::NotCurrentContext; -use glutin::context::PossiblyCurrentContext; -use glutin::context::Version; -use glutin::display::GetGlDisplay; -use glutin::prelude::*; -use glutin::surface::Surface; -use glutin::surface::SwapInterval; -use glutin::surface::WindowSurface; +use anyhow::Result; -use glutin_winit::DisplayBuilder; -use glutin_winit::GlWindow; +use glam::vec2; +use glam::vec3; + +use glam::Vec2; +use glam::Vec3; +use glfw::Context; +use glfw::PWindow; + +use log::*; pub mod gl { #![allow(clippy::all)] @@ -39,276 +21,136 @@ pub mod gl { pub use Gles2 as Gl; } -pub fn main(event_loop:winit::event_loop::EventLoop<()>) -> Result<(), Box> { - // The template will match only the configurations supporting rendering - // to windows. - // - // XXX We force transparency only on macOS, given that EGL on X11 doesn't - // have it, but we still want to show window. The macOS situation is like - // that, because we can query only one config at a time on it, but all - // normal platforms will return multiple configs, so we can find the config - // with transparency ourselves inside the `reduce`. - let template = ConfigTemplateBuilder::new().with_alpha_size(8).with_transparency(cfg!(target_os = "macos")); +impl GraphicsCommander for Renderer { + fn suspend_rendering(&mut self) { + } - let display_builder = DisplayBuilder::new().with_window_attributes(Some(window_attributes())); + fn resume_rendering(&mut self) { + } - let mut app = App::new(template, display_builder); - event_loop.run_app(&mut app)?; + fn render(&mut self, window:&mut glfw::PWindow, cataclysm:&mut Cataclysm) -> anyhow::Result<()> { + let (red, green, blue, alpha) = (0.0125, 0.0094, 0.0071, 1.0); + trace!("Clearing screen with color {red}|{green}|{blue}|{alpha}."); + unsafe { + self.gl.UseProgram(self.program); - app.exit_state -} + trace!("Bind."); + self.gl.BindVertexArray(self.vao); + self.gl.BindBuffer(gl::ARRAY_BUFFER, self.vbo); -impl ApplicationHandler for App { - fn resumed(&mut self, event_loop:&ActiveEventLoop) { - let (window, gl_config) = match &self.gl_display { - // We just created the event loop, so initialize the display, pick the config, and - // create the context. - GlDisplayCreationState::Builder(display_builder) => { - let (window, gl_config) = match display_builder.clone().build(event_loop, self.template.clone(), gl_config_picker) { - Ok((window, gl_config)) => (window.unwrap(), gl_config), - Err(err) => { - self.exit_state = Err(err); - event_loop.exit(); - return; - }, - }; - - println!("Picked a config with {} samples", gl_config.num_samples()); - - // Mark the display as initialized to not recreate it on resume, since the - // display is valid until we explicitly destroy it. - self.gl_display = GlDisplayCreationState::Init; - - // Create gl context. - self.gl_context = Some(create_gl_context(&window, &gl_config).treat_as_possibly_current()); - - (window, gl_config) - }, - GlDisplayCreationState::Init => { - println!("Recreating window in `resumed`"); - // Pick the config which we already use for the context. - let gl_config = self.gl_context.as_ref().unwrap().config(); - match glutin_winit::finalize_window(event_loop, window_attributes(), &gl_config) { - Ok(window) => (window, gl_config), - Err(err) => { - self.exit_state = Err(err.into()); - event_loop.exit(); - return; - }, - } - }, - }; - - let attrs = window.build_surface_attributes(Default::default()).expect("Failed to build surface attributes"); - let gl_surface = unsafe { gl_config.display().create_window_surface(&gl_config, &attrs).unwrap() }; - - // The context needs to be current for the Renderer to set up shaders and - // buffers. It also performs function loading, which needs a current context on - // WGL. - let gl_context = self.gl_context.as_ref().unwrap(); - gl_context.make_current(&gl_surface).unwrap(); - - self.renderer.get_or_insert_with(|| Renderer::new(&gl_config.display())); - - // Try setting vsync. - if let Err(res) = gl_surface.set_swap_interval(gl_context, SwapInterval::Wait(NonZeroU32::new(1).unwrap())) { - eprintln!("Error setting vsync: {res:?}"); + trace!("ClearColor."); + self.gl.ClearColor(red, green, blue, alpha); + trace!("Clear."); + self.gl.Clear(gl::COLOR_BUFFER_BIT); + trace!("DrawArrays."); + self.gl.DrawArrays(gl::TRIANGLES, 0, 3); } + trace!("Done clearing screen."); - assert!(self.state.replace(AppState { gl_surface, window }).is_none()); + window.swap_buffers(); + + Ok(()) } - fn suspended(&mut self, _event_loop:&ActiveEventLoop) { - // This event is only raised on Android, where the backing NativeWindow for a GL - // Surface can appear and disappear at any moment. - println!("Android window removed"); + fn register_texture(&mut self) { todo!() } - // Destroy the GL Surface and un-current the GL Context before ndk-glue releases - // the window back to the system. - self.state = None; + fn destroy_texture(&mut self) { todo!() } - // Make context not current. - self.gl_context = Some(self.gl_context.take().unwrap().make_not_current().unwrap().treat_as_possibly_current()); - } + //fn cleanup(&mut self) { todo!() } - fn window_event(&mut self, event_loop:&ActiveEventLoop, _window_id:winit::window::WindowId, event:WindowEvent) { - match event { - WindowEvent::Resized(size) if size.width != 0 && size.height != 0 => { - // Some platforms like EGL require resizing GL surface to update the size - // Notable platforms here are Wayland and macOS, other don't require it - // and the function is no-op, but it's wise to resize it for portability - // reasons. - if let Some(AppState { gl_surface, window: _ }) = self.state.as_ref() { - let gl_context = self.gl_context.as_ref().unwrap(); - gl_surface.resize(gl_context, NonZeroU32::new(size.width).unwrap(), NonZeroU32::new(size.height).unwrap()); - - let renderer = self.renderer.as_ref().unwrap(); - renderer.resize(size.width as i32, size.height as i32); - } - }, - WindowEvent::CloseRequested | - WindowEvent::KeyboardInput { - event: KeyEvent { - logical_key: Key::Named(NamedKey::Escape), - .. - }, - .. - } => event_loop.exit(), - _ => (), + fn exit(&mut self) { + trace!("Destroying OpenGL instance."); + unsafe { + self.gl.DeleteProgram(self.program); + for vbo in self.vbos.iter().take(self.vbos.len()) { + self.gl.DeleteBuffers(1, vbo); + } + self.gl.DeleteVertexArrays(1, &self.vao); } } - fn exiting(&mut self, _event_loop:&ActiveEventLoop) { - // NOTE: The handling below is only needed due to nvidia on Wayland to not crash - // on exit due to nvidia driver touching the Wayland display from on - // `exit` hook. - let _gl_display = self.gl_context.take().unwrap().display(); - - // Clear the window. - self.state = None; - #[cfg(egl_backend)] - #[allow(irrefutable_let_patterns)] - if let glutin::display::Display::Egl(display) = _gl_display { + fn register_vbos(&mut self, data:&[super::VertexData]) { + for data in data { + trace!("Creating OpenGL VAO."); unsafe { - display.terminate(); + let mut vao = std::mem::zeroed(); + self.gl.GenVertexArrays(1, &mut vao); + self.gl.BindVertexArray(vao); + } + trace!("Creating OpenGL VBO."); + unsafe { + let mut vbo = std::mem::zeroed(); + self.gl.GenBuffers(1, &mut vbo); + self.gl.BindBuffer(gl::ARRAY_BUFFER, vbo); + self.gl.BufferData( + gl::ARRAY_BUFFER, + (VERTEX_DATA.len() * std::mem::size_of::()) as gl::types::GLsizeiptr, + VERTEX_DATA.as_ptr() as *const _, + gl::STATIC_DRAW, + ); + } + + unsafe { + trace!("Applying shader attributes."); + let pos_attrib = self.gl.GetAttribLocation( self.program, b"position\0".as_ptr() as *const _); + let color_attrib = self.gl.GetAttribLocation(self.program, b"color\0".as_ptr() as *const _); + self.gl.VertexAttribPointer( + pos_attrib as gl::types::GLuint, + 2, + gl::FLOAT, + 0, + std::mem::size_of::() as gl::types::GLsizei, + std::ptr::null(), + ); + self.gl.VertexAttribPointer( + color_attrib as gl::types::GLuint, + 3, + gl::FLOAT, + 0, + 5 * std::mem::size_of::() as gl::types::GLsizei, + (2 * std::mem::size_of::()) as *const () as *const _, + ); + self.gl.EnableVertexAttribArray(pos_attrib as gl::types::GLuint); + self.gl.EnableVertexAttribArray(color_attrib as gl::types::GLuint); } } } - - fn about_to_wait(&mut self, _event_loop:&ActiveEventLoop) { - if let Some(AppState { gl_surface, window }) = self.state.as_ref() { - let gl_context = self.gl_context.as_ref().unwrap(); - let renderer = self.renderer.as_ref().unwrap(); - renderer.draw(); - window.request_redraw(); - - gl_surface.swap_buffers(gl_context).unwrap(); - } - } } -fn create_gl_context(window:&Window, gl_config:&Config) -> NotCurrentContext { - let raw_window_handle = window.window_handle().ok().map(|wh| wh.as_raw()); - - // The context creation part. - let context_attributes = ContextAttributesBuilder::new().build(raw_window_handle); - - // Since glutin by default tries to create OpenGL core context, which may not be - // present we should try gles. - let fallback_context_attributes = ContextAttributesBuilder::new() - .with_context_api(ContextApi::Gles(None)) - .build(raw_window_handle); - - // There are also some old devices that support neither modern OpenGL nor GLES. - // To support these we can try and create a 2.1 context. - let legacy_context_attributes = ContextAttributesBuilder::new() - .with_context_api(ContextApi::OpenGl(Some(Version::new(2, 1)))) - .build(raw_window_handle); - - // Reuse the uncurrented context from a suspended() call if it exists, otherwise - // this is the first time resumed() is called, where the context still - // has to be created. - let gl_display = gl_config.display(); - - unsafe { - gl_display.create_context(gl_config, &context_attributes).unwrap_or_else(|_| { - gl_display.create_context(gl_config, &fallback_context_attributes).unwrap_or_else(|_| { - gl_display - .create_context(gl_config, &legacy_context_attributes) - .expect("failed to create context") - }) - }) - } -} - -fn window_attributes() -> WindowAttributes { - Window::default_attributes() - .with_transparent(true) - .with_title("Glutin triangle gradient example (press Escape to exit)") -} - -enum GlDisplayCreationState { - /// The display was not build yet. - Builder(DisplayBuilder), - /// The display was already created for the application. - Init, -} - -struct App { - template: ConfigTemplateBuilder, - renderer: Option, - // NOTE: `AppState` carries the `Window`, thus it should be dropped after everything else. - state: Option, - gl_context:Option, - gl_display:GlDisplayCreationState, - exit_state:Result<(), Box>, -} - -impl App { - fn new(template:ConfigTemplateBuilder, display_builder:DisplayBuilder) -> Self { - Self { - template, - gl_display:GlDisplayCreationState::Builder(display_builder), - exit_state:Ok(()), - gl_context:None, - state:None, - renderer:None, - } - } -} - -struct AppState { - gl_surface:Surface, - // NOTE: Window should be dropped after all resources created using its - // raw-window-handle. - window: Window, -} - -// Find the config with the maximum number of samples, so our triangle will be -// smooth. -pub fn gl_config_picker(configs:Box+'_>) -> Config { - configs - .reduce(|accum, config| { - let transparency_check = config.supports_transparency().unwrap_or(false) & !accum.supports_transparency().unwrap_or(false); - - if transparency_check || config.num_samples() > accum.num_samples() { - config - } else { - accum - } - }) - .unwrap() -} +use std::ffi::CStr; +use std::ops::Deref; pub struct Renderer { program:gl::types::GLuint, vao: gl::types::GLuint, - vbo: gl::types::GLuint, + vbos: Vec, + //vbo: gl::types::GLuint, gl: gl::Gl, } impl Renderer { - pub fn new(gl_display:&D) -> Self { + pub fn create(window:&mut PWindow) -> Result { + trace!("Creating OpenGL renderer instance."); + unsafe { - let gl = gl::Gl::load_with(|symbol| { - let symbol = CString::new(symbol).unwrap(); - gl_display.get_proc_address(symbol.as_c_str()).cast() - }); + let gl = gl::Gl::load_with(|symbol| window.get_proc_address(symbol)); if let Some(renderer) = get_gl_string(&gl, gl::RENDERER) { - println!("Running on {}", renderer.to_string_lossy()); + info!("Running on {}", renderer.to_string_lossy()); } if let Some(version) = get_gl_string(&gl, gl::VERSION) { - println!("OpenGL Version {}", version.to_string_lossy()); + info!("OpenGL Version {}", version.to_string_lossy()); } if let Some(shaders_version) = get_gl_string(&gl, gl::SHADING_LANGUAGE_VERSION) { - println!("Shaders version on {}", shaders_version.to_string_lossy()); + info!("Shaders version on {}", shaders_version.to_string_lossy()); } + trace!("Loading shaders."); let vertex_shader = create_shader(&gl, gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE); let fragment_shader = create_shader(&gl, gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE); + trace!("Creating OpenGL shader program."); let program = gl.CreateProgram(); gl.AttachShader(program, vertex_shader); @@ -318,60 +160,12 @@ impl Renderer { gl.UseProgram(program); + trace!("Deleting shader objects."); gl.DeleteShader(vertex_shader); gl.DeleteShader(fragment_shader); - let mut vao = std::mem::zeroed(); - gl.GenVertexArrays(1, &mut vao); - gl.BindVertexArray(vao); - - let mut vbo = std::mem::zeroed(); - gl.GenBuffers(1, &mut vbo); - gl.BindBuffer(gl::ARRAY_BUFFER, vbo); - gl.BufferData( - gl::ARRAY_BUFFER, - (VERTEX_DATA.len() * std::mem::size_of::()) as gl::types::GLsizeiptr, - VERTEX_DATA.as_ptr() as *const _, - gl::STATIC_DRAW, - ); - - let pos_attrib = gl.GetAttribLocation(program, b"position\0".as_ptr() as *const _); - let color_attrib = gl.GetAttribLocation(program, b"color\0".as_ptr() as *const _); - gl.VertexAttribPointer( - pos_attrib as gl::types::GLuint, - 2, - gl::FLOAT, - 0, - 5 * std::mem::size_of::() as gl::types::GLsizei, - std::ptr::null(), - ); - gl.VertexAttribPointer( - color_attrib as gl::types::GLuint, - 3, - gl::FLOAT, - 0, - 5 * std::mem::size_of::() as gl::types::GLsizei, - (2 * std::mem::size_of::()) as *const () as *const _, - ); - gl.EnableVertexAttribArray(pos_attrib as gl::types::GLuint); - gl.EnableVertexAttribArray(color_attrib as gl::types::GLuint); - - Self { program, vao, vbo, gl } - } - } - - pub fn draw(&self) { self.draw_with_clear_color(0.1, 0.1, 0.1, 0.9) } - - pub fn draw_with_clear_color(&self, red:GLfloat, green:GLfloat, blue:GLfloat, alpha:GLfloat) { - unsafe { - self.gl.UseProgram(self.program); - - self.gl.BindVertexArray(self.vao); - self.gl.BindBuffer(gl::ARRAY_BUFFER, self.vbo); - - self.gl.ClearColor(red, green, blue, alpha); - self.gl.Clear(gl::COLOR_BUFFER_BIT); - self.gl.DrawArrays(gl::TRIANGLES, 0, 3); + trace!("OpenGL renderer instance created."); + Ok(Self { program, vao, vbos:vec![], gl }) } } @@ -388,16 +182,6 @@ impl Deref for Renderer { fn deref(&self) -> &Self::Target { &self.gl } } -impl Drop for Renderer { - fn drop(&mut self) { - unsafe { - self.gl.DeleteProgram(self.program); - self.gl.DeleteBuffers(1, &self.vbo); - self.gl.DeleteVertexArrays(1, &self.vao); - } - } -} - unsafe fn create_shader(gl:&gl::Gl, shader:gl::types::GLenum, source:&[u8]) -> gl::types::GLuint { let shader = gl.CreateShader(shader); gl.ShaderSource(shader, 1, [source.as_ptr().cast()].as_ptr(), std::ptr::null()); @@ -412,12 +196,72 @@ fn get_gl_string(gl:&gl::Gl, variant:gl::types::GLenum) -> Option<&'static CStr> } } +#[repr(C)] +#[derive(Copy, Clone, Debug)] +struct Vertex { + pos: Vec2, + color:Vec3, +} + #[rustfmt::skip] -static VERTEX_DATA: [f32; 15] = [ - -0.5, -0.5, 1.0, 0.0, 0.0, - 0.0, 0.5, 0.0, 1.0, 0.0, - 0.5, -0.5, 0.0, 0.0, 1.0, +static VERTEX_DATA: [Vertex; 3] = [ + //-0.5, -0.5, 1.0, 0.0, 0.0, + // 0.0, 0.5, 0.0, 1.0, 0.0, + // 0.5, -0.5, 0.0, 0.0, 1.0, + Vertex::new(vec2(-0.5, -0.5), vec3(0.3, 0.0, 1.0)), + Vertex::new(vec2(0.5, 0.5), vec3(0.3, 0.0, 1.0)), + Vertex::new(vec2(0.5, -0.5), vec3(0.3, 0.0, 1.0)), + //Vertex::new(vec2(-0.5, 0.5), vec3(0.3, 0.0, 1.0)), ]; +impl Vertex { + const fn new(pos:Vec2, color:Vec3) -> Self { Self { pos, color } } + + //fn binding_description() -> vk::VertexInputBindingDescription { + // vk::VertexInputBindingDescription::builder() + // .binding(0) + // .stride(size_of::() as u32) + // .input_rate(vk::VertexInputRate::VERTEX) + // .build() + //} + + //fn attribute_descriptions() -> [vk::VertexInputAttributeDescription; 2] { + // let pos = vk::VertexInputAttributeDescription::builder() + // .binding(0) + // .location(0) + // .format(vk::Format::R32G32_SFLOAT) + // .offset(0) + // .build(); + + // let color = vk::VertexInputAttributeDescription::builder() + // .binding(0) + // .location(1) + // .format(vk::Format::R32G32B32_SFLOAT) + // .offset(size_of::() as u32) + // .build(); + + // [pos, color] + //} +} + +const VERTEX_SHADER_SOURCE2:&[u8] = b" +#version 450 + +layout(binding = 0) uniform UniformBufferObject { + mat4 model; + mat4 view; + mat4 proj; +} ubo; + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inColor; + +layout(location = 0) out vec3 fragColor; + +void main() { + gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0); + fragColor = inColor; +} +\0"; const VERTEX_SHADER_SOURCE:&[u8] = b" #version 100 @@ -429,8 +273,20 @@ attribute vec3 color; varying vec3 v_color; void main() { - gl_Position = vec4(position, 0.0, 1.0); - v_color = color; + gl_Position = vec4(position, 0.0, 1.0); + v_color = color; +} +\0"; + +const FRAGMENT_SHADER_SOURCE2:&[u8] = b" +#version 450 + +layout(location = 0) in vec3 fragColor; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); } \0"; diff --git a/src/graphics_engines/vulkan/mod.rs b/src/graphics_engines/vulkan/mod.rs index 19fa374..c9674a5 100644 --- a/src/graphics_engines/vulkan/mod.rs +++ b/src/graphics_engines/vulkan/mod.rs @@ -29,7 +29,12 @@ use vulkanalia::vk::ExtDebugUtilsExtension; use vulkanalia::vk::KhrSurfaceExtension; use vulkanalia::vk::KhrSwapchainExtension; +use old_winit::dpi::LogicalSize; +use old_winit::event::Event; +use old_winit::event::WindowEvent; +use old_winit::event_loop::EventLoop; use old_winit::window::Window; +use old_winit::window::WindowBuilder; type Vec2f = cgmath::Vector2; type Vec3f = cgmath::Vector3; @@ -84,6 +89,73 @@ macro_rules! const_shaders { }; } +pub fn start() -> Result<()> { + info!("Initializing event loop and winit window instance."); + + // Window + + let event_loop = EventLoop::new()?; + let window = WindowBuilder::new() + .with_title("WHAT") + .with_inner_size(LogicalSize::new(1024, 768)) + .build(&event_loop)?; + + info!("Creating app and starting event loop."); + + // App + + let mut app = unsafe { App::create(&window)? }; + let mut minimized = false; + + //let shutdown_rx = std::sync::Arc::new(std::sync::Mutex::new(Some(shutdown_rx))); + + event_loop.run(move |event, elwt| { + //let mut shutdown_rx_guard = shutdown_rx.lock().unwrap(); + + //if let Some(receiver) = shutdown_rx_guard.as_mut() { + // if receiver.try_recv().is_ok() { + // info!("Closing event loop and destroying Vulkan instance."); + // elwt.exit(); + // unsafe { + // app.device.device_wait_idle().unwrap(); + // app.destroy(); + // } + // return; + // } + //} + + match event { + // Request a redraw when all events were processed. + Event::AboutToWait => window.request_redraw(), + Event::WindowEvent { event, .. } => match event { + // Render a frame if our Vulkan app is not being destroyed. + WindowEvent::RedrawRequested if !elwt.exiting() && !minimized => { + unsafe { app.render(&window) }.unwrap(); + }, + WindowEvent::Resized(size) => + if size.width == 0 || size.height == 0 { + minimized = true; + } else { + minimized = false; + app.resized = true; + }, + // Destroy our Vulkan app. + WindowEvent::CloseRequested => { + info!("Closing event loop and destroying Vulkan instance."); + elwt.exit(); + unsafe { + app.device.device_wait_idle().unwrap(); + app.destroy(); + } + }, + _ => {}, + }, + _ => {}, + } + })?; + Ok(()) +} + /// Our Vulkan app. #[derive(Clone, Debug)] pub(crate) struct App { @@ -1398,7 +1470,7 @@ unsafe fn copy_buffer_to_image(device:&Device, data:&AppData, buffer:vk::Buffer, unsafe fn create_texture_image_view(device:&Device, data:&mut AppData) -> Result<()> { data.texture_image_view = create_image_view(device, data.texture_image, vk::Format::R8G8B8A8_SRGB)?; - + Ok(()) } diff --git a/src/graphics_engines/vulkan_gc.rs b/src/graphics_engines/vulkan_gc.rs new file mode 100644 index 0000000..670df99 --- /dev/null +++ b/src/graphics_engines/vulkan_gc.rs @@ -0,0 +1,1449 @@ +use anyhow::Result; +use anyhow::anyhow; + +use cgmath::point3; +use cgmath::vec2; +use cgmath::vec3; + +use cgmath::Deg; +use glfw::PWindow; +use log::*; + +use std::collections::HashSet; +use std::ffi::CStr; +use std::fs::File; +use std::mem::size_of; +use std::os::raw::c_void; +use std::ptr::copy_nonoverlapping as memcpy; +use std::time::Instant; + +use thiserror::Error; + +use vulkanalia::Version; +use vulkanalia::bytecode::Bytecode; +use vulkanalia::loader::LIBRARY; +use vulkanalia::loader::LibloadingLoader; +use vulkanalia::prelude::v1_0::*; +use vulkanalia::window as vk_window; + +use vulkanalia::vk::ExtDebugUtilsExtension; +use vulkanalia::vk::KhrSurfaceExtension; +use vulkanalia::vk::KhrSwapchainExtension; + +use crate::cataclysm::Cataclysm; + +use super::GraphicsCommander; + +const VALIDATION_ENABLED:bool = cfg!(debug_assertions); // add env support? +const VALIDATION_LAYER:vk::ExtensionName = vk::ExtensionName::from_bytes(b"VK_LAYER_KHRONOS_validation"); + +const DEVICE_EXTENSIONS:&[vk::ExtensionName] = &[vk::KHR_SWAPCHAIN_EXTENSION.name]; +const PORTABILITY_MACOS_VERSION:Version = Version::new(1, 3, 216); + +const VK_APPLICATION_NAME:&'static [u8; 8] = b"minemod\0"; +const VK_ENGINE_NAME:&'static [u8; 10] = b"cataclysm\0"; +const MAX_FRAMES_IN_FLIGHT:usize = 2; + +// static VERTICES:[Vertex; 3] = [ +// Vertex::new(vec2(0.0, -0.5), vec3(0.3, 0.0, 1.0)), +// Vertex::new(vec2(0.5, 0.5), vec3(0.3, 0.0, 1.0)), +// Vertex::new(vec2(-0.5, 0.5), vec3(0.3, 0.0, 1.0)), +// ]; + +static VERTICES:[Vertex; 4] = [ + Vertex::new(vec2(-0.5, -0.5), vec3(0.3, 0.0, 1.0)), + Vertex::new(vec2(0.5, -0.5), vec3(0.3, 0.0, 1.0)), + Vertex::new(vec2(0.5, 0.5), vec3(0.3, 0.0, 1.0)), + Vertex::new(vec2(-0.5, 0.5), vec3(0.3, 0.0, 1.0)), + // Vertex::new(vec2(-1.0, -1.0),vec3(0.3, 0.0, 1.0)), + // Vertex::new(vec2(1.0, -1.0), vec3(0.3, 0.0, 1.0)), + // Vertex::new(vec2(1.0, 1.0), vec3(0.3, 0.0, 1.0)), + // Vertex::new(vec2(-1.0, 1.0), vec3(0.3, 0.0, 1.0)), +]; +const INDICES:&[u16] = &[0, 1, 2, 2, 3, 0]; + +macro_rules! const_shaders { + { $($vis:vis $identifier:ident = $string:literal; )* } => { + $( + #[allow(non_upper_case_globals)] + $vis static $identifier: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders/", $string)); + )* + }; +} + +/// Our Vulkan app. +#[derive(Clone, Debug)] +pub(crate) struct App { + /// Vulkan entrypoint + entry: Entry, + instance: Instance, + data: AppData, + pub device:Device, + frame: usize, // current frame + //pub resized:bool, + start: Instant, +} + +impl GraphicsCommander for App { + fn suspend_rendering(&mut self) { info!("SUSPEND") } + + fn resume_rendering(&mut self) { info!("RESUME") } + + /// Renders a frame for our Vulkan app. + fn render(&mut self, window:&mut PWindow, cataclysm:&mut Cataclysm) -> Result<()> { + unsafe { + self.device.wait_for_fences(&[self.data.in_flight_fences[self.frame]], true, u64::MAX)?; + + let result = self.device.acquire_next_image_khr( + self.data.swapchain, + u64::MAX, + self.data.image_available_semaphores[self.frame], + vk::Fence::null(), + ); + + let image_index = match result { + Ok((image_index, _)) => image_index as usize, + Err(vk::ErrorCode::OUT_OF_DATE_KHR) => return self.recreate_swapchain(window), + Err(e) => return Err(anyhow!(e)), + }; + + if !self.data.images_in_flight[image_index as usize].is_null() { + self.device + .wait_for_fences(&[self.data.images_in_flight[image_index as usize]], true, u64::MAX)?; + } + + self.data.images_in_flight[image_index as usize] = self.data.in_flight_fences[self.frame]; + + self.update_uniform_buffer(image_index)?; + + let wait_semaphores = &[self.data.image_available_semaphores[self.frame]]; + let wait_stages = &[vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; + let command_buffers = &[self.data.command_buffers[image_index as usize]]; + let signal_semaphores = &[self.data.render_finished_semaphores[self.frame]]; + let submit_info = vk::SubmitInfo::builder() + .wait_semaphores(wait_semaphores) + .wait_dst_stage_mask(wait_stages) + .command_buffers(command_buffers) + .signal_semaphores(signal_semaphores); + + self.device.reset_fences(&[self.data.in_flight_fences[self.frame]])?; + + self.device + .queue_submit(self.data.graphics_queue, &[submit_info], self.data.in_flight_fences[self.frame])?; + + let swapchains = &[self.data.swapchain]; + let image_indices = &[image_index as u32]; + let present_info = vk::PresentInfoKHR::builder() + .wait_semaphores(signal_semaphores) + .swapchains(swapchains) + .image_indices(image_indices); + + let result = self.device.queue_present_khr(self.data.present_queue, &present_info); + + let changed = result == Ok(vk::SuccessCode::SUBOPTIMAL_KHR) || result == Err(vk::ErrorCode::OUT_OF_DATE_KHR); + + if + /*self.resized ||*/ + changed { + //self.resized = false; + self.recreate_swapchain(window)?; + } else if let Err(e) = result { + return Err(anyhow!(e)); + } + + // self.device.queue_wait_idle(self.data.present_queue)?; + + self.frame = (self.frame + 1) % MAX_FRAMES_IN_FLIGHT; + + Ok(()) + } + } + + fn register_vbos(&mut self, data:&[super::VertexData]) { todo!() } + + fn register_texture(&mut self) { todo!() } + + fn destroy_texture(&mut self) { todo!() } + + fn exit(&mut self) { + info!("Destroying Vulkan instance."); + unsafe { + trace!("waiting"); + self.device.device_wait_idle().unwrap(); + + trace!("swapchain"); + self.destroy_swapchain(); + + trace!("fences"); + self.data.in_flight_fences.iter().for_each(|f| self.device.destroy_fence(*f, None)); + trace!("finished semaphores"); + self.data + .render_finished_semaphores + .iter() + .for_each(|s| self.device.destroy_semaphore(*s, None)); + trace!("available semaphores"); + self.data + .image_available_semaphores + .iter() + .for_each(|s| self.device.destroy_semaphore(*s, None)); + + trace!("index buffs"); + self.device.free_memory(self.data.index_buffer_memory, None); + self.device.destroy_buffer(self.data.index_buffer, None); + + trace!("vertex buffs"); + self.device.free_memory(self.data.vertex_buffer_memory, None); + self.device.destroy_buffer(self.data.vertex_buffer, None); + + trace!("texture image memory"); + self.device.free_memory(self.data.texture_image_memory, None); + self.device.destroy_image(self.data.texture_image, None); + self.device.destroy_image_view(self.data.texture_image_view, None); + + trace!("command pool"); + self.device.destroy_command_pool(self.data.command_pool, None); + + trace!("descriptor set layout"); + self.device.destroy_descriptor_set_layout(self.data.descriptor_set_layout, None); + + trace!("device"); + self.device.destroy_device(None); + + trace!("surface"); + self.instance.destroy_surface_khr(self.data.surface, None); + + if VALIDATION_ENABLED { + trace!("validation"); + self.instance.destroy_debug_utils_messenger_ext(self.data.messenger, None); + } + + trace!("instance"); + self.instance.destroy_instance(None); + } + } +} + +impl App { + /// Creates our Vulkan app. + /// doesnt need to be in graphics commander as it gets created knowing exactly what the type is rather than just something impl GraphicsCommander + pub unsafe fn create(window:&PWindow) -> Result { + // TODO figure out how to load vulkan here without reloading the same lib over and over, that can leak memory over time + let loader = LibloadingLoader::new(LIBRARY)?; + let entry = Entry::new(loader).map_err(|b| anyhow!("{}", b))?; + let mut data = AppData::default(); + let instance = create_instance(window, &entry, &mut data)?; + data.surface = vk_window::create_surface(&instance, &window, &window)?; + pick_physical_device(&instance, &mut data)?; + let device = create_logical_device(&entry, &instance, &mut data)?; + create_swapchain(window, &instance, &device, &mut data)?; + create_swapchain_image_views(&device, &mut data)?; + create_render_pass(&instance, &device, &mut data)?; + create_descriptor_set_layout(&device, &mut data)?; + create_pipeline(&device, &mut data)?; + create_framebuffers(&device, &mut data)?; + create_command_pool(&instance, &device, &mut data)?; + create_texture_image(&instance, &device, &mut data)?; + create_texture_image_view(&device, &mut data)?; + create_texture_sampler(&device, &mut data)?; + create_vertex_buffer(&instance, &device, &mut data)?; + create_index_buffer(&instance, &device, &mut data)?; + create_uniform_buffers(&instance, &device, &mut data)?; + create_descriptor_pool(&device, &mut data)?; + create_descriptor_sets(&device, &mut data)?; + create_command_buffers(&device, &mut data)?; + create_sync_objects(&device, &mut data)?; + Ok(Self { + entry, + instance, + data, + device, + frame:0, + //resized:false, + start:Instant::now(), + }) + } + + unsafe fn update_uniform_buffer(&self, image_index:usize) -> Result<()> { + let time = self.start.elapsed().as_secs_f32(); + + let model = Mat4f::from_axis_angle(vec3(0.0, 0.0, 1.0), Deg(45.0) * time); + + let view = Mat4f::look_at_rh(point3(2.0, 5.0, 2.0), point3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 1.0)); + + let mut proj = cgmath::perspective( + Deg(45.0), + self.data.swapchain_extent.width as f32 / self.data.swapchain_extent.height as f32, + 0.1, + 10.0, + ); + + // cgmath was made with opengl in mind, this fixes it to work with vulkan + proj[1][1] *= -1.0; + + let ubo = UniformBufferObject { model, view, proj }; + + let memory = self.device.map_memory( + self.data.uniform_buffers_memory[image_index], + 0, + size_of::() as u64, + vk::MemoryMapFlags::empty(), + )?; + + memcpy(&ubo, memory.cast(), 1); + + self.device.unmap_memory(self.data.uniform_buffers_memory[image_index]); + + Ok(()) + } + + unsafe fn recreate_swapchain(&mut self, window:&PWindow) -> Result<()> { + info!("recreating swapchain"); + self.device.device_wait_idle()?; + self.destroy_swapchain(); + create_swapchain(window, &self.instance, &self.device, &mut self.data)?; + create_swapchain_image_views(&self.device, &mut self.data)?; + create_render_pass(&self.instance, &self.device, &mut self.data)?; + create_pipeline(&self.device, &mut self.data)?; + create_framebuffers(&self.device, &mut self.data)?; + create_uniform_buffers(&self.instance, &self.device, &mut self.data)?; + create_descriptor_pool(&self.device, &mut self.data)?; + create_descriptor_sets(&self.device, &mut self.data)?; + create_command_buffers(&self.device, &mut self.data)?; + self.data.images_in_flight.resize(self.data.swapchain_images.len(), vk::Fence::null()); + + Ok(()) + } + + unsafe fn destroy_swapchain(&mut self) { + info!("Destroying vulkan swapchain."); + trace!("cmd buffs"); + self.device.free_command_buffers(self.data.command_pool, &self.data.command_buffers); + trace!("desc pool"); + self.device.destroy_descriptor_pool(self.data.descriptor_pool, None); + + trace!("uniform buffers"); + self.data.uniform_buffers_memory.iter().for_each(|m| self.device.free_memory(*m, None)); + self.data.uniform_buffers.iter().for_each(|b| self.device.destroy_buffer(*b, None)); + trace!("framebuffers"); + self.data.framebuffers.iter().for_each(|f| self.device.destroy_framebuffer(*f, None)); + trace!("pipeline"); + self.device.destroy_pipeline(self.data.pipeline, None); + trace!("pipeline layout"); + self.device.destroy_pipeline_layout(self.data.pipeline_layout, None); + trace!("render pass"); + self.device.destroy_render_pass(self.data.render_pass, None); + trace!("swapchian image views"); + self.data.swapchain_image_views.iter().for_each(|v| self.device.destroy_image_view(*v, None)); + trace!("swapchain"); + self.device.destroy_swapchain_khr(self.data.swapchain, None); + } +} + +/// The Vulkan handles and associated properties used by our Vulkan app. +#[derive(Clone, Debug, Default)] +struct AppData { + messenger: vk::DebugUtilsMessengerEXT, + surface: vk::SurfaceKHR, + physical_device: vk::PhysicalDevice, + graphics_queue: vk::Queue, + present_queue: vk::Queue, + swapchain_format: vk::Format, + swapchain_extent: vk::Extent2D, + swapchain: vk::SwapchainKHR, + swapchain_images: Vec, + swapchain_image_views: Vec, + render_pass: vk::RenderPass, + descriptor_set_layout: vk::DescriptorSetLayout, + pipeline_layout: vk::PipelineLayout, + pipeline: vk::Pipeline, + framebuffers: Vec, + command_pool: vk::CommandPool, + /// Vec of command buffers, one per in flight frame, this way they can be separated and you wont draw on the wrong frame + command_buffers: Vec, + image_available_semaphores:Vec, + render_finished_semaphores:Vec, + in_flight_fences: Vec, + images_in_flight: Vec, + vertex_buffer: vk::Buffer, + vertex_buffer_memory: vk::DeviceMemory, + index_buffer: vk::Buffer, + index_buffer_memory: vk::DeviceMemory, + uniform_buffers: Vec, + uniform_buffers_memory: Vec, + descriptor_pool: vk::DescriptorPool, + descriptor_sets: Vec, + texture_image: vk::Image, + texture_image_memory: vk::DeviceMemory, + texture_image_view: vk::ImageView, +} + +unsafe fn create_instance(window:&PWindow, entry:&Entry, data:&mut AppData) -> Result { + // TODO learn why we give this information to the vulkan driver, im assuming its for data training purposes? + // This way the driver can be shipped with pre trained paths for popular games allowing it to run better? + // Lets hope one day we will be on this list + + let application_info = vk::ApplicationInfo::builder() + // Our application information + .application_name(VK_APPLICATION_NAME) + .application_version(vk::make_version(0, 1, 0)) + // Our engine information + .engine_name(VK_ENGINE_NAME) + .engine_version(vk::make_version(0, 1, 0)) + // Vulkan api version target + .api_version(vk::make_version(1, 0, 0)); + + // Get the names of available layers + let available_layers = entry + .enumerate_instance_layer_properties()? + .iter() + .map(|l| l.layer_name) + .collect::>(); + + if VALIDATION_ENABLED && !available_layers.contains(&VALIDATION_LAYER) { + return Err(anyhow!("Validation layer requested but not supported.")); + } + + let layers = if VALIDATION_ENABLED { vec![VALIDATION_LAYER.as_ptr()] } else { Vec::new() }; + + // Generate a list of required extensions for creating a window instance via winit + let mut extensions = vk_window::get_required_instance_extensions(window) + .iter() + .map(|e| e.as_ptr()) + .collect::>(); + + // needed for semaphores somehow + extensions.push(vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION.name.as_ptr()); + + // Required by Vulkan SDK on macOS since 1.3.216. + let flags = if cfg!(target_os = "macos") && entry.version()? >= PORTABILITY_MACOS_VERSION { + info!("Enabling extensions for macOS portability."); + // extensions.push( + // // already present above + // vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION.name.as_ptr(), + // ); + extensions.push(vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name.as_ptr()); + vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR + } else { + vk::InstanceCreateFlags::empty() + }; + if VALIDATION_ENABLED { + extensions.push(vk::EXT_DEBUG_UTILS_EXTENSION.name.as_ptr()); + } + + let mut info = vk::InstanceCreateInfo::builder() + .application_info(&application_info) + .enabled_layer_names(&layers) + .enabled_extension_names(&extensions) + .flags(flags); + + let mut debug_info = vk::DebugUtilsMessengerCreateInfoEXT::builder() + .message_severity(vk::DebugUtilsMessageSeverityFlagsEXT::all()) + .message_type( + vk::DebugUtilsMessageTypeFlagsEXT::GENERAL | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE, + ) + .user_callback(Some(debug_callback)); + + if VALIDATION_ENABLED { + info = info.push_next(&mut debug_info); + } + + let instance = entry.create_instance(&info, None)?; + + if VALIDATION_ENABLED { + data.messenger = instance.create_debug_utils_messenger_ext(&debug_info, None)?; + } + + Ok(instance) +} + +extern "system" fn debug_callback( + severity:vk::DebugUtilsMessageSeverityFlagsEXT, type_:vk::DebugUtilsMessageTypeFlagsEXT, data:*const vk::DebugUtilsMessengerCallbackDataEXT, _:*mut c_void, +) -> vk::Bool32 { + let data = unsafe { *data }; + let message = unsafe { CStr::from_ptr(data.message) }.to_string_lossy(); + + if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::ERROR { + error!("({:?}) {}", type_, message); + } else if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING { + warn!("({:?}) {}", type_, message); + } else if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::INFO { + debug!("({:?}) {}", type_, message); + } else { + trace!("({:?}) {}", type_, message); + } + + vk::FALSE +} + +#[derive(Debug, Error)] +#[error("{0}")] +pub struct SuitabilityError(pub &'static str); + +unsafe fn pick_physical_device(instance:&Instance, data:&mut AppData) -> Result<()> { + for physical_device in instance.enumerate_physical_devices()? { + let properties = instance.get_physical_device_properties(physical_device); + + if let Err(error) = check_physical_device(instance, data, physical_device) { + warn!("Skipping physical device (`{}`): {}", properties.device_name, error); + } else { + info!("Selected physical device (`{}`).", properties.device_name); + data.physical_device = physical_device; + return Ok(()); + } + } + + Err(anyhow!("Failed to find suitable physical device.")) +} +unsafe fn check_physical_device(instance:&Instance, data:&AppData, physical_device:vk::PhysicalDevice) -> Result<()> { + QueueFamilyIndices::get(instance, data, physical_device)?; + check_physical_device_extensions(instance, physical_device)?; + + let support = SwapchainSupport::get(instance, data, physical_device)?; + if support.formats.is_empty() || support.present_modes.is_empty() { + return Err(anyhow!(SuitabilityError("Insufficient swapchain support."))); + } + + // // TODO handle this like the other one? + // let properties = instance.get_physical_device_properties(physical_device); + // if properties.device_type != vk::PhysicalDeviceType::DISCRETE_GPU { + // return Err(anyhow!(SuitabilityError( + // "Only discrete GPUs are supported." + // ))); + // } + + // let features = instance.get_physical_device_features(physical_device); + // let required_features = [ + // (features.geometry_shader, "Missing geometry shader support."), + // // ( // needed for vr + // // features.multi_viewport, + // // "Missing support for multiple viewports.", + // // ), + // ]; + + // for (feature, string) in required_features { + // if feature != vk::TRUE { + // return Err(anyhow!(SuitabilityError(string))); + // } + // } + + Ok(()) +} +unsafe fn check_physical_device_extensions(instance:&Instance, physical_device:vk::PhysicalDevice) -> Result<()> { + let extensions = instance + .enumerate_device_extension_properties(physical_device, None)? + .iter() + .map(|e| e.extension_name) + .collect::>(); + if DEVICE_EXTENSIONS.iter().all(|e| extensions.contains(e)) { + Ok(()) + } else { + Err(anyhow!(SuitabilityError("Missing required device extensions."))) + } +} + +unsafe fn create_logical_device(entry:&Entry, instance:&Instance, data:&mut AppData) -> Result { + let indices = QueueFamilyIndices::get(instance, data, data.physical_device)?; + + let mut unique_indices = HashSet::new(); + unique_indices.insert(indices.graphics); + unique_indices.insert(indices.present); + + let queue_priorities = &[1.0]; + let queue_infos = unique_indices + .iter() + .map(|i| vk::DeviceQueueCreateInfo::builder().queue_family_index(*i).queue_priorities(queue_priorities)) + .collect::>(); + + let layers = if VALIDATION_ENABLED { vec![VALIDATION_LAYER.as_ptr()] } else { vec![] }; + + let mut extensions = DEVICE_EXTENSIONS.iter().map(|n| n.as_ptr()).collect::>(); + + // Required by Vulkan SDK on macOS since 1.3.216. + if cfg!(target_os = "macos") && entry.version()? >= PORTABILITY_MACOS_VERSION { + extensions.push(vk::KHR_PORTABILITY_SUBSET_EXTENSION.name.as_ptr()); + } + + let features = vk::PhysicalDeviceFeatures::builder(); + + let info = vk::DeviceCreateInfo::builder() + .queue_create_infos(&queue_infos) + .enabled_layer_names(&layers) + .enabled_extension_names(&extensions) + .enabled_features(&features); + + let device = instance.create_device(data.physical_device, &info, None)?; + + data.graphics_queue = device.get_device_queue(indices.graphics, 0); + data.present_queue = device.get_device_queue(indices.present, 0); + + Ok(device) +} + +unsafe fn create_swapchain( + window:&PWindow, + instance:&Instance, + device:&Device, + data:&mut AppData, + // old_swapchain: Option +) -> Result<()> { + let indices = QueueFamilyIndices::get(instance, data, data.physical_device)?; + let support = SwapchainSupport::get(instance, data, data.physical_device)?; + + let surface_format = get_swapchain_surface_format(&support.formats); + let present_mode = get_swapchain_present_mode(&support.present_modes); + let extent = get_swapchain_extent(window, support.capabilities); + + data.swapchain_format = surface_format.format; + data.swapchain_extent = extent; + + let mut image_count = support.capabilities.min_image_count + 1; + if support.capabilities.max_image_count != 0 && image_count > support.capabilities.max_image_count { + image_count = support.capabilities.max_image_count; + } + + let mut queue_family_indices = vec![]; + let image_sharing_mode = if indices.graphics != indices.present { + queue_family_indices.push(indices.graphics); + queue_family_indices.push(indices.present); + vk::SharingMode::CONCURRENT + } else { + vk::SharingMode::EXCLUSIVE + }; + + let info = vk::SwapchainCreateInfoKHR::builder() + .surface(data.surface) + .min_image_count(image_count) + .image_format(surface_format.format) + .image_color_space(surface_format.color_space) + .image_extent(extent) + .image_array_layers(1) + .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT) + .image_sharing_mode(image_sharing_mode) + .queue_family_indices(&queue_family_indices) + .pre_transform(support.capabilities.current_transform) + .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE) + .present_mode(present_mode) + .clipped(true) + .old_swapchain(vk::SwapchainKHR::null()); + // .old_swapchain(data.swapchain); // TODO if experiencing issues replace with vk::SwapchainKHR::null() + + data.swapchain = device.create_swapchain_khr(&info, None)?; + + data.swapchain_images = device.get_swapchain_images_khr(data.swapchain)?; + + Ok(()) +} + +fn get_swapchain_surface_format(formats:&[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR { + formats + .iter() + .cloned() + .find(|f| f.format == vk::Format::B8G8R8A8_SRGB && f.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR) + .unwrap_or_else(|| formats[0]) +} + +fn get_swapchain_present_mode(present_modes:&[vk::PresentModeKHR]) -> vk::PresentModeKHR { + present_modes + .iter() + .cloned() + .find(|m| *m == vk::PresentModeKHR::MAILBOX) + .unwrap_or(vk::PresentModeKHR::FIFO) +} + +fn get_swapchain_extent(window:&PWindow, capabilities:vk::SurfaceCapabilitiesKHR) -> vk::Extent2D { + if capabilities.current_extent.width != u32::MAX { + capabilities.current_extent + } else { + vk::Extent2D::builder() + .width( + (window.get_size() + //.inner_size() + .0 as u32) // TODO come back here and fix this + .clamp(capabilities.min_image_extent.width, capabilities.max_image_extent.width), + ) + .height((window.get_size().1 as u32).clamp(capabilities.min_image_extent.height, capabilities.max_image_extent.height)) + .build() + } +} + +unsafe fn create_swapchain_image_views(device:&Device, data:&mut AppData) -> Result<()> { + data.swapchain_image_views = data + .swapchain_images + .iter() + .map(|i| create_image_view(device, *i, data.swapchain_format)) + .collect::, _>>()?; + + Ok(()) +} + +unsafe fn create_render_pass(instance:&Instance, device:&Device, data:&mut AppData) -> Result<()> { + let color_attachment = vk::AttachmentDescription::builder() + .format(data.swapchain_format) + .samples(vk::SampleCountFlags::_1) + .load_op(vk::AttachmentLoadOp::CLEAR) + .store_op(vk::AttachmentStoreOp::STORE) + .stencil_load_op(vk::AttachmentLoadOp::DONT_CARE) + .stencil_store_op(vk::AttachmentStoreOp::DONT_CARE) + .initial_layout(vk::ImageLayout::UNDEFINED) + .final_layout(vk::ImageLayout::PRESENT_SRC_KHR); + + let color_attachment_ref = vk::AttachmentReference::builder() + .attachment(0) + .layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL); + + let color_attachments = &[color_attachment_ref]; + let subpass = vk::SubpassDescription::builder() + .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) + .color_attachments(color_attachments); + + let dependency = vk::SubpassDependency::builder() + .src_subpass(vk::SUBPASS_EXTERNAL) + .dst_subpass(0) + .src_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) + .src_access_mask(vk::AccessFlags::empty()) + .dst_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT) + .dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE); + + let attachments = &[color_attachment]; + let subpasses = &[subpass]; + let dependencies = &[dependency]; + let info = vk::RenderPassCreateInfo::builder() + .attachments(attachments) + .subpasses(subpasses) + .dependencies(dependencies); + + data.render_pass = device.create_render_pass(&info, None)?; + + Ok(()) +} + +unsafe fn create_descriptor_set_layout(device:&Device, data:&mut AppData) -> Result<()> { + let ubo_binding = vk::DescriptorSetLayoutBinding::builder() + .binding(0) + .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) + .descriptor_count(1) + .stage_flags(vk::ShaderStageFlags::VERTEX); + + let bindings = &[ubo_binding]; + let info = vk::DescriptorSetLayoutCreateInfo::builder().bindings(bindings); + + data.descriptor_set_layout = device.create_descriptor_set_layout(&info, None)?; + + Ok(()) +} + +unsafe fn create_pipeline(device:&Device, data:&mut AppData) -> Result<()> { + const_shaders! { + frag = "f_default.spv"; + vert = "v_default.spv"; + } + + let vert_shader_module = create_shader_module(device, &vert[..])?; + let frag_shader_module = create_shader_module(device, &frag[..])?; + + let vert_stage = vk::PipelineShaderStageCreateInfo::builder() + .stage(vk::ShaderStageFlags::VERTEX) + .module(vert_shader_module) + .name(b"main\0"); // keep specialization_info in mind for pipeline creation optimizations that dont happen at render time + + let frag_stage = vk::PipelineShaderStageCreateInfo::builder() + .stage(vk::ShaderStageFlags::FRAGMENT) + .module(frag_shader_module) + .name(b"main\0"); + + let binding_descriptions = &[Vertex::binding_description()]; + let attribute_descriptions = Vertex::attribute_descriptions(); + let vertex_input_state = vk::PipelineVertexInputStateCreateInfo::builder() + .vertex_binding_descriptions(binding_descriptions) + .vertex_attribute_descriptions(&attribute_descriptions); + + let input_assembly_state = vk::PipelineInputAssemblyStateCreateInfo::builder() + .topology(vk::PrimitiveTopology::TRIANGLE_LIST) + .primitive_restart_enable(false); + + let viewport = vk::Viewport::builder() + .x(0.0) + .y(0.0) + .width(data.swapchain_extent.width as f32) + .height(data.swapchain_extent.height as f32) + .min_depth(0.0) + .max_depth(1.0); + + let scissor = vk::Rect2D::builder().offset(vk::Offset2D { x:0, y:0 }).extent(data.swapchain_extent); + + let viewports = &[viewport]; + let scissors = &[scissor]; + let viewport_state = vk::PipelineViewportStateCreateInfo::builder().viewports(viewports).scissors(scissors); + + let rasterization_state = vk::PipelineRasterizationStateCreateInfo::builder() + .depth_clamp_enable(false) + .rasterizer_discard_enable(false) + .polygon_mode(vk::PolygonMode::FILL) + .line_width(1.0) + .cull_mode(vk::CullModeFlags::BACK) + .front_face(vk::FrontFace::COUNTER_CLOCKWISE) + .depth_bias_enable(false); + + let multisample_state = vk::PipelineMultisampleStateCreateInfo::builder() + .sample_shading_enable(false) + .rasterization_samples(vk::SampleCountFlags::_1); + + let attachment = vk::PipelineColorBlendAttachmentState::builder() + .color_write_mask(vk::ColorComponentFlags::all()) + .blend_enable(true) + .src_color_blend_factor(vk::BlendFactor::SRC_ALPHA) + .dst_color_blend_factor(vk::BlendFactor::ONE_MINUS_SRC_ALPHA) + .color_blend_op(vk::BlendOp::ADD) + .src_alpha_blend_factor(vk::BlendFactor::ONE) + .dst_alpha_blend_factor(vk::BlendFactor::ZERO) + .alpha_blend_op(vk::BlendOp::ADD); + //.blend_enable(false); + + let attachments = &[attachment]; + let color_blend_state = vk::PipelineColorBlendStateCreateInfo::builder() + .logic_op_enable(false) + .logic_op(vk::LogicOp::COPY) + .attachments(attachments) + .blend_constants([0.0, 0.0, 0.0, 0.0]); + + let set_layouts = &[data.descriptor_set_layout]; + let layout_info = vk::PipelineLayoutCreateInfo::builder().set_layouts(set_layouts); + + data.pipeline_layout = device.create_pipeline_layout(&layout_info, None)?; + + let stages = &[vert_stage, frag_stage]; + let info = vk::GraphicsPipelineCreateInfo::builder() + .stages(stages) + .vertex_input_state(&vertex_input_state) + .input_assembly_state(&input_assembly_state) + .viewport_state(&viewport_state) + .rasterization_state(&rasterization_state) + .multisample_state(&multisample_state) + .color_blend_state(&color_blend_state) + .layout(data.pipeline_layout) + .render_pass(data.render_pass) + .subpass(0) + .base_pipeline_handle(vk::Pipeline::null()) // Optional. + .base_pipeline_index(-1); // Optional. + + data.pipeline = device.create_graphics_pipelines(vk::PipelineCache::null(), &[info], None)?.0[0]; + + device.destroy_shader_module(vert_shader_module, None); + device.destroy_shader_module(frag_shader_module, None); + Ok(()) +} + +unsafe fn create_shader_module(device:&Device, bytecode:&[u8]) -> Result { + let bytecode = Bytecode::new(bytecode).unwrap(); + + let info = vk::ShaderModuleCreateInfo::builder().code_size(bytecode.code_size()).code(bytecode.code()); + + Ok(device.create_shader_module(&info, None)?) +} + +unsafe fn create_framebuffers(device:&Device, data:&mut AppData) -> Result<()> { + data.framebuffers = data + .swapchain_image_views + .iter() + .map(|i| { + let attachments = &[*i]; + let create_info = vk::FramebufferCreateInfo::builder() + .render_pass(data.render_pass) + .attachments(attachments) + .width(data.swapchain_extent.width) + .height(data.swapchain_extent.height) + .layers(1); + + device.create_framebuffer(&create_info, None) + }) + .collect::, _>>()?; + + Ok(()) +} +unsafe fn create_command_pool(instance:&Instance, device:&Device, data:&mut AppData) -> Result<()> { + let indices = QueueFamilyIndices::get(instance, data, data.physical_device)?; + + let info = vk::CommandPoolCreateInfo::builder() + .flags(vk::CommandPoolCreateFlags::empty()) // Optional. + .queue_family_index(indices.graphics); + + data.command_pool = device.create_command_pool(&info, None)?; + + Ok(()) +} + +unsafe fn create_texture_image(instance:&Instance, device:&Device, data:&mut AppData) -> Result<()> { + let image = File::open("assets/common/archlogo.512.png")?; + + let decoder = png::Decoder::new(image); + let mut reader = decoder.read_info()?; + + let mut pixels = vec![0; reader.info().raw_bytes()]; + reader.next_frame(&mut pixels)?; // what format is this reading to? + + let size = reader.info().raw_bytes() as u64; + let (width, height) = reader.info().size(); + + let (staging_buffer, staging_buffer_memory) = create_buffer( + instance, + device, + data, + size, + vk::BufferUsageFlags::TRANSFER_SRC, + vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE, + )?; + + let memory = device.map_memory(staging_buffer_memory, 0, size, vk::MemoryMapFlags::empty())?; + + memcpy(pixels.as_ptr(), memory.cast(), pixels.len()); + + device.unmap_memory(staging_buffer_memory); + + let (texture_image, texture_image_memory) = create_image( + instance, + device, + data, + width, + height, + vk::Format::R8G8B8A8_SRGB, // BCn compression can be used here, its also possible that these formats are not available everywhere and this must be handled separately + vk::ImageTiling::OPTIMAL, // can be linear if we are planning to read from it on the cpu later? + vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::TRANSFER_DST, + vk::MemoryPropertyFlags::DEVICE_LOCAL, + )?; + + data.texture_image = texture_image; + data.texture_image_memory = texture_image_memory; + + transition_image_layout( + device, + data, + data.texture_image, + vk::Format::R8G8B8A8_SRGB, + vk::ImageLayout::UNDEFINED, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + )?; + + copy_buffer_to_image(device, data, staging_buffer, data.texture_image, width, height)?; + + transition_image_layout( + device, + data, + data.texture_image, + vk::Format::R8G8B8A8_SRGB, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, + )?; + device.destroy_buffer(staging_buffer, None); + device.free_memory(staging_buffer_memory, None); + + Ok(()) +} +unsafe fn create_command_buffers(device:&Device, data:&mut AppData) -> Result<()> { + let allocate_info = vk::CommandBufferAllocateInfo::builder() + .command_pool(data.command_pool) + .level(vk::CommandBufferLevel::PRIMARY) + .command_buffer_count(data.framebuffers.len() as u32); + + data.command_buffers = device.allocate_command_buffers(&allocate_info)?; + + for (i, command_buffer) in data.command_buffers.iter().enumerate() { + let inheritance = vk::CommandBufferInheritanceInfo::builder(); + + let info = vk::CommandBufferBeginInfo::builder() + .flags(vk::CommandBufferUsageFlags::empty()) // Optional. + .inheritance_info(&inheritance); // Optional. + + device.begin_command_buffer(*command_buffer, &info)?; + + let render_area = vk::Rect2D::builder().offset(vk::Offset2D::default()).extent(data.swapchain_extent); + + let color_clear_value = vk::ClearValue { + color:vk::ClearColorValue { + float32:[0.0125, 0.0094, 0.0071, 1.0], + }, + }; + + let clear_values = &[color_clear_value]; + let info = vk::RenderPassBeginInfo::builder() + .render_pass(data.render_pass) + .framebuffer(data.framebuffers[i]) + .render_area(render_area) + .clear_values(clear_values); + + device.cmd_begin_render_pass(*command_buffer, &info, vk::SubpassContents::INLINE); + device.cmd_bind_pipeline(*command_buffer, vk::PipelineBindPoint::GRAPHICS, data.pipeline); + + device.cmd_bind_vertex_buffers(*command_buffer, 0, &[data.vertex_buffer], &[0]); + device.cmd_bind_index_buffer(*command_buffer, data.index_buffer, 0, vk::IndexType::UINT16); + device.cmd_bind_descriptor_sets( + *command_buffer, + vk::PipelineBindPoint::GRAPHICS, + data.pipeline_layout, + 0, + &[data.descriptor_sets[i]], + &[], + ); + + device.cmd_draw_indexed(*command_buffer, INDICES.len() as u32, 1, 0, 0, 0); + + device.cmd_end_render_pass(*command_buffer); + device.end_command_buffer(*command_buffer)?; + } + + Ok(()) +} + +unsafe fn create_sync_objects(device:&Device, data:&mut AppData) -> Result<()> { + let semaphore_info = vk::SemaphoreCreateInfo::builder(); + let fence_info = vk::FenceCreateInfo::builder().flags(vk::FenceCreateFlags::SIGNALED); + + for _ in 0..MAX_FRAMES_IN_FLIGHT { + data.image_available_semaphores.push(device.create_semaphore(&semaphore_info, None)?); + data.render_finished_semaphores.push(device.create_semaphore(&semaphore_info, None)?); + + data.in_flight_fences.push(device.create_fence(&fence_info, None)?); + } + + data.images_in_flight = data.swapchain_images.iter().map(|_| vk::Fence::null()).collect(); + + Ok(()) +} + +#[derive(Copy, Clone, Debug)] +struct QueueFamilyIndices { + graphics:u32, + present: u32, +} + +impl QueueFamilyIndices { + unsafe fn get(instance:&Instance, data:&AppData, physical_device:vk::PhysicalDevice) -> Result { + let properties = instance.get_physical_device_queue_family_properties(physical_device); + + let graphics = properties + .iter() + .position(|p| p.queue_flags.contains(vk::QueueFlags::GRAPHICS)) + .map(|i| i as u32); + + let mut present = None; + for (index, properties) in properties.iter().enumerate() { + if instance.get_physical_device_surface_support_khr(physical_device, index as u32, data.surface)? { + present = Some(index as u32); + break; + } + } + + // Note that it's very likely that these end up being the same queue family after all, but throughout the program we will treat them as if they were separate queues for a uniform approach. Nevertheless, you could add logic to explicitly prefer a physical device that supports drawing and presentation in the same queue for improved performance. + if let (Some(graphics), Some(present)) = (graphics, present) { + Ok(Self { graphics, present }) + } else { + Err(anyhow!(SuitabilityError("Missing required queue families."))) + } + } +} + +#[derive(Clone, Debug)] +struct SwapchainSupport { + capabilities: vk::SurfaceCapabilitiesKHR, + formats: Vec, + present_modes:Vec, +} + +impl SwapchainSupport { + unsafe fn get(instance:&Instance, data:&AppData, physical_device:vk::PhysicalDevice) -> Result { + Ok(Self { + capabilities: instance.get_physical_device_surface_capabilities_khr(physical_device, data.surface)?, + formats: instance.get_physical_device_surface_formats_khr(physical_device, data.surface)?, + present_modes:instance.get_physical_device_surface_present_modes_khr(physical_device, data.surface)?, + }) + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +struct Vertex { + pos: Vec2f, + color:Vec3f, +} + +impl Vertex { + const fn new(pos:Vec2f, color:Vec3f) -> Self { Self { pos, color } } + + fn binding_description() -> vk::VertexInputBindingDescription { + vk::VertexInputBindingDescription::builder() + .binding(0) + .stride(size_of::() as u32) + .input_rate(vk::VertexInputRate::VERTEX) + .build() + } + + fn attribute_descriptions() -> [vk::VertexInputAttributeDescription; 2] { + let pos = vk::VertexInputAttributeDescription::builder() + .binding(0) + .location(0) + .format(vk::Format::R32G32_SFLOAT) + .offset(0) + .build(); + + let color = vk::VertexInputAttributeDescription::builder() + .binding(0) + .location(1) + .format(vk::Format::R32G32B32_SFLOAT) + .offset(size_of::() as u32) + .build(); + + [pos, color] + } +} + +unsafe fn create_vertex_buffer(instance:&Instance, device:&Device, data:&mut AppData) -> Result<()> { + let size = (size_of::() * VERTICES.len()) as u64; + + let (staging_buffer, staging_buffer_memory) = create_buffer( + instance, + device, + data, + size, + vk::BufferUsageFlags::TRANSFER_SRC, + vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE, + )?; + + let memory = device.map_memory(staging_buffer_memory, 0, size, vk::MemoryMapFlags::empty())?; + + memcpy(VERTICES.as_ptr(), memory.cast(), VERTICES.len()); + + device.unmap_memory(staging_buffer_memory); + + let (vertex_buffer, vertex_buffer_memory) = create_buffer( + instance, + device, + data, + size, + vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER, + vk::MemoryPropertyFlags::DEVICE_LOCAL, + )?; + + data.vertex_buffer = vertex_buffer; + data.vertex_buffer_memory = vertex_buffer_memory; + + copy_buffer(device, data, staging_buffer, vertex_buffer, size)?; + + device.destroy_buffer(staging_buffer, None); + device.free_memory(staging_buffer_memory, None); + + Ok(()) +} + +unsafe fn copy_buffer(device:&Device, data:&AppData, source:vk::Buffer, destination:vk::Buffer, size:vk::DeviceSize) -> Result<()> { + let command_buffer = begin_single_time_commands(device, data)?; + + let regions = vk::BufferCopy::builder().size(size); + device.cmd_copy_buffer(command_buffer, source, destination, &[regions]); + + end_single_time_commands(device, data, command_buffer)?; + + Ok(()) +} + +unsafe fn get_memory_type_index(instance:&Instance, data:&AppData, properties:vk::MemoryPropertyFlags, requirements:vk::MemoryRequirements) -> Result { + let memory = instance.get_physical_device_memory_properties(data.physical_device); + + (0..memory.memory_type_count) + .find(|i| { + let suitable = (requirements.memory_type_bits & (1 << i)) != 0; + let memory_type = memory.memory_types[*i as usize]; + suitable && memory_type.property_flags.contains(properties) + }) + .ok_or_else(|| anyhow!("Failed to find suitable memory type.")) +} + +unsafe fn create_buffer( + instance:&Instance, device:&Device, data:&AppData, size:vk::DeviceSize, usage:vk::BufferUsageFlags, properties:vk::MemoryPropertyFlags, +) -> Result<(vk::Buffer, vk::DeviceMemory)> { + let buffer_info = vk::BufferCreateInfo::builder().size(size).usage(usage).sharing_mode(vk::SharingMode::EXCLUSIVE); + + let buffer = device.create_buffer(&buffer_info, None)?; + + let requirements = device.get_buffer_memory_requirements(buffer); + + let memory_info = vk::MemoryAllocateInfo::builder() + .allocation_size(requirements.size) + .memory_type_index(get_memory_type_index(instance, data, properties, requirements)?); + + let buffer_memory = device.allocate_memory(&memory_info, None)?; + + device.bind_buffer_memory(buffer, buffer_memory, 0)?; + + Ok((buffer, buffer_memory)) +} + +unsafe fn create_index_buffer(instance:&Instance, device:&Device, data:&mut AppData) -> Result<()> { + let size = (size_of::() * INDICES.len()) as u64; + + let (staging_buffer, staging_buffer_memory) = create_buffer( + instance, + device, + data, + size, + vk::BufferUsageFlags::TRANSFER_SRC, + vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE, + )?; + + let memory = device.map_memory(staging_buffer_memory, 0, size, vk::MemoryMapFlags::empty())?; + + memcpy(INDICES.as_ptr(), memory.cast(), INDICES.len()); + + device.unmap_memory(staging_buffer_memory); + + let (index_buffer, index_buffer_memory) = create_buffer( + instance, + device, + data, + size, + vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::INDEX_BUFFER, + vk::MemoryPropertyFlags::DEVICE_LOCAL, + )?; + + data.index_buffer = index_buffer; + data.index_buffer_memory = index_buffer_memory; + + copy_buffer(device, data, staging_buffer, index_buffer, size)?; + + device.destroy_buffer(staging_buffer, None); + device.free_memory(staging_buffer_memory, None); + + Ok(()) +} + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +struct UniformBufferObject { + model:Mat4f, + view: Mat4f, + proj: Mat4f, +} + +unsafe fn create_uniform_buffers(instance:&Instance, device:&Device, data:&mut AppData) -> Result<()> { + data.uniform_buffers.clear(); + data.uniform_buffers_memory.clear(); + + for _ in 0..data.swapchain_images.len() { + let (uniform_buffer, uniform_buffer_memory) = create_buffer( + instance, + device, + data, + size_of::() as u64, + vk::BufferUsageFlags::UNIFORM_BUFFER, + vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE, + )?; + + data.uniform_buffers.push(uniform_buffer); + data.uniform_buffers_memory.push(uniform_buffer_memory); + } + + Ok(()) +} + +unsafe fn create_descriptor_pool(device:&Device, data:&mut AppData) -> Result<()> { + let ubo_size = vk::DescriptorPoolSize::builder() + .type_(vk::DescriptorType::UNIFORM_BUFFER) + .descriptor_count(data.swapchain_images.len() as u32); + + let pool_sizes = &[ubo_size]; + let info = vk::DescriptorPoolCreateInfo::builder() + .pool_sizes(pool_sizes) + .max_sets(data.swapchain_images.len() as u32); + + data.descriptor_pool = device.create_descriptor_pool(&info, None)?; + + Ok(()) +} + +unsafe fn create_descriptor_sets(device:&Device, data:&mut AppData) -> Result<()> { + let layouts = vec![data.descriptor_set_layout; data.swapchain_images.len()]; + let info = vk::DescriptorSetAllocateInfo::builder() + .descriptor_pool(data.descriptor_pool) + .set_layouts(&layouts); + + data.descriptor_sets = device.allocate_descriptor_sets(&info)?; + + for i in 0..data.swapchain_images.len() { + let info = vk::DescriptorBufferInfo::builder() + .buffer(data.uniform_buffers[i]) + .offset(0) + .range(size_of::() as u64); + + let buffer_info = &[info]; + let ubo_write = vk::WriteDescriptorSet::builder() + .dst_set(data.descriptor_sets[i]) + .dst_binding(0) + .dst_array_element(0) + .descriptor_type(vk::DescriptorType::UNIFORM_BUFFER) + .buffer_info(buffer_info); + + device.update_descriptor_sets(&[ubo_write], &[] as &[vk::CopyDescriptorSet]); + } + + Ok(()) +} + +unsafe fn create_image( + instance:&Instance, device:&Device, data:&AppData, width:u32, height:u32, format:vk::Format, tiling:vk::ImageTiling, usage:vk::ImageUsageFlags, + properties:vk::MemoryPropertyFlags, +) -> Result<(vk::Image, vk::DeviceMemory)> { + let info = vk::ImageCreateInfo::builder() + .image_type(vk::ImageType::_2D) + .extent(vk::Extent3D { width, height, depth:1 }) + .mip_levels(1) + .array_layers(1) + .format(format) + .tiling(tiling) + .initial_layout(vk::ImageLayout::UNDEFINED) + .usage(usage) + .samples(vk::SampleCountFlags::_1) + .sharing_mode(vk::SharingMode::EXCLUSIVE); + + let image = device.create_image(&info, None)?; + + let requirements = device.get_image_memory_requirements(image); + + let info = vk::MemoryAllocateInfo::builder() + .allocation_size(requirements.size) + .memory_type_index(get_memory_type_index(instance, data, properties, requirements)?); + + let image_memory = device.allocate_memory(&info, None)?; + + device.bind_image_memory(image, image_memory, 0)?; + + Ok((image, image_memory)) +} + +unsafe fn begin_single_time_commands(device:&Device, data:&AppData) -> Result { + let info = vk::CommandBufferAllocateInfo::builder() + .level(vk::CommandBufferLevel::PRIMARY) + .command_pool(data.command_pool) + .command_buffer_count(1); + + let command_buffer = device.allocate_command_buffers(&info)?[0]; + + let info = vk::CommandBufferBeginInfo::builder().flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT); + + device.begin_command_buffer(command_buffer, &info)?; + + Ok(command_buffer) +} + +unsafe fn end_single_time_commands(device:&Device, data:&AppData, command_buffer:vk::CommandBuffer) -> Result<()> { + device.end_command_buffer(command_buffer)?; + + let command_buffers = &[command_buffer]; + let info = vk::SubmitInfo::builder().command_buffers(command_buffers); + + device.queue_submit(data.graphics_queue, &[info], vk::Fence::null())?; + device.queue_wait_idle(data.graphics_queue)?; + + device.free_command_buffers(data.command_pool, &[command_buffer]); + + Ok(()) +} + +unsafe fn transition_image_layout( + device:&Device, data:&AppData, image:vk::Image, format:vk::Format, old_layout:vk::ImageLayout, new_layout:vk::ImageLayout, +) -> Result<()> { + let command_buffer = begin_single_time_commands(device, data)?; + + let subresource = vk::ImageSubresourceRange::builder() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .base_mip_level(0) + .level_count(1) + .base_array_layer(0) + .layer_count(1); + + let (src_access_mask, dst_access_mask, src_stage_mask, dst_stage_mask) = match (old_layout, new_layout) { + (vk::ImageLayout::UNDEFINED, vk::ImageLayout::TRANSFER_DST_OPTIMAL) => ( + vk::AccessFlags::empty(), + vk::AccessFlags::TRANSFER_WRITE, + vk::PipelineStageFlags::TOP_OF_PIPE, + vk::PipelineStageFlags::TRANSFER, + ), + (vk::ImageLayout::TRANSFER_DST_OPTIMAL, vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) => ( + vk::AccessFlags::TRANSFER_WRITE, + vk::AccessFlags::SHADER_READ, + vk::PipelineStageFlags::TRANSFER, + vk::PipelineStageFlags::FRAGMENT_SHADER, + ), + _ => return Err(anyhow!("Unsupported image layout transition!")), + }; + + let barrier = vk::ImageMemoryBarrier::builder() + .old_layout(old_layout) + .new_layout(new_layout) + .src_queue_family_index(vk::QUEUE_FAMILY_IGNORED) + .dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED) + .image(image) + .subresource_range(subresource) + .src_access_mask(src_access_mask) + .dst_access_mask(dst_access_mask); + + device.cmd_pipeline_barrier( + command_buffer, + src_stage_mask, + dst_stage_mask, + vk::DependencyFlags::empty(), + &[] as &[vk::MemoryBarrier], + &[] as &[vk::BufferMemoryBarrier], + &[barrier], + ); + + end_single_time_commands(device, data, command_buffer)?; + + Ok(()) +} + +unsafe fn copy_buffer_to_image(device:&Device, data:&AppData, buffer:vk::Buffer, image:vk::Image, width:u32, height:u32) -> Result<()> { + let command_buffer = begin_single_time_commands(device, data)?; + + let subresource = vk::ImageSubresourceLayers::builder() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .mip_level(0) + .base_array_layer(0) + .layer_count(1); + + let region = vk::BufferImageCopy::builder() + .buffer_offset(0) + .buffer_row_length(0) + .buffer_image_height(0) + .image_subresource(subresource) + .image_offset(vk::Offset3D { x:0, y:0, z:0 }) + .image_extent(vk::Extent3D { width, height, depth:1 }); + + device.cmd_copy_buffer_to_image(command_buffer, buffer, image, vk::ImageLayout::TRANSFER_DST_OPTIMAL, &[region]); + + end_single_time_commands(device, data, command_buffer)?; + + Ok(()) +} + +unsafe fn create_texture_image_view(device:&Device, data:&mut AppData) -> Result<()> { + data.texture_image_view = create_image_view(device, data.texture_image, vk::Format::R8G8B8A8_SRGB)?; + + Ok(()) +} + +unsafe fn create_image_view(device:&Device, image:vk::Image, format:vk::Format) -> Result { + let subresource_range = vk::ImageSubresourceRange::builder() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .base_mip_level(0) + .level_count(1) + .base_array_layer(0) + .layer_count(1); + + let info = vk::ImageViewCreateInfo::builder() + .image(image) + .view_type(vk::ImageViewType::_2D) + .format(format) + .subresource_range(subresource_range); + + Ok(device.create_image_view(&info, None)?) +} + +unsafe fn create_texture_sampler(device:&Device, data:&mut AppData) -> Result<()> { Ok(()) } diff --git a/src/macos/metal_bindgen/metal.rs b/src/input_systems/mod.rs similarity index 100% rename from src/macos/metal_bindgen/metal.rs rename to src/input_systems/mod.rs diff --git a/src/linux.rs b/src/linux.rs deleted file mode 100644 index 22c99c2..0000000 --- a/src/linux.rs +++ /dev/null @@ -1,116 +0,0 @@ -use std::process::exit; - -use anyhow::Result; - -use log::*; - -use vulkanalia::prelude::v1_0::*; - -use old_winit::dpi::LogicalSize; -use old_winit::event::Event; -use old_winit::event::WindowEvent; -use old_winit::event_loop::EventLoop; -use old_winit::window::WindowBuilder; - -use crate::graphics_engines; -use crate::graphics_engines::vulkan::App; - -const WINDOW_TITLE:&'static str = "MineMod"; - -const GRAPHICS_MODE:GMode = GMode::OpenGL; - -enum GMode { - Vulkan, - OpenGL, -} - -pub fn main() -> Result<()> { - super::init_logging(); - - info!("Registering CTRLC hook."); - - let (shutdown_tx, shutdown_rx) = std::sync::mpsc::channel(); - - ctrlc::set_handler(move || { - shutdown_tx.send(()).expect("Failed to send shutdown signal"); - }) - .expect("Error setting Ctrl-C handler"); - - match GRAPHICS_MODE { - GMode::Vulkan => { - info!("Initializing event loop and winit window instance."); - - // Window - - let event_loop = EventLoop::new()?; - let window = WindowBuilder::new() - .with_title(WINDOW_TITLE) - .with_inner_size(LogicalSize::new(1024, 768)) - .build(&event_loop)?; - - info!("Creating app and starting event loop."); - - // App - - let mut app = unsafe { App::create(&window)? }; - let mut minimized = false; - - let shutdown_rx = std::sync::Arc::new(std::sync::Mutex::new(Some(shutdown_rx))); - - event_loop.run(move |event, elwt| { - let mut shutdown_rx_guard = shutdown_rx.lock().unwrap(); - - if let Some(receiver) = shutdown_rx_guard.as_mut() { - if receiver.try_recv().is_ok() { - info!("Closing event loop and destroying Vulkan instance."); - elwt.exit(); - unsafe { - app.device.device_wait_idle().unwrap(); - app.destroy(); - } - return; - } - } - - match event { - // Request a redraw when all events were processed. - Event::AboutToWait => window.request_redraw(), - Event::WindowEvent { event, .. } => match event { - // Render a frame if our Vulkan app is not being destroyed. - WindowEvent::RedrawRequested if !elwt.exiting() && !minimized => { - unsafe { app.render(&window) }.unwrap(); - }, - WindowEvent::Resized(size) => - if size.width == 0 || size.height == 0 { - minimized = true; - } else { - minimized = false; - app.resized = true; - }, - // Destroy our Vulkan app. - WindowEvent::CloseRequested => { - info!("Closing event loop and destroying Vulkan instance."); - elwt.exit(); - unsafe { - app.device.device_wait_idle().unwrap(); - app.destroy(); - } - }, - _ => {}, - }, - _ => {}, - } - })?; - }, - GMode::OpenGL => { - if let Err(error) = graphics_engines::opengl::main(winit::event_loop::EventLoop::new()?) { - error!("gl error {error}"); - exit(-1); - } - }, - } - - info!("Exiting program."); - - Ok(()) -} diff --git a/src/mac.rs b/src/mac.rs deleted file mode 100644 index be6d4d8..0000000 --- a/src/mac.rs +++ /dev/null @@ -1,96 +0,0 @@ -use anyhow::Result; - -use log::*; - -use vulkanalia::prelude::v1_0::*; - -use winit::dpi::LogicalSize; -use winit::event::Event; -use winit::event::WindowEvent; -use winit::event_loop::EventLoop; -use winit::window::WindowBuilder; - -use crate::graphics_engines::vulkan::App; - -const WINDOW_TITLE:&'static str = "MineMod"; - -pub fn main() -> Result<()> { - super::init_logging(); - - info!("Registering CTRLC hook."); - - let (shutdown_tx, shutdown_rx) = std::sync::mpsc::channel(); - - ctrlc::set_handler(move || { - shutdown_tx.send(()).expect("Failed to send shutdown signal"); - }) - .expect("Error setting Ctrl-C handler"); - - info!("Initializing event loop and winit window instance."); - - // Window - - let event_loop = EventLoop::new()?; - let window = WindowBuilder::new() - .with_title(WINDOW_TITLE) - .with_inner_size(LogicalSize::new(1024, 768)) - .build(&event_loop)?; - - info!("Creating app and starting event loop."); - - // App - - let mut app = unsafe { App::create(&window)? }; - let mut minimized = false; - - let shutdown_rx = std::sync::Arc::new(std::sync::Mutex::new(Some(shutdown_rx))); - - event_loop.run(move |event, elwt| { - let mut shutdown_rx_guard = shutdown_rx.lock().unwrap(); - - if let Some(receiver) = shutdown_rx_guard.as_mut() { - if receiver.try_recv().is_ok() { - info!("Closing event loop and destroying Vulkan instance."); - elwt.exit(); - unsafe { - app.device.device_wait_idle().unwrap(); - app.destroy(); - } - return; - } - } - - match event { - // Request a redraw when all events were processed. - Event::AboutToWait => window.request_redraw(), - Event::WindowEvent { event, .. } => match event { - // Render a frame if our Vulkan app is not being destroyed. - WindowEvent::RedrawRequested if !elwt.exiting() && !minimized => { - unsafe { app.render(&window) }.unwrap(); - }, - WindowEvent::Resized(size) => - if size.width == 0 || size.height == 0 { - minimized = true; - } else { - minimized = false; - app.resized = true; - }, - // Destroy our Vulkan app. - WindowEvent::CloseRequested => { - info!("Closing event loop and destroying Vulkan instance."); - elwt.exit(); - unsafe { - app.device.device_wait_idle().unwrap(); - app.destroy(); - } - }, - _ => {}, - }, - _ => {}, - } - })?; - - info!("Exiting program."); - - Ok(()) -} diff --git a/src/main.rs b/src/main.rs index 0c239f0..69409c6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +//#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] #![deny(clippy::unwrap_used)] #![allow( // dead_code, @@ -8,8 +8,33 @@ unsafe_op_in_unsafe_fn )] +mod audio_engines; mod cataclysm; mod graphics_engines; +mod input_systems; +mod targets; + +/// i hope you will forgive me for these crimes, but as far as i can tell this is the best way +/// to handle all these platforms with wildly different requirements and capabilities +pub use targets::*; + +// Logging is currently common across all platforms so it may live here +fn init_logging() { + tracing_subscriber::fmt() + .compact() + .with_timer(tracing_subscriber::fmt::time::uptime()) + .with_ansi(true) + .with_level(true) + .with_thread_names(true) + .with_max_level(if cfg!(debug_assertions) { + tracing::level_filters::LevelFilter::DEBUG + } else { + tracing::level_filters::LevelFilter::INFO + }) + .init(); + + // pretty_env_logger::init_timed(); +} // NOTE use crate:: for things in engine that depend on the target platform // this allows an incredibly easy way to handle gui and others per platform @@ -38,58 +63,3 @@ mod graphics_engines; // test BCn vs raw formats // research why texture atlases exist, it seems like an easy way to reduce the allocation calls since they are limited, and it seems to provide better usage of memory overall - -// Planned system targets -#[cfg(target_os = "linux")] mod linux; -#[cfg(target_os = "linux")] pub use linux::*; -#[cfg(target_os = "windows")] mod windows; -#[cfg(target_os = "windows")] pub use windows::*; -#[cfg(target_os = "macos")] mod mac; -#[cfg(target_os = "macos")] pub use mac::*; -#[cfg(target_family = "wasm")] mod wasm; -#[cfg(target_family = "wasm")] pub use wasm::*; -#[cfg(target_os = "vita")] mod vita; -#[cfg(target_os = "vita")] pub use vita::*; - -// Potential system targets - -// bindgen, cc, https://github.com/rust-console - -// switch // c lib: libnx, crate: rust-switch, toolchain: devkitPro -// #[cfg(target_os = "horizon")] -// mod switch; -// #[cfg(target_os = "horizon")] -// pub use switch::*; -// ps3 // sdk: PSL1GHT, target: powerpc64-unknown-linux-gnu -// #[cfg(target_os = "psl1ght")] -// mod ps3; -// #[cfg(target_os = "psl1ght")] -// pub use ps3::*; -// x360 // c lib: libxenon, make custom spec for xenon target -// #[cfg(target_os = "xenon")] -// mod x369; -// #[cfg(target_os = "xenon")] -// pub use x360::*; -// wii // toolchain: devkitPPC, target: powerpc-unknown-eabi, c lib: libogc -// #[cfg(target_os = "wii")] -// mod wii; -// #[cfg(target_os = "wii")] -// pub use wii::*; - -fn init_logging() { - tracing_subscriber::fmt() - .compact() - .with_timer(tracing_subscriber::fmt::time::uptime()) - .with_ansi(true) - .with_level(true) - // .with_thread_ids(true) - .with_thread_names(true) - .with_max_level(if cfg!(debug_assertions) { - tracing::level_filters::LevelFilter::DEBUG - } else { - tracing::level_filters::LevelFilter::INFO - }) - .init(); - - // pretty_env_logger::init_timed(); -} diff --git a/src/targets/desktop/linux.rs b/src/targets/desktop/linux.rs new file mode 100644 index 0000000..2c82f24 --- /dev/null +++ b/src/targets/desktop/linux.rs @@ -0,0 +1,13 @@ +//use anyhow::Result; + +//use log::*; +//use winit::event_loop::EventLoop; + +//pub fn main() -> Result<()> { +// crate::init_logging(); + + + + +// Ok(()) +//} diff --git a/src/targets/desktop/mac/metal_bindgen/metal.rs b/src/targets/desktop/mac/metal_bindgen/metal.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/targets/desktop/mac/mod.rs b/src/targets/desktop/mac/mod.rs new file mode 100644 index 0000000..33e10ea --- /dev/null +++ b/src/targets/desktop/mac/mod.rs @@ -0,0 +1,96 @@ +//use anyhow::Result; + +//use log::*; + +//use vulkanalia::prelude::v1_0::*; + +//use winit::dpi::LogicalSize; +//use winit::event::Event; +//use winit::event::WindowEvent; +//use winit::event_loop::EventLoop; +//use winit::window::WindowBuilder; + +//use crate::graphics_engines::vulkan::App; + +//const WINDOW_TITLE:&'static str = "MineMod"; + +//pub fn main() -> Result<()> { +// super::init_logging(); + +// info!("Registering CTRLC hook."); + +// let (shutdown_tx, shutdown_rx) = std::sync::mpsc::channel(); + +// ctrlc::set_handler(move || { +// shutdown_tx.send(()).expect("Failed to send shutdown signal"); +// }) +// .expect("Error setting Ctrl-C handler"); + +// info!("Initializing event loop and winit window instance."); + +// // Window + +// let event_loop = EventLoop::new()?; +// let window = WindowBuilder::new() +// .with_title(WINDOW_TITLE) +// .with_inner_size(LogicalSize::new(1024, 768)) +// .build(&event_loop)?; + +// info!("Creating app and starting event loop."); + +// // App + +// let mut app = unsafe { App::create(&window)? }; +// let mut minimized = false; + +// let shutdown_rx = std::sync::Arc::new(std::sync::Mutex::new(Some(shutdown_rx))); + +// event_loop.run(move |event, elwt| { +// let mut shutdown_rx_guard = shutdown_rx.lock().unwrap(); + +// if let Some(receiver) = shutdown_rx_guard.as_mut() { +// if receiver.try_recv().is_ok() { +// info!("Closing event loop and destroying Vulkan instance."); +// elwt.exit(); +// unsafe { +// app.device.device_wait_idle().unwrap(); +// app.destroy(); +// } +// return; +// } +// } + +// match event { +// // Request a redraw when all events were processed. +// Event::AboutToWait => window.request_redraw(), +// Event::WindowEvent { event, .. } => match event { +// // Render a frame if our Vulkan app is not being destroyed. +// WindowEvent::RedrawRequested if !elwt.exiting() && !minimized => { +// unsafe { app.render(&window) }.unwrap(); +// }, +// WindowEvent::Resized(size) => +// if size.width == 0 || size.height == 0 { +// minimized = true; +// } else { +// minimized = false; +// app.resized = true; +// }, +// // Destroy our Vulkan app. +// WindowEvent::CloseRequested => { +// info!("Closing event loop and destroying Vulkan instance."); +// elwt.exit(); +// unsafe { +// app.device.device_wait_idle().unwrap(); +// app.destroy(); +// } +// }, +// _ => {}, +// }, +// _ => {}, +// } +// })?; + +// info!("Exiting program."); + +// Ok(()) +//} diff --git a/src/targets/desktop/mod.rs b/src/targets/desktop/mod.rs new file mode 100644 index 0000000..6199875 --- /dev/null +++ b/src/targets/desktop/mod.rs @@ -0,0 +1,166 @@ +use anyhow::Result; + +use glfw::Action; +use glfw::Context; +use glfw::Key; + +use log::*; + +use crate::cataclysm::Cataclysm; +use crate::cataclysm::CataclysmChunk; +use crate::cataclysm::SimpleBlock; +use crate::graphics_engines::GMode; +use crate::graphics_engines::GraphicsCommander; + +//#[cfg(target_os = "linux")] mod linux; +//#[cfg(target_os = "linux")] pub use linux::*; +//#[cfg(target_os = "windows")] mod windows; +//#[cfg(target_os = "windows")] pub use windows::*; +//#[cfg(target_os = "macos")] mod mac; +//#[cfg(target_os = "macos")] pub use mac::*; + +pub const WINDOW_TITLE:&'static str = "MineMod"; +pub const WINDOW_DECORATION_LEFT:bool = false; + +pub fn main() -> Result<(), Box> { + crate::init_logging(); + + info!("Registering ^C hook."); + + let (shutdown_tx, shutdown_rx) = std::sync::mpsc::channel(); + + ctrlc::set_handler(move || { + shutdown_tx.send(()).expect("Failed to send shutdown signal"); + }) + .expect("Error setting Ctrl-C handler"); + + let mut glfw = glfw::init(|err, string| match err { + // we dont give a shit because we supply our own render system + glfw::Error::NoWindowContext /*| glfw::Error::NoError*/ => warn!("GLFW Error: {err} {string}"), + _ => panic!("GLFW Error! {err}, {string}"), + })?; + + let graphics_mode = GMode::OpenGL; + + // if we do not want to use opengl, disable it + if graphics_mode != GMode::OpenGL { + glfw.window_hint(glfw::WindowHint::ClientApi(glfw::ClientApiHint::NoApi)); + } + + if let GMode::OpenGL = graphics_mode {} + + let (mut window, events) = if let Some(glfw) = glfw.create_window(1024, 768, &WINDOW_TITLE, glfw::WindowMode::Windowed) { + glfw + } else { + return Err("Could not create glfw window!".into()); + }; + + window.set_key_polling(true); + window.make_current(); + + let mut cmd = /*Some(*/make_graphics_commander(graphics_mode, &mut window)?/*)*/; + + let mut game_world = Cataclysm::new(); + + game_world.chunks.insert((0, 0, 0), CataclysmChunk::new()); + + for x in 0..Cataclysm::CHUNK_SIZE { + for y in 0..Cataclysm::CHUNK_SIZE { + for z in 0..Cataclysm::CHUNK_SIZE { + game_world.chunks.get_mut(&(0, 0, 0)).unwrap().simple_blocks.insert((x, y, z), SimpleBlock {}); + } + } + } + + //'mainloop: while !window.should_close() { + loop { + if shutdown_rx.try_recv().is_ok() { + info!("^C triggered."); + window.set_should_close(true); + } + + // Swap front and back buffers + //window.swap_buffers(); // cannot be used + + // dont flood the logs + //std::thread::sleep(Duration::from_secs(1)); + + trace!("Polling GLFW events."); + // Poll for and process events + glfw.poll_events(); + + for (e, event) in glfw::flush_messages(&events) { + info!("GLFW Event: {:?}", event); + match event { + //glfw::WindowEvent::FramebufferSize(x, y) => {}, + //glfw::WindowEvent::Close => window.set_should_close(true), + // minimize? doesnt appear to be + glfw::WindowEvent::Iconify(e) => + //if let Some(cmd) = graphics_commander.as_mut() { + if e { + cmd.suspend_rendering(); + } else { + cmd.resume_rendering(); + }, + //}, + glfw::WindowEvent::Key(key, _, Action::Press, _) => match key { + Key::Escape | Key::Q => window.set_should_close(true), + //Key::E => { + //if let Some(cmd) = graphics_commander.as_mut() { + // cmd.exit(); + //} + //let _gc = graphics_commander.take(); + //match graphics_mode { + // GMode::Vulkan => graphics_mode = GMode::OpenGL, + // GMode::OpenGL => graphics_mode = GMode::Vulkan, + // #[cfg(target_os = "macos")] + // GMode::Metal => todo!(), + // #[cfg(target_os = "windows")] + // GMode::DirectX => todo!(), + //} + //graphics_commander = Some(make_graphics_commander(graphics_mode, &mut window)?); + //}, + _ => (), + }, + event => { + dbg!(event); + }, + } + } + + if window.should_close() { + info!("Breaking loop."); + break; + } + + //if let Some(cmd) = graphics_commander.as_mut() { + trace!("Rendering."); + //cmd.render_simple_blocks(game_world.chunks.get_mut(&(0, 0, 0)).unwrap().simple_blocks); + cmd.render(&mut window, &mut game_world)?; + //} + } + + //if let Some(cmd) = graphics_commander.as_mut() { + info!("Closing GC instance."); + cmd.exit(); + //} + + info!("Exiting."); + Ok(()) +} + +fn make_graphics_commander(graphics_mode:GMode, window:&mut glfw::PWindow) -> Result> { + Ok(match graphics_mode { + GMode::Vulkan => Box::new(unsafe { crate::graphics_engines::vulkan_gc::App::create(&window)? }), + GMode::OpenGL => Box::new(crate::graphics_engines::opengl::Renderer::create(window)?), + #[cfg(target_os = "macos")] + GMode::Metal => todo!(), + #[cfg(target_os = "windows")] + GMode::DirectX => todo!(), + }) +} + +//fn make_glfw() -> Result> { + +// Ok(glfw) +//} diff --git a/src/targets/desktop/windows.rs b/src/targets/desktop/windows.rs new file mode 100644 index 0000000..d76fcc8 --- /dev/null +++ b/src/targets/desktop/windows.rs @@ -0,0 +1,96 @@ +//use anyhow::Result; + +//use log::*; + +//use vulkanalia::prelude::v1_0::*; + +//use winit::dpi::LogicalSize; +//use winit::event::Event; +//use winit::event::WindowEvent; +//use winit::event_loop::EventLoop; +//use winit::window::WindowBuilder; + +//use crate::graphics_engines::vulkan::App; + +//const WINDOW_TITLE:&'static str = "MineMod"; + +//pub fn main() -> Result<()> { +// super::init_logging(); + +// info!("Registering CTRLC hook."); + +// let (shutdown_tx, shutdown_rx) = std::sync::mpsc::channel::<()>(); + +// ctrlc::set_handler(move || { +// shutdown_tx.send(()).expect("Failed to send shutdown signal"); +// }) +// .expect("Error setting Ctrl-C handler"); + +// info!("Initializing event loop and winit window instance."); + +// // Window + +// let event_loop = EventLoop::new()?; +// let window = WindowBuilder::new() +// .with_title(WINDOW_TITLE) +// .with_inner_size(LogicalSize::new(1024, 768)) +// .build(&event_loop)?; + +// info!("Creating app and starting event loop."); + +// // App + +// let mut app = unsafe { App::create(&window)? }; +// let mut minimized = false; + +// let shutdown_rx = std::sync::Arc::new(std::sync::Mutex::new(Some(shutdown_rx))); + +// event_loop.run(move |event, elwt| { +// let mut shutdown_rx_guard = shutdown_rx.lock().unwrap(); + +// if let Some(receiver) = shutdown_rx_guard.as_mut() { +// if receiver.try_recv().is_ok() { +// info!("Closing event loop and destroying Vulkan instance."); +// elwt.exit(); +// unsafe { +// app.device.device_wait_idle().unwrap(); +// app.destroy(); +// } +// return; +// } +// } + +// match event { +// // Request a redraw when all events were processed. +// Event::AboutToWait => window.request_redraw(), +// Event::WindowEvent { event, .. } => match event { +// // Render a frame if our Vulkan app is not being destroyed. +// WindowEvent::RedrawRequested if !elwt.exiting() && !minimized => { +// unsafe { app.render(&window) }.unwrap(); +// }, +// WindowEvent::Resized(size) => +// if size.width == 0 || size.height == 0 { +// minimized = true; +// } else { +// minimized = false; +// app.resized = true; +// }, +// // Destroy our Vulkan app. +// WindowEvent::CloseRequested => { +// info!("Closing event loop and destroying Vulkan instance."); +// elwt.exit(); +// unsafe { +// app.device.device_wait_idle().unwrap(); +// app.destroy(); +// } +// }, +// _ => {}, +// }, +// _ => {}, +// } +// })?; + +// info!("Exiting program."); + +// Ok(()) +//} diff --git a/src/targets/mod.rs b/src/targets/mod.rs new file mode 100644 index 0000000..a258ef4 --- /dev/null +++ b/src/targets/mod.rs @@ -0,0 +1,37 @@ +// Planned system targets + +#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] +mod desktop; +#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] +pub use desktop::*; + +// wasm may count for desktop? it does not need windowing however +//#[cfg(target_family = "wasm")] mod wasm; +//#[cfg(target_family = "wasm")] pub use wasm::*; +//#[cfg(target_os = "vita")] mod vita; +//#[cfg(target_os = "vita")] pub use vita::*; + +// Potential system targets + +// bindgen, cc, https://github.com/rust-console + +// switch // c lib: libnx, crate: rust-switch, toolchain: devkitPro +// #[cfg(target_os = "horizon")] +// mod switch; +// #[cfg(target_os = "horizon")] +// pub use switch::*; +// ps3 // sdk: PSL1GHT, target: powerpc64-unknown-linux-gnu +// #[cfg(target_os = "psl1ght")] +// mod ps3; +// #[cfg(target_os = "psl1ght")] +// pub use ps3::*; +// x360 // c lib: libxenon, make custom spec for xenon target +// #[cfg(target_os = "xenon")] +// mod x369; +// #[cfg(target_os = "xenon")] +// pub use x360::*; +// wii // toolchain: devkitPPC, target: powerpc-unknown-eabi, c lib: libogc +// #[cfg(target_os = "wii")] +// mod wii; +// #[cfg(target_os = "wii")] +// pub use wii::*; \ No newline at end of file diff --git a/src/vita/debug_screen/font.bin b/src/targets/vita/debug_screen/font.bin similarity index 100% rename from src/vita/debug_screen/font.bin rename to src/targets/vita/debug_screen/font.bin diff --git a/src/vita/debug_screen/font.rs b/src/targets/vita/debug_screen/font.rs similarity index 100% rename from src/vita/debug_screen/font.rs rename to src/targets/vita/debug_screen/font.rs diff --git a/src/vita/debug_screen/fonts.rs b/src/targets/vita/debug_screen/fonts.rs similarity index 100% rename from src/vita/debug_screen/fonts.rs rename to src/targets/vita/debug_screen/fonts.rs diff --git a/src/vita/debug_screen/framebuffer.rs b/src/targets/vita/debug_screen/framebuffer.rs similarity index 100% rename from src/vita/debug_screen/framebuffer.rs rename to src/targets/vita/debug_screen/framebuffer.rs diff --git a/src/vita/debug_screen/mod.rs b/src/targets/vita/debug_screen/mod.rs similarity index 100% rename from src/vita/debug_screen/mod.rs rename to src/targets/vita/debug_screen/mod.rs diff --git a/src/vita/gui/font.bin b/src/targets/vita/gui/font.bin similarity index 100% rename from src/vita/gui/font.bin rename to src/targets/vita/gui/font.bin diff --git a/src/vita/gui/framebuffer.rs b/src/targets/vita/gui/framebuffer.rs similarity index 100% rename from src/vita/gui/framebuffer.rs rename to src/targets/vita/gui/framebuffer.rs diff --git a/src/vita/gui/mod.rs b/src/targets/vita/gui/mod.rs similarity index 100% rename from src/vita/gui/mod.rs rename to src/targets/vita/gui/mod.rs diff --git a/src/vita/mod.rs b/src/targets/vita/mod.rs similarity index 100% rename from src/vita/mod.rs rename to src/targets/vita/mod.rs diff --git a/src/wasm.rs b/src/targets/wasm.rs similarity index 100% rename from src/wasm.rs rename to src/targets/wasm.rs diff --git a/src/windows.rs b/src/windows.rs deleted file mode 100644 index 2b92962..0000000 --- a/src/windows.rs +++ /dev/null @@ -1,96 +0,0 @@ -use anyhow::Result; - -use log::*; - -use vulkanalia::prelude::v1_0::*; - -use winit::dpi::LogicalSize; -use winit::event::Event; -use winit::event::WindowEvent; -use winit::event_loop::EventLoop; -use winit::window::WindowBuilder; - -use crate::graphics_engines::vulkan::App; - -const WINDOW_TITLE:&'static str = "MineMod"; - -pub fn main() -> Result<()> { - super::init_logging(); - - info!("Registering CTRLC hook."); - - let (shutdown_tx, shutdown_rx) = std::sync::mpsc::channel::<()>(); - - ctrlc::set_handler(move || { - shutdown_tx.send(()).expect("Failed to send shutdown signal"); - }) - .expect("Error setting Ctrl-C handler"); - - info!("Initializing event loop and winit window instance."); - - // Window - - let event_loop = EventLoop::new()?; - let window = WindowBuilder::new() - .with_title(WINDOW_TITLE) - .with_inner_size(LogicalSize::new(1024, 768)) - .build(&event_loop)?; - - info!("Creating app and starting event loop."); - - // App - - let mut app = unsafe { App::create(&window)? }; - let mut minimized = false; - - let shutdown_rx = std::sync::Arc::new(std::sync::Mutex::new(Some(shutdown_rx))); - - event_loop.run(move |event, elwt| { - let mut shutdown_rx_guard = shutdown_rx.lock().unwrap(); - - if let Some(receiver) = shutdown_rx_guard.as_mut() { - if receiver.try_recv().is_ok() { - info!("Closing event loop and destroying Vulkan instance."); - elwt.exit(); - unsafe { - app.device.device_wait_idle().unwrap(); - app.destroy(); - } - return; - } - } - - match event { - // Request a redraw when all events were processed. - Event::AboutToWait => window.request_redraw(), - Event::WindowEvent { event, .. } => match event { - // Render a frame if our Vulkan app is not being destroyed. - WindowEvent::RedrawRequested if !elwt.exiting() && !minimized => { - unsafe { app.render(&window) }.unwrap(); - }, - WindowEvent::Resized(size) => - if size.width == 0 || size.height == 0 { - minimized = true; - } else { - minimized = false; - app.resized = true; - }, - // Destroy our Vulkan app. - WindowEvent::CloseRequested => { - info!("Closing event loop and destroying Vulkan instance."); - elwt.exit(); - unsafe { - app.device.device_wait_idle().unwrap(); - app.destroy(); - } - }, - _ => {}, - }, - _ => {}, - } - })?; - - info!("Exiting program."); - - Ok(()) -}