added underdeveloped but working image support (no freeing or samplers)
This commit is contained in:
702
Cargo.lock
generated
702
Cargo.lock
generated
@@ -18,6 +18,12 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2187590a23ab1e3df8681afdf0987c48504d80291f002fcdb651f0ef5e25169"
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.12"
|
||||
@@ -25,12 +31,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"getrandom 0.3.3",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aligned-vec"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b"
|
||||
dependencies = [
|
||||
"equator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-activity"
|
||||
version = "0.6.0"
|
||||
@@ -67,6 +82,29 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
|
||||
|
||||
[[package]]
|
||||
name = "arg_enum_proc_macro"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.9"
|
||||
@@ -106,6 +144,29 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "av1-grain"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arrayvec",
|
||||
"log",
|
||||
"nom",
|
||||
"num-rational",
|
||||
"v_frame",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "avif-serialize"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47c8fbc0f831f4519fe8b810b6a7a91410ec83031b8233f730a0480029f6a23f"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.8.0"
|
||||
@@ -121,6 +182,12 @@ version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -136,6 +203,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitstream-io"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2"
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
@@ -151,6 +224,12 @@ dependencies = [
|
||||
"objc2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "built"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.19.0"
|
||||
@@ -177,6 +256,12 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder-lite"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.10.1"
|
||||
@@ -226,6 +311,16 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-expr"
|
||||
version = "0.15.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.1"
|
||||
@@ -249,6 +344,12 @@ dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.7"
|
||||
@@ -329,6 +430,34 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
@@ -383,6 +512,32 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "equator"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc"
|
||||
dependencies = [
|
||||
"equator-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equator-macro"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
@@ -399,6 +554,40 @@ dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exr"
|
||||
version = "1.73.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"half",
|
||||
"lebe",
|
||||
"miniz_oxide",
|
||||
"rayon-core",
|
||||
"smallvec",
|
||||
"zune-inflate",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fdeflate"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
|
||||
dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
@@ -442,6 +631,17 @@ dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.3"
|
||||
@@ -451,7 +651,17 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi",
|
||||
"wasi 0.14.2+wasi-0.2.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gif"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b"
|
||||
dependencies = [
|
||||
"color_quant",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -537,16 +747,6 @@ dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"pollster",
|
||||
"wgpu",
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.6.0"
|
||||
@@ -567,6 +767,12 @@ dependencies = [
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.5.2"
|
||||
@@ -579,6 +785,45 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
"color_quant",
|
||||
"exr",
|
||||
"gif",
|
||||
"image-webp",
|
||||
"num-traits",
|
||||
"png",
|
||||
"qoi",
|
||||
"ravif",
|
||||
"rayon",
|
||||
"rgb",
|
||||
"tiff",
|
||||
"zune-core",
|
||||
"zune-jpeg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "image-webp"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6970fe7a5300b4b42e62c52efa0187540a5bef546c60edaf554ef595d2e6f0b"
|
||||
dependencies = [
|
||||
"byteorder-lite",
|
||||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imgref"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.10.0"
|
||||
@@ -589,6 +834,26 @@ dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "interpolate_name"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.21.1"
|
||||
@@ -617,10 +882,16 @@ version = "0.1.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.3.3",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jpeg-decoder"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.77"
|
||||
@@ -648,12 +919,28 @@ version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
||||
|
||||
[[package]]
|
||||
name = "lebe"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.174"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.8"
|
||||
@@ -715,6 +1002,15 @@ version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "loop9"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062"
|
||||
dependencies = [
|
||||
"imgref",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
@@ -724,6 +1020,16 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maybe-rayon"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.5"
|
||||
@@ -754,6 +1060,22 @@ dependencies = [
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "26.0.0"
|
||||
@@ -810,6 +1132,69 @@ dependencies = [
|
||||
"jni-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "noop_proc_macro"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
@@ -1154,6 +1539,19 @@ version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.17.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "3.10.0"
|
||||
@@ -1189,6 +1587,15 @@ dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "presser"
|
||||
version = "0.3.1"
|
||||
@@ -1218,6 +1625,34 @@ name = "profiling"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
|
||||
dependencies = [
|
||||
"profiling-procmacros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "profiling-procmacros"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "qoi"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
@@ -1243,18 +1678,118 @@ version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "range-alloc"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde"
|
||||
|
||||
[[package]]
|
||||
name = "rav1e"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"arg_enum_proc_macro",
|
||||
"arrayvec",
|
||||
"av1-grain",
|
||||
"bitstream-io",
|
||||
"built",
|
||||
"cfg-if",
|
||||
"interpolate_name",
|
||||
"itertools",
|
||||
"libc",
|
||||
"libfuzzer-sys",
|
||||
"log",
|
||||
"maybe-rayon",
|
||||
"new_debug_unreachable",
|
||||
"noop_proc_macro",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"profiling",
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
"simd_helpers",
|
||||
"system-deps",
|
||||
"thiserror 1.0.69",
|
||||
"v_frame",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ravif"
|
||||
version = "0.11.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b"
|
||||
dependencies = [
|
||||
"avif-serialize",
|
||||
"imgref",
|
||||
"loop9",
|
||||
"quick-error",
|
||||
"rav1e",
|
||||
"rayon",
|
||||
"rgb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
@@ -1279,6 +1814,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
||||
|
||||
[[package]]
|
||||
name = "rgb"
|
||||
version = "0.8.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
@@ -1371,12 +1912,36 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
|
||||
[[package]]
|
||||
name = "simd_helpers"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6"
|
||||
dependencies = [
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.11"
|
||||
@@ -1464,6 +2029,25 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-deps"
|
||||
version = "6.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349"
|
||||
dependencies = [
|
||||
"cfg-expr",
|
||||
"heck",
|
||||
"pkg-config",
|
||||
"toml",
|
||||
"version-compare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
@@ -1513,6 +2097,17 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"jpeg-decoder",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia"
|
||||
version = "0.11.4"
|
||||
@@ -1538,11 +2133,26 @@ dependencies = [
|
||||
"strict-num",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
@@ -1551,6 +2161,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
@@ -1577,6 +2189,17 @@ version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
|
||||
|
||||
[[package]]
|
||||
name = "ui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"image",
|
||||
"pollster",
|
||||
"wgpu",
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
@@ -1595,6 +2218,23 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
|
||||
|
||||
[[package]]
|
||||
name = "v_frame"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2"
|
||||
dependencies = [
|
||||
"aligned-vec",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
@@ -1611,6 +2251,12 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.14.2+wasi-0.2.4"
|
||||
@@ -1820,6 +2466,12 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3"
|
||||
|
||||
[[package]]
|
||||
name = "wgpu"
|
||||
version = "26.0.1"
|
||||
@@ -2479,3 +3131,27 @@ dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zune-core"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
|
||||
|
||||
[[package]]
|
||||
name = "zune-inflate"
|
||||
version = "0.2.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
|
||||
dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zune-jpeg"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc1f7e205ce79eb2da3cd71c5f55f3589785cb7c79f6a03d1c8d1491bda5d089"
|
||||
dependencies = [
|
||||
"zune-core",
|
||||
]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "gui"
|
||||
name = "ui"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
@@ -10,4 +10,5 @@ pollster = "0.4.0"
|
||||
winit = "0.30.11"
|
||||
wgpu = "26.0.1"
|
||||
bytemuck = "1.23.1"
|
||||
image = "0.25.6"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ pub struct Regioned {
|
||||
impl<Ctx: 'static> Widget<Ctx> for Regioned {
|
||||
fn draw(&self, painter: &mut Painter<Ctx>) {
|
||||
painter.region.select(&self.region);
|
||||
painter.draw(&self.inner);
|
||||
painter.draw_inner(&self.inner);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
63
src/core/image.rs
Normal file
63
src/core/image.rs
Normal file
@@ -0,0 +1,63 @@
|
||||
use image::DynamicImage;
|
||||
|
||||
use crate::{Color, TextureHandle, Widget, WidgetFnRet, render::RectPrimitive};
|
||||
|
||||
pub struct Image {
|
||||
handle: Option<TextureHandle>,
|
||||
}
|
||||
|
||||
impl<Ctx> Widget<Ctx> for Image {
|
||||
fn draw(&self, painter: &mut crate::Painter<Ctx>) {
|
||||
if let Some(handle) = &self.handle {
|
||||
painter.draw_texture(handle);
|
||||
} else {
|
||||
painter.write(RectPrimitive {
|
||||
color: Color::MAGENTA,
|
||||
inner_radius: 0.0,
|
||||
radius: 0.0,
|
||||
thickness: 0.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image<Ctx>(image: impl LoadableImage) -> WidgetFnRet!(Image, Ctx) {
|
||||
let image = match image.get_image() {
|
||||
Ok(image) => Some(image),
|
||||
Err(e) => {
|
||||
println!("Failed to load image: {e}");
|
||||
None
|
||||
}
|
||||
};
|
||||
move |ui| Image {
|
||||
handle: image.map(|image| ui.add_texture(image)),
|
||||
}
|
||||
}
|
||||
|
||||
pub trait LoadableImage {
|
||||
fn get_image(self) -> Result<DynamicImage, String>;
|
||||
}
|
||||
|
||||
impl LoadableImage for &str {
|
||||
fn get_image(self) -> Result<DynamicImage, String> {
|
||||
image::open(self).map_err(|e| format!("{e:?}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl LoadableImage for String {
|
||||
fn get_image(self) -> Result<DynamicImage, String> {
|
||||
image::open(self).map_err(|e| format!("{e:?}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl<const LEN: usize> LoadableImage for &[u8; LEN] {
|
||||
fn get_image(self) -> Result<DynamicImage, String> {
|
||||
image::load_from_memory(self).map_err(|e| format!("{e:?}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl LoadableImage for DynamicImage {
|
||||
fn get_image(self) -> Result<DynamicImage, String> {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
mod frame;
|
||||
mod image;
|
||||
mod num;
|
||||
mod rect;
|
||||
mod sense;
|
||||
@@ -7,6 +8,7 @@ mod stack;
|
||||
mod trait_fns;
|
||||
|
||||
pub use frame::*;
|
||||
pub use image::*;
|
||||
pub use num::*;
|
||||
pub use rect::*;
|
||||
pub use sense::*;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{primitive::RoundedRectData, Painter, UiNum, UiColor, Widget};
|
||||
use crate::{Painter, UiColor, UiNum, Widget, render::RectPrimitive};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Rect {
|
||||
@@ -29,7 +29,7 @@ impl Rect {
|
||||
|
||||
impl<Ctx> Widget<Ctx> for Rect {
|
||||
fn draw(&self, painter: &mut Painter<Ctx>) {
|
||||
painter.write(RoundedRectData {
|
||||
painter.write(RectPrimitive {
|
||||
color: self.color,
|
||||
radius: self.radius,
|
||||
thickness: self.thickness,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{Dir, Painter, Sign, UiNum, UiRegion, UIScalar, Widget, WidgetId};
|
||||
use crate::{Dir, Painter, Sign, UIScalar, UiNum, UiRegion, Widget, WidgetId};
|
||||
|
||||
pub struct Span {
|
||||
pub children: Vec<(WidgetId, SpanLen)>,
|
||||
|
||||
@@ -7,7 +7,7 @@ pub struct Stack {
|
||||
impl<Ctx> Widget<Ctx> for Stack {
|
||||
fn draw(&self, painter: &mut crate::Painter<Ctx>) {
|
||||
for child in &self.children {
|
||||
painter.draw_within(child, painter.region);
|
||||
painter.draw(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
mod color;
|
||||
mod id;
|
||||
mod painter;
|
||||
mod region;
|
||||
mod sense;
|
||||
mod texture;
|
||||
mod ui;
|
||||
mod vec2;
|
||||
mod widget;
|
||||
mod id;
|
||||
|
||||
pub use color::*;
|
||||
pub use id::*;
|
||||
pub use painter::*;
|
||||
pub use region::*;
|
||||
pub use sense::*;
|
||||
pub use texture::*;
|
||||
pub use ui::*;
|
||||
pub use vec2::*;
|
||||
pub use widget::*;
|
||||
pub use id::*;
|
||||
|
||||
pub type UiColor = Color<u8>;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
ActiveSensors, SensorMap, UiRegion, WidgetId, Widgets,
|
||||
primitive::{Primitive, Primitives},
|
||||
ActiveSensors, SensorMap, TextureHandle, UiRegion, WidgetId, Widgets,
|
||||
render::{Primitive, Primitives},
|
||||
};
|
||||
|
||||
pub struct Painter<'a, Ctx: 'static> {
|
||||
@@ -32,7 +32,9 @@ impl<'a, Ctx> Painter<'a, Ctx> {
|
||||
self.primitives.write(data, self.region);
|
||||
}
|
||||
|
||||
pub fn draw<W>(&mut self, id: &WidgetId<W>)
|
||||
/// Draws a widget but does NOT maintain the region.
|
||||
/// Useful if you only have a single widget to draw.
|
||||
pub fn draw_inner<W>(&mut self, id: &WidgetId<W>)
|
||||
where
|
||||
Ctx: 'static,
|
||||
{
|
||||
@@ -42,16 +44,34 @@ impl<'a, Ctx> Painter<'a, Ctx> {
|
||||
self.nodes.get_dyn(id).draw(self);
|
||||
}
|
||||
|
||||
pub fn draw_within(&mut self, node: &WidgetId, region: UiRegion)
|
||||
/// Draws a widget and maintains the original region.
|
||||
/// Useful if you need to draw multiple overlapping child widgets.
|
||||
pub fn draw<W>(&mut self, id: &WidgetId<W>)
|
||||
where
|
||||
Ctx: 'static,
|
||||
{
|
||||
let old = self.region;
|
||||
self.draw_inner(id);
|
||||
self.region = old;
|
||||
}
|
||||
|
||||
/// Draws a widget within an inner region and maintains the original region.
|
||||
/// Useful if you need to draw multiple child widgets in select areas within the original
|
||||
/// region.
|
||||
pub fn draw_within(&mut self, id: &WidgetId, region: UiRegion)
|
||||
where
|
||||
Ctx: 'static,
|
||||
{
|
||||
let old = self.region;
|
||||
self.region.select(®ion);
|
||||
self.draw(node);
|
||||
self.draw_inner(id);
|
||||
self.region = old;
|
||||
}
|
||||
|
||||
pub fn draw_texture(&mut self, handle: &TextureHandle) {
|
||||
self.write(handle.inner);
|
||||
}
|
||||
|
||||
pub fn finish(self) -> Primitives {
|
||||
self.primitives
|
||||
}
|
||||
|
||||
48
src/layout/texture.rs
Normal file
48
src/layout/texture.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
use image::DynamicImage;
|
||||
|
||||
use crate::render::TexturePrimitive;
|
||||
|
||||
/// TODO: proper resource management
|
||||
pub struct TextureHandle {
|
||||
pub inner: TexturePrimitive,
|
||||
}
|
||||
|
||||
/// a texture manager for a ui
|
||||
/// note that this is heavily oriented towards wgpu's renderer so the primitives don't need mapped
|
||||
#[derive(Default)]
|
||||
pub struct Textures {
|
||||
/// TODO: these are images, not views rn
|
||||
views: Vec<DynamicImage>,
|
||||
changed: bool,
|
||||
}
|
||||
|
||||
pub struct TextureUpdates<'a> {
|
||||
pub images: Option<&'a [DynamicImage]>,
|
||||
}
|
||||
|
||||
impl Textures {
|
||||
pub fn add(&mut self, image: DynamicImage) -> TextureHandle {
|
||||
let view_idx = self.views.len() as u32;
|
||||
self.views.push(image);
|
||||
// 0 == default in renderer; TODO: actually create samplers here
|
||||
let sampler_idx = 0;
|
||||
self.changed = true;
|
||||
TextureHandle {
|
||||
inner: TexturePrimitive {
|
||||
view_idx,
|
||||
sampler_idx,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updates(&mut self) -> TextureUpdates<'_> {
|
||||
if self.changed {
|
||||
self.changed = false;
|
||||
TextureUpdates {
|
||||
images: Some(&self.views),
|
||||
}
|
||||
} else {
|
||||
TextureUpdates { images: None }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
use image::DynamicImage;
|
||||
|
||||
use crate::{
|
||||
ActiveSensors, HashMap, Painter, SensorMap, Widget, WidgetId, WidgetLike,
|
||||
primitive::Primitives,
|
||||
util::{IDTracker, Id},
|
||||
ActiveSensors, HashMap, Painter, SensorMap, TextureHandle, TextureUpdates, Textures, Widget,
|
||||
WidgetId, WidgetLike,
|
||||
render::Primitives,
|
||||
util::{Id, IdTracker},
|
||||
};
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
@@ -10,20 +13,24 @@ use std::{
|
||||
};
|
||||
|
||||
pub struct Ui<Ctx> {
|
||||
ids: IDTracker,
|
||||
base: Option<WidgetId>,
|
||||
widgets: Widgets<Ctx>,
|
||||
updates: Vec<WidgetId>,
|
||||
del_recv: Receiver<Id>,
|
||||
del_send: Sender<Id>,
|
||||
primitives: Primitives,
|
||||
textures: Textures,
|
||||
full_redraw: bool,
|
||||
|
||||
pub(super) active_sensors: ActiveSensors,
|
||||
pub(super) sensor_map: SensorMap<Ctx>,
|
||||
primitives: Primitives,
|
||||
full_redraw: bool,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Widgets<Ctx>(HashMap<Id, Box<dyn Widget<Ctx>>>);
|
||||
pub struct Widgets<Ctx> {
|
||||
ids: IdTracker,
|
||||
map: HashMap<Id, Box<dyn Widget<Ctx>>>,
|
||||
}
|
||||
|
||||
impl<Ctx> Ui<Ctx> {
|
||||
pub fn add<W: Widget<Ctx>, Tag>(
|
||||
@@ -68,7 +75,15 @@ impl<Ctx> Ui<Ctx> {
|
||||
}
|
||||
|
||||
pub fn id<W: Widget<Ctx>>(&mut self) -> WidgetId<W> {
|
||||
WidgetId::new(self.ids.next(), TypeId::of::<W>(), self.del_send.clone())
|
||||
WidgetId::new(
|
||||
self.widgets.reserve(),
|
||||
TypeId::of::<W>(),
|
||||
self.del_send.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn add_texture(&mut self, image: DynamicImage) -> TextureHandle {
|
||||
self.textures.add(image)
|
||||
}
|
||||
|
||||
pub fn redraw_all(&mut self, ctx: &mut Ctx)
|
||||
@@ -83,12 +98,12 @@ impl<Ctx> Ui<Ctx> {
|
||||
&mut self.active_sensors,
|
||||
);
|
||||
if let Some(base) = &self.base {
|
||||
painter.draw(base);
|
||||
painter.draw_inner(base);
|
||||
}
|
||||
self.primitives = painter.finish();
|
||||
}
|
||||
|
||||
pub fn update(&mut self, ctx: &mut Ctx) -> Option<&Primitives>
|
||||
pub fn update(&mut self, ctx: &mut Ctx) -> UiRenderUpdates
|
||||
where
|
||||
Ctx: 'static,
|
||||
{
|
||||
@@ -99,14 +114,24 @@ impl<Ctx> Ui<Ctx> {
|
||||
if self.full_redraw {
|
||||
self.redraw_all(ctx);
|
||||
self.full_redraw = false;
|
||||
return Some(&self.primitives);
|
||||
UiRenderUpdates {
|
||||
primitives: Some(&self.primitives),
|
||||
textures: self.textures.updates(),
|
||||
}
|
||||
} else if self.updates.is_empty() {
|
||||
UiRenderUpdates {
|
||||
primitives: None,
|
||||
textures: self.textures.updates(),
|
||||
}
|
||||
} else {
|
||||
// TODO: partial updates
|
||||
self.redraw_all(ctx);
|
||||
self.updates.drain(..);
|
||||
UiRenderUpdates {
|
||||
primitives: Some(&self.primitives),
|
||||
textures: self.textures.updates(),
|
||||
}
|
||||
}
|
||||
if self.updates.is_empty() {
|
||||
return None;
|
||||
}
|
||||
self.redraw_all(ctx);
|
||||
self.updates.drain(..);
|
||||
Some(&self.primitives)
|
||||
}
|
||||
|
||||
pub fn needs_redraw(&self) -> bool {
|
||||
@@ -135,39 +160,51 @@ impl<W: Widget<Ctx>, Ctx> IndexMut<&WidgetId<W>> for Ui<Ctx> {
|
||||
|
||||
impl<Ctx> Widgets<Ctx> {
|
||||
pub fn new() -> Self {
|
||||
Self(HashMap::new())
|
||||
Self {
|
||||
ids: IdTracker::default(),
|
||||
map: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_dyn<W>(&self, id: &WidgetId<W>) -> &dyn Widget<Ctx> {
|
||||
self.0.get(&id.id).unwrap().as_ref()
|
||||
self.map.get(&id.id).unwrap().as_ref()
|
||||
}
|
||||
|
||||
pub fn get<W: Widget<Ctx>>(&self, id: &WidgetId<W>) -> Option<&W> {
|
||||
self.0.get(&id.id).unwrap().as_any().downcast_ref()
|
||||
self.map.get(&id.id).unwrap().as_any().downcast_ref()
|
||||
}
|
||||
|
||||
pub fn get_mut<W: Widget<Ctx>>(&mut self, id: &WidgetId<W>) -> Option<&mut W> {
|
||||
self.0.get_mut(&id.id).unwrap().as_any_mut().downcast_mut()
|
||||
self.map
|
||||
.get_mut(&id.id)
|
||||
.unwrap()
|
||||
.as_any_mut()
|
||||
.downcast_mut()
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, id: Id, widget: impl Widget<Ctx>) {
|
||||
self.0.insert(id, Box::new(widget));
|
||||
self.map.insert(id, Box::new(widget));
|
||||
}
|
||||
|
||||
pub fn insert_any(&mut self, id: Id, widget: Box<dyn Widget<Ctx>>) {
|
||||
self.0.insert(id, widget);
|
||||
self.map.insert(id, widget);
|
||||
}
|
||||
|
||||
pub fn delete(&mut self, id: Id) {
|
||||
self.0.remove(&id);
|
||||
self.map.remove(&id);
|
||||
self.ids.free(id);
|
||||
}
|
||||
|
||||
pub fn reserve(&mut self) -> Id {
|
||||
self.ids.next()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
self.map.len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
self.map.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,11 +222,11 @@ impl<Ctx: 'static> Default for Ui<Ctx> {
|
||||
fn default() -> Self {
|
||||
let (del_send, del_recv) = channel();
|
||||
Self {
|
||||
ids: Default::default(),
|
||||
base: Default::default(),
|
||||
widgets: Widgets::new(),
|
||||
updates: Default::default(),
|
||||
primitives: Default::default(),
|
||||
textures: Textures::default(),
|
||||
full_redraw: false,
|
||||
active_sensors: Default::default(),
|
||||
sensor_map: Default::default(),
|
||||
@@ -198,3 +235,8 @@ impl<Ctx: 'static> Default for Ui<Ctx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UiRenderUpdates<'a> {
|
||||
pub primitives: Option<&'a Primitives>,
|
||||
pub textures: TextureUpdates<'a>,
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::{util::{impl_op, F32Util}, UiNum};
|
||||
use std::ops::*;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Default, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
#[derive(Clone, Copy, PartialEq, Default, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
pub struct Vec2 {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
@@ -60,3 +60,9 @@ impl<T: UiNum, U: UiNum> From<(T, U)> for Vec2 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Vec2 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "({}, {})", self.x, self.y)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,8 +41,7 @@ pub(crate) use WidgetFnRet;
|
||||
impl<W: Widget<Ctx>, Ctx, F: FnOnce(&mut Ui<Ctx>) -> W> WidgetLike<Ctx, FnTag> for F {
|
||||
type Widget = W;
|
||||
fn add(self, ui: &mut Ui<Ctx>) -> WidgetId<W> {
|
||||
let w = self(ui);
|
||||
ui.add(w)
|
||||
self(ui).add(ui)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,13 @@
|
||||
#![feature(trait_alias)]
|
||||
#![feature(negative_impls)]
|
||||
|
||||
mod layout;
|
||||
mod render;
|
||||
mod util;
|
||||
mod core;
|
||||
mod layout;
|
||||
pub mod render;
|
||||
mod util;
|
||||
|
||||
pub use layout::*;
|
||||
pub use render::*;
|
||||
pub use core::*;
|
||||
pub use layout::*;
|
||||
|
||||
pub type HashMap<K, V> = std::collections::HashMap<K, V>;
|
||||
pub type HashSet<K> = std::collections::HashSet<K>;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use std::num::NonZero;
|
||||
|
||||
use crate::{
|
||||
primitive::{PrimitiveBuffers, Primitives},
|
||||
render::{data::PrimitiveInstance, util::ArrBuf},
|
||||
Ui, UiRenderUpdates,
|
||||
render::{data::PrimitiveInstance, texture::GpuTextures, util::ArrBuf},
|
||||
};
|
||||
use data::WindowUniform;
|
||||
use wgpu::{
|
||||
@@ -10,41 +12,55 @@ use wgpu::{
|
||||
use winit::dpi::PhysicalSize;
|
||||
|
||||
mod data;
|
||||
pub mod primitive;
|
||||
mod primitive;
|
||||
mod texture;
|
||||
mod util;
|
||||
|
||||
pub use primitive::*;
|
||||
|
||||
const SHAPE_SHADER: &str = include_str!("./shader.wgsl");
|
||||
|
||||
pub struct UIRenderNode {
|
||||
layout0: BindGroupLayout,
|
||||
group0: BindGroup,
|
||||
pub struct UiRenderer {
|
||||
uniform_layout: BindGroupLayout,
|
||||
uniform_group: BindGroup,
|
||||
primitive_layout: BindGroupLayout,
|
||||
primitive_group: BindGroup,
|
||||
rsc_layout: BindGroupLayout,
|
||||
rsc_group: BindGroup,
|
||||
|
||||
pipeline: RenderPipeline,
|
||||
|
||||
window_buffer: Buffer,
|
||||
instance: ArrBuf<PrimitiveInstance>,
|
||||
primitives: PrimitiveBuffers,
|
||||
|
||||
limits: UiLimits,
|
||||
textures: GpuTextures,
|
||||
}
|
||||
|
||||
impl UIRenderNode {
|
||||
impl UiRenderer {
|
||||
pub fn draw<'a>(&'a self, pass: &mut RenderPass<'a>) {
|
||||
if self.instance.len() != 0 {
|
||||
pass.set_pipeline(&self.pipeline);
|
||||
pass.set_bind_group(0, &self.group0, &[]);
|
||||
pass.set_bind_group(1, &self.primitive_group, &[]);
|
||||
pass.set_vertex_buffer(0, self.instance.buffer.slice(..));
|
||||
pass.draw(0..4, 0..self.instance.len() as u32);
|
||||
if self.instance.len() == 0 {
|
||||
return;
|
||||
}
|
||||
pass.set_pipeline(&self.pipeline);
|
||||
pass.set_bind_group(0, &self.uniform_group, &[]);
|
||||
pass.set_bind_group(1, &self.primitive_group, &[]);
|
||||
pass.set_bind_group(2, &self.rsc_group, &[]);
|
||||
pass.set_vertex_buffer(0, self.instance.buffer.slice(..));
|
||||
pass.draw(0..4, 0..self.instance.len() as u32);
|
||||
}
|
||||
|
||||
pub fn update(&mut self, device: &Device, queue: &Queue, primitives: Option<&Primitives>) {
|
||||
if let Some(primitives) = primitives {
|
||||
pub fn update(&mut self, device: &Device, queue: &Queue, updates: UiRenderUpdates) {
|
||||
if let Some(primitives) = updates.primitives {
|
||||
self.instance.update(device, queue, &primitives.instances);
|
||||
self.primitives.update(device, queue, &primitives.data);
|
||||
self.primitive_group =
|
||||
Self::primitive_group(device, &self.primitive_layout, self.primitives.buffers())
|
||||
}
|
||||
if self.textures.apply(updates.textures) {
|
||||
self.rsc_group = Self::rsc_group(device, &self.rsc_layout, &self.textures)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, size: &PhysicalSize<u32>, queue: &Queue) {
|
||||
@@ -55,7 +71,12 @@ impl UIRenderNode {
|
||||
queue.write_buffer(&self.window_buffer, 0, bytemuck::cast_slice(slice));
|
||||
}
|
||||
|
||||
pub fn new(device: &Device, config: &SurfaceConfiguration) -> Self {
|
||||
pub fn new(
|
||||
device: &Device,
|
||||
queue: &Queue,
|
||||
config: &SurfaceConfiguration,
|
||||
limits: UiLimits,
|
||||
) -> Self {
|
||||
let shader = device.create_shader_module(ShaderModuleDescriptor {
|
||||
label: Some("UI Shape Shader"),
|
||||
source: ShaderSource::Wgsl(SHAPE_SHADER.into()),
|
||||
@@ -75,7 +96,7 @@ impl UIRenderNode {
|
||||
);
|
||||
let primitives = PrimitiveBuffers::new(device);
|
||||
|
||||
let layout0 = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
||||
let uniform_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
||||
entries: &[BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: ShaderStages::VERTEX,
|
||||
@@ -89,7 +110,7 @@ impl UIRenderNode {
|
||||
label: Some("window"),
|
||||
});
|
||||
|
||||
let group0 = Self::bind_group_0(device, &layout0, &window_buffer);
|
||||
let uniform_group = Self::bind_group_0(device, &uniform_layout, &window_buffer);
|
||||
|
||||
let primitive_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
||||
entries: &core::array::from_fn::<_, { PrimitiveBuffers::LEN }, _>(|i| {
|
||||
@@ -110,9 +131,13 @@ impl UIRenderNode {
|
||||
let primitive_group =
|
||||
Self::primitive_group(device, &primitive_layout, primitives.buffers());
|
||||
|
||||
let tex_manager = GpuTextures::new(device, queue);
|
||||
let rsc_layout = Self::rsc_layout(device, &limits);
|
||||
let rsc_group = Self::rsc_group(device, &rsc_layout, &tex_manager);
|
||||
|
||||
let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
|
||||
label: Some("UI Shape Pipeline Layout"),
|
||||
bind_group_layouts: &[&layout0, &primitive_layout],
|
||||
bind_group_layouts: &[&uniform_layout, &primitive_layout, &rsc_layout],
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
let pipeline = device.create_render_pipeline(&RenderPipelineDescriptor {
|
||||
@@ -154,18 +179,22 @@ impl UIRenderNode {
|
||||
});
|
||||
|
||||
Self {
|
||||
layout0,
|
||||
group0,
|
||||
uniform_layout,
|
||||
uniform_group,
|
||||
primitive_layout,
|
||||
primitive_group,
|
||||
rsc_layout,
|
||||
rsc_group,
|
||||
pipeline,
|
||||
window_buffer,
|
||||
instance,
|
||||
primitives,
|
||||
limits,
|
||||
textures: tex_manager,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bind_group_0(
|
||||
fn bind_group_0(
|
||||
device: &Device,
|
||||
layout: &BindGroupLayout,
|
||||
window_buffer: &Buffer,
|
||||
@@ -180,18 +209,86 @@ impl UIRenderNode {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn primitive_group(
|
||||
fn primitive_group(
|
||||
device: &Device,
|
||||
layout: &BindGroupLayout,
|
||||
buffers: [&Buffer; PrimitiveBuffers::LEN],
|
||||
buffers: [(u32, &Buffer); PrimitiveBuffers::LEN],
|
||||
) -> BindGroup {
|
||||
device.create_bind_group(&BindGroupDescriptor {
|
||||
layout,
|
||||
entries: &buffers.each_ref().map(|b| BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: b.as_entire_binding(),
|
||||
entries: &buffers.map(|(binding, buf)| BindGroupEntry {
|
||||
binding,
|
||||
resource: buf.as_entire_binding(),
|
||||
}),
|
||||
label: Some("ui primitives"),
|
||||
})
|
||||
}
|
||||
|
||||
fn rsc_layout(device: &Device, limits: &UiLimits) -> BindGroupLayout {
|
||||
device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
||||
entries: &[
|
||||
BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: ShaderStages::FRAGMENT,
|
||||
ty: BindingType::Texture {
|
||||
sample_type: TextureSampleType::Float { filterable: false },
|
||||
view_dimension: TextureViewDimension::D2,
|
||||
multisampled: false,
|
||||
},
|
||||
count: Some(NonZero::new(limits.max_textures).unwrap()),
|
||||
},
|
||||
BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: ShaderStages::FRAGMENT,
|
||||
ty: BindingType::Sampler(SamplerBindingType::NonFiltering),
|
||||
count: Some(NonZero::new(limits.max_samplers).unwrap()),
|
||||
},
|
||||
],
|
||||
label: Some("ui rsc"),
|
||||
})
|
||||
}
|
||||
|
||||
fn rsc_group(
|
||||
device: &Device,
|
||||
layout: &BindGroupLayout,
|
||||
tex_manager: &GpuTextures,
|
||||
) -> BindGroup {
|
||||
device.create_bind_group(&BindGroupDescriptor {
|
||||
layout,
|
||||
entries: &[
|
||||
BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: BindingResource::TextureViewArray(&tex_manager.views()),
|
||||
},
|
||||
BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: BindingResource::SamplerArray(&tex_manager.samplers()),
|
||||
},
|
||||
],
|
||||
label: Some("ui rsc"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UiLimits {
|
||||
max_textures: u32,
|
||||
max_samplers: u32,
|
||||
}
|
||||
|
||||
impl Default for UiLimits {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
max_textures: 100000,
|
||||
max_samplers: 1000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UiLimits {
|
||||
pub fn max_binding_array_elements_per_shader_stage(&self) -> u32 {
|
||||
self.max_textures + self.max_samplers
|
||||
}
|
||||
pub fn max_binding_array_sampler_elements_per_shader_stage(&self) -> u32 {
|
||||
self.max_samplers
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,9 +35,9 @@ macro_rules! primitives {
|
||||
|
||||
impl PrimitiveBuffers {
|
||||
pub const LEN: usize = primitives!(@count $($name)*);
|
||||
pub fn buffers(&self) -> [&Buffer; Self::LEN] {
|
||||
pub fn buffers(&self) -> [(u32, &Buffer); Self::LEN] {
|
||||
[
|
||||
$(&self.$name.buffer)*
|
||||
$((<$ty>::BINDING, &self.$name.buffer),)*
|
||||
]
|
||||
}
|
||||
pub fn new(device: &Device) -> Self {
|
||||
@@ -46,7 +46,7 @@ macro_rules! primitives {
|
||||
device,
|
||||
BufferUsages::STORAGE | BufferUsages::COPY_DST,
|
||||
stringify!($name),
|
||||
))*
|
||||
),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,14 +62,10 @@ macro_rules! primitives {
|
||||
}
|
||||
)*
|
||||
};
|
||||
(@count $t1:tt, $($t:tt),+) => { 1 + gen!(@count $($t),+) };
|
||||
(@count $t1:tt $($t:tt)+) => { 1 + primitives!(@count $($t),+) };
|
||||
(@count $t:tt) => { 1 };
|
||||
}
|
||||
|
||||
primitives!(
|
||||
rects: RoundedRectData => 0,
|
||||
);
|
||||
|
||||
impl Primitives {
|
||||
pub fn write<P: Primitive>(&mut self, data: P, region: UiRegion) {
|
||||
let vec = P::vec(&mut self.data);
|
||||
@@ -83,11 +79,23 @@ impl Primitives {
|
||||
}
|
||||
}
|
||||
|
||||
primitives!(
|
||||
rects: RectPrimitive => 0,
|
||||
textures: TexturePrimitive => 1,
|
||||
);
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct RoundedRectData {
|
||||
pub struct RectPrimitive {
|
||||
pub color: Color<u8>,
|
||||
pub radius: f32,
|
||||
pub thickness: f32,
|
||||
pub inner_radius: f32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct TexturePrimitive {
|
||||
pub view_idx: u32,
|
||||
pub sampler_idx: u32,
|
||||
}
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
const RECT: u32 = 0;
|
||||
const TEXTURE: u32 = 1;
|
||||
|
||||
@group(0) @binding(0)
|
||||
var<uniform> window: WindowUniform;
|
||||
@group(1) @binding(RECT)
|
||||
var<storage> rects: array<RoundedRect>;
|
||||
var<storage> rects: array<Rect>;
|
||||
@group(1) @binding(TEXTURE)
|
||||
var<storage> textures: array<TextureInfo>;
|
||||
|
||||
struct Rect {
|
||||
color: u32,
|
||||
radius: f32,
|
||||
thickness: f32,
|
||||
inner_radius: f32,
|
||||
}
|
||||
|
||||
struct TextureInfo {
|
||||
view_idx: u32,
|
||||
sampler_idx: u32,
|
||||
}
|
||||
|
||||
@group(2) @binding(0)
|
||||
var views: binding_array<texture_2d<f32>>;
|
||||
@group(2) @binding(1)
|
||||
var samplers: binding_array<sampler>;
|
||||
|
||||
struct WindowUniform {
|
||||
dim: vec2<f32>,
|
||||
@@ -18,23 +38,18 @@ struct InstanceInput {
|
||||
@location(5) idx: u32,
|
||||
}
|
||||
|
||||
struct RoundedRect {
|
||||
color: u32,
|
||||
radius: f32,
|
||||
thickness: f32,
|
||||
inner_radius: f32,
|
||||
}
|
||||
|
||||
struct VertexOutput {
|
||||
@location(0) top_left: vec2<f32>,
|
||||
@location(1) bot_right: vec2<f32>,
|
||||
@location(2) binding: u32,
|
||||
@location(3) idx: u32,
|
||||
@location(2) uv: vec2<f32>,
|
||||
@location(3) binding: u32,
|
||||
@location(4) idx: u32,
|
||||
@builtin(position) clip_position: vec4<f32>,
|
||||
};
|
||||
|
||||
struct Region {
|
||||
pos: vec2<f32>,
|
||||
uv: vec2<f32>,
|
||||
top_left: vec2<f32>,
|
||||
bot_right: vec2<f32>,
|
||||
}
|
||||
@@ -50,12 +65,13 @@ fn vs_main(
|
||||
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>(
|
||||
let uv = vec2<f32>(
|
||||
f32(vi % 2u),
|
||||
f32(vi / 2u)
|
||||
) * size;
|
||||
pos = pos / window.dim * 2.0 - 1.0;
|
||||
);
|
||||
let pos = (top_left + uv * size) / window.dim * 2.0 - 1.0;
|
||||
out.clip_position = vec4<f32>(pos.x, -pos.y, 0.0, 1.0);
|
||||
out.uv = uv;
|
||||
out.binding = in.binding;
|
||||
out.idx = in.idx;
|
||||
out.top_left = top_left;
|
||||
@@ -69,19 +85,27 @@ fn fs_main(
|
||||
in: VertexOutput
|
||||
) -> @location(0) vec4<f32> {
|
||||
let pos = in.clip_position.xy;
|
||||
let region = Region(pos, in.top_left, in.bot_right);
|
||||
let region = Region(pos, in.uv, in.top_left, in.bot_right);
|
||||
let i = in.idx;
|
||||
switch in.binding {
|
||||
case RECT: {
|
||||
return draw_rounded_rect(region, rects[i]);
|
||||
}
|
||||
case TEXTURE: {
|
||||
return draw_texture(region, textures[i]);
|
||||
}
|
||||
default: {
|
||||
return vec4(1.0, 0.0, 1.0, 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_rounded_rect(region: Region, rect: RoundedRect) -> vec4<f32> {
|
||||
// TODO: this seems really inefficient (per frag indexing)?
|
||||
fn draw_texture(region: Region, info: TextureInfo) -> vec4<f32> {
|
||||
return textureSample(views[info.view_idx], samplers[info.sampler_idx], region.uv);
|
||||
}
|
||||
|
||||
fn draw_rounded_rect(region: Region, rect: Rect) -> vec4<f32> {
|
||||
var color = read_color(rect.color);
|
||||
|
||||
let edge = 0.5;
|
||||
@@ -106,7 +130,7 @@ fn distance_from_rect(pixel_pos: vec2<f32>, rect_center: vec2<f32>, rect_corner:
|
||||
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;
|
||||
return length(max(q, vec2(0.0))) - radius;
|
||||
}
|
||||
|
||||
fn read_color(c: u32) -> vec4<f32> {
|
||||
|
||||
98
src/render/texture.rs
Normal file
98
src/render/texture.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
use image::{DynamicImage, EncodableLayout};
|
||||
use wgpu::{util::DeviceExt, *};
|
||||
|
||||
use crate::TextureUpdates;
|
||||
|
||||
pub struct GpuTextures {
|
||||
device: Device,
|
||||
queue: Queue,
|
||||
views: Vec<TextureView>,
|
||||
samplers: Vec<Sampler>,
|
||||
no_views: Vec<TextureView>,
|
||||
}
|
||||
|
||||
impl GpuTextures {
|
||||
pub fn apply(&mut self, updates: TextureUpdates) -> bool {
|
||||
if let Some(images) = updates.images {
|
||||
for img in images {
|
||||
self.add_view(img);
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
fn add_view(&mut self, image: &DynamicImage) {
|
||||
let image = image.to_rgba8();
|
||||
let (width, height) = image.dimensions();
|
||||
let texture = self.device.create_texture_with_data(
|
||||
&self.queue,
|
||||
&TextureDescriptor {
|
||||
label: None,
|
||||
size: Extent3d {
|
||||
width,
|
||||
height,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: TextureDimension::D2,
|
||||
format: TextureFormat::Rgba8Unorm,
|
||||
usage: TextureUsages::TEXTURE_BINDING,
|
||||
view_formats: &[],
|
||||
},
|
||||
wgt::TextureDataOrder::MipMajor,
|
||||
image.as_bytes(),
|
||||
);
|
||||
let view = texture.create_view(&TextureViewDescriptor::default());
|
||||
self.views.push(view);
|
||||
}
|
||||
|
||||
pub fn new(device: &Device, queue: &Queue) -> Self {
|
||||
Self {
|
||||
device: device.clone(),
|
||||
queue: queue.clone(),
|
||||
views: Vec::new(),
|
||||
samplers: vec![default_sampler(device)],
|
||||
no_views: vec![null_texture_view(device)],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn views(&self) -> Vec<&TextureView> {
|
||||
if self.views.is_empty() {
|
||||
&self.no_views
|
||||
} else {
|
||||
&self.views
|
||||
}
|
||||
.iter()
|
||||
.by_ref()
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn samplers(&self) -> Vec<&Sampler> {
|
||||
self.samplers.iter().by_ref().collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn null_texture_view(device: &Device) -> TextureView {
|
||||
device
|
||||
.create_texture(&TextureDescriptor {
|
||||
label: Some("null"),
|
||||
size: Extent3d {
|
||||
width: 1,
|
||||
height: 1,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: TextureDimension::D2,
|
||||
format: TextureFormat::Rgba8Unorm,
|
||||
usage: TextureUsages::TEXTURE_BINDING,
|
||||
view_formats: &[],
|
||||
})
|
||||
.create_view(&TextureViewDescriptor::default())
|
||||
}
|
||||
|
||||
pub fn default_sampler(device: &Device) -> Sampler {
|
||||
device.create_sampler(&SamplerDescriptor::default())
|
||||
}
|
||||
@@ -32,7 +32,7 @@ impl<T: Pod> ArrBuf<T> {
|
||||
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);
|
||||
size = size.max(std::mem::size_of::<T>() as u64);
|
||||
}
|
||||
device.create_buffer(&BufferDescriptor {
|
||||
label: Some(label),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use gui::Ui;
|
||||
use ui::Ui;
|
||||
use winit::{
|
||||
application::ApplicationHandler,
|
||||
event::WindowEvent,
|
||||
|
||||
BIN
src/testing/assets/sungals.png
Executable file
BIN
src/testing/assets/sungals.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 8.7 KiB |
@@ -1,4 +1,4 @@
|
||||
use gui::{CursorState, Vec2};
|
||||
use ui::{CursorState, Vec2};
|
||||
use winit::event::WindowEvent;
|
||||
|
||||
use crate::testing::Client;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use app::App;
|
||||
use gui::*;
|
||||
use render::Renderer;
|
||||
use ui::*;
|
||||
use winit::{event::WindowEvent, event_loop::ActiveEventLoop, window::Window};
|
||||
|
||||
use crate::testing::input::Input;
|
||||
@@ -76,6 +76,8 @@ impl Client {
|
||||
let span_add_test = ui.add(Span::empty(Dir::RIGHT).id(&span_add));
|
||||
let main: WidgetId<Regioned> = ui.id();
|
||||
|
||||
let image_test = ui.add(image(include_bytes!("assets/sungals.png")));
|
||||
|
||||
fn switch_button<To>(
|
||||
color: UiColor,
|
||||
main: &WidgetId<Regioned>,
|
||||
@@ -104,8 +106,9 @@ impl Client {
|
||||
switch_button(UiColor::RED, &main, &pad_test),
|
||||
switch_button(UiColor::GREEN, &main, &span_test),
|
||||
switch_button(UiColor::BLUE, &main, &span_add_test),
|
||||
switch_button(UiColor::MAGENTA, &main, &image_test),
|
||||
)
|
||||
.span(Dir::RIGHT, [1, 1, 1]),
|
||||
.span(Dir::RIGHT, [1, 1, 1, 1]),
|
||||
);
|
||||
let test_button = Rect::new(Color::PURPLE)
|
||||
.radius(30)
|
||||
@@ -156,8 +159,8 @@ impl Client {
|
||||
match event {
|
||||
WindowEvent::CloseRequested => event_loop.exit(),
|
||||
WindowEvent::RedrawRequested => {
|
||||
let primitives = ui.update(self);
|
||||
self.renderer.update(primitives);
|
||||
let updates = ui.update(self);
|
||||
self.renderer.update(updates);
|
||||
self.renderer.draw()
|
||||
}
|
||||
WindowEvent::Resized(size) => self.renderer.resize(&size),
|
||||
|
||||
@@ -1,48 +1,51 @@
|
||||
use gui::{UIRenderNode, primitive::Primitives};
|
||||
use pollster::FutureExt;
|
||||
use std::sync::Arc;
|
||||
use wgpu::util::StagingBelt;
|
||||
use ui::{
|
||||
UiRenderUpdates,
|
||||
render::{UiLimits, UiRenderer},
|
||||
};
|
||||
use wgpu::{util::StagingBelt, *};
|
||||
use winit::{dpi::PhysicalSize, window::Window};
|
||||
|
||||
pub const CLEAR_COLOR: wgpu::Color = wgpu::Color::BLACK;
|
||||
pub const CLEAR_COLOR: Color = Color::BLACK;
|
||||
|
||||
pub struct Renderer {
|
||||
window: Arc<Window>,
|
||||
surface: wgpu::Surface<'static>,
|
||||
device: wgpu::Device,
|
||||
queue: wgpu::Queue,
|
||||
config: wgpu::SurfaceConfiguration,
|
||||
encoder: wgpu::CommandEncoder,
|
||||
surface: Surface<'static>,
|
||||
device: Device,
|
||||
queue: Queue,
|
||||
config: SurfaceConfiguration,
|
||||
encoder: CommandEncoder,
|
||||
staging_belt: StagingBelt,
|
||||
ui_node: UIRenderNode,
|
||||
ui: UiRenderer,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
pub fn update(&mut self, primitives: Option<&Primitives>) {
|
||||
self.ui_node.update(&self.device, &self.queue, primitives);
|
||||
pub fn update(&mut self, updates: UiRenderUpdates) {
|
||||
self.ui.update(&self.device, &self.queue, updates);
|
||||
}
|
||||
|
||||
pub fn draw(&mut self) {
|
||||
let output = self.surface.get_current_texture().unwrap();
|
||||
let view = output
|
||||
.texture
|
||||
.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
.create_view(&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 {
|
||||
let render_pass = &mut encoder.begin_render_pass(&RenderPassDescriptor {
|
||||
color_attachments: &[Some(RenderPassColorAttachment {
|
||||
view: &view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(CLEAR_COLOR),
|
||||
store: wgpu::StoreOp::Store,
|
||||
ops: Operations {
|
||||
load: LoadOp::Clear(CLEAR_COLOR),
|
||||
store: StoreOp::Store,
|
||||
},
|
||||
depth_slice: None,
|
||||
})],
|
||||
..Default::default()
|
||||
});
|
||||
self.ui_node.draw(render_pass);
|
||||
self.ui.draw(render_pass);
|
||||
}
|
||||
|
||||
self.queue.submit(std::iter::once(encoder.finish()));
|
||||
@@ -55,11 +58,11 @@ impl Renderer {
|
||||
self.config.width = size.width;
|
||||
self.config.height = size.height;
|
||||
self.surface.configure(&self.device, &self.config);
|
||||
self.ui_node.resize(size, &self.queue);
|
||||
self.ui.resize(size, &self.queue);
|
||||
}
|
||||
|
||||
fn create_encoder(device: &wgpu::Device) -> wgpu::CommandEncoder {
|
||||
device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||
fn create_encoder(device: &Device) -> CommandEncoder {
|
||||
device.create_command_encoder(&CommandEncoderDescriptor {
|
||||
label: Some("Render Encoder"),
|
||||
})
|
||||
}
|
||||
@@ -67,8 +70,8 @@ impl Renderer {
|
||||
pub fn new(window: Arc<Window>) -> Self {
|
||||
let size = window.inner_size();
|
||||
|
||||
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
|
||||
backends: wgpu::Backends::PRIMARY,
|
||||
let instance = Instance::new(&InstanceDescriptor {
|
||||
backends: Backends::PRIMARY,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
@@ -77,18 +80,28 @@ impl Renderer {
|
||||
.expect("Could not create window surface!");
|
||||
|
||||
let adapter = instance
|
||||
.request_adapter(&wgpu::RequestAdapterOptions {
|
||||
power_preference: wgpu::PowerPreference::default(),
|
||||
.request_adapter(&RequestAdapterOptions {
|
||||
power_preference: PowerPreference::default(),
|
||||
compatible_surface: Some(&surface),
|
||||
force_fallback_adapter: false,
|
||||
})
|
||||
.block_on()
|
||||
.expect("Could not get adapter!");
|
||||
|
||||
let ui_limits = UiLimits::default();
|
||||
|
||||
let (device, queue) = adapter
|
||||
.request_device(&wgpu::DeviceDescriptor {
|
||||
required_features: wgpu::Features::empty(),
|
||||
required_limits: wgpu::Limits::default(),
|
||||
.request_device(&DeviceDescriptor {
|
||||
required_features: Features::TEXTURE_BINDING_ARRAY
|
||||
| Features::PARTIALLY_BOUND_BINDING_ARRAY
|
||||
| Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING,
|
||||
required_limits: Limits {
|
||||
max_binding_array_elements_per_shader_stage: ui_limits
|
||||
.max_binding_array_elements_per_shader_stage(),
|
||||
max_binding_array_sampler_elements_per_shader_stage: ui_limits
|
||||
.max_binding_array_sampler_elements_per_shader_stage(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.block_on()
|
||||
@@ -102,12 +115,12 @@ impl Renderer {
|
||||
.find(|f| f.is_srgb())
|
||||
.unwrap_or(surface_caps.formats[0]);
|
||||
|
||||
let config = wgpu::SurfaceConfiguration {
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
let config = SurfaceConfiguration {
|
||||
usage: TextureUsages::RENDER_ATTACHMENT,
|
||||
format: surface_format,
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
present_mode: wgpu::PresentMode::AutoVsync,
|
||||
present_mode: PresentMode::AutoVsync,
|
||||
alpha_mode: surface_caps.alpha_modes[0],
|
||||
desired_maximum_frame_latency: 2,
|
||||
view_formats: vec![],
|
||||
@@ -118,7 +131,7 @@ impl Renderer {
|
||||
let staging_belt = StagingBelt::new(4096 * 4);
|
||||
let encoder = Self::create_encoder(&device);
|
||||
|
||||
let shape_pipeline = UIRenderNode::new(&device, &config);
|
||||
let shape_pipeline = UiRenderer::new(&device, &queue, &config, ui_limits);
|
||||
|
||||
Self {
|
||||
surface,
|
||||
@@ -127,7 +140,7 @@ impl Renderer {
|
||||
config,
|
||||
encoder,
|
||||
staging_belt,
|
||||
ui_node: shape_pipeline,
|
||||
ui: shape_pipeline,
|
||||
window,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
pub struct Id(u64);
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct IDTracker {
|
||||
pub struct IdTracker {
|
||||
free: Vec<Id>,
|
||||
cur: u64,
|
||||
}
|
||||
|
||||
impl IDTracker {
|
||||
impl IdTracker {
|
||||
#[allow(clippy::should_implement_trait)]
|
||||
pub fn next(&mut self) -> Id {
|
||||
if let Some(id) = self.free.pop() {
|
||||
|
||||
Reference in New Issue
Block a user