Move to egui + winit, add rating
This commit is contained in:
parent
7b475a969c
commit
f55424b98f
325
Cargo.lock
generated
325
Cargo.lock
generated
@ -597,18 +597,6 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "base64"
|
|
||||||
version = "0.21.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "base64"
|
|
||||||
version = "0.22.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-set"
|
name = "bit-set"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
@ -1269,12 +1257,6 @@ dependencies = [
|
|||||||
"zbus",
|
"zbus",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "data-url"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dconf_rs"
|
name = "dconf_rs"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@ -1511,23 +1493,6 @@ dependencies = [
|
|||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "egui_extras"
|
|
||||||
version = "0.31.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "624659a2e972a46f4d5f646557906c55f1cd5a0836eddbe610fdf1afba1b4226"
|
|
||||||
dependencies = [
|
|
||||||
"ahash 0.8.11",
|
|
||||||
"egui",
|
|
||||||
"ehttp",
|
|
||||||
"enum-map",
|
|
||||||
"image 0.25.6",
|
|
||||||
"log",
|
|
||||||
"mime_guess2",
|
|
||||||
"profiling",
|
|
||||||
"resvg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "egui_glow"
|
name = "egui_glow"
|
||||||
version = "0.31.1"
|
version = "0.31.1"
|
||||||
@ -1546,20 +1511,6 @@ dependencies = [
|
|||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ehttp"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "59a81c221a1e4dad06cb9c9deb19aea1193a5eea084e8cd42d869068132bf876"
|
|
||||||
dependencies = [
|
|
||||||
"document-features",
|
|
||||||
"js-sys",
|
|
||||||
"ureq",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"wasm-bindgen-futures",
|
|
||||||
"web-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.15.0"
|
version = "1.15.0"
|
||||||
@ -1581,27 +1532,6 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf"
|
checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "enum-map"
|
|
||||||
version = "2.7.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9"
|
|
||||||
dependencies = [
|
|
||||||
"enum-map-derive",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "enum-map-derive"
|
|
||||||
version = "0.17.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.100",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "enumflags2"
|
name = "enumflags2"
|
||||||
version = "0.7.11"
|
version = "0.7.11"
|
||||||
@ -1778,12 +1708,6 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "float-cmp"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "float_next_after"
|
name = "float_next_after"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@ -1811,7 +1735,7 @@ version = "0.5.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7"
|
checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"roxmltree 0.20.0",
|
"roxmltree",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2474,7 +2398,7 @@ dependencies = [
|
|||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cosmic-text",
|
"cosmic-text",
|
||||||
"iced_graphics",
|
"iced_graphics",
|
||||||
"kurbo 0.10.4",
|
"kurbo",
|
||||||
"log",
|
"log",
|
||||||
"rustc-hash 2.1.1",
|
"rustc-hash 2.1.1",
|
||||||
"softbuffer",
|
"softbuffer",
|
||||||
@ -2727,21 +2651,17 @@ dependencies = [
|
|||||||
"quick-error",
|
"quick-error",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "imagesize"
|
|
||||||
version = "0.12.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "imflow"
|
name = "imflow"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
"clap 4.5.34",
|
"clap 4.5.34",
|
||||||
"criterion",
|
"criterion",
|
||||||
"eframe",
|
"eframe",
|
||||||
"egui",
|
"egui",
|
||||||
"egui_extras",
|
"egui-wgpu",
|
||||||
|
"egui-winit",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"iced",
|
"iced",
|
||||||
"image 0.25.6",
|
"image 0.25.6",
|
||||||
@ -3061,15 +2981,6 @@ version = "3.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "kurbo"
|
|
||||||
version = "0.9.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bd85a5776cd9500c2e2059c8c76c3b01528566b7fcbaf8098b55a33fc298849b"
|
|
||||||
dependencies = [
|
|
||||||
"arrayvec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kurbo"
|
name = "kurbo"
|
||||||
version = "0.10.4"
|
version = "0.10.4"
|
||||||
@ -3340,22 +3251,6 @@ dependencies = [
|
|||||||
"paste",
|
"paste",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mime"
|
|
||||||
version = "0.3.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mime_guess2"
|
|
||||||
version = "2.0.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "25a3333bb1609500601edc766a39b4c1772874a4ce26022f4d866854dc020c41"
|
|
||||||
dependencies = [
|
|
||||||
"mime",
|
|
||||||
"unicase",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "minifb"
|
name = "minifb"
|
||||||
version = "0.28.0"
|
version = "0.28.0"
|
||||||
@ -4080,15 +3975,9 @@ version = "0.11.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"siphasher 1.0.1",
|
"siphasher",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pico-args"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project"
|
name = "pin-project"
|
||||||
version = "1.1.10"
|
version = "1.1.10"
|
||||||
@ -4434,12 +4323,6 @@ dependencies = [
|
|||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rctree"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3b42e27ef78c35d3998403c1d26f3efd9e135d3e5121b0a4845cc5cc27547f4f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "read-fonts"
|
name = "read-fonts"
|
||||||
version = "0.22.7"
|
version = "0.22.7"
|
||||||
@ -4523,20 +4406,6 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "resvg"
|
|
||||||
version = "0.37.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cadccb3d99a9efb8e5e00c16fbb732cbe400db2ec7fc004697ee7d97d86cf1f4"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"pico-args",
|
|
||||||
"rgb",
|
|
||||||
"svgtypes",
|
|
||||||
"tiny-skia",
|
|
||||||
"usvg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rexiv2"
|
name = "rexiv2"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
@ -4553,29 +4422,6 @@ name = "rgb"
|
|||||||
version = "0.8.50"
|
version = "0.8.50"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a"
|
checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a"
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ring"
|
|
||||||
version = "0.17.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"cfg-if",
|
|
||||||
"getrandom 0.2.15",
|
|
||||||
"libc",
|
|
||||||
"untrusted",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "roxmltree"
|
|
||||||
version = "0.19.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roxmltree"
|
name = "roxmltree"
|
||||||
@ -4637,38 +4483,6 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustls"
|
|
||||||
version = "0.23.25"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"once_cell",
|
|
||||||
"ring",
|
|
||||||
"rustls-pki-types",
|
|
||||||
"rustls-webpki",
|
|
||||||
"subtle",
|
|
||||||
"zeroize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustls-pki-types"
|
|
||||||
version = "1.11.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustls-webpki"
|
|
||||||
version = "0.103.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03"
|
|
||||||
dependencies = [
|
|
||||||
"ring",
|
|
||||||
"rustls-pki-types",
|
|
||||||
"untrusted",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.20"
|
version = "1.0.20"
|
||||||
@ -4873,21 +4687,6 @@ dependencies = [
|
|||||||
"quote",
|
"quote",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "simplecss"
|
|
||||||
version = "0.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "siphasher"
|
|
||||||
version = "0.3.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@ -5031,9 +4830,6 @@ name = "strict-num"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
||||||
dependencies = [
|
|
||||||
"float-cmp",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
@ -5063,28 +4859,12 @@ dependencies = [
|
|||||||
"syn 2.0.100",
|
"syn 2.0.100",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "subtle"
|
|
||||||
version = "2.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "svg_fmt"
|
name = "svg_fmt"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce5d813d71d82c4cbc1742135004e4a79fd870214c155443451c139c9470a0aa"
|
checksum = "ce5d813d71d82c4cbc1742135004e4a79fd870214c155443451c139c9470a0aa"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "svgtypes"
|
|
||||||
version = "0.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6e44e288cd960318917cbd540340968b90becc8bc81f171345d706e7a89d9d70"
|
|
||||||
dependencies = [
|
|
||||||
"kurbo 0.9.5",
|
|
||||||
"siphasher 0.3.11",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "swash"
|
name = "swash"
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
@ -5477,12 +5257,6 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicase"
|
|
||||||
version = "2.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.18"
|
version = "0.3.18"
|
||||||
@ -5543,28 +5317,6 @@ version = "0.2.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "untrusted"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ureq"
|
|
||||||
version = "2.12.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d"
|
|
||||||
dependencies = [
|
|
||||||
"base64 0.22.1",
|
|
||||||
"flate2",
|
|
||||||
"log",
|
|
||||||
"once_cell",
|
|
||||||
"rustls",
|
|
||||||
"rustls-pki-types",
|
|
||||||
"url",
|
|
||||||
"webpki-roots",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.5.4"
|
version = "2.5.4"
|
||||||
@ -5576,50 +5328,6 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "usvg"
|
|
||||||
version = "0.37.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "38b0a51b72ab80ca511d126b77feeeb4fb1e972764653e61feac30adc161a756"
|
|
||||||
dependencies = [
|
|
||||||
"base64 0.21.7",
|
|
||||||
"log",
|
|
||||||
"pico-args",
|
|
||||||
"usvg-parser",
|
|
||||||
"usvg-tree",
|
|
||||||
"xmlwriter",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "usvg-parser"
|
|
||||||
version = "0.37.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9bd4e3c291f45d152929a31f0f6c819245e2921bfd01e7bd91201a9af39a2bdc"
|
|
||||||
dependencies = [
|
|
||||||
"data-url",
|
|
||||||
"flate2",
|
|
||||||
"imagesize",
|
|
||||||
"kurbo 0.9.5",
|
|
||||||
"log",
|
|
||||||
"roxmltree 0.19.0",
|
|
||||||
"simplecss",
|
|
||||||
"siphasher 0.3.11",
|
|
||||||
"svgtypes",
|
|
||||||
"usvg-tree",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "usvg-tree"
|
|
||||||
version = "0.37.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8ee3d202ebdb97a6215604b8f5b4d6ef9024efd623cf2e373a6416ba976ec7d3"
|
|
||||||
dependencies = [
|
|
||||||
"rctree",
|
|
||||||
"strict-num",
|
|
||||||
"svgtypes",
|
|
||||||
"tiny-skia-path",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf16_iter"
|
name = "utf16_iter"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
@ -6005,15 +5713,6 @@ dependencies = [
|
|||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "webpki-roots"
|
|
||||||
version = "0.26.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9"
|
|
||||||
dependencies = [
|
|
||||||
"rustls-pki-types",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "weezl"
|
name = "weezl"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
@ -6748,12 +6447,6 @@ version = "0.8.25"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4"
|
checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xmlwriter"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yazi"
|
name = "yazi"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
@ -6950,12 +6643,6 @@ dependencies = [
|
|||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zeroize"
|
|
||||||
version = "1.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerovec"
|
name = "zerovec"
|
||||||
version = "0.10.4"
|
version = "0.10.4"
|
||||||
|
15
Cargo.toml
15
Cargo.toml
@ -4,10 +4,16 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
egui = "0.31.1"
|
||||||
|
egui-wgpu = { version = "0.31.1",features = ["winit"] }
|
||||||
|
egui-winit = "0.31.1"
|
||||||
|
winit = "0.30.9"
|
||||||
|
pollster = "0.4.0"
|
||||||
|
|
||||||
clap = { version = "4.5.34", features = ["derive"] }
|
clap = { version = "4.5.34", features = ["derive"] }
|
||||||
eframe = "0.31.1"
|
eframe = "0.31.1"
|
||||||
egui = "0.31.1"
|
# egui = "0.31.1"
|
||||||
egui_extras = { version = "0.31.1", features = ["all_loaders"] }
|
# egui_extras = { version = "0.31.1", features = ["all_loaders"] }
|
||||||
env_logger = "0.11.7"
|
env_logger = "0.11.7"
|
||||||
iced = { version = "0.13.1", features = ["debug", "canvas", "tokio", "image"]}
|
iced = { version = "0.13.1", features = ["debug", "canvas", "tokio", "image"]}
|
||||||
image = "0.25.6"
|
image = "0.25.6"
|
||||||
@ -15,15 +21,16 @@ image = "0.25.6"
|
|||||||
itertools = "0.12"
|
itertools = "0.12"
|
||||||
memmap2 = "0.9.5"
|
memmap2 = "0.9.5"
|
||||||
minifb = "0.28.0"
|
minifb = "0.28.0"
|
||||||
pollster = "0.4.0"
|
# pollster = "0.4.0"
|
||||||
rexiv2 = "0.10.0"
|
rexiv2 = "0.10.0"
|
||||||
threadpool = "1.8.1"
|
threadpool = "1.8.1"
|
||||||
# rustc-hash.workspace = true
|
# rustc-hash.workspace = true
|
||||||
tokio = { version = "1.44.1", features = ["sync"] }
|
tokio = { version = "1.44.1", features = ["sync"] }
|
||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = "0.3"
|
||||||
wgpu = "24.0.3"
|
wgpu = "24.0.3"
|
||||||
winit = "0.30.9"
|
# winit = "0.30.9"
|
||||||
zune-image = {version = "0.4.15", features = ["all"]}
|
zune-image = {version = "0.4.15", features = ["all"]}
|
||||||
|
bytemuck = "1.22.0"
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
debug = false
|
debug = false
|
||||||
|
609
src/app.rs
Normal file
609
src/app.rs
Normal file
@ -0,0 +1,609 @@
|
|||||||
|
use crate::egui_tools::EguiRenderer;
|
||||||
|
use eframe::WindowAttributes;
|
||||||
|
use egui::{Event, Key};
|
||||||
|
use egui_wgpu::wgpu::SurfaceError;
|
||||||
|
use egui_wgpu::{ScreenDescriptor, wgpu};
|
||||||
|
use imflow::store::ImageStore;
|
||||||
|
use std::any::Any;
|
||||||
|
use std::process::exit;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time;
|
||||||
|
use wgpu::util::DeviceExt;
|
||||||
|
use wgpu::{PipelineCompilationOptions, SurfaceConfiguration};
|
||||||
|
use winit::application::ApplicationHandler;
|
||||||
|
use winit::dpi::{LogicalSize, PhysicalSize};
|
||||||
|
use winit::event::WindowEvent;
|
||||||
|
use winit::event_loop::ActiveEventLoop;
|
||||||
|
use winit::platform::x11::WindowAttributesExtX11;
|
||||||
|
use winit::window::{Window, WindowId};
|
||||||
|
|
||||||
|
fn setup_texture(
|
||||||
|
device: &wgpu::Device,
|
||||||
|
surface_config: SurfaceConfiguration,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
) -> (wgpu::Texture, wgpu::BindGroup, wgpu::RenderPipeline) {
|
||||||
|
// Create your texture (one-time setup)
|
||||||
|
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||||
|
label: Some("Image texture"),
|
||||||
|
size: wgpu::Extent3d {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
||||||
|
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
||||||
|
view_formats: &[],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create texture view and sampler
|
||||||
|
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
||||||
|
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||||
|
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||||
|
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
||||||
|
mag_filter: wgpu::FilterMode::Linear,
|
||||||
|
min_filter: wgpu::FilterMode::Linear,
|
||||||
|
mipmap_filter: wgpu::FilterMode::Linear,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create bind group layout for the texture
|
||||||
|
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
|
label: Some("Texture Bind Group Layout"),
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 0,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Texture {
|
||||||
|
sample_type: wgpu::TextureSampleType::Float { filterable: true },
|
||||||
|
view_dimension: wgpu::TextureViewDimension::D2,
|
||||||
|
multisampled: false,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 1,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create bind group with your texture
|
||||||
|
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: Some("Texture Bind Group"),
|
||||||
|
layout: &bind_group_layout,
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: wgpu::BindingResource::TextureView(&texture_view),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 1,
|
||||||
|
resource: wgpu::BindingResource::Sampler(&sampler),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
// Define vertex buffer layout
|
||||||
|
let vertex_buffer_layout = wgpu::VertexBufferLayout {
|
||||||
|
array_stride: 5 * std::mem::size_of::<f32>() as wgpu::BufferAddress,
|
||||||
|
step_mode: wgpu::VertexStepMode::Vertex,
|
||||||
|
attributes: &[
|
||||||
|
// Position
|
||||||
|
wgpu::VertexAttribute {
|
||||||
|
offset: 0,
|
||||||
|
shader_location: 0,
|
||||||
|
format: wgpu::VertexFormat::Float32x3,
|
||||||
|
},
|
||||||
|
// UV
|
||||||
|
wgpu::VertexAttribute {
|
||||||
|
offset: 3 * std::mem::size_of::<f32>() as wgpu::BufferAddress,
|
||||||
|
shader_location: 1,
|
||||||
|
format: wgpu::VertexFormat::Float32x2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create shader modules
|
||||||
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
|
label: Some("Texture Shader"),
|
||||||
|
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(include_str!("shader.wgsl"))),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create the render pipeline (simplified, you'd need to define vertex buffers, etc.)
|
||||||
|
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: Some("Texture Render Pipeline"),
|
||||||
|
layout: Some(
|
||||||
|
&device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
|
label: Some("Texture Pipeline Layout"),
|
||||||
|
bind_group_layouts: &[&bind_group_layout],
|
||||||
|
push_constant_ranges: &[],
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: Some("vs_main"),
|
||||||
|
buffers: &[vertex_buffer_layout],
|
||||||
|
compilation_options: PipelineCompilationOptions::default(),
|
||||||
|
},
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: Some("fs_main"),
|
||||||
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
|
format: surface_config.format,
|
||||||
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
|
})],
|
||||||
|
compilation_options: PipelineCompilationOptions::default(),
|
||||||
|
}),
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
|
cache: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
(texture, bind_group, render_pipeline)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AppState {
|
||||||
|
pub device: wgpu::Device,
|
||||||
|
pub queue: wgpu::Queue,
|
||||||
|
pub surface_config: wgpu::SurfaceConfiguration,
|
||||||
|
pub surface: wgpu::Surface<'static>,
|
||||||
|
pub scale_factor: f32,
|
||||||
|
pub egui_renderer: EguiRenderer,
|
||||||
|
pub store: ImageStore,
|
||||||
|
pub image_texture: wgpu::Texture,
|
||||||
|
pub bind_group: wgpu::BindGroup,
|
||||||
|
pub render_pipeline: wgpu::RenderPipeline,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppState {
|
||||||
|
async fn new(
|
||||||
|
instance: &wgpu::Instance,
|
||||||
|
surface: wgpu::Surface<'static>,
|
||||||
|
window: &Window,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
) -> Self {
|
||||||
|
let power_pref = wgpu::PowerPreference::default();
|
||||||
|
let adapter = instance
|
||||||
|
.request_adapter(&wgpu::RequestAdapterOptions {
|
||||||
|
power_preference: power_pref,
|
||||||
|
force_fallback_adapter: false,
|
||||||
|
compatible_surface: Some(&surface),
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.expect("Failed to find an appropriate adapter");
|
||||||
|
|
||||||
|
let features = wgpu::Features::empty();
|
||||||
|
let (device, queue) = adapter
|
||||||
|
.request_device(
|
||||||
|
&wgpu::DeviceDescriptor {
|
||||||
|
label: None,
|
||||||
|
required_features: features,
|
||||||
|
required_limits: Default::default(),
|
||||||
|
memory_hints: Default::default(),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("Failed to create device");
|
||||||
|
|
||||||
|
let swapchain_capabilities = surface.get_capabilities(&adapter);
|
||||||
|
let selected_format = wgpu::TextureFormat::Bgra8UnormSrgb;
|
||||||
|
let swapchain_format = swapchain_capabilities
|
||||||
|
.formats
|
||||||
|
.iter()
|
||||||
|
.find(|d| **d == selected_format)
|
||||||
|
.expect("failed to select proper surface texture format!");
|
||||||
|
|
||||||
|
let surface_config = wgpu::SurfaceConfiguration {
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
|
format: *swapchain_format,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
present_mode: wgpu::PresentMode::AutoVsync,
|
||||||
|
desired_maximum_frame_latency: 0,
|
||||||
|
alpha_mode: swapchain_capabilities.alpha_modes[0],
|
||||||
|
view_formats: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
surface.configure(&device, &surface_config);
|
||||||
|
|
||||||
|
let egui_renderer = EguiRenderer::new(&device, surface_config.format, None, 1, window);
|
||||||
|
|
||||||
|
let scale_factor = 1.0;
|
||||||
|
|
||||||
|
let store = ImageStore::new("./test_images".into());
|
||||||
|
|
||||||
|
let (image_texture, bind_group, render_pipeline) =
|
||||||
|
setup_texture(&device, surface_config.clone(), 6000, 4000);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
device,
|
||||||
|
queue,
|
||||||
|
surface,
|
||||||
|
surface_config,
|
||||||
|
egui_renderer,
|
||||||
|
scale_factor,
|
||||||
|
store,
|
||||||
|
image_texture,
|
||||||
|
bind_group,
|
||||||
|
render_pipeline,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize_surface(&mut self, width: u32, height: u32) {
|
||||||
|
self.surface_config.width = width;
|
||||||
|
self.surface_config.height = height;
|
||||||
|
self.surface.configure(&self.device, &self.surface_config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct App {
|
||||||
|
instance: wgpu::Instance,
|
||||||
|
state: Option<AppState>,
|
||||||
|
window: Option<Arc<Window>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl App {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let instance = egui_wgpu::wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
|
||||||
|
Self {
|
||||||
|
instance,
|
||||||
|
state: None,
|
||||||
|
window: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_window(&mut self, window: Window) {
|
||||||
|
let window = Arc::new(window);
|
||||||
|
let initial_width = 1500;
|
||||||
|
let initial_height = 1000;
|
||||||
|
|
||||||
|
let _ = window.request_inner_size(PhysicalSize::new(initial_width, initial_height));
|
||||||
|
|
||||||
|
let surface = self
|
||||||
|
.instance
|
||||||
|
.create_surface(window.clone())
|
||||||
|
.expect("Failed to create surface!");
|
||||||
|
|
||||||
|
let state = AppState::new(
|
||||||
|
&self.instance,
|
||||||
|
surface,
|
||||||
|
&window,
|
||||||
|
initial_width,
|
||||||
|
initial_width,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
self.window.get_or_insert(window);
|
||||||
|
self.state.get_or_insert(state);
|
||||||
|
|
||||||
|
self.update_texture();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_resized(&mut self, width: u32, height: u32) {
|
||||||
|
println!("Resized {} {}", width, height);
|
||||||
|
if width > 0 && height > 0 {
|
||||||
|
self.state.as_mut().unwrap().resize_surface(width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_texture(&mut self) {
|
||||||
|
let state = self.state.as_mut().unwrap();
|
||||||
|
|
||||||
|
state.store.check_loaded_images();
|
||||||
|
let imbuf = if let Some(full) = state.store.get_current_image() {
|
||||||
|
println!("full");
|
||||||
|
full
|
||||||
|
} else {
|
||||||
|
state.store.get_thumbnail()
|
||||||
|
};
|
||||||
|
let width = imbuf.width as u32;
|
||||||
|
let height = imbuf.height as u32;
|
||||||
|
let buffer_u8 = unsafe {
|
||||||
|
std::slice::from_raw_parts(
|
||||||
|
imbuf.argb_buffer.as_ptr() as *const u8,
|
||||||
|
imbuf.argb_buffer.len() * 4,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
state.queue.write_texture(
|
||||||
|
wgpu::TexelCopyTextureInfo {
|
||||||
|
texture: &state.image_texture,
|
||||||
|
mip_level: 0,
|
||||||
|
origin: wgpu::Origin3d::ZERO,
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
},
|
||||||
|
&buffer_u8,
|
||||||
|
wgpu::TexelCopyBufferLayout {
|
||||||
|
offset: 0,
|
||||||
|
bytes_per_row: Some(4 * width), // 4 bytes per ARGB pixel
|
||||||
|
rows_per_image: Some(height),
|
||||||
|
},
|
||||||
|
wgpu::Extent3d {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_redraw(&mut self) {
|
||||||
|
// Attempt to handle minimizing window
|
||||||
|
if let Some(window) = self.window.as_ref() {
|
||||||
|
if let Some(min) = window.is_minimized() {
|
||||||
|
if min {
|
||||||
|
println!("Window is minimized");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let state = self.state.as_mut().unwrap();
|
||||||
|
|
||||||
|
let screen_descriptor = ScreenDescriptor {
|
||||||
|
size_in_pixels: [state.surface_config.width, state.surface_config.height],
|
||||||
|
pixels_per_point: self.window.as_ref().unwrap().scale_factor() as f32
|
||||||
|
* state.scale_factor,
|
||||||
|
};
|
||||||
|
|
||||||
|
let surface_texture = state.surface.get_current_texture();
|
||||||
|
|
||||||
|
let surface_texture = match surface_texture {
|
||||||
|
Err(SurfaceError::Outdated) => {
|
||||||
|
// Ignoring outdated to allow resizing and minimization
|
||||||
|
println!("wgpu surface outdated");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(SurfaceError::Timeout) => {
|
||||||
|
println!("wgpu surface timeout");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
surface_texture.expect("Failed to acquire next swap chain texture");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Ok(surface_texture) => surface_texture,
|
||||||
|
};
|
||||||
|
|
||||||
|
let surface_view = surface_texture
|
||||||
|
.texture
|
||||||
|
.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
||||||
|
let mut encoder = state
|
||||||
|
.device
|
||||||
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||||
|
|
||||||
|
// Add this render pass to clear the screen with green
|
||||||
|
{
|
||||||
|
let _ = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: None,
|
||||||
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
view: &surface_view,
|
||||||
|
resolve_target: None,
|
||||||
|
ops: wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Clear(wgpu::Color {
|
||||||
|
r: 0.0,
|
||||||
|
g: 1.0, // Green
|
||||||
|
b: 0.0,
|
||||||
|
a: 1.0,
|
||||||
|
}),
|
||||||
|
store: wgpu::StoreOp::Store,
|
||||||
|
},
|
||||||
|
})],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
timestamp_writes: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Define vertices for your quad
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
struct Vertex {
|
||||||
|
position: [f32; 3],
|
||||||
|
tex_coords: [f32; 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define a quad (two triangles)
|
||||||
|
let vertices = [
|
||||||
|
// Position (x, y, z), Texture coords (u, v)
|
||||||
|
Vertex {
|
||||||
|
position: [-1.0, -1.0, 0.0],
|
||||||
|
tex_coords: [0.0, 1.0],
|
||||||
|
}, // bottom left
|
||||||
|
Vertex {
|
||||||
|
position: [-1.0, 1.0, 0.0],
|
||||||
|
tex_coords: [0.0, 0.0],
|
||||||
|
}, // top left
|
||||||
|
Vertex {
|
||||||
|
position: [1.0, -1.0, 0.0],
|
||||||
|
tex_coords: [1.0, 1.0],
|
||||||
|
}, // bottom right
|
||||||
|
Vertex {
|
||||||
|
position: [1.0, 1.0, 0.0],
|
||||||
|
tex_coords: [1.0, 0.0],
|
||||||
|
}, // top right
|
||||||
|
];
|
||||||
|
|
||||||
|
// Create indices for drawing two triangles
|
||||||
|
let indices: [u16; 6] = [0, 1, 2, 2, 1, 3];
|
||||||
|
|
||||||
|
// Create vertex buffer
|
||||||
|
let vertex_buffer =
|
||||||
|
state
|
||||||
|
.device
|
||||||
|
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some("Vertex Buffer"),
|
||||||
|
contents: bytemuck::cast_slice(&vertices),
|
||||||
|
usage: wgpu::BufferUsages::VERTEX,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create index buffer
|
||||||
|
let index_buffer = state
|
||||||
|
.device
|
||||||
|
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some("Index Buffer"),
|
||||||
|
contents: bytemuck::cast_slice(&indices),
|
||||||
|
usage: wgpu::BufferUsages::INDEX,
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: Some("Texture Render Pass"),
|
||||||
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
view: &surface_view,
|
||||||
|
resolve_target: None,
|
||||||
|
ops: wgpu::Operations {
|
||||||
|
// Use Load instead of Clear so we don't erase the green background
|
||||||
|
load: wgpu::LoadOp::Load,
|
||||||
|
store: wgpu::StoreOp::Store,
|
||||||
|
},
|
||||||
|
})],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
timestamp_writes: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
render_pass.set_pipeline(&state.render_pipeline);
|
||||||
|
render_pass.set_bind_group(0, &state.bind_group, &[]);
|
||||||
|
|
||||||
|
// Bind the vertex buffer
|
||||||
|
render_pass.set_vertex_buffer(0, vertex_buffer.slice(..));
|
||||||
|
|
||||||
|
// Draw using the index buffer (more efficient)
|
||||||
|
render_pass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint16);
|
||||||
|
render_pass.draw_indexed(0..6, 0, 0..1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let rating = state.store.get_current_rating();
|
||||||
|
let window = self.window.as_ref().unwrap();
|
||||||
|
{
|
||||||
|
state.egui_renderer.begin_frame(window);
|
||||||
|
|
||||||
|
egui::Window::new("Rating")
|
||||||
|
.collapsible(false)
|
||||||
|
.resizable(false)
|
||||||
|
.default_width(5.0)
|
||||||
|
.show(state.egui_renderer.context(), |ui| {
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
ui.label(
|
||||||
|
egui::RichText::new(format!("{:.1}", rating))
|
||||||
|
.size(42.0)
|
||||||
|
.strong(),
|
||||||
|
);
|
||||||
|
// ui.add_space(10.0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
state.egui_renderer.end_frame_and_draw(
|
||||||
|
&state.device,
|
||||||
|
&state.queue,
|
||||||
|
&mut encoder,
|
||||||
|
window,
|
||||||
|
&surface_view,
|
||||||
|
screen_descriptor,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.queue.submit(Some(encoder.finish()));
|
||||||
|
surface_texture.present();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplicationHandler for App {
|
||||||
|
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
|
||||||
|
let attributes = Window::default_attributes()
|
||||||
|
.with_base_size(LogicalSize::new(2000, 4000))
|
||||||
|
.with_resizable(false);
|
||||||
|
let window = event_loop.create_window(attributes).unwrap();
|
||||||
|
pollster::block_on(self.set_window(window));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_event(&mut self, event_loop: &ActiveEventLoop, _: WindowId, event: WindowEvent) {
|
||||||
|
// let egui render to process the event first
|
||||||
|
self.state
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.egui_renderer
|
||||||
|
.handle_input(self.window.as_ref().unwrap(), &event);
|
||||||
|
|
||||||
|
match event {
|
||||||
|
WindowEvent::CloseRequested => {
|
||||||
|
println!("The close button was pressed; stopping");
|
||||||
|
event_loop.exit();
|
||||||
|
}
|
||||||
|
WindowEvent::RedrawRequested => {
|
||||||
|
let start = time::Instant::now();
|
||||||
|
self.handle_redraw();
|
||||||
|
// println!("Updated in: {}ms", start.elapsed().as_millis());
|
||||||
|
// Extract the events by cloning them from the input context
|
||||||
|
let events = self
|
||||||
|
.state
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.egui_renderer
|
||||||
|
.context()
|
||||||
|
.input(|i| {
|
||||||
|
i.events.clone() // Clone the events to own them outside the closure
|
||||||
|
});
|
||||||
|
|
||||||
|
// Now use the extracted events outside the closure
|
||||||
|
events.iter().for_each(|e| {
|
||||||
|
if let Event::Key { key, pressed, .. } = e {
|
||||||
|
if !*pressed {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
match *key {
|
||||||
|
Key::ArrowLeft => {
|
||||||
|
self.state.as_mut().unwrap().store.next_image(-1);
|
||||||
|
self.update_texture();
|
||||||
|
}
|
||||||
|
Key::ArrowRight => {
|
||||||
|
self.state.as_mut().unwrap().store.next_image(1);
|
||||||
|
self.update_texture();
|
||||||
|
}
|
||||||
|
Key::ArrowUp => {
|
||||||
|
let rating =
|
||||||
|
self.state.as_mut().unwrap().store.get_current_rating();
|
||||||
|
self.state.as_mut().unwrap().store.set_rating(rating + 1);
|
||||||
|
}
|
||||||
|
Key::ArrowDown => {
|
||||||
|
let rating =
|
||||||
|
self.state.as_mut().unwrap().store.get_current_rating();
|
||||||
|
self.state.as_mut().unwrap().store.set_rating(rating - 1);
|
||||||
|
}
|
||||||
|
Key::Backtick => self.state.as_mut().unwrap().store.set_rating(0),
|
||||||
|
Key::Num0 => self.state.as_mut().unwrap().store.set_rating(0),
|
||||||
|
Key::Num1 => self.state.as_mut().unwrap().store.set_rating(1),
|
||||||
|
Key::Num2 => self.state.as_mut().unwrap().store.set_rating(2),
|
||||||
|
Key::Num3 => self.state.as_mut().unwrap().store.set_rating(3),
|
||||||
|
Key::Num4 => self.state.as_mut().unwrap().store.set_rating(4),
|
||||||
|
Key::Num5 => self.state.as_mut().unwrap().store.set_rating(5),
|
||||||
|
Key::Escape => exit(0),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.window.as_ref().unwrap().request_redraw();
|
||||||
|
}
|
||||||
|
WindowEvent::Resized(new_size) => {
|
||||||
|
self.handle_resized(new_size.width, new_size.height);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
118
src/egui_tools.rs
Normal file
118
src/egui_tools.rs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
use egui::Context;
|
||||||
|
use egui_wgpu::wgpu::{CommandEncoder, Device, Queue, StoreOp, TextureFormat, TextureView};
|
||||||
|
use egui_wgpu::{wgpu, Renderer, ScreenDescriptor};
|
||||||
|
use egui_winit::State;
|
||||||
|
use winit::event::WindowEvent;
|
||||||
|
use winit::window::Window;
|
||||||
|
|
||||||
|
pub struct EguiRenderer {
|
||||||
|
state: State,
|
||||||
|
renderer: Renderer,
|
||||||
|
frame_started: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EguiRenderer {
|
||||||
|
pub fn context(&self) -> &Context {
|
||||||
|
self.state.egui_ctx()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(
|
||||||
|
device: &Device,
|
||||||
|
output_color_format: TextureFormat,
|
||||||
|
output_depth_format: Option<TextureFormat>,
|
||||||
|
msaa_samples: u32,
|
||||||
|
window: &Window,
|
||||||
|
) -> EguiRenderer {
|
||||||
|
let egui_context = Context::default();
|
||||||
|
|
||||||
|
let egui_state = egui_winit::State::new(
|
||||||
|
egui_context,
|
||||||
|
egui::viewport::ViewportId::ROOT,
|
||||||
|
&window,
|
||||||
|
Some(window.scale_factor() as f32),
|
||||||
|
None,
|
||||||
|
Some(2 * 1024), // default dimension is 2048
|
||||||
|
);
|
||||||
|
let egui_renderer = Renderer::new(
|
||||||
|
device,
|
||||||
|
output_color_format,
|
||||||
|
output_depth_format,
|
||||||
|
msaa_samples,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
EguiRenderer {
|
||||||
|
state: egui_state,
|
||||||
|
renderer: egui_renderer,
|
||||||
|
frame_started: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_input(&mut self, window: &Window, event: &WindowEvent) {
|
||||||
|
let _ = self.state.on_window_event(window, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ppp(&mut self, v: f32) {
|
||||||
|
self.context().set_pixels_per_point(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn begin_frame(&mut self, window: &Window) {
|
||||||
|
let raw_input = self.state.take_egui_input(window);
|
||||||
|
self.state.egui_ctx().begin_pass(raw_input);
|
||||||
|
self.frame_started = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn end_frame_and_draw(
|
||||||
|
&mut self,
|
||||||
|
device: &Device,
|
||||||
|
queue: &Queue,
|
||||||
|
encoder: &mut CommandEncoder,
|
||||||
|
window: &Window,
|
||||||
|
window_surface_view: &TextureView,
|
||||||
|
screen_descriptor: ScreenDescriptor,
|
||||||
|
) {
|
||||||
|
if !self.frame_started {
|
||||||
|
panic!("begin_frame must be called before end_frame_and_draw can be called!");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ppp(screen_descriptor.pixels_per_point);
|
||||||
|
|
||||||
|
let full_output = self.state.egui_ctx().end_pass();
|
||||||
|
|
||||||
|
self.state
|
||||||
|
.handle_platform_output(window, full_output.platform_output);
|
||||||
|
|
||||||
|
let tris = self
|
||||||
|
.state
|
||||||
|
.egui_ctx()
|
||||||
|
.tessellate(full_output.shapes, self.state.egui_ctx().pixels_per_point());
|
||||||
|
for (id, image_delta) in &full_output.textures_delta.set {
|
||||||
|
self.renderer
|
||||||
|
.update_texture(device, queue, *id, image_delta);
|
||||||
|
}
|
||||||
|
self.renderer
|
||||||
|
.update_buffers(device, queue, encoder, &tris, &screen_descriptor);
|
||||||
|
let rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
view: window_surface_view,
|
||||||
|
resolve_target: None,
|
||||||
|
ops: egui_wgpu::wgpu::Operations {
|
||||||
|
load: egui_wgpu::wgpu::LoadOp::Load,
|
||||||
|
store: StoreOp::Store,
|
||||||
|
},
|
||||||
|
})],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
timestamp_writes: None,
|
||||||
|
label: Some("egui main render pass"),
|
||||||
|
occlusion_query_set: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
self.renderer
|
||||||
|
.render(&mut rpass.forget_lifetime(), &tris, &screen_descriptor);
|
||||||
|
for x in &full_output.textures_delta.free {
|
||||||
|
self.renderer.free_texture(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.frame_started = false;
|
||||||
|
}
|
||||||
|
}
|
47
src/image.rs
47
src/image.rs
@ -1,6 +1,7 @@
|
|||||||
use iced::widget::image::Handle;
|
use iced::widget::image::Handle;
|
||||||
use image::DynamicImage;
|
use image::DynamicImage;
|
||||||
use image::imageops::FilterType;
|
use image::imageops::FilterType;
|
||||||
|
use rexiv2::Metadata;
|
||||||
use zune_image::codecs::jpeg::JpegDecoder;
|
use zune_image::codecs::jpeg::JpegDecoder;
|
||||||
use zune_image::codecs::qoi::zune_core::colorspace::ColorSpace;
|
use zune_image::codecs::qoi::zune_core::colorspace::ColorSpace;
|
||||||
use zune_image::codecs::qoi::zune_core::options::DecoderOptions;
|
use zune_image::codecs::qoi::zune_core::options::DecoderOptions;
|
||||||
@ -17,16 +18,38 @@ pub struct ImflowImageBuffer {
|
|||||||
pub width: usize,
|
pub width: usize,
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
pub argb_buffer: Vec<u32>,
|
pub argb_buffer: Vec<u32>,
|
||||||
|
pub rating: i32
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_iced_handle(width: u32, height: u32, rgba: Vec<u8>) -> Handle {
|
pub fn create_iced_handle(width: u32, height: u32, rgba: Vec<u8>) -> Handle {
|
||||||
Handle::from_rgba(width, height, rgba)
|
Handle::from_rgba(width, height, rgba)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_rating(filename: PathBuf) -> i32 {
|
||||||
|
// if !path_exists(filename.clone()) {
|
||||||
|
// anyhow::bail!("File doesn't exist");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Use xmp-toolkit for video files
|
||||||
|
// if is_video(&filename) {
|
||||||
|
// return Ok(read_rating_xmp(filename.clone()).unwrap_or(0));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Use rexiv2 for image files
|
||||||
|
let meta = Metadata::new_from_path(filename);
|
||||||
|
match meta {
|
||||||
|
Ok(meta) => {
|
||||||
|
let rating = meta.get_tag_numeric("Xmp.xmp.Rating");
|
||||||
|
rating
|
||||||
|
}
|
||||||
|
Err(e) => panic!("{:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_image(path: PathBuf) -> ImflowImageBuffer {
|
pub fn load_image(path: PathBuf) -> ImflowImageBuffer {
|
||||||
let total_start = Instant::now();
|
let total_start = Instant::now();
|
||||||
|
|
||||||
let file = read(path).unwrap();
|
let file = read(path.clone()).unwrap();
|
||||||
let mut decoder = JpegDecoder::new(&file);
|
let mut decoder = JpegDecoder::new(&file);
|
||||||
let options = DecoderOptions::new_fast().jpeg_set_out_colorspace(ColorSpace::BGRA);
|
let options = DecoderOptions::new_fast().jpeg_set_out_colorspace(ColorSpace::BGRA);
|
||||||
decoder.set_options(options);
|
decoder.set_options(options);
|
||||||
@ -52,10 +75,13 @@ pub fn load_image(path: PathBuf) -> ImflowImageBuffer {
|
|||||||
let total_time = total_start.elapsed();
|
let total_time = total_start.elapsed();
|
||||||
println!("Total loading time: {:?}", total_time);
|
println!("Total loading time: {:?}", total_time);
|
||||||
|
|
||||||
|
let rating = get_rating(path);
|
||||||
|
|
||||||
ImflowImageBuffer {
|
ImflowImageBuffer {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
argb_buffer: buffer_u32,
|
argb_buffer: buffer_u32,
|
||||||
|
rating
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,12 +89,14 @@ pub fn image_to_argb_buffer(img: DynamicImage) -> Vec<u32> {
|
|||||||
let flat = img.into_rgba8();
|
let flat = img.into_rgba8();
|
||||||
let buf = flat.as_raw();
|
let buf = flat.as_raw();
|
||||||
|
|
||||||
buf.chunks_exact(4).map(|rgba| {
|
buf.chunks_exact(4)
|
||||||
let r = rgba[0] as u32;
|
.map(|rgba| {
|
||||||
let g = rgba[1] as u32;
|
let r = rgba[0] as u32;
|
||||||
let b = rgba[2] as u32;
|
let g = rgba[1] as u32;
|
||||||
r << 16 | g << 8 | b
|
let b = rgba[2] as u32;
|
||||||
}).collect()
|
r << 16 | g << 8 | b
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_available_images(dir: PathBuf) -> Vec<PathBuf> {
|
pub fn load_available_images(dir: PathBuf) -> Vec<PathBuf> {
|
||||||
@ -121,10 +149,13 @@ pub fn load_thumbnail_exif(path: &PathBuf) -> Option<ImflowImageBuffer> {
|
|||||||
*argb = r << 16 | g << 8 | b;
|
*argb = r << 16 | g << 8 | b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let rating = get_rating(path.into());
|
||||||
|
|
||||||
Some(ImflowImageBuffer {
|
Some(ImflowImageBuffer {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
argb_buffer: buffer,
|
argb_buffer: buffer,
|
||||||
|
rating
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -143,10 +174,12 @@ pub fn load_thumbnail_full(path: &PathBuf) -> ImflowImageBuffer {
|
|||||||
let width = image.width() as usize;
|
let width = image.width() as usize;
|
||||||
let height = image.height() as usize;
|
let height = image.height() as usize;
|
||||||
let buffer = image_to_argb_buffer(image);
|
let buffer = image_to_argb_buffer(image);
|
||||||
|
let rating = get_rating(path.into());
|
||||||
|
|
||||||
ImflowImageBuffer {
|
ImflowImageBuffer {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
argb_buffer: buffer,
|
argb_buffer: buffer,
|
||||||
|
rating
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
260
src/main.rs
260
src/main.rs
@ -317,6 +317,66 @@ use imflow::store::ImageStore;
|
|||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
use egui::{ColorImage, Image, TextureHandle, TextureOptions};
|
use egui::{ColorImage, Image, TextureHandle, TextureOptions};
|
||||||
|
|
||||||
|
mod app;
|
||||||
|
mod egui_tools;
|
||||||
|
|
||||||
|
use winit::event_loop::{ControlFlow, EventLoop};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
{
|
||||||
|
pollster::block_on(run());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run() {
|
||||||
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
|
event_loop.set_control_flow(ControlFlow::Poll);
|
||||||
|
|
||||||
|
let mut app = app::App::new();
|
||||||
|
|
||||||
|
event_loop.run_app(&mut app).expect("Failed to run app");
|
||||||
|
|
||||||
|
// let path = args.path.unwrap_or("./test_images".into());
|
||||||
|
// let mut state = ImageStore::new(path);
|
||||||
|
// let mut waiting = true;
|
||||||
|
// window.set_key_repeat_delay(0.1);
|
||||||
|
// window.set_key_repeat_rate(0.1);
|
||||||
|
|
||||||
|
// show_image(&mut window, state.get_thumbnail());
|
||||||
|
|
||||||
|
// while window.is_open() && !window.is_key_down(Key::Escape) {
|
||||||
|
// window.update();
|
||||||
|
// state.check_loaded_images();
|
||||||
|
// if window.is_key_pressed(Key::Right, minifb::KeyRepeat::Yes) {
|
||||||
|
// state.next_image(1);
|
||||||
|
// if let Some(full) = state.get_current_image() {
|
||||||
|
// show_image(&mut window, full);
|
||||||
|
// } else {
|
||||||
|
// show_image(&mut window, state.get_thumbnail());
|
||||||
|
// waiting = true;
|
||||||
|
// }
|
||||||
|
// } else if window.is_key_pressed(Key::Left, minifb::KeyRepeat::Yes) {
|
||||||
|
// state.next_image(-1);
|
||||||
|
// if let Some(full) = state.get_current_image() {
|
||||||
|
// show_image(&mut window, full);
|
||||||
|
// } else {
|
||||||
|
// show_image(&mut window, state.get_thumbnail());
|
||||||
|
// waiting = true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if waiting {
|
||||||
|
// if let Some(image) = state.get_current_image() {
|
||||||
|
// waiting = false;
|
||||||
|
|
||||||
|
// show_image(&mut window, &image);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct MyApp {
|
struct MyApp {
|
||||||
// image: Image,
|
// image: Image,
|
||||||
store: ImageStore,
|
store: ImageStore,
|
||||||
@ -361,105 +421,133 @@ struct Args {
|
|||||||
path: Option<PathBuf>,
|
path: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
// fn init_app() {
|
||||||
let native_options = eframe::NativeOptions {
|
|
||||||
viewport: egui::ViewportBuilder::default().with_inner_size((400.0, 400.0)),
|
// let mut store = ImageStore::new("./test_images".into());
|
||||||
..eframe::NativeOptions::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
eframe::run_native(
|
// let mut imbuf = store.get_current_image().unwrap();
|
||||||
"aaa",
|
|
||||||
native_options,
|
|
||||||
Box::new(|cc| {
|
|
||||||
// Initialize image loaders
|
|
||||||
egui_extras::install_image_loaders(&cc.egui_ctx);
|
|
||||||
let mut store = ImageStore::new("./test_images".into());
|
|
||||||
|
|
||||||
let mut imbuf = store.get_current_image().unwrap();
|
// let width = imbuf.width;
|
||||||
|
// let height = imbuf.height;
|
||||||
|
|
||||||
let width = imbuf.width;
|
// let mut buffer = imbuf.argb_buffer.clone();
|
||||||
let height = imbuf.height;
|
// // Reinterpret to avoid copying
|
||||||
|
// let buffer_u8 = unsafe {
|
||||||
|
// Vec::from_raw_parts(
|
||||||
|
// buffer.as_mut_ptr() as *mut u8,
|
||||||
|
// buffer.len() * 4,
|
||||||
|
// buffer.capacity() * 4,
|
||||||
|
// )
|
||||||
|
// };
|
||||||
|
// std::mem::forget(buffer);
|
||||||
|
|
||||||
let mut buffer = imbuf.argb_buffer.clone();
|
// let color_image = ColorImage::from_rgba_unmultiplied([width, height], &buffer_u8);
|
||||||
// Reinterpret to avoid copying
|
// let texture = cc
|
||||||
let buffer_u8 = unsafe {
|
// .egui_ctx
|
||||||
Vec::from_raw_parts(
|
// .load_texture("img", color_image, TextureOptions::LINEAR);
|
||||||
buffer.as_mut_ptr() as *mut u8,
|
|
||||||
buffer.len() * 4,
|
|
||||||
buffer.capacity() * 4,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
std::mem::forget(buffer);
|
|
||||||
|
|
||||||
let color_image = ColorImage::from_rgba_unmultiplied([width, height], &buffer_u8);
|
// Ok(Box::new(MyApp::new(store, texture)))
|
||||||
let texture = cc
|
// }
|
||||||
.egui_ctx
|
|
||||||
.load_texture("img", color_image, TextureOptions::LINEAR);
|
|
||||||
|
|
||||||
Ok(Box::new(MyApp::new(store, texture)))
|
// fn main() {
|
||||||
}),
|
// let native_options = eframe::NativeOptions {
|
||||||
)
|
// viewport: egui::ViewportBuilder::default().with_inner_size((400.0, 400.0)),
|
||||||
.unwrap();
|
// ..eframe::NativeOptions::default()
|
||||||
// eframe::run_native(Box::new(MyApp::default()), options);
|
// };
|
||||||
|
|
||||||
let args = Args::parse();
|
// eframe::run_native(
|
||||||
const WIDTH: usize = 2000;
|
// "aaa",
|
||||||
const HEIGHT: usize = 1000;
|
// native_options,
|
||||||
let mut window = Window::new(
|
// Box::new(|cc| {
|
||||||
"Test - ESC to exit",
|
// // Initialize image loaders
|
||||||
WIDTH,
|
// egui_extras::install_image_loaders(&cc.egui_ctx);
|
||||||
HEIGHT,
|
// let mut store = ImageStore::new("./test_images".into());
|
||||||
WindowOptions::default(),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
panic!("{}", e);
|
|
||||||
});
|
|
||||||
|
|
||||||
window.set_target_fps(120);
|
// let mut imbuf = store.get_current_image().unwrap();
|
||||||
|
|
||||||
let path = args.path.unwrap_or("./test_images".into());
|
// let width = imbuf.width;
|
||||||
let mut state = ImageStore::new(path);
|
// let height = imbuf.height;
|
||||||
let mut waiting = true;
|
|
||||||
window.set_key_repeat_delay(0.1);
|
|
||||||
window.set_key_repeat_rate(0.1);
|
|
||||||
|
|
||||||
show_image(&mut window, state.get_thumbnail());
|
// let mut buffer = imbuf.argb_buffer.clone();
|
||||||
|
// // Reinterpret to avoid copying
|
||||||
|
// let buffer_u8 = unsafe {
|
||||||
|
// Vec::from_raw_parts(
|
||||||
|
// buffer.as_mut_ptr() as *mut u8,
|
||||||
|
// buffer.len() * 4,
|
||||||
|
// buffer.capacity() * 4,
|
||||||
|
// )
|
||||||
|
// };
|
||||||
|
// std::mem::forget(buffer);
|
||||||
|
|
||||||
while window.is_open() && !window.is_key_down(Key::Escape) {
|
// let color_image = ColorImage::from_rgba_unmultiplied([width, height], &buffer_u8);
|
||||||
window.update();
|
// let texture = cc
|
||||||
state.check_loaded_images();
|
// .egui_ctx
|
||||||
if window.is_key_pressed(Key::Right, minifb::KeyRepeat::Yes) {
|
// .load_texture("img", color_image, TextureOptions::LINEAR);
|
||||||
state.next_image(1);
|
|
||||||
if let Some(full) = state.get_current_image() {
|
|
||||||
show_image(&mut window, full);
|
|
||||||
} else {
|
|
||||||
show_image(&mut window, state.get_thumbnail());
|
|
||||||
waiting = true;
|
|
||||||
}
|
|
||||||
} else if window.is_key_pressed(Key::Left, minifb::KeyRepeat::Yes) {
|
|
||||||
state.next_image(-1);
|
|
||||||
if let Some(full) = state.get_current_image() {
|
|
||||||
show_image(&mut window, full);
|
|
||||||
} else {
|
|
||||||
show_image(&mut window, state.get_thumbnail());
|
|
||||||
waiting = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if waiting {
|
|
||||||
if let Some(image) = state.get_current_image() {
|
|
||||||
waiting = false;
|
|
||||||
|
|
||||||
show_image(&mut window, &image);
|
// Ok(Box::new(MyApp::new(store, texture)))
|
||||||
}
|
// }),
|
||||||
}
|
// )
|
||||||
}
|
// .unwrap();
|
||||||
}
|
// // eframe::run_native(Box::new(MyApp::default()), options);
|
||||||
|
|
||||||
fn show_image(window: &mut Window, image: &ImflowImageBuffer) {
|
// let args = Args::parse();
|
||||||
window
|
// const WIDTH: usize = 2000;
|
||||||
.update_with_buffer(&image.argb_buffer, image.width, image.height)
|
// const HEIGHT: usize = 1000;
|
||||||
.unwrap();
|
// let mut window = Window::new(
|
||||||
}
|
// "Test - ESC to exit",
|
||||||
|
// WIDTH,
|
||||||
|
// HEIGHT,
|
||||||
|
// WindowOptions::default(),
|
||||||
|
// )
|
||||||
|
// .unwrap_or_else(|e| {
|
||||||
|
// panic!("{}", e);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// window.set_target_fps(120);
|
||||||
|
|
||||||
|
// let path = args.path.unwrap_or("./test_images".into());
|
||||||
|
// let mut state = ImageStore::new(path);
|
||||||
|
// let mut waiting = true;
|
||||||
|
// window.set_key_repeat_delay(0.1);
|
||||||
|
// window.set_key_repeat_rate(0.1);
|
||||||
|
|
||||||
|
// show_image(&mut window, state.get_thumbnail());
|
||||||
|
|
||||||
|
// while window.is_open() && !window.is_key_down(Key::Escape) {
|
||||||
|
// window.update();
|
||||||
|
// state.check_loaded_images();
|
||||||
|
// if window.is_key_pressed(Key::Right, minifb::KeyRepeat::Yes) {
|
||||||
|
// state.next_image(1);
|
||||||
|
// if let Some(full) = state.get_current_image() {
|
||||||
|
// show_image(&mut window, full);
|
||||||
|
// } else {
|
||||||
|
// show_image(&mut window, state.get_thumbnail());
|
||||||
|
// waiting = true;
|
||||||
|
// }
|
||||||
|
// } else if window.is_key_pressed(Key::Left, minifb::KeyRepeat::Yes) {
|
||||||
|
// state.next_image(-1);
|
||||||
|
// if let Some(full) = state.get_current_image() {
|
||||||
|
// show_image(&mut window, full);
|
||||||
|
// } else {
|
||||||
|
// show_image(&mut window, state.get_thumbnail());
|
||||||
|
// waiting = true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if waiting {
|
||||||
|
// if let Some(image) = state.get_current_image() {
|
||||||
|
// waiting = false;
|
||||||
|
|
||||||
|
// show_image(&mut window, &image);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn show_image(window: &mut Window, image: &ImflowImageBuffer) {
|
||||||
|
// window
|
||||||
|
// .update_with_buffer(&image.argb_buffer, image.width, image.height)
|
||||||
|
// .unwrap();
|
||||||
|
// }
|
||||||
|
|
||||||
// struct MainApp {
|
// struct MainApp {
|
||||||
// is_playing: bool,
|
// is_playing: bool,
|
||||||
|
25
src/shader.wgsl
Normal file
25
src/shader.wgsl
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
struct VertexInput {
|
||||||
|
@location(0) position: vec3<f32>,
|
||||||
|
@location(1) uv: vec2<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) position: vec4<f32>,
|
||||||
|
@location(0) uv: vec2<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
out.position = vec4<f32>(in.position, 1.0);
|
||||||
|
out.uv = in.uv;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@group(0) @binding(0) var texture: texture_2d<f32>;
|
||||||
|
@group(0) @binding(1) var texture_sampler: sampler;
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fs_main(@location(0) uv: vec2<f32>) -> @location(0) vec4<f32> {
|
||||||
|
return textureSample(texture, texture_sampler, uv);
|
||||||
|
}
|
35
src/store.rs
35
src/store.rs
@ -1,7 +1,6 @@
|
|||||||
use crate::image::load_thumbnail;
|
use crate::image::load_thumbnail;
|
||||||
use crate::image::{
|
use crate::image::{ImflowImageBuffer, load_available_images, load_image};
|
||||||
ImflowImageBuffer, load_available_images, load_image,
|
use rexiv2::Metadata;
|
||||||
};
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -73,6 +72,36 @@ impl ImageStore {
|
|||||||
state
|
state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_rating(&mut self, rating: i32) {
|
||||||
|
let meta = Metadata::new_from_path(self.current_image_path.clone());
|
||||||
|
match meta {
|
||||||
|
Ok(meta) => {
|
||||||
|
meta.set_tag_numeric("Xmp.xmp.Rating", rating).unwrap();
|
||||||
|
meta.save_to_file(self.current_image_path.clone()).unwrap();
|
||||||
|
}
|
||||||
|
Err(e) => panic!("{:?}", e),
|
||||||
|
}
|
||||||
|
if let Some(full) = self.loaded_images.get_mut(&self.current_image_path.clone()) {
|
||||||
|
full.rating = rating;
|
||||||
|
}
|
||||||
|
if let Some(thumbnail) = self.loaded_images_thumbnails.get_mut(&self.current_image_path.clone()) {
|
||||||
|
thumbnail.rating = rating;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_current_rating(&self) -> i32 {
|
||||||
|
let imbuf = if let Some(full) = self.get_current_image() {
|
||||||
|
println!("full");
|
||||||
|
full
|
||||||
|
} else {
|
||||||
|
// TODO: this assumes loaded thumbnail
|
||||||
|
self.loaded_images_thumbnails
|
||||||
|
.get(&self.current_image_path)
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
imbuf.rating
|
||||||
|
}
|
||||||
|
|
||||||
pub fn preload_next_images(&mut self, n: usize) {
|
pub fn preload_next_images(&mut self, n: usize) {
|
||||||
for image in self
|
for image in self
|
||||||
.available_images
|
.available_images
|
||||||
|
Loading…
x
Reference in New Issue
Block a user