diff --git a/Cargo.lock b/Cargo.lock index 0ae7da2f..3e94b1d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,9 +26,9 @@ checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] name = "addr2line" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" dependencies = [ "gimli", ] @@ -97,9 +97,9 @@ dependencies = [ [[package]] name = "android-activity" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c77a0045eda8b888c76ea473c2b0515ba6f471d318f8927c5c72240937035a6" +checksum = "40bc1575e653f158cbdc6ebcd917b9564e66321c5325c232c3591269c257be69" dependencies = [ "android-properties", "bitflags 1.3.2", @@ -110,7 +110,7 @@ dependencies = [ "ndk 0.7.0", "ndk-context", "ndk-sys 0.4.1+23.1.7779620", - "num_enum 0.5.11", + "num_enum 0.6.1", ] [[package]] @@ -196,9 +196,9 @@ checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "ash" @@ -210,14 +210,125 @@ dependencies = [ ] [[package]] -name = "async-trait" -version = "0.1.68" +name = "async-broadcast" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" +dependencies = [ + "event-listener", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" +dependencies = [ + "async-lock", + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" +dependencies = [ + "async-lock", + "autocfg", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite", + "log", + "parking", + "polling", + "rustix", + "slab", + "socket2", + "waker-fn", +] + +[[package]] +name = "async-lock" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-process" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" +dependencies = [ + "async-io", + "async-lock", + "autocfg", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", + "signal-hook", + "windows-sys 0.48.0", +] + +[[package]] +name = "async-recursion" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", +] + +[[package]] +name = "async-task" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" + +[[package]] +name = "async-trait" +version = "0.1.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2d0f03b3640e3a630367e40c468cb7f309529c708ed1d88597047b0e7c6ef7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", ] [[package]] @@ -241,24 +352,14 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] -name = "attohttpc" -version = "0.22.0" +name = "atomic-waker" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcf00bc6d5abb29b5f97e3c61a90b6d3caa12f3faf897d4a3e3607c050a35a7" -dependencies = [ - "flate2", - "http", - "log", - "native-tls", - "serde", - "serde_json", - "serde_urlencoded", - "url", -] +checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" [[package]] name = "atty" @@ -280,7 +381,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "autoquant" version = "0.1.0" -source = "git+https://github.com/truedoctor/autoquant#50366e04b9b6268a5e77f1829d70d799bcc9de8d" +source = "git+https://github.com/truedoctor/autoquant#dfb14dcc7fb92521a5ef7b37122178b203585424" dependencies = [ "anyhow", "argmin", @@ -288,7 +389,7 @@ dependencies = [ "log", "nalgebra 0.30.1", "num", - "varpro", + "rayon", ] [[package]] @@ -305,7 +406,7 @@ dependencies = [ "http", "http-body", "hyper", - "itoa 1.0.6", + "itoa 1.0.8", "matchit", "memchr", "mime", @@ -342,15 +443,15 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" dependencies = [ "addr2line", "cc", "cfg-if", "libc", - "miniz_oxide 0.6.2", + "miniz_oxide", "object", "rustc-demangle", ] @@ -423,9 +524,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.1" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6776fc96284a0bb647b615056fc496d1fe1644a7ab01829818a6d91cae888b84" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" [[package]] name = "block" @@ -461,6 +562,21 @@ dependencies = [ "objc2-encode", ] +[[package]] +name = "blocking" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" +dependencies = [ + "async-channel", + "async-lock", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", + "log", +] + [[package]] name = "brotli" version = "3.3.4" @@ -515,7 +631,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -529,6 +645,9 @@ name = "bytes" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +dependencies = [ + "serde", +] [[package]] name = "cairo-rs" @@ -551,7 +670,7 @@ checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" dependencies = [ "glib-sys", "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -575,7 +694,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "599aa35200ffff8f04c1925aa1acc92fa2e08874379ef42e210a80e527e60838" dependencies = [ "serde", - "toml 0.7.3", + "toml 0.7.5", ] [[package]] @@ -615,9 +734,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70d3ad08698a0568b0562f22710fe6bfc1f4a61a367c77d0398c562eadd453a" +checksum = "215c0072ecc28f92eeb0eea38ba63ddfcb65c2828c46311d646f1a3ff5f9841c" dependencies = [ "smallvec", "target-lexicon", @@ -756,6 +875,15 @@ dependencies = [ "tower-http", ] +[[package]] +name = "concurrent-queue" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -803,21 +931,20 @@ dependencies = [ [[package]] name = "core-graphics-types" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" dependencies = [ "bitflags 1.3.2", "core-foundation", - "foreign-types", "libc", ] [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" dependencies = [ "libc", ] @@ -841,6 +968,30 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset 0.9.0", + "scopeguard", +] + [[package]] name = "crossbeam-queue" version = "0.3.8" @@ -853,9 +1004,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -900,7 +1051,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -945,7 +1096,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -956,18 +1107,7 @@ checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" dependencies = [ "darling_core", "quote", - "syn 2.0.18", -] - -[[package]] -name = "dbus" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" -dependencies = [ - "libc", - "libdbus-sys", - "winapi", + "syn 2.0.23", ] [[package]] @@ -1057,9 +1197,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "dtoa" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65d09067bfacaa79114679b279d7f5885b53295b1e2cfb4e79c8e4bd3d633169" +checksum = "519b83cd10f5f6e969625a409f735182bea5558cd8b64c655806ceaae36f1999" [[package]] name = "dtoa-short" @@ -1102,14 +1242,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" [[package]] -name = "embed-resource" -version = "2.1.1" +name = "either" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80663502655af01a2902dff3f06869330782267924bf1788410b74edcd93770a" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "embed-resource" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7f1e82a60222fc67bfd50d752a9c89da5cce4c39ed39decc84a443b07bbd69a" dependencies = [ "cc", "rustc_version", - "toml 0.7.3", + "toml 0.7.5", "vswhom", "winreg 0.11.0", ] @@ -1129,6 +1275,27 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enumflags2" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c041f5090df68b32bcd905365fd51769c8b9d553fe87fde0b683534f10c01bd2" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] + [[package]] name = "env_logger" version = "0.8.4" @@ -1142,6 +1309,12 @@ dependencies = [ "termcolor", ] +[[package]] +name = "equivalent" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" + [[package]] name = "errno" version = "0.3.1" @@ -1163,6 +1336,12 @@ dependencies = [ "libc", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + [[package]] name = "fastrand" version = "1.9.0" @@ -1226,7 +1405,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ "crc32fast", - "miniz_oxide 0.7.1", + "miniz_oxide", ] [[package]] @@ -1338,6 +1517,21 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + [[package]] name = "futures-macro" version = "0.3.28" @@ -1346,7 +1540,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -1427,7 +1621,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -1444,7 +1638,21 @@ dependencies = [ "libc", "pango-sys", "pkg-config", - "system-deps 6.1.0", + "system-deps 6.1.1", +] + +[[package]] +name = "gdkwayland-sys" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cca49a59ad8cfdf36ef7330fe7bdfbe1d34323220cc16a0de2679ee773aee2c2" +dependencies = [ + "gdk-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", + "system-deps 6.1.1", ] [[package]] @@ -1456,15 +1664,15 @@ dependencies = [ "gdk-sys", "glib-sys", "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", "x11", ] [[package]] name = "generator" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e123d9ae7c02966b4d892e550bdc32164f05853cd40ab570650ad600596a8a" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" dependencies = [ "cc", "libc", @@ -1507,9 +1715,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" [[package]] name = "gio" @@ -1537,7 +1745,7 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", "winapi", ] @@ -1594,7 +1802,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" dependencies = [ "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -1636,7 +1844,7 @@ checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a" dependencies = [ "glib-sys", "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -1691,7 +1899,7 @@ checksum = "0b0c02e1ba0bdb14e965058ca34e09c020f8e507a760df1121728e0aef68d57a" dependencies = [ "bitflags 1.3.2", "gpu-descriptor-types", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -1743,6 +1951,36 @@ dependencies = [ "xxhash-rust", ] +[[package]] +name = "graphene-cli" +version = "0.1.0" +dependencies = [ + "bezier-rs", + "bitflags 1.3.2", + "chrono", + "dyn-any", + "env_logger", + "fern", + "future-executor", + "futures", + "glam", + "gpu-executor", + "graph-craft", + "graphene-core", + "graphene-std", + "graphite-document-legacy", + "image", + "interpreted-executor", + "log", + "serde", + "serde_json", + "test-case", + "tokio", + "wasm-bindgen", + "wgpu", + "wgpu-executor", +] + [[package]] name = "graphene-core" version = "0.1.0" @@ -1796,6 +2034,8 @@ dependencies = [ "serde", "serde_json", "tempfile", + "tokio", + "url", "vulkan-executor", "wasm-bindgen", "wasm-bindgen-futures", @@ -1803,6 +2043,7 @@ dependencies = [ "wgpu", "wgpu-executor", "wgpu-types", + "winit", "xxhash-rust", ] @@ -1945,7 +2186,7 @@ dependencies = [ "gobject-sys", "libc", "pango-sys", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -1964,9 +2205,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" dependencies = [ "bytes", "fnv", @@ -1974,7 +2215,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -1983,10 +2224,11 @@ dependencies = [ [[package]] name = "half" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" dependencies = [ + "cfg-if", "crunchy", ] @@ -1999,6 +2241,12 @@ dependencies = [ "ahash 0.7.6", ] +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + [[package]] name = "hassle-rs" version = "0.10.0" @@ -2040,18 +2288,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -2087,7 +2326,7 @@ checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", - "itoa 1.0.6", + "itoa 1.0.8", ] [[package]] @@ -2133,9 +2372,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.26" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -2146,7 +2385,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa 1.0.6", + "itoa 1.0.8", "pin-project-lite", "socket2", "tokio", @@ -2232,11 +2471,10 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.18" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" dependencies = [ - "crossbeam-utils", "globset", "lazy_static", "log", @@ -2257,6 +2495,7 @@ dependencies = [ "bytemuck", "byteorder", "color_quant", + "jpeg-decoder", "num-rational", "num-traits", "png", @@ -2269,10 +2508,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", "serde", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + [[package]] name = "infer" version = "0.12.0" @@ -2320,16 +2569,16 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi 0.3.2", "libc", "windows-sys 0.48.0", ] [[package]] name = "ipnet" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "itoa" @@ -2339,9 +2588,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" [[package]] name = "javascriptcore-rs" @@ -2395,6 +2644,12 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" + [[package]] name = "js-sys" version = "0.3.63" @@ -2442,10 +2697,11 @@ dependencies = [ [[package]] name = "kurbo" version = "0.9.5" -source = "git+https://github.com/linebender/kurbo.git#8c07a06d5e04daf0d65abb5a59c63c8003ac59b1" +source = "git+https://github.com/linebender/kurbo.git#68a8ff6ee387f5a38ab06be7184675317a95a961" dependencies = [ "arrayvec", "serde", + "smallvec", ] [[package]] @@ -2454,32 +2710,11 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "levenberg-marquardt" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758849cc08a08003567842a85887e6a528017114a893d5402b6f08744a5f51aa" -dependencies = [ - "cfg-if", - "nalgebra 0.30.1", - "num-traits", - "rustc_version", -] - [[package]] name = "libc" -version = "0.2.146" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" - -[[package]] -name = "libdbus-sys" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" -dependencies = [ - "pkg-config", -] +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libloading" @@ -2540,9 +2775,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.18" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "loom" @@ -2575,7 +2810,7 @@ dependencies = [ "dirs-next", "objc-foundation", "objc_id", - "time 0.3.15", + "time 0.3.22", ] [[package]] @@ -2656,6 +2891,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "memoffset" version = "0.9.0" @@ -2691,15 +2935,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.7.1" @@ -2732,7 +2967,7 @@ dependencies = [ "bitflags 1.3.2", "codespan-reporting", "hexf-parse", - "indexmap", + "indexmap 1.9.3", "log", "num-traits", "petgraph", @@ -2887,6 +3122,19 @@ dependencies = [ "memoffset 0.6.5", ] +[[package]] +name = "nix" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", + "static_assertions", +] + [[package]] name = "node-macro" version = "0.0.0" @@ -2918,10 +3166,11 @@ version = "4.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bfa211d18e360f08e36c364308f394b5eb23a6629150690e109a916dc6f610e" dependencies = [ - "dbus", "log", "mac-notification-sys", + "serde", "tauri-winrt-notification", + "zbus", ] [[package]] @@ -3025,11 +3274,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.2", "libc", ] @@ -3072,7 +3321,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -3084,6 +3333,15 @@ dependencies = [ "libc", ] +[[package]] +name = "nvtx" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfd9a105a93591e01bc67a8c0f86f697a6c09e384f3129aa2bd55823bc431261" +dependencies = [ + "cc", +] + [[package]] name = "objc" version = "0.2.7" @@ -3151,9 +3409,9 @@ dependencies = [ [[package]] name = "object" -version = "0.30.4" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ "memchr", ] @@ -3176,9 +3434,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.54" +version = "0.10.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b3f656a17a6cbc115b5c7a40c616947d213ba182135b014d6051b73ab6f019" +checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" dependencies = [ "bitflags 1.3.2", "cfg-if", @@ -3197,7 +3455,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -3208,9 +3466,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.88" +version = "0.9.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ce0f250f34a308dcfdbb351f511359857d4ed2134ba715a4eadd46e1ffd617" +checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" dependencies = [ "cc", "libc", @@ -3227,6 +3485,16 @@ dependencies = [ "redox_syscall 0.3.5", ] +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "os_info" version = "3.7.0" @@ -3260,7 +3528,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "706de7e2214113d63a8238d1910463cfce781129a6f263d13fdb09ff64355ba4" dependencies = [ - "ttf-parser 0.19.0", + "ttf-parser 0.19.1", ] [[package]] @@ -3285,9 +3553,15 @@ dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 6.1.0", + "system-deps 6.1.1", ] +[[package]] +name = "parking" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" + [[package]] name = "parking_lot" version = "0.12.1" @@ -3308,14 +3582,14 @@ dependencies = [ "libc", "redox_syscall 0.3.5", "smallvec", - "windows-targets 0.48.0", + "windows-targets 0.48.1", ] [[package]] name = "paste" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" [[package]] name = "pathdiff" @@ -3336,7 +3610,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 1.9.3", ] [[package]] @@ -3439,29 +3713,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" [[package]] name = "pin-utils" @@ -3482,24 +3756,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bd9647b268a3d3e14ff09c23201133a62589c658db02bb7388c7246aafe0590" dependencies = [ "base64 0.21.2", - "indexmap", + "indexmap 1.9.3", "line-wrap", "quick-xml 0.28.2", "serde", - "time 0.3.15", + "time 0.3.22", ] [[package]] name = "png" -version = "0.17.8" +version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa" +checksum = "59871cc5b6cce7eaccca5a802b4173377a1c2ba90654246789a8fa2334426d11" dependencies = [ "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", - "miniz_oxide 0.7.1", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", ] [[package]] @@ -3556,9 +3846,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] @@ -3589,9 +3879,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.28" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -3707,6 +3997,28 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -3770,13 +4082,13 @@ checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "remain" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13cca257d068dd3a390d04b2c3009a3fad2ee5048dfa8f239d048372810470c" +checksum = "6a7353bbc5701e3ea03298c88c3d087c23798589a351e3b42819d5e5fadc91bf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -3818,10 +4130,12 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls", + "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", "webpki-roots", "winreg 0.10.1", @@ -3900,9 +4214,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.19" +version = "0.37.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "8818fa822adcc98b18fedbb3632a6a33213c070556b5aa7c4c8cc21cff565c4c" dependencies = [ "bitflags 1.3.2", "errno", @@ -3914,9 +4228,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.1" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e" +checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" dependencies = [ "log", "ring", @@ -3926,9 +4240,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ "base64 0.21.2", ] @@ -3945,9 +4259,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f" [[package]] name = "rustybuzz" @@ -3967,9 +4281,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" [[package]] name = "safe_arch" @@ -3997,11 +4311,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] @@ -4093,9 +4407,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.163" +version = "1.0.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "d01b7404f9d441d3ad40e6a636a7782c377d2abdbe4fa2440e2edcc2f4f10db8" dependencies = [ "serde_derive", ] @@ -4124,51 +4438,52 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "5dd83d6dde2b6b2d466e14d9d1acce8816dedee94f735eac6395808b3483c6d6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" dependencies = [ - "itoa 1.0.6", + "itoa 1.0.8", "ryu", "serde", ] [[package]] name = "serde_path_to_error" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7f05c1d5476066defcdfacce1f52fc3cae3af1d3089727100c02ae92e5abbe0" +checksum = "0b1b6471d7496b051e03f1958802a73f88b947866f5146f329e47e36554f4e55" dependencies = [ + "itoa 1.0.8", "serde", ] [[package]] name = "serde_repr" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" +checksum = "6f0a21fba416426ac927b1691996e82079f8b6156e920c85345f135b2e9ba2de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] name = "serde_spanned" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ "serde", ] @@ -4180,37 +4495,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.6", + "itoa 1.0.8", "ryu", "serde", ] [[package]] name = "serde_with" -version = "2.3.3" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +checksum = "9f02d8aa6e3c385bf084924f660ce2a3a6bd333ba55b35e8590b321f35d88513" dependencies = [ - "base64 0.13.1", + "base64 0.21.2", "chrono", "hex", - "indexmap", + "indexmap 1.9.3", "serde", "serde_json", "serde_with_macros", - "time 0.3.15", + "time 0.3.22", ] [[package]] name = "serde_with_macros" -version = "2.3.3" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +checksum = "edc7d5d3932fb12ce722ee5e64dd38c504efba37567f0c402f6ca728c3b8b070" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -4246,10 +4561,21 @@ dependencies = [ ] [[package]] -name = "sha2" -version = "0.10.6" +name = "sha1" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", @@ -4275,6 +4601,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "signal-hook" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" +dependencies = [ + "libc", + "signal-hook-registry", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -4345,7 +4681,7 @@ dependencies = [ "serde", "serde_json", "slog", - "time 0.3.15", + "time 0.3.22", ] [[package]] @@ -4358,7 +4694,7 @@ dependencies = [ "slog", "term", "thread_local", - "time 0.3.15", + "time 0.3.22", ] [[package]] @@ -4574,27 +4910,6 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "strum" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7ac893c7d471c8a21f31cfe213ec4f6d9afeed25537c772e08ef3f005f8729e" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339f799d8b549e3744c7ac7feb216383e4005d94bdb22561b3ab8f3b808ae9fb" -dependencies = [ - "heck 0.3.3", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "syn" version = "1.0.109" @@ -4608,9 +4923,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" dependencies = [ "proc-macro2", "quote", @@ -4623,6 +4938,19 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sys-locale" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a11bd9c338fdba09f7881ab41551932ad42e405f61d01e8406baea71c07aee" +dependencies = [ + "js-sys", + "libc", + "wasm-bindgen", + "web-sys", + "windows-sys 0.45.0", +] + [[package]] name = "system-deps" version = "5.0.0" @@ -4638,14 +4966,14 @@ dependencies = [ [[package]] name = "system-deps" -version = "6.1.0" +version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5fa6fb9ee296c0dc2df41a656ca7948546d061958115ddb0bcaae43ad0d17d2" +checksum = "30c2de8a4d8f4b823d634affc9cd2a74ec98c53a756f317e529a48046cbf71f3" dependencies = [ - "cfg-expr 0.15.2", + "cfg-expr 0.15.3", "heck 0.4.1", "pkg-config", - "toml 0.7.3", + "toml 0.7.5", "version-compare 0.1.1", ] @@ -4657,9 +4985,9 @@ checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" [[package]] name = "tao" -version = "0.15.8" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac8e6399427c8494f9849b58694754d7cc741293348a6836b6c8d2c5aa82d8e6" +checksum = "6a6d198e01085564cea63e976ad1566c1ba2c2e4cc79578e35d9f05521505e31" dependencies = [ "bitflags 1.3.2", "cairo-rs", @@ -4672,6 +5000,7 @@ dependencies = [ "gdk", "gdk-pixbuf", "gdk-sys", + "gdkwayland-sys", "gdkx11-sys", "gio", "glib", @@ -4689,11 +5018,11 @@ dependencies = [ "objc", "once_cell", "parking_lot", - "paste", "png", "raw-window-handle", "scopeguard", "serde", + "tao-macros", "unicode-segmentation", "uuid", "windows 0.39.0", @@ -4701,6 +5030,17 @@ dependencies = [ "x11-dl", ] +[[package]] +name = "tao-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b27a4bcc5eb524658234589bdffc7e7bfb996dbae6ce9393bfd39cb4159b445" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "tar" version = "0.4.38" @@ -4714,18 +5054,18 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.7" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" +checksum = "1b1c7f239eb94671427157bd93b3694320f3668d4e1eff08c7285366fd777fac" [[package]] name = "tauri" -version = "1.2.5" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a1fe72365a6d860fddf3403934649a5157b2bbb6f0b50dd3a8858cd1a22412" +checksum = "7fbe522898e35407a8e60dc3870f7579fea2fc262a6a6072eccdd37ae1e1d91e" dependencies = [ "anyhow", - "attohttpc", + "bytes", "cocoa", "dirs-next", "embed_plist", @@ -4748,6 +5088,7 @@ dependencies = [ "rand 0.8.5", "raw-window-handle", "regex", + "reqwest", "rfd", "semver", "serde", @@ -4756,6 +5097,7 @@ dependencies = [ "serialize-to-javascript", "shared_child", "state", + "sys-locale", "tar", "tauri-macros", "tauri-runtime", @@ -4773,9 +5115,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "929b3bd1248afc07b63e33a6a53c3f82c32d0b0a5e216e4530e94c467e019389" +checksum = "7d2edd6a259b5591c8efdeb9d5702cb53515b82a6affebd55c7fd6d3a27b7d1b" dependencies = [ "anyhow", "cargo_toml", @@ -4786,14 +5128,13 @@ dependencies = [ "serde_json", "tauri-utils", "tauri-winres", - "winnow", ] [[package]] name = "tauri-codegen" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a2105f807c6f50b2fa2ce5abd62ef207bc6f14c9fcc6b8caec437f6fb13bde" +checksum = "54ad2d49fdeab4a08717f5b49a163bdc72efc3b1950b6758245fcde79b645e1a" dependencies = [ "base64 0.21.2", "brotli", @@ -4810,16 +5151,16 @@ dependencies = [ "sha2", "tauri-utils", "thiserror", - "time 0.3.15", + "time 0.3.22", "uuid", "walkdir", ] [[package]] name = "tauri-macros" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8784cfe6f5444097e93c69107d1ac5e8f13d02850efa8d8f2a40fe79674cef46" +checksum = "8eb12a2454e747896929338d93b0642144bb51e0dddbb36e579035731f0d76b7" dependencies = [ "heck 0.4.1", "proc-macro2", @@ -4831,9 +5172,9 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "0.12.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc36898ad4acb6c381878acf903c320a36cf29b68b74f6e791d6045b6557128c" +checksum = "108683199cb18f96d2d4134187bb789964143c845d2d154848dda209191fd769" dependencies = [ "gtk", "http", @@ -4852,9 +5193,9 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "0.12.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2ebc22bc5566ba33310744fadd86709fa591ed163491b165855474523ac1aab" +checksum = "0b7aa256a1407a3a091b5d843eccc1a5042289baf0a43d1179d9f0fcfea37c1b" dependencies = [ "cocoa", "gtk", @@ -4863,7 +5204,6 @@ dependencies = [ "raw-window-handle", "tauri-runtime", "tauri-utils", - "url", "uuid", "webkit2gtk", "webview2-com", @@ -4873,12 +5213,13 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6f9c2dafef5cbcf52926af57ce9561bd33bb41d7394f8bb849c0330260d864" +checksum = "03fc02bb6072bb397e1d473c6f76c953cda48b4a2d0cce605df284aa74a12e84" dependencies = [ "brotli", "ctor", + "dunce", "glob", "heck 0.4.1", "html5ever", @@ -4906,17 +5247,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5993dc129e544393574288923d1ec447c857f3f644187f4fbf7d9a875fbfc4fb" dependencies = [ "embed-resource", - "toml 0.7.3", + "toml 0.7.5", ] [[package]] name = "tauri-winrt-notification" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58de036c4d2e20717024de2a3c4bf56c301f07b21bc8ef9b57189fce06f1f3b" +checksum = "4f5bff1d532fead7c43324a0fa33643b8621a47ce2944a633be4cb6c0240898f" dependencies = [ "quick-xml 0.23.1", - "strum", "windows 0.39.0", ] @@ -5010,7 +5350,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -5036,22 +5376,32 @@ dependencies = [ [[package]] name = "time" -version = "0.3.15" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d634a985c4d4238ec39cacaed2e7ae552fbd3c476b552c1deac3021b7d7eaf0c" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" dependencies = [ - "itoa 1.0.6", + "itoa 1.0.8", "libc", "num_threads", "serde", + "time-core", "time-macros", ] [[package]] -name = "time-macros" -version = "0.2.4" +name = "time-core" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +dependencies = [ + "time-core", +] [[package]] name = "tiny-skia" @@ -5095,11 +5445,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.2" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -5120,7 +5471,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -5135,9 +5486,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls", "tokio", @@ -5168,9 +5519,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240" dependencies = [ "serde", "serde_spanned", @@ -5180,20 +5531,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.8" +version = "0.19.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" dependencies = [ - "indexmap", + "indexmap 2.0.0", "serde", "serde_spanned", "toml_datetime", @@ -5218,11 +5569,11 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d1d42a9b3f3ec46ba828e8d376aec14592ea199f70a06a548587ecd1c4ab658" +checksum = "a8bd22a874a2d0b70452d5597b12c537331d49060824a95f49f108994f94aa4c" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.3.3", "bytes", "futures-core", "futures-util", @@ -5261,13 +5612,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", ] [[package]] @@ -5332,9 +5683,9 @@ checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff" [[package]] name = "ttf-parser" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44dcf002ae3b32cd25400d6df128c5babec3927cd1eb7ce813cfff20eb6c3746" +checksum = "a464a4b34948a5f67fddd2b823c62d9d92e44be75058b99939eae6c5b6960b33" [[package]] name = "typed-arena" @@ -5348,6 +5699,16 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "uds_windows" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d" +dependencies = [ + "tempfile", + "winapi", +] + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -5374,9 +5735,9 @@ checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" [[package]] name = "unicode-normalization" @@ -5437,9 +5798,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "uuid" -version = "1.3.3" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2" +checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" dependencies = [ "getrandom 0.2.10", ] @@ -5450,18 +5811,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "varpro" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e009f2c6b59b31a6fe335cb6a9ab413170ddfd13ed837a835aef1dcf865b364" -dependencies = [ - "levenberg-marquardt", - "nalgebra 0.30.1", - "num-traits", - "thiserror", -] - [[package]] name = "vcpkg" version = "0.2.15" @@ -5550,7 +5899,7 @@ dependencies = [ "crossbeam-queue", "half", "heck 0.4.1", - "indexmap", + "indexmap 1.9.3", "lazy_static", "libloading 0.7.4", "objc", @@ -5564,6 +5913,12 @@ dependencies = [ "vk-parse", ] +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + [[package]] name = "walkdir" version = "2.3.3" @@ -5576,11 +5931,10 @@ dependencies = [ [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -5623,7 +5977,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", "wasm-bindgen-shared", ] @@ -5657,7 +6011,7 @@ checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.23", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5705,6 +6059,19 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-streams" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wayland-client" version = "0.29.5" @@ -5832,7 +6199,7 @@ dependencies = [ "pango-sys", "pkg-config", "soup2-sys", - "system-deps 6.1.0", + "system-deps 6.1.1", ] [[package]] @@ -5924,7 +6291,7 @@ checksum = "8f478237b4bf0d5b70a39898a66fa67ca3a007d79f2520485b8b0c3dfc46f8c2" dependencies = [ "arrayvec", "bit-vec", - "bitflags 2.3.1", + "bitflags 2.3.3", "codespan-reporting", "log", "naga", @@ -5956,6 +6323,7 @@ dependencies = [ "graphene-core", "log", "num-traits", + "nvtx", "serde", "spirv", "web-sys", @@ -5973,7 +6341,7 @@ dependencies = [ "arrayvec", "ash", "bit-set", - "bitflags 2.3.1", + "bitflags 2.3.3", "block", "core-graphics-types", "d3d12", @@ -6011,7 +6379,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bd33a976130f03dcdcd39b3810c0c3fc05daf86f0aaf867db14bfb7c4a9a32b" dependencies = [ - "bitflags 2.3.1", + "bitflags 2.3.3", "js-sys", "web-sys", ] @@ -6105,7 +6473,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.1", ] [[package]] @@ -6164,7 +6532,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.1", ] [[package]] @@ -6184,9 +6552,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm 0.48.0", "windows_aarch64_msvc 0.48.0", @@ -6384,9 +6752,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.4.1" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" dependencies = [ "memchr", ] @@ -6412,9 +6780,9 @@ dependencies = [ [[package]] name = "wry" -version = "0.23.4" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c1ad8e2424f554cc5bdebe8aa374ef5b433feff817aebabca0389961fc7ef98" +checksum = "33748f35413c8a98d45f7a08832d848c0c5915501803d1faade5a4ebcd258cea" dependencies = [ "base64 0.13.1", "block", @@ -6488,13 +6856,127 @@ dependencies = [ ] [[package]] -name = "xml-rs" -version = "0.8.14" +name = "xdg-home" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52839dc911083a8ef63efa4d039d1f58b5e409f923e44c80828f206f66e5541c" +checksum = "2769203cd13a0c6015d515be729c526d041e9cf2c0cc478d57faee85f40c6dcd" +dependencies = [ + "nix 0.26.2", + "winapi", +] + +[[package]] +name = "xml-rs" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a56c84a8ccd4258aed21c92f70c0f6dea75356b6892ae27c24139da456f9336" [[package]] name = "xxhash-rust" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "735a71d46c4d68d71d4b24d03fdc2b98e38cea81730595801db779c04fe80d70" + +[[package]] +name = "zbus" +version = "3.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31de390a2d872e4cd04edd71b425e29853f786dc99317ed72d73d6fcf5ebb948" +dependencies = [ + "async-broadcast", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "byteorder", + "derivative", + "enumflags2", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix 0.26.2", + "once_cell", + "ordered-stream", + "rand 0.8.5", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "winapi", + "xdg-home", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "3.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d1794a946878c0e807f55a397187c11fc7a038ba5d868e7db4f3bd7760bc9d" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb80bb776dbda6e23d705cf0123c3b95df99c4ebeaec6c2599d4a5419902b4a9" +dependencies = [ + "serde", + "static_assertions", + "zvariant", +] + +[[package]] +name = "zvariant" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44b291bee0d960c53170780af148dca5fa260a63cdd24f1962fa82e03e53338c" +dependencies = [ + "byteorder", + "enumflags2", + "libc", + "serde", + "static_assertions", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "934d7a7dfc310d6ee06c87ffe88ef4eca7d3e37bb251dece2ef93da8f17d8ecd" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] diff --git a/Cargo.toml b/Cargo.toml index 96347157..2d8aec23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "node-graph/gcore", "node-graph/gstd", "node-graph/graph-craft", + "node-graph/graphene-cli", "node-graph/interpreted-executor", "node-graph/node-macro", "node-graph/compilation-server", diff --git a/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler.rs index 16d5e2d5..c0cffcfa 100644 --- a/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler.rs @@ -111,12 +111,12 @@ impl<'a> ModifyInputsContext<'a> { fn stroke_set(&mut self, stroke: Stroke) { self.modify_inputs("Stroke", false, |inputs| { inputs[1] = NodeInput::value(TaggedValue::OptionalColor(stroke.color), false); - inputs[2] = NodeInput::value(TaggedValue::F64(stroke.weight), false); + inputs[2] = NodeInput::value(TaggedValue::F32(stroke.weight as f32), false); inputs[3] = NodeInput::value(TaggedValue::VecF32(stroke.dash_lengths), false); - inputs[4] = NodeInput::value(TaggedValue::F64(stroke.dash_offset), false); + inputs[4] = NodeInput::value(TaggedValue::F32(stroke.dash_offset as f32), false); inputs[5] = NodeInput::value(TaggedValue::LineCap(stroke.line_cap), false); inputs[6] = NodeInput::value(TaggedValue::LineJoin(stroke.line_join), false); - inputs[7] = NodeInput::value(TaggedValue::F64(stroke.line_join_miter_limit), false); + inputs[7] = NodeInput::value(TaggedValue::F32(stroke.line_join_miter_limit as f32), false); }); } diff --git a/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler/transform_utils.rs b/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler/transform_utils.rs index 5dd99558..8afb21b4 100644 --- a/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler/transform_utils.rs +++ b/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler/transform_utils.rs @@ -36,7 +36,7 @@ pub fn update_transform(inputs: &mut [NodeInput], transform: DAffine2) { let (scale, angle, translation, shear) = compute_scale_angle_translation_shear(transform); inputs[1] = NodeInput::value(TaggedValue::DVec2(translation), false); - inputs[2] = NodeInput::value(TaggedValue::F64(angle), false); + inputs[2] = NodeInput::value(TaggedValue::F32(angle as f32), false); inputs[3] = NodeInput::value(TaggedValue::DVec2(scale), false); inputs[4] = NodeInput::value(TaggedValue::DVec2(shear), false); } @@ -87,7 +87,7 @@ pub fn get_current_transform(inputs: &[NodeInput]) -> DAffine2 { }; let angle = if let NodeInput::Value { - tagged_value: TaggedValue::F64(angle), + tagged_value: TaggedValue::F32(angle), .. } = inputs[2] { @@ -116,7 +116,7 @@ pub fn get_current_transform(inputs: &[NodeInput]) -> DAffine2 { DVec2::ZERO }; - DAffine2::from_scale_angle_translation(scale, angle, translation) * DAffine2::from_cols_array(&[1., shear.y, shear.x, 1., 0., 0.]) + DAffine2::from_scale_angle_translation(scale, angle as f64, translation) * DAffine2::from_cols_array(&[1., shear.y, shear.x, 1., 0., 0.]) } /// Extract the current normalized pivot from the layer diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs index 91923e82..c190482b 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs @@ -254,6 +254,50 @@ fn static_nodes() -> Vec { }], properties: node_properties::input_properties, }, + DocumentNodeType { + name: "Load Image", + category: "Structural", + identifier: NodeImplementation::DocumentNode(NodeNetwork { + inputs: vec![0, 0], + outputs: vec![NodeOutput::new(1, 0)], + nodes: [ + DocumentNode { + name: "Load Resource".to_string(), + inputs: vec![NodeInput::Network(concrete!(WasmEditorApi)), NodeInput::Network(concrete!(String))], + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::wasm_application_io::LoadResourceNode<_>")), + ..Default::default() + }, + DocumentNode { + name: "Decode Image".to_string(), + inputs: vec![NodeInput::node(0, 0)], + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::wasm_application_io::DecodeImageNode")), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (id as NodeId, node)) + .collect(), + ..Default::default() + }), + inputs: vec![ + DocumentInputType { + name: "api", + data_type: FrontendGraphDataType::General, + default: NodeInput::Network(concrete!(WasmEditorApi)), + }, + DocumentInputType { + name: "path", + data_type: FrontendGraphDataType::General, + default: NodeInput::value(TaggedValue::String("graphite:null".to_string()), false), + }, + ], + outputs: vec![DocumentOutputType { + name: "Image Frame", + data_type: FrontendGraphDataType::Raster, + }], + properties: node_properties::load_image_properties, + }, DocumentNodeType { name: "Create Canvas", category: "Structural", @@ -289,7 +333,7 @@ fn static_nodes() -> Vec { name: "Canvas", data_type: FrontendGraphDataType::General, }], - properties: node_properties::input_properties, + properties: node_properties::no_properties, }, DocumentNodeType { name: "Draw Canvas", @@ -345,7 +389,7 @@ fn static_nodes() -> Vec { name: "Canvas", data_type: FrontendGraphDataType::General, }], - properties: node_properties::input_properties, + properties: node_properties::no_properties, }, DocumentNodeType { name: "Begin Scope", @@ -490,7 +534,7 @@ fn static_nodes() -> Vec { DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true), DocumentInputType::value("Second", TaggedValue::ImageFrame(ImageFrame::empty()), true), DocumentInputType::value("BlendMode", TaggedValue::BlendMode(BlendMode::Normal), false), - DocumentInputType::value("Opacity", TaggedValue::F64(100.), false), + DocumentInputType::value("Opacity", TaggedValue::F32(100.), false), ], outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)], properties: node_properties::blend_properties, @@ -508,27 +552,27 @@ fn static_nodes() -> Vec { DocumentInputType { name: "Shadows", data_type: FrontendGraphDataType::Number, - default: NodeInput::value(TaggedValue::F64(0.), false), + default: NodeInput::value(TaggedValue::F32(0.), false), }, DocumentInputType { name: "Midtones", data_type: FrontendGraphDataType::Number, - default: NodeInput::value(TaggedValue::F64(50.), false), + default: NodeInput::value(TaggedValue::F32(50.), false), }, DocumentInputType { name: "Highlights", data_type: FrontendGraphDataType::Number, - default: NodeInput::value(TaggedValue::F64(100.), false), + default: NodeInput::value(TaggedValue::F32(100.), false), }, DocumentInputType { name: "Output Minimums", data_type: FrontendGraphDataType::Number, - default: NodeInput::value(TaggedValue::F64(0.), false), + default: NodeInput::value(TaggedValue::F32(0.), false), }, DocumentInputType { name: "Output Maximums", data_type: FrontendGraphDataType::Number, - default: NodeInput::value(TaggedValue::F64(100.), false), + default: NodeInput::value(TaggedValue::F32(100.), false), }, ], outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)], @@ -552,32 +596,32 @@ fn static_nodes() -> Vec { DocumentInputType { name: "Reds", data_type: FrontendGraphDataType::Number, - default: NodeInput::value(TaggedValue::F64(40.), false), + default: NodeInput::value(TaggedValue::F32(40.), false), }, DocumentInputType { name: "Yellows", data_type: FrontendGraphDataType::Number, - default: NodeInput::value(TaggedValue::F64(60.), false), + default: NodeInput::value(TaggedValue::F32(60.), false), }, DocumentInputType { name: "Greens", data_type: FrontendGraphDataType::Number, - default: NodeInput::value(TaggedValue::F64(40.), false), + default: NodeInput::value(TaggedValue::F32(40.), false), }, DocumentInputType { name: "Cyans", data_type: FrontendGraphDataType::Number, - default: NodeInput::value(TaggedValue::F64(60.), false), + default: NodeInput::value(TaggedValue::F32(60.), false), }, DocumentInputType { name: "Blues", data_type: FrontendGraphDataType::Number, - default: NodeInput::value(TaggedValue::F64(20.), false), + default: NodeInput::value(TaggedValue::F32(20.), false), }, DocumentInputType { name: "Magentas", data_type: FrontendGraphDataType::Number, - default: NodeInput::value(TaggedValue::F64(80.), false), + default: NodeInput::value(TaggedValue::F32(80.), false), }, ], outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)], @@ -713,7 +757,10 @@ fn static_nodes() -> Vec { name: "Memoize", category: "Structural", identifier: NodeImplementation::proto("graphene_core::memo::MemoNode<_, _>"), - inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true)], + inputs: vec![ + DocumentInputType::value("ShortCircut", TaggedValue::None, false), + DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true), + ], outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)], properties: node_properties::no_properties, }, @@ -1136,7 +1183,7 @@ fn static_nodes() -> Vec { category: "Gpu", identifier: NodeImplementation::DocumentNode(NodeNetwork { inputs: vec![1, 1, 0], - outputs: vec![NodeOutput::new(2, 0)], + outputs: vec![NodeOutput::new(1, 0)], nodes: [ DocumentNode { name: "Extract Executor".to_string(), @@ -1154,12 +1201,6 @@ fn static_nodes() -> Vec { implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("gpu_executor::RenderTextureNode<_, _>")), ..Default::default() }, - DocumentNode { - name: "Cache".to_string(), - inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(1, 0)], - implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")), - ..Default::default() - }, ] .into_iter() .enumerate() @@ -1367,9 +1408,9 @@ fn static_nodes() -> Vec { identifier: NodeImplementation::proto("graphene_core::raster::HueSaturationNode<_, _, _>"), inputs: vec![ DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true), - DocumentInputType::value("Hue Shift", TaggedValue::F64(0.), false), - DocumentInputType::value("Saturation Shift", TaggedValue::F64(0.), false), - DocumentInputType::value("Lightness Shift", TaggedValue::F64(0.), false), + DocumentInputType::value("Hue Shift", TaggedValue::F32(0.), false), + DocumentInputType::value("Saturation Shift", TaggedValue::F32(0.), false), + DocumentInputType::value("Lightness Shift", TaggedValue::F32(0.), false), ], outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)], properties: node_properties::adjust_hsl_properties, @@ -1380,8 +1421,8 @@ fn static_nodes() -> Vec { identifier: NodeImplementation::proto("graphene_core::raster::BrightnessContrastNode<_, _, _>"), inputs: vec![ DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true), - DocumentInputType::value("Brightness", TaggedValue::F64(0.), false), - DocumentInputType::value("Contrast", TaggedValue::F64(0.), false), + DocumentInputType::value("Brightness", TaggedValue::F32(0.), false), + DocumentInputType::value("Contrast", TaggedValue::F32(0.), false), DocumentInputType::value("Use Legacy", TaggedValue::Bool(false), false), ], outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)], @@ -1393,8 +1434,8 @@ fn static_nodes() -> Vec { identifier: NodeImplementation::proto("graphene_core::raster::ThresholdNode<_, _, _>"), inputs: vec![ DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true), - DocumentInputType::value("Min Luminance", TaggedValue::F64(50.), false), - DocumentInputType::value("Max Luminance", TaggedValue::F64(100.), false), + DocumentInputType::value("Min Luminance", TaggedValue::F32(50.), false), + DocumentInputType::value("Max Luminance", TaggedValue::F32(100.), false), DocumentInputType::value("Luminance Calc", TaggedValue::LuminanceCalculation(LuminanceCalculation::SRGB), false), ], outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)], @@ -1406,7 +1447,7 @@ fn static_nodes() -> Vec { identifier: NodeImplementation::proto("graphene_core::raster::VibranceNode<_>"), inputs: vec![ DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true), - DocumentInputType::value("Vibrance", TaggedValue::F64(0.), false), + DocumentInputType::value("Vibrance", TaggedValue::F32(0.), false), ], outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)], properties: node_properties::adjust_vibrance_properties, @@ -1420,25 +1461,25 @@ fn static_nodes() -> Vec { // Monochrome toggle DocumentInputType::value("Monochrome", TaggedValue::Bool(false), false), // Monochrome - DocumentInputType::value("Red", TaggedValue::F64(40.), false), - DocumentInputType::value("Green", TaggedValue::F64(40.), false), - DocumentInputType::value("Blue", TaggedValue::F64(20.), false), - DocumentInputType::value("Constant", TaggedValue::F64(0.), false), + DocumentInputType::value("Red", TaggedValue::F32(40.), false), + DocumentInputType::value("Green", TaggedValue::F32(40.), false), + DocumentInputType::value("Blue", TaggedValue::F32(20.), false), + DocumentInputType::value("Constant", TaggedValue::F32(0.), false), // Red output channel - DocumentInputType::value("(Red) Red", TaggedValue::F64(100.), false), - DocumentInputType::value("(Red) Green", TaggedValue::F64(0.), false), - DocumentInputType::value("(Red) Blue", TaggedValue::F64(0.), false), - DocumentInputType::value("(Red) Constant", TaggedValue::F64(0.), false), + DocumentInputType::value("(Red) Red", TaggedValue::F32(100.), false), + DocumentInputType::value("(Red) Green", TaggedValue::F32(0.), false), + DocumentInputType::value("(Red) Blue", TaggedValue::F32(0.), false), + DocumentInputType::value("(Red) Constant", TaggedValue::F32(0.), false), // Green output channel - DocumentInputType::value("(Green) Red", TaggedValue::F64(0.), false), - DocumentInputType::value("(Green) Green", TaggedValue::F64(100.), false), - DocumentInputType::value("(Green) Blue", TaggedValue::F64(0.), false), - DocumentInputType::value("(Green) Constant", TaggedValue::F64(0.), false), + DocumentInputType::value("(Green) Red", TaggedValue::F32(0.), false), + DocumentInputType::value("(Green) Green", TaggedValue::F32(100.), false), + DocumentInputType::value("(Green) Blue", TaggedValue::F32(0.), false), + DocumentInputType::value("(Green) Constant", TaggedValue::F32(0.), false), // Blue output channel - DocumentInputType::value("(Blue) Red", TaggedValue::F64(0.), false), - DocumentInputType::value("(Blue) Green", TaggedValue::F64(0.), false), - DocumentInputType::value("(Blue) Blue", TaggedValue::F64(100.), false), - DocumentInputType::value("(Blue) Constant", TaggedValue::F64(0.), false), + DocumentInputType::value("(Blue) Red", TaggedValue::F32(0.), false), + DocumentInputType::value("(Blue) Green", TaggedValue::F32(0.), false), + DocumentInputType::value("(Blue) Blue", TaggedValue::F32(100.), false), + DocumentInputType::value("(Blue) Constant", TaggedValue::F32(0.), false), // Display-only properties (not used within the node) DocumentInputType::value("Output Channel", TaggedValue::RedGreenBlue(RedGreenBlue::Red), false), ], @@ -1456,50 +1497,50 @@ fn static_nodes() -> Vec { // Mode DocumentInputType::value("Mode", TaggedValue::RelativeAbsolute(RelativeAbsolute::Relative), false), // Reds - DocumentInputType::value("(Reds) Cyan", TaggedValue::F64(0.), false), - DocumentInputType::value("(Reds) Magenta", TaggedValue::F64(0.), false), - DocumentInputType::value("(Reds) Yellow", TaggedValue::F64(0.), false), - DocumentInputType::value("(Reds) Black", TaggedValue::F64(0.), false), + DocumentInputType::value("(Reds) Cyan", TaggedValue::F32(0.), false), + DocumentInputType::value("(Reds) Magenta", TaggedValue::F32(0.), false), + DocumentInputType::value("(Reds) Yellow", TaggedValue::F32(0.), false), + DocumentInputType::value("(Reds) Black", TaggedValue::F32(0.), false), // Yellows - DocumentInputType::value("(Yellows) Cyan", TaggedValue::F64(0.), false), - DocumentInputType::value("(Yellows) Magenta", TaggedValue::F64(0.), false), - DocumentInputType::value("(Yellows) Yellow", TaggedValue::F64(0.), false), - DocumentInputType::value("(Yellows) Black", TaggedValue::F64(0.), false), + DocumentInputType::value("(Yellows) Cyan", TaggedValue::F32(0.), false), + DocumentInputType::value("(Yellows) Magenta", TaggedValue::F32(0.), false), + DocumentInputType::value("(Yellows) Yellow", TaggedValue::F32(0.), false), + DocumentInputType::value("(Yellows) Black", TaggedValue::F32(0.), false), // Greens - DocumentInputType::value("(Greens) Cyan", TaggedValue::F64(0.), false), - DocumentInputType::value("(Greens) Magenta", TaggedValue::F64(0.), false), - DocumentInputType::value("(Greens) Yellow", TaggedValue::F64(0.), false), - DocumentInputType::value("(Greens) Black", TaggedValue::F64(0.), false), + DocumentInputType::value("(Greens) Cyan", TaggedValue::F32(0.), false), + DocumentInputType::value("(Greens) Magenta", TaggedValue::F32(0.), false), + DocumentInputType::value("(Greens) Yellow", TaggedValue::F32(0.), false), + DocumentInputType::value("(Greens) Black", TaggedValue::F32(0.), false), // Cyans - DocumentInputType::value("(Cyans) Cyan", TaggedValue::F64(0.), false), - DocumentInputType::value("(Cyans) Magenta", TaggedValue::F64(0.), false), - DocumentInputType::value("(Cyans) Yellow", TaggedValue::F64(0.), false), - DocumentInputType::value("(Cyans) Black", TaggedValue::F64(0.), false), + DocumentInputType::value("(Cyans) Cyan", TaggedValue::F32(0.), false), + DocumentInputType::value("(Cyans) Magenta", TaggedValue::F32(0.), false), + DocumentInputType::value("(Cyans) Yellow", TaggedValue::F32(0.), false), + DocumentInputType::value("(Cyans) Black", TaggedValue::F32(0.), false), // Blues - DocumentInputType::value("(Blues) Cyan", TaggedValue::F64(0.), false), - DocumentInputType::value("(Blues) Magenta", TaggedValue::F64(0.), false), - DocumentInputType::value("(Blues) Yellow", TaggedValue::F64(0.), false), - DocumentInputType::value("(Blues) Black", TaggedValue::F64(0.), false), + DocumentInputType::value("(Blues) Cyan", TaggedValue::F32(0.), false), + DocumentInputType::value("(Blues) Magenta", TaggedValue::F32(0.), false), + DocumentInputType::value("(Blues) Yellow", TaggedValue::F32(0.), false), + DocumentInputType::value("(Blues) Black", TaggedValue::F32(0.), false), // Magentas - DocumentInputType::value("(Magentas) Cyan", TaggedValue::F64(0.), false), - DocumentInputType::value("(Magentas) Magenta", TaggedValue::F64(0.), false), - DocumentInputType::value("(Magentas) Yellow", TaggedValue::F64(0.), false), - DocumentInputType::value("(Magentas) Black", TaggedValue::F64(0.), false), + DocumentInputType::value("(Magentas) Cyan", TaggedValue::F32(0.), false), + DocumentInputType::value("(Magentas) Magenta", TaggedValue::F32(0.), false), + DocumentInputType::value("(Magentas) Yellow", TaggedValue::F32(0.), false), + DocumentInputType::value("(Magentas) Black", TaggedValue::F32(0.), false), // Whites - DocumentInputType::value("(Whites) Cyan", TaggedValue::F64(0.), false), - DocumentInputType::value("(Whites) Magenta", TaggedValue::F64(0.), false), - DocumentInputType::value("(Whites) Yellow", TaggedValue::F64(0.), false), - DocumentInputType::value("(Whites) Black", TaggedValue::F64(0.), false), + DocumentInputType::value("(Whites) Cyan", TaggedValue::F32(0.), false), + DocumentInputType::value("(Whites) Magenta", TaggedValue::F32(0.), false), + DocumentInputType::value("(Whites) Yellow", TaggedValue::F32(0.), false), + DocumentInputType::value("(Whites) Black", TaggedValue::F32(0.), false), // Neutrals - DocumentInputType::value("(Neutrals) Cyan", TaggedValue::F64(0.), false), - DocumentInputType::value("(Neutrals) Magenta", TaggedValue::F64(0.), false), - DocumentInputType::value("(Neutrals) Yellow", TaggedValue::F64(0.), false), - DocumentInputType::value("(Neutrals) Black", TaggedValue::F64(0.), false), + DocumentInputType::value("(Neutrals) Cyan", TaggedValue::F32(0.), false), + DocumentInputType::value("(Neutrals) Magenta", TaggedValue::F32(0.), false), + DocumentInputType::value("(Neutrals) Yellow", TaggedValue::F32(0.), false), + DocumentInputType::value("(Neutrals) Black", TaggedValue::F32(0.), false), // Blacks - DocumentInputType::value("(Blacks) Cyan", TaggedValue::F64(0.), false), - DocumentInputType::value("(Blacks) Magenta", TaggedValue::F64(0.), false), - DocumentInputType::value("(Blacks) Yellow", TaggedValue::F64(0.), false), - DocumentInputType::value("(Blacks) Black", TaggedValue::F64(0.), false), + DocumentInputType::value("(Blacks) Cyan", TaggedValue::F32(0.), false), + DocumentInputType::value("(Blacks) Magenta", TaggedValue::F32(0.), false), + DocumentInputType::value("(Blacks) Yellow", TaggedValue::F32(0.), false), + DocumentInputType::value("(Blacks) Black", TaggedValue::F32(0.), false), // Display-only properties (not used within the node) DocumentInputType::value("Colors", TaggedValue::SelectiveColorChoice(SelectiveColorChoice::Reds), false), ], @@ -1512,7 +1553,7 @@ fn static_nodes() -> Vec { identifier: NodeImplementation::proto("graphene_core::raster::OpacityNode<_>"), inputs: vec![ DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true), - DocumentInputType::value("Factor", TaggedValue::F64(100.), false), + DocumentInputType::value("Factor", TaggedValue::F32(100.), false), ], outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)], properties: node_properties::multiply_opacity, @@ -1523,7 +1564,7 @@ fn static_nodes() -> Vec { identifier: NodeImplementation::proto("graphene_core::raster::PosterizeNode<_>"), inputs: vec![ DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true), - DocumentInputType::value("Value", TaggedValue::F64(4.), false), + DocumentInputType::value("Value", TaggedValue::F32(4.), false), ], outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)], properties: node_properties::posterize_properties, @@ -1534,9 +1575,9 @@ fn static_nodes() -> Vec { identifier: NodeImplementation::proto("graphene_core::raster::ExposureNode<_, _, _>"), inputs: vec![ DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true), - DocumentInputType::value("Exposure", TaggedValue::F64(0.), false), - DocumentInputType::value("Offset", TaggedValue::F64(0.), false), - DocumentInputType::value("Gamma Correction", TaggedValue::F64(1.), false), + DocumentInputType::value("Exposure", TaggedValue::F32(0.), false), + DocumentInputType::value("Offset", TaggedValue::F32(0.), false), + DocumentInputType::value("Gamma Correction", TaggedValue::F32(1.), false), ], outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)], properties: node_properties::exposure_properties, @@ -1546,8 +1587,8 @@ fn static_nodes() -> Vec { category: "Math", identifier: NodeImplementation::proto("graphene_core::ops::AddParameterNode<_>"), inputs: vec![ - DocumentInputType::value("Input", TaggedValue::F64(0.), true), - DocumentInputType::value("Addend", TaggedValue::F64(0.), true), + DocumentInputType::value("Input", TaggedValue::F32(0.), true), + DocumentInputType::value("Addend", TaggedValue::F32(0.), true), ], outputs: vec![DocumentOutputType::new("Output", FrontendGraphDataType::Number)], properties: node_properties::add_properties, @@ -1580,7 +1621,7 @@ fn static_nodes() -> Vec { DocumentInputType::none(), DocumentInputType::value("Text", TaggedValue::String("hello world".to_string()), false), DocumentInputType::value("Font", TaggedValue::Font(Font::new(DEFAULT_FONT_FAMILY.into(), DEFAULT_FONT_STYLE.into())), false), - DocumentInputType::value("Size", TaggedValue::F64(24.), false), + DocumentInputType::value("Size", TaggedValue::F32(24.), false), ], outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], properties: node_properties::node_section_font, @@ -1592,7 +1633,7 @@ fn static_nodes() -> Vec { inputs: vec![ DocumentInputType::value("Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), DocumentInputType::value("Translation", TaggedValue::DVec2(DVec2::ZERO), false), - DocumentInputType::value("Rotation", TaggedValue::F64(0.), false), + DocumentInputType::value("Rotation", TaggedValue::F32(0.), false), DocumentInputType::value("Scale", TaggedValue::DVec2(DVec2::ONE), false), DocumentInputType::value("Skew", TaggedValue::DVec2(DVec2::ZERO), false), DocumentInputType::value("Pivot", TaggedValue::DVec2(DVec2::splat(0.5)), false), @@ -1635,12 +1676,12 @@ fn static_nodes() -> Vec { inputs: vec![ DocumentInputType::value("Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), DocumentInputType::value("Color", TaggedValue::OptionalColor(Some(Color::BLACK)), false), - DocumentInputType::value("Weight", TaggedValue::F64(0.), false), + DocumentInputType::value("Weight", TaggedValue::F32(0.), false), DocumentInputType::value("Dash Lengths", TaggedValue::VecF32(Vec::new()), false), - DocumentInputType::value("Dash Offset", TaggedValue::F64(0.), false), + DocumentInputType::value("Dash Offset", TaggedValue::F32(0.), false), DocumentInputType::value("Line Cap", TaggedValue::LineCap(graphene_core::vector::style::LineCap::Butt), false), DocumentInputType::value("Line Join", TaggedValue::LineJoin(graphene_core::vector::style::LineJoin::Miter), false), - DocumentInputType::value("Miter Limit", TaggedValue::F64(4.), false), + DocumentInputType::value("Miter Limit", TaggedValue::F32(4.), false), ], outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], properties: node_properties::stroke_properties, @@ -1727,18 +1768,18 @@ pub static IMAGINATE_NODE: Lazy = Lazy::new(|| DocumentNodeTyp default: NodeInput::Network(concrete!(WasmEditorApi)), }, DocumentInputType::value("Controller", TaggedValue::ImaginateController(Default::default()), false), - DocumentInputType::value("Seed", TaggedValue::F64(0.), false), // Remember to keep index used in `ImaginateRandom` updated with this entry's index + DocumentInputType::value("Seed", TaggedValue::F32(0.), false), // Remember to keep index used in `ImaginateRandom` updated with this entry's index DocumentInputType::value("Resolution", TaggedValue::OptionalDVec2(None), false), DocumentInputType::value("Samples", TaggedValue::U32(30), false), DocumentInputType::value("Sampling Method", TaggedValue::ImaginateSamplingMethod(ImaginateSamplingMethod::EulerA), false), - DocumentInputType::value("Prompt Guidance", TaggedValue::F64(7.5), false), + DocumentInputType::value("Prompt Guidance", TaggedValue::F32(7.5), false), DocumentInputType::value("Prompt", TaggedValue::String(String::new()), false), DocumentInputType::value("Negative Prompt", TaggedValue::String(String::new()), false), DocumentInputType::value("Adapt Input Image", TaggedValue::Bool(false), false), - DocumentInputType::value("Image Creativity", TaggedValue::F64(66.), false), + DocumentInputType::value("Image Creativity", TaggedValue::F32(66.), false), DocumentInputType::value("Masking Layer", TaggedValue::LayerPath(None), false), DocumentInputType::value("Inpaint", TaggedValue::Bool(true), false), - DocumentInputType::value("Mask Blur", TaggedValue::F64(4.), false), + DocumentInputType::value("Mask Blur", TaggedValue::F32(4.), false), DocumentInputType::value("Mask Starting Fill", TaggedValue::ImaginateMaskStartingFill(ImaginateMaskStartingFill::Fill), false), DocumentInputType::value("Improve Faces", TaggedValue::Bool(false), false), DocumentInputType::value("Tiling", TaggedValue::Bool(false), false), @@ -1767,7 +1808,9 @@ impl DocumentNodeType { let inner_network = match &self.identifier { NodeImplementation::DocumentNode(network) => network.clone(), - NodeImplementation::ProtoNode(ident) => { + + NodeImplementation::ProtoNode(ident) => return DocumentNodeImplementation::Unresolved(ident.clone()), + /* NodeNetwork { inputs: (0..num_inputs).map(|_| 0).collect(), outputs: vec![NodeOutput::new(0, 0)], @@ -1785,23 +1828,10 @@ impl DocumentNodeType { .collect(), ..Default::default() } + } - NodeImplementation::Extract => NodeNetwork { - inputs: (0..num_inputs).map(|_| 0).collect(), - outputs: vec![NodeOutput::new(0, 0)], - nodes: [( - 0, - DocumentNode { - name: "ExtractNode".to_string(), - implementation: DocumentNodeImplementation::Extract, - inputs: self.inputs.iter().map(|i| NodeInput::Network(i.default.ty())).collect(), - ..Default::default() - }, - )] - .into_iter() - .collect(), - ..Default::default() - }, + */ + NodeImplementation::Extract => return DocumentNodeImplementation::Extract, }; DocumentNodeImplementation::Network(inner_network) @@ -1830,9 +1860,9 @@ impl DocumentNodeType { } pub fn wrap_network_in_scope(mut network: NodeNetwork) -> NodeNetwork { - let node_ids = network.nodes.keys().copied().collect::>(); - network.generate_node_paths(&[]); + + let node_ids = network.nodes.keys().copied().collect::>(); for id in node_ids { network.flatten(id); } @@ -1927,7 +1957,7 @@ pub fn new_vector_network(subpaths: Vec NodeNetwork { +pub fn new_text_network(text: String, font: Font, size: f32) -> NodeNetwork { let text_generator = resolve_document_node_type("Text").expect("Text node does not exist"); let transform = resolve_document_node_type("Transform").expect("Transform node does not exist"); let fill = resolve_document_node_type("Fill").expect("Fill node does not exist"); @@ -1944,7 +1974,7 @@ pub fn new_text_network(text: String, font: Font, size: f64) -> NodeNetwork { NodeInput::Network(concrete!(WasmEditorApi)), NodeInput::value(TaggedValue::String(text), false), NodeInput::value(TaggedValue::Font(font), false), - NodeInput::value(TaggedValue::F64(size), false), + NodeInput::value(TaggedValue::F32(size), false), ], DocumentNodeMetadata::position((0, 4)), ), diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs index f9dd10d3..1ebc542e 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs @@ -624,6 +624,12 @@ pub fn blend_properties(document_node: &DocumentNode, node_id: NodeId, _context: vec![backdrop, blend_mode, LayoutGroup::Row { widgets: opacity }] } +pub fn load_image_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { + let url = text_widget(document_node, node_id, 1, "Url", true); + + vec![LayoutGroup::Row { widgets: url }] +} + pub fn output_properties(_document_node: &DocumentNode, _node_id: NodeId, context: &mut NodePropertiesContext) -> Vec { let output_type = context.executor.previous_output_type(context.layer_path); let raster_output_type = concrete!(ImageFrame); diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 42a46678..8bda6fcd 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -319,7 +319,7 @@ impl TextToolData { else if let Some(editing_text) = self.editing_text.as_ref().filter(|_| state == TextToolFsmState::Ready) { responses.add(DocumentMessage::StartTransaction); - let network = new_text_network(String::new(), editing_text.font.clone(), editing_text.font_size); + let network = new_text_network(String::new(), editing_text.font.clone(), editing_text.font_size as f32); responses.add(Operation::AddFrame { path: self.layer_path.clone(), diff --git a/libraries/dyn-any/src/lib.rs b/libraries/dyn-any/src/lib.rs index c85198c8..99d7ba2a 100644 --- a/libraries/dyn-any/src/lib.rs +++ b/libraries/dyn-any/src/lib.rs @@ -156,9 +156,6 @@ unsafe impl StaticType for *const [T] { unsafe impl StaticType for *mut [T] { type Static = *mut [::Static]; } -unsafe impl<'a, T: StaticTypeSized> StaticType for &'a [T] { - type Static = &'static [::Static]; -} macro_rules! impl_slice { ($($id:ident),*) => { $( @@ -192,6 +189,9 @@ unsafe impl<'a, T: 'a + StaticType + ?Sized> StaticType for &'a T { unsafe impl StaticType for [T; N] { type Static = [::Static; N]; } +unsafe impl StaticType for [T] { + type Static = [::Static]; +} unsafe impl StaticType for dyn for<'i> DynAny<'_> + '_ { type Static = dyn DynAny<'static>; @@ -271,7 +271,9 @@ impl_type!(Rc); #[cfg(all(feature = "rc", feature = "alloc"))] use std::sync::Arc; #[cfg(all(feature = "rc", feature = "alloc"))] -impl_type!(Arc); +unsafe impl StaticType for Arc { + type Static = Arc<::Static>; +} #[cfg(feature = "glam")] use glam::*; diff --git a/node-graph/compilation-server/src/main.rs b/node-graph/compilation-server/src/main.rs index 90959f43..20ac2eb5 100644 --- a/node-graph/compilation-server/src/main.rs +++ b/node-graph/compilation-server/src/main.rs @@ -43,7 +43,7 @@ async fn post_compile_spirv(State(state): State>, Json(compile_req let result = compile_request.compile(state.compile_dir.path().to_str().expect("non utf8 tempdir path"), &path).map_err(|e| { eprintln!("compilation failed: {}", e); StatusCode::INTERNAL_SERVER_ERROR - }); - state.cache.write().unwrap().insert(compile_request, result.clone()); - result + })?; + state.cache.write().unwrap().insert(compile_request, Ok(result.clone())); + Ok(result) } diff --git a/node-graph/gcore/Cargo.toml b/node-graph/gcore/Cargo.toml index ae51bcdb..84ec2ebe 100644 --- a/node-graph/gcore/Cargo.toml +++ b/node-graph/gcore/Cargo.toml @@ -9,24 +9,10 @@ license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -std = [ - "dyn-any", - "dyn-any/std", - "alloc", - "glam/std", - "specta", - "num-traits/std", - "rustybuzz", -] +std = ["dyn-any", "dyn-any/std", "alloc", "glam/std", "specta", "num-traits/std", "rustybuzz"] default = ["async", "serde", "kurbo", "log", "std", "rand_chacha", "wasm"] log = ["dep:log"] -serde = [ - "dep:serde", - "glam/serde", - "bezier-rs/serde", - "bezier-rs/serde", - "base64", -] +serde = ["dep:serde", "glam/serde", "bezier-rs/serde", "bezier-rs/serde", "base64"] gpu = ["spirv-std", "glam/bytemuck", "dyn-any", "glam/libm"] async = ["async-trait", "alloc"] nightly = [] diff --git a/node-graph/gcore/src/application_io.rs b/node-graph/gcore/src/application_io.rs index 5b23d02b..02ca21a6 100644 --- a/node-graph/gcore/src/application_io.rs +++ b/node-graph/gcore/src/application_io.rs @@ -8,7 +8,10 @@ use dyn_any::StaticType; use dyn_any::StaticTypeSized; use glam::DAffine2; +use core::any::Any; +use core::future::Future; use core::hash::{Hash, Hasher}; +use core::pin::Pin; use crate::text::FontCache; @@ -93,6 +96,7 @@ pub trait ApplicationIo { fn gpu_executor(&self) -> Option<&Self::Executor> { None } + fn load_resource<'a>(&self, url: impl AsRef) -> Result, ApplicationError>>>>, ApplicationError>; } impl ApplicationIo for &T { @@ -110,6 +114,16 @@ impl ApplicationIo for &T { fn gpu_executor(&self) -> Option<&T::Executor> { (**self).gpu_executor() } + + fn load_resource<'a>(&self, url: impl AsRef) -> Result, ApplicationError>>>>, ApplicationError> { + (**self).load_resource(url) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ApplicationError { + NotFound, + InvalidUrl, } #[derive(Debug, Clone)] diff --git a/node-graph/gcore/src/generic.rs b/node-graph/gcore/src/generic.rs index 1b7106fe..12010886 100644 --- a/node-graph/gcore/src/generic.rs +++ b/node-graph/gcore/src/generic.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use crate::Node; +use crate::{Node, NodeMut}; pub struct FnNode O, I, O>(T, PhantomData<(I, O)>); impl<'i, T: Fn(I) -> O + 'i, O: 'i, I: 'i> Node<'i, I> for FnNode { @@ -16,6 +16,21 @@ impl O, I, O> FnNode { } } +pub struct FnMutNode O, I, O>(T, PhantomData<(I, O)>); + +impl<'i, T: FnMut(I) -> O + 'i, O: 'i, I: 'i> NodeMut<'i, I> for FnMutNode { + type MutOutput = O; + fn eval_mut(&'i mut self, input: I) -> Self::MutOutput { + self.0(input) + } +} + +impl<'i, T: FnMut(I) -> O + 'i, I: 'i, O: 'i> FnMutNode { + pub fn new(f: T) -> Self { + FnMutNode(f, PhantomData) + } +} + pub struct FnNodeWithState<'i, T: Fn(I, &'i State) -> O, I, O, State: 'i>(T, State, PhantomData<(&'i O, I)>); impl<'i, I: 'i, O: 'i, State, T: Fn(I, &'i State) -> O + 'i> Node<'i, I> for FnNodeWithState<'i, T, I, O, State> { type Output = O; diff --git a/node-graph/gcore/src/lib.rs b/node-graph/gcore/src/lib.rs index 018588c4..1c2fdd31 100644 --- a/node-graph/gcore/src/lib.rs +++ b/node-graph/gcore/src/lib.rs @@ -55,6 +55,32 @@ pub trait Node<'i, Input: 'i>: 'i { } } +pub trait NodeMut<'i, Input: 'i>: 'i { + type MutOutput: 'i; + fn eval_mut(&'i mut self, input: Input) -> Self::MutOutput; +} + +pub trait NodeOnce<'i, Input> +where + Input: 'i, +{ + type OnceOutput: 'i; + fn eval_once(self, input: Input) -> Self::OnceOutput; +} + +impl<'i, T: Node<'i, I>, I: 'i> NodeOnce<'i, I> for &'i T { + type OnceOutput = T::Output; + fn eval_once(self, input: I) -> Self::OnceOutput { + (self).eval(input) + } +} +impl<'i, T: Node<'i, I> + ?Sized, I: 'i> NodeMut<'i, I> for &'i T { + type MutOutput = T::Output; + fn eval_mut(&'i mut self, input: I) -> Self::MutOutput { + (*self).eval(input) + } +} + #[cfg(feature = "alloc")] mod types; #[cfg(feature = "alloc")] @@ -98,52 +124,40 @@ where { } -impl<'i, 's: 'i, I: 'i, O: 'i, N: Node<'i, I, Output = O>> Node<'i, I> for &'s N { +impl<'i, 's: 'i, I: 'i, N: Node<'i, I> + ?Sized> Node<'i, I> for &'i N { + type Output = N::Output; + fn eval(&'i self, input: I) -> N::Output { + (*self).eval(input) + } +} +#[cfg(feature = "alloc")] +impl<'i, 's: 'i, I: 'i, O: 'i, N: Node<'i, I, Output = O> + ?Sized> Node<'i, I> for Box { type Output = O; - - fn eval(&'i self, input: I) -> Self::Output { + fn eval(&'i self, input: I) -> O { (**self).eval(input) } } #[cfg(feature = "alloc")] -impl<'i, 's: 'i, I: 'i, O: 'i, N: Node<'i, I, Output = O>> Node<'i, I> for Box { +impl<'i, 's: 'i, I: 'i, O: 'i, N: Node<'i, I, Output = O> + ?Sized> Node<'i, I> for alloc::sync::Arc { type Output = O; - - fn eval(&'i self, input: I) -> Self::Output { - (**self).eval(input) - } -} -#[cfg(feature = "alloc")] -impl<'i, 's: 'i, I: 'i, O: 'i, N: Node<'i, I, Output = O>> Node<'i, I> for alloc::sync::Arc { - type Output = O; - - fn eval(&'i self, input: I) -> Self::Output { + fn eval(&'i self, input: I) -> O { (**self).eval(input) } } -impl<'i, I: 'i, O: 'i> Node<'i, I> for &'i dyn Node<'i, I, Output = O> { - type Output = O; - - fn eval(&'i self, input: I) -> Self::Output { - (**self).eval(input) - } -} use core::pin::Pin; use dyn_any::StaticTypeSized; #[cfg(feature = "alloc")] impl<'i, I: 'i, O: 'i> Node<'i, I> for Pin + 'i>> { type Output = O; - - fn eval(&'i self, input: I) -> Self::Output { + fn eval(&'i self, input: I) -> O { (**self).eval(input) } } impl<'i, I: 'i, O: 'i> Node<'i, I> for Pin<&'i (dyn NodeIO<'i, I, Output = O> + 'i)> { type Output = O; - - fn eval(&'i self, input: I) -> Self::Output { + fn eval(&'i self, input: I) -> O { (**self).eval(input) } } diff --git a/node-graph/gcore/src/memo.rs b/node-graph/gcore/src/memo.rs index 8ba30abc..21d26712 100644 --- a/node-graph/gcore/src/memo.rs +++ b/node-graph/gcore/src/memo.rs @@ -21,7 +21,7 @@ where // TODO: This should return a reference to the cached cached_value // but that requires a lot of lifetime magic <- This was suggested by copilot but is pretty acurate xD type Output = Pin + 'i>>; - fn eval(&'i self, input: ()) -> Self::Output { + fn eval(&'i self, input: ()) -> Pin + 'i>> { Box::pin(async move { if let Some(cached_value) = self.cache.take() { self.cache.set(Some(cached_value.clone())); diff --git a/node-graph/gcore/src/ops.rs b/node-graph/gcore/src/ops.rs index dd152335..ac5d12fb 100644 --- a/node-graph/gcore/src/ops.rs +++ b/node-graph/gcore/src/ops.rs @@ -210,6 +210,7 @@ pub struct IntoNode { _i: PhantomData, _o: PhantomData, } +#[cfg(feature = "alloc")] #[node_macro::node_fn(IntoNode<_I, _O>)] async fn into<_I, _O>(input: _I) -> _O where diff --git a/node-graph/gcore/src/quantization.rs b/node-graph/gcore/src/quantization.rs index 50feb98e..6d0210a9 100644 --- a/node-graph/gcore/src/quantization.rs +++ b/node-graph/gcore/src/quantization.rs @@ -1,58 +1,121 @@ -use crate::raster::Color; +use crate::raster::{Color, Pixel}; use crate::Node; +use bytemuck::{Pod, Zeroable}; use dyn_any::{DynAny, StaticType}; +use num_traits::CheckedShr; #[cfg(target_arch = "spirv")] use spirv_std::num_traits::Float; -#[derive(Clone, Debug, DynAny, PartialEq)] +#[derive(Clone, Copy, DynAny, PartialEq, Pod, Zeroable)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[repr(C, align(16))] pub struct Quantization { - pub fn_index: usize, pub a: f32, pub b: f32, - pub c: f32, - pub d: f32, + pub bits: u32, + _padding: u32, +} + +impl core::fmt::Debug for Quantization { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Quantization").field("a", &self.a).field("b", &self.b()).field("bits", &self.bits()).finish() + } +} + +impl Quantization { + pub fn new(a: f32, b: f32, bits: u32) -> Self { + Self { a, b, bits, _padding: 0 } + } + + pub fn a(&self) -> f32 { + self.a + } + + pub fn b(&self) -> f32 { + self.b + } + + pub fn bits(&self) -> u32 { + self.bits + } } impl core::hash::Hash for Quantization { fn hash(&self, state: &mut H) { - self.fn_index.hash(state); - self.a.to_bits().hash(state); - self.b.to_bits().hash(state); - self.c.to_bits().hash(state); - self.d.to_bits().hash(state); + self.bits().hash(state); + self.a().to_bits().hash(state); + self.b().to_bits().hash(state); } } impl Default for Quantization { fn default() -> Self { - Self { - fn_index: Default::default(), - a: 1., - b: Default::default(), - c: Default::default(), - d: Default::default(), - } + Self::new(1., 0., 8) } } pub type QuantizationChannels = [Quantization; 4]; +#[repr(transparent)] +#[derive(DynAny, Clone, Copy, Debug, PartialEq, Eq, Pod, Zeroable)] +pub struct PackedPixel(pub u32); -fn quantize(value: f32, quantization: &Quantization) -> f32 { - let Quantization { fn_index, a, b, c, d } = quantization; - match fn_index { - 1 => ((value + a) * d).abs().ln() * b + c, - _ => a * value + b, - } +impl Pixel for PackedPixel {} + +/* +#[inline(always)] +fn quantize(value: f32, offset: u32, quantization: Quantization) -> u32 { + let a = quantization.a(); + let bits = quantization.bits(); + let b = quantization.b(); + let value = (((a * value) * ((1 << bits) - 1) as f32) as i32 + b) as u32; + value.checked_shl(32 - bits - offset).unwrap_or(0) +}*/ + +#[inline(always)] +fn quantize(value: f32, offset: u32, quantization: Quantization) -> u32 { + let a = quantization.a(); + let b = quantization.b(); + let bits = quantization.bits(); + + // Calculate the quantized value + // Scale the value by 'a' and the maximum quantization range + let scaled_value = ((a * value) + b) * ((1 << bits) - 1) as f32; + // Round the scaled value to the nearest integer + let rounded_value = scaled_value.clamp(0., (1 << bits) as f32 - 1.) as u32; + + // Shift the quantized value to the appropriate position based on the offset + let shifted_value = rounded_value.checked_shl(32 - bits - offset).unwrap(); + + shifted_value as u32 } +/* +#[inline(always)] +fn decode(value: u32, offset: u32, quantization: Quantization) -> f32 { + let a = quantization.a(); + let bits = quantization.bits(); + let b = quantization.b(); + let value = (value << offset) >> (31 - bits); + let value = value as i32 - b; + (value as f32 / ((1 << bits) - 1) as f32) / a +}*/ -fn decode(value: f32, quantization: &Quantization) -> f32 { - let Quantization { fn_index, a, b, c, d } = quantization; - match fn_index { - 1 => -(-c / b).exp() * (a * d * (c / b).exp() - (value / b).exp()) / d, - _ => (value - b) / a, - } +#[inline(always)] +fn decode(value: u32, offset: u32, quantization: Quantization) -> f32 { + let a = quantization.a(); + let bits = quantization.bits(); + let b = quantization.b(); + + // Shift the value to the appropriate position based on the offset + let shifted_value = value.checked_shr(32 - bits - offset).unwrap(); + + // Unpack the quantized value + let unpacked_value = shifted_value & ((1 << bits) - 1); // Mask out the unnecessary bits + let normalized_value = unpacked_value as f32 / ((1 << bits) - 1) as f32; // Normalize the value based on the quantization range + let decoded_value = normalized_value - b; + let original_value = decoded_value / a; + + original_value } pub struct QuantizeNode { @@ -60,14 +123,22 @@ pub struct QuantizeNode { } #[node_macro::node_fn(QuantizeNode)] -fn quantize_fn<'a>(color: Color, quantization: [Quantization; 4]) -> Color { - let quant = quantization.as_slice(); - let r = quantize(color.r(), &quant[0]); - let g = quantize(color.g(), &quant[1]); - let b = quantize(color.b(), &quant[2]); - let a = quantize(color.a(), &quant[3]); +fn quantize_fn<'a>(color: Color, quantization: [Quantization; 4]) -> PackedPixel { + let quant = quantization; + quantize_color(color, quant) +} - Color::from_rgbaf32_unchecked(r, g, b, a) +pub fn quantize_color(color: Color, quant: [Quantization; 4]) -> PackedPixel { + let mut offset = 0; + let r = quantize(color.r(), offset, quant[0]); + offset += quant[0].bits(); + let g = quantize(color.g(), offset, quant[1]); + offset += quant[1].bits(); + let b = quantize(color.b(), offset, quant[2]); + offset += quant[2].bits(); + let a = quantize(color.a(), offset, quant[3]); + + PackedPixel(r | g | b | a) } pub struct DeQuantizeNode { @@ -75,12 +146,53 @@ pub struct DeQuantizeNode { } #[node_macro::node_fn(DeQuantizeNode)] -fn dequantize_fn<'a>(color: Color, quantization: [Quantization; 4]) -> Color { - let quant = quantization.as_slice(); - let r = decode(color.r(), &quant[0]); - let g = decode(color.g(), &quant[1]); - let b = decode(color.b(), &quant[2]); - let a = decode(color.a(), &quant[3]); +fn dequantize_fn<'a>(color: PackedPixel, quantization: [Quantization; 4]) -> Color { + let quant = quantization; + dequantize_color(color, quant) +} + +pub fn dequantize_color(color: PackedPixel, quant: [Quantization; 4]) -> Color { + let mut offset = 0; + let r = decode(color.0, offset, quant[0]); + offset += quant[0].bits(); + let g = decode(color.0, offset, quant[1]); + offset += quant[1].bits(); + let b = decode(color.0, offset, quant[2]); + offset += quant[2].bits(); + let a = decode(color.0, offset, quant[3]); Color::from_rgbaf32_unchecked(r, g, b, a) } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn quantize() { + let quant = Quantization::new(1., 0., 8); + let color = Color::from_rgbaf32_unchecked(0.5, 0.5, 0.5, 0.5); + let quantized = quantize_color(color, [quant; 4]); + assert_eq!(quantized.0, 0x7f7f7f7f); + let dequantized = dequantize_color(quantized, [quant; 4]); + //assert_eq!(color, dequantized); + } + + #[test] + fn quantize_black() { + let quant = Quantization::new(1., 0., 8); + let color = Color::from_rgbaf32_unchecked(0., 0., 0., 1.); + let quantized = quantize_color(color, [quant; 4]); + assert_eq!(quantized.0, 0xff); + let dequantized = dequantize_color(quantized, [quant; 4]); + assert_eq!(color, dequantized); + } + + #[test] + fn test_getters() { + let quant = Quantization::new(1., 3., 8); + assert_eq!(quant.a(), 1.); + assert_eq!(quant.b(), 3.); + assert_eq!(quant.bits(), 8); + } +} diff --git a/node-graph/gcore/src/raster.rs b/node-graph/gcore/src/raster.rs index 2ca26f94..8911c078 100644 --- a/node-graph/gcore/src/raster.rs +++ b/node-graph/gcore/src/raster.rs @@ -11,6 +11,7 @@ pub mod adjustments; pub mod bbox; #[cfg(not(target_arch = "spirv"))] pub mod brightness_contrast; +#[cfg(not(target_arch = "spirv"))] pub mod brush_cache; pub mod color; pub mod discrete_srgb; diff --git a/node-graph/gcore/src/raster/adjustments.rs b/node-graph/gcore/src/raster/adjustments.rs index a91da0ca..990d4a05 100644 --- a/node-graph/gcore/src/raster/adjustments.rs +++ b/node-graph/gcore/src/raster/adjustments.rs @@ -229,7 +229,7 @@ pub struct LevelsNode { // From https://stackoverflow.com/questions/39510072/algorithm-for-adjustment-of-image-levels #[node_macro::node_fn(LevelsNode)] -fn levels_node(color: Color, input_start: f64, input_mid: f64, input_end: f64, output_start: f64, output_end: f64) -> Color { +fn levels_node(color: Color, input_start: f32, input_mid: f32, input_end: f32, output_start: f32, output_end: f32) -> Color { let color = color.to_gamma_srgb(); // Input Range (Range: 0-1) @@ -238,8 +238,8 @@ fn levels_node(color: Color, input_start: f64, input_mid: f64, input_end: f64, o let input_highlights = (input_end / 100.) as f32; // Output Range (Range: 0-1) - let output_minimums = (output_start / 100.) as f32; - let output_maximums = (output_end / 100.) as f32; + let output_minimums = output_start / 100.; + let output_maximums = output_end / 100.; // Midtones interpolation factor between minimums and maximums (Range: 0-1) let midtones = output_minimums + (output_maximums - output_minimums) * input_midtones; @@ -286,7 +286,7 @@ pub struct GrayscaleNode { // From // Works the same for gamma and linear color #[node_macro::node_fn(GrayscaleNode)] -fn grayscale_color_node(color: Color, tint: Color, reds: f64, yellows: f64, greens: f64, cyans: f64, blues: f64, magentas: f64) -> Color { +fn grayscale_color_node(color: Color, tint: Color, reds: f32, yellows: f32, greens: f32, cyans: f32, blues: f32, magentas: f32) -> Color { let color = color.to_gamma_srgb(); let reds = reds as f32 / 100.; @@ -321,38 +321,29 @@ fn grayscale_color_node(color: Color, tint: Color, reds: f64, yellows: f64, gree color.to_linear_srgb() } -#[cfg(not(target_arch = "spirv"))] -pub use hue_shift::HueSaturationNode; +#[derive(Debug)] +pub struct HueSaturationNode { + hue_shift: Hue, + saturation_shift: Saturation, + lightness_shift: Lightness, +} -// TODO: Make this work on GPU so it can be removed from the wrapper module that excludes GPU (it doesn't work because of the modulo) -#[cfg(not(target_arch = "spirv"))] -mod hue_shift { - use super::*; +#[node_macro::node_fn(HueSaturationNode)] +fn hue_shift_color_node(color: Color, hue_shift: f32, saturation_shift: f32, lightness_shift: f32) -> Color { + let color = color.to_gamma_srgb(); - #[derive(Debug)] - pub struct HueSaturationNode { - hue_shift: Hue, - saturation_shift: Saturation, - lightness_shift: Lightness, - } + let [hue, saturation, lightness, alpha] = color.to_hsla(); - #[node_macro::node_fn(HueSaturationNode)] - fn hue_shift_color_node(color: Color, hue_shift: f64, saturation_shift: f64, lightness_shift: f64) -> Color { - let color = color.to_gamma_srgb(); + let color = Color::from_hsla( + (hue + hue_shift / 360.) % 1., + // TODO: Improve the way saturation works (it's slightly off) + (saturation + saturation_shift / 100.).clamp(0., 1.), + // TODO: Fix the way lightness works (it's very off) + (lightness + lightness_shift / 100.).clamp(0., 1.), + alpha, + ); - let [hue, saturation, lightness, alpha] = color.to_hsla(); - - let color = Color::from_hsla( - (hue + hue_shift as f32 / 360.) % 1., - // TODO: Improve the way saturation works (it's slightly off) - (saturation + saturation_shift as f32 / 100.).clamp(0., 1.), - // TODO: Fix the way lightness works (it's very off) - (lightness + lightness_shift as f32 / 100.).clamp(0., 1.), - alpha, - ); - - color.to_linear_srgb() - } + color.to_linear_srgb() } #[derive(Debug, Clone, Copy)] @@ -388,9 +379,9 @@ pub struct ThresholdNode { } #[node_macro::node_fn(ThresholdNode)] -fn threshold_node(color: Color, min_luminance: f64, max_luminance: f64, luminance_calc: LuminanceCalculation) -> Color { - let min_luminance = Color::srgb_to_linear(min_luminance as f32 / 100.); - let max_luminance = Color::srgb_to_linear(max_luminance as f32 / 100.); +fn threshold_node(color: Color, min_luminance: f32, max_luminance: f32, luminance_calc: LuminanceCalculation) -> Color { + let min_luminance = Color::srgb_to_linear(min_luminance / 100.); + let max_luminance = Color::srgb_to_linear(max_luminance / 100.); let luminance = match luminance_calc { LuminanceCalculation::SRGB => color.luminance_srgb(), @@ -414,7 +405,7 @@ pub struct BlendNode { } #[node_macro::node_fn(BlendNode)] -fn blend_node(input: (Color, Color), blend_mode: BlendMode, opacity: f64) -> Color { +fn blend_node(input: (Color, Color), blend_mode: BlendMode, opacity: f32) -> Color { blend_colors(input.0, input.1, blend_mode, opacity as f32 / 100.) } @@ -470,8 +461,8 @@ pub struct VibranceNode { // Modified from https://stackoverflow.com/questions/33966121/what-is-the-algorithm-for-vibrance-filters // The results of this implementation are very close to correct, but not quite perfect #[node_macro::node_fn(VibranceNode)] -fn vibrance_node(color: Color, vibrance: f64) -> Color { - let vibrance = vibrance as f32 / 100.; +fn vibrance_node(color: Color, vibrance: f32) -> Color { + let vibrance = vibrance / 100.; // Slow the effect down by half when it's negative, since artifacts begin appearing past -50%. // So this scales the 0% to -50% range to 0% to -100%. let slowed_vibrance = if vibrance >= 0. { vibrance } else { vibrance * 0.5 }; @@ -562,22 +553,22 @@ pub struct ChannelMixerNode Color { let color = color.to_gamma_srgb(); @@ -699,42 +690,42 @@ pub struct SelectiveColorNode Color { let color = color.to_gamma_srgb(); @@ -784,7 +775,7 @@ fn selective_color_node( // Skip this color parameter group... // ...if it's unchanged from the default of zero offset on all CMYK paramters, or... // ...if this pixel's color isn't in the range affected by this color parameter group - if (c < f64::EPSILON && m < f64::EPSILON && y < f64::EPSILON && k < f64::EPSILON) || (!pixel_color_range(color_parameter_group)) { + if (c < f32::EPSILON && m < f32::EPSILON && y < f32::EPSILON && k < f32::EPSILON) || (!pixel_color_range(color_parameter_group)) { return acc; } @@ -816,7 +807,7 @@ pub struct OpacityNode { } #[node_macro::node_fn(OpacityNode)] -fn image_opacity(color: Color, opacity_multiplier: f64) -> Color { +fn image_opacity(color: Color, opacity_multiplier: f32) -> Color { let opacity_multiplier = opacity_multiplier as f32 / 100.; Color::from_rgbaf32_unchecked(color.r(), color.g(), color.b(), color.a() * opacity_multiplier) } @@ -829,7 +820,7 @@ pub struct PosterizeNode

{ // Based on http://www.axiomx.com/posterize.htm // This algorithm is perfectly accurate. #[node_macro::node_fn(PosterizeNode)] -fn posterize(color: Color, posterize_value: f64) -> Color { +fn posterize(color: Color, posterize_value: f32) -> Color { let color = color.to_gamma_srgb(); let posterize_value = posterize_value as f32; @@ -850,7 +841,7 @@ pub struct ExposureNode { // Based on https://geraldbakker.nl/psnumbers/exposure.html #[node_macro::node_fn(ExposureNode)] -fn exposure(color: Color, exposure: f64, offset: f64, gamma_correction: f64) -> Color { +fn exposure(color: Color, exposure: f32, offset: f32, gamma_correction: f32) -> Color { let adjusted = color // Exposure .map_rgb(|c: f32| c * 2_f32.powf(exposure as f32)) diff --git a/node-graph/gcore/src/raster/brush_cache.rs b/node-graph/gcore/src/raster/brush_cache.rs index f6002aca..eadb03c6 100644 --- a/node-graph/gcore/src/raster/brush_cache.rs +++ b/node-graph/gcore/src/raster/brush_cache.rs @@ -100,7 +100,6 @@ pub struct BrushPlan { } #[derive(Debug, DynAny, Default)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct BrushCache { inner: Arc>, proto: bool, diff --git a/node-graph/gcore/src/structural.rs b/node-graph/gcore/src/structural.rs index 273db245..ddaea936 100644 --- a/node-graph/gcore/src/structural.rs +++ b/node-graph/gcore/src/structural.rs @@ -1,8 +1,8 @@ use core::marker::PhantomData; -use crate::Node; +use crate::{Node, NodeMut}; -#[derive(Clone)] +#[derive(Clone, Copy)] pub struct ComposeNode { first: First, second: Second, @@ -21,12 +21,20 @@ where second.eval(arg) } } - -impl<'i, First, Second, Input: 'i> ComposeNode +impl<'i, 'f: 'i, 's: 'i, Input: 'i, First, Second> NodeMut<'i, Input> for ComposeNode where First: Node<'i, Input>, - Second: Node<'i, >::Output>, + Second: NodeMut<'i, >::Output> + 'i, { + type MutOutput = >::Output>>::MutOutput; + fn eval_mut(&'i mut self, input: Input) -> Self::MutOutput { + let arg = self.first.eval(input); + let second = &mut self.second; + second.eval_mut(arg) + } +} + +impl<'i, First, Second, Input: 'i> ComposeNode { pub const fn new(first: First, second: Second) -> Self { ComposeNode:: { first, second, phantom: PhantomData } } diff --git a/node-graph/gcore/src/text.rs b/node-graph/gcore/src/text.rs index 2bab0dd4..01f21689 100644 --- a/node-graph/gcore/src/text.rs +++ b/node-graph/gcore/src/text.rs @@ -15,7 +15,7 @@ pub struct TextGenerator { } #[node_fn(TextGenerator)] -fn generate_text<'a: 'input, T>(editor: EditorApi<'a, T>, text: String, font_name: Font, font_size: f64) -> crate::vector::VectorData { +fn generate_text<'a: 'input, T>(editor: EditorApi<'a, T>, text: String, font_name: Font, font_size: f32) -> crate::vector::VectorData { let buzz_face = editor.font_cache.get(&font_name).map(|data| load_face(data)); - crate::vector::VectorData::from_subpaths(to_path(&text, buzz_face, font_size, None)) + crate::vector::VectorData::from_subpaths(to_path(&text, buzz_face, font_size as f64, None)) } diff --git a/node-graph/gcore/src/transform.rs b/node-graph/gcore/src/transform.rs index 8d58cd08..b99955e1 100644 --- a/node-graph/gcore/src/transform.rs +++ b/node-graph/gcore/src/transform.rs @@ -78,10 +78,10 @@ pub struct TransformNode { } #[node_macro::node_fn(TransformNode)] -pub(crate) fn transform_vector_data(mut data: Data, translate: DVec2, rotate: f64, scale: DVec2, shear: DVec2, pivot: DVec2) -> Data { +pub(crate) fn transform_vector_data(mut data: Data, translate: DVec2, rotate: f32, scale: DVec2, shear: DVec2, pivot: DVec2) -> Data { let pivot = DAffine2::from_translation(data.local_pivot(pivot)); - let modification = pivot * DAffine2::from_scale_angle_translation(scale, rotate, translate) * DAffine2::from_cols_array(&[1., shear.y, shear.x, 1., 0., 0.]) * pivot.inverse(); + let modification = pivot * DAffine2::from_scale_angle_translation(scale, rotate as f64, translate) * DAffine2::from_cols_array(&[1., shear.y, shear.x, 1., 0., 0.]) * pivot.inverse(); let data_transform = data.transform_mut(); *data_transform = modification * (*data_transform); diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index be4d6473..be86ea51 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -53,21 +53,21 @@ pub struct SetStrokeNode, - weight: f64, + weight: f32, dash_lengths: Vec, - dash_offset: f64, + dash_offset: f32, line_cap: super::style::LineCap, line_join: super::style::LineJoin, - miter_limit: f64, + miter_limit: f32, ) -> VectorData { vector_data.style.set_stroke(Stroke { color, - weight, + weight: weight as f64, dash_lengths, - dash_offset, + dash_offset: dash_offset as f64, line_cap, line_join, - line_join_miter_limit: miter_limit, + line_join_miter_limit: miter_limit as f64, }); vector_data } diff --git a/node-graph/gpu-compiler/Cargo.lock b/node-graph/gpu-compiler/Cargo.lock index bcd97033..3ab216b0 100644 --- a/node-graph/gpu-compiler/Cargo.lock +++ b/node-graph/gpu-compiler/Cargo.lock @@ -597,7 +597,6 @@ dependencies = [ "bytemuck", "dyn-any", "glam", - "js-sys", "kurbo", "log", "node-macro", @@ -610,7 +609,6 @@ dependencies = [ "specta", "spin", "spirv-std", - "wasm-bindgen", "web-sys", ] diff --git a/node-graph/gpu-compiler/src/lib.rs b/node-graph/gpu-compiler/src/lib.rs index 5056f37a..89517645 100644 --- a/node-graph/gpu-compiler/src/lib.rs +++ b/node-graph/gpu-compiler/src/lib.rs @@ -121,7 +121,7 @@ impl SpirVCompiler for GpuCompiler { pub fn serialize_gpu(networks: &[ProtoNetwork], io: &ShaderIO) -> anyhow::Result { fn nid(id: &u64) -> String { - format!("n{id}") + format!("n{id:0x}") } dbg!(&io); @@ -151,13 +151,13 @@ pub fn serialize_gpu(networks: &[ProtoNetwork], io: &ShaderIO) -> anyhow::Result } for (i, id) in network.inputs.iter().enumerate() { let Some((_, node)) = network.nodes.iter().find(|(i, _)| i == id) else { - anyhow::bail!("Input node not found"); - }; + anyhow::bail!("Input node not found"); + }; let fqn = &node.identifier.name; let id = nid(id); let node = Node { id: id.clone(), - index: i, + index: i + 2, fqn: fqn.to_string().split('<').next().unwrap().to_owned(), args: node.construction_args.new_function_args(), }; @@ -202,7 +202,7 @@ pub fn serialize_gpu(networks: &[ProtoNetwork], io: &ShaderIO) -> anyhow::Result context.insert("input_nodes", &input_nodes); context.insert("output_nodes", &output_nodes); context.insert("nodes", &nodes); - context.insert("compute_threads", &64); + context.insert("compute_threads", "12, 8"); Ok(tera.render("spirv", &context)?) } @@ -215,9 +215,13 @@ pub fn compile(dir: &Path) -> Result { - pub shader: E::ShaderHandle, + pub shader: Arc, pub entry_point: String, - pub bind_group: Bindgroup, + pub bind_group: Arc>, pub output_buffer: Arc>, } +impl Clone for PipelineLayout { + fn clone(&self) -> Self { + Self { + shader: self.shader.clone(), + entry_point: self.entry_point.clone(), + bind_group: self.bind_group.clone(), + output_buffer: self.output_buffer.clone(), + } + } +} + unsafe impl StaticType for PipelineLayout where E::Static: GpuExecutor, @@ -457,9 +468,9 @@ pub struct CreatePipelineLayoutNode<_E, EntryPoint, Bindgroup, OutputBuffer> { #[node_macro::node_fn(CreatePipelineLayoutNode<_E>)] async fn create_pipeline_layout_node<_E: GpuExecutor>(shader: _E::ShaderHandle, entry_point: String, bind_group: Bindgroup<_E>, output_buffer: Arc>) -> PipelineLayout<_E> { PipelineLayout { - shader, + shader: shader.into(), entry_point, - bind_group, + bind_group: bind_group.into(), output_buffer, } } @@ -520,6 +531,7 @@ where #[node_macro::node_fn(RenderTextureNode)] async fn render_texture_node<'a: 'input, E: 'a + GpuExecutor>(image: ShaderInputFrame, surface: Arc>, executor: &'a E) -> SurfaceFrame { let surface_id = surface.surface_id; + log::trace!("rendering to surface {:?}", surface_id); executor.create_render_pass(image.shader_input, surface).unwrap(); diff --git a/node-graph/graph-craft/src/document.rs b/node-graph/graph-craft/src/document.rs index bb0d3298..9ce09b83 100644 --- a/node-graph/graph-craft/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -99,7 +99,7 @@ impl DocumentNode { document_node_path: self.path.unwrap_or(Vec::new()), } } else { - unreachable!("tried to resolve not flattened node on resolved node"); + unreachable!("tried to resolve not flattened node on resolved node {:?}", self); } } @@ -654,10 +654,13 @@ impl NodeNetwork { /// Recursively dissolve non-primitive document nodes and return a single flattened network of nodes. pub fn flatten_with_fns(&mut self, node: NodeId, map_ids: impl Fn(NodeId, NodeId) -> NodeId + Copy, gen_id: impl Fn() -> NodeId + Copy) { - let (id, mut node) = self + self.resolve_extract_nodes(); + let Some((id, mut node)) = self .nodes - .remove_entry(&node) - .unwrap_or_else(|| panic!("The node which was supposed to be flattened does not exist in the network, id {} network {:#?}", node, self)); + .remove_entry(&node) else { + warn!("The node which was supposed to be flattened does not exist in the network, id {} network {:#?}", node, self); + return; + }; if self.disabled.contains(&id) { node.implementation = DocumentNodeImplementation::Unresolved("graphene_core::ops::IdNode".into()); @@ -665,11 +668,12 @@ impl NodeNetwork { self.nodes.insert(id, node); return; } + log::debug!("Flattening node {:?}", &node.name); // replace value inputs with value nodes for input in &mut node.inputs { // Skip inputs that are already value nodes - if node.implementation == DocumentNodeImplementation::Unresolved("graphene_core::value::ValueNode".into()) { + if node.implementation == DocumentNodeImplementation::Unresolved("graphene_core::value::ClonedNode".into()) { break; } @@ -690,7 +694,7 @@ impl NodeNetwork { DocumentNode { name: "Value".into(), inputs: vec![NodeInput::Value { tagged_value, exposed }], - implementation: DocumentNodeImplementation::Unresolved("graphene_core::value::ValueNode".into()), + implementation: DocumentNodeImplementation::Unresolved("graphene_core::value::ClonedNode".into()), path, ..Default::default() }, @@ -706,6 +710,8 @@ impl NodeNetwork { } if let DocumentNodeImplementation::Network(mut inner_network) = node.implementation { + // Resolve all extract nodes in the inner network + inner_network.resolve_extract_nodes(); // Connect all network inputs to either the parent network nodes, or newly created value nodes. inner_network.map_ids(|inner_id| map_ids(id, inner_id)); let new_nodes = inner_network.nodes.keys().cloned().collect::>(); @@ -717,8 +723,10 @@ impl NodeNetwork { assert_eq!( node.inputs.len(), inner_network.inputs.len(), - "The number of inputs to the node and the inner network must be the same {}", - node.name + "The number of inputs to the node and the inner network must be the same for {}. The node has {:?} inputs, the network has {:?} inputs.", + node.name, + node.inputs, + inner_network.inputs ); // Match the document node input and the inputs of the inner network for (document_input, network_input) in node.inputs.into_iter().zip(inner_network.inputs.iter()) { @@ -829,21 +837,30 @@ impl NodeNetwork { self.nodes.retain(|_, node| !matches!(node.implementation, DocumentNodeImplementation::Extract)); for (_, node) in &mut extraction_nodes { + log::info!("extraction network: {:#?}", &self); if let DocumentNodeImplementation::Extract = node.implementation { assert_eq!(node.inputs.len(), 1); + log::debug!("Resolving extract node {:?}", node); let NodeInput::Node { node_id, output_index, .. } = node.inputs.pop().unwrap() else { - panic!("Extract node has no input"); + panic!("Extract node has no input, inputs: {:?}", node.inputs); }; assert_eq!(output_index, 0); // TODO: check if we can readd lambda checking let mut input_node = self.nodes.remove(&node_id).unwrap(); - node.implementation = DocumentNodeImplementation::Unresolved("graphene_core::value::ValueNode".into()); + node.implementation = DocumentNodeImplementation::Unresolved("graphene_core::value::ClonedNode".into()); + if let Some(input) = input_node.inputs.get_mut(0) { + *input = match &input { + NodeInput::Node { .. } => NodeInput::Network(generic!(T)), + ni => NodeInput::Network(ni.ty()), + }; + } + for input in input_node.inputs.iter_mut() { - match input { - NodeInput::Node { .. } | NodeInput::Value { .. } => *input = NodeInput::Network(generic!(T)), - _ => (), + if let NodeInput::Node { .. } = input { + *input = NodeInput::Network(generic!(T)) } } + log::debug!("Extract node {:?} resolved to {:?}", node, input_node); node.inputs = vec![NodeInput::value(TaggedValue::DocumentNode(input_node), false)]; } } @@ -1108,7 +1125,7 @@ mod test { tagged_value: TaggedValue::U32(2), exposed: false, }], - implementation: DocumentNodeImplementation::Unresolved("graphene_core::value::ValueNode".into()), + implementation: DocumentNodeImplementation::Unresolved("graphene_core::value::ClonedNode".into()), path: Some(vec![1, 4]), ..Default::default() }, diff --git a/node-graph/graph-craft/src/document/value.rs b/node-graph/graph-craft/src/document/value.rs index c2578ea4..de220d37 100644 --- a/node-graph/graph-craft/src/document/value.rs +++ b/node-graph/graph-craft/src/document/value.rs @@ -55,6 +55,7 @@ pub enum TaggedValue { ManipulatorGroupIds(Vec), Font(graphene_core::text::Font), BrushStrokes(Vec), + #[cfg_attr(feature = "serde", serde(skip))] BrushCache(BrushCache), Segments(Vec>), DocumentNode(DocumentNode), @@ -193,6 +194,7 @@ impl<'a> TaggedValue { TaggedValue::F64(x) => x.to_string() + "_f64", TaggedValue::Bool(x) => x.to_string(), TaggedValue::BlendMode(blend_mode) => "BlendMode::".to_string() + &blend_mode.to_string(), + TaggedValue::Color(color) => "graphene_core::Color::from_rgbaf32_unchecked(0.,0.,0.,1.)".to_string(), _ => panic!("Cannot convert to primitive string"), } } diff --git a/node-graph/graph-craft/src/graphene_compiler.rs b/node-graph/graph-craft/src/graphene_compiler.rs index fbdeb373..1b7e1156 100644 --- a/node-graph/graph-craft/src/graphene_compiler.rs +++ b/node-graph/graph-craft/src/graphene_compiler.rs @@ -9,13 +9,12 @@ pub struct Compiler {} impl Compiler { pub fn compile(&self, mut network: NodeNetwork, resolve_inputs: bool) -> impl Iterator { - let node_ids = network.nodes.keys().copied().collect::>(); println!("flattening"); + let node_ids = network.nodes.keys().copied().collect::>(); for id in node_ids { network.flatten(id); } network.remove_redundant_id_nodes(); - network.resolve_extract_nodes(); network.remove_dead_nodes(); let proto_networks = network.into_proto_networks(); proto_networks.map(move |mut proto_network| { diff --git a/node-graph/graph-craft/src/proto.rs b/node-graph/graph-craft/src/proto.rs index bdc8c017..1ae68082 100644 --- a/node-graph/graph-craft/src/proto.rs +++ b/node-graph/graph-craft/src/proto.rs @@ -20,10 +20,10 @@ pub type LocalFuture<'n, T> = Pin + 'n> pub type Any<'n> = Box + 'n>; pub type FutureAny<'n> = DynFuture<'n, Any<'n>>; pub type TypeErasedNode<'n> = dyn for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n; -pub type TypeErasedPinnedRef<'n> = Pin<&'n (dyn for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n)>; -pub type TypeErasedRef<'n> = &'n (dyn for<'i> NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n); -pub type TypeErasedBox<'n> = Box NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n>; -pub type TypeErasedPinned<'n> = Pin NodeIO<'i, Any<'i>, Output = FutureAny<'i>> + 'n>>; +pub type TypeErasedPinnedRef<'n> = Pin<&'n TypeErasedNode<'n>>; +pub type TypeErasedRef<'n> = &'n TypeErasedNode<'n>; +pub type TypeErasedBox<'n> = Box>; +pub type TypeErasedPinned<'n> = Pin>>; pub type NodeConstructor = for<'a> fn(Vec>) -> DynFuture<'static, TypeErasedBox<'static>>; @@ -181,7 +181,7 @@ impl Hash for ConstructionArgs { impl ConstructionArgs { pub fn new_function_args(&self) -> Vec { match self { - ConstructionArgs::Nodes(nodes) => nodes.iter().map(|n| format!("&n{}", n.0)).collect(), + ConstructionArgs::Nodes(nodes) => nodes.iter().map(|n| format!("n{:0x}", n.0)).collect(), ConstructionArgs::Value(value) => vec![value.to_primitive_string()], ConstructionArgs::Inline(inline) => vec![inline.expr.clone()], } @@ -248,7 +248,7 @@ impl ProtoNode { pub fn value(value: ConstructionArgs, path: Vec) -> Self { Self { - identifier: NodeIdentifier::new("graphene_core::value::ValueNode"), + identifier: NodeIdentifier::new("graphene_core::value::ClonedNode"), construction_args: value, input: ProtoNodeInput::None, document_node_path: path, diff --git a/node-graph/graphene-cli/Cargo.toml b/node-graph/graphene-cli/Cargo.toml new file mode 100644 index 00000000..e408ce3f --- /dev/null +++ b/node-graph/graphene-cli/Cargo.toml @@ -0,0 +1,62 @@ +[package] +name = "graphene-cli" +version = "0.1.0" +edition = "2021" +description = "CLI interface for the graphene language" +authors = ["Graphite Authors "] +license = "MIT OR Apache-2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +gpu = [ + "interpreted-executor/gpu", + "graphene-std/gpu", + "graphene-core/gpu", + "wgpu-executor", + "gpu-executor", +] +default = ["wgpu"] +wgpu = ["wgpu-executor", "gpu", "graphene-std/wgpu"] +wayland = ["graphene-std/wayland"] +profiling = ["wgpu-executor/profiling"] +passthrough = ["wgpu-executor/passthrough"] +quantization = ["graphene-std/quantization"] + + +[dependencies] +log = "0.4" +bitflags = "1.2.1" +serde = { version = "1.0", features = ["derive"] } +serde_json = { version = "1.0" } +bezier-rs = { path = "../../libraries/bezier-rs" } +glam = { version = "0.22", features = ["serde"] } + +# Node graph +graphene-std = { path = "../gstd" } +image = { version = "0.24", default-features = false, features = [ + "bmp", + "png", +] } +graph-craft = { path = "../graph-craft" } +wgpu-executor = { path = "../wgpu-executor", optional = true } +gpu-executor = { path = "../gpu-executor", optional = true } +interpreted-executor = { path = "../interpreted-executor" } +dyn-any = { path = "../../libraries/dyn-any" } +graphene-core = { path = "../gcore" } +future-executor = { path = "../future-executor", optional = true } + +wasm-bindgen = { version = "0.2.86", optional = true } +futures = "0.3.28" +fern = { version = "0.6.2", features = ["colored"] } +chrono = "0.4.26" +tokio = { version = "1.28.2", features = ["macros", "rt"] } +wgpu = "0.16.1" + +[dependencies.document-legacy] +path = "../../document-legacy" +package = "graphite-document-legacy" + +[dev-dependencies] +env_logger = "0.8.4" +test-case = "2.1" diff --git a/node-graph/graphene-cli/src/main.rs b/node-graph/graphene-cli/src/main.rs new file mode 100644 index 00000000..3abe3b5a --- /dev/null +++ b/node-graph/graphene-cli/src/main.rs @@ -0,0 +1,234 @@ +use fern::colors::{Color, ColoredLevelConfig}; +use std::{collections::HashMap, error::Error, sync::Arc}; + +use document_legacy::{ + document::Document, + layers::layer_info::{LayerData, LayerDataType}, +}; +use futures::executor::block_on; +use graph_craft::{ + concrete, + document::{value::TaggedValue, *}, + graphene_compiler::{Compiler, Executor}, + imaginate_input::ImaginatePreferences, + NodeIdentifier, Type, TypeDescriptor, +}; +use graphene_core::{ + application_io::{self, ApplicationIo, NodeGraphUpdateSender}, + raster::ImageFrame, + text::FontCache, + Cow, +}; +use graphene_std::wasm_application_io::{WasmApplicationIo, WasmEditorApi}; +use interpreted_executor::dynamic_executor::DynamicExecutor; + +struct UpdateLogger {} + +impl NodeGraphUpdateSender for UpdateLogger { + fn send(&self, message: graphene_core::application_io::NodeGraphUpdateMessage) { + println!("{:?}", message); + } +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + init_logging(); + + let document_path = std::env::args().nth(1).expect("No document path provided"); + + let image_path = std::env::args().nth(2); + + let document_string = std::fs::read_to_string(&document_path).expect("Failed to read document"); + + let executor = create_executor(document_string)?; + println!("creating gpu context",); + let mut application_io = block_on(WasmApplicationIo::new()); + if let Some(image_path) = image_path { + application_io.resources.insert("null".to_string(), Arc::from(std::fs::read(image_path).expect("Failed to read image"))); + } + + let device = application_io.gpu_executor().unwrap().context.device.clone(); + std::thread::spawn(move || loop { + std::thread::sleep(std::time::Duration::from_nanos(10)); + device.poll(wgpu::Maintain::Poll); + }); + + let editor_api = WasmEditorApi { + image_frame: None, + font_cache: &FontCache::default(), + application_io: &application_io, + node_graph_message_sender: &UpdateLogger {}, + imaginate_preferences: &ImaginatePreferences::default(), + }; + + loop { + //println!("executing"); + let result = (&executor).execute(editor_api.clone()).await?; + //println!("result: {:?}", result); + std::thread::sleep(std::time::Duration::from_millis(16)); + } + + Ok(()) +} + +fn init_logging() { + let colors = ColoredLevelConfig::new().debug(Color::Magenta).info(Color::Green).error(Color::Red); + fern::Dispatch::new() + .chain(std::io::stdout()) + .level_for("iced", log::LevelFilter::Trace) + .level_for("wgpu", log::LevelFilter::Debug) + .level(log::LevelFilter::Trace) + .format(move |out, message, record| { + out.finish(format_args!( + "[{}]{} {}", + // This will color the log level only, not the whole line. Just a touch. + colors.color(record.level()), + chrono::Utc::now().format("[%Y-%m-%d %H:%M:%S]"), + message + )) + }) + .apply() + .unwrap(); +} + +fn create_executor(document_string: String) -> Result> { + let document: serde_json::Value = serde_json::from_str(&document_string).expect("Failed to parse document"); + let document = serde_json::from_value::(document["document_legacy"].clone()).expect("Failed to parse document"); + let Some(LayerDataType::Layer(ref node_graph)) = document.root.iter().find(|layer| matches!(layer.data, LayerDataType::Layer(_))).map(|x|&x.data) else { panic!("failed to extract node graph from docmuent") }; + let network = &node_graph.network; + let wrapped_network = wrap_network_in_scope(network.clone()); + let compiler = Compiler {}; + let protograph = compiler.compile_single(wrapped_network, true)?; + let executor = block_on(DynamicExecutor::new(protograph))?; + Ok(executor) +} + +#[cfg(test)] +mod test { + use super::*; + + #[tokio::test] + #[cfg_attr(not(feature = "wayland"), ignore)] + async fn grays_scale() { + let document_string = include_str!("../test_files/gray.graphite"); + let executor = create_executor(document_string.to_string()).unwrap(); + let editor_api = WasmEditorApi { + image_frame: None, + font_cache: &FontCache::default(), + application_io: &block_on(WasmApplicationIo::new()), + node_graph_message_sender: &UpdateLogger {}, + imaginate_preferences: &ImaginatePreferences::default(), + }; + let result = (&executor).execute(editor_api.clone()).await.unwrap(); + println!("result: {:?}", result); + } + + #[tokio::test] + #[cfg_attr(not(feature = "wayland"), ignore)] + async fn hue() { + let document_string = include_str!("../test_files/hue.graphite"); + let executor = create_executor(document_string.to_string()).unwrap(); + let editor_api = WasmEditorApi { + image_frame: None, + font_cache: &FontCache::default(), + application_io: &block_on(WasmApplicationIo::new()), + node_graph_message_sender: &UpdateLogger {}, + imaginate_preferences: &ImaginatePreferences::default(), + }; + let result = (&executor).execute(editor_api.clone()).await.unwrap(); + println!("result: {:?}", result); + } +} + +pub fn wrap_network_in_scope(mut network: NodeNetwork) -> NodeNetwork { + let node_ids = network.nodes.keys().copied().collect::>(); + + network.generate_node_paths(&[]); + for id in node_ids { + network.flatten(id); + } + + let mut network_inputs = Vec::new(); + let mut input_type = None; + for (id, node) in network.nodes.iter() { + for input in node.inputs.iter() { + if let NodeInput::Network(_) = input { + if input_type.is_none() { + input_type = Some(input.clone()); + } + assert_eq!(input, input_type.as_ref().unwrap(), "Networks wrapped in scope must have the same input type"); + network_inputs.push(*id); + } + } + } + let len = network_inputs.len(); + network.inputs = network_inputs; + + // if the network has no inputs, it doesn't need to be wrapped in a scope + if len == 0 { + return network; + } + + let inner_network = DocumentNode { + name: "Scope".to_string(), + implementation: DocumentNodeImplementation::Network(network), + inputs: core::iter::repeat(NodeInput::node(0, 1)).take(len).collect(), + ..Default::default() + }; + + // wrap the inner network in a scope + let nodes = vec![ + begin_scope(), + inner_network, + DocumentNode { + name: "End Scope".to_string(), + implementation: DocumentNodeImplementation::proto("graphene_core::memo::EndLetNode<_>"), + inputs: vec![NodeInput::node(0, 0), NodeInput::node(1, 0)], + ..Default::default() + }, + ]; + NodeNetwork { + inputs: vec![0], + outputs: vec![NodeOutput::new(2, 0)], + nodes: nodes.into_iter().enumerate().map(|(id, node)| (id as NodeId, node)).collect(), + ..Default::default() + } +} + +fn begin_scope() -> DocumentNode { + DocumentNode { + name: "Begin Scope".to_string(), + implementation: DocumentNodeImplementation::Network(NodeNetwork { + inputs: vec![0], + outputs: vec![NodeOutput::new(1, 0), NodeOutput::new(2, 0)], + nodes: [ + DocumentNode { + name: "SetNode".to_string(), + inputs: vec![NodeInput::ShortCircut(concrete!(WasmEditorApi))], + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::SomeNode")), + ..Default::default() + }, + DocumentNode { + name: "LetNode".to_string(), + inputs: vec![NodeInput::node(0, 0)], + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::LetNode<_>")), + ..Default::default() + }, + DocumentNode { + name: "RefNode".to_string(), + inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::lambda(1, 0)], + implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::RefNode<_, _>")), + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .map(|(id, node)| (id as NodeId, node)) + .collect(), + + ..Default::default() + }), + inputs: vec![NodeInput::Network(concrete!(WasmEditorApi))], + ..Default::default() + } +} diff --git a/node-graph/graphene-cli/test_files/cat.jpg b/node-graph/graphene-cli/test_files/cat.jpg new file mode 100644 index 00000000..3f2e0d26 Binary files /dev/null and b/node-graph/graphene-cli/test_files/cat.jpg differ diff --git a/node-graph/graphene-cli/test_files/cow_transparent.png b/node-graph/graphene-cli/test_files/cow_transparent.png new file mode 100644 index 00000000..70f311cf Binary files /dev/null and b/node-graph/graphene-cli/test_files/cow_transparent.png differ diff --git a/node-graph/graphene-cli/test_files/duck.jpg b/node-graph/graphene-cli/test_files/duck.jpg new file mode 100644 index 00000000..a8af5090 Binary files /dev/null and b/node-graph/graphene-cli/test_files/duck.jpg differ diff --git a/node-graph/graphene-cli/test_files/football.jpg b/node-graph/graphene-cli/test_files/football.jpg new file mode 100644 index 00000000..05fdfb64 Binary files /dev/null and b/node-graph/graphene-cli/test_files/football.jpg differ diff --git a/node-graph/graphene-cli/test_files/gray.graphite b/node-graph/graphene-cli/test_files/gray.graphite new file mode 100644 index 00000000..ce4cccde --- /dev/null +++ b/node-graph/graphene-cli/test_files/gray.graphite @@ -0,0 +1,1329 @@ +{ + "document_legacy": { + "root": { + "visible": true, + "name": null, + "data": { + "Folder": { + "next_assignment_id": 4489767774157203372, + "layer_ids": [ + 4489767774157203371 + ], + "layers": [ + { + "visible": true, + "name": null, + "data": { + "Layer": { + "network": { + "inputs": [], + "outputs": [ + { + "node_id": 3, + "node_output_index": 0 + } + ], + "nodes": { + "5624267029878925495": { + "name": "GpuImage", + "inputs": [ + { + "Node": { + "node_id": 1, + "output_index": 0, + "lambda": false + } + }, + { + "Node": { + "node_id": 7287024673900605762, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::executor::MapGpuSingleImageNode<_>" + } + }, + "metadata": { + "position": [ + 27, + 4 + ] + }, + "path": null + }, + "3": { + "name": "Output", + "inputs": [ + { + "Node": { + "node_id": 11144230787879644735, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 49, + 4 + ] + }, + "path": null + }, + "11144230787879644735": { + "name": "RenderTexture", + "inputs": [ + { + "Node": { + "node_id": 8006866457842175788, + "output_index": 0, + "lambda": false + } + }, + { + "Node": { + "node_id": 13282494292107396350, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 1, + 1, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "1": { + "name": "Render Texture", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "gpu_executor::ShaderInputFrame", + "size": 56, + "align": 8 + } + } + }, + { + "Network": { + "Concrete": { + "name": "alloc::sync::Arc>", + "size": 4, + "align": 4 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::RenderTextureNode<_, _>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "0": { + "name": "Extract Executor", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IntoNode<_, &WgpuExecutor>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 42, + 4 + ] + }, + "path": null + }, + "2037214651900404495": { + "name": "Grayscale", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "Color": { + "red": 0.0, + "green": 0.0, + "blue": 0.0, + "alpha": 1.0 + } + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 40.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 60.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 40.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 60.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 20.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 80.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 5 + ] + }, + "path": null + }, + "10587777034180159163": { + "name": "Hue/Saturation", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 20.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::HueSaturationNode<_, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 6 + ] + }, + "path": null + }, + "13282494292107396350": { + "name": "CreateGpuSurface", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Create Gpu Surface", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::CreateGpuSurfaceNode" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "1": { + "name": "Cache", + "inputs": [ + { + "ShortCircut": { + "Concrete": { + "name": "()", + "size": 0, + "align": 1 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::memo::MemoNode<_, _>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 32, + 5 + ] + }, + "path": null + }, + "5830922276166168539": { + "name": "Identity", + "inputs": [ + { + "Value": { + "tagged_value": "None", + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + }, + "7451453699006996668": { + "name": "Vibrance", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 57.672 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::VibranceNode<_>" + } + }, + "metadata": { + "position": [ + 8, + 9 + ] + }, + "path": null + }, + "7287024673900605762": { + "name": "Extract", + "inputs": [ + { + "Node": { + "node_id": 2037214651900404495, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": "Extract", + "metadata": { + "position": [ + 16, + 6 + ] + }, + "path": null + }, + "7980892639443901364": { + "name": "Invert RGB", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::InvertRGBNode" + } + }, + "metadata": { + "position": [ + 8, + 7 + ] + }, + "path": null + }, + "16497589343611227601": { + "name": "Load Image", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + }, + { + "Value": { + "tagged_value": { + "String": "graphite:null" + }, + "exposed": false + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 0, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Load Resource", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + }, + { + "Network": { + "Concrete": { + "name": "alloc::string::String", + "size": 12, + "align": 4 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::wasm_application_io::LoadResourceNode<_>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "1": { + "name": "Decode Image", + "inputs": [ + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::wasm_application_io::DecodeImageNode" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 5, + 1 + ] + }, + "path": null + }, + "18254980474364940368": { + "name": "Memoize", + "inputs": [ + { + "Value": { + "tagged_value": "None", + "exposed": false + } + }, + { + "Node": { + "node_id": 16497589343611227601, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::memo::MemoNode<_, _>" + } + }, + "metadata": { + "position": [ + 13, + 1 + ] + }, + "path": null + }, + "13651929780047367852": { + "name": "Levels", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 12.6984 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 32.9806 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 86.7725 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 100.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::LevelsNode<_, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 8 + ] + }, + "path": null + }, + "1": { + "name": "Transform", + "inputs": [ + { + "Node": { + "node_id": 18254980474364940368, + "output_index": 0, + "lambda": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 880.6764305713131, + 368.44115971583955 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 843.2940793504903, + 632.4705595128677 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 0.0, + 0.0 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 0.5, + 0.5 + ] + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::transform::TransformNode<_, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 21, + 2 + ] + }, + "path": null + }, + "8006866457842175788": { + "name": "UploadTexture", + "inputs": [ + { + "Node": { + "node_id": 5624267029878925495, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 1, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "1": { + "name": "Upload Texture", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::raster::image::ImageFrame", + "size": 72, + "align": 8 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::UploadTextureNode<_>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "0": { + "name": "Extract Executor", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IntoNode<_, &WgpuExecutor>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 35, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + } + }, + "transform": { + "matrix2": [ + 843.2940793504903, + 0.0, + 0.0, + 632.4705595128677 + ], + "translation": [ + 459.5293908960679, + 52.705879959405706 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + } + ] + } + }, + "transform": { + "matrix2": [ + 0.44995911033081615, + 0.0, + 0.0, + 0.44995911033081615 + ], + "translation": [ + -54.99999999999994, + 228.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + }, + "document_network": { + "inputs": [], + "outputs": [ + { + "node_id": 0, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Output", + "inputs": [ + { + "Value": { + "tagged_value": { + "GraphicGroup": [] + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "saved_document_identifier": 11707807670791570700, + "auto_saved_document_identifier": 2974151965283546860, + "name": "hue_no_cache.graphite", + "version": "0.0.16", + "document_mode": "DesignMode", + "view_mode": "Normal", + "snapping_enabled": true, + "overlays_visible": true, + "layer_metadata": [ + [ + [], + { + "selected": false, + "expanded": true + } + ], + [ + [ + 4489767774157203371 + ], + { + "selected": true, + "expanded": false + } + ] + ], + "layer_range_selection_reference": [ + 4489767774157203371 + ], + "navigation_handler": { + "pan": [ + -1186.1884042415631, + -667.5946688108043 + ], + "panning": false, + "snap_tilt": false, + "snap_tilt_released": false, + "tilt": 0.0, + "tilting": false, + "zoom": 0.44995911033081615, + "zooming": false, + "snap_zoom": false, + "mouse_position": [ + 0.0, + 0.0 + ] + }, + "artboard_message_handler": { + "artboards_document": { + "root": { + "visible": true, + "name": null, + "data": { + "Folder": { + "next_assignment_id": 17819678939779928469, + "layer_ids": [ + 17819678939779928468 + ], + "layers": [ + { + "visible": true, + "name": null, + "data": { + "Shape": { + "shape": { + "elements": [ + { + "points": [ + { + "position": [ + 0.0, + 0.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 0.0, + 1.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 1.0, + 1.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 1.0, + 0.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + null, + null, + null + ] + } + ], + "element_ids": [ + 1, + 2, + 3, + 4, + 5 + ], + "next_id": 5 + }, + "style": { + "stroke": null, + "fill": { + "Solid": { + "red": 1.0, + "green": 1.0, + "blue": 1.0, + "alpha": 1.0 + } + } + }, + "render_index": 1 + } + }, + "transform": { + "matrix2": [ + 1920.0, + 0.0, + -0.0, + 1080.0 + ], + "translation": [ + 0.0, + 0.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + } + ] + } + }, + "transform": { + "matrix2": [ + 0.44995911033081615, + 0.0, + 0.0, + 0.44995911033081615 + ], + "translation": [ + -54.99999999999994, + 228.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + }, + "document_network": { + "inputs": [], + "outputs": [ + { + "node_id": 0, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Output", + "inputs": [ + { + "Value": { + "tagged_value": { + "GraphicGroup": [] + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "artboard_ids": [ + 17819678939779928468 + ] + }, + "properties_panel_message_handler": { + "active_selection": [ + [ + 4489767774157203371 + ], + "Artwork" + ] + } +} diff --git a/node-graph/graphene-cli/test_files/hue.graphite b/node-graph/graphene-cli/test_files/hue.graphite new file mode 100644 index 00000000..90201b37 --- /dev/null +++ b/node-graph/graphene-cli/test_files/hue.graphite @@ -0,0 +1,1329 @@ +{ + "document_legacy": { + "root": { + "visible": true, + "name": null, + "data": { + "Folder": { + "next_assignment_id": 4489767774157203372, + "layer_ids": [ + 4489767774157203371 + ], + "layers": [ + { + "visible": true, + "name": null, + "data": { + "Layer": { + "network": { + "inputs": [], + "outputs": [ + { + "node_id": 3, + "node_output_index": 0 + } + ], + "nodes": { + "5624267029878925495": { + "name": "GpuImage", + "inputs": [ + { + "Node": { + "node_id": 1, + "output_index": 0, + "lambda": false + } + }, + { + "Node": { + "node_id": 7287024673900605762, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::executor::MapGpuSingleImageNode<_>" + } + }, + "metadata": { + "position": [ + 27, + 4 + ] + }, + "path": null + }, + "3": { + "name": "Output", + "inputs": [ + { + "Node": { + "node_id": 11144230787879644735, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 49, + 4 + ] + }, + "path": null + }, + "11144230787879644735": { + "name": "RenderTexture", + "inputs": [ + { + "Node": { + "node_id": 8006866457842175788, + "output_index": 0, + "lambda": false + } + }, + { + "Node": { + "node_id": 13282494292107396350, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 1, + 1, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "1": { + "name": "Render Texture", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "gpu_executor::ShaderInputFrame", + "size": 56, + "align": 8 + } + } + }, + { + "Network": { + "Concrete": { + "name": "alloc::sync::Arc>", + "size": 4, + "align": 4 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::RenderTextureNode<_, _>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "0": { + "name": "Extract Executor", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IntoNode<_, &WgpuExecutor>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 42, + 4 + ] + }, + "path": null + }, + "2037214651900404495": { + "name": "Grayscale", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "Color": { + "red": 0.0, + "green": 0.0, + "blue": 0.0, + "alpha": 1.0 + } + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 40.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 60.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 40.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 60.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 20.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 80.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 5 + ] + }, + "path": null + }, + "10587777034180159163": { + "name": "Hue/Saturation", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 20.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::HueSaturationNode<_, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 6 + ] + }, + "path": null + }, + "13282494292107396350": { + "name": "CreateGpuSurface", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Create Gpu Surface", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::CreateGpuSurfaceNode" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "1": { + "name": "Cache", + "inputs": [ + { + "ShortCircut": { + "Concrete": { + "name": "()", + "size": 0, + "align": 1 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::memo::MemoNode<_, _>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 32, + 5 + ] + }, + "path": null + }, + "5830922276166168539": { + "name": "Identity", + "inputs": [ + { + "Value": { + "tagged_value": "None", + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + }, + "7451453699006996668": { + "name": "Vibrance", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 57.672 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::VibranceNode<_>" + } + }, + "metadata": { + "position": [ + 8, + 9 + ] + }, + "path": null + }, + "7287024673900605762": { + "name": "Extract", + "inputs": [ + { + "Node": { + "node_id": 10587777034180159163, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": "Extract", + "metadata": { + "position": [ + 16, + 6 + ] + }, + "path": null + }, + "7980892639443901364": { + "name": "Invert RGB", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::InvertRGBNode" + } + }, + "metadata": { + "position": [ + 8, + 7 + ] + }, + "path": null + }, + "16497589343611227601": { + "name": "Load Image", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + }, + { + "Value": { + "tagged_value": { + "String": "graphite:null" + }, + "exposed": false + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 0, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Load Resource", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + }, + { + "Network": { + "Concrete": { + "name": "alloc::string::String", + "size": 12, + "align": 4 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::wasm_application_io::LoadResourceNode<_>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "1": { + "name": "Decode Image", + "inputs": [ + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::wasm_application_io::DecodeImageNode" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 5, + 1 + ] + }, + "path": null + }, + "18254980474364940368": { + "name": "Memoize", + "inputs": [ + { + "Value": { + "tagged_value": "None", + "exposed": false + } + }, + { + "Node": { + "node_id": 16497589343611227601, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::memo::MemoNode<_, _>" + } + }, + "metadata": { + "position": [ + 13, + 1 + ] + }, + "path": null + }, + "13651929780047367852": { + "name": "Levels", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 12.6984 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 32.9806 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 86.7725 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 100.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::LevelsNode<_, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 8 + ] + }, + "path": null + }, + "1": { + "name": "Transform", + "inputs": [ + { + "Node": { + "node_id": 18254980474364940368, + "output_index": 0, + "lambda": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 880.6764305713131, + 368.44115971583955 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 843.2940793504903, + 632.4705595128677 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 0.0, + 0.0 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 0.5, + 0.5 + ] + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::transform::TransformNode<_, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 21, + 2 + ] + }, + "path": null + }, + "8006866457842175788": { + "name": "UploadTexture", + "inputs": [ + { + "Node": { + "node_id": 5624267029878925495, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 1, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "1": { + "name": "Upload Texture", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::raster::image::ImageFrame", + "size": 72, + "align": 8 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::UploadTextureNode<_>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "0": { + "name": "Extract Executor", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IntoNode<_, &WgpuExecutor>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 35, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + } + }, + "transform": { + "matrix2": [ + 843.2940793504903, + 0.0, + 0.0, + 632.4705595128677 + ], + "translation": [ + 459.5293908960679, + 52.705879959405706 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + } + ] + } + }, + "transform": { + "matrix2": [ + 0.44995911033081615, + 0.0, + 0.0, + 0.44995911033081615 + ], + "translation": [ + -54.99999999999994, + 228.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + }, + "document_network": { + "inputs": [], + "outputs": [ + { + "node_id": 0, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Output", + "inputs": [ + { + "Value": { + "tagged_value": { + "GraphicGroup": [] + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "saved_document_identifier": 4964327076847783748, + "auto_saved_document_identifier": 11707807670791570700, + "name": "hue_no_cache.graphite", + "version": "0.0.16", + "document_mode": "DesignMode", + "view_mode": "Normal", + "snapping_enabled": true, + "overlays_visible": true, + "layer_metadata": [ + [ + [], + { + "selected": false, + "expanded": true + } + ], + [ + [ + 4489767774157203371 + ], + { + "selected": true, + "expanded": false + } + ] + ], + "layer_range_selection_reference": [ + 4489767774157203371 + ], + "navigation_handler": { + "pan": [ + -1186.1884042415631, + -667.5946688108043 + ], + "panning": false, + "snap_tilt": false, + "snap_tilt_released": false, + "tilt": 0.0, + "tilting": false, + "zoom": 0.44995911033081615, + "zooming": false, + "snap_zoom": false, + "mouse_position": [ + 0.0, + 0.0 + ] + }, + "artboard_message_handler": { + "artboards_document": { + "root": { + "visible": true, + "name": null, + "data": { + "Folder": { + "next_assignment_id": 17819678939779928469, + "layer_ids": [ + 17819678939779928468 + ], + "layers": [ + { + "visible": true, + "name": null, + "data": { + "Shape": { + "shape": { + "elements": [ + { + "points": [ + { + "position": [ + 0.0, + 0.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 0.0, + 1.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 1.0, + 1.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 1.0, + 0.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + null, + null, + null + ] + } + ], + "element_ids": [ + 1, + 2, + 3, + 4, + 5 + ], + "next_id": 5 + }, + "style": { + "stroke": null, + "fill": { + "Solid": { + "red": 1.0, + "green": 1.0, + "blue": 1.0, + "alpha": 1.0 + } + } + }, + "render_index": 1 + } + }, + "transform": { + "matrix2": [ + 1920.0, + 0.0, + -0.0, + 1080.0 + ], + "translation": [ + 0.0, + 0.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + } + ] + } + }, + "transform": { + "matrix2": [ + 0.44995911033081615, + 0.0, + 0.0, + 0.44995911033081615 + ], + "translation": [ + -54.99999999999994, + 228.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + }, + "document_network": { + "inputs": [], + "outputs": [ + { + "node_id": 0, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Output", + "inputs": [ + { + "Value": { + "tagged_value": { + "GraphicGroup": [] + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "artboard_ids": [ + 17819678939779928468 + ] + }, + "properties_panel_message_handler": { + "active_selection": [ + [ + 4489767774157203371 + ], + "Artwork" + ] + } +} diff --git a/node-graph/graphene-cli/test_files/id.graphite b/node-graph/graphene-cli/test_files/id.graphite new file mode 100644 index 00000000..72e261ae --- /dev/null +++ b/node-graph/graphene-cli/test_files/id.graphite @@ -0,0 +1,1329 @@ +{ + "document_legacy": { + "root": { + "visible": true, + "name": null, + "data": { + "Folder": { + "next_assignment_id": 4489767774157203372, + "layer_ids": [ + 4489767774157203371 + ], + "layers": [ + { + "visible": true, + "name": null, + "data": { + "Layer": { + "network": { + "inputs": [], + "outputs": [ + { + "node_id": 3, + "node_output_index": 0 + } + ], + "nodes": { + "5624267029878925495": { + "name": "GpuImage", + "inputs": [ + { + "Node": { + "node_id": 1, + "output_index": 0, + "lambda": false + } + }, + { + "Node": { + "node_id": 7287024673900605762, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::executor::MapGpuSingleImageNode<_>" + } + }, + "metadata": { + "position": [ + 27, + 4 + ] + }, + "path": null + }, + "3": { + "name": "Output", + "inputs": [ + { + "Node": { + "node_id": 11144230787879644735, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 49, + 4 + ] + }, + "path": null + }, + "11144230787879644735": { + "name": "RenderTexture", + "inputs": [ + { + "Node": { + "node_id": 8006866457842175788, + "output_index": 0, + "lambda": false + } + }, + { + "Node": { + "node_id": 13282494292107396350, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 1, + 1, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "1": { + "name": "Render Texture", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "gpu_executor::ShaderInputFrame", + "size": 56, + "align": 8 + } + } + }, + { + "Network": { + "Concrete": { + "name": "alloc::sync::Arc>", + "size": 4, + "align": 4 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::RenderTextureNode<_, _>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "0": { + "name": "Extract Executor", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IntoNode<_, &WgpuExecutor>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 42, + 4 + ] + }, + "path": null + }, + "2037214651900404495": { + "name": "Grayscale", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "Color": { + "red": 0.0, + "green": 0.0, + "blue": 0.0, + "alpha": 1.0 + } + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 40.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 60.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 40.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 60.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 20.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 80.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 5 + ] + }, + "path": null + }, + "10587777034180159163": { + "name": "Hue/Saturation", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 20.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::HueSaturationNode<_, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 6 + ] + }, + "path": null + }, + "13282494292107396350": { + "name": "CreateGpuSurface", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Create Gpu Surface", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::CreateGpuSurfaceNode" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "1": { + "name": "Cache", + "inputs": [ + { + "ShortCircut": { + "Concrete": { + "name": "()", + "size": 0, + "align": 1 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::memo::MemoNode<_, _>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 32, + 5 + ] + }, + "path": null + }, + "5830922276166168539": { + "name": "Identity", + "inputs": [ + { + "Value": { + "tagged_value": "None", + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + }, + "7451453699006996668": { + "name": "Vibrance", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 57.672 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::VibranceNode<_>" + } + }, + "metadata": { + "position": [ + 8, + 9 + ] + }, + "path": null + }, + "7287024673900605762": { + "name": "Extract", + "inputs": [ + { + "Node": { + "node_id": 5830922276166168539, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": "Extract", + "metadata": { + "position": [ + 16, + 6 + ] + }, + "path": null + }, + "7980892639443901364": { + "name": "Invert RGB", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::InvertRGBNode" + } + }, + "metadata": { + "position": [ + 8, + 7 + ] + }, + "path": null + }, + "16497589343611227601": { + "name": "Load Image", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + }, + { + "Value": { + "tagged_value": { + "String": "graphite:null" + }, + "exposed": false + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 0, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Load Resource", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + }, + { + "Network": { + "Concrete": { + "name": "alloc::string::String", + "size": 12, + "align": 4 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::wasm_application_io::LoadResourceNode<_>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "1": { + "name": "Decode Image", + "inputs": [ + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::wasm_application_io::DecodeImageNode" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 5, + 1 + ] + }, + "path": null + }, + "18254980474364940368": { + "name": "Memoize", + "inputs": [ + { + "Value": { + "tagged_value": "None", + "exposed": false + } + }, + { + "Node": { + "node_id": 16497589343611227601, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::memo::MemoNode<_, _>" + } + }, + "metadata": { + "position": [ + 13, + 1 + ] + }, + "path": null + }, + "13651929780047367852": { + "name": "Levels", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 12.6984 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 32.9806 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 86.7725 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 100.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::LevelsNode<_, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 8 + ] + }, + "path": null + }, + "1": { + "name": "Transform", + "inputs": [ + { + "Node": { + "node_id": 18254980474364940368, + "output_index": 0, + "lambda": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 880.6764305713131, + 368.44115971583955 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 843.2940793504903, + 632.4705595128677 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 0.0, + 0.0 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 0.5, + 0.5 + ] + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::transform::TransformNode<_, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 21, + 2 + ] + }, + "path": null + }, + "8006866457842175788": { + "name": "UploadTexture", + "inputs": [ + { + "Node": { + "node_id": 5624267029878925495, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 1, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "1": { + "name": "Upload Texture", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::raster::image::ImageFrame", + "size": 72, + "align": 8 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::UploadTextureNode<_>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "0": { + "name": "Extract Executor", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IntoNode<_, &WgpuExecutor>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 35, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + } + }, + "transform": { + "matrix2": [ + 843.2940793504903, + 0.0, + 0.0, + 632.4705595128677 + ], + "translation": [ + 459.5293908960679, + 52.705879959405706 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + } + ] + } + }, + "transform": { + "matrix2": [ + 0.44995911033081615, + 0.0, + 0.0, + 0.44995911033081615 + ], + "translation": [ + -54.99999999999994, + 228.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + }, + "document_network": { + "inputs": [], + "outputs": [ + { + "node_id": 0, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Output", + "inputs": [ + { + "Value": { + "tagged_value": { + "GraphicGroup": [] + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "saved_document_identifier": 2974151965283546860, + "auto_saved_document_identifier": 0, + "name": "hue_no_cache.graphite", + "version": "0.0.16", + "document_mode": "DesignMode", + "view_mode": "Normal", + "snapping_enabled": true, + "overlays_visible": true, + "layer_metadata": [ + [ + [], + { + "selected": false, + "expanded": true + } + ], + [ + [ + 4489767774157203371 + ], + { + "selected": true, + "expanded": false + } + ] + ], + "layer_range_selection_reference": [ + 4489767774157203371 + ], + "navigation_handler": { + "pan": [ + -1186.1884042415631, + -667.5946688108043 + ], + "panning": false, + "snap_tilt": false, + "snap_tilt_released": false, + "tilt": 0.0, + "tilting": false, + "zoom": 0.44995911033081615, + "zooming": false, + "snap_zoom": false, + "mouse_position": [ + 0.0, + 0.0 + ] + }, + "artboard_message_handler": { + "artboards_document": { + "root": { + "visible": true, + "name": null, + "data": { + "Folder": { + "next_assignment_id": 17819678939779928469, + "layer_ids": [ + 17819678939779928468 + ], + "layers": [ + { + "visible": true, + "name": null, + "data": { + "Shape": { + "shape": { + "elements": [ + { + "points": [ + { + "position": [ + 0.0, + 0.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 0.0, + 1.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 1.0, + 1.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 1.0, + 0.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + null, + null, + null + ] + } + ], + "element_ids": [ + 1, + 2, + 3, + 4, + 5 + ], + "next_id": 5 + }, + "style": { + "stroke": null, + "fill": { + "Solid": { + "red": 1.0, + "green": 1.0, + "blue": 1.0, + "alpha": 1.0 + } + } + }, + "render_index": 1 + } + }, + "transform": { + "matrix2": [ + 1920.0, + 0.0, + -0.0, + 1080.0 + ], + "translation": [ + 0.0, + 0.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + } + ] + } + }, + "transform": { + "matrix2": [ + 0.44995911033081615, + 0.0, + 0.0, + 0.44995911033081615 + ], + "translation": [ + -54.99999999999994, + 228.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + }, + "document_network": { + "inputs": [], + "outputs": [ + { + "node_id": 0, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Output", + "inputs": [ + { + "Value": { + "tagged_value": { + "GraphicGroup": [] + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "artboard_ids": [ + 17819678939779928468 + ] + }, + "properties_panel_message_handler": { + "active_selection": [ + [ + 4489767774157203371 + ], + "Artwork" + ] + } +} diff --git a/node-graph/graphene-cli/test_files/invert.graphite b/node-graph/graphene-cli/test_files/invert.graphite new file mode 100644 index 00000000..8e44fbf1 --- /dev/null +++ b/node-graph/graphene-cli/test_files/invert.graphite @@ -0,0 +1,1329 @@ +{ + "document_legacy": { + "root": { + "visible": true, + "name": null, + "data": { + "Folder": { + "next_assignment_id": 4489767774157203372, + "layer_ids": [ + 4489767774157203371 + ], + "layers": [ + { + "visible": true, + "name": null, + "data": { + "Layer": { + "network": { + "inputs": [], + "outputs": [ + { + "node_id": 3, + "node_output_index": 0 + } + ], + "nodes": { + "5624267029878925495": { + "name": "GpuImage", + "inputs": [ + { + "Node": { + "node_id": 1, + "output_index": 0, + "lambda": false + } + }, + { + "Node": { + "node_id": 7287024673900605762, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::executor::MapGpuSingleImageNode<_>" + } + }, + "metadata": { + "position": [ + 27, + 4 + ] + }, + "path": null + }, + "3": { + "name": "Output", + "inputs": [ + { + "Node": { + "node_id": 11144230787879644735, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 49, + 4 + ] + }, + "path": null + }, + "11144230787879644735": { + "name": "RenderTexture", + "inputs": [ + { + "Node": { + "node_id": 8006866457842175788, + "output_index": 0, + "lambda": false + } + }, + { + "Node": { + "node_id": 13282494292107396350, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 1, + 1, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "1": { + "name": "Render Texture", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "gpu_executor::ShaderInputFrame", + "size": 56, + "align": 8 + } + } + }, + { + "Network": { + "Concrete": { + "name": "alloc::sync::Arc>", + "size": 4, + "align": 4 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::RenderTextureNode<_, _>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "0": { + "name": "Extract Executor", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IntoNode<_, &WgpuExecutor>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 42, + 4 + ] + }, + "path": null + }, + "2037214651900404495": { + "name": "Grayscale", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "Color": { + "red": 0.0, + "green": 0.0, + "blue": 0.0, + "alpha": 1.0 + } + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 40.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 60.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 40.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 60.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 20.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 80.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 5 + ] + }, + "path": null + }, + "10587777034180159163": { + "name": "Hue/Saturation", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 20.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::HueSaturationNode<_, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 6 + ] + }, + "path": null + }, + "13282494292107396350": { + "name": "CreateGpuSurface", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Create Gpu Surface", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::CreateGpuSurfaceNode" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "1": { + "name": "Cache", + "inputs": [ + { + "ShortCircut": { + "Concrete": { + "name": "()", + "size": 0, + "align": 1 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::memo::MemoNode<_, _>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 32, + 5 + ] + }, + "path": null + }, + "5830922276166168539": { + "name": "Identity", + "inputs": [ + { + "Value": { + "tagged_value": "None", + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + }, + "7451453699006996668": { + "name": "Vibrance", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 57.672 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::VibranceNode<_>" + } + }, + "metadata": { + "position": [ + 8, + 9 + ] + }, + "path": null + }, + "7287024673900605762": { + "name": "Extract", + "inputs": [ + { + "Node": { + "node_id": 7980892639443901364, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": "Extract", + "metadata": { + "position": [ + 16, + 6 + ] + }, + "path": null + }, + "7980892639443901364": { + "name": "Invert RGB", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::InvertRGBNode" + } + }, + "metadata": { + "position": [ + 8, + 7 + ] + }, + "path": null + }, + "16497589343611227601": { + "name": "Load Image", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + }, + { + "Value": { + "tagged_value": { + "String": "graphite:null" + }, + "exposed": false + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 0, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Load Resource", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + }, + { + "Network": { + "Concrete": { + "name": "alloc::string::String", + "size": 12, + "align": 4 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::wasm_application_io::LoadResourceNode<_>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "1": { + "name": "Decode Image", + "inputs": [ + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::wasm_application_io::DecodeImageNode" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 5, + 1 + ] + }, + "path": null + }, + "18254980474364940368": { + "name": "Memoize", + "inputs": [ + { + "Value": { + "tagged_value": "None", + "exposed": false + } + }, + { + "Node": { + "node_id": 16497589343611227601, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::memo::MemoNode<_, _>" + } + }, + "metadata": { + "position": [ + 13, + 1 + ] + }, + "path": null + }, + "13651929780047367852": { + "name": "Levels", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 12.6984 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 32.9806 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 86.7725 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 100.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::LevelsNode<_, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 8 + ] + }, + "path": null + }, + "1": { + "name": "Transform", + "inputs": [ + { + "Node": { + "node_id": 18254980474364940368, + "output_index": 0, + "lambda": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 880.6764305713131, + 368.44115971583955 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 843.2940793504903, + 632.4705595128677 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 0.0, + 0.0 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 0.5, + 0.5 + ] + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::transform::TransformNode<_, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 21, + 2 + ] + }, + "path": null + }, + "8006866457842175788": { + "name": "UploadTexture", + "inputs": [ + { + "Node": { + "node_id": 5624267029878925495, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 1, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "1": { + "name": "Upload Texture", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::raster::image::ImageFrame", + "size": 72, + "align": 8 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::UploadTextureNode<_>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "0": { + "name": "Extract Executor", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IntoNode<_, &WgpuExecutor>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 35, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + } + }, + "transform": { + "matrix2": [ + 843.2940793504903, + 0.0, + 0.0, + 632.4705595128677 + ], + "translation": [ + 459.5293908960679, + 52.705879959405706 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + } + ] + } + }, + "transform": { + "matrix2": [ + 0.44995911033081615, + 0.0, + 0.0, + 0.44995911033081615 + ], + "translation": [ + -54.99999999999994, + 228.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + }, + "document_network": { + "inputs": [], + "outputs": [ + { + "node_id": 0, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Output", + "inputs": [ + { + "Value": { + "tagged_value": { + "GraphicGroup": [] + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "saved_document_identifier": 16230223273732637430, + "auto_saved_document_identifier": 4964327076847783748, + "name": "hue_no_cache.graphite", + "version": "0.0.16", + "document_mode": "DesignMode", + "view_mode": "Normal", + "snapping_enabled": true, + "overlays_visible": true, + "layer_metadata": [ + [ + [], + { + "selected": false, + "expanded": true + } + ], + [ + [ + 4489767774157203371 + ], + { + "selected": true, + "expanded": false + } + ] + ], + "layer_range_selection_reference": [ + 4489767774157203371 + ], + "navigation_handler": { + "pan": [ + -1186.1884042415631, + -667.5946688108043 + ], + "panning": false, + "snap_tilt": false, + "snap_tilt_released": false, + "tilt": 0.0, + "tilting": false, + "zoom": 0.44995911033081615, + "zooming": false, + "snap_zoom": false, + "mouse_position": [ + 0.0, + 0.0 + ] + }, + "artboard_message_handler": { + "artboards_document": { + "root": { + "visible": true, + "name": null, + "data": { + "Folder": { + "next_assignment_id": 17819678939779928469, + "layer_ids": [ + 17819678939779928468 + ], + "layers": [ + { + "visible": true, + "name": null, + "data": { + "Shape": { + "shape": { + "elements": [ + { + "points": [ + { + "position": [ + 0.0, + 0.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 0.0, + 1.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 1.0, + 1.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 1.0, + 0.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + null, + null, + null + ] + } + ], + "element_ids": [ + 1, + 2, + 3, + 4, + 5 + ], + "next_id": 5 + }, + "style": { + "stroke": null, + "fill": { + "Solid": { + "red": 1.0, + "green": 1.0, + "blue": 1.0, + "alpha": 1.0 + } + } + }, + "render_index": 1 + } + }, + "transform": { + "matrix2": [ + 1920.0, + 0.0, + -0.0, + 1080.0 + ], + "translation": [ + 0.0, + 0.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + } + ] + } + }, + "transform": { + "matrix2": [ + 0.44995911033081615, + 0.0, + 0.0, + 0.44995911033081615 + ], + "translation": [ + -54.99999999999994, + 228.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + }, + "document_network": { + "inputs": [], + "outputs": [ + { + "node_id": 0, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Output", + "inputs": [ + { + "Value": { + "tagged_value": { + "GraphicGroup": [] + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "artboard_ids": [ + 17819678939779928468 + ] + }, + "properties_panel_message_handler": { + "active_selection": [ + [ + 4489767774157203371 + ], + "Artwork" + ] + } +} diff --git a/node-graph/graphene-cli/test_files/levels.graphite b/node-graph/graphene-cli/test_files/levels.graphite new file mode 100644 index 00000000..95c50e31 --- /dev/null +++ b/node-graph/graphene-cli/test_files/levels.graphite @@ -0,0 +1,1329 @@ +{ + "document_legacy": { + "root": { + "visible": true, + "name": null, + "data": { + "Folder": { + "next_assignment_id": 4489767774157203372, + "layer_ids": [ + 4489767774157203371 + ], + "layers": [ + { + "visible": true, + "name": null, + "data": { + "Layer": { + "network": { + "inputs": [], + "outputs": [ + { + "node_id": 3, + "node_output_index": 0 + } + ], + "nodes": { + "5624267029878925495": { + "name": "GpuImage", + "inputs": [ + { + "Node": { + "node_id": 1, + "output_index": 0, + "lambda": false + } + }, + { + "Node": { + "node_id": 7287024673900605762, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::executor::MapGpuSingleImageNode<_>" + } + }, + "metadata": { + "position": [ + 27, + 4 + ] + }, + "path": null + }, + "3": { + "name": "Output", + "inputs": [ + { + "Node": { + "node_id": 11144230787879644735, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 49, + 4 + ] + }, + "path": null + }, + "11144230787879644735": { + "name": "RenderTexture", + "inputs": [ + { + "Node": { + "node_id": 8006866457842175788, + "output_index": 0, + "lambda": false + } + }, + { + "Node": { + "node_id": 13282494292107396350, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 1, + 1, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "1": { + "name": "Render Texture", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "gpu_executor::ShaderInputFrame", + "size": 56, + "align": 8 + } + } + }, + { + "Network": { + "Concrete": { + "name": "alloc::sync::Arc>", + "size": 4, + "align": 4 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::RenderTextureNode<_, _>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "0": { + "name": "Extract Executor", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IntoNode<_, &WgpuExecutor>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 42, + 4 + ] + }, + "path": null + }, + "2037214651900404495": { + "name": "Grayscale", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "Color": { + "red": 0.0, + "green": 0.0, + "blue": 0.0, + "alpha": 1.0 + } + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 40.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 60.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 40.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 60.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 20.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 80.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 5 + ] + }, + "path": null + }, + "10587777034180159163": { + "name": "Hue/Saturation", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 20.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::HueSaturationNode<_, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 6 + ] + }, + "path": null + }, + "13282494292107396350": { + "name": "CreateGpuSurface", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Create Gpu Surface", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::CreateGpuSurfaceNode" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "1": { + "name": "Cache", + "inputs": [ + { + "ShortCircut": { + "Concrete": { + "name": "()", + "size": 0, + "align": 1 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::memo::MemoNode<_, _>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 32, + 5 + ] + }, + "path": null + }, + "5830922276166168539": { + "name": "Identity", + "inputs": [ + { + "Value": { + "tagged_value": "None", + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + }, + "7451453699006996668": { + "name": "Vibrance", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 57.672 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::VibranceNode<_>" + } + }, + "metadata": { + "position": [ + 8, + 9 + ] + }, + "path": null + }, + "7287024673900605762": { + "name": "Extract", + "inputs": [ + { + "Node": { + "node_id": 13651929780047367852, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": "Extract", + "metadata": { + "position": [ + 16, + 6 + ] + }, + "path": null + }, + "7980892639443901364": { + "name": "Invert RGB", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::InvertRGBNode" + } + }, + "metadata": { + "position": [ + 8, + 7 + ] + }, + "path": null + }, + "16497589343611227601": { + "name": "Load Image", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + }, + { + "Value": { + "tagged_value": { + "String": "graphite:null" + }, + "exposed": false + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 0, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Load Resource", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + }, + { + "Network": { + "Concrete": { + "name": "alloc::string::String", + "size": 12, + "align": 4 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::wasm_application_io::LoadResourceNode<_>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "1": { + "name": "Decode Image", + "inputs": [ + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::wasm_application_io::DecodeImageNode" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 5, + 1 + ] + }, + "path": null + }, + "18254980474364940368": { + "name": "Memoize", + "inputs": [ + { + "Value": { + "tagged_value": "None", + "exposed": false + } + }, + { + "Node": { + "node_id": 16497589343611227601, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::memo::MemoNode<_, _>" + } + }, + "metadata": { + "position": [ + 13, + 1 + ] + }, + "path": null + }, + "13651929780047367852": { + "name": "Levels", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 12.6984 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 32.9806 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 86.7725 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 100.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::LevelsNode<_, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 8 + ] + }, + "path": null + }, + "1": { + "name": "Transform", + "inputs": [ + { + "Node": { + "node_id": 18254980474364940368, + "output_index": 0, + "lambda": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 880.6764305713131, + 368.44115971583955 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 843.2940793504903, + 632.4705595128677 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 0.0, + 0.0 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 0.5, + 0.5 + ] + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::transform::TransformNode<_, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 21, + 2 + ] + }, + "path": null + }, + "8006866457842175788": { + "name": "UploadTexture", + "inputs": [ + { + "Node": { + "node_id": 5624267029878925495, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 1, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "1": { + "name": "Upload Texture", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::raster::image::ImageFrame", + "size": 72, + "align": 8 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::UploadTextureNode<_>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "0": { + "name": "Extract Executor", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IntoNode<_, &WgpuExecutor>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 35, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + } + }, + "transform": { + "matrix2": [ + 843.2940793504903, + 0.0, + 0.0, + 632.4705595128677 + ], + "translation": [ + 459.5293908960679, + 52.705879959405706 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + } + ] + } + }, + "transform": { + "matrix2": [ + 0.44995911033081615, + 0.0, + 0.0, + 0.44995911033081615 + ], + "translation": [ + -54.99999999999994, + 228.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + }, + "document_network": { + "inputs": [], + "outputs": [ + { + "node_id": 0, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Output", + "inputs": [ + { + "Value": { + "tagged_value": { + "GraphicGroup": [] + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "saved_document_identifier": 17372779026958210523, + "auto_saved_document_identifier": 16230223273732637430, + "name": "hue_no_cache.graphite", + "version": "0.0.16", + "document_mode": "DesignMode", + "view_mode": "Normal", + "snapping_enabled": true, + "overlays_visible": true, + "layer_metadata": [ + [ + [], + { + "selected": false, + "expanded": true + } + ], + [ + [ + 4489767774157203371 + ], + { + "selected": true, + "expanded": false + } + ] + ], + "layer_range_selection_reference": [ + 4489767774157203371 + ], + "navigation_handler": { + "pan": [ + -1186.1884042415631, + -667.5946688108043 + ], + "panning": false, + "snap_tilt": false, + "snap_tilt_released": false, + "tilt": 0.0, + "tilting": false, + "zoom": 0.44995911033081615, + "zooming": false, + "snap_zoom": false, + "mouse_position": [ + 0.0, + 0.0 + ] + }, + "artboard_message_handler": { + "artboards_document": { + "root": { + "visible": true, + "name": null, + "data": { + "Folder": { + "next_assignment_id": 17819678939779928469, + "layer_ids": [ + 17819678939779928468 + ], + "layers": [ + { + "visible": true, + "name": null, + "data": { + "Shape": { + "shape": { + "elements": [ + { + "points": [ + { + "position": [ + 0.0, + 0.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 0.0, + 1.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 1.0, + 1.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 1.0, + 0.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + null, + null, + null + ] + } + ], + "element_ids": [ + 1, + 2, + 3, + 4, + 5 + ], + "next_id": 5 + }, + "style": { + "stroke": null, + "fill": { + "Solid": { + "red": 1.0, + "green": 1.0, + "blue": 1.0, + "alpha": 1.0 + } + } + }, + "render_index": 1 + } + }, + "transform": { + "matrix2": [ + 1920.0, + 0.0, + -0.0, + 1080.0 + ], + "translation": [ + 0.0, + 0.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + } + ] + } + }, + "transform": { + "matrix2": [ + 0.44995911033081615, + 0.0, + 0.0, + 0.44995911033081615 + ], + "translation": [ + -54.99999999999994, + 228.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + }, + "document_network": { + "inputs": [], + "outputs": [ + { + "node_id": 0, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Output", + "inputs": [ + { + "Value": { + "tagged_value": { + "GraphicGroup": [] + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "artboard_ids": [ + 17819678939779928468 + ] + }, + "properties_panel_message_handler": { + "active_selection": [ + [ + 4489767774157203371 + ], + "Artwork" + ] + } +} diff --git a/node-graph/graphene-cli/test_files/mansion.jpg b/node-graph/graphene-cli/test_files/mansion.jpg new file mode 100644 index 00000000..395722e9 Binary files /dev/null and b/node-graph/graphene-cli/test_files/mansion.jpg differ diff --git a/node-graph/graphene-cli/test_files/paper.jpg b/node-graph/graphene-cli/test_files/paper.jpg new file mode 100644 index 00000000..7ade4950 Binary files /dev/null and b/node-graph/graphene-cli/test_files/paper.jpg differ diff --git a/node-graph/graphene-cli/test_files/pizza.jpg b/node-graph/graphene-cli/test_files/pizza.jpg new file mode 100644 index 00000000..b8ac0c96 Binary files /dev/null and b/node-graph/graphene-cli/test_files/pizza.jpg differ diff --git a/node-graph/graphene-cli/test_files/pizza_transparent.png b/node-graph/graphene-cli/test_files/pizza_transparent.png new file mode 100644 index 00000000..2eb2b1d4 Binary files /dev/null and b/node-graph/graphene-cli/test_files/pizza_transparent.png differ diff --git a/node-graph/graphene-cli/test_files/vibrance.graphite b/node-graph/graphene-cli/test_files/vibrance.graphite new file mode 100644 index 00000000..715f8070 --- /dev/null +++ b/node-graph/graphene-cli/test_files/vibrance.graphite @@ -0,0 +1,1329 @@ +{ + "document_legacy": { + "root": { + "visible": true, + "name": null, + "data": { + "Folder": { + "next_assignment_id": 4489767774157203372, + "layer_ids": [ + 4489767774157203371 + ], + "layers": [ + { + "visible": true, + "name": null, + "data": { + "Layer": { + "network": { + "inputs": [], + "outputs": [ + { + "node_id": 3, + "node_output_index": 0 + } + ], + "nodes": { + "5624267029878925495": { + "name": "GpuImage", + "inputs": [ + { + "Node": { + "node_id": 1, + "output_index": 0, + "lambda": false + } + }, + { + "Node": { + "node_id": 7287024673900605762, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::executor::MapGpuSingleImageNode<_>" + } + }, + "metadata": { + "position": [ + 27, + 4 + ] + }, + "path": null + }, + "3": { + "name": "Output", + "inputs": [ + { + "Node": { + "node_id": 11144230787879644735, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 49, + 4 + ] + }, + "path": null + }, + "11144230787879644735": { + "name": "RenderTexture", + "inputs": [ + { + "Node": { + "node_id": 8006866457842175788, + "output_index": 0, + "lambda": false + } + }, + { + "Node": { + "node_id": 13282494292107396350, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 1, + 1, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "1": { + "name": "Render Texture", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "gpu_executor::ShaderInputFrame", + "size": 56, + "align": 8 + } + } + }, + { + "Network": { + "Concrete": { + "name": "alloc::sync::Arc>", + "size": 4, + "align": 4 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::RenderTextureNode<_, _>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "0": { + "name": "Extract Executor", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IntoNode<_, &WgpuExecutor>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 42, + 4 + ] + }, + "path": null + }, + "2037214651900404495": { + "name": "Grayscale", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "Color": { + "red": 0.0, + "green": 0.0, + "blue": 0.0, + "alpha": 1.0 + } + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 40.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 60.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 40.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 60.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 20.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 80.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 5 + ] + }, + "path": null + }, + "10587777034180159163": { + "name": "Hue/Saturation", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 20.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::HueSaturationNode<_, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 6 + ] + }, + "path": null + }, + "13282494292107396350": { + "name": "CreateGpuSurface", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Create Gpu Surface", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::CreateGpuSurfaceNode" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "1": { + "name": "Cache", + "inputs": [ + { + "ShortCircut": { + "Concrete": { + "name": "()", + "size": 0, + "align": 1 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::memo::MemoNode<_, _>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 32, + 5 + ] + }, + "path": null + }, + "5830922276166168539": { + "name": "Identity", + "inputs": [ + { + "Value": { + "tagged_value": "None", + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + }, + "7451453699006996668": { + "name": "Vibrance", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 57.672 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::VibranceNode<_>" + } + }, + "metadata": { + "position": [ + 8, + 9 + ] + }, + "path": null + }, + "7287024673900605762": { + "name": "Extract", + "inputs": [ + { + "Node": { + "node_id": 7451453699006996668, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": "Extract", + "metadata": { + "position": [ + 16, + 6 + ] + }, + "path": null + }, + "7980892639443901364": { + "name": "Invert RGB", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::InvertRGBNode" + } + }, + "metadata": { + "position": [ + 8, + 7 + ] + }, + "path": null + }, + "16497589343611227601": { + "name": "Load Image", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + }, + { + "Value": { + "tagged_value": { + "String": "graphite:null" + }, + "exposed": false + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 0, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Load Resource", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + }, + { + "Network": { + "Concrete": { + "name": "alloc::string::String", + "size": 12, + "align": 4 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::wasm_application_io::LoadResourceNode<_>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "1": { + "name": "Decode Image", + "inputs": [ + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_std::wasm_application_io::DecodeImageNode" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 5, + 1 + ] + }, + "path": null + }, + "18254980474364940368": { + "name": "Memoize", + "inputs": [ + { + "Value": { + "tagged_value": "None", + "exposed": false + } + }, + { + "Node": { + "node_id": 16497589343611227601, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::memo::MemoNode<_, _>" + } + }, + "metadata": { + "position": [ + 13, + 1 + ] + }, + "path": null + }, + "13651929780047367852": { + "name": "Levels", + "inputs": [ + { + "Value": { + "tagged_value": { + "ImageFrame": { + "image": { + "width": 0, + "height": 0, + "data": "" + }, + "transform": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + } + }, + "exposed": true + } + }, + { + "Value": { + "tagged_value": { + "F32": 12.6984 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 32.9806 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 86.7725 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 100.0 + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::raster::LevelsNode<_, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 8, + 8 + ] + }, + "path": null + }, + "1": { + "name": "Transform", + "inputs": [ + { + "Node": { + "node_id": 18254980474364940368, + "output_index": 0, + "lambda": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 880.6764305713131, + 368.44115971583955 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "F32": 0.0 + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 843.2940793504903, + 632.4705595128677 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 0.0, + 0.0 + ] + }, + "exposed": false + } + }, + { + "Value": { + "tagged_value": { + "DVec2": [ + 0.5, + 0.5 + ] + }, + "exposed": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::transform::TransformNode<_, _, _, _, _>" + } + }, + "metadata": { + "position": [ + 21, + 2 + ] + }, + "path": null + }, + "8006866457842175788": { + "name": "UploadTexture", + "inputs": [ + { + "Node": { + "node_id": 5624267029878925495, + "output_index": 0, + "lambda": false + } + }, + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Network": { + "inputs": [ + 1, + 0 + ], + "outputs": [ + { + "node_id": 1, + "node_output_index": 0 + } + ], + "nodes": { + "1": { + "name": "Upload Texture", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::raster::image::ImageFrame", + "size": 72, + "align": 8 + } + } + }, + { + "Node": { + "node_id": 0, + "output_index": 0, + "lambda": false + } + } + ], + "implementation": { + "Unresolved": { + "name": "gpu_executor::UploadTextureNode<_>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + }, + "0": { + "name": "Extract Executor", + "inputs": [ + { + "Network": { + "Concrete": { + "name": "graphene_core::application_io::EditorApi", + "size": 96, + "align": 8 + } + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IntoNode<_, &WgpuExecutor>" + } + }, + "metadata": { + "position": [ + 0, + 0 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "metadata": { + "position": [ + 35, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + } + }, + "transform": { + "matrix2": [ + 843.2940793504903, + 0.0, + 0.0, + 632.4705595128677 + ], + "translation": [ + 459.5293908960679, + 52.705879959405706 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + } + ] + } + }, + "transform": { + "matrix2": [ + 0.44995911033081615, + 0.0, + 0.0, + 0.44995911033081615 + ], + "translation": [ + -54.99999999999994, + 228.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + }, + "document_network": { + "inputs": [], + "outputs": [ + { + "node_id": 0, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Output", + "inputs": [ + { + "Value": { + "tagged_value": { + "GraphicGroup": [] + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "saved_document_identifier": 3155036688339849220, + "auto_saved_document_identifier": 17372779026958210523, + "name": "hue_no_cache.graphite", + "version": "0.0.16", + "document_mode": "DesignMode", + "view_mode": "Normal", + "snapping_enabled": true, + "overlays_visible": true, + "layer_metadata": [ + [ + [], + { + "selected": false, + "expanded": true + } + ], + [ + [ + 4489767774157203371 + ], + { + "selected": true, + "expanded": false + } + ] + ], + "layer_range_selection_reference": [ + 4489767774157203371 + ], + "navigation_handler": { + "pan": [ + -1186.1884042415631, + -667.5946688108043 + ], + "panning": false, + "snap_tilt": false, + "snap_tilt_released": false, + "tilt": 0.0, + "tilting": false, + "zoom": 0.44995911033081615, + "zooming": false, + "snap_zoom": false, + "mouse_position": [ + 0.0, + 0.0 + ] + }, + "artboard_message_handler": { + "artboards_document": { + "root": { + "visible": true, + "name": null, + "data": { + "Folder": { + "next_assignment_id": 17819678939779928469, + "layer_ids": [ + 17819678939779928468 + ], + "layers": [ + { + "visible": true, + "name": null, + "data": { + "Shape": { + "shape": { + "elements": [ + { + "points": [ + { + "position": [ + 0.0, + 0.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 0.0, + 1.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 1.0, + 1.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + { + "position": [ + 1.0, + 0.0 + ], + "manipulator_type": "Anchor" + }, + null, + null + ] + }, + { + "points": [ + null, + null, + null + ] + } + ], + "element_ids": [ + 1, + 2, + 3, + 4, + 5 + ], + "next_id": 5 + }, + "style": { + "stroke": null, + "fill": { + "Solid": { + "red": 1.0, + "green": 1.0, + "blue": 1.0, + "alpha": 1.0 + } + } + }, + "render_index": 1 + } + }, + "transform": { + "matrix2": [ + 1920.0, + 0.0, + -0.0, + 1080.0 + ], + "translation": [ + 0.0, + 0.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + } + ] + } + }, + "transform": { + "matrix2": [ + 0.44995911033081615, + 0.0, + 0.0, + 0.44995911033081615 + ], + "translation": [ + -54.99999999999994, + 228.0 + ] + }, + "preserve_aspect": true, + "pivot": [ + 0.5, + 0.5 + ], + "blend_mode": "Normal", + "opacity": 1.0 + }, + "document_network": { + "inputs": [], + "outputs": [ + { + "node_id": 0, + "node_output_index": 0 + } + ], + "nodes": { + "0": { + "name": "Output", + "inputs": [ + { + "Value": { + "tagged_value": { + "GraphicGroup": [] + }, + "exposed": true + } + } + ], + "implementation": { + "Unresolved": { + "name": "graphene_core::ops::IdNode" + } + }, + "metadata": { + "position": [ + 8, + 4 + ] + }, + "path": null + } + }, + "disabled": [], + "previous_outputs": null + } + }, + "artboard_ids": [ + 17819678939779928468 + ] + }, + "properties_panel_message_handler": { + "active_selection": [ + [ + 4489767774157203371 + ], + "Artwork" + ] + } +} diff --git a/node-graph/gstd/Cargo.toml b/node-graph/gstd/Cargo.toml index c92cf7b6..4fe39a42 100644 --- a/node-graph/gstd/Cargo.toml +++ b/node-graph/gstd/Cargo.toml @@ -21,7 +21,7 @@ wgpu = ["gpu", "wgpu-executor"] quantization = ["autoquant"] wasm = ["wasm-bindgen", "web-sys", "js-sys"] imaginate = ["image/png", "base64", "js-sys", "web-sys", "wasm-bindgen-futures"] - +wayland = [] [dependencies] autoquant = { git = "https://github.com/truedoctor/autoquant", optional = true, features = [ @@ -42,7 +42,7 @@ gpu-compiler-bin-wrapper = { path = "../gpu-compiler/gpu-compiler-bin-wrapper", compilation-client = { path = "../compilation-client", optional = true } bytemuck = { version = "1.8" } tempfile = "3" -image = { version = "*", default-features = false } +image = { version = "*", default-features = false, features = ["png", "jpeg"] } base64 = { version = "0.21", optional = true } dyn-clone = "1.0" @@ -62,6 +62,9 @@ js-sys = { version = "0.3.63", optional = true } wgpu-types = "0.16.0" wgpu = "0.16.1" wasm-bindgen-futures = { version = "0.4.36", optional = true } +winit = "0.28.6" +url = "2.4.0" +tokio = { version = "1.29.0", optional = true, features = ["fs", "io-std"] } [dependencies.serde] version = "1.0" diff --git a/node-graph/gstd/src/gpu_nodes.rs b/node-graph/gstd/src/gpu_nodes.rs index 3b18a4da..87caa3ce 100644 --- a/node-graph/gstd/src/gpu_nodes.rs +++ b/node-graph/gstd/src/gpu_nodes.rs @@ -1,13 +1,17 @@ +use dyn_any::{StaticType, StaticTypeSized}; use glam::{DAffine2, DVec2, Mat2, Vec2}; use gpu_executor::{Bindgroup, ComputePassDimensions, PipelineLayout, StorageBufferOptions}; use gpu_executor::{GpuExecutor, ShaderIO, ShaderInput}; use graph_craft::document::value::TaggedValue; use graph_craft::document::*; use graph_craft::proto::*; +use graphene_core::quantization::{PackedPixel, QuantizationChannels}; use graphene_core::raster::*; use graphene_core::*; use wgpu_executor::WgpuExecutor; +use std::cell::RefCell; +use std::collections::HashMap; use std::sync::Arc; use crate::wasm_application_io::WasmApplicationIo; @@ -42,18 +46,110 @@ async fn compile_gpu(node: &'input DocumentNode, mut typing_context: TypingConte pub struct MapGpuNode { node: Node, editor_api: EditorApi, + cache: RefCell>>, } -#[node_macro::node_fn(MapGpuNode)] +struct ComputePass { + pipeline_layout: PipelineLayout, + readback_buffer: Option>>, +} + +impl Clone for ComputePass { + fn clone(&self) -> Self { + Self { + pipeline_layout: self.pipeline_layout.clone(), + readback_buffer: self.readback_buffer.clone(), + } + } +} + +#[node_macro::node_impl(MapGpuNode)] async fn map_gpu<'a: 'input>(image: ImageFrame, node: DocumentNode, editor_api: graphene_core::application_io::EditorApi<'a, WasmApplicationIo>) -> ImageFrame { log::debug!("Executing gpu node"); + let executor = &editor_api.application_io.gpu_executor.as_ref().unwrap(); + + #[cfg(feature = "quantization")] + let quantization = crate::quantization::generate_quantization_from_image_frame(&image); + #[cfg(not(feature = "quantization"))] + let quantization = QuantizationChannels::default(); + log::debug!("quantization: {:?}", quantization); + + #[cfg(feature = "quantization")] + let image = ImageFrame { + image: Image { + data: image.image.data.iter().map(|c| quantization::quantize_color(*c, quantization)).collect(), + width: image.image.width, + height: image.image.height, + }, + transform: image.transform, + }; + // TODO: The cache should be based on the network topology not the node name + let compute_pass_descriptor = if self.cache.borrow().contains_key(&node.name) { + self.cache.borrow().get(&node.name).unwrap().clone() + } else { + let name = node.name.clone(); + let compute_pass_descriptor = create_compute_pass_descriptor(node, &image, executor, quantization).await; + self.cache.borrow_mut().insert(name, compute_pass_descriptor.clone()); + log::error!("created compute pass"); + compute_pass_descriptor + }; + + let compute_pass = executor + .create_compute_pass( + &compute_pass_descriptor.pipeline_layout, + compute_pass_descriptor.readback_buffer.clone(), + ComputePassDimensions::XY(image.image.width / 12 + 1, image.image.height / 8 + 1), + ) + .unwrap(); + executor.execute_compute_pipeline(compute_pass).unwrap(); + log::debug!("executed pipeline"); + log::debug!("reading buffer"); + let result = executor.read_output_buffer(compute_pass_descriptor.readback_buffer.clone().unwrap()).await.unwrap(); + #[cfg(feature = "quantization")] + let colors = bytemuck::pod_collect_to_vec::(result.as_slice()); + #[cfg(feature = "quantization")] + log::debug!("first color: {:b}", colors[0].0); + #[cfg(feature = "quantization")] + let colors: Vec<_> = colors.iter().map(|c| quantization::dequantize_color(*c, quantization)).collect(); + #[cfg(not(feature = "quantization"))] + let colors = bytemuck::pod_collect_to_vec::(result.as_slice()); + log::debug!("first color: {:?}", colors[0]); + ImageFrame { + image: Image { + data: colors, + width: image.image.width, + height: image.image.height, + }, + transform: image.transform, + } +} + +impl MapGpuNode { + pub fn new(node: Node, editor_api: EditorApi) -> Self { + Self { + node, + editor_api, + cache: RefCell::new(HashMap::new()), + } + } +} + +async fn create_compute_pass_descriptor( + node: DocumentNode, + image: &ImageFrame, + executor: &&WgpuExecutor, + quantization: QuantizationChannels, +) -> ComputePass { let compiler = graph_craft::graphene_compiler::Compiler {}; let inner_network = NodeNetwork::value_network(node); log::debug!("inner_network: {:?}", inner_network); let network = NodeNetwork { - inputs: vec![], //vec![0, 1], - outputs: vec![NodeOutput::new(1, 0)], + inputs: vec![2, 1], //vec![0, 1], + #[cfg(feature = "quantization")] + outputs: vec![NodeOutput::new(5, 0)], + #[cfg(not(feature = "quantization"))] + outputs: vec![NodeOutput::new(3, 0)], nodes: [ DocumentNode { name: "Slice".into(), @@ -61,6 +157,18 @@ async fn map_gpu<'a: 'input>(image: ImageFrame, node: DocumentNode, edito implementation: DocumentNodeImplementation::Unresolved("graphene_core::value::CopiedNode".into()), ..Default::default() }, + DocumentNode { + name: "Quantization".into(), + inputs: vec![NodeInput::Network(concrete!(quantization::Quantization))], + implementation: DocumentNodeImplementation::Unresolved("graphene_core::ops::IdNode".into()), + ..Default::default() + }, + DocumentNode { + name: "Width".into(), + inputs: vec![NodeInput::Network(concrete!(u32))], + implementation: DocumentNodeImplementation::Unresolved("graphene_core::ops::IdNode".into()), + ..Default::default() + }, /*DocumentNode { name: "Index".into(), //inputs: vec![NodeInput::Network(concrete!(UVec3))], @@ -68,30 +176,48 @@ async fn map_gpu<'a: 'input>(image: ImageFrame, node: DocumentNode, edito implementation: DocumentNodeImplementation::Unresolved("graphene_core::value::CopiedNode".into()), ..Default::default() },*/ - /* + /* DocumentNode { name: "GetNode".into(), inputs: vec![NodeInput::node(1, 0), NodeInput::node(0, 0)], implementation: DocumentNodeImplementation::Unresolved("graphene_core::storage::GetNode".into()), ..Default::default() },*/ + #[cfg(feature = "quantization")] + DocumentNode { + name: "Dequantize".into(), + inputs: vec![NodeInput::node(0, 0), NodeInput::node(1, 0)], + implementation: DocumentNodeImplementation::proto("graphene_core::quantization::DeQuantizeNode"), + ..Default::default() + }, DocumentNode { name: "MapNode".into(), + #[cfg(feature = "quantization")] + inputs: vec![NodeInput::node(3, 0)], + #[cfg(not(feature = "quantization"))] inputs: vec![NodeInput::node(0, 0)], implementation: DocumentNodeImplementation::Network(inner_network), ..Default::default() }, + #[cfg(feature = "quantization")] + DocumentNode { + name: "Quantize".into(), + inputs: vec![NodeInput::node(4, 0), NodeInput::node(1, 0)], + implementation: DocumentNodeImplementation::proto("graphene_core::quantization::QuantizeNode"), + ..Default::default() + }, /* DocumentNode { name: "SaveNode".into(), inputs: vec![ - //NodeInput::node(0, 0), + NodeInput::node(5, 0), NodeInput::Inline(InlineRust::new( - "o0[_global_index.x as usize] = i0[_global_index.x as usize]".into(), - Type::Fn(Box::new(concrete!(Color)), Box::new(concrete!(()))), + "|x| o0[(_global_index.y * i1 + _global_index.x) as usize] = x".into(), + //"|x|()".into(), + Type::Fn(Box::new(concrete!(PackedPixel)), Box::new(concrete!(()))), )), ], - implementation: DocumentNodeImplementation::Unresolved("graphene_core::value::ValueNode".into()), + implementation: DocumentNodeImplementation::Unresolved("graphene_core::generic::FnMutNode".into()), ..Default::default() }, */ @@ -110,12 +236,23 @@ async fn map_gpu<'a: 'input>(image: ImageFrame, node: DocumentNode, edito vec![concrete!(u32), concrete!(Color)], //, concrete!(u32)], vec![concrete!(Color)], ShaderIO { + #[cfg(feature = "quantization")] + inputs: vec![ + ShaderInput::UniformBuffer((), concrete!(u32)), + ShaderInput::StorageBuffer((), concrete!(PackedPixel)), + ShaderInput::UniformBuffer((), concrete!(quantization::QuantizationChannels)), + //ShaderInput::Constant(gpu_executor::GPUConstant::GlobalInvocationId), + ShaderInput::OutputBuffer((), concrete!(PackedPixel)), + ], + #[cfg(not(feature = "quantization"))] inputs: vec![ ShaderInput::UniformBuffer((), concrete!(u32)), ShaderInput::StorageBuffer((), concrete!(Color)), - //ShaderInput::Constant(gpu_executor::GPUConstant::GlobalInvocationId), ShaderInput::OutputBuffer((), concrete!(Color)), ], + #[cfg(feature = "quantization")] + output: ShaderInput::OutputBuffer((), concrete!(PackedPixel)), + #[cfg(not(feature = "quantization"))] output: ShaderInput::OutputBuffer((), concrete!(Color)), }, ) @@ -124,8 +261,6 @@ async fn map_gpu<'a: 'input>(image: ImageFrame, node: DocumentNode, edito //return ImageFrame::empty(); let len: usize = image.image.data.len(); - let executor = &editor_api.application_io.gpu_executor.as_ref().unwrap(); - /* let canvas = editor_api.application_io.create_surface(); @@ -144,6 +279,7 @@ async fn map_gpu<'a: 'input>(image: ImageFrame, node: DocumentNode, edito return frame;*/ log::debug!("creating buffer"); let width_uniform = executor.create_uniform_buffer(image.image.width).unwrap(); + let quantization_uniform = executor.create_uniform_buffer(quantization).unwrap(); let storage_buffer = executor .create_storage_buffer( image.image.data.clone(), @@ -156,6 +292,7 @@ async fn map_gpu<'a: 'input>(image: ImageFrame, node: DocumentNode, edito ) .unwrap(); let width_uniform = Arc::new(width_uniform); + let quantization_uniform = Arc::new(quantization_uniform); let storage_buffer = Arc::new(storage_buffer); let output_buffer = executor.create_output_buffer(len, concrete!(Color), false).unwrap(); let output_buffer = Arc::new(output_buffer); @@ -163,6 +300,9 @@ async fn map_gpu<'a: 'input>(image: ImageFrame, node: DocumentNode, edito let readback_buffer = Arc::new(readback_buffer); log::debug!("created buffer"); let bind_group = Bindgroup { + #[cfg(feature = "quantization")] + buffers: vec![width_uniform.clone(), storage_buffer.clone(), quantization_uniform.clone()], + #[cfg(not(feature = "quantization"))] buffers: vec![width_uniform.clone(), storage_buffer.clone()], }; @@ -175,36 +315,18 @@ async fn map_gpu<'a: 'input>(image: ImageFrame, node: DocumentNode, edito let shader = executor.load_shader(shader).unwrap(); log::debug!("loaded shader"); let pipeline = PipelineLayout { - shader, + shader: shader.into(), entry_point: "eval".to_string(), - bind_group, + bind_group: bind_group.into(), output_buffer: output_buffer.clone(), }; log::debug!("created pipeline"); - let compute_pass = executor - .create_compute_pass(&pipeline, Some(readback_buffer.clone()), ComputePassDimensions::XY(image.image.width, image.image.height)) - .unwrap(); - executor.execute_compute_pipeline(compute_pass).unwrap(); - log::debug!("executed pipeline"); - log::debug!("reading buffer"); - let result = executor.read_output_buffer(readback_buffer).await.unwrap(); - let colors = bytemuck::pod_collect_to_vec::(result.as_slice()); - ImageFrame { - image: Image { - data: colors, - width: image.image.width, - height: image.image.height, - }, - transform: image.transform, - } - /* - let executor: GpuExecutor = GpuExecutor::new(Context::new().await.unwrap(), shader.into(), "gpu::eval".into()).unwrap(); - let data: Vec<_> = input.into_iter().collect(); - let result = executor.execute(Box::new(data)).unwrap(); - let result = dyn_any::downcast::>(result).unwrap(); - *result - */ + let compute_pass_descriptor = ComputePass { + pipeline_layout: pipeline, + readback_buffer: Some(readback_buffer.clone()), + }; + compute_pass_descriptor } /* #[node_macro::node_fn(MapGpuNode)] @@ -414,9 +536,9 @@ async fn blend_gpu_image(foreground: ImageFrame, background: ImageFrame { #[node_macro::node_fn(GenerateQuantizationNode)] fn generate_quantization_fn(image_frame: ImageFrame, samples: u32, function: u32) -> [Quantization; 4] { - let image = image_frame.image; + generate_quantization_from_image_frame(&image_frame) +} + +pub fn generate_quantization_from_image_frame(image_frame: &ImageFrame) -> [Quantization; 4] { + let image = &image_frame.image; let len = image.data.len().min(10000); - let mut channels: Vec<_> = (0..4).map(|_| Vec::with_capacity(image.data.len())).collect(); - image + let data = image .data .iter() .enumerate() .filter(|(i, _)| i % (image.data.len() / len) == 0) - .map(|(_, x)| vec![x.r() as f64, x.g() as f64, x.b() as f64, x.a() as f64]) - .for_each(|x| x.into_iter().enumerate().for_each(|(i, value)| channels[i].push(value))); - let quantization: Vec = channels.into_iter().map(|x| generate_quantization_per_channel(x, samples)).collect(); - core::array::from_fn(|i| quantization[i].clone()) + .flat_map(|(_, x)| vec![x.r() as f64, x.g() as f64, x.b() as f64, x.a() as f64]) + .collect::>(); + generate_quantization(data, len) +} +fn generate_quantization(data: Vec, samples: usize) -> [Quantization; 4] { + let red = create_distribution(data.clone(), samples, 0); + let green = create_distribution(data.clone(), samples, 1); + let blue = create_distribution(data.clone(), samples, 2); + let alpha = create_distribution(data, samples, 3); + + let fit_red = autoquant::calculate_error_function(&red, 1, &red); + let fit_green = autoquant::calculate_error_function(&green, 1, &green); + let fit_blue = autoquant::calculate_error_function(&blue, 1, &blue); + let fit_alpha = autoquant::calculate_error_function(&alpha, 1, &alpha); + let red_error: ErrorFunction<10> = autoquant::packing::ErrorFunction::new(fit_red.as_slice()); + let green_error: ErrorFunction<10> = autoquant::packing::ErrorFunction::new(fit_green.as_slice()); + let blue_error: ErrorFunction<10> = autoquant::packing::ErrorFunction::new(fit_blue.as_slice()); + let alpha_error: ErrorFunction<10> = autoquant::packing::ErrorFunction::new(fit_alpha.as_slice()); + let merged: ErrorFunction<20> = autoquant::packing::merge_error_functions(&red_error, &green_error); + let merged: ErrorFunction<30> = autoquant::packing::merge_error_functions(&merged, &blue_error); + let merged: ErrorFunction<40> = autoquant::packing::merge_error_functions(&merged, &alpha_error); + + let bin_size = 32; + let mut distributions = [red, green, blue, alpha].into_iter(); + + let bits = &merged.bits[bin_size]; + + core::array::from_fn(|i| { + let fit = autoquant::models::OptimizedLin::new(distributions.next().unwrap(), (1 << bits[i]) - 1); + let parameters = fit.parameters(); + Quantization::new(parameters[0] as f32, parameters[1] as f32, bits[i] as u32) + }) } -fn generate_quantization_per_channel(data: Vec, samples: u32) -> Quantization { +/* +// TODO: make this work with generic size parameters +fn generate_quantization(data: Vec, samples: usize, channels: usize) -> [Quantization; N] { + let mut quantizations = Vec::new(); + let mut merged_error: Option> = None; + let bin_size = 32; + + for i in 0..channels { + let channel_data = create_distribution(data.clone(), samples, i); + + let fit = autoquant::calculate_error_function(&channel_data, 0, &channel_data); + let error: ErrorFunction<10> = autoquant::packing::ErrorFunction::new(fit.as_slice()); + + // Merge current error function with previous ones + merged_error = match merged_error { + Some(prev_error) => Some(autoquant::packing::merge_error_functions(&prev_error, &error)), + None => Some(error.clone()), + }; + + println!("Merged: {:?}", merged_error); + + let bits = merged_error.as_ref().unwrap().bits.iter().map(|x| x[i]).collect::>(); + let model_fit = autoquant::models::OptimizedLin::new(channel_data, 1 << bits[bin_size]); + let parameters = model_fit.parameters(); + let quantization = Quantization::new(parameters[0] as f32, parameters[1] as u32, bits[bin_size] as u32); + + quantizations.push(quantization); + } + + core::array::from_fn(|x| quantizations[x]) +}*/ + +fn create_distribution(data: Vec, samples: usize, channel: usize) -> Vec<(f64, f64)> { + let data: Vec = data.chunks(4 * (data.len() / (4 * samples.min(data.len() / 4)))).map(|x| x[channel] as f64).collect(); + let max = *data.iter().max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)).unwrap(); + let data: Vec = data.iter().map(|x| x / max).collect(); + dbg!(max); + //let data = autoquant::generate_normal_distribution(3.0, 1.1, 1000); + //data.iter_mut().for_each(|x| *x = x.abs()); let mut dist = autoquant::integrate_distribution(data); autoquant::drop_duplicates(&mut dist); let dist = autoquant::normalize_distribution(dist.as_slice()); - let max = dist.last().unwrap().0; - /*let linear = Box::new(autoquant::SimpleFitFn { - function: move |x| x / max, - inverse: move |x| x * max, - name: "identity", - });*/ - - let linear = Quantization { - fn_index: 0, - a: max as f32, - b: 0., - c: 0., - d: 0., - }; - let log_fit = autoquant::models::OptimizedLog::new(dist, samples as u64); - let parameters = log_fit.parameters(); - let log_fit = Quantization { - fn_index: 1, - a: parameters[0] as f32, - b: parameters[1] as f32, - c: parameters[2] as f32, - d: parameters[3] as f32, - }; - log_fit + dist } diff --git a/node-graph/gstd/src/value.rs b/node-graph/gstd/src/value.rs index e3990543..fcca52cd 100644 --- a/node-graph/gstd/src/value.rs +++ b/node-graph/gstd/src/value.rs @@ -7,8 +7,7 @@ use dyn_any::DynAny; pub struct AnyRefNode<'n, N: Node<'n>>(N, PhantomData<&'n ()>); impl<'n, N: Node<'n, Output = &'n O>, O: DynAny<'n> + 'n> Node<'n> for AnyRefNode<'n, N> { - type Output = &'n (dyn DynAny<'n>); - fn eval(&'n self) -> Self::Output { + fn eval(&'n self) -> &'n (dyn DynAny<'n>) { let value: &O = self.0.eval(); value } @@ -22,8 +21,7 @@ impl<'n, N: Node<'n, Output = &'n O>, O: 'n + ?Sized> AnyRefNode<'n, N> { pub struct StorageNode<'n>(&'n dyn Node<'n, Output = &'n dyn DynAny<'n>>); impl<'n> Node<'n> for StorageNode<'n> { - type Output = &'n (dyn DynAny<'n>); - fn eval(&'n self) -> Self::Output { + fn eval(&'n self) -> &'n (dyn DynAny<'n>) { self.0.eval() } } @@ -36,7 +34,6 @@ impl<'n> StorageNode<'n> { #[derive(Default)] pub struct AnyValueNode<'n, T>(T, PhantomData<&'n ()>); impl<'n, T: 'n + DynAny<'n>> Node<'n> for AnyValueNode<'n, T> { - type Output = &'n dyn DynAny<'n>; fn eval(&'n self) -> &'n dyn DynAny<'n> { &self.0 } diff --git a/node-graph/gstd/src/wasm_application_io.rs b/node-graph/gstd/src/wasm_application_io.rs index e6cce3bf..a7542685 100644 --- a/node-graph/gstd/src/wasm_application_io.rs +++ b/node-graph/gstd/src/wasm_application_io.rs @@ -1,13 +1,21 @@ +use std::any::Any; use std::cell::RefCell; +use core::future::Future; use dyn_any::StaticType; -use graphene_core::application_io::{ApplicationIo, SurfaceHandle, SurfaceHandleFrame, SurfaceId}; +use graphene_core::application_io::{ApplicationError, ApplicationIo, SurfaceHandle, SurfaceHandleFrame, SurfaceId}; +use graphene_core::raster::Image; +use graphene_core::Color; use graphene_core::{ raster::{color::SRGBA8, ImageFrame}, Node, }; use js_sys::{Object, Reflect}; +use std::collections::HashMap; +use std::pin::Pin; use std::sync::Arc; +#[cfg(feature = "tokio")] +use tokio::io::AsyncReadExt; use wasm_bindgen::{Clamped, JsCast, JsValue}; use web_sys::{window, CanvasRenderingContext2d, HtmlCanvasElement}; #[cfg(feature = "wgpu")] @@ -20,15 +28,23 @@ pub struct WasmApplicationIo { ids: RefCell, #[cfg(feature = "wgpu")] pub(crate) gpu_executor: Option, + #[cfg(not(target_arch = "wasm32"))] + windows: RefCell>>, + pub resources: HashMap>, } impl WasmApplicationIo { pub async fn new() -> Self { - Self { + let mut io = Self { ids: RefCell::new(0), #[cfg(feature = "wgpu")] gpu_executor: WgpuExecutor::new().await, - } + #[cfg(not(target_arch = "wasm32"))] + windows: RefCell::new(Vec::new()), + resources: HashMap::new(), + }; + io.resources.insert("null".to_string(), Arc::from(include_bytes!("null.png").to_vec())); + io } } @@ -51,12 +67,16 @@ impl<'a> From<&'a WasmApplicationIo> for &'a WgpuExecutor { pub type WasmEditorApi<'a> = graphene_core::application_io::EditorApi<'a, WasmApplicationIo>; impl ApplicationIo for WasmApplicationIo { + #[cfg(target_arch = "wasm32")] type Surface = HtmlCanvasElement; + #[cfg(not(target_arch = "wasm32"))] + type Surface = Arc; #[cfg(feature = "wgpu")] type Executor = WgpuExecutor; #[cfg(not(feature = "wgpu"))] type Executor = (); + #[cfg(target_arch = "wasm32")] fn create_surface(&self) -> SurfaceHandle { let wrapper = || { let document = window().expect("should have a window in this context").document().expect("window should have a document"); @@ -90,7 +110,29 @@ impl ApplicationIo for WasmApplicationIo { wrapper().expect("should be able to set canvas in global scope") } + #[cfg(not(target_arch = "wasm32"))] + fn create_surface(&self) -> SurfaceHandle { + #[cfg(feature = "wayland")] + use winit::platform::wayland::EventLoopBuilderExtWayland; + #[cfg(feature = "wayland")] + let event_loop = winit::event_loop::EventLoopBuilder::new().with_any_thread(true).build(); + #[cfg(not(feature = "wayland"))] + let event_loop = winit::event_loop::EventLoop::new(); + let window = winit::window::WindowBuilder::new() + .with_title("Graphite") + .with_inner_size(winit::dpi::PhysicalSize::new(800, 600)) + .build(&event_loop) + .unwrap(); + let window = Arc::new(window); + self.windows.borrow_mut().push(window.clone()); + SurfaceHandle { + surface_id: SurfaceId(window.id().into()), + surface: window, + } + } + + #[cfg(target_arch = "wasm32")] fn destroy_surface(&self, surface_id: SurfaceId) { let window = window().expect("should have a window in this context"); let window = Object::from(window); @@ -111,10 +153,50 @@ impl ApplicationIo for WasmApplicationIo { wrapper().expect("should be able to set canvas in global scope") } + #[cfg(not(target_arch = "wasm32"))] + fn destroy_surface(&self, _surface_id: SurfaceId) {} + #[cfg(feature = "wgpu")] fn gpu_executor(&self) -> Option<&Self::Executor> { self.gpu_executor.as_ref() } + + fn load_resource(&self, url: impl AsRef) -> Result, ApplicationError>>>>, ApplicationError> { + let url = url::Url::parse(url.as_ref()).map_err(|_| ApplicationError::InvalidUrl)?; + log::info!("Loading resource: {:?}", url); + match url.scheme() { + #[cfg(feature = "tokio")] + "file" => { + let path = url.to_file_path().map_err(|_| ApplicationError::NotFound)?; + let path = path.to_str().ok_or(ApplicationError::NotFound)?; + let path = path.to_owned(); + Ok(Box::pin(async move { + let file = tokio::fs::File::open(path).await.map_err(|_| ApplicationError::NotFound)?; + let mut reader = tokio::io::BufReader::new(file); + let mut data = Vec::new(); + reader.read_to_end(&mut data).await.map_err(|_| ApplicationError::NotFound)?; + Ok(Arc::from(data)) + }) as Pin, _>>>>) + } + "http" | "https" => { + let url = url.to_string(); + Ok(Box::pin(async move { + let client = reqwest::Client::new(); + let response = client.get(url).send().await.map_err(|_| ApplicationError::NotFound)?; + let data = response.bytes().await.map_err(|_| ApplicationError::NotFound)?; + Ok(Arc::from(data.to_vec())) + }) as Pin, _>>>>) + } + "graphite" => { + let path = url.path(); + let path = path.to_owned(); + log::info!("Loading resource: {}", path); + let data = self.resources.get(&path).ok_or(ApplicationError::NotFound)?.clone(); + Ok(Box::pin(async move { Ok(data.clone()) }) as Pin, _>>>>) + } + _ => Err(ApplicationError::NotFound), + } + } } pub type WasmSurfaceHandle = SurfaceHandle; @@ -123,7 +205,7 @@ pub type WasmSurfaceHandleFrame = SurfaceHandleFrame; pub struct CreateSurfaceNode {} #[node_macro::node_fn(CreateSurfaceNode)] -async fn create_surface_node<'a: 'input>(editor: WasmEditorApi<'a>) -> Arc> { +async fn create_surface_node<'a: 'input>(editor: WasmEditorApi<'a>) -> Arc::Surface>> { editor.application_io.create_surface().into() } @@ -149,3 +231,29 @@ async fn draw_image_frame_node<'a: 'input>(image: ImageFrame, surface_ha transform: image.transform, } } + +pub struct LoadResourceNode { + url: Url, +} + +#[node_macro::node_fn(LoadResourceNode)] +async fn load_resource_node<'a: 'input>(editor: WasmEditorApi<'a>, url: String) -> Arc<[u8]> { + editor.application_io.load_resource(url).unwrap().await.unwrap() +} + +pub struct DecodeImageNode; + +#[node_macro::node_fn(DecodeImageNode)] +fn decode_image_node<'a: 'input>(data: Arc<[u8]>) -> ImageFrame { + let image = image::load_from_memory(data.as_ref()).expect("Failed to decode image"); + let image = image.to_rgba32f(); + let image = ImageFrame { + image: Image { + data: image.chunks(4).map(|pixel| Color::from_unassociated_alpha(pixel[0], pixel[1], pixel[2], pixel[3])).collect(), + width: image.width(), + height: image.height(), + }, + transform: glam::DAffine2::IDENTITY, + }; + image +} diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index d59e8d12..0dd4d58e 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -1,7 +1,7 @@ use graph_craft::imaginate_input::{ImaginateCache, ImaginateController, ImaginateMaskStartingFill, ImaginateSamplingMethod}; use graph_craft::proto::{NodeConstructor, TypeErasedBox}; use graphene_core::ops::IdNode; -use graphene_core::quantization::QuantizationChannels; +use graphene_core::quantization::{PackedPixel, QuantizationChannels}; use graphene_core::raster::brush_cache::BrushCache; use graphene_core::raster::color::Color; @@ -191,10 +191,10 @@ fn node_registry() -> HashMap, input: &u32, params: [u32]), register_node!(graphene_core::ops::AddParameterNode<_>, input: u32, params: [&u32]), register_node!(graphene_core::ops::AddParameterNode<_>, input: &u32, params: [&u32]), - register_node!(graphene_core::ops::AddParameterNode<_>, input: f64, params: [f64]), - register_node!(graphene_core::ops::AddParameterNode<_>, input: &f64, params: [f64]), - register_node!(graphene_core::ops::AddParameterNode<_>, input: f64, params: [&f64]), - register_node!(graphene_core::ops::AddParameterNode<_>, input: &f64, params: [&f64]), + register_node!(graphene_core::ops::AddParameterNode<_>, input: f32, params: [f32]), + register_node!(graphene_core::ops::AddParameterNode<_>, input: &f32, params: [f32]), + register_node!(graphene_core::ops::AddParameterNode<_>, input: f32, params: [&f32]), + register_node!(graphene_core::ops::AddParameterNode<_>, input: &f32, params: [&f32]), register_node!(graphene_core::ops::SomeNode, input: WasmEditorApi, params: []), async_node!(graphene_core::ops::IntoNode<_, ImageFrame>, input: ImageFrame, output: ImageFrame, params: []), async_node!(graphene_core::ops::IntoNode<_, ImageFrame>, input: ImageFrame, output: ImageFrame, params: []), @@ -251,6 +251,8 @@ fn node_registry() -> HashMap, input: DAffine2, params: [Color]), register_node!(graphene_core::memo::MonitorNode<_>, input: ImageFrame, params: []), register_node!(graphene_core::memo::MonitorNode<_>, input: graphene_core::GraphicGroup, params: []), + async_node!(graphene_std::wasm_application_io::LoadResourceNode<_>, input: WasmEditorApi, output: Arc<[u8]>, params: [String]), + register_node!(graphene_std::wasm_application_io::DecodeImageNode, input: Arc<[u8]>, params: []), async_node!(graphene_std::wasm_application_io::CreateSurfaceNode, input: WasmEditorApi, output: Arc::Surface>>, params: []), async_node!( graphene_std::wasm_application_io::DrawImageFrameNode<_>, @@ -284,7 +286,7 @@ fn node_registry() -> HashMap, input: Arc>, output: Vec, params: [&WgpuExecutor, ()]), - #[cfg(all(feature = "gpu", target_arch = "wasm32"))] + #[cfg(feature = "gpu")] async_node!(gpu_executor::CreateGpuSurfaceNode, input: WasmEditorApi, output: Arc::Surface>>, params: []), #[cfg(feature = "gpu")] async_node!(gpu_executor::RenderTextureNode<_, _>, input: ShaderInputFrame, output: SurfaceFrame, params: [Arc::Surface>>, &WgpuExecutor]), @@ -310,7 +312,7 @@ fn node_registry() -> HashMap), - concrete!(SurfaceFrame), + concrete!(ImageFrame), vec![fn_type!(graph_craft::document::DocumentNode), fn_type!(WasmEditorApi)], ), )], @@ -355,7 +357,7 @@ fn node_registry() -> HashMap, params: [RedGreenBlue]), raster_node!(graphene_core::raster::ExtractAlphaNode<>, params: []), raster_node!(graphene_core::raster::ExtractOpaqueNode<>, params: []), - raster_node!(graphene_core::raster::LevelsNode<_, _, _, _, _>, params: [f64, f64, f64, f64, f64]), + raster_node!(graphene_core::raster::LevelsNode<_, _, _, _, _>, params: [f32, f32, f32, f32, f32]), register_node!(graphene_std::image_segmentation::ImageSegmentationNode<_>, input: ImageFrame, params: [ImageFrame]), register_node!(graphene_core::raster::IndexNode<_>, input: Vec>, params: [u32]), vec![( @@ -364,7 +366,7 @@ fn node_registry() -> HashMap> = DowncastBothNode::new(args[0].clone()); let blend_mode: DowncastBothNode<(), BlendMode> = DowncastBothNode::new(args[1].clone()); - let opacity: DowncastBothNode<(), f64> = DowncastBothNode::new(args[2].clone()); + let opacity: DowncastBothNode<(), f32> = DowncastBothNode::new(args[2].clone()); let blend_node = graphene_core::raster::BlendNode::new(CopiedNode::new(blend_mode.eval(()).await), CopiedNode::new(opacity.eval(()).await)); let node = graphene_std::raster::BlendImageNode::new(image, blend_node); let any: DynAnyNode, _, _> = graphene_std::any::DynAnyNode::new(node); @@ -374,21 +376,21 @@ fn node_registry() -> HashMap), concrete!(ImageFrame), - vec![fn_type!(ImageFrame), fn_type!(BlendMode), fn_type!(f64)], + vec![fn_type!(ImageFrame), fn_type!(BlendMode), fn_type!(f32)], ), )], - raster_node!(graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>, params: [Color, f64, f64, f64, f64, f64, f64]), - raster_node!(graphene_core::raster::HueSaturationNode<_, _, _>, params: [f64, f64, f64]), + raster_node!(graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>, params: [Color, f32, f32, f32, f32, f32, f32]), + raster_node!(graphene_core::raster::HueSaturationNode<_, _, _>, params: [f32, f32, f32]), raster_node!(graphene_core::raster::InvertRGBNode, params: []), - raster_node!(graphene_core::raster::ThresholdNode<_, _, _>, params: [f64, f64, LuminanceCalculation]), - raster_node!(graphene_core::raster::VibranceNode<_>, params: [f64]), + raster_node!(graphene_core::raster::ThresholdNode<_, _, _>, params: [f32, f32, LuminanceCalculation]), + raster_node!(graphene_core::raster::VibranceNode<_>, params: [f32]), raster_node!( graphene_core::raster::ChannelMixerNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>, - params: [bool, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64] + params: [bool, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32] ), raster_node!( graphene_core::raster::SelectiveColorNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>, - params: [RelativeAbsolute, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64, f64] + params: [RelativeAbsolute, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32] ), vec![( NodeIdentifier::new("graphene_core::raster::BrightnessContrastNode<_, _, _>"), @@ -396,9 +398,9 @@ fn node_registry() -> HashMap = DowncastBothNode::new(args[0].clone()); + let brightness: DowncastBothNode<(), f32> = DowncastBothNode::new(args[0].clone()); let brightness = ClonedNode::new(brightness.eval(()).await as f32); - let contrast: DowncastBothNode<(), f64> = DowncastBothNode::new(args[1].clone()); + let contrast: DowncastBothNode<(), f32> = DowncastBothNode::new(args[1].clone()); let contrast = ClonedNode::new(contrast.eval(()).await as f32); let use_legacy: DowncastBothNode<(), bool> = DowncastBothNode::new(args[2].clone()); @@ -417,11 +419,11 @@ fn node_registry() -> HashMap), concrete!(ImageFrame), vec![fn_type!(f64), fn_type!(f64), fn_type!(bool)]), + NodeIOTypes::new(concrete!(ImageFrame), concrete!(ImageFrame), vec![fn_type!(f32), fn_type!(f32), fn_type!(bool)]), )], - raster_node!(graphene_core::raster::OpacityNode<_>, params: [f64]), - raster_node!(graphene_core::raster::PosterizeNode<_>, params: [f64]), - raster_node!(graphene_core::raster::ExposureNode<_, _, _>, params: [f64, f64, f64]), + raster_node!(graphene_core::raster::OpacityNode<_>, params: [f32]), + raster_node!(graphene_core::raster::PosterizeNode<_>, params: [f32]), + raster_node!(graphene_core::raster::ExposureNode<_, _, _>, params: [f32, f32, f32]), register_node!(graphene_core::memo::LetNode<_>, input: Option>, params: []), register_node!(graphene_core::memo::LetNode<_>, input: Option, params: []), async_node!(graphene_core::memo::EndLetNode<_>, input: WasmEditorApi, output: ImageFrame, params: [ImageFrame]), @@ -479,18 +481,18 @@ fn node_registry() -> HashMap), fn_type!(u32), fn_type!(ImaginateSamplingMethod), - fn_type!(f64), + fn_type!(f32), fn_type!(String), fn_type!(String), fn_type!(bool), - fn_type!(f64), + fn_type!(f32), fn_type!(Option>), fn_type!(bool), - fn_type!(f64), + fn_type!(f32), fn_type!(ImaginateMaskStartingFill), fn_type!(bool), fn_type!(bool), @@ -513,25 +515,25 @@ fn node_registry() -> HashMap, input: Image, params: [DAffine2]), #[cfg(feature = "quantization")] register_node!(graphene_std::quantization::GenerateQuantizationNode<_, _>, input: ImageFrame, params: [u32, u32]), - raster_node!(graphene_core::quantization::QuantizeNode<_>, params: [QuantizationChannels]), - raster_node!(graphene_core::quantization::DeQuantizeNode<_>, params: [QuantizationChannels]), + register_node!(graphene_core::quantization::QuantizeNode<_>, input: Color, params: [QuantizationChannels]), + register_node!(graphene_core::quantization::DeQuantizeNode<_>, input: PackedPixel, params: [QuantizationChannels]), register_node!(graphene_core::ops::CloneNode<_>, input: &QuantizationChannels, params: []), - register_node!(graphene_core::transform::TransformNode<_, _, _, _, _>, input: VectorData, params: [DVec2, f64, DVec2, DVec2, DVec2]), - register_node!(graphene_core::transform::TransformNode<_, _, _, _, _>, input: ImageFrame, params: [DVec2, f64, DVec2, DVec2, DVec2]), - register_node!(graphene_core::transform::TransformNode<_, _, _, _, _>, input: WasmSurfaceHandleFrame, params: [DVec2, f64, DVec2, DVec2, DVec2]), + register_node!(graphene_core::transform::TransformNode<_, _, _, _, _>, input: VectorData, params: [DVec2, f32, DVec2, DVec2, DVec2]), + register_node!(graphene_core::transform::TransformNode<_, _, _, _, _>, input: ImageFrame, params: [DVec2, f32, DVec2, DVec2, DVec2]), + register_node!(graphene_core::transform::TransformNode<_, _, _, _, _>, input: WasmSurfaceHandleFrame, params: [DVec2, f32, DVec2, DVec2, DVec2]), register_node!(graphene_core::transform::SetTransformNode<_>, input: VectorData, params: [VectorData]), register_node!(graphene_core::transform::SetTransformNode<_>, input: ImageFrame, params: [ImageFrame]), register_node!(graphene_core::transform::SetTransformNode<_>, input: VectorData, params: [DAffine2]), register_node!(graphene_core::transform::SetTransformNode<_>, input: ImageFrame, params: [DAffine2]), register_node!(graphene_core::vector::SetFillNode<_, _, _, _, _, _, _>, input: VectorData, params: [graphene_core::vector::style::FillType, Option, graphene_core::vector::style::GradientType, DVec2, DVec2, DAffine2, Vec<(f64, Option)>]), - register_node!(graphene_core::vector::SetStrokeNode<_, _, _, _, _, _, _>, input: VectorData, params: [Option, f64, Vec, f64, graphene_core::vector::style::LineCap, graphene_core::vector::style::LineJoin, f64]), + register_node!(graphene_core::vector::SetStrokeNode<_, _, _, _, _, _, _>, input: VectorData, params: [Option, f32, Vec, f32, graphene_core::vector::style::LineCap, graphene_core::vector::style::LineJoin, f32]), register_node!(graphene_core::vector::generator_nodes::UnitCircleGenerator, input: (), params: []), register_node!( graphene_core::vector::generator_nodes::PathGenerator<_>, input: Vec>, params: [Vec] ), - register_node!(graphene_core::text::TextGenerator<_, _, _>, input: WasmEditorApi, params: [String, graphene_core::text::Font, f64]), + register_node!(graphene_core::text::TextGenerator<_, _, _>, input: WasmEditorApi, params: [String, graphene_core::text::Font, f32]), register_node!(graphene_std::brush::VectorPointsNode, input: VectorData, params: []), register_node!(graphene_core::ExtractImageFrame, input: WasmEditorApi, params: []), register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::vector::VectorData, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]), diff --git a/node-graph/wgpu-executor/Cargo.toml b/node-graph/wgpu-executor/Cargo.toml index 5d99ea72..8e9a338d 100644 --- a/node-graph/wgpu-executor/Cargo.toml +++ b/node-graph/wgpu-executor/Cargo.toml @@ -6,6 +6,8 @@ license = "MIT OR Apache-2.0" [features] default = [] +profiling = ["nvtx"] +passthrough = [] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -38,3 +40,4 @@ futures-intrusive = "0.5.0" futures = "0.3.25" web-sys = { version = "0.3.4", features = ["HtmlCanvasElement"] } winit = "0.28.6" +nvtx = { version = "1.1.1", optional = true } diff --git a/node-graph/wgpu-executor/src/context.rs b/node-graph/wgpu-executor/src/context.rs index 2285ad3a..33e99e18 100644 --- a/node-graph/wgpu-executor/src/context.rs +++ b/node-graph/wgpu-executor/src/context.rs @@ -12,23 +12,25 @@ pub struct Context { impl Context { pub async fn new() -> Option { // Instantiates instance of WebGPU - let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::default()); + let mut instance_descriptor = wgpu::InstanceDescriptor::default(); + instance_descriptor.backends = wgpu::Backends::VULKAN | wgpu::Backends::BROWSER_WEBGPU; + let instance = wgpu::Instance::new(instance_descriptor); // `request_adapter` instantiates the general connection to the GPU let adapter = instance.request_adapter(&wgpu::RequestAdapterOptions::default()).await?; - //let limits = adapter.limits(); - - //log::trace!("Adapter limits: {:?}", limits); - + let limits = adapter.limits(); // `request_device` instantiates the feature specific connection to the GPU, defining some parameters, // `features` being the available features. let (device, queue) = adapter .request_device( &wgpu::DeviceDescriptor { label: None, + #[cfg(not(feature = "passthrough"))] features: wgpu::Features::empty(), - limits: Default::default(), + #[cfg(feature = "passthrough")] + features: wgpu::Features::SPIRV_SHADER_PASSTHROUGH, + limits: limits, }, None, ) diff --git a/node-graph/wgpu-executor/src/lib.rs b/node-graph/wgpu-executor/src/lib.rs index 57e71a96..d41988d5 100644 --- a/node-graph/wgpu-executor/src/lib.rs +++ b/node-graph/wgpu-executor/src/lib.rs @@ -11,19 +11,30 @@ use anyhow::{bail, Result}; use futures::Future; use graphene_core::application_io::{ApplicationIo, EditorApi, SurfaceHandle}; +use std::cell::Cell; use std::pin::Pin; use std::sync::Arc; use wgpu::util::DeviceExt; -use wgpu::{Buffer, BufferDescriptor, CommandBuffer, ShaderModule, Texture, TextureView}; +use wgpu::{Buffer, BufferDescriptor, CommandBuffer, ShaderModule, SurfaceConfiguration, SurfaceError, Texture, TextureView}; #[cfg(target_arch = "wasm32")] use web_sys::HtmlCanvasElement; -#[derive(Debug, dyn_any::DynAny)] +#[derive(dyn_any::DynAny)] pub struct WgpuExecutor { - context: Context, + pub context: Context, render_configuration: RenderConfiguration, + surface_config: Cell>, +} + +impl std::fmt::Debug for WgpuExecutor { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("WgpuExecutor") + .field("context", &self.context) + .field("render_configuration", &self.render_configuration) + .finish() + } } impl<'a, T: ApplicationIo> From> for &'a WgpuExecutor { @@ -104,13 +115,21 @@ impl gpu_executor::GpuExecutor for WgpuExecutor { #[cfg(target_arch = "wasm32")] type Window = HtmlCanvasElement; #[cfg(not(target_arch = "wasm32"))] - type Window = winit::window::Window; + type Window = Arc; fn load_shader(&self, shader: Shader) -> Result { + #[cfg(not(feature = "passthrough"))] let shader_module = self.context.device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some(shader.name), source: wgpu::ShaderSource::SpirV(shader.source), }); + #[cfg(feature = "passthrough")] + let shader_module = unsafe { + self.context.device.create_shader_module_spirv(&wgpu::ShaderModuleDescriptorSpirV { + label: Some(shader.name), + source: shader.source, + }) + }; Ok(ShaderModuleWrapper(shader_module)) } @@ -234,14 +253,16 @@ impl gpu_executor::GpuExecutor for WgpuExecutor { entries: entries.as_slice(), }); - let mut encoder = self.context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + let mut encoder = self.context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("compute encoder") }); { let dimensions = instances.get(); let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: None }); cpass.set_pipeline(&compute_pipeline); cpass.set_bind_group(0, &bind_group, &[]); cpass.insert_debug_marker("compute node network evaluation"); + cpass.push_debug_group("compute shader"); cpass.dispatch_workgroups(dimensions.0, dimensions.1, dimensions.2); // Number of cells to run, the (x,y,z) size of item being processed + cpass.pop_debug_group(); } // Sets adds copy operation to command encoder. // Will copy data from storage buffer on GPU to staging buffer on CPU. @@ -265,7 +286,40 @@ impl gpu_executor::GpuExecutor for WgpuExecutor { fn create_render_pass(&self, texture: Arc>, canvas: Arc>) -> Result<()> { let texture = texture.texture().expect("Expected texture input"); let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default()); - let output = canvas.as_ref().surface.get_current_texture()?; + let result = canvas.as_ref().surface.get_current_texture(); + + let surface = &canvas.as_ref().surface; + let surface_caps = surface.get_capabilities(&self.context.adapter); + println!("{:?}", surface_caps); + if surface_caps.formats.is_empty() { + log::warn!("No surface formats available"); + //return Ok(()); + } + let Some(config) = self.surface_config.take() else {return Ok(())}; + let new_config = config.clone(); + self.surface_config.replace(Some(config)); + let output = match result { + Err(SurfaceError::Timeout) => { + log::warn!("Timeout when getting current texture"); + return Ok(()); + } + Err(SurfaceError::Lost) => { + log::warn!("Surface lost"); + + surface.configure(&self.context.device, &new_config); + return Ok(()); + } + Err(SurfaceError::OutOfMemory) => { + log::warn!("Out of memory"); + return Ok(()); + } + Err(SurfaceError::Outdated) => { + log::warn!("Surface outdated"); + surface.configure(&self.context.device, &new_config); + return Ok(()); + } + Ok(surface) => surface, + }; let view = output.texture.create_view(&wgpu::TextureViewDescriptor { format: Some(wgpu::TextureFormat::Bgra8Unorm), ..Default::default() @@ -306,10 +360,16 @@ impl gpu_executor::GpuExecutor for WgpuExecutor { render_pass.set_vertex_buffer(0, self.render_configuration.vertex_buffer.slice(..)); render_pass.set_index_buffer(self.render_configuration.index_buffer.slice(..), wgpu::IndexFormat::Uint16); render_pass.draw_indexed(0..self.render_configuration.num_indices, 0, 0..1); + render_pass.insert_debug_marker("render node network"); } let encoder = encoder.finish(); + #[cfg(feature = "profiling")] + nvtx::range_push!("render"); self.context.queue.submit(Some(encoder)); + #[cfg(feature = "profiling")] + nvtx::range_pop!(); + log::trace!("Submitted render pass"); output.present(); Ok(()) @@ -318,10 +378,6 @@ impl gpu_executor::GpuExecutor for WgpuExecutor { fn execute_compute_pipeline(&self, encoder: Self::CommandBuffer) -> Result<()> { self.context.queue.submit(Some(encoder.0)); - // Poll the device in a blocking manner so that our future resolves. - // In an actual application, `device.poll(...)` should - // be called in an event loop or on another thread. - self.context.device.poll(wgpu::Maintain::Wait); Ok(()) } @@ -394,8 +450,25 @@ impl gpu_executor::GpuExecutor for WgpuExecutor { }) } #[cfg(not(target_arch = "wasm32"))] - fn create_surface(&self, window: SurfaceHandle) -> Result> { - let surface = unsafe { self.context.instance.create_surface(&window.surface) }?; + fn create_surface(&self, window: SurfaceHandle) -> Result> { + let surface = unsafe { self.context.instance.create_surface(window.surface.as_ref()) }?; + + let size = window.surface.inner_size(); + let surface_caps = surface.get_capabilities(&self.context.adapter); + println!("{:?}", surface_caps); + let surface_format = wgpu::TextureFormat::Bgra8Unorm; + let config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: surface_format, + width: size.width, + height: size.height, + present_mode: surface_caps.present_modes[0], + alpha_mode: surface_caps.alpha_modes[0], + view_formats: vec![], + }; + surface.configure(&self.context.device, &config); + self.surface_config.set(Some(config)); + let surface_id = window.surface_id; Ok(SurfaceHandle { surface_id, surface }) } @@ -404,6 +477,7 @@ impl gpu_executor::GpuExecutor for WgpuExecutor { impl WgpuExecutor { pub async fn new() -> Option { let context = Context::new().await?; + println!("wgpu executor created"); let texture_bind_group_layout = context.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { entries: &[ @@ -512,7 +586,11 @@ impl WgpuExecutor { sampler, }; - Some(Self { context, render_configuration }) + Some(Self { + context, + render_configuration, + surface_config: Cell::new(None), + }) } }