Comparar commits
7 Commits
68843293ff
...
main
Autor | SHA1 | Data | |
---|---|---|---|
74139cc54b | |||
58aad8dbab | |||
0cddc9d9a1 | |||
13ba4368aa | |||
2dfdea361e | |||
38f383a0b2 | |||
ceb772bbec |
592
Cargo.lock
gerado
592
Cargo.lock
gerado
@ -138,6 +138,12 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aligned-vec"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1"
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
@ -236,12 +242,27 @@ version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
|
||||
|
||||
[[package]]
|
||||
name = "approx"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ar"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d67af77d68a931ecd5cbd8a3b5987d63a1d1d1278f7f6a60ae33db485cdebb69"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
|
||||
|
||||
[[package]]
|
||||
name = "arboard"
|
||||
version = "3.4.1"
|
||||
@ -260,6 +281,17 @@ dependencies = [
|
||||
"x11rb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arg_enum_proc_macro"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.9"
|
||||
@ -493,6 +525,38 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "av1-grain"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arrayvec",
|
||||
"log",
|
||||
"nom",
|
||||
"num-rational",
|
||||
"v_frame",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "avif-serialize"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e335041290c43101ca215eed6f43ec437eb5a42125573f600fc3fa42b9bddd62"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.8.0"
|
||||
@ -508,6 +572,12 @@ version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@ -523,6 +593,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitstream-io"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2"
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
@ -560,6 +636,12 @@ dependencies = [
|
||||
"piper",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "built"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
@ -647,6 +729,16 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-expr"
|
||||
version = "0.15.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
@ -687,6 +779,12 @@ dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
@ -786,12 +884,46 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
@ -1142,6 +1274,21 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exr"
|
||||
version = "1.73.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"half",
|
||||
"lebe",
|
||||
"miniz_oxide",
|
||||
"rayon-core",
|
||||
"smallvec",
|
||||
"zune-inflate",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
@ -1174,19 +1321,26 @@ name = "flare"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx",
|
||||
"bytemuck",
|
||||
"eframe",
|
||||
"egui",
|
||||
"egui-wgpu",
|
||||
"env_logger",
|
||||
"epaint",
|
||||
"flare-shader",
|
||||
"futures",
|
||||
"futures-executor",
|
||||
"glam",
|
||||
"image",
|
||||
"log",
|
||||
"profiling",
|
||||
"puffin",
|
||||
"puffin_http",
|
||||
"rand",
|
||||
"rand_xoshiro",
|
||||
"spirv-builder",
|
||||
"wgpu",
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1252,6 +1406,31 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.31"
|
||||
@ -1317,6 +1496,7 @@ version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
@ -1359,6 +1539,16 @@ dependencies = [
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gif"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2"
|
||||
dependencies = [
|
||||
"color_quant",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.30.0"
|
||||
@ -1520,6 +1710,16 @@ dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
@ -1725,11 +1925,37 @@ checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
"color_quant",
|
||||
"exr",
|
||||
"gif",
|
||||
"image-webp",
|
||||
"num-traits",
|
||||
"png",
|
||||
"qoi",
|
||||
"ravif",
|
||||
"rayon",
|
||||
"rgb",
|
||||
"tiff",
|
||||
"zune-core",
|
||||
"zune-jpeg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "image-webp"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b77d01e822461baa8409e156015a1d91735549f0f2c17691bd2d996bef238f7f"
|
||||
dependencies = [
|
||||
"byteorder-lite",
|
||||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imgref"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408"
|
||||
|
||||
[[package]]
|
||||
name = "immutable-chunkmap"
|
||||
version = "2.0.6"
|
||||
@ -1755,6 +1981,17 @@ version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "969ee3fc68ec2e88eb21434ce4d9b7e1600d1ce92ff974560a6c4a304f5124b9"
|
||||
|
||||
[[package]]
|
||||
name = "interpolate_name"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
@ -1770,6 +2007,15 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.14"
|
||||
@ -1846,12 +2092,28 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "lebe"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.6"
|
||||
@ -1919,6 +2181,21 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86"
|
||||
|
||||
[[package]]
|
||||
name = "loop9"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062"
|
||||
dependencies = [
|
||||
"imgref",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lz4_flex"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5"
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
@ -1928,6 +2205,16 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maybe-rayon"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
@ -1967,6 +2254,12 @@ dependencies = [
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.3"
|
||||
@ -2039,6 +2332,12 @@ dependencies = [
|
||||
"jni-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.29.0"
|
||||
@ -2058,6 +2357,63 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "noop_proc_macro"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
@ -2531,6 +2887,65 @@ name = "profiling"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d"
|
||||
dependencies = [
|
||||
"profiling-procmacros",
|
||||
"puffin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "profiling-procmacros"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "puffin"
|
||||
version = "0.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa9dae7b05c02ec1a6bc9bcf20d8bc64a7dcbf57934107902a872014899b741f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"byteorder",
|
||||
"cfg-if",
|
||||
"itertools 0.10.5",
|
||||
"lz4_flex",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "puffin_http"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "739a3c7f56604713b553d7addd7718c226e88d598979ae3450320800bd0e9810"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"crossbeam-channel",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"puffin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "qoi"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
@ -2605,6 +3020,56 @@ version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde"
|
||||
|
||||
[[package]]
|
||||
name = "rav1e"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"arg_enum_proc_macro",
|
||||
"arrayvec",
|
||||
"av1-grain",
|
||||
"bitstream-io",
|
||||
"built",
|
||||
"cfg-if",
|
||||
"interpolate_name",
|
||||
"itertools 0.12.1",
|
||||
"libc",
|
||||
"libfuzzer-sys",
|
||||
"log",
|
||||
"maybe-rayon",
|
||||
"new_debug_unreachable",
|
||||
"noop_proc_macro",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"profiling",
|
||||
"rand",
|
||||
"rand_chacha",
|
||||
"simd_helpers",
|
||||
"system-deps",
|
||||
"thiserror 1.0.69",
|
||||
"v_frame",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ravif"
|
||||
version = "0.11.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2413fd96bd0ea5cdeeb37eaf446a22e6ed7b981d792828721e74ded1980a45c6"
|
||||
dependencies = [
|
||||
"avif-serialize",
|
||||
"imgref",
|
||||
"loop9",
|
||||
"quick-error",
|
||||
"rav1e",
|
||||
"rayon",
|
||||
"rgb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-string"
|
||||
version = "0.3.5"
|
||||
@ -2617,6 +3082,26 @@ version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
@ -2670,6 +3155,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
||||
|
||||
[[package]]
|
||||
name = "rgb"
|
||||
version = "0.8.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a"
|
||||
|
||||
[[package]]
|
||||
name = "rspirv"
|
||||
version = "0.12.0+sdk-1.3.268.0"
|
||||
@ -2702,7 +3193,7 @@ dependencies = [
|
||||
"bytemuck",
|
||||
"either",
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"itertools 0.10.5",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
@ -2867,6 +3358,15 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
@ -2899,6 +3399,15 @@ version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
|
||||
[[package]]
|
||||
name = "simd_helpers"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6"
|
||||
dependencies = [
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
@ -2983,7 +3492,7 @@ dependencies = [
|
||||
"elsa",
|
||||
"indexmap",
|
||||
"internal-iterator",
|
||||
"itertools",
|
||||
"itertools 0.10.5",
|
||||
"lazy_static",
|
||||
"longest-increasing-subsequence",
|
||||
"rustc-hash",
|
||||
@ -3124,6 +3633,25 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-deps"
|
||||
version = "6.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349"
|
||||
dependencies = [
|
||||
"cfg-expr",
|
||||
"heck",
|
||||
"pkg-config",
|
||||
"toml",
|
||||
"version-compare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.15.0"
|
||||
@ -3245,11 +3773,26 @@ dependencies = [
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
@ -3258,6 +3801,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
@ -3388,6 +3933,23 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "v_frame"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b"
|
||||
dependencies = [
|
||||
"aligned-vec",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
@ -4395,6 +4957,30 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zune-core"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
|
||||
|
||||
[[package]]
|
||||
name = "zune-inflate"
|
||||
version = "0.2.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
|
||||
dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zune-jpeg"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028"
|
||||
dependencies = [
|
||||
"zune-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant"
|
||||
version = "4.2.0"
|
||||
|
@ -158,19 +158,32 @@ impl ThreadState {
|
||||
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
#[repr(C)]
|
||||
pub struct Coefs {
|
||||
a: f32,
|
||||
b: f32,
|
||||
c: f32,
|
||||
d: f32,
|
||||
e: f32,
|
||||
f: f32,
|
||||
pub a: f32,
|
||||
pub b: f32,
|
||||
pub c: f32,
|
||||
pub d: f32,
|
||||
pub e: f32,
|
||||
pub f: f32,
|
||||
}
|
||||
|
||||
impl Coefs {
|
||||
pub const IDENTITY: Coefs = Coefs {
|
||||
a: 1.0,
|
||||
b: 0.0,
|
||||
c: 0.0,
|
||||
d: 0.0,
|
||||
e: 1.0,
|
||||
f: 0.0
|
||||
};
|
||||
|
||||
pub fn new(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) -> Self {
|
||||
Self { a, b, c, d, e, f }
|
||||
}
|
||||
|
||||
pub fn new_from_xml_order(a: f32, d: f32, b: f32, e: f32, c: f32, f: f32) -> Self {
|
||||
Self { a, b, c, d, e, f }
|
||||
}
|
||||
|
||||
pub fn apply(&self, point: glam::Vec2) -> glam::Vec2 {
|
||||
vec2(
|
||||
self.a * point.x + self.b * point.y + self.c,
|
||||
@ -339,7 +352,7 @@ pub fn main_fs(
|
||||
#[spirv(frag_coord)] frag_coord: Vec4,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] viewport_constants: &ViewportConstants,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] accum_constants: &AccumConstants,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 2)] _accum_image: &mut [Vec4],
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 3)] accum_image: &mut [Vec4],
|
||||
output: &mut Vec4,
|
||||
) {
|
||||
// Bootleg texture sampling; map from viewport image pixel coordinates to accumulator image
|
||||
@ -365,29 +378,19 @@ pub fn main_fs(
|
||||
let offset_x = (v_width * scale - a_width) / 2.0;
|
||||
let offset_y = (v_height * scale - a_height) / 2.0;
|
||||
|
||||
let _accum_coordinate = viewport_coordinate.as_vec2() * scale - vec2(offset_x, offset_y);
|
||||
let accum_coordinate = viewport_coordinate.as_vec2() * scale - vec2(offset_x, offset_y);
|
||||
|
||||
/*
|
||||
if accum_coordinate.x < 0.0
|
||||
|| accum_coordinate.x >= ifs_constants.accum_width as f32
|
||||
|| accum_coordinate.x >= accum_constants.width as f32
|
||||
|| accum_coordinate.y < 0.0
|
||||
|| accum_coordinate.y >= ifs_constants.accum_height as f32
|
||||
|| accum_coordinate.y >= accum_constants.height as f32
|
||||
{
|
||||
*output = ifs_constants.background_color;
|
||||
*output = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
} else {
|
||||
*output = accum_image[image_index(
|
||||
accum_coordinate.x as i32,
|
||||
accum_coordinate.y as i32,
|
||||
ifs_constants.accum_width,
|
||||
accum_constants.width,
|
||||
) as usize];
|
||||
}
|
||||
*/
|
||||
|
||||
if viewport_coordinate.x == 0
|
||||
|| viewport_coordinate.x == viewport_constants.width as u32 - 1
|
||||
|| viewport_coordinate.y == 0
|
||||
|| viewport_coordinate.y == viewport_constants.height as u32 - 1
|
||||
{
|
||||
*output = glam::Vec4::splat(1.);
|
||||
}
|
||||
}
|
||||
|
@ -7,18 +7,25 @@ license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
approx = "0.5"
|
||||
bytemuck.workspace = true
|
||||
eframe = { version = "0.31", features = ["wgpu"]}
|
||||
egui = "0.31"
|
||||
egui-wgpu = "0.31"
|
||||
env_logger.workspace = true
|
||||
epaint = "0.31"
|
||||
flare-shader = { path = "../flare-shader" }
|
||||
futures = "0.3"
|
||||
futures-executor.workspace = true
|
||||
glam.workspace = true
|
||||
image = "0.25"
|
||||
puffin = "0.19"
|
||||
puffin_http = "0.16"
|
||||
rand = { workspace = true, default-features = true }
|
||||
rand_xoshiro.workspace = true
|
||||
wgpu.workspace = true
|
||||
winit.workspace = true
|
||||
log = "0.4.25"
|
||||
profiling = { version = "1.0", features = ["profile-with-puffin"]}
|
||||
|
||||
[build-dependencies]
|
||||
spirv-builder.workspace = true
|
||||
|
75
crates/flare/examples/transform_editor.rs
Arquivo normal
75
crates/flare/examples/transform_editor.rs
Arquivo normal
@ -0,0 +1,75 @@
|
||||
use egui::{Frame, Ui};
|
||||
use flare::gui::transform_editor::TransformEditor;
|
||||
use flare_shader::Coefs;
|
||||
use log::info;
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
struct TransformEditorApp {
|
||||
transform_editor: TransformEditor,
|
||||
transforms: Vec<Coefs>,
|
||||
}
|
||||
|
||||
impl TransformEditorApp {
|
||||
}
|
||||
|
||||
impl eframe::App for TransformEditorApp {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
|
||||
egui::menu::bar(ui, |ui| {
|
||||
ui.menu_button("File", |ui| {
|
||||
if ui.button("Quit").clicked() {
|
||||
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
|
||||
}
|
||||
});
|
||||
if ui.button("Add Transform").clicked() {
|
||||
self.transforms.push(Coefs::new(1.0, 0.0, 0.0, 0.0, 1.0, 0.0))
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
egui::TopBottomPanel::bottom("bottom_panel").show(ctx, |ui| {
|
||||
self.transform_editor.interact_debug(ui);
|
||||
});
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
Frame::canvas(ui.style()).show(ui, |ui| {
|
||||
self.transform_editor.interact(ui, &mut self.transforms)
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> eframe::Result {
|
||||
std::env::set_var("RUST_LOG", "info");
|
||||
env_logger::init();
|
||||
|
||||
let initial_dimensions = egui::vec2(800., 600.);
|
||||
let mut wgpu_options = egui_wgpu::WgpuConfiguration::default();
|
||||
wgpu_options.present_mode = wgpu::PresentMode::Immediate;
|
||||
wgpu_options.desired_maximum_frame_latency = Some(1);
|
||||
let native_options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default().with_inner_size(initial_dimensions),
|
||||
wgpu_options,
|
||||
renderer: eframe::Renderer::Wgpu,
|
||||
vsync: false,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
puffin::set_scopes_on(true);
|
||||
match puffin_http::Server::new("localhost:8585") {
|
||||
Ok(server) => {
|
||||
info!("Server open");
|
||||
std::mem::forget(server);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// std::mem::forget(puffin_http::Server::new("127.0.0.1:8585").expect("Unable to start server"));
|
||||
|
||||
eframe::run_native(
|
||||
"transform_editor",
|
||||
native_options,
|
||||
Box::new(|cc| {
|
||||
Ok(Box::new(TransformEditorApp::default()))
|
||||
}),
|
||||
)
|
||||
}
|
1
crates/flare/src/gui/mod.rs
Arquivo normal
1
crates/flare/src/gui/mod.rs
Arquivo normal
@ -0,0 +1 @@
|
||||
pub mod transform_editor;
|
364
crates/flare/src/gui/transform_editor.rs
Arquivo normal
364
crates/flare/src/gui/transform_editor.rs
Arquivo normal
@ -0,0 +1,364 @@
|
||||
use egui::emath::RectTransform;
|
||||
use egui::*;
|
||||
use flare_shader::Coefs;
|
||||
use std::ops::Add;
|
||||
|
||||
/// Radius (in pixels) of the transform element draw circle
|
||||
const ELEMENT_DRAW_RADIUS_PX: f32 = 7.0;
|
||||
|
||||
/// Stroke size (in pixels) of the transform element draw circle
|
||||
const ELEMENT_DRAW_STROKE_PX: f32 = 2.0;
|
||||
|
||||
/// Offset (in pixels) of the transform element draw circle
|
||||
const ELEMENT_DRAW_OFFSET_PX: Vec2 = vec2(-2.0, -2.0);
|
||||
|
||||
fn test_in_circle(pt: Pos2, center: Pos2, radius: f32) -> bool {
|
||||
((pt.x - center.x).powf(2.0) + (pt.y - center.y).powf(2.0)) <= radius.powf(2.0)
|
||||
}
|
||||
|
||||
fn test_in_triangle(pt: Pos2, v1: Pos2, v2: Pos2, v3: Pos2) -> bool {
|
||||
// https://stackoverflow.com/a/2049593
|
||||
let sign = |p1: Pos2, p2: Pos2, p3: Pos2| -> f32 {
|
||||
(p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y)
|
||||
};
|
||||
|
||||
let d1 = sign(pt, v1, v2);
|
||||
let d2 = sign(pt, v2, v3);
|
||||
let d3 = sign(pt, v3, v1);
|
||||
|
||||
let has_neg = [d1, d2, d3].iter().any(|v| *v < 0.0);
|
||||
let has_pos = [d1, d2, d3].iter().any(|v| *v > 0.0);
|
||||
|
||||
!(has_neg && has_pos)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum TransformElement {
|
||||
Origin,
|
||||
X,
|
||||
Y,
|
||||
}
|
||||
|
||||
/// Affine coefficients expressed as three points of a triangle
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct TransformTriangle {
|
||||
origin: Pos2,
|
||||
x: Pos2,
|
||||
y: Pos2,
|
||||
}
|
||||
|
||||
impl TransformTriangle {
|
||||
pub fn new(origin: Pos2, x: Pos2, y: Pos2) -> Self {
|
||||
Self { origin, x, y }
|
||||
}
|
||||
|
||||
pub fn interact_drag(self, element: TransformElement, drag_delta: Vec2) -> Self {
|
||||
match element {
|
||||
TransformElement::X => Self::new(self.origin, self.x + drag_delta, self.y),
|
||||
TransformElement::Y => Self::new(self.origin, self.x, self.y + drag_delta),
|
||||
TransformElement::Origin => Self::new(
|
||||
self.origin + drag_delta,
|
||||
self.x + drag_delta,
|
||||
self.y + drag_delta,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transform_pos(self, rect: RectTransform) -> Self {
|
||||
Self {
|
||||
origin: rect.transform_pos(self.origin),
|
||||
x: rect.transform_pos(self.x),
|
||||
y: rect.transform_pos(self.y),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_hovered(
|
||||
&self,
|
||||
hover_pos: Pos2,
|
||||
ifs_to_screen: RectTransform,
|
||||
) -> Option<TransformElement> {
|
||||
let origin_pos = ifs_to_screen.transform_pos(self.origin);
|
||||
let x_pos = ifs_to_screen.transform_pos(self.x);
|
||||
let y_pos = ifs_to_screen.transform_pos(self.y);
|
||||
|
||||
if test_in_circle(hover_pos, x_pos, ELEMENT_DRAW_RADIUS_PX) {
|
||||
Some(TransformElement::X)
|
||||
} else if test_in_circle(hover_pos, y_pos, ELEMENT_DRAW_RADIUS_PX) {
|
||||
Some(TransformElement::Y)
|
||||
} else if test_in_circle(hover_pos, origin_pos, ELEMENT_DRAW_RADIUS_PX)
|
||||
|| test_in_triangle(hover_pos, origin_pos, x_pos, y_pos)
|
||||
{
|
||||
Some(TransformElement::Origin)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Coefs> for TransformTriangle {
|
||||
fn from(value: Coefs) -> Self {
|
||||
let origin = pos2(value.c, -value.f);
|
||||
Self {
|
||||
origin,
|
||||
x: origin + vec2(value.a, -value.d),
|
||||
y: origin + vec2(-value.b, value.e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Coefs> for TransformTriangle {
|
||||
fn into(self) -> Coefs {
|
||||
Coefs {
|
||||
a: self.x.x - self.origin.x,
|
||||
b: self.origin.x - self.y.x,
|
||||
c: self.origin.x,
|
||||
d: self.origin.y - self.x.y,
|
||||
e: self.y.y - self.origin.y,
|
||||
f: -self.origin.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Vec2> for TransformTriangle {
|
||||
type Output = TransformTriangle;
|
||||
|
||||
fn add(self, rhs: Vec2) -> Self::Output {
|
||||
Self {
|
||||
origin: self.origin + rhs,
|
||||
x: self.x + rhs,
|
||||
y: self.y + rhs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Widget for manipulating IFS transform affine coefficients
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct TransformEditor {
|
||||
/// Center point (in IFS coordinates) of the editor window
|
||||
center_ifs: Pos2,
|
||||
|
||||
/// Total range (in IFS coordinates) of the editor window
|
||||
range_ifs: f32,
|
||||
|
||||
/// Transform index the cursor is hovering over
|
||||
hover_index: Option<usize>,
|
||||
|
||||
/// Specific element of the transform hovered by the cursor
|
||||
hover_element: Option<TransformElement>,
|
||||
|
||||
/// Transform index the cursor is dragging
|
||||
drag_index: Option<usize>,
|
||||
}
|
||||
|
||||
impl Default for TransformEditor {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
center_ifs: Pos2::ZERO,
|
||||
range_ifs: 4.0,
|
||||
hover_index: None,
|
||||
hover_element: None,
|
||||
drag_index: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_viewport_ifs(aspect_ratio: f32, center_ifs: Pos2, range_ifs: f32) -> Rect {
|
||||
let size_ifs = if aspect_ratio >= 1.0 {
|
||||
vec2(range_ifs * aspect_ratio, range_ifs)
|
||||
} else {
|
||||
vec2(range_ifs, range_ifs / aspect_ratio)
|
||||
};
|
||||
let min_ifs = center_ifs - size_ifs / 2.0;
|
||||
let max_ifs = center_ifs + size_ifs / 2.0;
|
||||
|
||||
// IFS coordinates follow the "value increases from top left to bottom right" convention.
|
||||
// Because we want coordinates to behave like a Cartesian plot, the Y-axis is flipped
|
||||
Rect::from_min_max(pos2(min_ifs.x, max_ifs.y), pos2(max_ifs.x, min_ifs.y))
|
||||
}
|
||||
|
||||
impl TransformEditor {
|
||||
/// Interact with the provided transform coefficients. Returns the index of the focused transform, if any
|
||||
pub fn interact(&mut self, ui: &mut Ui, transforms: &mut [Coefs]) -> Option<usize> {
|
||||
let (response, painter) = ui.allocate_painter(ui.available_size(), Sense::drag());
|
||||
|
||||
if transforms.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let interact_rect = response.interact_rect;
|
||||
let ifs_rect = build_viewport_ifs(
|
||||
interact_rect.aspect_ratio(),
|
||||
self.center_ifs,
|
||||
self.range_ifs,
|
||||
);
|
||||
|
||||
// Update internal state based on screen interactions, then paint to screen
|
||||
let ifs_to_screen = RectTransform::from_to(ifs_rect, interact_rect);
|
||||
self.interact_update(
|
||||
ui.input(|i| i.pointer.interact_pos()),
|
||||
ui.input(|i| i.pointer.delta()),
|
||||
ui.input(|i| i.pointer.primary_pressed()),
|
||||
ui.input(|i| i.pointer.primary_released()),
|
||||
ifs_to_screen,
|
||||
transforms,
|
||||
);
|
||||
|
||||
self.interact_draw(painter, ifs_to_screen, transforms);
|
||||
|
||||
self.drag_index
|
||||
}
|
||||
|
||||
/// Update state of the provided transform coefficients based on current interactions,
|
||||
/// return the transform coefficients that have claimed focus (if any)
|
||||
fn interact_update(
|
||||
&mut self,
|
||||
hover_pos: Option<Pos2>,
|
||||
hover_delta: Vec2,
|
||||
primary_pressed: bool,
|
||||
primary_released: bool,
|
||||
ifs_to_screen: RectTransform,
|
||||
transforms: &mut [Coefs],
|
||||
) {
|
||||
// If the cursor is not in this widget, reset state
|
||||
if hover_pos.is_none() {
|
||||
self.hover_index = None;
|
||||
self.hover_element = None;
|
||||
self.drag_index = None;
|
||||
return;
|
||||
}
|
||||
|
||||
let hover_pos = hover_pos.unwrap();
|
||||
|
||||
// If the transform array was modified, reset state and then proceed
|
||||
if self.hover_index.map_or(false, |i| i >= transforms.len())
|
||||
|| self.drag_index.map_or(false, |i| i >= transforms.len())
|
||||
{
|
||||
self.hover_index = None;
|
||||
self.hover_element = None;
|
||||
self.drag_index = None;
|
||||
}
|
||||
|
||||
// If a transform is being dragged, update its position
|
||||
if self.drag_index.is_some() {
|
||||
let hover_index = self.hover_index.unwrap();
|
||||
let hover_element = self.hover_element.unwrap();
|
||||
|
||||
let hover_delta_ifs = hover_delta / ifs_to_screen.scale();
|
||||
let transform_triangle: TransformTriangle = transforms[hover_index].into();
|
||||
transforms[hover_index] = transform_triangle
|
||||
.interact_drag(hover_element, hover_delta_ifs)
|
||||
.into();
|
||||
}
|
||||
|
||||
// Check if the currently-hovered transform is still hovered
|
||||
let mut hover_found = false;
|
||||
|
||||
if let Some(hover_index) = self.hover_index {
|
||||
let transform_triangle: TransformTriangle = transforms[hover_index].into();
|
||||
self.hover_element = transform_triangle.is_hovered(hover_pos, ifs_to_screen);
|
||||
hover_found = self.hover_element.is_some();
|
||||
}
|
||||
|
||||
// Check if any transform is hovered
|
||||
if !hover_found {
|
||||
for (i, transform) in transforms.iter().enumerate() {
|
||||
let transform_triangle: TransformTriangle = (*transform).into();
|
||||
self.hover_element = transform_triangle.is_hovered(hover_pos, ifs_to_screen);
|
||||
|
||||
if self.hover_element.is_some() {
|
||||
hover_found = true;
|
||||
self.hover_index = Some(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !hover_found {
|
||||
// No hovers found, reset state
|
||||
self.hover_index = None;
|
||||
self.hover_element = None;
|
||||
self.drag_index = None;
|
||||
}
|
||||
|
||||
// Check drag state
|
||||
if primary_pressed && self.hover_index.is_some() {
|
||||
self.drag_index = self.hover_index;
|
||||
}
|
||||
if primary_released {
|
||||
self.drag_index = None;
|
||||
}
|
||||
}
|
||||
|
||||
fn interact_draw_transform(
|
||||
hover_element: Option<TransformElement>,
|
||||
painter: &Painter,
|
||||
ifs_to_screen: RectTransform,
|
||||
transform: Coefs,
|
||||
) {
|
||||
// `epaint` doesn't provide an option for whether the stroke is drawn inside, in the middle,
|
||||
// or outside the shape to paint. In manual testing, hover detection works best when assuming
|
||||
// the stroke is outside the shape.
|
||||
// Also in manual testing, hover detection seems to work best when drawing the circle at
|
||||
// a slight offset to the actual center position. Not clear why.
|
||||
let transform_triangle: TransformTriangle = transform.into();
|
||||
let draw_triangle =
|
||||
transform_triangle.transform_pos(ifs_to_screen) + ELEMENT_DRAW_OFFSET_PX;
|
||||
|
||||
let stroke = Stroke::new(ELEMENT_DRAW_STROKE_PX, Color32::BLUE);
|
||||
painter.circle_stroke(
|
||||
draw_triangle.origin,
|
||||
ELEMENT_DRAW_RADIUS_PX - ELEMENT_DRAW_STROKE_PX,
|
||||
stroke,
|
||||
);
|
||||
painter.circle_stroke(
|
||||
draw_triangle.x,
|
||||
ELEMENT_DRAW_RADIUS_PX - ELEMENT_DRAW_STROKE_PX,
|
||||
stroke,
|
||||
);
|
||||
painter.circle_stroke(
|
||||
draw_triangle.y,
|
||||
ELEMENT_DRAW_RADIUS_PX - ELEMENT_DRAW_STROKE_PX,
|
||||
stroke,
|
||||
);
|
||||
|
||||
let body_alpha: u8 = if hover_element.is_some() { 8 } else { 0 };
|
||||
let body_fill = Color32::from_rgba_unmultiplied(0, 0, u8::MAX, body_alpha);
|
||||
let body = Shape::convex_polygon(
|
||||
vec![draw_triangle.origin, draw_triangle.x, draw_triangle.y],
|
||||
body_fill,
|
||||
stroke,
|
||||
);
|
||||
painter.add(body);
|
||||
}
|
||||
|
||||
/// Draw the provided transform coefficients to the screen.
|
||||
fn interact_draw(&self, painter: Painter, ifs_to_screen: RectTransform, transforms: &[Coefs]) {
|
||||
transforms
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(i, _)| Some(*i) != self.hover_index)
|
||||
.for_each(|(_, transform)| {
|
||||
Self::interact_draw_transform(None, &painter, ifs_to_screen, *transform)
|
||||
});
|
||||
|
||||
self.hover_index.map(|i| {
|
||||
Self::interact_draw_transform(
|
||||
self.hover_element,
|
||||
&painter,
|
||||
ifs_to_screen,
|
||||
transforms[i],
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
pub fn interact_debug(&self, ui: &mut Ui) {
|
||||
Grid::new("transform_editor_debug")
|
||||
.num_columns(3)
|
||||
.show(ui, |ui| {
|
||||
ui.set_width(ui.available_width());
|
||||
ui.label(format!("Hover index: {:?}", self.hover_index));
|
||||
ui.label(format!("Hover element: {:?}", self.hover_element));
|
||||
ui.label(format!("Drag index: {:?}", self.drag_index));
|
||||
});
|
||||
}
|
||||
}
|
2
crates/flare/src/lib.rs
Arquivo normal
2
crates/flare/src/lib.rs
Arquivo normal
@ -0,0 +1,2 @@
|
||||
pub mod transform_editor;
|
||||
pub mod gui;
|
@ -1,12 +1,24 @@
|
||||
extern crate core;
|
||||
|
||||
use eframe::Frame;
|
||||
use eframe::epaint::PaintCallbackInfo;
|
||||
use egui::Context;
|
||||
use egui::{Context, Rect};
|
||||
use egui_wgpu::{CallbackResources, CallbackTrait, ScreenDescriptor};
|
||||
use flare_shader::{CameraConstants, Coefs, ViewportConstants, ThreadState, Transform, Variation, VariationKind, AccumConstants};
|
||||
use flare_shader::{
|
||||
AccumConstants, CameraConstants, Coefs, ThreadState, Transform, Variation, VariationKind,
|
||||
ViewportConstants,
|
||||
};
|
||||
use futures::channel::oneshot;
|
||||
use futures_executor::block_on;
|
||||
use image::codecs::png::PngEncoder;
|
||||
use image::{ExtendedColorType, ImageEncoder};
|
||||
use rand::thread_rng;
|
||||
use std::fs::File;
|
||||
use wgpu::util::DeviceExt;
|
||||
use wgpu::{CommandBuffer, CommandEncoder, Device, Queue, RenderPass};
|
||||
|
||||
pub mod transform_editor;
|
||||
|
||||
struct RenderGroup {
|
||||
device: wgpu::Device,
|
||||
queue: wgpu::Queue,
|
||||
@ -74,11 +86,11 @@ impl RenderGroup {
|
||||
|
||||
fn build_image_accum_buffer(device: &wgpu::Device, width: i32, height: i32) -> wgpu::Buffer {
|
||||
let pixel_count = (width * height) as u64;
|
||||
let size = pixel_count * size_of::<f32>() as u64;
|
||||
let size = pixel_count * 4 * size_of::<f32>() as u64;
|
||||
device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("accum_image"),
|
||||
size,
|
||||
usage: wgpu::BufferUsages::STORAGE,
|
||||
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_SRC,
|
||||
mapped_at_creation: false,
|
||||
})
|
||||
}
|
||||
@ -115,12 +127,7 @@ impl RenderGroup {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> Self {
|
||||
pub fn new(device: &wgpu::Device, queue: &wgpu::Queue, width: i32, height: i32) -> Self {
|
||||
let bind_group_layout = Self::bind_group_layout(device);
|
||||
|
||||
let viewport_constants_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
@ -146,8 +153,7 @@ impl RenderGroup {
|
||||
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
||||
});
|
||||
|
||||
let image_accum_buffer =
|
||||
Self::build_image_accum_buffer(device, width, height);
|
||||
let image_accum_buffer = Self::build_image_accum_buffer(device, width, height);
|
||||
|
||||
let bind_group = Self::build_bind_group(
|
||||
device,
|
||||
@ -192,8 +198,17 @@ impl RenderGroup {
|
||||
|
||||
pub fn set_viewport_dimensions(&mut self, rect: egui::Rect) {
|
||||
let offset = rect.left_top();
|
||||
let viewport_constants = ViewportConstants::new(offset.x as i32, offset.y as i32, rect.width() as i32, rect.height() as i32);
|
||||
self.queue.write_buffer(&self.viewport_constants_buffer, 0, bytemuck::cast_slice(&[viewport_constants]))
|
||||
let viewport_constants = ViewportConstants::new(
|
||||
offset.x as i32,
|
||||
offset.y as i32,
|
||||
rect.width() as i32,
|
||||
rect.height() as i32,
|
||||
);
|
||||
self.queue.write_buffer(
|
||||
&self.viewport_constants_buffer,
|
||||
0,
|
||||
bytemuck::cast_slice(&[viewport_constants]),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn bind_group(&self) -> &wgpu::BindGroup {
|
||||
@ -276,20 +291,24 @@ impl IfsGroup {
|
||||
}
|
||||
|
||||
pub fn set_transforms(&mut self, transforms: &[Transform]) {
|
||||
let transforms_buffer = self.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("transforms"),
|
||||
contents: bytemuck::cast_slice(transforms),
|
||||
usage: wgpu::BufferUsages::STORAGE,
|
||||
});
|
||||
let transforms_buffer = self
|
||||
.device
|
||||
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("transforms"),
|
||||
contents: bytemuck::cast_slice(transforms),
|
||||
usage: wgpu::BufferUsages::STORAGE,
|
||||
});
|
||||
let _ = self.transforms_buffer.insert(transforms_buffer);
|
||||
}
|
||||
|
||||
pub fn set_variations(&mut self, variations: &[Variation]) {
|
||||
let variations_buffer = self.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("variations"),
|
||||
contents: bytemuck::cast_slice(variations),
|
||||
usage: wgpu::BufferUsages::STORAGE,
|
||||
});
|
||||
let variations_buffer = self
|
||||
.device
|
||||
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("variations"),
|
||||
contents: bytemuck::cast_slice(variations),
|
||||
usage: wgpu::BufferUsages::STORAGE,
|
||||
});
|
||||
let _ = self.variations_buffer.insert(variations_buffer);
|
||||
}
|
||||
|
||||
@ -453,6 +472,13 @@ impl eframe::App for Flare {
|
||||
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
|
||||
egui::menu::bar(ui, |ui| {
|
||||
ui.menu_button("File", |ui| {
|
||||
if ui.button("Debug").clicked() {
|
||||
ui.painter().add(egui_wgpu::Callback::new_paint_callback(
|
||||
Rect::ZERO,
|
||||
DebugIfs,
|
||||
));
|
||||
ui.close_menu();
|
||||
}
|
||||
if ui.button("Quit").clicked() {
|
||||
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
|
||||
}
|
||||
@ -477,6 +503,85 @@ impl eframe::App for Flare {
|
||||
}
|
||||
}
|
||||
|
||||
struct DebugIfs;
|
||||
|
||||
impl CallbackTrait for DebugIfs {
|
||||
fn prepare(
|
||||
&self,
|
||||
device: &Device,
|
||||
queue: &Queue,
|
||||
_screen_descriptor: &ScreenDescriptor,
|
||||
egui_encoder: &mut CommandEncoder,
|
||||
callback_resources: &mut CallbackResources,
|
||||
) -> Vec<CommandBuffer> {
|
||||
let flare_assets = callback_resources
|
||||
.get::<FlareAssets>()
|
||||
.expect("Missing assets");
|
||||
|
||||
let export_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("image_export"),
|
||||
size: flare_assets.render_group.image_accum_buffer.size(),
|
||||
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
let device_extra = device.clone();
|
||||
let width_extra = flare_assets.render_group.accum_constants.width as u32;
|
||||
let height_extra = flare_assets.render_group.accum_constants.height as u32;
|
||||
|
||||
egui_encoder.copy_buffer_to_buffer(
|
||||
&flare_assets.render_group.image_accum_buffer,
|
||||
0,
|
||||
&export_buffer,
|
||||
0,
|
||||
export_buffer.size(),
|
||||
);
|
||||
queue.on_submitted_work_done(move || {
|
||||
let slice = export_buffer.slice(..);
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
|
||||
slice.map_async(wgpu::MapMode::Read, move |result| {
|
||||
if let Ok(result) = result {
|
||||
sender.send(result).unwrap()
|
||||
}
|
||||
});
|
||||
|
||||
device_extra.poll(wgpu::Maintain::Wait);
|
||||
block_on(receiver).expect("Unable to map buffer");
|
||||
|
||||
let result: Vec<f32> = {
|
||||
let data = slice.get_mapped_range();
|
||||
bytemuck::cast_slice(&data).to_vec()
|
||||
};
|
||||
export_buffer.unmap();
|
||||
|
||||
let result_u8: Vec<u8> = result.iter().map(|v| (*v * 256.0) as u8).collect();
|
||||
|
||||
let file = File::create("accum_image.png").expect("Unable to create output image");
|
||||
let png_encoder = PngEncoder::new(file);
|
||||
|
||||
png_encoder
|
||||
.write_image(
|
||||
&result_u8,
|
||||
width_extra,
|
||||
height_extra,
|
||||
ExtendedColorType::Rgba8,
|
||||
)
|
||||
.expect("Unable to write output");
|
||||
});
|
||||
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&self,
|
||||
_info: PaintCallbackInfo,
|
||||
_render_pass: &mut RenderPass<'static>,
|
||||
_callback_resources: &CallbackResources,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
struct PaintIfs {
|
||||
run_accumulate: bool,
|
||||
viewport: egui::Rect,
|
||||
@ -491,11 +596,11 @@ impl CallbackTrait for PaintIfs {
|
||||
egui_encoder: &mut CommandEncoder,
|
||||
callback_resources: &mut CallbackResources,
|
||||
) -> Vec<CommandBuffer> {
|
||||
if self.run_accumulate {
|
||||
let flare_assets = callback_resources
|
||||
.get_mut::<FlareAssets>()
|
||||
.expect("Missing assets");
|
||||
let flare_assets = callback_resources
|
||||
.get_mut::<FlareAssets>()
|
||||
.expect("Missing assets");
|
||||
|
||||
if self.run_accumulate {
|
||||
flare_assets
|
||||
.render_group
|
||||
.set_accum_dimensions(self.viewport.width() as i32, self.viewport.height() as i32);
|
||||
@ -510,8 +615,9 @@ impl CallbackTrait for PaintIfs {
|
||||
pass.dispatch_workgroups(1, 1, 1);
|
||||
}
|
||||
|
||||
let flare_assets = callback_resources.get_mut::<FlareAssets>().expect("Missing assets");
|
||||
flare_assets.render_group.set_viewport_dimensions(self.viewport);
|
||||
flare_assets
|
||||
.render_group
|
||||
.set_viewport_dimensions(self.viewport);
|
||||
|
||||
vec![]
|
||||
}
|
||||
@ -545,6 +651,12 @@ fn main() -> eframe::Result {
|
||||
eframe::run_native(
|
||||
"flare",
|
||||
native_options,
|
||||
Box::new(|cc| Ok(Box::new(Flare::new(cc, initial_dimensions.x as i32, initial_dimensions.y as i32)))),
|
||||
Box::new(|cc| {
|
||||
Ok(Box::new(Flare::new(
|
||||
cc,
|
||||
initial_dimensions.x as i32,
|
||||
initial_dimensions.y as i32,
|
||||
)))
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
303
crates/flare/src/transform_editor.rs
Arquivo normal
303
crates/flare/src/transform_editor.rs
Arquivo normal
@ -0,0 +1,303 @@
|
||||
use bytemuck::Contiguous;
|
||||
use egui::{DragValue, Rect, Sense, Ui, emath};
|
||||
use epaint::{Color32, Shape, Stroke};
|
||||
use log::info;
|
||||
use flare_shader::Coefs;
|
||||
|
||||
pub const TRANSFORM_POINT_RADIUS: f32 = 0.03;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum TransformElement {
|
||||
Origin,
|
||||
X,
|
||||
Y,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Transform {
|
||||
origin: egui::Pos2,
|
||||
x: egui::Pos2,
|
||||
y: egui::Pos2,
|
||||
active_element: Option<TransformElement>,
|
||||
}
|
||||
|
||||
impl Transform {
|
||||
pub fn check_active(&mut self, hover_pos: Option<egui::Pos2>, drag_delta: egui::Vec2) -> bool {
|
||||
if hover_pos.is_none() {
|
||||
self.active_element.take();
|
||||
return false;
|
||||
}
|
||||
|
||||
let hover_pos = hover_pos.unwrap();
|
||||
self.active_element = if test_point_in_circle(hover_pos, self.x + drag_delta, TRANSFORM_POINT_RADIUS * 2.0) {
|
||||
Some(TransformElement::X)
|
||||
} else if test_point_in_circle(hover_pos, self.y + drag_delta, TRANSFORM_POINT_RADIUS * 2.0) {
|
||||
Some(TransformElement::Y)
|
||||
} else if test_point_in_circle(hover_pos, self.origin + drag_delta, TRANSFORM_POINT_RADIUS * 2.0)
|
||||
|| test_point_in_triangle(hover_pos, self.origin + drag_delta, self.x + drag_delta, self.y + drag_delta)
|
||||
{
|
||||
Some(TransformElement::Origin)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
self.active_element.is_some()
|
||||
}
|
||||
|
||||
pub fn drag_update(&mut self, drag_delta: egui::Vec2) {
|
||||
if let Some(active_element) = self.active_element {
|
||||
match active_element {
|
||||
TransformElement::X => self.x += drag_delta,
|
||||
TransformElement::Y => self.y += drag_delta,
|
||||
TransformElement::Origin => {
|
||||
self.origin += drag_delta;
|
||||
self.x += drag_delta;
|
||||
self.y += drag_delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ui_draw(&self, painter: &egui::Painter, to_screen: emath::RectTransform, drag_delta: egui::Vec2) {
|
||||
let color_active = Color32::from_rgba_unmultiplied(0, 0, u8::MAX_VALUE, 8);
|
||||
|
||||
let stroke = Stroke::new(2.0, Color32::BLUE);
|
||||
|
||||
let origin_ifs = match self.active_element {
|
||||
Some(TransformElement::Origin) => self.origin + drag_delta,
|
||||
_ => self.origin
|
||||
};
|
||||
let origin_screen = to_screen.transform_pos(origin_ifs);
|
||||
|
||||
let x_ifs = match self.active_element {
|
||||
Some(TransformElement::X | TransformElement::Origin) => self.x + drag_delta,
|
||||
_ => self.x
|
||||
};
|
||||
let x_screen = to_screen.transform_pos(x_ifs);
|
||||
|
||||
let y_ifs = match self.active_element {
|
||||
Some(TransformElement::Y | TransformElement::Origin) => self.y + drag_delta,
|
||||
_ => self.y
|
||||
};
|
||||
let y_screen = to_screen.transform_pos(y_ifs);
|
||||
|
||||
let body_color = if self.active_element.is_some() {
|
||||
color_active
|
||||
} else {
|
||||
Color32::TRANSPARENT
|
||||
};
|
||||
painter.add(Shape::convex_polygon(
|
||||
vec![origin_screen, x_screen, y_screen],
|
||||
body_color,
|
||||
stroke,
|
||||
));
|
||||
|
||||
let point_radius = to_screen.scale().min_elem() * TRANSFORM_POINT_RADIUS;
|
||||
|
||||
let origin_color = match self.active_element {
|
||||
Some(TransformElement::Origin) => color_active,
|
||||
_ => Color32::TRANSPARENT,
|
||||
};
|
||||
painter.add(Shape::circle_stroke(origin_screen, point_radius, stroke));
|
||||
painter.add(Shape::circle_filled(
|
||||
origin_screen,
|
||||
point_radius,
|
||||
origin_color,
|
||||
));
|
||||
|
||||
let x_color = match self.active_element {
|
||||
Some(TransformElement::X) => color_active,
|
||||
_ => Color32::TRANSPARENT,
|
||||
};
|
||||
painter.add(Shape::circle_stroke(x_screen, point_radius, stroke));
|
||||
painter.add(Shape::circle_filled(x_screen, point_radius, x_color));
|
||||
|
||||
let y_color = match self.active_element {
|
||||
Some(TransformElement::X) => color_active,
|
||||
_ => Color32::TRANSPARENT,
|
||||
};
|
||||
painter.add(Shape::circle_stroke(y_screen, point_radius, stroke));
|
||||
painter.add(Shape::circle_filled(y_screen, point_radius, y_color));
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Transform {
|
||||
fn default() -> Self {
|
||||
Transform {
|
||||
origin: egui::pos2(0.0, 0.0),
|
||||
x: egui::pos2(1.0, 0.0),
|
||||
y: egui::pos2(0.0, -1.0),
|
||||
active_element: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct TransformEditor {
|
||||
transforms: Vec<Transform>,
|
||||
hover_index: Option<usize>,
|
||||
hover_pos: Option<egui::Pos2>,
|
||||
drag_index: Option<usize>,
|
||||
drag_start_pos: Option<egui::Pos2>,
|
||||
}
|
||||
|
||||
fn test_point_in_triangle(pt: egui::Pos2, v1: egui::Pos2, v2: egui::Pos2, v3: egui::Pos2) -> bool {
|
||||
puffin::profile_function!();
|
||||
|
||||
// https://stackoverflow.com/a/2049593
|
||||
let sign = |p1: egui::Pos2, p2: egui::Pos2, p3: egui::Pos2| -> f32 {
|
||||
(p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y)
|
||||
};
|
||||
|
||||
let d1 = sign(pt, v1, v2);
|
||||
let d2 = sign(pt, v2, v3);
|
||||
let d3 = sign(pt, v3, v1);
|
||||
|
||||
let has_neg = [d1, d2, d3].iter().any(|v| *v < 0.0);
|
||||
let has_pos = [d1, d2, d3].iter().any(|v| *v > 0.0);
|
||||
|
||||
!(has_neg && has_pos)
|
||||
}
|
||||
|
||||
fn test_point_in_circle(pt: egui::Pos2, center: egui::Pos2, radius: f32) -> bool {
|
||||
((pt.x - center.x).powf(2.0) + (pt.y - center.y).powf(2.0)) < radius.powf(2.0)
|
||||
}
|
||||
|
||||
impl TransformEditor {
|
||||
pub fn new() -> Self {
|
||||
let mut editor = TransformEditor::default();
|
||||
editor.add_transform();
|
||||
|
||||
editor
|
||||
}
|
||||
|
||||
pub fn add_transform(&mut self) {
|
||||
self.transforms.push(Default::default());
|
||||
}
|
||||
|
||||
fn check_active(&mut self, hover_pos: Option<egui::Pos2>) {
|
||||
// Find the active transform; the previously active transform has priority
|
||||
let drag_delta = self.drag_delta();
|
||||
if let Some(hover_index) = self.hover_index {
|
||||
if self.transforms[hover_index].check_active(hover_pos, drag_delta) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (i, transform) in self.transforms.iter_mut().enumerate() {
|
||||
if transform.check_active(hover_pos, drag_delta) {
|
||||
self.hover_index = Some(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.hover_index.take();
|
||||
}
|
||||
|
||||
fn drag_delta(&self) -> egui::Vec2 {
|
||||
if let (Some(hover_pos), Some(drag_start_pos)) = (self.hover_pos, self.drag_start_pos) {
|
||||
hover_pos - drag_start_pos
|
||||
} else {
|
||||
egui::Vec2::ZERO
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ui_update(
|
||||
&mut self,
|
||||
hover_pos: Option<egui::Pos2>,
|
||||
drag_delta: egui::Vec2,
|
||||
clicked: bool,
|
||||
drag_started: bool,
|
||||
drag_ended: bool,
|
||||
) {
|
||||
if self.transforms.is_empty() {
|
||||
self.hover_index.take();
|
||||
self.drag_index.take();
|
||||
self.drag_start_pos.take();
|
||||
return;
|
||||
}
|
||||
|
||||
self.hover_pos = hover_pos;
|
||||
self.check_active(hover_pos);
|
||||
|
||||
if clicked || drag_started {
|
||||
self.drag_index = self.hover_index;
|
||||
self.drag_start_pos = Some(hover_pos.unwrap() - drag_delta);
|
||||
}
|
||||
|
||||
if drag_ended {
|
||||
if let Some(drag_index) = self.drag_index {
|
||||
let drag_delta = self.drag_delta();
|
||||
info!("Applying drag delta {:?}", drag_delta);
|
||||
self.transforms[drag_index].drag_update(drag_delta);
|
||||
}
|
||||
|
||||
self.drag_index.take();
|
||||
self.drag_start_pos.take();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ui_draw(&mut self, painter: &egui::Painter, to_screen: emath::RectTransform) {
|
||||
let drag_delta = if let (Some(hover_pos), Some(drag_start_pos)) = (self.hover_pos, self.drag_start_pos) {
|
||||
hover_pos - drag_start_pos
|
||||
} else {
|
||||
egui::Vec2::ZERO
|
||||
};
|
||||
|
||||
for (index, transform) in self.transforms.iter().enumerate() {
|
||||
// Active transform is painted at the end to maintain priority
|
||||
if self.hover_index.map_or(false, |i| i == index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
transform.ui_draw(painter, to_screen, drag_delta);
|
||||
}
|
||||
|
||||
self.hover_index.map(|i| self.transforms[i].ui_draw(painter, to_screen, drag_delta));
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ctx: &egui::Context, ui: &mut egui::Ui) -> egui::Response {
|
||||
let (response, painter) = ui.allocate_painter(ui.available_size(), Sense::click_and_drag());
|
||||
|
||||
// Step one: set up conversions between screen space and IFS space coordinates
|
||||
let interact_rect = response.interact_rect;
|
||||
let interact_max_dim = interact_rect.width().max(interact_rect.height());
|
||||
let interact_min_dim = interact_rect.width().min(interact_rect.height());
|
||||
let interact_max_is_width = interact_max_dim == interact_rect.width();
|
||||
let ifs_scale = interact_max_dim / interact_min_dim * 4.0;
|
||||
|
||||
let ifs_min = if interact_max_is_width {
|
||||
egui::pos2(-ifs_scale / 2.0, -2.0)
|
||||
} else {
|
||||
egui::pos2(-2.0, -ifs_scale / 2.0)
|
||||
};
|
||||
|
||||
let transform_area = Rect::from_min_max(ifs_min, ifs_min * -1.0);
|
||||
let to_screen = emath::RectTransform::from_to(transform_area, response.interact_rect);
|
||||
let to_ifs = emath::RectTransform::from_to(response.interact_rect, transform_area);
|
||||
|
||||
egui::TopBottomPanel::bottom("response_stats").show(ctx, |ui| {
|
||||
let hover_pos_string = response.hover_pos().map_or_else(|| "None".to_owned(), |p| {
|
||||
let ifs_pos = to_ifs.transform_pos(p);
|
||||
format!("({} {})", ifs_pos.x, ifs_pos.y)
|
||||
});
|
||||
ui.label(format!("Hover Pos: {}", hover_pos_string));
|
||||
ui.label(format!("Hover Index: {:?}", self.hover_index));
|
||||
ui.label(format!("Drag Index: {:?}", self.drag_index));
|
||||
});
|
||||
|
||||
// Step two: update internal state based on recent interactions
|
||||
self.ui_update(
|
||||
response.hover_pos().map(|v| to_ifs.transform_pos(v)),
|
||||
response.drag_delta() / interact_max_dim,
|
||||
response.clicked(),
|
||||
response.drag_started(),
|
||||
response.drag_stopped(),
|
||||
);
|
||||
|
||||
// Step three: draw the transforms
|
||||
self.ui_draw(&painter, to_screen);
|
||||
|
||||
response
|
||||
}
|
||||
}
|
Referência em uma nova issue
Block a user