initial commit
This commit is contained in:
313
Cargo.lock
generated
313
Cargo.lock
generated
@@ -4,9 +4,9 @@ version = 4
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ab_glyph"
|
name = "ab_glyph"
|
||||||
version = "0.2.29"
|
version = "0.2.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0"
|
checksum = "e074464580a518d16a7126262fffaaa47af89d4099d4cb403f8ed938ba12ee7d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ab_glyph_rasterizer",
|
"ab_glyph_rasterizer",
|
||||||
"owned_ttf_parser",
|
"owned_ttf_parser",
|
||||||
@@ -14,9 +14,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ab_glyph_rasterizer"
|
name = "ab_glyph_rasterizer"
|
||||||
version = "0.1.8"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
|
checksum = "b2187590a23ab1e3df8681afdf0987c48504d80291f002fcdb651f0ef5e25169"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
@@ -48,7 +48,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"ndk",
|
"ndk",
|
||||||
"ndk-context",
|
"ndk-context",
|
||||||
"ndk-sys 0.6.0+11769913",
|
"ndk-sys",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
@@ -154,24 +154,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.18.1"
|
version = "3.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
|
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.23.1"
|
version = "1.23.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422"
|
checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck_derive",
|
"bytemuck_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck_derive"
|
name = "bytemuck_derive"
|
||||||
version = "1.9.3"
|
version = "1.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1"
|
checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -212,9 +212,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.27"
|
version = "1.2.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
|
checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -299,6 +299,16 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation-sys"
|
name = "core-foundation-sys"
|
||||||
version = "0.8.7"
|
version = "0.8.7"
|
||||||
@@ -312,8 +322,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
|
checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"core-foundation",
|
"core-foundation 0.9.4",
|
||||||
"core-graphics-types",
|
"core-graphics-types 0.1.3",
|
||||||
"foreign-types",
|
"foreign-types",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -325,7 +335,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
|
checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"core-foundation",
|
"core-foundation 0.9.4",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-graphics-types"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.9.1",
|
||||||
|
"core-foundation 0.10.1",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -337,9 +358,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crunchy"
|
name = "crunchy"
|
||||||
version = "0.2.3"
|
version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
|
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cursor-icon"
|
name = "cursor-icon"
|
||||||
@@ -399,18 +420,6 @@ dependencies = [
|
|||||||
"windows-sys 0.60.2",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "filetime"
|
|
||||||
version = "0.2.25"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"libredox",
|
|
||||||
"windows-sys 0.59.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foldhash"
|
name = "foldhash"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@@ -497,15 +506,6 @@ dependencies = [
|
|||||||
"xml-rs",
|
"xml-rs",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "glam"
|
|
||||||
version = "0.30.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "50a99dbe56b72736564cfa4b85bf9a33079f16ae8b74983ab06af3b1a3696b11"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glow"
|
name = "glow"
|
||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
@@ -583,7 +583,6 @@ name = "gui"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"glam",
|
|
||||||
"notify",
|
"notify",
|
||||||
"pollster",
|
"pollster",
|
||||||
"rhai",
|
"rhai",
|
||||||
@@ -604,19 +603,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.4"
|
version = "0.15.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
|
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"foldhash",
|
"foldhash",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "heck"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@@ -631,9 +624,9 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.9.0"
|
version = "2.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
@@ -760,7 +753,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
|
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-targets 0.53.2",
|
"windows-targets 0.53.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -771,13 +764,13 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
version = "0.1.3"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.5.13",
|
"redox_syscall 0.5.17",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -794,9 +787,9 @@ checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litrs"
|
name = "litrs"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
|
checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
@@ -831,22 +824,22 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memmap2"
|
name = "memmap2"
|
||||||
version = "0.9.5"
|
version = "0.9.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f"
|
checksum = "483758ad303d734cec05e5c12b41d7e93e6a6390c5e9dae6bdeb7c1259012d28"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "metal"
|
name = "metal"
|
||||||
version = "0.31.0"
|
version = "0.32.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e"
|
checksum = "00c15a6f673ff72ddcc22394663290f870fb224c1bfce55734a75c414150e605"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"block",
|
"block",
|
||||||
"core-graphics-types",
|
"core-graphics-types 0.2.0",
|
||||||
"foreign-types",
|
"foreign-types",
|
||||||
"log",
|
"log",
|
||||||
"objc",
|
"objc",
|
||||||
@@ -867,25 +860,26 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "naga"
|
name = "naga"
|
||||||
version = "25.0.1"
|
version = "26.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b977c445f26e49757f9aca3631c3b8b836942cb278d69a92e7b80d3b24da632"
|
checksum = "916cbc7cb27db60be930a4e2da243cf4bc39569195f22fd8ee419cd31d5b662c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bit-set",
|
"bit-set",
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
|
"cfg-if",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
"half",
|
"half",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
"hexf-parse",
|
"hexf-parse",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"libm",
|
||||||
"log",
|
"log",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"spirv",
|
"spirv",
|
||||||
"strum",
|
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -899,7 +893,7 @@ dependencies = [
|
|||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"jni-sys",
|
"jni-sys",
|
||||||
"log",
|
"log",
|
||||||
"ndk-sys 0.6.0+11769913",
|
"ndk-sys",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
@@ -911,15 +905,6 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
|
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ndk-sys"
|
|
||||||
version = "0.5.0+25.2.9519653"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691"
|
|
||||||
dependencies = [
|
|
||||||
"jni-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk-sys"
|
name = "ndk-sys"
|
||||||
version = "0.6.0+11769913"
|
version = "0.6.0+11769913"
|
||||||
@@ -931,12 +916,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "notify"
|
name = "notify"
|
||||||
version = "8.0.0"
|
version = "8.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943"
|
checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"filetime",
|
|
||||||
"fsevent-sys",
|
"fsevent-sys",
|
||||||
"inotify",
|
"inotify",
|
||||||
"kqueue",
|
"kqueue",
|
||||||
@@ -945,7 +929,7 @@ dependencies = [
|
|||||||
"mio",
|
"mio",
|
||||||
"notify-types",
|
"notify-types",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1218,18 +1202,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ordered-float"
|
name = "ordered-float"
|
||||||
version = "4.6.0"
|
version = "5.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951"
|
checksum = "e2c1f9f56e534ac6a9b8a4600bdf0f530fb393b5f393e7b4d03489c3cf0c3f01"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "owned_ttf_parser"
|
name = "owned_ttf_parser"
|
||||||
version = "0.25.0"
|
version = "0.25.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4"
|
checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ttf-parser",
|
"ttf-parser",
|
||||||
]
|
]
|
||||||
@@ -1252,7 +1236,7 @@ checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.5.13",
|
"redox_syscall 0.5.17",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
@@ -1303,17 +1287,16 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polling"
|
name = "polling"
|
||||||
version = "3.8.0"
|
version = "3.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b53a684391ad002dd6a596ceb6c74fd004fdce75f4be2e3f615068abbea5fd50"
|
checksum = "b5bd19146350fe804f7cb2669c851c03d69da628803dab0d98018142aaa5d829"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"rustix 1.0.7",
|
"rustix 1.0.8",
|
||||||
"tracing",
|
"windows-sys 0.60.2",
|
||||||
"windows-sys 0.59.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1328,6 +1311,15 @@ version = "1.11.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
|
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "portable-atomic-util"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
|
||||||
|
dependencies = [
|
||||||
|
"portable-atomic",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "presser"
|
name = "presser"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@@ -1405,9 +1397,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.13"
|
version = "0.5.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
|
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
]
|
]
|
||||||
@@ -1421,7 +1413,7 @@ checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "rhai"
|
name = "rhai"
|
||||||
version = "1.22.2"
|
version = "1.22.2"
|
||||||
source = "git+https://github.com/rhaiscript/rhai#08baaaf4e2d6767f2da4d89a4f91352f8637b45a"
|
source = "git+https://github.com/rhaiscript/rhai#9508db6a828d8d8b2ac868054d985098c62ba904"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
@@ -1436,8 +1428,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rhai_codegen"
|
name = "rhai_codegen"
|
||||||
version = "3.0.0"
|
version = "3.1.0"
|
||||||
source = "git+https://github.com/rhaiscript/rhai#08baaaf4e2d6767f2da4d89a4f91352f8637b45a"
|
source = "git+https://github.com/rhaiscript/rhai#9508db6a828d8d8b2ac868054d985098c62ba904"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1465,15 +1457,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "1.0.7"
|
version = "1.0.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys 0.9.4",
|
"linux-raw-sys 0.9.4",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1544,9 +1536,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.10"
|
version = "0.4.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d"
|
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slotmap"
|
name = "slotmap"
|
||||||
@@ -1629,28 +1621,6 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strum"
|
|
||||||
version = "0.26.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
|
||||||
dependencies = [
|
|
||||||
"strum_macros",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strum_macros"
|
|
||||||
version = "0.26.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
|
||||||
dependencies = [
|
|
||||||
"heck",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"rustversion",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.104"
|
version = "2.0.104"
|
||||||
@@ -1912,13 +1882,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-backend"
|
name = "wayland-backend"
|
||||||
version = "0.3.10"
|
version = "0.3.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121"
|
checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"downcast-rs",
|
"downcast-rs",
|
||||||
"rustix 0.38.44",
|
"rustix 1.0.8",
|
||||||
"scoped-tls",
|
"scoped-tls",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"wayland-sys",
|
"wayland-sys",
|
||||||
@@ -1926,12 +1896,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-client"
|
name = "wayland-client"
|
||||||
version = "0.31.10"
|
version = "0.31.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61"
|
checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"rustix 0.38.44",
|
"rustix 1.0.8",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
"wayland-scanner",
|
"wayland-scanner",
|
||||||
]
|
]
|
||||||
@@ -1949,20 +1919,20 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-cursor"
|
name = "wayland-cursor"
|
||||||
version = "0.31.10"
|
version = "0.31.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a65317158dec28d00416cb16705934070aef4f8393353d41126c54264ae0f182"
|
checksum = "447ccc440a881271b19e9989f75726d60faa09b95b0200a9b7eb5cc47c3eeb29"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustix 0.38.44",
|
"rustix 1.0.8",
|
||||||
"wayland-client",
|
"wayland-client",
|
||||||
"xcursor",
|
"xcursor",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-protocols"
|
name = "wayland-protocols"
|
||||||
version = "0.32.8"
|
version = "0.32.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "779075454e1e9a521794fed15886323ea0feda3f8b0fc1390f5398141310422a"
|
checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
@@ -1972,9 +1942,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-protocols-plasma"
|
name = "wayland-protocols-plasma"
|
||||||
version = "0.3.8"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4fd38cdad69b56ace413c6bcc1fbf5acc5e2ef4af9d5f8f1f9570c0c83eae175"
|
checksum = "a07a14257c077ab3279987c4f8bb987851bf57081b93710381daea94f2c2c032"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
@@ -1985,9 +1955,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-protocols-wlr"
|
name = "wayland-protocols-wlr"
|
||||||
version = "0.3.8"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1cb6cdc73399c0e06504c437fe3cf886f25568dd5454473d565085b36d6a8bbf"
|
checksum = "efd94963ed43cf9938a090ca4f7da58eb55325ec8200c3848963e98dc25b78ec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
@@ -1998,9 +1968,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-scanner"
|
name = "wayland-scanner"
|
||||||
version = "0.31.6"
|
version = "0.31.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484"
|
checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quick-xml",
|
"quick-xml",
|
||||||
@@ -2009,9 +1979,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-sys"
|
name = "wayland-sys"
|
||||||
version = "0.31.6"
|
version = "0.31.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615"
|
checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dlib",
|
"dlib",
|
||||||
"log",
|
"log",
|
||||||
@@ -2041,12 +2011,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu"
|
name = "wgpu"
|
||||||
version = "25.0.2"
|
version = "26.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec8fb398f119472be4d80bc3647339f56eb63b2a331f6a3d16e25d8144197dd9"
|
checksum = "70b6ff82bbf6e9206828e1a3178e851f8c20f1c9028e74dd3a8090741ccd5798"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
|
"cfg-if",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"document-features",
|
"document-features",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
@@ -2069,9 +2040,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-core"
|
name = "wgpu-core"
|
||||||
version = "25.0.2"
|
version = "26.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7b882196f8368511d613c6aeec80655160db6646aebddf8328879a88d54e500"
|
checksum = "d5f62f1053bd28c2268f42916f31588f81f64796e2ff91b81293515017ca8bd9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bit-set",
|
"bit-set",
|
||||||
@@ -2100,36 +2071,36 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-core-deps-apple"
|
name = "wgpu-core-deps-apple"
|
||||||
version = "25.0.0"
|
version = "26.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cfd488b3239b6b7b185c3b045c39ca6bf8af34467a4c5de4e0b1a564135d093d"
|
checksum = "18ae5fbde6a4cbebae38358aa73fcd6e0f15c6144b67ef5dc91ded0db125dbdf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wgpu-hal",
|
"wgpu-hal",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-core-deps-emscripten"
|
name = "wgpu-core-deps-emscripten"
|
||||||
version = "25.0.0"
|
version = "26.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f09ad7aceb3818e52539acc679f049d3475775586f3f4e311c30165cf2c00445"
|
checksum = "d7670e390f416006f746b4600fdd9136455e3627f5bd763abf9a65daa216dd2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wgpu-hal",
|
"wgpu-hal",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-core-deps-windows-linux-android"
|
name = "wgpu-core-deps-windows-linux-android"
|
||||||
version = "25.0.0"
|
version = "26.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cba5fb5f7f9c98baa7c889d444f63ace25574833df56f5b817985f641af58e46"
|
checksum = "720a5cb9d12b3d337c15ff0e24d3e97ed11490ff3f7506e7f3d98c68fa5d6f14"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wgpu-hal",
|
"wgpu-hal",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-hal"
|
name = "wgpu-hal"
|
||||||
version = "25.0.2"
|
version = "26.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f968767fe4d3d33747bbd1473ccd55bf0f6451f55d733b5597e67b5deab4ad17"
|
checksum = "7df2c64ac282a91ad7662c90bc4a77d4a2135bc0b2a2da5a4d4e267afc034b9e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android_system_properties",
|
"android_system_properties",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
@@ -2140,7 +2111,7 @@ dependencies = [
|
|||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"core-graphics-types",
|
"core-graphics-types 0.2.0",
|
||||||
"glow",
|
"glow",
|
||||||
"glutin_wgl_sys",
|
"glutin_wgl_sys",
|
||||||
"gpu-alloc",
|
"gpu-alloc",
|
||||||
@@ -2154,11 +2125,12 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"metal",
|
"metal",
|
||||||
"naga",
|
"naga",
|
||||||
"ndk-sys 0.5.0+25.2.9519653",
|
"ndk-sys",
|
||||||
"objc",
|
"objc",
|
||||||
"ordered-float",
|
"ordered-float",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
|
"portable-atomic-util",
|
||||||
"profiling",
|
"profiling",
|
||||||
"range-alloc",
|
"range-alloc",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
@@ -2174,9 +2146,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-types"
|
name = "wgpu-types"
|
||||||
version = "25.0.0"
|
version = "26.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2aa49460c2a8ee8edba3fca54325540d904dd85b2e086ada762767e17d06e8bc"
|
checksum = "eca7a8d8af57c18f57d393601a1fb159ace8b2328f1b6b5f80893f7d672c9ae2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
@@ -2240,6 +2212,12 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-link"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-result"
|
name = "windows-result"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@@ -2292,7 +2270,7 @@ version = "0.60.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets 0.53.2",
|
"windows-targets 0.53.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2343,10 +2321,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.53.2"
|
version = "0.53.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
|
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
"windows_aarch64_gnullvm 0.53.0",
|
"windows_aarch64_gnullvm 0.53.0",
|
||||||
"windows_aarch64_msvc 0.53.0",
|
"windows_aarch64_msvc 0.53.0",
|
||||||
"windows_i686_gnu 0.53.0",
|
"windows_i686_gnu 0.53.0",
|
||||||
@@ -2539,9 +2518,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit"
|
name = "winit"
|
||||||
version = "0.30.11"
|
version = "0.30.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4409c10174df8779dc29a4788cac85ed84024ccbc1743b776b21a520ee1aaf4"
|
checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"android-activity",
|
"android-activity",
|
||||||
@@ -2552,7 +2531,7 @@ dependencies = [
|
|||||||
"calloop",
|
"calloop",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"core-foundation",
|
"core-foundation 0.9.4",
|
||||||
"core-graphics",
|
"core-graphics",
|
||||||
"cursor-icon",
|
"cursor-icon",
|
||||||
"dpi",
|
"dpi",
|
||||||
@@ -2591,9 +2570,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.7.11"
|
version = "0.7.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
|
checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@@ -2641,9 +2620,9 @@ checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xcursor"
|
name = "xcursor"
|
||||||
version = "0.3.9"
|
version = "0.3.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "635887f4315a33cb714eb059bdbd7c1c92bfa71bc5b9d5115460502f788c2ab5"
|
checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xkbcommon-dl"
|
name = "xkbcommon-dl"
|
||||||
@@ -2666,9 +2645,9 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xml-rs"
|
name = "xml-rs"
|
||||||
version = "0.8.26"
|
version = "0.8.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda"
|
checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
|
|||||||
@@ -6,11 +6,10 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytemuck = "1.23.1"
|
|
||||||
glam = { version = "0.30.4", features = ["bytemuck"] }
|
|
||||||
pollster = "0.4.0"
|
pollster = "0.4.0"
|
||||||
wgpu = "25.0.2"
|
|
||||||
winit = "0.30.11"
|
winit = "0.30.11"
|
||||||
rhai = { git = "https://github.com/rhaiscript/rhai", features = ["f32_float"] }
|
rhai = { git = "https://github.com/rhaiscript/rhai", features = ["f32_float"] }
|
||||||
notify = "8.0.0"
|
notify = "8.0.0"
|
||||||
|
wgpu = "26.0.1"
|
||||||
|
bytemuck = "1.23.1"
|
||||||
|
|
||||||
|
|||||||
66
src/layout/mod.rs
Normal file
66
src/layout/mod.rs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
mod node;
|
||||||
|
pub use node::*;
|
||||||
|
|
||||||
|
use crate::primitive::{Color, Painter};
|
||||||
|
|
||||||
|
pub type UIColor = Color<u8>;
|
||||||
|
|
||||||
|
pub trait UINode: 'static {
|
||||||
|
fn draw(&self, painter: &mut Painter);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UI {
|
||||||
|
base: Box<dyn UINode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UI {
|
||||||
|
pub fn to_primitives(&self) -> Painter {
|
||||||
|
let mut painter = Painter::default();
|
||||||
|
self.base.draw(&mut painter);
|
||||||
|
painter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: UINode> From<N> for UI {
|
||||||
|
fn from(node: N) -> Self {
|
||||||
|
Self {
|
||||||
|
base: Box::new(node),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UINode for Box<dyn UINode> {
|
||||||
|
fn draw(&self, painter: &mut Painter) {
|
||||||
|
self.as_ref().draw(painter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NodeArray<const LEN: usize> {
|
||||||
|
fn to_arr(self) -> [Box<dyn UINode>; LEN];
|
||||||
|
}
|
||||||
|
|
||||||
|
// I hate this language it's so bad why do I even use it
|
||||||
|
macro_rules! impl_node_arr {
|
||||||
|
($n:expr;$($T:tt)+) => {
|
||||||
|
impl<$($T: UINode,)*> NodeArray<$n> for ($($T,)*) {
|
||||||
|
fn to_arr(self) -> [Box<dyn UINode>; $n] {
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
let ($($T,)*) = self;
|
||||||
|
[$(Box::new($T),)*]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_node_arr!(1;A);
|
||||||
|
impl_node_arr!(2;A B);
|
||||||
|
impl_node_arr!(3;A B C);
|
||||||
|
impl_node_arr!(4;A B C D);
|
||||||
|
impl_node_arr!(5;A B C D E);
|
||||||
|
impl_node_arr!(6;A B C D E F);
|
||||||
|
impl_node_arr!(7;A B C D E F G);
|
||||||
|
impl_node_arr!(8;A B C D E F G H);
|
||||||
|
impl_node_arr!(9;A B C D E F G H I);
|
||||||
|
impl_node_arr!(10;A B C D E F G H I J);
|
||||||
|
impl_node_arr!(11;A B C D E F G H I J K);
|
||||||
|
impl_node_arr!(12;A B C D E F G H I J K L);
|
||||||
164
src/layout/node.rs
Normal file
164
src/layout/node.rs
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
primitive::{Axis, Painter, RoundedRectData, UIRegion},
|
||||||
|
NodeArray, UIColor, UINode,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct RoundedRect {
|
||||||
|
pub color: UIColor,
|
||||||
|
pub radius: f32,
|
||||||
|
pub thickness: f32,
|
||||||
|
pub inner_radius: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RoundedRect {
|
||||||
|
pub fn color(mut self, color: UIColor) -> Self {
|
||||||
|
self.color = color;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UINode for RoundedRect {
|
||||||
|
fn draw(&self, painter: &mut Painter) {
|
||||||
|
painter.write(RoundedRectData {
|
||||||
|
color: self.color,
|
||||||
|
radius: self.radius,
|
||||||
|
thickness: self.thickness,
|
||||||
|
inner_radius: self.inner_radius,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Span {
|
||||||
|
pub elements: Vec<(Range<f32>, Box<dyn UINode>)>,
|
||||||
|
pub axis: Axis,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UINode for Span {
|
||||||
|
fn draw(&self, painter: &mut Painter) {
|
||||||
|
for (span, child) in &self.elements {
|
||||||
|
let mut sub_region = UIRegion::full();
|
||||||
|
let view = sub_region.axis_mut(self.axis);
|
||||||
|
*view.top_left.anchor = span.start;
|
||||||
|
*view.bot_right.anchor = span.end;
|
||||||
|
painter.draw_within(child, sub_region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Span {
|
||||||
|
pub fn proportioned<const LEN: usize>(
|
||||||
|
axis: Axis,
|
||||||
|
ratios: [impl UINum; LEN],
|
||||||
|
elements: impl NodeArray<LEN>,
|
||||||
|
) -> Self {
|
||||||
|
let ratios = ratios.map(|r| r.to_f32());
|
||||||
|
let total: f32 = ratios.iter().sum();
|
||||||
|
let mut start = 0.0;
|
||||||
|
Self {
|
||||||
|
elements: elements
|
||||||
|
.to_arr()
|
||||||
|
.into_iter()
|
||||||
|
.zip(ratios)
|
||||||
|
.map(|(e, r)| {
|
||||||
|
let end = start + r / total;
|
||||||
|
let res = (start..end, e);
|
||||||
|
start = end;
|
||||||
|
res
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
axis,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Regioned<N: UINode> {
|
||||||
|
region: UIRegion,
|
||||||
|
inner: N,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: UINode> UINode for Regioned<N> {
|
||||||
|
fn draw(&self, painter: &mut Painter) {
|
||||||
|
painter.region.select(&self.region);
|
||||||
|
self.inner.draw(painter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Padding {
|
||||||
|
left: f32,
|
||||||
|
right: f32,
|
||||||
|
top: f32,
|
||||||
|
bottom: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Padding {
|
||||||
|
pub fn uniform(amt: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
left: amt,
|
||||||
|
right: amt,
|
||||||
|
top: amt,
|
||||||
|
bottom: amt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn region(&self) -> UIRegion {
|
||||||
|
let mut region = UIRegion::full();
|
||||||
|
region.top_left.offset.x += self.left;
|
||||||
|
region.top_left.offset.y += self.top;
|
||||||
|
region.bot_right.offset.x -= self.right;
|
||||||
|
region.bot_right.offset.y -= self.bottom;
|
||||||
|
region
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: UINum> From<T> for Padding {
|
||||||
|
fn from(amt: T) -> Self {
|
||||||
|
Self::uniform(amt.to_f32())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NodeUtil: Sized + UINode {
|
||||||
|
fn pad(self, padding: impl Into<Padding>) -> Regioned<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: UINode> NodeUtil for T {
|
||||||
|
fn pad(self, padding: impl Into<Padding>) -> Regioned<Self> {
|
||||||
|
Regioned {
|
||||||
|
region: padding.into().region(),
|
||||||
|
inner: self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NodeArrayUtil<const LEN: usize> {
|
||||||
|
fn proportioned(self, axis: Axis, ratios: [impl UINum; LEN]) -> Span;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: NodeArray<LEN>, const LEN: usize> NodeArrayUtil<LEN> for T {
|
||||||
|
fn proportioned(self, axis: Axis, ratios: [impl UINum; LEN]) -> Span {
|
||||||
|
Span::proportioned(axis, ratios, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait UINum {
|
||||||
|
fn to_f32(self) -> f32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UINum for f32 {
|
||||||
|
fn to_f32(self) -> f32 {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UINum for u32 {
|
||||||
|
fn to_f32(self) -> f32 {
|
||||||
|
self as f32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UINum for i32 {
|
||||||
|
fn to_f32(self) -> f32 {
|
||||||
|
self as f32
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/lib.rs
Normal file
10
src/lib.rs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#![feature(macro_metavar_expr_concat)]
|
||||||
|
#![feature(const_ops)]
|
||||||
|
#![feature(const_trait_impl)]
|
||||||
|
#![feature(const_from)]
|
||||||
|
|
||||||
|
mod layout;
|
||||||
|
mod render;
|
||||||
|
|
||||||
|
pub use layout::*;
|
||||||
|
pub use render::*;
|
||||||
35
src/main.rs
35
src/main.rs
@@ -1,36 +1,5 @@
|
|||||||
use std::sync::Arc;
|
mod testing;
|
||||||
|
|
||||||
use app::App;
|
|
||||||
use render::Renderer;
|
|
||||||
use winit::{event::WindowEvent, event_loop::ActiveEventLoop, window::Window};
|
|
||||||
|
|
||||||
mod app;
|
|
||||||
mod render;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::run();
|
testing::main();
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Client {
|
|
||||||
window: Arc<Window>,
|
|
||||||
renderer: Renderer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Client {
|
|
||||||
pub fn new(window: Arc<Window>) -> Self {
|
|
||||||
let renderer = Renderer::new(window.clone());
|
|
||||||
Self {
|
|
||||||
window,
|
|
||||||
renderer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) {
|
|
||||||
match event {
|
|
||||||
WindowEvent::CloseRequested => event_loop.exit(),
|
|
||||||
WindowEvent::RedrawRequested => self.renderer.draw(),
|
|
||||||
WindowEvent::Resized(size) => self.renderer.resize(&size),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
34
src/render/data.rs
Normal file
34
src/render/data.rs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
use crate::primitive::UIRegion;
|
||||||
|
use wgpu::VertexAttribute;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
pub struct PrimitiveInstance {
|
||||||
|
pub region: UIRegion,
|
||||||
|
pub ptr: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable, Default)]
|
||||||
|
pub struct WindowUniform {
|
||||||
|
pub width: f32,
|
||||||
|
pub height: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrimitiveInstance {
|
||||||
|
const ATTRIBS: [VertexAttribute; 5] = wgpu::vertex_attr_array![
|
||||||
|
0 => Float32x2,
|
||||||
|
1 => Float32x2,
|
||||||
|
2 => Float32x2,
|
||||||
|
3 => Float32x2,
|
||||||
|
4 => Uint32,
|
||||||
|
];
|
||||||
|
|
||||||
|
pub fn desc() -> wgpu::VertexBufferLayout<'static> {
|
||||||
|
wgpu::VertexBufferLayout {
|
||||||
|
array_stride: std::mem::size_of::<Self>() as wgpu::BufferAddress,
|
||||||
|
step_mode: wgpu::VertexStepMode::Instance,
|
||||||
|
attributes: &Self::ATTRIBS,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,199 +1,184 @@
|
|||||||
use std::sync::{
|
use crate::{
|
||||||
mpsc::{channel, Receiver},
|
render::{data::PrimitiveInstance, util::ArrBuf},
|
||||||
Arc,
|
UI,
|
||||||
};
|
};
|
||||||
|
use data::WindowUniform;
|
||||||
use notify::{
|
use wgpu::{
|
||||||
event::{CreateKind, ModifyKind},
|
util::{BufferInitDescriptor, DeviceExt},
|
||||||
EventKind, RecommendedWatcher, Watcher,
|
*,
|
||||||
};
|
};
|
||||||
use pollster::FutureExt;
|
use winit::dpi::PhysicalSize;
|
||||||
use primitive::{RoundedRect, UIPos};
|
|
||||||
use shape::ShapePipeline;
|
|
||||||
use wgpu::util::StagingBelt;
|
|
||||||
use winit::{dpi::PhysicalSize, window::Window};
|
|
||||||
|
|
||||||
|
mod data;
|
||||||
pub mod primitive;
|
pub mod primitive;
|
||||||
mod shape;
|
mod util;
|
||||||
|
|
||||||
pub const CLEAR_COLOR: wgpu::Color = wgpu::Color::BLACK;
|
const SHAPE_SHADER: &str = include_str!("./shader.wgsl");
|
||||||
|
|
||||||
pub struct Renderer {
|
pub struct UIRenderNode {
|
||||||
surface: wgpu::Surface<'static>,
|
bind_group_layout: BindGroupLayout,
|
||||||
device: wgpu::Device,
|
bind_group: BindGroup,
|
||||||
queue: wgpu::Queue,
|
pipeline: RenderPipeline,
|
||||||
config: wgpu::SurfaceConfiguration,
|
|
||||||
adapter: wgpu::Adapter,
|
window_buffer: Buffer,
|
||||||
encoder: wgpu::CommandEncoder,
|
instance: ArrBuf<PrimitiveInstance>,
|
||||||
staging_belt: StagingBelt,
|
data: ArrBuf<u32>,
|
||||||
shape_pipeline: ShapePipeline,
|
|
||||||
recv: Receiver<Vec<RoundedRect>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer {
|
impl UIRenderNode {
|
||||||
pub fn new(window: Arc<Window>) -> Self {
|
pub fn draw<'a>(&'a self, pass: &mut RenderPass<'a>) {
|
||||||
let size = window.inner_size();
|
pass.set_pipeline(&self.pipeline);
|
||||||
|
pass.set_bind_group(0, &self.bind_group, &[]);
|
||||||
|
if self.instance.len() != 0 {
|
||||||
|
pass.set_vertex_buffer(0, self.instance.buffer.slice(..));
|
||||||
|
pass.draw(0..4, 0..self.instance.len() as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let (send, recv) = channel();
|
pub fn update(&mut self, device: &Device, queue: &Queue, ui: &UI) {
|
||||||
|
let primitives = ui.to_primitives();
|
||||||
|
self.instance.update(device, queue, &primitives.instances);
|
||||||
|
self.data.update(device, queue, &primitives.data);
|
||||||
|
self.bind_group = Self::bind_group(
|
||||||
|
device,
|
||||||
|
&self.bind_group_layout,
|
||||||
|
&self.window_buffer,
|
||||||
|
&self.data.buffer,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("data/test.rhai");
|
pub fn resize(&mut self, size: &PhysicalSize<u32>, queue: &Queue) {
|
||||||
let w2 = window.clone();
|
let slice = &[WindowUniform {
|
||||||
std::thread::spawn(move || {
|
width: size.width as f32,
|
||||||
let (tx, rx) = channel();
|
height: size.height as f32,
|
||||||
|
}];
|
||||||
|
queue.write_buffer(&self.window_buffer, 0, bytemuck::cast_slice(slice));
|
||||||
|
}
|
||||||
|
|
||||||
let mut watcher = RecommendedWatcher::new(tx, Default::default()).unwrap();
|
pub fn new(device: &Device, config: &SurfaceConfiguration) -> Self {
|
||||||
watcher
|
let shader = device.create_shader_module(ShaderModuleDescriptor {
|
||||||
.watch("data".as_ref(), notify::RecursiveMode::Recursive)
|
label: Some("UI Shape Shader"),
|
||||||
.unwrap();
|
source: ShaderSource::Wgsl(SHAPE_SHADER.into()),
|
||||||
|
|
||||||
for res in rx {
|
|
||||||
let Ok(ev) = res else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
if !ev.paths.contains(&path) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if !matches!(
|
|
||||||
ev.kind,
|
|
||||||
EventKind::Create(CreateKind::File) | EventKind::Modify(ModifyKind::Data(_))
|
|
||||||
) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
println!("reloaded {ev:?}");
|
|
||||||
let mut engine = rhai::Engine::new();
|
|
||||||
engine.build_type::<RoundedRect>();
|
|
||||||
engine.register_type::<UIPos>();
|
|
||||||
engine.register_fn("anchor_offset", UIPos::anchor_offset);
|
|
||||||
engine.register_fn("rect", RoundedRect::default);
|
|
||||||
let Ok(code) = std::fs::read_to_string(&path) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
let rects = engine
|
|
||||||
.eval::<rhai::Array>(&code)
|
|
||||||
.map_err(|e| println!("{e:?}"))
|
|
||||||
.unwrap_or_default()
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|d| match rhai::Dynamic::try_cast(d.clone()) {
|
|
||||||
Some(v) => Some(v),
|
|
||||||
None => {
|
|
||||||
println!("{d:?} is not a RoundedRect");
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<RoundedRect>>();
|
|
||||||
send.send(rects).unwrap();
|
|
||||||
w2.request_redraw();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
|
let window_uniform = WindowUniform::default();
|
||||||
backends: wgpu::Backends::PRIMARY,
|
let window_buffer = device.create_buffer_init(&BufferInitDescriptor {
|
||||||
..Default::default()
|
label: Some("Camera Buffer"),
|
||||||
|
contents: bytemuck::cast_slice(&[window_uniform]),
|
||||||
|
usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
|
||||||
});
|
});
|
||||||
|
|
||||||
let surface = instance
|
let instance = ArrBuf::new(
|
||||||
.create_surface(window.clone())
|
device,
|
||||||
.expect("Could not create window surface!");
|
BufferUsages::VERTEX | BufferUsages::COPY_DST,
|
||||||
|
"instance",
|
||||||
|
);
|
||||||
|
let data = ArrBuf::new(
|
||||||
|
device,
|
||||||
|
BufferUsages::STORAGE | BufferUsages::COPY_DST,
|
||||||
|
"data",
|
||||||
|
);
|
||||||
|
|
||||||
let adapter = instance
|
let bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
||||||
.request_adapter(&wgpu::RequestAdapterOptions {
|
entries: &[
|
||||||
power_preference: wgpu::PowerPreference::default(),
|
BindGroupLayoutEntry {
|
||||||
compatible_surface: Some(&surface),
|
binding: 0,
|
||||||
force_fallback_adapter: false,
|
visibility: ShaderStages::VERTEX,
|
||||||
})
|
ty: BindingType::Buffer {
|
||||||
.block_on()
|
ty: BufferBindingType::Uniform,
|
||||||
.expect("Could not get adapter!");
|
has_dynamic_offset: false,
|
||||||
|
min_binding_size: None,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
BindGroupLayoutEntry {
|
||||||
|
binding: 1,
|
||||||
|
visibility: ShaderStages::FRAGMENT,
|
||||||
|
ty: BindingType::Buffer {
|
||||||
|
ty: BufferBindingType::Storage { read_only: true },
|
||||||
|
has_dynamic_offset: false,
|
||||||
|
min_binding_size: None,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
label: Some("camera_bind_group_layout"),
|
||||||
|
});
|
||||||
|
|
||||||
let (device, queue) = adapter
|
let bind_group = Self::bind_group(device, &bind_group_layout, &window_buffer, &data.buffer);
|
||||||
.request_device(&wgpu::DeviceDescriptor {
|
|
||||||
required_features: wgpu::Features::empty(),
|
|
||||||
required_limits: wgpu::Limits::default(),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.block_on()
|
|
||||||
.expect("Could not get device!");
|
|
||||||
|
|
||||||
let surface_caps = surface.get_capabilities(&adapter);
|
let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
|
||||||
let surface_format = surface_caps
|
label: Some("UI Shape Pipeline Layout"),
|
||||||
.formats
|
bind_group_layouts: &[&bind_group_layout],
|
||||||
.iter()
|
push_constant_ranges: &[],
|
||||||
.copied()
|
});
|
||||||
.find(|f| f.is_srgb())
|
let pipeline = device.create_render_pipeline(&RenderPipelineDescriptor {
|
||||||
.unwrap_or(surface_caps.formats[0]);
|
label: Some("UI Shape Pipeline"),
|
||||||
|
layout: Some(&pipeline_layout),
|
||||||
let config = wgpu::SurfaceConfiguration {
|
vertex: VertexState {
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
module: &shader,
|
||||||
format: surface_format,
|
entry_point: Some("vs_main"),
|
||||||
width: size.width,
|
buffers: &[PrimitiveInstance::desc()],
|
||||||
height: size.height,
|
compilation_options: Default::default(),
|
||||||
present_mode: surface_caps.present_modes[0],
|
},
|
||||||
alpha_mode: surface_caps.alpha_modes[0],
|
fragment: Some(FragmentState {
|
||||||
desired_maximum_frame_latency: 2,
|
module: &shader,
|
||||||
view_formats: vec![],
|
entry_point: Some("fs_main"),
|
||||||
};
|
targets: &[Some(ColorTargetState {
|
||||||
|
format: config.format,
|
||||||
surface.configure(&device, &config);
|
blend: Some(BlendState::ALPHA_BLENDING),
|
||||||
|
write_mask: ColorWrites::ALL,
|
||||||
let staging_belt = StagingBelt::new(4096 * 4);
|
})],
|
||||||
let encoder = Self::create_encoder(&device);
|
compilation_options: Default::default(),
|
||||||
|
}),
|
||||||
let shape_pipeline = ShapePipeline::new(&device, &config);
|
primitive: PrimitiveState {
|
||||||
|
topology: PrimitiveTopology::TriangleStrip,
|
||||||
|
strip_index_format: None,
|
||||||
|
front_face: FrontFace::Cw,
|
||||||
|
cull_mode: Some(Face::Back),
|
||||||
|
polygon_mode: PolygonMode::Fill,
|
||||||
|
unclipped_depth: false,
|
||||||
|
conservative: false,
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: MultisampleState {
|
||||||
|
count: 1,
|
||||||
|
mask: !0,
|
||||||
|
alpha_to_coverage_enabled: false,
|
||||||
|
},
|
||||||
|
multiview: None,
|
||||||
|
cache: None,
|
||||||
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
surface,
|
bind_group_layout,
|
||||||
device,
|
bind_group,
|
||||||
queue,
|
pipeline,
|
||||||
config,
|
window_buffer,
|
||||||
adapter,
|
instance,
|
||||||
encoder,
|
data,
|
||||||
staging_belt,
|
|
||||||
shape_pipeline,
|
|
||||||
recv,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_encoder(device: &wgpu::Device) -> wgpu::CommandEncoder {
|
pub fn bind_group(
|
||||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
device: &Device,
|
||||||
label: Some("Render Encoder"),
|
layout: &BindGroupLayout,
|
||||||
|
window_buffer: &Buffer,
|
||||||
|
data: &Buffer,
|
||||||
|
) -> BindGroup {
|
||||||
|
device.create_bind_group(&BindGroupDescriptor {
|
||||||
|
layout,
|
||||||
|
entries: &[
|
||||||
|
BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: window_buffer.as_entire_binding(),
|
||||||
|
},
|
||||||
|
BindGroupEntry {
|
||||||
|
binding: 1,
|
||||||
|
resource: data.as_entire_binding(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
label: Some("ui_bind_group"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&mut self) {
|
|
||||||
if let Some(rects) = self.recv.try_iter().last() {
|
|
||||||
self.shape_pipeline
|
|
||||||
.update(&self.device, &self.queue, &rects);
|
|
||||||
}
|
|
||||||
let output = self.surface.get_current_texture().unwrap();
|
|
||||||
let view = output
|
|
||||||
.texture
|
|
||||||
.create_view(&wgpu::TextureViewDescriptor::default());
|
|
||||||
|
|
||||||
let mut encoder = std::mem::replace(&mut self.encoder, Self::create_encoder(&self.device));
|
|
||||||
{
|
|
||||||
let render_pass = &mut encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
|
||||||
view: &view,
|
|
||||||
resolve_target: None,
|
|
||||||
ops: wgpu::Operations {
|
|
||||||
load: wgpu::LoadOp::Clear(CLEAR_COLOR),
|
|
||||||
store: wgpu::StoreOp::Store,
|
|
||||||
},
|
|
||||||
})],
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
self.shape_pipeline.draw(render_pass);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.queue.submit(std::iter::once(encoder.finish()));
|
|
||||||
self.staging_belt.finish();
|
|
||||||
output.present();
|
|
||||||
self.staging_belt.recall();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resize(&mut self, size: &PhysicalSize<u32>) {
|
|
||||||
self.config.width = size.width;
|
|
||||||
self.config.height = size.height;
|
|
||||||
self.surface.configure(&self.device, &self.config);
|
|
||||||
self.shape_pipeline.resize(size, &self.queue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
use glam::Vec2;
|
|
||||||
use rhai::{CustomType, TypeBuilder};
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable, CustomType)]
|
|
||||||
pub struct RoundedRect {
|
|
||||||
pub top_left: UIPos,
|
|
||||||
pub bottom_right: UIPos,
|
|
||||||
pub colors: [[f32; 4]; 4],
|
|
||||||
pub radius: f32,
|
|
||||||
pub inner_radius: f32,
|
|
||||||
pub thickness: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for RoundedRect {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
top_left: Default::default(),
|
|
||||||
bottom_right: Default::default(),
|
|
||||||
colors: [
|
|
||||||
[1.0, 0.0, 0.0, 1.0],
|
|
||||||
[0.0, 1.0, 0.0, 1.0],
|
|
||||||
[0.0, 0.0, 1.0, 1.0],
|
|
||||||
[1.0, 1.0, 1.0, 1.0],
|
|
||||||
],
|
|
||||||
radius: Default::default(),
|
|
||||||
inner_radius: Default::default(),
|
|
||||||
thickness: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Clone)]
|
|
||||||
pub struct Text {
|
|
||||||
pub content: String,
|
|
||||||
pub align: Align,
|
|
||||||
pub pos: Vec2,
|
|
||||||
pub bounds: (f32, f32),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Text {
|
|
||||||
pub fn empty() -> Self {
|
|
||||||
Self {
|
|
||||||
content: String::new(),
|
|
||||||
align: Align::Left,
|
|
||||||
pos: Vec2::default(),
|
|
||||||
bounds: (0.0, 0.0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable, Default)]
|
|
||||||
pub struct UIPos {
|
|
||||||
pub anchor: Vec2,
|
|
||||||
pub offset: Vec2,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UIPos {
|
|
||||||
pub fn anchor_offset(anchor_x: f32, anchor_y: f32, offset_x: f32, offset_y: f32) -> Self {
|
|
||||||
Self {
|
|
||||||
anchor: Vec2::new(anchor_x, anchor_y),
|
|
||||||
offset: Vec2::new(offset_x, offset_y),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Clone)]
|
|
||||||
pub enum Align {
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Center,
|
|
||||||
}
|
|
||||||
47
src/render/primitive/color.rs
Normal file
47
src/render/primitive/color.rs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#![allow(clippy::multiple_bound_locations)]
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, bytemuck::Zeroable)]
|
||||||
|
pub struct Color<T: ColorNum> {
|
||||||
|
r: T,
|
||||||
|
g: T,
|
||||||
|
b: T,
|
||||||
|
a: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ColorNum> Color<T> {
|
||||||
|
pub const BLACK: Self = Self::rgb(T::MIN, T::MIN, T::MIN);
|
||||||
|
pub const WHITE: Self = Self::rgb(T::MAX, T::MAX, T::MAX);
|
||||||
|
|
||||||
|
pub const RED: Self = Self::rgb(T::MAX, T::MIN, T::MIN);
|
||||||
|
pub const ORANGE: Self = Self::rgb(T::MAX, T::MID, T::MIN);
|
||||||
|
pub const YELLOW: Self = Self::rgb(T::MAX, T::MAX, T::MIN);
|
||||||
|
pub const LIME: Self = Self::rgb(T::MID, T::MAX, T::MIN);
|
||||||
|
pub const GREEN: Self = Self::rgb(T::MIN, T::MAX, T::MIN);
|
||||||
|
pub const CYAN: Self = Self::rgb(T::MIN, T::MAX, T::MAX);
|
||||||
|
pub const BLUE: Self = Self::rgb(T::MIN, T::MIN, T::MAX);
|
||||||
|
pub const MAGENTA: Self = Self::rgb(T::MAX, T::MIN, T::MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ColorNum> Color<T> {
|
||||||
|
pub const fn new(r: T, g: T, b: T, a: T) -> Self {
|
||||||
|
Self { r, g, b, a }
|
||||||
|
}
|
||||||
|
pub const fn rgb(r: T, g: T, b: T) -> Self {
|
||||||
|
Self { r, g, b, a: T::MAX }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ColorNum {
|
||||||
|
const MIN: Self;
|
||||||
|
const MID: Self;
|
||||||
|
const MAX: Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColorNum for u8 {
|
||||||
|
const MIN: Self = u8::MIN;
|
||||||
|
const MID: Self = u8::MAX / 2;
|
||||||
|
const MAX: Self = u8::MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl bytemuck::Pod for Color<u8> {}
|
||||||
14
src/render/primitive/def.rs
Normal file
14
src/render/primitive/def.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
use crate::primitive::{Color, PrimitiveData};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
pub struct RoundedRectData {
|
||||||
|
pub color: Color<u8>,
|
||||||
|
pub radius: f32,
|
||||||
|
pub thickness: f32,
|
||||||
|
pub inner_radius: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrimitiveData for RoundedRectData {
|
||||||
|
const DISCRIM: u32 = 0;
|
||||||
|
}
|
||||||
97
src/render/primitive/format.rs
Normal file
97
src/render/primitive/format.rs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
use crate::primitive::{point::point, Point};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable, Default)]
|
||||||
|
pub struct UIPos {
|
||||||
|
pub anchor: Point,
|
||||||
|
pub offset: Point,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UIPos {
|
||||||
|
pub const fn anchor_offset(anchor_x: f32, anchor_y: f32, offset_x: f32, offset_y: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
anchor: point(anchor_x, anchor_y),
|
||||||
|
offset: point(offset_x, offset_y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn top_left() -> Self {
|
||||||
|
Self::anchor_offset(0.0, 0.0, 0.0, 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn bottom_right() -> Self {
|
||||||
|
Self::anchor_offset(1.0, 1.0, 0.0, 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn within(&self, region: &UIRegion) -> UIPos {
|
||||||
|
let range = region.bot_right.anchor - region.top_left.anchor;
|
||||||
|
let region_offset = region
|
||||||
|
.top_left
|
||||||
|
.offset
|
||||||
|
.lerp(region.bot_right.offset, self.anchor);
|
||||||
|
UIPos {
|
||||||
|
anchor: region.top_left.anchor + self.anchor * range,
|
||||||
|
offset: self.offset + region_offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn axis_mut(&mut self, axis: Axis) -> UIPosAxisView<'_> {
|
||||||
|
match axis {
|
||||||
|
Axis::X => UIPosAxisView {
|
||||||
|
anchor: &mut self.anchor.x,
|
||||||
|
offset: &mut self.offset.x,
|
||||||
|
},
|
||||||
|
Axis::Y => UIPosAxisView {
|
||||||
|
anchor: &mut self.anchor.y,
|
||||||
|
offset: &mut self.offset.y,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UIPosAxisView<'a> {
|
||||||
|
pub anchor: &'a mut f32,
|
||||||
|
pub offset: &'a mut f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
pub struct UIRegion {
|
||||||
|
pub top_left: UIPos,
|
||||||
|
pub bot_right: UIPos,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UIRegion {
|
||||||
|
pub const fn full() -> Self {
|
||||||
|
Self {
|
||||||
|
top_left: UIPos::top_left(),
|
||||||
|
bot_right: UIPos::bottom_right(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn within(&self, parent: &Self) -> Self {
|
||||||
|
Self {
|
||||||
|
top_left: self.top_left.within(parent),
|
||||||
|
bot_right: self.bot_right.within(parent),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn select(&mut self, inner: &Self) {
|
||||||
|
*self = inner.within(self);
|
||||||
|
}
|
||||||
|
pub fn axis_mut(&mut self, axis: Axis) -> UIRegionAxisView<'_> {
|
||||||
|
UIRegionAxisView {
|
||||||
|
top_left: self.top_left.axis_mut(axis),
|
||||||
|
bot_right: self.bot_right.axis_mut(axis),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UIRegionAxisView<'a> {
|
||||||
|
pub top_left: UIPosAxisView<'a>,
|
||||||
|
pub bot_right: UIPosAxisView<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum Axis {
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
}
|
||||||
50
src/render/primitive/mod.rs
Normal file
50
src/render/primitive/mod.rs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
mod color;
|
||||||
|
mod def;
|
||||||
|
mod format;
|
||||||
|
mod point;
|
||||||
|
|
||||||
|
pub use color::*;
|
||||||
|
pub use def::*;
|
||||||
|
pub use format::*;
|
||||||
|
pub use point::*;
|
||||||
|
|
||||||
|
use crate::{render::data::PrimitiveInstance, UINode};
|
||||||
|
use bytemuck::Pod;
|
||||||
|
|
||||||
|
pub struct Painter {
|
||||||
|
pub region: UIRegion,
|
||||||
|
pub instances: Vec<PrimitiveInstance>,
|
||||||
|
pub data: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Painter {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
region: UIRegion::full(),
|
||||||
|
instances: Default::default(),
|
||||||
|
data: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// NOTE: Self must have at least u32 alignment
|
||||||
|
pub trait PrimitiveData: Pod {
|
||||||
|
const DISCRIM: u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Painter {
|
||||||
|
pub fn write<D: PrimitiveData>(&mut self, data: D) {
|
||||||
|
let ptr = self.data.len() as u32;
|
||||||
|
let region = self.region;
|
||||||
|
self.instances.push(PrimitiveInstance { region, ptr });
|
||||||
|
self.data.push(D::DISCRIM);
|
||||||
|
self.data
|
||||||
|
.extend_from_slice(bytemuck::cast_slice::<_, u32>(&[data]));
|
||||||
|
}
|
||||||
|
pub fn draw_within(&mut self, node: &impl UINode, region: UIRegion) {
|
||||||
|
let old = self.region;
|
||||||
|
self.region.select(®ion);
|
||||||
|
node.draw(self);
|
||||||
|
self.region = old;
|
||||||
|
}
|
||||||
|
}
|
||||||
84
src/render/primitive/point.rs
Normal file
84
src/render/primitive/point.rs
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
use std::ops::*;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, PartialEq, Default, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
pub struct Point {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn point(x: f32, y: f32) -> Point {
|
||||||
|
Point::new(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Point {
|
||||||
|
pub const fn new(x: f32, y: f32) -> Self {
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn lerp(self, to: Self, amt: impl const Into<Self>) -> Self {
|
||||||
|
let amt = amt.into();
|
||||||
|
Self {
|
||||||
|
x: lerp(self.x, to.x, amt.x),
|
||||||
|
y: lerp(self.y, to.y, amt.y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn lerp(x: f32, y: f32, amt: f32) -> f32 {
|
||||||
|
(1.0 - amt) * x + y * amt
|
||||||
|
}
|
||||||
|
|
||||||
|
impl const From<f32> for Point {
|
||||||
|
fn from(v: f32) -> Self {
|
||||||
|
Self { x: v, y: v }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_op_inner {
|
||||||
|
($op:ident $fn:ident $opa:ident $fna:ident) => {
|
||||||
|
impl const $op for Point {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn $fn(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x.$fn(rhs.x),
|
||||||
|
y: self.y.$fn(rhs.y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl $opa for Point {
|
||||||
|
fn $fna(&mut self, rhs: Self) {
|
||||||
|
self.x.$fna(rhs.x);
|
||||||
|
self.y.$fna(rhs.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl const $op<f32> for Point {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn $fn(self, rhs: f32) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x.$fn(rhs),
|
||||||
|
y: self.y.$fn(rhs),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl $opa<f32> for Point {
|
||||||
|
fn $fna(&mut self, rhs: f32) {
|
||||||
|
self.x.$fna(rhs);
|
||||||
|
self.y.$fna(rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_op {
|
||||||
|
($op:ident $fn:ident) => {
|
||||||
|
impl_op_inner!($op $fn ${concat($op,Assign)} ${concat($fn,_assign)});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_op!(Add add);
|
||||||
|
impl_op!(Sub sub);
|
||||||
|
impl_op!(Mul mul);
|
||||||
|
impl_op!(Div div);
|
||||||
110
src/render/shader.wgsl
Normal file
110
src/render/shader.wgsl
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
@group(0) @binding(0)
|
||||||
|
var<uniform> window: WindowUniform;
|
||||||
|
@group(0) @binding(1)
|
||||||
|
var<storage> data: array<u32>;
|
||||||
|
|
||||||
|
struct WindowUniform {
|
||||||
|
dim: vec2<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InstanceInput {
|
||||||
|
@location(0) top_left_anchor: vec2<f32>,
|
||||||
|
@location(1) top_left_offset: vec2<f32>,
|
||||||
|
@location(2) bottom_right_anchor: vec2<f32>,
|
||||||
|
@location(3) bottom_right_offset: vec2<f32>,
|
||||||
|
@location(4) pointer: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RoundedRect {
|
||||||
|
color: u32,
|
||||||
|
radius: f32,
|
||||||
|
thickness: f32,
|
||||||
|
inner_radius: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VertexOutput {
|
||||||
|
@location(0) pointer: u32,
|
||||||
|
@location(1) top_left: vec2<f32>,
|
||||||
|
@location(2) bot_right: vec2<f32>,
|
||||||
|
@builtin(position) clip_position: vec4<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Region {
|
||||||
|
pos: vec2<f32>,
|
||||||
|
top_left: vec2<f32>,
|
||||||
|
bot_right: vec2<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn vs_main(
|
||||||
|
@builtin(vertex_index) vi: u32,
|
||||||
|
in: InstanceInput,
|
||||||
|
) -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
|
||||||
|
let top_left = in.top_left_anchor * window.dim + in.top_left_offset;
|
||||||
|
let bot_right = in.bottom_right_anchor * window.dim + in.bottom_right_offset;
|
||||||
|
let size = bot_right - top_left;
|
||||||
|
|
||||||
|
var pos = top_left + vec2<f32>(
|
||||||
|
f32(vi % 2u),
|
||||||
|
f32(vi / 2u)
|
||||||
|
) * size;
|
||||||
|
pos = pos / window.dim * 2.0 - 1.0;
|
||||||
|
out.clip_position = vec4<f32>(pos.x, -pos.y, 0.0, 1.0);
|
||||||
|
out.pointer = in.pointer;
|
||||||
|
out.top_left = top_left;
|
||||||
|
out.bot_right = bot_right;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fs_main(
|
||||||
|
in: VertexOutput
|
||||||
|
) -> @location(0) vec4<f32> {
|
||||||
|
let pos = in.clip_position.xy;
|
||||||
|
let ty = data[in.pointer];
|
||||||
|
let dp = in.pointer + 1u;
|
||||||
|
let region = Region(pos, in.top_left, in.bot_right);
|
||||||
|
switch ty {
|
||||||
|
case 0u: {
|
||||||
|
return draw_rounded_rect(region, RoundedRect(
|
||||||
|
data[dp + 0u],
|
||||||
|
bitcast<f32>(data[dp + 1u]),
|
||||||
|
bitcast<f32>(data[dp + 2u]),
|
||||||
|
bitcast<f32>(data[dp + 3u]),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
default: {}
|
||||||
|
}
|
||||||
|
return vec4(1.0, 0.0, 1.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_rounded_rect(region: Region, rect: RoundedRect) -> vec4<f32> {
|
||||||
|
var color = unpack4x8unorm(rect.color);
|
||||||
|
|
||||||
|
let edge = 0.5;
|
||||||
|
|
||||||
|
let size = region.bot_right - region.top_left;
|
||||||
|
let corner = size / 2.0;
|
||||||
|
let center = region.top_left + corner;
|
||||||
|
|
||||||
|
let dist = distance_from_rect(region.pos, center, corner, rect.radius);
|
||||||
|
color.a *= 1.0 - smoothstep(-min(edge, rect.radius), edge, dist);
|
||||||
|
|
||||||
|
if rect.thickness > 0.0 {
|
||||||
|
let dist2 = distance_from_rect(region.pos, center, corner - rect.thickness, rect.inner_radius);
|
||||||
|
color.a *= smoothstep(-min(edge, rect.inner_radius), edge, dist2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn distance_from_rect(pixel_pos: vec2<f32>, rect_center: vec2<f32>, rect_corner: vec2<f32>, radius: f32) -> f32 {
|
||||||
|
// vec from center to pixel
|
||||||
|
let p = pixel_pos - rect_center;
|
||||||
|
// vec from inner rect corner to pixel
|
||||||
|
let q = abs(p) - (rect_corner - radius);
|
||||||
|
return length(max(q, vec2<f32>(0.0, 0.0))) - radius;
|
||||||
|
}
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
use wgpu::{RenderPass, VertexAttribute};
|
|
||||||
|
|
||||||
use crate::render::primitive::RoundedRect;
|
|
||||||
|
|
||||||
pub struct RoundedRectBuffer {
|
|
||||||
buffer: wgpu::Buffer,
|
|
||||||
len: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable, Default)]
|
|
||||||
pub struct WindowUniform {
|
|
||||||
pub width: f32,
|
|
||||||
pub height: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl RoundedRectBuffer {
|
|
||||||
pub fn new(device: &wgpu::Device) -> Self {
|
|
||||||
Self {
|
|
||||||
buffer: Self::init_buf(device, 0),
|
|
||||||
len: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn update(
|
|
||||||
&mut self,
|
|
||||||
device: &wgpu::Device,
|
|
||||||
queue: &wgpu::Queue,
|
|
||||||
rects: &[RoundedRect],
|
|
||||||
) {
|
|
||||||
if self.len != rects.len() {
|
|
||||||
self.len = rects.len();
|
|
||||||
self.buffer = Self::init_buf(device, std::mem::size_of_val(rects));
|
|
||||||
}
|
|
||||||
queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(rects));
|
|
||||||
}
|
|
||||||
fn init_buf(device: &wgpu::Device, size: usize) -> wgpu::Buffer {
|
|
||||||
device.create_buffer(&wgpu::BufferDescriptor {
|
|
||||||
label: Some("Instance Buffer"),
|
|
||||||
size: size as u64,
|
|
||||||
mapped_at_creation: false,
|
|
||||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.len
|
|
||||||
}
|
|
||||||
pub fn set_in<'a>(&'a self, pass: &mut RenderPass<'a>) {
|
|
||||||
pass.set_vertex_buffer(0, self.buffer.slice(..));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RoundedRect {
|
|
||||||
const ATTRIBS: [VertexAttribute; 11] = wgpu::vertex_attr_array![
|
|
||||||
0 => Float32x2,
|
|
||||||
1 => Float32x2,
|
|
||||||
2 => Float32x2,
|
|
||||||
3 => Float32x2,
|
|
||||||
4 => Float32x4,
|
|
||||||
5 => Float32x4,
|
|
||||||
6 => Float32x4,
|
|
||||||
7 => Float32x4,
|
|
||||||
8 => Float32,
|
|
||||||
9 => Float32,
|
|
||||||
10 => Float32,
|
|
||||||
];
|
|
||||||
pub fn desc() -> wgpu::VertexBufferLayout<'static> {
|
|
||||||
wgpu::VertexBufferLayout {
|
|
||||||
array_stride: std::mem::size_of::<RoundedRect>() as wgpu::BufferAddress,
|
|
||||||
step_mode: wgpu::VertexStepMode::Instance,
|
|
||||||
attributes: &Self::ATTRIBS,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
use wgpu::{
|
|
||||||
util::{BufferInitDescriptor, DeviceExt},
|
|
||||||
BufferUsages,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::render::primitive::RoundedRect;
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
data::{RoundedRectBuffer, WindowUniform},
|
|
||||||
ShapeBuffers, ShapePipeline, SHAPE_SHADER,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl ShapePipeline {
|
|
||||||
pub fn new(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration) -> Self {
|
|
||||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
|
||||||
label: Some("UI Shape Shader"),
|
|
||||||
source: wgpu::ShaderSource::Wgsl(SHAPE_SHADER.into()),
|
|
||||||
});
|
|
||||||
|
|
||||||
let window_uniform = WindowUniform::default();
|
|
||||||
let window_buffer = device.create_buffer_init(&BufferInitDescriptor {
|
|
||||||
label: Some("Camera Buffer"),
|
|
||||||
contents: bytemuck::cast_slice(&[window_uniform]),
|
|
||||||
usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
|
|
||||||
});
|
|
||||||
|
|
||||||
let instance_buffer = RoundedRectBuffer::new(device);
|
|
||||||
|
|
||||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
||||||
entries: &[wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 0,
|
|
||||||
visibility: wgpu::ShaderStages::VERTEX,
|
|
||||||
ty: wgpu::BindingType::Buffer {
|
|
||||||
ty: wgpu::BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: None,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
}],
|
|
||||||
label: Some("camera_bind_group_layout"),
|
|
||||||
});
|
|
||||||
|
|
||||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
|
||||||
layout: &bind_group_layout,
|
|
||||||
entries: &[wgpu::BindGroupEntry {
|
|
||||||
binding: 0,
|
|
||||||
resource: window_buffer.as_entire_binding(),
|
|
||||||
}],
|
|
||||||
label: Some("camera_bind_group"),
|
|
||||||
});
|
|
||||||
|
|
||||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
|
||||||
label: Some("UI Shape Pipeline Layout"),
|
|
||||||
bind_group_layouts: &[&bind_group_layout],
|
|
||||||
push_constant_ranges: &[],
|
|
||||||
});
|
|
||||||
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
|
||||||
label: Some("UI Shape Pipeline"),
|
|
||||||
layout: Some(&pipeline_layout),
|
|
||||||
vertex: wgpu::VertexState {
|
|
||||||
module: &shader,
|
|
||||||
entry_point: Some("vs_main"),
|
|
||||||
buffers: &[RoundedRect::desc()],
|
|
||||||
compilation_options: Default::default(),
|
|
||||||
},
|
|
||||||
fragment: Some(wgpu::FragmentState {
|
|
||||||
module: &shader,
|
|
||||||
entry_point: Some("fs_main"),
|
|
||||||
targets: &[Some(wgpu::ColorTargetState {
|
|
||||||
format: config.format,
|
|
||||||
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
|
|
||||||
write_mask: wgpu::ColorWrites::ALL,
|
|
||||||
})],
|
|
||||||
compilation_options: Default::default(),
|
|
||||||
}),
|
|
||||||
primitive: wgpu::PrimitiveState {
|
|
||||||
topology: wgpu::PrimitiveTopology::TriangleStrip,
|
|
||||||
strip_index_format: None,
|
|
||||||
front_face: wgpu::FrontFace::Cw,
|
|
||||||
cull_mode: Some(wgpu::Face::Back),
|
|
||||||
polygon_mode: wgpu::PolygonMode::Fill,
|
|
||||||
unclipped_depth: false,
|
|
||||||
conservative: false,
|
|
||||||
},
|
|
||||||
depth_stencil: None,
|
|
||||||
multisample: wgpu::MultisampleState {
|
|
||||||
count: 1,
|
|
||||||
mask: !0,
|
|
||||||
alpha_to_coverage_enabled: false,
|
|
||||||
},
|
|
||||||
multiview: None,
|
|
||||||
cache: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
let buffers = ShapeBuffers {
|
|
||||||
window: window_buffer,
|
|
||||||
instance: instance_buffer,
|
|
||||||
};
|
|
||||||
|
|
||||||
Self {
|
|
||||||
bind_group,
|
|
||||||
pipeline,
|
|
||||||
buffers,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
use crate::render::primitive::RoundedRect;
|
|
||||||
use data::{RoundedRectBuffer, WindowUniform};
|
|
||||||
use wgpu::{BindGroup, Buffer, RenderPass, RenderPipeline};
|
|
||||||
use winit::dpi::PhysicalSize;
|
|
||||||
|
|
||||||
mod data;
|
|
||||||
mod layout;
|
|
||||||
|
|
||||||
pub const SHAPE_SHADER: &str = include_str!("./shader.wgsl");
|
|
||||||
|
|
||||||
pub struct ShapeBuffers {
|
|
||||||
pub window: Buffer,
|
|
||||||
pub instance: RoundedRectBuffer,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ShapePipeline {
|
|
||||||
pub bind_group: BindGroup,
|
|
||||||
pub pipeline: RenderPipeline,
|
|
||||||
|
|
||||||
pub buffers: ShapeBuffers,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ShapePipeline {
|
|
||||||
pub fn draw<'a>(&'a self, pass: &mut RenderPass<'a>) {
|
|
||||||
pass.set_pipeline(&self.pipeline);
|
|
||||||
pass.set_bind_group(0, &self.bind_group, &[]);
|
|
||||||
if self.buffers.instance.len() != 0 {
|
|
||||||
self.buffers.instance.set_in(pass);
|
|
||||||
pass.draw(0..4, 0..self.buffers.instance.len() as u32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, rects: &[RoundedRect]) {
|
|
||||||
self.buffers.instance.update(device, queue, rects);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resize(&mut self, size: &PhysicalSize<u32>, queue: &wgpu::Queue) {
|
|
||||||
let slice = &[WindowUniform {
|
|
||||||
width: size.width as f32,
|
|
||||||
height: size.height as f32,
|
|
||||||
}];
|
|
||||||
queue.write_buffer(&self.buffers.window, 0, bytemuck::cast_slice(slice));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
|
|
||||||
// vertex shader
|
|
||||||
|
|
||||||
struct VertexOutput {
|
|
||||||
@location(0) color: vec4<f32>,
|
|
||||||
@location(1) center: vec2<f32>,
|
|
||||||
@location(2) corner: vec2<f32>,
|
|
||||||
@location(3) radius: f32,
|
|
||||||
@location(4) inner_radius: f32,
|
|
||||||
@location(5) thickness: f32,
|
|
||||||
@builtin(position) clip_position: vec4<f32>,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WindowUniform {
|
|
||||||
dim: vec2<f32>,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct InstanceInput {
|
|
||||||
@location(0) top_left_anchor: vec2<f32>,
|
|
||||||
@location(1) top_left_offset: vec2<f32>,
|
|
||||||
@location(2) bottom_right_anchor: vec2<f32>,
|
|
||||||
@location(3) bottom_right_offset: vec2<f32>,
|
|
||||||
@location(4) top_right_color: vec4<f32>,
|
|
||||||
@location(5) top_left_color: vec4<f32>,
|
|
||||||
@location(6) bottom_right_color: vec4<f32>,
|
|
||||||
@location(7) bottom_left_color: vec4<f32>,
|
|
||||||
@location(8) radius: f32,
|
|
||||||
@location(9) inner_radius: f32,
|
|
||||||
@location(10) thickness: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
@group(0) @binding(0)
|
|
||||||
var<uniform> window: WindowUniform;
|
|
||||||
|
|
||||||
@vertex
|
|
||||||
fn vs_main(
|
|
||||||
@builtin(vertex_index) vi: u32,
|
|
||||||
in: InstanceInput,
|
|
||||||
) -> VertexOutput {
|
|
||||||
var out: VertexOutput;
|
|
||||||
|
|
||||||
let top_left = in.top_left_anchor * window.dim + in.top_left_offset;
|
|
||||||
let bottom_right = in.bottom_right_anchor * window.dim + in.bottom_right_offset;
|
|
||||||
let size = bottom_right - top_left;
|
|
||||||
|
|
||||||
var pos = top_left + vec2<f32>(
|
|
||||||
f32(vi % 2u),
|
|
||||||
f32(vi / 2u)
|
|
||||||
) * size;
|
|
||||||
pos = pos / window.dim * 2.0 - 1.0;
|
|
||||||
out.clip_position = vec4<f32>(pos.x, -pos.y, 0.0, 1.0);
|
|
||||||
|
|
||||||
if vi == 0u {
|
|
||||||
out.color = in.top_left_color;
|
|
||||||
} else if vi == 1u {
|
|
||||||
out.color = in.top_right_color;
|
|
||||||
} else if vi == 2u {
|
|
||||||
out.color = in.bottom_left_color;
|
|
||||||
} else if vi == 3u {
|
|
||||||
out.color = in.bottom_right_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
out.corner = size / 2.0;
|
|
||||||
out.center = top_left + out.corner;
|
|
||||||
out.radius = in.radius;
|
|
||||||
out.inner_radius = in.inner_radius;
|
|
||||||
out.thickness = in.thickness;
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@fragment
|
|
||||||
fn fs_main(
|
|
||||||
in: VertexOutput
|
|
||||||
) -> @location(0) vec4<f32> {
|
|
||||||
var color = in.color;
|
|
||||||
|
|
||||||
let edge = 0.5;
|
|
||||||
|
|
||||||
let dist = distance_from_rect(in.clip_position.xy, in.center, in.corner, in.radius);
|
|
||||||
color.a *= 1.0 - smoothstep(-min(edge, in.radius), edge, dist);
|
|
||||||
|
|
||||||
if in.thickness > 0.0 {
|
|
||||||
let dist2 = distance_from_rect(in.clip_position.xy, in.center, in.corner - in.thickness, in.inner_radius);
|
|
||||||
color.a *= smoothstep(-min(edge, in.inner_radius), edge, dist2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn distance_from_rect(pixel_pos: vec2<f32>, rect_center: vec2<f32>, rect_corner: vec2<f32>, radius: f32) -> f32 {
|
|
||||||
// vec from center to pixel
|
|
||||||
let p = pixel_pos - rect_center;
|
|
||||||
// vec from inner rect corner to pixel
|
|
||||||
let q = abs(p) - (rect_corner - radius);
|
|
||||||
return length(max(q, vec2<f32>(0.0, 0.0))) - radius;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
pub mod pipeline;
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
use glyphon::{
|
|
||||||
Attrs, Buffer, Color, Family, FontSystem, Metrics, Resolution, Shaping, SwashCache, TextArea,
|
|
||||||
TextAtlas, TextBounds, TextRenderer,
|
|
||||||
};
|
|
||||||
use wgpu::{MultisampleState, RenderPass};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
client::ui::element::Align,
|
|
||||||
render::{primitive::TextPrimitive, surface::RenderSurface},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct TextPipeline {
|
|
||||||
pub renderer: glyphon::TextRenderer,
|
|
||||||
pub font_system: glyphon::FontSystem,
|
|
||||||
pub atlas: glyphon::TextAtlas,
|
|
||||||
pub cache: glyphon::SwashCache,
|
|
||||||
pub text_buffers: Vec<glyphon::Buffer>,
|
|
||||||
pub old_text: Vec<TextPrimitive>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TextPipeline {
|
|
||||||
pub fn new(surface: &RenderSurface) -> Self {
|
|
||||||
let RenderSurface {
|
|
||||||
device,
|
|
||||||
config,
|
|
||||||
queue,
|
|
||||||
..
|
|
||||||
} = surface;
|
|
||||||
|
|
||||||
let font_system = FontSystem::new();
|
|
||||||
let cache = SwashCache::new();
|
|
||||||
let mut atlas = TextAtlas::new(&device, &queue, config.format);
|
|
||||||
let renderer = TextRenderer::new(&mut atlas, &device, MultisampleState::default(), None);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
font_system,
|
|
||||||
atlas,
|
|
||||||
cache,
|
|
||||||
renderer,
|
|
||||||
text_buffers: Vec::new(),
|
|
||||||
old_text: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw<'a>(&'a self, pass: &mut RenderPass<'a>) {
|
|
||||||
self.renderer.render(&self.atlas, pass).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update(&mut self, surface: &RenderSurface, text: &[TextPrimitive]) {
|
|
||||||
let buffers = &mut self.text_buffers;
|
|
||||||
if buffers.len() < text.len() {
|
|
||||||
self.old_text.resize(text.len(), TextPrimitive::empty());
|
|
||||||
buffers.resize_with(text.len(), || {
|
|
||||||
Buffer::new(&mut self.font_system, Metrics::new(20.0, 25.0))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
for ((buffer, text), old) in buffers.iter_mut().zip(text).zip(&mut self.old_text) {
|
|
||||||
if text != old {
|
|
||||||
*old = text.clone();
|
|
||||||
buffer.set_size(&mut self.font_system, f32::MAX, f32::MAX);
|
|
||||||
buffer.set_text(
|
|
||||||
&mut self.font_system,
|
|
||||||
&text.content,
|
|
||||||
Attrs::new().family(Family::SansSerif),
|
|
||||||
Shaping::Basic,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let color = Color::rgb(255, 255, 255);
|
|
||||||
let areas = buffers.iter().zip(text).map(|(buffer, text)| {
|
|
||||||
let width = measure(&buffer).0;
|
|
||||||
let mut left = text.pos.x
|
|
||||||
- match text.align {
|
|
||||||
Align::Left => 0.0,
|
|
||||||
Align::Center => width / 2.0,
|
|
||||||
Align::Right => width,
|
|
||||||
};
|
|
||||||
let x = text.pos.x;
|
|
||||||
let w = text.bounds.0;
|
|
||||||
let x_bounds = match text.align {
|
|
||||||
Align::Left => (x, x + w),
|
|
||||||
Align::Center => (x - w / 2.0, x + w / 2.0),
|
|
||||||
Align::Right => (x - w, x),
|
|
||||||
};
|
|
||||||
if left < x_bounds.0 {
|
|
||||||
left = x_bounds.0;
|
|
||||||
}
|
|
||||||
TextArea {
|
|
||||||
buffer: &buffer,
|
|
||||||
left,
|
|
||||||
top: text.pos.y,
|
|
||||||
scale: 1.0,
|
|
||||||
bounds: TextBounds {
|
|
||||||
left: x_bounds.0 as i32,
|
|
||||||
top: text.pos.y as i32,
|
|
||||||
right: x_bounds.1 as i32,
|
|
||||||
bottom: (text.pos.y + text.bounds.1) as i32,
|
|
||||||
},
|
|
||||||
default_color: color,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
self.renderer
|
|
||||||
.prepare(
|
|
||||||
&surface.device,
|
|
||||||
&surface.queue,
|
|
||||||
&mut self.font_system,
|
|
||||||
&mut self.atlas,
|
|
||||||
Resolution {
|
|
||||||
width: surface.config.width,
|
|
||||||
height: surface.config.height,
|
|
||||||
},
|
|
||||||
areas,
|
|
||||||
&mut self.cache,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn measure(buffer: &glyphon::Buffer) -> (f32, f32) {
|
|
||||||
let (width, total_lines) = buffer
|
|
||||||
.layout_runs()
|
|
||||||
.fold((0.0, 0usize), |(width, total_lines), run| {
|
|
||||||
(run.line_w.max(width), total_lines + 1)
|
|
||||||
});
|
|
||||||
|
|
||||||
(width, total_lines as f32 * buffer.metrics().line_height)
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
use wgpu::{
|
|
||||||
util::DeviceExt,
|
|
||||||
BindGroup, BindGroupLayout, Device, Queue,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::render::surface::RenderSurface;
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
pipeline::{TexturePipeline, TEXTURE_SHADER},
|
|
||||||
vertex::{TextureVertex, TEXTURE_VERTICES}, texture::GameTexture,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl TexturePipeline {
|
|
||||||
pub fn new(surface: &RenderSurface) -> Self {
|
|
||||||
let RenderSurface {
|
|
||||||
device,
|
|
||||||
config,
|
|
||||||
queue,
|
|
||||||
..
|
|
||||||
} = surface;
|
|
||||||
|
|
||||||
let (bind_group_layout, diffuse_bind_group) = Self::init_textures(device, queue);
|
|
||||||
|
|
||||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
|
||||||
label: Some("UI Texture Shader"),
|
|
||||||
source: wgpu::ShaderSource::Wgsl(TEXTURE_SHADER.into()),
|
|
||||||
});
|
|
||||||
|
|
||||||
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
|
||||||
label: Some("Texture Vertex Buffer"),
|
|
||||||
contents: bytemuck::cast_slice(TEXTURE_VERTICES),
|
|
||||||
usage: wgpu::BufferUsages::VERTEX,
|
|
||||||
});
|
|
||||||
|
|
||||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
|
||||||
label: Some("UI Texture Pipeline Layout"),
|
|
||||||
bind_group_layouts: &[&bind_group_layout],
|
|
||||||
push_constant_ranges: &[],
|
|
||||||
});
|
|
||||||
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
|
||||||
label: Some("UI Texture Pipeline"),
|
|
||||||
layout: Some(&pipeline_layout),
|
|
||||||
vertex: wgpu::VertexState {
|
|
||||||
module: &shader,
|
|
||||||
entry_point: "vs_main",
|
|
||||||
buffers: &[TextureVertex::desc()],
|
|
||||||
},
|
|
||||||
fragment: Some(wgpu::FragmentState {
|
|
||||||
module: &shader,
|
|
||||||
entry_point: "fs_main",
|
|
||||||
targets: &[Some(wgpu::ColorTargetState {
|
|
||||||
format: config.format,
|
|
||||||
blend: Some(wgpu::BlendState::REPLACE),
|
|
||||||
write_mask: wgpu::ColorWrites::ALL,
|
|
||||||
})],
|
|
||||||
}),
|
|
||||||
primitive: wgpu::PrimitiveState {
|
|
||||||
topology: wgpu::PrimitiveTopology::TriangleStrip,
|
|
||||||
strip_index_format: None,
|
|
||||||
front_face: wgpu::FrontFace::Ccw,
|
|
||||||
cull_mode: Some(wgpu::Face::Back),
|
|
||||||
polygon_mode: wgpu::PolygonMode::Fill,
|
|
||||||
unclipped_depth: false,
|
|
||||||
conservative: false,
|
|
||||||
},
|
|
||||||
depth_stencil: None,
|
|
||||||
multisample: wgpu::MultisampleState {
|
|
||||||
count: 1,
|
|
||||||
mask: !0,
|
|
||||||
alpha_to_coverage_enabled: false,
|
|
||||||
},
|
|
||||||
multiview: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
Self {
|
|
||||||
pipeline,
|
|
||||||
vertex_buffer,
|
|
||||||
diffuse_bind_group,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_textures(device: &Device, queue: &Queue) -> (BindGroupLayout, BindGroup) {
|
|
||||||
let diffuse_bytes = include_bytes!("./textures/happy-tree.png");
|
|
||||||
let diffuse_texture =
|
|
||||||
GameTexture::from_bytes(&device, &queue, diffuse_bytes, "happy-tree.png").unwrap();
|
|
||||||
|
|
||||||
let texture_bind_group_layout =
|
|
||||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
||||||
entries: &[
|
|
||||||
wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 0,
|
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
|
||||||
ty: wgpu::BindingType::Texture {
|
|
||||||
multisampled: false,
|
|
||||||
view_dimension: wgpu::TextureViewDimension::D2,
|
|
||||||
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
|
||||||
// This should match the filterable field of the
|
|
||||||
// corresponding Texture entry above.
|
|
||||||
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
label: Some("texture_bind_group_layout"),
|
|
||||||
});
|
|
||||||
|
|
||||||
let diffuse_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
|
||||||
layout: &texture_bind_group_layout,
|
|
||||||
entries: &[
|
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 0,
|
|
||||||
resource: wgpu::BindingResource::TextureView(&diffuse_texture.view),
|
|
||||||
},
|
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 1,
|
|
||||||
resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
label: Some("diffuse_bind_group"),
|
|
||||||
});
|
|
||||||
|
|
||||||
(texture_bind_group_layout, diffuse_bind_group)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
mod init;
|
|
||||||
mod vertex;
|
|
||||||
mod texture;
|
|
||||||
|
|
||||||
use wgpu::{RenderPass, RenderPipeline};
|
|
||||||
|
|
||||||
pub const TEXTURE_SHADER: &str = include_str!("./shader.wgsl");
|
|
||||||
|
|
||||||
pub struct TexturePipeline {
|
|
||||||
pub pipeline: RenderPipeline,
|
|
||||||
pub vertex_buffer: wgpu::Buffer,
|
|
||||||
pub diffuse_bind_group: wgpu::BindGroup,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TexturePipeline {
|
|
||||||
pub fn draw<'a>(&'a self, pass: &mut RenderPass<'a>) {
|
|
||||||
pass.set_pipeline(&self.pipeline);
|
|
||||||
pass.set_bind_group(0, &self.diffuse_bind_group, &[]);
|
|
||||||
pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
|
|
||||||
pass.draw(0..4, 0..1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
// Vertex shader
|
|
||||||
|
|
||||||
struct VertexInput {
|
|
||||||
@location(0) position: vec2<f32>,
|
|
||||||
@location(1) tex_coords: vec2<f32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VertexOutput {
|
|
||||||
@builtin(position) clip_position: vec4<f32>,
|
|
||||||
@location(0) tex_coords: vec2<f32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
@vertex
|
|
||||||
fn vs_main(
|
|
||||||
model: VertexInput,
|
|
||||||
) -> VertexOutput {
|
|
||||||
var out: VertexOutput;
|
|
||||||
out.tex_coords = model.tex_coords;
|
|
||||||
out.clip_position = vec4<f32>(model.position, 0.0, 1.0);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fragment shader
|
|
||||||
|
|
||||||
@group(0) @binding(0)
|
|
||||||
var t_diffuse: texture_2d<f32>;
|
|
||||||
@group(0)@binding(1)
|
|
||||||
var s_diffuse: sampler;
|
|
||||||
|
|
||||||
@fragment
|
|
||||||
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
|
||||||
return textureSample(t_diffuse, s_diffuse, in.tex_coords);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
use image::{GenericImageView, ImageResult};
|
|
||||||
|
|
||||||
pub struct GameTexture {
|
|
||||||
pub texture: wgpu::Texture,
|
|
||||||
pub view: wgpu::TextureView,
|
|
||||||
pub sampler: wgpu::Sampler,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GameTexture {
|
|
||||||
pub fn from_bytes(
|
|
||||||
device: &wgpu::Device,
|
|
||||||
queue: &wgpu::Queue,
|
|
||||||
bytes: &[u8],
|
|
||||||
label: &str
|
|
||||||
) -> ImageResult<Self> {
|
|
||||||
let img = image::load_from_memory(bytes)?;
|
|
||||||
Self::from_image(device, queue, &img, Some(label))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_image(
|
|
||||||
device: &wgpu::Device,
|
|
||||||
queue: &wgpu::Queue,
|
|
||||||
img: &image::DynamicImage,
|
|
||||||
label: Option<&str>
|
|
||||||
) -> ImageResult<Self> {
|
|
||||||
let rgba = img.to_rgba8();
|
|
||||||
let dimensions = img.dimensions();
|
|
||||||
|
|
||||||
let size = wgpu::Extent3d {
|
|
||||||
width: dimensions.0,
|
|
||||||
height: dimensions.1,
|
|
||||||
depth_or_array_layers: 1,
|
|
||||||
};
|
|
||||||
let texture = device.create_texture(
|
|
||||||
&wgpu::TextureDescriptor {
|
|
||||||
label,
|
|
||||||
size,
|
|
||||||
mip_level_count: 1,
|
|
||||||
sample_count: 1,
|
|
||||||
dimension: wgpu::TextureDimension::D2,
|
|
||||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
|
||||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
|
||||||
view_formats: &[],
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
queue.write_texture(
|
|
||||||
wgpu::ImageCopyTexture {
|
|
||||||
aspect: wgpu::TextureAspect::All,
|
|
||||||
texture: &texture,
|
|
||||||
mip_level: 0,
|
|
||||||
origin: wgpu::Origin3d::ZERO,
|
|
||||||
},
|
|
||||||
&rgba,
|
|
||||||
wgpu::ImageDataLayout {
|
|
||||||
offset: 0,
|
|
||||||
bytes_per_row: Some(4 * dimensions.0),
|
|
||||||
rows_per_image: Some(dimensions.1),
|
|
||||||
},
|
|
||||||
size,
|
|
||||||
);
|
|
||||||
|
|
||||||
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
|
||||||
let sampler = device.create_sampler(
|
|
||||||
&wgpu::SamplerDescriptor {
|
|
||||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
|
||||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
|
||||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
|
||||||
mag_filter: wgpu::FilterMode::Linear,
|
|
||||||
min_filter: wgpu::FilterMode::Nearest,
|
|
||||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(Self { texture, view, sampler })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 28 KiB |
@@ -1,35 +0,0 @@
|
|||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
|
|
||||||
pub struct TextureVertex {
|
|
||||||
position: [f32; 2],
|
|
||||||
tex_coords: [f32; 2],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TextureVertex {
|
|
||||||
const ATTRIBS: [wgpu::VertexAttribute; 2] =
|
|
||||||
wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x2];
|
|
||||||
|
|
||||||
pub fn desc() -> wgpu::VertexBufferLayout<'static> {
|
|
||||||
use std::mem;
|
|
||||||
wgpu::VertexBufferLayout {
|
|
||||||
array_stride: mem::size_of::<TextureVertex>() as wgpu::BufferAddress,
|
|
||||||
step_mode: wgpu::VertexStepMode::Vertex,
|
|
||||||
attributes: &Self::ATTRIBS,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const TEXTURE_VERTICES: &[TextureVertex] = &[
|
|
||||||
TextureVertex { position: [0.0, 0.0], tex_coords: [0.0, 1.0], },
|
|
||||||
TextureVertex { position: [0.5, 0.0], tex_coords: [1.0, 1.0], },
|
|
||||||
TextureVertex { position: [0.0, 0.5], tex_coords: [0.0, 0.0], },
|
|
||||||
TextureVertex { position: [0.5, 0.5], tex_coords: [1.0, 0.0], },
|
|
||||||
];
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
|
|
||||||
pub struct ShapeVertex {
|
|
||||||
position: [f32; 2],
|
|
||||||
tex_coords: [f32; 2],
|
|
||||||
}
|
|
||||||
|
|
||||||
48
src/render/util/mod.rs
Normal file
48
src/render/util/mod.rs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use bytemuck::Pod;
|
||||||
|
use wgpu::*;
|
||||||
|
|
||||||
|
pub struct ArrBuf<T: Pod> {
|
||||||
|
label: &'static str,
|
||||||
|
usage: BufferUsages,
|
||||||
|
pub buffer: Buffer,
|
||||||
|
len: usize,
|
||||||
|
_pd: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Pod> ArrBuf<T> {
|
||||||
|
pub fn new(device: &Device, usage: BufferUsages, label: &'static str) -> Self {
|
||||||
|
Self {
|
||||||
|
label,
|
||||||
|
usage,
|
||||||
|
buffer: Self::init_buf(device, 0, usage, label),
|
||||||
|
len: 0,
|
||||||
|
_pd: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn update(&mut self, device: &Device, queue: &Queue, data: &[T]) {
|
||||||
|
if self.len != data.len() {
|
||||||
|
self.len = data.len();
|
||||||
|
self.buffer =
|
||||||
|
Self::init_buf(device, std::mem::size_of_val(data), self.usage, self.label);
|
||||||
|
}
|
||||||
|
queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(data));
|
||||||
|
}
|
||||||
|
fn init_buf(device: &Device, size: usize, usage: BufferUsages, label: &'static str) -> Buffer {
|
||||||
|
let mut size = size as u64;
|
||||||
|
if usage.contains(BufferUsages::STORAGE) {
|
||||||
|
size = size.max(1);
|
||||||
|
}
|
||||||
|
device.create_buffer(&BufferDescriptor {
|
||||||
|
label: Some(label),
|
||||||
|
size,
|
||||||
|
mapped_at_creation: false,
|
||||||
|
usage,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
#[allow(clippy::len_without_is_empty)]
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.len
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ impl ApplicationHandler for App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_event(&mut self, event_loop: &ActiveEventLoop, id: WindowId, event: WindowEvent) {
|
fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) {
|
||||||
self.client.as_mut().unwrap().event(event, event_loop);
|
self.client.as_mut().unwrap().event(event, event_loop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
58
src/testing/mod.rs
Normal file
58
src/testing/mod.rs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use app::App;
|
||||||
|
use gui::{primitive::Axis, NodeArrayUtil, NodeUtil, RoundedRect, UIColor};
|
||||||
|
use render::Renderer;
|
||||||
|
use winit::{event::WindowEvent, event_loop::ActiveEventLoop, window::Window};
|
||||||
|
|
||||||
|
mod app;
|
||||||
|
mod render;
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
App::run();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Client {
|
||||||
|
renderer: Renderer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub fn new(window: Arc<Window>) -> Self {
|
||||||
|
let mut renderer = Renderer::new(window);
|
||||||
|
let rect = RoundedRect {
|
||||||
|
color: UIColor::WHITE,
|
||||||
|
radius: 10.0,
|
||||||
|
thickness: 0.0,
|
||||||
|
inner_radius: 0.0,
|
||||||
|
};
|
||||||
|
let ui = (
|
||||||
|
(
|
||||||
|
rect.color(UIColor::BLUE),
|
||||||
|
(
|
||||||
|
rect.color(UIColor::RED),
|
||||||
|
(rect.color(UIColor::ORANGE), rect.color(UIColor::LIME))
|
||||||
|
.proportioned(Axis::Y, [1, 1]),
|
||||||
|
rect.color(UIColor::YELLOW),
|
||||||
|
)
|
||||||
|
.proportioned(Axis::X, [2, 2, 1])
|
||||||
|
.pad(10),
|
||||||
|
)
|
||||||
|
.proportioned(Axis::X, [1, 3]),
|
||||||
|
rect.color(UIColor::GREEN),
|
||||||
|
)
|
||||||
|
.proportioned(Axis::Y, [3, 1])
|
||||||
|
.pad(10)
|
||||||
|
.into();
|
||||||
|
renderer.update(&ui);
|
||||||
|
Self { renderer }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) {
|
||||||
|
match event {
|
||||||
|
WindowEvent::CloseRequested => event_loop.exit(),
|
||||||
|
WindowEvent::RedrawRequested => self.renderer.draw(),
|
||||||
|
WindowEvent::Resized(size) => self.renderer.resize(&size),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
132
src/testing/render/mod.rs
Normal file
132
src/testing/render/mod.rs
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
use gui::{UIRenderNode, UI};
|
||||||
|
use pollster::FutureExt;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use wgpu::util::StagingBelt;
|
||||||
|
use winit::{dpi::PhysicalSize, window::Window};
|
||||||
|
|
||||||
|
pub const CLEAR_COLOR: wgpu::Color = wgpu::Color::BLACK;
|
||||||
|
|
||||||
|
pub struct Renderer {
|
||||||
|
surface: wgpu::Surface<'static>,
|
||||||
|
device: wgpu::Device,
|
||||||
|
queue: wgpu::Queue,
|
||||||
|
config: wgpu::SurfaceConfiguration,
|
||||||
|
encoder: wgpu::CommandEncoder,
|
||||||
|
staging_belt: StagingBelt,
|
||||||
|
ui_node: UIRenderNode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Renderer {
|
||||||
|
pub fn update(&mut self, ui: &UI) {
|
||||||
|
self.ui_node.update(&self.device, &self.queue, ui);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&mut self) {
|
||||||
|
let output = self.surface.get_current_texture().unwrap();
|
||||||
|
let view = output
|
||||||
|
.texture
|
||||||
|
.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
||||||
|
let mut encoder = std::mem::replace(&mut self.encoder, Self::create_encoder(&self.device));
|
||||||
|
{
|
||||||
|
let render_pass = &mut encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
view: &view,
|
||||||
|
resolve_target: None,
|
||||||
|
ops: wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Clear(CLEAR_COLOR),
|
||||||
|
store: wgpu::StoreOp::Store,
|
||||||
|
},
|
||||||
|
depth_slice: None,
|
||||||
|
})],
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
self.ui_node.draw(render_pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.queue.submit(std::iter::once(encoder.finish()));
|
||||||
|
self.staging_belt.finish();
|
||||||
|
output.present();
|
||||||
|
self.staging_belt.recall();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resize(&mut self, size: &PhysicalSize<u32>) {
|
||||||
|
self.config.width = size.width;
|
||||||
|
self.config.height = size.height;
|
||||||
|
self.surface.configure(&self.device, &self.config);
|
||||||
|
self.ui_node.resize(size, &self.queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_encoder(device: &wgpu::Device) -> wgpu::CommandEncoder {
|
||||||
|
device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||||
|
label: Some("Render Encoder"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(window: Arc<Window>) -> Self {
|
||||||
|
let size = window.inner_size();
|
||||||
|
|
||||||
|
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
|
||||||
|
backends: wgpu::Backends::PRIMARY,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
let surface = instance
|
||||||
|
.create_surface(window.clone())
|
||||||
|
.expect("Could not create window surface!");
|
||||||
|
|
||||||
|
let adapter = instance
|
||||||
|
.request_adapter(&wgpu::RequestAdapterOptions {
|
||||||
|
power_preference: wgpu::PowerPreference::default(),
|
||||||
|
compatible_surface: Some(&surface),
|
||||||
|
force_fallback_adapter: false,
|
||||||
|
})
|
||||||
|
.block_on()
|
||||||
|
.expect("Could not get adapter!");
|
||||||
|
|
||||||
|
let (device, queue) = adapter
|
||||||
|
.request_device(&wgpu::DeviceDescriptor {
|
||||||
|
required_features: wgpu::Features::empty(),
|
||||||
|
required_limits: wgpu::Limits::default(),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.block_on()
|
||||||
|
.expect("Could not get device!");
|
||||||
|
|
||||||
|
let surface_caps = surface.get_capabilities(&adapter);
|
||||||
|
let surface_format = surface_caps
|
||||||
|
.formats
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.find(|f| f.is_srgb())
|
||||||
|
.unwrap_or(surface_caps.formats[0]);
|
||||||
|
|
||||||
|
let config = wgpu::SurfaceConfiguration {
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
|
format: surface_format,
|
||||||
|
width: size.width,
|
||||||
|
height: size.height,
|
||||||
|
present_mode: wgpu::PresentMode::AutoVsync,
|
||||||
|
alpha_mode: surface_caps.alpha_modes[0],
|
||||||
|
desired_maximum_frame_latency: 2,
|
||||||
|
view_formats: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
surface.configure(&device, &config);
|
||||||
|
|
||||||
|
let staging_belt = StagingBelt::new(4096 * 4);
|
||||||
|
let encoder = Self::create_encoder(&device);
|
||||||
|
|
||||||
|
let shape_pipeline = UIRenderNode::new(&device, &config);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
surface,
|
||||||
|
device,
|
||||||
|
queue,
|
||||||
|
config,
|
||||||
|
encoder,
|
||||||
|
staging_belt,
|
||||||
|
ui_node: shape_pipeline,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user