Add egui_wgpu crate (#1564)
Based on https://github.com/hasenbanck/egui_wgpu_backend `egui-wgpu` is now an official backend for `eframe` (opt-in). Use the `wgpu` feature flag on `eframe` and the `NativeOptions::renderer` settings to pick it. Co-authored-by: Nils Hasenbanck <nils@hasenbanck.de> Co-authored-by: Sven Niederberger <niederberger@embotech.com> Co-authored-by: Sven Niederberger <73159570+s-nie@users.noreply.github.com>
This commit is contained in:
parent
3d52cc8867
commit
931e716b97
32 changed files with 1540 additions and 101 deletions
2
.github/workflows/rust.yml
vendored
2
.github/workflows/rust.yml
vendored
|
@ -82,7 +82,7 @@ jobs:
|
||||||
override: true
|
override: true
|
||||||
- run: rustup target add wasm32-unknown-unknown
|
- run: rustup target add wasm32-unknown-unknown
|
||||||
- name: check
|
- name: check
|
||||||
run: cargo check -p eframe --lib --no-default-features --features persistence --target wasm32-unknown-unknown
|
run: cargo check -p eframe --lib --no-default-features --features glow,persistence --target wasm32-unknown-unknown
|
||||||
|
|
||||||
check_web_all_features:
|
check_web_all_features:
|
||||||
name: cargo check web --all-features
|
name: cargo check web --all-features
|
||||||
|
|
290
Cargo.lock
generated
290
Cargo.lock
generated
|
@ -132,6 +132,15 @@ version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ash"
|
||||||
|
version = "0.34.0+1.2.203"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0f780da53d0063880d45554306489f09dd8d1bda47688b4a57bc579119356df"
|
||||||
|
dependencies = [
|
||||||
|
"libloading",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-broadcast"
|
name = "async-broadcast"
|
||||||
version = "0.3.4"
|
version = "0.3.4"
|
||||||
|
@ -469,6 +478,12 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg_aliases"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cgl"
|
name = "cgl"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
@ -583,6 +598,16 @@ dependencies = [
|
||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "codespan-reporting"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||||
|
dependencies = [
|
||||||
|
"termcolor",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color_quant"
|
name = "color_quant"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -625,6 +650,12 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "copyless"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -865,6 +896,17 @@ dependencies = [
|
||||||
"eframe",
|
"eframe",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "d3d12"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2daefd788d1e96e0a9d66dee4b828b883509bc3ea9ce30665f04c3246372690c"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"libloading",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dark-light"
|
name = "dark-light"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -1081,6 +1123,7 @@ dependencies = [
|
||||||
"dark-light",
|
"dark-light",
|
||||||
"directories-next",
|
"directories-next",
|
||||||
"egui",
|
"egui",
|
||||||
|
"egui-wgpu",
|
||||||
"egui-winit",
|
"egui-winit",
|
||||||
"egui_glow",
|
"egui_glow",
|
||||||
"glow",
|
"glow",
|
||||||
|
@ -1110,6 +1153,18 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "egui-wgpu"
|
||||||
|
version = "0.18.0"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"egui",
|
||||||
|
"pollster",
|
||||||
|
"tracing",
|
||||||
|
"wgpu",
|
||||||
|
"winit",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "egui-winit"
|
name = "egui-winit"
|
||||||
version = "0.18.0"
|
version = "0.18.0"
|
||||||
|
@ -1135,7 +1190,6 @@ dependencies = [
|
||||||
"egui",
|
"egui",
|
||||||
"egui_demo_lib",
|
"egui_demo_lib",
|
||||||
"egui_extras",
|
"egui_extras",
|
||||||
"egui_glow",
|
|
||||||
"ehttp",
|
"ehttp",
|
||||||
"image",
|
"image",
|
||||||
"poll-promise",
|
"poll-promise",
|
||||||
|
@ -1466,6 +1520,15 @@ dependencies = [
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fxhash"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gdk-pixbuf-sys"
|
name = "gdk-pixbuf-sys"
|
||||||
version = "0.15.10"
|
version = "0.15.10"
|
||||||
|
@ -1694,6 +1757,45 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gpu-alloc"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7fc59e5f710e310e76e6707f86c561dd646f69a8876da9131703b2f717de818d"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"gpu-alloc-types",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gpu-alloc-types"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gpu-descriptor"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a538f217be4d405ff4719a283ca68323cc2384003eca5baaa87501e821c81dda"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"gpu-descriptor-types",
|
||||||
|
"hashbrown 0.11.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gpu-descriptor-types"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "363e3677e55ad168fef68cf9de3a4a310b53124c5e784c53a1d70e92d23f2126"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gtk-sys"
|
name = "gtk-sys"
|
||||||
version = "0.15.3"
|
version = "0.15.3"
|
||||||
|
@ -1737,6 +1839,9 @@ name = "hashbrown"
|
||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||||
|
dependencies = [
|
||||||
|
"ahash 0.7.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
|
@ -1766,6 +1871,12 @@ version = "0.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hexf-parse"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "humantime"
|
name = "humantime"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -1815,6 +1926,12 @@ dependencies = [
|
||||||
"hashbrown 0.11.2",
|
"hashbrown 0.11.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inplace_it"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90953f308a79fe6d62a4643e51f848fbfddcd05975a38e69fdf4ab86a7baf7ca"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
|
@ -1892,6 +2009,16 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "khronos-egl"
|
||||||
|
version = "4.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"libloading",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "khronos_api"
|
name = "khronos_api"
|
||||||
version = "3.1.0"
|
version = "3.1.0"
|
||||||
|
@ -2023,6 +2150,20 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "metal"
|
||||||
|
version = "0.23.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0514f491f4cc03632ab399ee01e2c1c1b12d3e1cf2d667c1ff5f87d6dcd2084"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"block",
|
||||||
|
"core-graphics-types",
|
||||||
|
"foreign-types",
|
||||||
|
"log",
|
||||||
|
"objc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "minimal-lexical"
|
name = "minimal-lexical"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -2067,6 +2208,24 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "naga"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3012f2dbcc79e8e0b5825a4836a7106a75dd9b2fe42c528163be0f572538c705"
|
||||||
|
dependencies = [
|
||||||
|
"bit-set",
|
||||||
|
"bitflags",
|
||||||
|
"codespan-reporting",
|
||||||
|
"hexf-parse",
|
||||||
|
"indexmap",
|
||||||
|
"log",
|
||||||
|
"num-traits",
|
||||||
|
"rustc-hash",
|
||||||
|
"spirv",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk"
|
name = "ndk"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -2566,6 +2725,12 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pollster"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5da3b0203fd7ee5720aa0b5e790b591aa5d3f41c3ed2c34a3a393382198af2f7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
|
@ -2591,6 +2756,12 @@ dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "profiling"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9145ac0af1d93c638c98c40cf7d25665f427b2a44ad0a99b1dccf3e2f25bb987"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "puffin"
|
name = "puffin"
|
||||||
version = "0.13.1"
|
version = "0.13.1"
|
||||||
|
@ -2667,6 +2838,12 @@ dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "range-alloc"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "raw-window-handle"
|
name = "raw-window-handle"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
|
@ -2749,6 +2926,12 @@ version = "0.6.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "renderdoc-sys"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "resvg"
|
name = "resvg"
|
||||||
version = "0.22.0"
|
version = "0.22.0"
|
||||||
|
@ -3153,6 +3336,16 @@ version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spirv"
|
||||||
|
version = "0.2.0+1.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "static_assertions"
|
name = "static_assertions"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -3506,7 +3699,7 @@ version = "1.6.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0"
|
checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10",
|
"cfg-if 1.0.0",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -3856,7 +4049,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc6a3cffdb686fbb24d9fb8f03a213803277ed2300f11026a3afe1f108dc021b"
|
checksum = "fc6a3cffdb686fbb24d9fb8f03a213803277ed2300f11026a3afe1f108dc021b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jni",
|
"jni",
|
||||||
"ndk-glue 0.5.2",
|
"ndk-glue 0.6.2",
|
||||||
"url",
|
"url",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"widestring",
|
"widestring",
|
||||||
|
@ -3897,6 +4090,97 @@ dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wgpu"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b97cd781ff044d6d697b632a2e212032c2e957d1afaa21dbf58069cbb8f78567"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec 0.7.2",
|
||||||
|
"js-sys",
|
||||||
|
"log",
|
||||||
|
"naga",
|
||||||
|
"parking_lot 0.11.2",
|
||||||
|
"raw-window-handle",
|
||||||
|
"smallvec",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"wasm-bindgen-futures",
|
||||||
|
"web-sys",
|
||||||
|
"wgpu-core",
|
||||||
|
"wgpu-hal",
|
||||||
|
"wgpu-types",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wgpu-core"
|
||||||
|
version = "0.12.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4688c000eb841ca55f7b35db659b78d6e1cd77d7caf8fb929f4e181f754047d"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec 0.7.2",
|
||||||
|
"bitflags",
|
||||||
|
"cfg_aliases",
|
||||||
|
"codespan-reporting",
|
||||||
|
"copyless",
|
||||||
|
"fxhash",
|
||||||
|
"log",
|
||||||
|
"naga",
|
||||||
|
"parking_lot 0.11.2",
|
||||||
|
"profiling",
|
||||||
|
"raw-window-handle",
|
||||||
|
"smallvec",
|
||||||
|
"thiserror",
|
||||||
|
"wgpu-hal",
|
||||||
|
"wgpu-types",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wgpu-hal"
|
||||||
|
version = "0.12.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d684ea6a34974a2fc19f1dfd183d11a62e22d75c4f187a574bb1224df8e056c2"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec 0.7.2",
|
||||||
|
"ash",
|
||||||
|
"bit-set",
|
||||||
|
"bitflags",
|
||||||
|
"block",
|
||||||
|
"core-graphics-types",
|
||||||
|
"d3d12",
|
||||||
|
"foreign-types",
|
||||||
|
"fxhash",
|
||||||
|
"glow",
|
||||||
|
"gpu-alloc",
|
||||||
|
"gpu-descriptor",
|
||||||
|
"inplace_it",
|
||||||
|
"js-sys",
|
||||||
|
"khronos-egl",
|
||||||
|
"libloading",
|
||||||
|
"log",
|
||||||
|
"metal",
|
||||||
|
"naga",
|
||||||
|
"objc",
|
||||||
|
"parking_lot 0.11.2",
|
||||||
|
"profiling",
|
||||||
|
"range-alloc",
|
||||||
|
"raw-window-handle",
|
||||||
|
"renderdoc-sys",
|
||||||
|
"thiserror",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
"wgpu-types",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wgpu-types"
|
||||||
|
version = "0.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "549533d9e1cdd4b4cda7718d33ff500fc4c34b5467b71d76b547ae0324f3b2a2"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "which"
|
name = "which"
|
||||||
version = "4.2.5"
|
version = "4.2.5"
|
||||||
|
|
|
@ -6,6 +6,7 @@ members = [
|
||||||
"egui_extras",
|
"egui_extras",
|
||||||
"egui_glium",
|
"egui_glium",
|
||||||
"egui_glow",
|
"egui_glow",
|
||||||
|
"egui-wgpu",
|
||||||
"egui-winit",
|
"egui-winit",
|
||||||
"egui",
|
"egui",
|
||||||
"emath",
|
"emath",
|
||||||
|
|
|
@ -165,6 +165,7 @@ These are the official egui integrations:
|
||||||
* [`eframe`](https://github.com/emilk/egui/tree/master/eframe) for compiling the same app to web/wasm and desktop/native. Uses `egui_glow` and `egui-winit`.
|
* [`eframe`](https://github.com/emilk/egui/tree/master/eframe) for compiling the same app to web/wasm and desktop/native. Uses `egui_glow` and `egui-winit`.
|
||||||
* [`egui_glium`](https://github.com/emilk/egui/tree/master/egui_glium) for compiling native apps with [Glium](https://github.com/glium/glium).
|
* [`egui_glium`](https://github.com/emilk/egui/tree/master/egui_glium) for compiling native apps with [Glium](https://github.com/glium/glium).
|
||||||
* [`egui_glow`](https://github.com/emilk/egui/tree/master/egui_glow) for rendering egui with [glow](https://github.com/grovesNL/glow) on native and web, and for making native apps.
|
* [`egui_glow`](https://github.com/emilk/egui/tree/master/egui_glow) for rendering egui with [glow](https://github.com/grovesNL/glow) on native and web, and for making native apps.
|
||||||
|
* [`egui-wgpu`](https://github.com/emilk/egui/tree/master/egui-wgpu) for [wgpu](https://crates.io/crates/wgpu) (WebGPU API).
|
||||||
* [`egui-winit`](https://github.com/emilk/egui/tree/master/egui-winit) for integrating with [winit](https://github.com/rust-windowing/winit).
|
* [`egui-winit`](https://github.com/emilk/egui/tree/master/egui-winit) for integrating with [winit](https://github.com/rust-windowing/winit).
|
||||||
|
|
||||||
### 3rd party integrations
|
### 3rd party integrations
|
||||||
|
@ -174,7 +175,6 @@ These are the official egui integrations:
|
||||||
* [`egui_glfw_gl`](https://github.com/cohaereo/egui_glfw_gl) for [GLFW](https://crates.io/crates/glfw).
|
* [`egui_glfw_gl`](https://github.com/cohaereo/egui_glfw_gl) for [GLFW](https://crates.io/crates/glfw).
|
||||||
* [`egui_sdl2_gl`](https://crates.io/crates/egui_sdl2_gl) for [SDL2](https://crates.io/crates/sdl2).
|
* [`egui_sdl2_gl`](https://crates.io/crates/egui_sdl2_gl) for [SDL2](https://crates.io/crates/sdl2).
|
||||||
* [`egui_vulkano`](https://github.com/derivator/egui_vulkano) for [Vulkano](https://github.com/vulkano-rs/vulkano).
|
* [`egui_vulkano`](https://github.com/derivator/egui_vulkano) for [Vulkano](https://github.com/vulkano-rs/vulkano).
|
||||||
* [`egui_wgpu_backend`](https://crates.io/crates/egui_wgpu_backend) for [wgpu](https://crates.io/crates/wgpu) (WebGPU API).
|
|
||||||
* [`egui_winit_vulkano`](https://github.com/hakolao/egui_winit_vulkano) for [Vulkano](https://github.com/vulkano-rs/vulkano).
|
* [`egui_winit_vulkano`](https://github.com/hakolao/egui_winit_vulkano) for [Vulkano](https://github.com/vulkano-rs/vulkano).
|
||||||
* [`egui-macroquad`](https://github.com/optozorax/egui-macroquad) for [macroquad](https://github.com/not-fl3/macroquad).
|
* [`egui-macroquad`](https://github.com/optozorax/egui-macroquad) for [macroquad](https://github.com/not-fl3/macroquad).
|
||||||
* [`egui-miniquad`](https://github.com/not-fl3/egui-miniquad) for [Miniquad](https://github.com/not-fl3/miniquad).
|
* [`egui-miniquad`](https://github.com/not-fl3/egui-miniquad) for [Miniquad](https://github.com/not-fl3/miniquad).
|
||||||
|
|
|
@ -6,6 +6,9 @@ NOTE: [`egui-winit`](../egui-winit/CHANGELOG.md), [`egui_glium`](../egui_glium/C
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
* `egui_glow`: remove calls to `gl.get_error` in release builds to speed up rendering ([#1583](https://github.com/emilk/egui/pull/1583)).
|
* `egui_glow`: remove calls to `gl.get_error` in release builds to speed up rendering ([#1583](https://github.com/emilk/egui/pull/1583)).
|
||||||
|
* Add `wgpu` rendering backed ([#1564](https://github.com/emilk/egui/pull/1564)):
|
||||||
|
* Add features "wgpu" and "glow"
|
||||||
|
* Add `NativeOptions::renderer` to switch between the rendering backends
|
||||||
|
|
||||||
|
|
||||||
## 0.18.0 - 2022-04-30
|
## 0.18.0 - 2022-04-30
|
||||||
|
|
|
@ -20,7 +20,7 @@ all-features = true
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["default_fonts"]
|
default = ["default_fonts", "glow"]
|
||||||
|
|
||||||
# detect dark mode system preference
|
# detect dark mode system preference
|
||||||
dark-light = ["dep:dark-light"]
|
dark-light = ["dep:dark-light"]
|
||||||
|
@ -29,6 +29,8 @@ dark-light = ["dep:dark-light"]
|
||||||
# If you plan on specifying your own fonts you may disable this feature.
|
# If you plan on specifying your own fonts you may disable this feature.
|
||||||
default_fonts = ["egui/default_fonts"]
|
default_fonts = ["egui/default_fonts"]
|
||||||
|
|
||||||
|
glow = ["dep:glow", "egui_glow"]
|
||||||
|
|
||||||
# Enable saving app state to disk.
|
# Enable saving app state to disk.
|
||||||
persistence = [
|
persistence = [
|
||||||
"directories-next",
|
"directories-next",
|
||||||
|
@ -49,19 +51,23 @@ screen_reader = [
|
||||||
"tts",
|
"tts",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Use WGPU as the backend instead of glow
|
||||||
|
wgpu = ["egui-wgpu"]
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
egui = { version = "0.18.0", path = "../egui", default-features = false, features = [
|
egui = { version = "0.18.0", path = "../egui", default-features = false, features = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"tracing",
|
"tracing",
|
||||||
] }
|
] }
|
||||||
egui_glow = { version = "0.18.0", path = "../egui_glow", default-features = false }
|
|
||||||
glow = "0.11"
|
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
|
||||||
# optional:
|
# optional:
|
||||||
|
egui_glow = { version = "0.18.0", path = "../egui_glow", optional = true, default-features = false }
|
||||||
|
egui-wgpu = { version = "0.18.0", path = "../egui-wgpu", optional = true, features = ["winit"] }
|
||||||
|
glow = { version = "0.11", optional = true }
|
||||||
ron = { version = "0.7", optional = true }
|
ron = { version = "0.7", optional = true }
|
||||||
serde = { version = "1", optional = true }
|
serde = { version = "1", optional = true, features = ["derive"] }
|
||||||
|
|
||||||
# -------------------------------------------
|
# -------------------------------------------
|
||||||
# native:
|
# native:
|
||||||
|
|
|
@ -27,6 +27,8 @@ sudo apt-get install libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev lib
|
||||||
|
|
||||||
You need to either use `edition = "2021"`, or set `resolver = "2"` in the `[workspace`] section of your to-level `Cargo.toml`. See [this link](https://doc.rust-lang.org/edition-guide/rust-2021/default-cargo-resolver.html) for more info.
|
You need to either use `edition = "2021"`, or set `resolver = "2"` in the `[workspace`] section of your to-level `Cargo.toml`. See [this link](https://doc.rust-lang.org/edition-guide/rust-2021/default-cargo-resolver.html) for more info.
|
||||||
|
|
||||||
|
You can opt-in to the using [`egui_wgpu`](https://github.com/emilk/egui/tree/master/egui_wgpu) for rendering by enabling the `wgpu` feature and setting `NativeOptions::renderer` to `Renderer::Wgpu`.
|
||||||
|
|
||||||
|
|
||||||
## Alternatives
|
## Alternatives
|
||||||
`eframe` is not the only way to write an app using `egui`! You can also try [`egui-miniquad`](https://github.com/not-fl3/egui-miniquad), [`bevy_egui`](https://github.com/mvlabat/bevy_egui), [`egui_sdl2_gl`](https://github.com/ArjunNair/egui_sdl2_gl), and others.
|
`eframe` is not the only way to write an app using `egui`! You can also try [`egui-miniquad`](https://github.com/not-fl3/egui-miniquad), [`bevy_egui`](https://github.com/mvlabat/bevy_egui), [`egui_sdl2_gl`](https://github.com/ArjunNair/egui_sdl2_gl), and others.
|
||||||
|
|
|
@ -27,7 +27,8 @@ pub struct CreationContext<'s> {
|
||||||
|
|
||||||
/// The [`glow::Context`] allows you to initialize OpenGL resources (e.g. shaders) that
|
/// The [`glow::Context`] allows you to initialize OpenGL resources (e.g. shaders) that
|
||||||
/// you might want to use later from a [`egui::PaintCallback`].
|
/// you might want to use later from a [`egui::PaintCallback`].
|
||||||
pub gl: std::rc::Rc<glow::Context>,
|
#[cfg(feature = "glow")]
|
||||||
|
pub gl: Option<std::rc::Rc<glow::Context>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -71,7 +72,17 @@ pub trait App {
|
||||||
/// Called once on shutdown, after [`Self::save`].
|
/// Called once on shutdown, after [`Self::save`].
|
||||||
///
|
///
|
||||||
/// If you need to abort an exit use [`Self::on_exit_event`].
|
/// If you need to abort an exit use [`Self::on_exit_event`].
|
||||||
fn on_exit(&mut self, _gl: &glow::Context) {}
|
///
|
||||||
|
/// To get a [`glow`] context you need to compile with the `glow` feature flag,
|
||||||
|
/// and run eframe with the glow backend.
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
|
fn on_exit(&mut self, _gl: Option<&glow::Context>) {}
|
||||||
|
|
||||||
|
/// Called once on shutdown, after [`Self::save`].
|
||||||
|
///
|
||||||
|
/// If you need to abort an exit use [`Self::on_exit_event`].
|
||||||
|
#[cfg(not(feature = "glow"))]
|
||||||
|
fn on_exit(&mut self) {}
|
||||||
|
|
||||||
// ---------
|
// ---------
|
||||||
// Settings:
|
// Settings:
|
||||||
|
@ -199,6 +210,9 @@ pub struct NativeOptions {
|
||||||
///
|
///
|
||||||
/// `egui` doesn't need the stencil buffer, so the default value is 0.
|
/// `egui` doesn't need the stencil buffer, so the default value is 0.
|
||||||
pub stencil_buffer: u8,
|
pub stencil_buffer: u8,
|
||||||
|
|
||||||
|
/// What rendering backend to use.
|
||||||
|
pub renderer: Renderer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NativeOptions {
|
impl Default for NativeOptions {
|
||||||
|
@ -219,10 +233,74 @@ impl Default for NativeOptions {
|
||||||
multisampling: 0,
|
multisampling: 0,
|
||||||
depth_buffer: 0,
|
depth_buffer: 0,
|
||||||
stencil_buffer: 0,
|
stencil_buffer: 0,
|
||||||
|
renderer: Renderer::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// What rendering backend to use.
|
||||||
|
///
|
||||||
|
/// You need to enable the "glow" and "wgpu" features to have a choice.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
|
||||||
|
pub enum Renderer {
|
||||||
|
/// Use [`egui_glow`] renderer for [`glow`](https://github.com/grovesNL/glow).
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
|
Glow,
|
||||||
|
|
||||||
|
/// Use [`egui_wgpu`] renderer for [`wgpu`](https://github.com/gfx-rs/wgpu).
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
|
Wgpu,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Renderer {
|
||||||
|
fn default() -> Self {
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
|
return Self::Glow;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "glow"))]
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
|
return Self::Wgpu;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "glow"))]
|
||||||
|
#[cfg(not(feature = "wgpu"))]
|
||||||
|
compile_error!("eframe: you must enable at least one of the rendering backend features: 'glow' or 'wgpu'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Renderer {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
|
Self::Glow => "glow".fmt(f),
|
||||||
|
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
|
Self::Wgpu => "wgpu".fmt(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::str::FromStr for Renderer {
|
||||||
|
type Err = String;
|
||||||
|
|
||||||
|
fn from_str(name: &str) -> Result<Self, String> {
|
||||||
|
match name.to_lowercase().as_str() {
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
|
"glow" => Ok(Self::Glow),
|
||||||
|
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
|
"wgpu" => Ok(Self::Wgpu),
|
||||||
|
|
||||||
|
_ => Err(format!("eframe renderer {name:?} is not available. Make sure that the corresponding eframe feature is enabled."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Image data for an application icon.
|
/// Image data for an application icon.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct IconData {
|
pub struct IconData {
|
||||||
|
@ -254,8 +332,9 @@ pub struct Frame {
|
||||||
pub storage: Option<Box<dyn Storage>>,
|
pub storage: Option<Box<dyn Storage>>,
|
||||||
|
|
||||||
/// A reference to the underlying [`glow`] (OpenGL) context.
|
/// A reference to the underlying [`glow`] (OpenGL) context.
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub gl: std::rc::Rc<glow::Context>,
|
pub gl: Option<std::rc::Rc<glow::Context>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
|
@ -288,8 +367,12 @@ impl Frame {
|
||||||
///
|
///
|
||||||
/// Note that all egui painting is deferred to after the call to [`App::update`]
|
/// Note that all egui painting is deferred to after the call to [`App::update`]
|
||||||
/// ([`egui`] only collects [`egui::Shape`]s and then eframe paints them all in one go later on).
|
/// ([`egui`] only collects [`egui::Shape`]s and then eframe paints them all in one go later on).
|
||||||
pub fn gl(&self) -> &std::rc::Rc<glow::Context> {
|
///
|
||||||
&self.gl
|
/// To get a [`glow`] context you need to compile with the `glow` feature flag,
|
||||||
|
/// and run eframe with the glow backend.
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
|
pub fn gl(&self) -> Option<&std::rc::Rc<glow::Context>> {
|
||||||
|
self.gl.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Signal the app to stop/exit/quit the app (only works for native apps, not web apps).
|
/// Signal the app to stop/exit/quit the app (only works for native apps, not web apps).
|
||||||
|
|
|
@ -56,7 +56,10 @@
|
||||||
#![allow(clippy::needless_doctest_main)]
|
#![allow(clippy::needless_doctest_main)]
|
||||||
|
|
||||||
// Re-export all useful libraries:
|
// Re-export all useful libraries:
|
||||||
pub use {egui, egui::emath, egui::epaint, glow};
|
pub use {egui, egui::emath, egui::epaint};
|
||||||
|
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
|
pub use {egui_glow, glow};
|
||||||
|
|
||||||
mod epi;
|
mod epi;
|
||||||
|
|
||||||
|
@ -142,7 +145,21 @@ mod native;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
#[allow(clippy::needless_pass_by_value)]
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
pub fn run_native(app_name: &str, native_options: NativeOptions, app_creator: AppCreator) -> ! {
|
pub fn run_native(app_name: &str, native_options: NativeOptions, app_creator: AppCreator) -> ! {
|
||||||
native::run(app_name, &native_options, app_creator)
|
let renderer = native_options.renderer;
|
||||||
|
|
||||||
|
match renderer {
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
|
Renderer::Glow => {
|
||||||
|
tracing::debug!("Using the glow renderer");
|
||||||
|
native::run::run_glow(app_name, &native_options, app_creator)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
|
Renderer::Wgpu => {
|
||||||
|
tracing::debug!("Using the wgpu renderer");
|
||||||
|
native::run::run_wgpu(app_name, &native_options, app_creator)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -28,6 +28,7 @@ pub fn window_builder(
|
||||||
multisampling: _, // used in `fn create_display`
|
multisampling: _, // used in `fn create_display`
|
||||||
depth_buffer: _, // used in `fn create_display`
|
depth_buffer: _, // used in `fn create_display`
|
||||||
stencil_buffer: _, // used in `fn create_display`
|
stencil_buffer: _, // used in `fn create_display`
|
||||||
|
renderer: _, // used in `fn run_native`
|
||||||
} = native_options;
|
} = native_options;
|
||||||
|
|
||||||
let window_icon = icon_data.clone().and_then(load_icon);
|
let window_icon = icon_data.clone().and_then(load_icon);
|
||||||
|
@ -159,10 +160,10 @@ pub struct EpiIntegration {
|
||||||
|
|
||||||
impl EpiIntegration {
|
impl EpiIntegration {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
gl: std::rc::Rc<glow::Context>,
|
|
||||||
max_texture_side: usize,
|
max_texture_side: usize,
|
||||||
window: &winit::window::Window,
|
window: &winit::window::Window,
|
||||||
storage: Option<Box<dyn epi::Storage>>,
|
storage: Option<Box<dyn epi::Storage>>,
|
||||||
|
#[cfg(feature = "glow")] gl: Option<std::rc::Rc<glow::Context>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let egui_ctx = egui::Context::default();
|
let egui_ctx = egui::Context::default();
|
||||||
|
|
||||||
|
@ -179,6 +180,7 @@ impl EpiIntegration {
|
||||||
},
|
},
|
||||||
output: Default::default(),
|
output: Default::default(),
|
||||||
storage,
|
storage,
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
gl,
|
gl,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
mod epi_integration;
|
mod epi_integration;
|
||||||
mod run;
|
pub mod run;
|
||||||
|
|
||||||
/// File storage which can be used by native backends.
|
/// File storage which can be used by native backends.
|
||||||
#[cfg(feature = "persistence")]
|
#[cfg(feature = "persistence")]
|
||||||
pub mod file_storage;
|
pub mod file_storage;
|
||||||
|
|
||||||
pub use run::run;
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ use egui_winit::winit;
|
||||||
|
|
||||||
struct RequestRepaintEvent;
|
struct RequestRepaintEvent;
|
||||||
|
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn create_display(
|
fn create_display(
|
||||||
native_options: &NativeOptions,
|
native_options: &NativeOptions,
|
||||||
|
@ -37,13 +38,18 @@ fn create_display(
|
||||||
pub use epi::NativeOptions;
|
pub use epi::NativeOptions;
|
||||||
|
|
||||||
/// Run an egui app
|
/// Run an egui app
|
||||||
#[allow(unsafe_code)]
|
#[cfg(feature = "glow")]
|
||||||
pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi::AppCreator) -> ! {
|
pub fn run_glow(
|
||||||
|
app_name: &str,
|
||||||
|
native_options: &epi::NativeOptions,
|
||||||
|
app_creator: epi::AppCreator,
|
||||||
|
) -> ! {
|
||||||
let storage = epi_integration::create_storage(app_name);
|
let storage = epi_integration::create_storage(app_name);
|
||||||
let window_settings = epi_integration::load_window_settings(storage.as_deref());
|
let window_settings = epi_integration::load_window_settings(storage.as_deref());
|
||||||
|
let event_loop = winit::event_loop::EventLoop::with_user_event();
|
||||||
|
|
||||||
let window_builder =
|
let window_builder =
|
||||||
epi_integration::window_builder(native_options, &window_settings).with_title(app_name);
|
epi_integration::window_builder(native_options, &window_settings).with_title(app_name);
|
||||||
let event_loop = winit::event_loop::EventLoop::with_user_event();
|
|
||||||
let (gl_window, gl) = create_display(native_options, window_builder, &event_loop);
|
let (gl_window, gl) = create_display(native_options, window_builder, &event_loop);
|
||||||
let gl = std::rc::Rc::new(gl);
|
let gl = std::rc::Rc::new(gl);
|
||||||
|
|
||||||
|
@ -51,10 +57,10 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi
|
||||||
.unwrap_or_else(|error| panic!("some OpenGL error occurred {}\n", error));
|
.unwrap_or_else(|error| panic!("some OpenGL error occurred {}\n", error));
|
||||||
|
|
||||||
let mut integration = epi_integration::EpiIntegration::new(
|
let mut integration = epi_integration::EpiIntegration::new(
|
||||||
gl.clone(),
|
|
||||||
painter.max_texture_side(),
|
painter.max_texture_side(),
|
||||||
gl_window.window(),
|
gl_window.window(),
|
||||||
storage,
|
storage,
|
||||||
|
Some(gl.clone()),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -68,7 +74,7 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi
|
||||||
egui_ctx: integration.egui_ctx.clone(),
|
egui_ctx: integration.egui_ctx.clone(),
|
||||||
integration_info: integration.frame.info(),
|
integration_info: integration.frame.info(),
|
||||||
storage: integration.frame.storage(),
|
storage: integration.frame.storage(),
|
||||||
gl: gl.clone(),
|
gl: Some(gl.clone()),
|
||||||
});
|
});
|
||||||
|
|
||||||
if app.warm_up_enabled() {
|
if app.warm_up_enabled() {
|
||||||
|
@ -78,22 +84,14 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi
|
||||||
let mut is_focused = true;
|
let mut is_focused = true;
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| {
|
event_loop.run(move |event, _, control_flow| {
|
||||||
|
let window = gl_window.window();
|
||||||
|
|
||||||
let mut redraw = || {
|
let mut redraw = || {
|
||||||
#[cfg(feature = "puffin")]
|
#[cfg(feature = "puffin")]
|
||||||
puffin::GlobalProfiler::lock().new_frame();
|
puffin::GlobalProfiler::lock().new_frame();
|
||||||
|
|
||||||
if !is_focused {
|
|
||||||
// On Mac, a minimized Window uses up all CPU: https://github.com/emilk/egui/issues/325
|
|
||||||
// We can't know if we are minimized: https://github.com/rust-windowing/winit/issues/208
|
|
||||||
// But we know if we are focused (in foreground). When minimized, we are not focused.
|
|
||||||
// However, a user may want an egui with an animation in the background,
|
|
||||||
// so we still need to repaint quite fast.
|
|
||||||
crate::profile_scope!("bg_sleep");
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
|
||||||
}
|
|
||||||
|
|
||||||
crate::profile_scope!("frame");
|
crate::profile_scope!("frame");
|
||||||
let screen_size_in_pixels: [u32; 2] = gl_window.window().inner_size().into();
|
|
||||||
|
let screen_size_in_pixels: [u32; 2] = window.inner_size().into();
|
||||||
|
|
||||||
egui_glow::painter::clear(
|
egui_glow::painter::clear(
|
||||||
&gl,
|
&gl,
|
||||||
|
@ -106,9 +104,9 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi
|
||||||
needs_repaint,
|
needs_repaint,
|
||||||
textures_delta,
|
textures_delta,
|
||||||
shapes,
|
shapes,
|
||||||
} = integration.update(app.as_mut(), gl_window.window());
|
} = integration.update(app.as_mut(), window);
|
||||||
|
|
||||||
integration.handle_platform_output(gl_window.window(), platform_output);
|
integration.handle_platform_output(window, platform_output);
|
||||||
|
|
||||||
let clipped_primitives = {
|
let clipped_primitives = {
|
||||||
crate::profile_scope!("tessellate");
|
crate::profile_scope!("tessellate");
|
||||||
|
@ -127,18 +125,26 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi
|
||||||
gl_window.swap_buffers().unwrap();
|
gl_window.swap_buffers().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
*control_flow = if integration.should_quit() {
|
||||||
*control_flow = if integration.should_quit() {
|
winit::event_loop::ControlFlow::Exit
|
||||||
winit::event_loop::ControlFlow::Exit
|
} else if needs_repaint {
|
||||||
} else if needs_repaint {
|
window.request_redraw();
|
||||||
gl_window.window().request_redraw();
|
winit::event_loop::ControlFlow::Poll
|
||||||
winit::event_loop::ControlFlow::Poll
|
} else {
|
||||||
} else {
|
winit::event_loop::ControlFlow::Wait
|
||||||
winit::event_loop::ControlFlow::Wait
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
integration.maybe_autosave(app.as_mut(), gl_window.window());
|
integration.maybe_autosave(app.as_mut(), window);
|
||||||
|
|
||||||
|
if !is_focused {
|
||||||
|
// On Mac, a minimized Window uses up all CPU: https://github.com/emilk/egui/issues/325
|
||||||
|
// We can't know if we are minimized: https://github.com/rust-windowing/winit/issues/208
|
||||||
|
// But we know if we are focused (in foreground). When minimized, we are not focused.
|
||||||
|
// However, a user may want an egui with an animation in the background,
|
||||||
|
// so we still need to repaint quite fast.
|
||||||
|
crate::profile_scope!("bg_sleep");
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
|
@ -149,35 +155,194 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi
|
||||||
winit::event::Event::RedrawRequested(_) if !cfg!(windows) => redraw(),
|
winit::event::Event::RedrawRequested(_) if !cfg!(windows) => redraw(),
|
||||||
|
|
||||||
winit::event::Event::WindowEvent { event, .. } => {
|
winit::event::Event::WindowEvent { event, .. } => {
|
||||||
if let winit::event::WindowEvent::Focused(new_focused) = event {
|
match &event {
|
||||||
is_focused = new_focused;
|
winit::event::WindowEvent::Focused(new_focused) => {
|
||||||
}
|
is_focused = *new_focused;
|
||||||
|
}
|
||||||
if let winit::event::WindowEvent::Resized(physical_size) = &event {
|
winit::event::WindowEvent::Resized(physical_size) => {
|
||||||
gl_window.resize(*physical_size);
|
// Resize with 0 width and height is used by winit to signal a minimize event on Windows.
|
||||||
} else if let glutin::event::WindowEvent::ScaleFactorChanged {
|
// See: https://github.com/rust-windowing/winit/issues/208
|
||||||
new_inner_size,
|
// This solves an issue where the app would panic when minimizing on Windows.
|
||||||
..
|
if physical_size.width > 0 && physical_size.height > 0 {
|
||||||
} = &event
|
gl_window.resize(*physical_size);
|
||||||
{
|
}
|
||||||
gl_window.resize(**new_inner_size);
|
}
|
||||||
|
winit::event::WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
|
||||||
|
gl_window.resize(**new_inner_size);
|
||||||
|
}
|
||||||
|
winit::event::WindowEvent::CloseRequested => {
|
||||||
|
*control_flow = winit::event_loop::ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
integration.on_event(app.as_mut(), &event);
|
integration.on_event(app.as_mut(), &event);
|
||||||
if integration.should_quit() {
|
if integration.should_quit() {
|
||||||
*control_flow = winit::event_loop::ControlFlow::Exit;
|
*control_flow = winit::event_loop::ControlFlow::Exit;
|
||||||
}
|
}
|
||||||
|
window.request_redraw(); // TODO: ask egui if the events warrants a repaint instead
|
||||||
gl_window.window().request_redraw(); // TODO: ask egui if the events warrants a repaint instead
|
|
||||||
}
|
}
|
||||||
winit::event::Event::LoopDestroyed => {
|
winit::event::Event::LoopDestroyed => {
|
||||||
integration.save(&mut *app, gl_window.window());
|
integration.save(&mut *app, window);
|
||||||
app.on_exit(&gl);
|
app.on_exit(Some(&gl));
|
||||||
painter.destroy();
|
painter.destroy();
|
||||||
}
|
}
|
||||||
winit::event::Event::UserEvent(RequestRepaintEvent) => {
|
winit::event::Event::UserEvent(RequestRepaintEvent) => window.request_redraw(),
|
||||||
gl_window.window().request_redraw();
|
_ => (),
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: merge with with the clone above
|
||||||
|
/// Run an egui app
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
|
pub fn run_wgpu(
|
||||||
|
app_name: &str,
|
||||||
|
native_options: &epi::NativeOptions,
|
||||||
|
app_creator: epi::AppCreator,
|
||||||
|
) -> ! {
|
||||||
|
let storage = epi_integration::create_storage(app_name);
|
||||||
|
let window_settings = epi_integration::load_window_settings(storage.as_deref());
|
||||||
|
let event_loop = winit::event_loop::EventLoop::with_user_event();
|
||||||
|
|
||||||
|
let window = epi_integration::window_builder(native_options, &window_settings)
|
||||||
|
.with_title(app_name)
|
||||||
|
.build(&event_loop)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// SAFETY: `window` must outlive `painter`.
|
||||||
|
#[allow(unsafe_code)]
|
||||||
|
let mut painter = unsafe {
|
||||||
|
egui_wgpu::winit::Painter::new(&window, native_options.multisampling.max(1) as _)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut integration = epi_integration::EpiIntegration::new(
|
||||||
|
painter.max_texture_side(),
|
||||||
|
&window,
|
||||||
|
storage,
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
let event_loop_proxy = egui::mutex::Mutex::new(event_loop.create_proxy());
|
||||||
|
integration.egui_ctx.set_request_repaint_callback(move || {
|
||||||
|
event_loop_proxy.lock().send_event(RequestRepaintEvent).ok();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut app = app_creator(&epi::CreationContext {
|
||||||
|
egui_ctx: integration.egui_ctx.clone(),
|
||||||
|
integration_info: integration.frame.info(),
|
||||||
|
storage: integration.frame.storage(),
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
|
gl: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
if app.warm_up_enabled() {
|
||||||
|
integration.warm_up(app.as_mut(), &window);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut is_focused = true;
|
||||||
|
|
||||||
|
event_loop.run(move |event, _, control_flow| {
|
||||||
|
let window = &window;
|
||||||
|
|
||||||
|
let mut redraw = || {
|
||||||
|
#[cfg(feature = "puffin")]
|
||||||
|
puffin::GlobalProfiler::lock().new_frame();
|
||||||
|
crate::profile_scope!("frame");
|
||||||
|
|
||||||
|
let egui::FullOutput {
|
||||||
|
platform_output,
|
||||||
|
needs_repaint,
|
||||||
|
textures_delta,
|
||||||
|
shapes,
|
||||||
|
} = integration.update(app.as_mut(), window);
|
||||||
|
|
||||||
|
integration.handle_platform_output(window, platform_output);
|
||||||
|
|
||||||
|
let clipped_primitives = {
|
||||||
|
crate::profile_scope!("tessellate");
|
||||||
|
integration.egui_ctx.tessellate(shapes)
|
||||||
|
};
|
||||||
|
|
||||||
|
painter.paint_and_update_textures(
|
||||||
|
integration.egui_ctx.pixels_per_point(),
|
||||||
|
app.clear_color(&integration.egui_ctx.style().visuals),
|
||||||
|
&clipped_primitives,
|
||||||
|
&textures_delta,
|
||||||
|
);
|
||||||
|
|
||||||
|
*control_flow = if integration.should_quit() {
|
||||||
|
winit::event_loop::ControlFlow::Exit
|
||||||
|
} else if needs_repaint {
|
||||||
|
window.request_redraw();
|
||||||
|
winit::event_loop::ControlFlow::Poll
|
||||||
|
} else {
|
||||||
|
winit::event_loop::ControlFlow::Wait
|
||||||
|
};
|
||||||
|
|
||||||
|
integration.maybe_autosave(app.as_mut(), window);
|
||||||
|
|
||||||
|
if !is_focused {
|
||||||
|
// On Mac, a minimized Window uses up all CPU: https://github.com/emilk/egui/issues/325
|
||||||
|
// We can't know if we are minimized: https://github.com/rust-windowing/winit/issues/208
|
||||||
|
// But we know if we are focused (in foreground). When minimized, we are not focused.
|
||||||
|
// However, a user may want an egui with an animation in the background,
|
||||||
|
// so we still need to repaint quite fast.
|
||||||
|
crate::profile_scope!("bg_sleep");
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match event {
|
||||||
|
// Platform-dependent event handlers to workaround a winit bug
|
||||||
|
// See: https://github.com/rust-windowing/winit/issues/987
|
||||||
|
// See: https://github.com/rust-windowing/winit/issues/1619
|
||||||
|
winit::event::Event::RedrawEventsCleared if cfg!(windows) => redraw(),
|
||||||
|
winit::event::Event::RedrawRequested(_) if !cfg!(windows) => redraw(),
|
||||||
|
|
||||||
|
winit::event::Event::WindowEvent { event, .. } => {
|
||||||
|
match &event {
|
||||||
|
winit::event::WindowEvent::Focused(new_focused) => {
|
||||||
|
is_focused = *new_focused;
|
||||||
|
}
|
||||||
|
winit::event::WindowEvent::Resized(physical_size) => {
|
||||||
|
// Resize with 0 width and height is used by winit to signal a minimize event on Windows.
|
||||||
|
// See: https://github.com/rust-windowing/winit/issues/208
|
||||||
|
// This solves an issue where the app would panic when minimizing on Windows.
|
||||||
|
if physical_size.width > 0 && physical_size.height > 0 {
|
||||||
|
painter.on_window_resized(physical_size.width, physical_size.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
winit::event::WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
|
||||||
|
painter.on_window_resized(new_inner_size.width, new_inner_size.height);
|
||||||
|
}
|
||||||
|
winit::event::WindowEvent::CloseRequested => {
|
||||||
|
*control_flow = winit::event_loop::ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
integration.on_event(app.as_mut(), &event);
|
||||||
|
if integration.should_quit() {
|
||||||
|
*control_flow = winit::event_loop::ControlFlow::Exit;
|
||||||
|
}
|
||||||
|
window.request_redraw(); // TODO: ask egui if the events warrants a repaint instead
|
||||||
|
}
|
||||||
|
winit::event::Event::LoopDestroyed => {
|
||||||
|
integration.save(&mut *app, window);
|
||||||
|
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
|
app.on_exit(None);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "glow"))]
|
||||||
|
app.on_exit();
|
||||||
|
|
||||||
|
painter.destroy();
|
||||||
|
}
|
||||||
|
winit::event::Event::UserEvent(RequestRepaintEvent) => window.request_redraw(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -167,14 +167,16 @@ impl AppRunner {
|
||||||
egui_ctx: egui_ctx.clone(),
|
egui_ctx: egui_ctx.clone(),
|
||||||
integration_info: info.clone(),
|
integration_info: info.clone(),
|
||||||
storage: Some(&storage),
|
storage: Some(&storage),
|
||||||
gl: painter.painter.gl().clone(),
|
#[cfg(feature = "glow")]
|
||||||
|
gl: Some(painter.painter.gl().clone()),
|
||||||
});
|
});
|
||||||
|
|
||||||
let frame = epi::Frame {
|
let frame = epi::Frame {
|
||||||
info,
|
info,
|
||||||
output: Default::default(),
|
output: Default::default(),
|
||||||
storage: Some(Box::new(storage)),
|
storage: Some(Box::new(storage)),
|
||||||
gl: painter.gl().clone(),
|
#[cfg(feature = "glow")]
|
||||||
|
gl: Some(painter.gl().clone()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let needs_repaint: std::sync::Arc<NeedRepaint> = Default::default();
|
let needs_repaint: std::sync::Arc<NeedRepaint> = Default::default();
|
||||||
|
|
37
egui-wgpu/Cargo.toml
Normal file
37
egui-wgpu/Cargo.toml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
[package]
|
||||||
|
name = "egui-wgpu"
|
||||||
|
version = "0.18.0"
|
||||||
|
description = "Bindings for using egui natively using the wgpu library"
|
||||||
|
authors = [
|
||||||
|
"Nils Hasenbanck <nils@hasenbanck.de>",
|
||||||
|
"embotech <opensource@embotech.com>",
|
||||||
|
"Emil Ernerfeldt <emil.ernerfeldt@gmail.com>",
|
||||||
|
]
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.60"
|
||||||
|
homepage = "https://github.com/emilk/egui/tree/master/egui-wgpu"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
readme = "README.md"
|
||||||
|
repository = "https://github.com/emilk/egui/tree/master/egui-wgpu"
|
||||||
|
categories = ["gui", "game-development"]
|
||||||
|
keywords = ["wgpu", "egui", "gui", "gamedev"]
|
||||||
|
include = ["../LICENSE-APACHE", "../LICENSE-MIT", "**/*.rs", "Cargo.toml"]
|
||||||
|
|
||||||
|
|
||||||
|
[features]
|
||||||
|
# Make it easy to create bindings for winit.
|
||||||
|
winit = ["dep:pollster", "dep:winit"]
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
egui = { version = "0.18.1", path = "../egui", default-features = false, features = [
|
||||||
|
"bytemuck",
|
||||||
|
] }
|
||||||
|
|
||||||
|
bytemuck = "1.7"
|
||||||
|
tracing = "0.1"
|
||||||
|
wgpu = { version = "0.12", features = ["webgl"] }
|
||||||
|
|
||||||
|
# Optional:
|
||||||
|
pollster = { version = "0.2", optional = true }
|
||||||
|
winit = { version = "0.26", optional = true }
|
10
egui-wgpu/README.md
Normal file
10
egui-wgpu/README.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# egui-wgpu
|
||||||
|
|
||||||
|
[](https://crates.io/crates/egui-wgpu)
|
||||||
|
[](https://docs.rs/egui-wgpu)
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
This crates provides bindings between [`egui`](https://github.com/emilk/egui) and [wgpu](https://crates.io/crates/wgpu).
|
||||||
|
|
||||||
|
This was originally hosted at https://github.com/hasenbanck/egui_wgpu_backend
|
86
egui-wgpu/src/egui.wgsl
Normal file
86
egui-wgpu/src/egui.wgsl
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
// Vertex shader bindings
|
||||||
|
|
||||||
|
struct VertexOutput {
|
||||||
|
[[location(0)]] tex_coord: vec2<f32>;
|
||||||
|
[[location(1)]] color: vec4<f32>;
|
||||||
|
[[builtin(position)]] position: vec4<f32>;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Locals {
|
||||||
|
screen_size: vec2<f32>;
|
||||||
|
};
|
||||||
|
[[group(0), binding(0)]] var<uniform> r_locals: Locals;
|
||||||
|
|
||||||
|
// 0-1 from 0-255
|
||||||
|
fn linear_from_srgb(srgb: vec3<f32>) -> vec3<f32> {
|
||||||
|
let cutoff = srgb < vec3<f32>(10.31475);
|
||||||
|
let lower = srgb / vec3<f32>(3294.6);
|
||||||
|
let higher = pow((srgb + vec3<f32>(14.025)) / vec3<f32>(269.025), vec3<f32>(2.4));
|
||||||
|
return select(higher, lower, cutoff);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[stage(vertex)]]
|
||||||
|
fn vs_main(
|
||||||
|
[[location(0)]] a_pos: vec2<f32>,
|
||||||
|
[[location(1)]] a_tex_coord: vec2<f32>,
|
||||||
|
[[location(2)]] a_color: u32,
|
||||||
|
) -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
out.tex_coord = a_tex_coord;
|
||||||
|
|
||||||
|
// [u8; 4] SRGB as u32 -> [r, g, b, a]
|
||||||
|
let color = vec4<f32>(
|
||||||
|
f32(a_color & 255u),
|
||||||
|
f32((a_color >> 8u) & 255u),
|
||||||
|
f32((a_color >> 16u) & 255u),
|
||||||
|
f32((a_color >> 24u) & 255u),
|
||||||
|
);
|
||||||
|
out.color = vec4<f32>(linear_from_srgb(color.rgb), color.a / 255.0);
|
||||||
|
|
||||||
|
out.position = vec4<f32>(
|
||||||
|
2.0 * a_pos.x / r_locals.screen_size.x - 1.0,
|
||||||
|
1.0 - 2.0 * a_pos.y / r_locals.screen_size.y,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[stage(vertex)]]
|
||||||
|
fn vs_conv_main(
|
||||||
|
[[location(0)]] a_pos: vec2<f32>,
|
||||||
|
[[location(1)]] a_tex_coord: vec2<f32>,
|
||||||
|
[[location(2)]] a_color: u32,
|
||||||
|
) -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
out.tex_coord = a_tex_coord;
|
||||||
|
|
||||||
|
// [u8; 4] SRGB as u32 -> [r, g, b, a]
|
||||||
|
let color = vec4<f32>(
|
||||||
|
f32(a_color & 255u),
|
||||||
|
f32((a_color >> 8u) & 255u),
|
||||||
|
f32((a_color >> 16u) & 255u),
|
||||||
|
f32((a_color >> 24u) & 255u),
|
||||||
|
);
|
||||||
|
out.color = vec4<f32>(color.rgba / 255.0);
|
||||||
|
|
||||||
|
out.position = vec4<f32>(
|
||||||
|
2.0 * a_pos.x / r_locals.screen_size.x - 1.0,
|
||||||
|
1.0 - 2.0 * a_pos.y / r_locals.screen_size.y,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fragment shader bindings
|
||||||
|
|
||||||
|
[[group(1), binding(0)]] var r_tex_color: texture_2d<f32>;
|
||||||
|
[[group(1), binding(1)]] var r_tex_sampler: sampler;
|
||||||
|
|
||||||
|
[[stage(fragment)]]
|
||||||
|
fn fs_main(in: VertexOutput) -> [[location(0)]] vec4<f32> {
|
||||||
|
return in.color * textureSample(r_tex_color, r_tex_sampler, in.tex_coord);
|
||||||
|
}
|
12
egui-wgpu/src/lib.rs
Normal file
12
egui-wgpu/src/lib.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
//! This crates provides bindings between [`egui`](https://github.com/emilk/egui) and [wgpu](https://crates.io/crates/wgpu).
|
||||||
|
|
||||||
|
#![allow(unsafe_code)]
|
||||||
|
|
||||||
|
pub use wgpu;
|
||||||
|
|
||||||
|
/// Low-level painting of [`egui`] on [`wgpu`].
|
||||||
|
pub mod renderer;
|
||||||
|
|
||||||
|
/// Module for painting [`egui`] with [`wgpu`] on [`winit`].
|
||||||
|
#[cfg(feature = "winit")]
|
||||||
|
pub mod winit;
|
544
egui-wgpu/src/renderer.rs
Normal file
544
egui-wgpu/src/renderer.rs
Normal file
|
@ -0,0 +1,544 @@
|
||||||
|
#![allow(unsafe_code)]
|
||||||
|
|
||||||
|
use std::{borrow::Cow, collections::HashMap, num::NonZeroU32};
|
||||||
|
|
||||||
|
use egui::epaint::Primitive;
|
||||||
|
use wgpu;
|
||||||
|
use wgpu::util::DeviceExt as _;
|
||||||
|
|
||||||
|
/// Enum for selecting the right buffer type.
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum BufferType {
|
||||||
|
Uniform,
|
||||||
|
Index,
|
||||||
|
Vertex,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Information about the screen used for rendering.
|
||||||
|
pub struct ScreenDescriptor {
|
||||||
|
/// Size of the window in physical pixels.
|
||||||
|
pub size_in_pixels: [u32; 2],
|
||||||
|
|
||||||
|
/// HiDPI scale factor (pixels per point).
|
||||||
|
pub pixels_per_point: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScreenDescriptor {
|
||||||
|
/// size in "logical" points
|
||||||
|
fn screen_size_in_points(&self) -> [f32; 2] {
|
||||||
|
[
|
||||||
|
self.size_in_pixels[0] as f32 / self.pixels_per_point,
|
||||||
|
self.size_in_pixels[1] as f32 / self.pixels_per_point,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Uniform buffer used when rendering.
|
||||||
|
#[derive(Clone, Copy, Debug, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct UniformBuffer {
|
||||||
|
screen_size_in_points: [f32; 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wraps the buffers and includes additional information.
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct SizedBuffer {
|
||||||
|
buffer: wgpu::Buffer,
|
||||||
|
/// number of bytes
|
||||||
|
size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render pass to render a egui based GUI.
|
||||||
|
pub struct RenderPass {
|
||||||
|
render_pipeline: wgpu::RenderPipeline,
|
||||||
|
index_buffers: Vec<SizedBuffer>,
|
||||||
|
vertex_buffers: Vec<SizedBuffer>,
|
||||||
|
uniform_buffer: SizedBuffer,
|
||||||
|
uniform_bind_group: wgpu::BindGroup,
|
||||||
|
texture_bind_group_layout: wgpu::BindGroupLayout,
|
||||||
|
textures: HashMap<egui::TextureId, (wgpu::Texture, wgpu::BindGroup)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderPass {
|
||||||
|
/// Creates a new render pass to render a egui UI.
|
||||||
|
///
|
||||||
|
/// If the format passed is not a *Srgb format, the shader will automatically convert to `sRGB` colors in the shader.
|
||||||
|
pub fn new(
|
||||||
|
device: &wgpu::Device,
|
||||||
|
output_format: wgpu::TextureFormat,
|
||||||
|
msaa_samples: u32,
|
||||||
|
) -> Self {
|
||||||
|
let shader = wgpu::ShaderModuleDescriptor {
|
||||||
|
label: Some("egui_shader"),
|
||||||
|
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("egui.wgsl"))),
|
||||||
|
};
|
||||||
|
let module = device.create_shader_module(&shader);
|
||||||
|
|
||||||
|
let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some("egui_uniform_buffer"),
|
||||||
|
contents: bytemuck::cast_slice(&[UniformBuffer {
|
||||||
|
screen_size_in_points: [0.0, 0.0],
|
||||||
|
}]),
|
||||||
|
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||||
|
});
|
||||||
|
let uniform_buffer = SizedBuffer {
|
||||||
|
buffer: uniform_buffer,
|
||||||
|
size: std::mem::size_of::<UniformBuffer>(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let uniform_bind_group_layout =
|
||||||
|
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
|
label: Some("egui_uniform_bind_group_layout"),
|
||||||
|
entries: &[wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 0,
|
||||||
|
visibility: wgpu::ShaderStages::VERTEX,
|
||||||
|
ty: wgpu::BindingType::Buffer {
|
||||||
|
has_dynamic_offset: false,
|
||||||
|
min_binding_size: None,
|
||||||
|
ty: wgpu::BufferBindingType::Uniform,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
let uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: Some("egui_uniform_bind_group"),
|
||||||
|
layout: &uniform_bind_group_layout,
|
||||||
|
entries: &[wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
|
||||||
|
buffer: &uniform_buffer.buffer,
|
||||||
|
offset: 0,
|
||||||
|
size: None,
|
||||||
|
}),
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
let texture_bind_group_layout =
|
||||||
|
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
|
label: Some("egui_texture_bind_group_layout"),
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 0,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Texture {
|
||||||
|
multisampled: false,
|
||||||
|
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||||
|
view_dimension: wgpu::TextureViewDimension::D2,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 1,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
|
label: Some("egui_pipeline_layout"),
|
||||||
|
bind_group_layouts: &[&uniform_bind_group_layout, &texture_bind_group_layout],
|
||||||
|
push_constant_ranges: &[],
|
||||||
|
});
|
||||||
|
|
||||||
|
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: Some("egui_pipeline"),
|
||||||
|
layout: Some(&pipeline_layout),
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
entry_point: if output_format.describe().srgb {
|
||||||
|
"vs_main"
|
||||||
|
} else {
|
||||||
|
"vs_conv_main"
|
||||||
|
},
|
||||||
|
module: &module,
|
||||||
|
buffers: &[wgpu::VertexBufferLayout {
|
||||||
|
array_stride: 5 * 4,
|
||||||
|
step_mode: wgpu::VertexStepMode::Vertex,
|
||||||
|
// 0: vec2 position
|
||||||
|
// 1: vec2 texture coordinates
|
||||||
|
// 2: uint color
|
||||||
|
attributes: &wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x2, 2 => Uint32],
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||||
|
unclipped_depth: false,
|
||||||
|
conservative: false,
|
||||||
|
cull_mode: None,
|
||||||
|
front_face: wgpu::FrontFace::default(),
|
||||||
|
polygon_mode: wgpu::PolygonMode::default(),
|
||||||
|
strip_index_format: None,
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState {
|
||||||
|
alpha_to_coverage_enabled: false,
|
||||||
|
count: msaa_samples,
|
||||||
|
mask: !0,
|
||||||
|
},
|
||||||
|
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &module,
|
||||||
|
entry_point: "fs_main",
|
||||||
|
targets: &[wgpu::ColorTargetState {
|
||||||
|
format: output_format,
|
||||||
|
blend: Some(wgpu::BlendState {
|
||||||
|
color: wgpu::BlendComponent {
|
||||||
|
src_factor: wgpu::BlendFactor::One,
|
||||||
|
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
alpha: wgpu::BlendComponent {
|
||||||
|
src_factor: wgpu::BlendFactor::OneMinusDstAlpha,
|
||||||
|
dst_factor: wgpu::BlendFactor::One,
|
||||||
|
operation: wgpu::BlendOperation::Add,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
multiview: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
render_pipeline,
|
||||||
|
vertex_buffers: Vec::with_capacity(64),
|
||||||
|
index_buffers: Vec::with_capacity(64),
|
||||||
|
uniform_buffer,
|
||||||
|
uniform_bind_group,
|
||||||
|
texture_bind_group_layout,
|
||||||
|
textures: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Executes the egui render pass.
|
||||||
|
pub fn execute(
|
||||||
|
&self,
|
||||||
|
encoder: &mut wgpu::CommandEncoder,
|
||||||
|
color_attachment: &wgpu::TextureView,
|
||||||
|
paint_jobs: &[egui::epaint::ClippedPrimitive],
|
||||||
|
screen_descriptor: &ScreenDescriptor,
|
||||||
|
clear_color: Option<wgpu::Color>,
|
||||||
|
) {
|
||||||
|
let load_operation = if let Some(color) = clear_color {
|
||||||
|
wgpu::LoadOp::Clear(color)
|
||||||
|
} else {
|
||||||
|
wgpu::LoadOp::Load
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
color_attachments: &[wgpu::RenderPassColorAttachment {
|
||||||
|
view: color_attachment,
|
||||||
|
resolve_target: None,
|
||||||
|
ops: wgpu::Operations {
|
||||||
|
load: load_operation,
|
||||||
|
store: true,
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
label: Some("egui main render pass"),
|
||||||
|
});
|
||||||
|
rpass.push_debug_group("egui_pass");
|
||||||
|
|
||||||
|
self.execute_with_renderpass(&mut rpass, paint_jobs, screen_descriptor);
|
||||||
|
|
||||||
|
rpass.pop_debug_group();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Executes the egui render pass onto an existing wgpu renderpass.
|
||||||
|
pub fn execute_with_renderpass<'rpass>(
|
||||||
|
&'rpass self,
|
||||||
|
rpass: &mut wgpu::RenderPass<'rpass>,
|
||||||
|
paint_jobs: &[egui::epaint::ClippedPrimitive],
|
||||||
|
screen_descriptor: &ScreenDescriptor,
|
||||||
|
) {
|
||||||
|
rpass.set_pipeline(&self.render_pipeline);
|
||||||
|
|
||||||
|
rpass.set_bind_group(0, &self.uniform_bind_group, &[]);
|
||||||
|
|
||||||
|
let pixels_per_point = screen_descriptor.pixels_per_point;
|
||||||
|
let size_in_pixels = screen_descriptor.size_in_pixels;
|
||||||
|
|
||||||
|
for (
|
||||||
|
(
|
||||||
|
egui::ClippedPrimitive {
|
||||||
|
clip_rect,
|
||||||
|
primitive,
|
||||||
|
},
|
||||||
|
vertex_buffer,
|
||||||
|
),
|
||||||
|
index_buffer,
|
||||||
|
) in paint_jobs
|
||||||
|
.iter()
|
||||||
|
.zip(&self.vertex_buffers)
|
||||||
|
.zip(&self.index_buffers)
|
||||||
|
{
|
||||||
|
// Transform clip rect to physical pixels.
|
||||||
|
let clip_min_x = pixels_per_point * clip_rect.min.x;
|
||||||
|
let clip_min_y = pixels_per_point * clip_rect.min.y;
|
||||||
|
let clip_max_x = pixels_per_point * clip_rect.max.x;
|
||||||
|
let clip_max_y = pixels_per_point * clip_rect.max.y;
|
||||||
|
|
||||||
|
// Make sure clip rect can fit within an `u32`.
|
||||||
|
let clip_min_x = clip_min_x.clamp(0.0, size_in_pixels[0] as f32);
|
||||||
|
let clip_min_y = clip_min_y.clamp(0.0, size_in_pixels[1] as f32);
|
||||||
|
let clip_max_x = clip_max_x.clamp(clip_min_x, size_in_pixels[0] as f32);
|
||||||
|
let clip_max_y = clip_max_y.clamp(clip_min_y, size_in_pixels[1] as f32);
|
||||||
|
|
||||||
|
let clip_min_x = clip_min_x.round() as u32;
|
||||||
|
let clip_min_y = clip_min_y.round() as u32;
|
||||||
|
let clip_max_x = clip_max_x.round() as u32;
|
||||||
|
let clip_max_y = clip_max_y.round() as u32;
|
||||||
|
|
||||||
|
let width = (clip_max_x - clip_min_x).max(1);
|
||||||
|
let height = (clip_max_y - clip_min_y).max(1);
|
||||||
|
|
||||||
|
{
|
||||||
|
// Clip scissor rectangle to target size.
|
||||||
|
let x = clip_min_x.min(size_in_pixels[0]);
|
||||||
|
let y = clip_min_y.min(size_in_pixels[1]);
|
||||||
|
let width = width.min(size_in_pixels[0] - x);
|
||||||
|
let height = height.min(size_in_pixels[1] - y);
|
||||||
|
|
||||||
|
// Skip rendering with zero-sized clip areas.
|
||||||
|
if width == 0 || height == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpass.set_scissor_rect(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
match primitive {
|
||||||
|
Primitive::Mesh(mesh) => {
|
||||||
|
if let Some((_texture, bind_group)) = self.textures.get(&mesh.texture_id) {
|
||||||
|
rpass.set_bind_group(1, bind_group, &[]);
|
||||||
|
rpass.set_index_buffer(
|
||||||
|
index_buffer.buffer.slice(..),
|
||||||
|
wgpu::IndexFormat::Uint32,
|
||||||
|
);
|
||||||
|
rpass.set_vertex_buffer(0, vertex_buffer.buffer.slice(..));
|
||||||
|
rpass.draw_indexed(0..mesh.indices.len() as u32, 0, 0..1);
|
||||||
|
} else {
|
||||||
|
tracing::warn!("Missing texture: {:?}", mesh.texture_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Primitive::Callback(_) => {
|
||||||
|
// already warned about earlier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Should be called before `execute()`.
|
||||||
|
pub fn update_texture(
|
||||||
|
&mut self,
|
||||||
|
device: &wgpu::Device,
|
||||||
|
queue: &wgpu::Queue,
|
||||||
|
id: egui::TextureId,
|
||||||
|
image_delta: &egui::epaint::ImageDelta,
|
||||||
|
) {
|
||||||
|
let width = image_delta.image.width() as u32;
|
||||||
|
let height = image_delta.image.height() as u32;
|
||||||
|
|
||||||
|
let size = wgpu::Extent3d {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let data_color32 = match &image_delta.image {
|
||||||
|
egui::ImageData::Color(image) => {
|
||||||
|
assert_eq!(
|
||||||
|
width as usize * height as usize,
|
||||||
|
image.pixels.len(),
|
||||||
|
"Mismatch between texture size and texel count"
|
||||||
|
);
|
||||||
|
Cow::Borrowed(&image.pixels)
|
||||||
|
}
|
||||||
|
egui::ImageData::Font(image) => {
|
||||||
|
assert_eq!(
|
||||||
|
width as usize * height as usize,
|
||||||
|
image.pixels.len(),
|
||||||
|
"Mismatch between texture size and texel count"
|
||||||
|
);
|
||||||
|
Cow::Owned(image.srgba_pixels(1.0).collect::<Vec<_>>())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let data_bytes: &[u8] = bytemuck::cast_slice(data_color32.as_slice());
|
||||||
|
|
||||||
|
let queue_write_data_to_texture = |texture, origin| {
|
||||||
|
queue.write_texture(
|
||||||
|
wgpu::ImageCopyTexture {
|
||||||
|
texture,
|
||||||
|
mip_level: 0,
|
||||||
|
origin,
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
},
|
||||||
|
data_bytes,
|
||||||
|
wgpu::ImageDataLayout {
|
||||||
|
offset: 0,
|
||||||
|
bytes_per_row: NonZeroU32::new(4 * width),
|
||||||
|
rows_per_image: NonZeroU32::new(height),
|
||||||
|
},
|
||||||
|
size,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(pos) = image_delta.pos {
|
||||||
|
// update the existing texture
|
||||||
|
let (texture, _bind_group) = self
|
||||||
|
.textures
|
||||||
|
.get(&id)
|
||||||
|
.expect("Tried to update a texture that has not been allocated yet.");
|
||||||
|
let origin = wgpu::Origin3d {
|
||||||
|
x: pos[0] as u32,
|
||||||
|
y: pos[1] as u32,
|
||||||
|
z: 0,
|
||||||
|
};
|
||||||
|
queue_write_data_to_texture(texture, origin);
|
||||||
|
} else {
|
||||||
|
// allocate a new texture
|
||||||
|
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||||
|
label: None,
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
||||||
|
label: None,
|
||||||
|
mag_filter: wgpu::FilterMode::Linear,
|
||||||
|
min_filter: wgpu::FilterMode::Linear,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: None,
|
||||||
|
layout: &self.texture_bind_group_layout,
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: wgpu::BindingResource::TextureView(
|
||||||
|
&texture.create_view(&wgpu::TextureViewDescriptor::default()),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 1,
|
||||||
|
resource: wgpu::BindingResource::Sampler(&sampler),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
let origin = wgpu::Origin3d::ZERO;
|
||||||
|
queue_write_data_to_texture(&texture, origin);
|
||||||
|
self.textures.insert(id, (texture, bind_group));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Should be called before `execute()`.
|
||||||
|
pub fn free_texture(&mut self, id: &egui::TextureId) {
|
||||||
|
self.textures.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Uploads the uniform, vertex and index data used by the render pass.
|
||||||
|
/// Should be called before `execute()`.
|
||||||
|
pub fn update_buffers(
|
||||||
|
&mut self,
|
||||||
|
device: &wgpu::Device,
|
||||||
|
queue: &wgpu::Queue,
|
||||||
|
paint_jobs: &[egui::epaint::ClippedPrimitive],
|
||||||
|
screen_descriptor: &ScreenDescriptor,
|
||||||
|
) {
|
||||||
|
let screen_size_in_points = screen_descriptor.screen_size_in_points();
|
||||||
|
|
||||||
|
self.update_buffer(
|
||||||
|
device,
|
||||||
|
queue,
|
||||||
|
&BufferType::Uniform,
|
||||||
|
0,
|
||||||
|
bytemuck::cast_slice(&[UniformBuffer {
|
||||||
|
screen_size_in_points,
|
||||||
|
}]),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (i, egui::ClippedPrimitive { primitive, .. }) in paint_jobs.iter().enumerate() {
|
||||||
|
match primitive {
|
||||||
|
Primitive::Mesh(mesh) => {
|
||||||
|
let data: &[u8] = bytemuck::cast_slice(&mesh.indices);
|
||||||
|
if i < self.index_buffers.len() {
|
||||||
|
self.update_buffer(device, queue, &BufferType::Index, i, data);
|
||||||
|
} else {
|
||||||
|
let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some("egui_index_buffer"),
|
||||||
|
contents: data,
|
||||||
|
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
|
||||||
|
});
|
||||||
|
self.index_buffers.push(SizedBuffer {
|
||||||
|
buffer,
|
||||||
|
size: data.len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let data: &[u8] = bytemuck::cast_slice(&mesh.vertices);
|
||||||
|
if i < self.vertex_buffers.len() {
|
||||||
|
self.update_buffer(device, queue, &BufferType::Vertex, i, data);
|
||||||
|
} else {
|
||||||
|
let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some("egui_vertex_buffer"),
|
||||||
|
contents: data,
|
||||||
|
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||||
|
});
|
||||||
|
|
||||||
|
self.vertex_buffers.push(SizedBuffer {
|
||||||
|
buffer,
|
||||||
|
size: data.len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Primitive::Callback(_) => {
|
||||||
|
tracing::warn!("Painting callbacks not supported by egui-wgpu (yet)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates the buffers used by egui. Will properly re-size the buffers if needed.
|
||||||
|
fn update_buffer(
|
||||||
|
&mut self,
|
||||||
|
device: &wgpu::Device,
|
||||||
|
queue: &wgpu::Queue,
|
||||||
|
buffer_type: &BufferType,
|
||||||
|
index: usize,
|
||||||
|
data: &[u8],
|
||||||
|
) {
|
||||||
|
let (buffer, storage, label) = match buffer_type {
|
||||||
|
BufferType::Index => (
|
||||||
|
&mut self.index_buffers[index],
|
||||||
|
wgpu::BufferUsages::INDEX,
|
||||||
|
"egui_index_buffer",
|
||||||
|
),
|
||||||
|
BufferType::Vertex => (
|
||||||
|
&mut self.vertex_buffers[index],
|
||||||
|
wgpu::BufferUsages::VERTEX,
|
||||||
|
"egui_vertex_buffer",
|
||||||
|
),
|
||||||
|
BufferType::Uniform => (
|
||||||
|
&mut self.uniform_buffer,
|
||||||
|
wgpu::BufferUsages::UNIFORM,
|
||||||
|
"egui_uniform_buffer",
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
if data.len() > buffer.size {
|
||||||
|
buffer.size = data.len();
|
||||||
|
buffer.buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some(label),
|
||||||
|
contents: bytemuck::cast_slice(data),
|
||||||
|
usage: storage | wgpu::BufferUsages::COPY_DST,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
queue.write_buffer(&buffer.buffer, 0, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
148
egui-wgpu/src/winit.rs
Normal file
148
egui-wgpu/src/winit.rs
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
use crate::renderer;
|
||||||
|
|
||||||
|
/// Everything you need to paint egui with [`wgpu`] on [`winit`].
|
||||||
|
///
|
||||||
|
/// Alternatively you can use [`crate::renderer`] directly.
|
||||||
|
pub struct Painter {
|
||||||
|
device: wgpu::Device,
|
||||||
|
queue: wgpu::Queue,
|
||||||
|
surface_config: wgpu::SurfaceConfiguration,
|
||||||
|
surface: wgpu::Surface,
|
||||||
|
egui_rpass: renderer::RenderPass,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Painter {
|
||||||
|
/// Creates a [`wgpu`] surface for the given window, and things required to render egui onto it.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// The given `window` must outlive the returned [`Painter`].
|
||||||
|
pub unsafe fn new(window: &winit::window::Window, msaa_samples: u32) -> Self {
|
||||||
|
let instance = wgpu::Instance::new(wgpu::Backends::PRIMARY | wgpu::Backends::GL);
|
||||||
|
let surface = instance.create_surface(&window);
|
||||||
|
|
||||||
|
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
|
||||||
|
power_preference: wgpu::PowerPreference::HighPerformance,
|
||||||
|
compatible_surface: Some(&surface),
|
||||||
|
force_fallback_adapter: false,
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let (device, queue) = pollster::block_on(adapter.request_device(
|
||||||
|
&wgpu::DeviceDescriptor {
|
||||||
|
features: wgpu::Features::default(),
|
||||||
|
limits: wgpu::Limits::default(),
|
||||||
|
label: None,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let size = window.inner_size();
|
||||||
|
let surface_format = surface.get_preferred_format(&adapter).unwrap();
|
||||||
|
let surface_config = wgpu::SurfaceConfiguration {
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
|
format: surface_format,
|
||||||
|
width: size.width as u32,
|
||||||
|
height: size.height as u32,
|
||||||
|
present_mode: wgpu::PresentMode::Fifo, // TODO: make vsync configurable
|
||||||
|
};
|
||||||
|
surface.configure(&device, &surface_config);
|
||||||
|
|
||||||
|
let egui_rpass = renderer::RenderPass::new(&device, surface_format, msaa_samples);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
device,
|
||||||
|
queue,
|
||||||
|
surface_config,
|
||||||
|
surface,
|
||||||
|
egui_rpass,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_texture_side(&self) -> usize {
|
||||||
|
self.device.limits().max_texture_dimension_2d as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_window_resized(&mut self, width_in_pixels: u32, height_in_pixels: u32) {
|
||||||
|
self.surface_config.width = width_in_pixels;
|
||||||
|
self.surface_config.height = height_in_pixels;
|
||||||
|
self.surface.configure(&self.device, &self.surface_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn paint_and_update_textures(
|
||||||
|
&mut self,
|
||||||
|
pixels_per_point: f32,
|
||||||
|
clear_color: egui::Rgba,
|
||||||
|
clipped_primitives: &[egui::ClippedPrimitive],
|
||||||
|
textures_delta: &egui::TexturesDelta,
|
||||||
|
) {
|
||||||
|
let output_frame = match self.surface.get_current_texture() {
|
||||||
|
Ok(frame) => frame,
|
||||||
|
Err(wgpu::SurfaceError::Outdated) => {
|
||||||
|
// This error occurs when the app is minimized on Windows.
|
||||||
|
// Silently return here to prevent spamming the console with:
|
||||||
|
// "The underlying surface has changed, and therefore the swap chain must be updated"
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
tracing::warn!("Dropped frame with error: {e}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let output_view = output_frame
|
||||||
|
.texture
|
||||||
|
.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
||||||
|
let mut encoder = self
|
||||||
|
.device
|
||||||
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||||
|
label: Some("encoder"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Upload all resources for the GPU.
|
||||||
|
let screen_descriptor = renderer::ScreenDescriptor {
|
||||||
|
size_in_pixels: [self.surface_config.width, self.surface_config.height],
|
||||||
|
pixels_per_point,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (id, image_delta) in &textures_delta.set {
|
||||||
|
self.egui_rpass
|
||||||
|
.update_texture(&self.device, &self.queue, *id, image_delta);
|
||||||
|
}
|
||||||
|
for id in &textures_delta.free {
|
||||||
|
self.egui_rpass.free_texture(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.egui_rpass.update_buffers(
|
||||||
|
&self.device,
|
||||||
|
&self.queue,
|
||||||
|
clipped_primitives,
|
||||||
|
&screen_descriptor,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Record all render passes.
|
||||||
|
self.egui_rpass.execute(
|
||||||
|
&mut encoder,
|
||||||
|
&output_view,
|
||||||
|
clipped_primitives,
|
||||||
|
&screen_descriptor,
|
||||||
|
Some(wgpu::Color {
|
||||||
|
r: clear_color.r() as f64,
|
||||||
|
g: clear_color.g() as f64,
|
||||||
|
b: clear_color.b() as f64,
|
||||||
|
a: clear_color.a() as f64,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Submit the commands.
|
||||||
|
self.queue.submit(std::iter::once(encoder.finish()));
|
||||||
|
|
||||||
|
// Redraw egui
|
||||||
|
output_frame.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::unused_self)]
|
||||||
|
pub fn destroy(&mut self) {
|
||||||
|
// TODO: something here?
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["persistence"]
|
default = ["glow", "persistence"]
|
||||||
|
|
||||||
http = ["ehttp", "image", "poll-promise", "egui_extras/image"]
|
http = ["ehttp", "image", "poll-promise", "egui_extras/image"]
|
||||||
persistence = [
|
persistence = [
|
||||||
|
@ -32,13 +32,15 @@ serde = [
|
||||||
]
|
]
|
||||||
syntax_highlighting = ["egui_demo_lib/syntax_highlighting"]
|
syntax_highlighting = ["egui_demo_lib/syntax_highlighting"]
|
||||||
|
|
||||||
|
glow = ["eframe/glow"]
|
||||||
|
wgpu = ["eframe/wgpu"]
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = { version = "0.4", features = ["js-sys", "wasmbind"] }
|
chrono = { version = "0.4", features = ["js-sys", "wasmbind"] }
|
||||||
eframe = { version = "0.18.0", path = "../eframe" }
|
eframe = { version = "0.18.0", path = "../eframe", default-features = false }
|
||||||
egui = { version = "0.18.0", path = "../egui", features = ["extra_debug_asserts"] }
|
egui = { version = "0.18.0", path = "../egui", features = ["extra_debug_asserts"] }
|
||||||
egui_demo_lib = { version = "0.18.0", path = "../egui_demo_lib", features = ["chrono"] }
|
egui_demo_lib = { version = "0.18.0", path = "../egui_demo_lib", features = ["chrono"] }
|
||||||
egui_glow = { version = "0.18.0", path = "../egui_glow" }
|
|
||||||
|
|
||||||
# Optional dependencies:
|
# Optional dependencies:
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use eframe::egui_glow;
|
||||||
use egui::mutex::Mutex;
|
use egui::mutex::Mutex;
|
||||||
use egui_glow::glow;
|
use egui_glow::glow;
|
||||||
|
|
||||||
|
@ -39,8 +40,10 @@ impl eframe::App for Custom3d {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_exit(&mut self, gl: &glow::Context) {
|
fn on_exit(&mut self, gl: Option<&glow::Context>) {
|
||||||
self.rotating_triangle.lock().destroy(gl);
|
if let Some(gl) = gl {
|
||||||
|
self.rotating_triangle.lock().destroy(gl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
mod custom3d;
|
mod custom3d;
|
||||||
|
|
||||||
mod fractal_clock;
|
mod fractal_clock;
|
||||||
|
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
mod http_app;
|
mod http_app;
|
||||||
|
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
pub use custom3d::Custom3d;
|
pub use custom3d::Custom3d;
|
||||||
|
|
||||||
pub use fractal_clock::FractalClock;
|
pub use fractal_clock::FractalClock;
|
||||||
|
|
||||||
#[cfg(feature = "http")]
|
#[cfg(feature = "http")]
|
||||||
pub use http_app::HttpApp;
|
pub use http_app::HttpApp;
|
||||||
|
|
|
@ -9,6 +9,10 @@ fn main() {
|
||||||
|
|
||||||
let options = eframe::NativeOptions {
|
let options = eframe::NativeOptions {
|
||||||
drag_and_drop_support: true,
|
drag_and_drop_support: true,
|
||||||
|
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
|
renderer: eframe::Renderer::Wgpu,
|
||||||
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
eframe::run_native(
|
eframe::run_native(
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use egui_demo_lib::is_mobile;
|
use egui_demo_lib::is_mobile;
|
||||||
use egui_glow::glow;
|
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
|
use eframe::glow;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
@ -91,7 +93,8 @@ pub struct State {
|
||||||
pub struct WrapApp {
|
pub struct WrapApp {
|
||||||
state: State,
|
state: State,
|
||||||
// not serialized (because it contains OpenGL buffers etc)
|
// not serialized (because it contains OpenGL buffers etc)
|
||||||
custom3d: crate::apps::Custom3d,
|
#[cfg(feature = "glow")]
|
||||||
|
custom3d: Option<crate::apps::Custom3d>,
|
||||||
dropped_files: Vec<egui::DroppedFile>,
|
dropped_files: Vec<egui::DroppedFile>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +103,8 @@ impl WrapApp {
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut slf = Self {
|
let mut slf = Self {
|
||||||
state: State::default(),
|
state: State::default(),
|
||||||
custom3d: crate::apps::Custom3d::new(&cc.gl),
|
#[cfg(feature = "glow")]
|
||||||
|
custom3d: cc.gl.as_ref().map(|gl| crate::apps::Custom3d::new(gl)),
|
||||||
dropped_files: Default::default(),
|
dropped_files: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -121,7 +125,7 @@ impl WrapApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apps_iter_mut(&mut self) -> impl Iterator<Item = (&str, &str, &mut dyn eframe::App)> {
|
fn apps_iter_mut(&mut self) -> impl Iterator<Item = (&str, &str, &mut dyn eframe::App)> {
|
||||||
vec![
|
let mut vec = vec![
|
||||||
(
|
(
|
||||||
"✨ Demos",
|
"✨ Demos",
|
||||||
"demo",
|
"demo",
|
||||||
|
@ -143,18 +147,24 @@ impl WrapApp {
|
||||||
"clock",
|
"clock",
|
||||||
&mut self.state.clock as &mut dyn eframe::App,
|
&mut self.state.clock as &mut dyn eframe::App,
|
||||||
),
|
),
|
||||||
(
|
];
|
||||||
|
|
||||||
|
#[cfg(feature = "glow")]
|
||||||
|
if let Some(custom3d) = &mut self.custom3d {
|
||||||
|
vec.push((
|
||||||
"🔺 3D painting",
|
"🔺 3D painting",
|
||||||
"custom3e",
|
"custom3e",
|
||||||
&mut self.custom3d as &mut dyn eframe::App,
|
custom3d as &mut dyn eframe::App,
|
||||||
),
|
));
|
||||||
(
|
}
|
||||||
"🎨 Color test",
|
|
||||||
"colors",
|
vec.push((
|
||||||
&mut self.state.color_test as &mut dyn eframe::App,
|
"🎨 Color test",
|
||||||
),
|
"colors",
|
||||||
]
|
&mut self.state.color_test as &mut dyn eframe::App,
|
||||||
.into_iter()
|
));
|
||||||
|
|
||||||
|
vec.into_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,8 +222,11 @@ impl eframe::App for WrapApp {
|
||||||
self.ui_file_drag_and_drop(ctx);
|
self.ui_file_drag_and_drop(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_exit(&mut self, gl: &glow::Context) {
|
#[cfg(feature = "glow")]
|
||||||
self.custom3d.on_exit(gl);
|
fn on_exit(&mut self, gl: Option<&glow::Context>) {
|
||||||
|
if let Some(custom3d) = &mut self.custom3d {
|
||||||
|
custom3d.on_exit(gl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -649,6 +649,7 @@ impl Painter {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(gl: &glow::Context, screen_size_in_pixels: [u32; 2], clear_color: egui::Rgba) {
|
pub fn clear(gl: &glow::Context, screen_size_in_pixels: [u32; 2], clear_color: egui::Rgba) {
|
||||||
|
crate::profile_function!();
|
||||||
unsafe {
|
unsafe {
|
||||||
gl.disable(glow::SCISSOR_TEST);
|
gl.disable(glow::SCISSOR_TEST);
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,6 @@ publish = false
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
eframe = { path = "../../eframe" }
|
eframe = { path = "../../eframe", features = ["glow"] }
|
||||||
egui_glow = { path = "../../egui_glow" }
|
egui_glow = { path = "../../egui_glow" }
|
||||||
glow = "0.11"
|
glow = "0.11"
|
||||||
|
|
|
@ -10,6 +10,7 @@ fn main() {
|
||||||
let options = eframe::NativeOptions {
|
let options = eframe::NativeOptions {
|
||||||
initial_window_size: Some(egui::vec2(350.0, 380.0)),
|
initial_window_size: Some(egui::vec2(350.0, 380.0)),
|
||||||
multisampling: 8,
|
multisampling: 8,
|
||||||
|
renderer: eframe::Renderer::Glow,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
eframe::run_native(
|
eframe::run_native(
|
||||||
|
@ -27,8 +28,12 @@ struct MyApp {
|
||||||
|
|
||||||
impl MyApp {
|
impl MyApp {
|
||||||
fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||||
|
let gl = cc
|
||||||
|
.gl
|
||||||
|
.as_ref()
|
||||||
|
.expect("You need to run eframe with the glow backend");
|
||||||
Self {
|
Self {
|
||||||
rotating_triangle: Arc::new(Mutex::new(RotatingTriangle::new(&cc.gl))),
|
rotating_triangle: Arc::new(Mutex::new(RotatingTriangle::new(gl))),
|
||||||
angle: 0.0,
|
angle: 0.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,8 +56,10 @@ impl eframe::App for MyApp {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_exit(&mut self, gl: &glow::Context) {
|
fn on_exit(&mut self, gl: Option<&glow::Context>) {
|
||||||
self.rotating_triangle.lock().destroy(gl);
|
if let Some(gl) = gl {
|
||||||
|
self.rotating_triangle.lock().destroy(gl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ publish = false
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
eframe = { path = "../../eframe" }
|
eframe = { path = "../../eframe", features = ["glow"] }
|
||||||
egui_glow = { path = "../../egui_glow" }
|
egui_glow = { path = "../../egui_glow" }
|
||||||
glow = "0.11"
|
glow = "0.11"
|
||||||
three-d = { version = "0.11", default-features = false }
|
three-d = { version = "0.11", default-features = false }
|
||||||
|
|
|
@ -6,6 +6,7 @@ fn main() {
|
||||||
let options = eframe::NativeOptions {
|
let options = eframe::NativeOptions {
|
||||||
initial_window_size: Some(egui::vec2(550.0, 610.0)),
|
initial_window_size: Some(egui::vec2(550.0, 610.0)),
|
||||||
multisampling: 8,
|
multisampling: 8,
|
||||||
|
renderer: eframe::Renderer::Glow,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
eframe::run_native(
|
eframe::run_native(
|
||||||
|
|
|
@ -4,7 +4,7 @@ script_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
|
||||||
cd "$script_path/.."
|
cd "$script_path/.."
|
||||||
|
|
||||||
CRATE_NAME="egui_demo_app"
|
CRATE_NAME="egui_demo_app"
|
||||||
FEATURES="http,persistence,screen_reader"
|
FEATURES="glow,http,persistence,screen_reader"
|
||||||
|
|
||||||
OPEN=false
|
OPEN=false
|
||||||
FAST=false
|
FAST=false
|
||||||
|
|
|
@ -20,9 +20,11 @@ cargo fmt --all -- --check
|
||||||
cargo doc -p eframe -p egui -p egui_demo_lib -p egui_extras -p egui_glium -p egui_glow -p egui-winit -p emath -p epaint --lib --no-deps --all-features
|
cargo doc -p eframe -p egui -p egui_demo_lib -p egui_extras -p egui_glium -p egui_glow -p egui-winit -p emath -p epaint --lib --no-deps --all-features
|
||||||
cargo doc --document-private-items --no-deps --all-features
|
cargo doc --document-private-items --no-deps --all-features
|
||||||
|
|
||||||
(cd eframe && cargo check --no-default-features)
|
(cd eframe && cargo check --no-default-features --features "glow")
|
||||||
|
(cd eframe && cargo check --no-default-features --features "wgpu")
|
||||||
(cd egui && cargo check --no-default-features --features "serde")
|
(cd egui && cargo check --no-default-features --features "serde")
|
||||||
(cd egui_demo_app && cargo check --no-default-features)
|
(cd egui_demo_app && cargo check --no-default-features --features "glow")
|
||||||
|
(cd egui_demo_app && cargo check --no-default-features --features "wgpu")
|
||||||
(cd egui_demo_lib && cargo check --no-default-features)
|
(cd egui_demo_lib && cargo check --no-default-features)
|
||||||
(cd egui_extras && cargo check --no-default-features)
|
(cd egui_extras && cargo check --no-default-features)
|
||||||
(cd egui_glium && cargo check --no-default-features)
|
(cd egui_glium && cargo check --no-default-features)
|
||||||
|
|
|
@ -4,7 +4,7 @@ script_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
|
||||||
cd "$script_path/.."
|
cd "$script_path/.."
|
||||||
|
|
||||||
CRATE_NAME="egui_demo_app"
|
CRATE_NAME="egui_demo_app"
|
||||||
FEATURES="http,persistence,screen_reader"
|
FEATURES="glow,http,persistence,screen_reader"
|
||||||
|
|
||||||
# This is required to enable the web_sys clipboard API which eframe web uses
|
# This is required to enable the web_sys clipboard API which eframe web uses
|
||||||
# https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Clipboard.html
|
# https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Clipboard.html
|
||||||
|
|
Loading…
Reference in a new issue