diff --git a/Cargo.lock b/Cargo.lock index 66ce5f990..a9511676c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,6 +131,103 @@ dependencies = [ "libloading", ] +[[package]] +name = "ashpd" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dcc8ed0b5211687437636d8c95f6a608f4281d142101b3b5d314b38bfadd40f" +dependencies = [ + "enumflags2", + "futures", + "rand", + "serde", + "serde_repr", + "zbus", +] + +[[package]] +name = "async-broadcast" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d26004fe83b2d1cd3a97609b21e39f9a31535822210fe83205d2ce48866ea61" +dependencies = [ + "event-listener", + "futures-core", + "parking_lot", +] + +[[package]] +name = "async-channel" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "slab", +] + +[[package]] +name = "async-io" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8121296a9f05be7f34aa4196b1747243b3b62e048bb7906f644f3fbfc490cf7" +dependencies = [ + "async-lock", + "autocfg", + "concurrent-queue", + "futures-lite", + "libc", + "log", + "parking", + "polling", + "slab", + "socket2", + "waker-fn", + "winapi", +] + +[[package]] +name = "async-lock" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685" +dependencies = [ + "event-listener", + "futures-lite", +] + +[[package]] +name = "async-recursion" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-task" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" + [[package]] name = "async-trait" version = "0.1.58" @@ -293,6 +390,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +[[package]] +name = "cache-padded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" + [[package]] name = "calloop" version = "0.10.1" @@ -300,7 +403,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a22a6a8f622f797120d452c630b0ab12e1331a1a753e2039ce7868d4ac77b4ee" dependencies = [ "log", - "nix", + "nix 0.24.2", "slotmap", "thiserror", "vec_map", @@ -484,6 +587,15 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "concurrent-queue" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c" +dependencies = [ + "cache-padded", +] + [[package]] name = "copyless" version = "0.1.5" @@ -750,12 +862,43 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "diff" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -858,6 +1001,27 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enumflags2" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "env_logger" version = "0.9.1" @@ -886,6 +1050,12 @@ dependencies = [ "parking_lot", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + [[package]] name = "expat-sys" version = "2.1.6" @@ -1067,12 +1237,14 @@ name = "fj-viewer" version = "0.21.0" dependencies = [ "bytemuck", + "crossbeam-channel", "egui", "egui-wgpu", "fj-interop", "fj-math", "getrandom", "raw-window-handle 0.4.3", + "rfd", "thiserror", "tracing", "wgpu", @@ -1083,6 +1255,7 @@ dependencies = [ name = "fj-window" version = "0.21.0" dependencies = [ + "crossbeam-channel", "egui-winit", "fj-host", "fj-interop", @@ -1241,6 +1414,21 @@ version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +[[package]] +name = "futures-lite" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + [[package]] name = "futures-macro" version = "0.3.25" @@ -1443,6 +1631,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hexf-parse" version = "0.2.1" @@ -2010,6 +2204,19 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "nix" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset", +] + [[package]] name = "nix" version = "0.24.2" @@ -2178,6 +2385,17 @@ dependencies = [ "objc_exception", ] +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + [[package]] name = "objc_exception" version = "0.1.2" @@ -2187,6 +2405,15 @@ dependencies = [ "cc", ] +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + [[package]] name = "object" version = "0.29.0" @@ -2286,6 +2513,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ordered-stream" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44630c059eacfd6e08bdaa51b1db2ce33119caa4ddc1235e923109aa5f25ccb1" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "os_pipe" version = "0.9.2" @@ -2326,6 +2563,12 @@ dependencies = [ "ttf-parser", ] +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + [[package]] name = "parking_lot" version = "0.12.1" @@ -2465,6 +2708,26 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "polling" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4609a838d88b73d8238967b60dd115cc08d38e2bbaf51ee1e4b695f89122e2" +dependencies = [ + "autocfg", + "cfg-if", + "libc", + "log", + "wepoll-ffi", + "winapi", +] + +[[package]] +name = "pollster" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da3b0203fd7ee5720aa0b5e790b591aa5d3f41c3ed2c34a3a393382198af2f7" + [[package]] name = "ppv-lite86" version = "0.2.16" @@ -2648,6 +2911,17 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + [[package]] name = "regex" version = "1.6.0" @@ -2745,6 +3019,29 @@ dependencies = [ "winreg", ] +[[package]] +name = "rfd" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0149778bd99b6959285b0933288206090c50e2327f47a9c463bfdbf45c8823ea" +dependencies = [ + "ashpd", + "block", + "dispatch", + "js-sys", + "log", + "objc", + "objc-foundation", + "objc_id", + "pollster", + "raw-window-handle 0.5.0", + "urlencoding", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows", +] + [[package]] name = "ring" version = "0.16.20" @@ -2950,6 +3247,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2983,6 +3291,21 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "sha1" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + [[package]] name = "sharded-slab" version = "0.1.4" @@ -3062,7 +3385,7 @@ dependencies = [ "lazy_static", "log", "memmap2", - "nix", + "nix 0.24.2", "pkg-config", "wayland-client", "wayland-cursor", @@ -3501,6 +3824,16 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +[[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 = "uncased" version = "0.9.7" @@ -3570,6 +3903,12 @@ dependencies = [ "serde", ] +[[package]] +name = "urlencoding" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9" + [[package]] name = "valuable" version = "0.1.0" @@ -3594,6 +3933,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[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.2" @@ -3702,7 +4047,7 @@ dependencies = [ "bitflags", "downcast-rs", "libc", - "nix", + "nix 0.24.2", "scoped-tls", "wayland-commons", "wayland-scanner", @@ -3715,7 +4060,7 @@ version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" dependencies = [ - "nix", + "nix 0.24.2", "once_cell", "smallvec", "wayland-sys", @@ -3727,7 +4072,7 @@ version = "0.29.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" dependencies = [ - "nix", + "nix 0.24.2", "wayland-client", "xcursor", ] @@ -3776,6 +4121,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "wepoll-ffi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +dependencies = [ + "cc", +] + [[package]] name = "wgpu" version = "0.13.1" @@ -3923,6 +4277,19 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647" +dependencies = [ + "windows_aarch64_msvc 0.37.0", + "windows_i686_gnu 0.37.0", + "windows_i686_msvc 0.37.0", + "windows_x86_64_gnu 0.37.0", + "windows_x86_64_msvc 0.37.0", +] + [[package]] name = "windows-sys" version = "0.36.1" @@ -3963,6 +4330,12 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +[[package]] +name = "windows_aarch64_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a" + [[package]] name = "windows_aarch64_msvc" version = "0.42.0" @@ -3975,6 +4348,12 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +[[package]] +name = "windows_i686_gnu" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1" + [[package]] name = "windows_i686_gnu" version = "0.42.0" @@ -3987,6 +4366,12 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +[[package]] +name = "windows_i686_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c" + [[package]] name = "windows_i686_msvc" version = "0.42.0" @@ -3999,6 +4384,12 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d" + [[package]] name = "windows_x86_64_gnu" version = "0.42.0" @@ -4017,6 +4408,12 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +[[package]] +name = "windows_x86_64_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d" + [[package]] name = "windows_x86_64_msvc" version = "0.42.0" @@ -4112,6 +4509,70 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "zbus" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d8f1a037b2c4a67d9654dc7bdfa8ff2e80555bbefdd3c1833c1d1b27c963a6b" +dependencies = [ + "async-broadcast", + "async-channel", + "async-executor", + "async-io", + "async-lock", + "async-recursion", + "async-task", + "async-trait", + "byteorder 1.4.3", + "derivative", + "dirs", + "enumflags2", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "lazy_static", + "nix 0.23.1", + "once_cell", + "ordered-stream", + "rand", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "winapi", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f8fb5186d1c87ae88cf234974c240671238b4a679158ad3b94ec465237349a6" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "zbus_names" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a408fd8a352695690f53906dc7fd036be924ec51ea5e05666ff42685ed0af5" +dependencies = [ + "serde", + "static_assertions", + "zvariant", +] + [[package]] name = "zeroize" version = "1.5.7" @@ -4129,3 +4590,29 @@ dependencies = [ "crossbeam-utils", "flate2", ] + +[[package]] +name = "zvariant" +version = "3.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794fb7f59af4105697b0449ba31731ee5dbb3e773a17dbdf3d36206ea1b1644" +dependencies = [ + "byteorder 1.4.3", + "enumflags2", + "libc", + "serde", + "static_assertions", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "3.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd58d4b6c8e26d3dd2149c8c40c6613ef6451b9885ff1296d1ac86c388351a54" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] diff --git a/crates/fj-app/src/main.rs b/crates/fj-app/src/main.rs index b89c9cd70..e8ab235a5 100644 --- a/crates/fj-app/src/main.rs +++ b/crates/fj-app/src/main.rs @@ -16,6 +16,7 @@ mod args; mod config; mod path; +use anyhow::{anyhow, Context}; use fj_export::export; use fj_host::Parameters; use fj_operations::shape_processor::ShapeProcessor; @@ -42,18 +43,18 @@ fn main() -> anyhow::Result<()> { let args = Args::parse(); let config = Config::load()?; - let model_path = ModelPath::from_args_and_config(&args, &config)?; + let model_path = ModelPath::from_args_and_config(&args, &config); let parameters = args.parameters.unwrap_or_else(Parameters::empty); let shape_processor = ShapeProcessor { tolerance: args.tolerance, }; - let model = model_path.load_model(parameters)?; + let model = model_path.map(|m| m.load_model(parameters)).transpose()?; if let Some(export_path) = args.export { // export only mode. just load model, process, export and exit - let evaluation = model.evaluate()?; + let evaluation = model.with_context(no_model_error)?.evaluate()?; let shape = shape_processor.process(&evaluation.shape)?; export(&shape.mesh, &export_path)?; @@ -66,3 +67,11 @@ fn main() -> anyhow::Result<()> { Ok(()) } + +fn no_model_error() -> anyhow::Error { + anyhow!( + "You must specify a model to start Fornjot in export only mode.\n\ + - Pass a model as a command-line argument. See `fj-app --help`.\n\ + - Specify a default model in the configuration file." + ) +} diff --git a/crates/fj-app/src/path.rs b/crates/fj-app/src/path.rs index 3fd33d361..5d0a7c02e 100644 --- a/crates/fj-app/src/path.rs +++ b/crates/fj-app/src/path.rs @@ -3,7 +3,7 @@ use std::{ path::{Path, PathBuf}, }; -use anyhow::{anyhow, Context}; +use anyhow::Context; use fj_host::{Model, Parameters}; use crate::{args::Args, config::Config}; @@ -14,10 +14,7 @@ pub struct ModelPath { } impl ModelPath { - pub fn from_args_and_config( - args: &Args, - config: &Config, - ) -> anyhow::Result { + pub fn from_args_and_config(args: &Args, config: &Config) -> Option { let default_path = config.default_path.clone(); let model_path_from_args = args @@ -28,11 +25,9 @@ impl ModelPath { .default_model .as_ref() .map(|model| ModelPathSource::Config(model.clone())); - let model_path = model_path_from_args - .or(model_path_from_config) - .ok_or_else(no_model_error)?; + let model_path = model_path_from_args.or(model_path_from_config)?; - Ok(Self { + Some(Self { default_path, model_path, }) @@ -142,11 +137,3 @@ fn load_error_context_inner( Ok(context) } - -fn no_model_error() -> anyhow::Error { - anyhow!( - "You must specify a model to start Fornjot.\n\ - - Pass a model as a command-line argument. See `fj-app --help`.\n\ - - Specify a default model in the configuration file." - ) -} diff --git a/crates/fj-host/src/host.rs b/crates/fj-host/src/host.rs index 191423c5c..948946468 100644 --- a/crates/fj-host/src/host.rs +++ b/crates/fj-host/src/host.rs @@ -16,7 +16,10 @@ impl Host { pub fn from_model(model: Model) -> Result { let watch_path = model.watch_path(); let evaluator = Evaluator::from_model(model); - let _watcher = Watcher::watch_model(&watch_path, &evaluator)?; + let _watcher = match Watcher::watch_model(&watch_path, &evaluator) { + Ok(_watcher) => _watcher, + Err(e) => return Err(e), + }; Ok(Self { evaluator, diff --git a/crates/fj-viewer/Cargo.toml b/crates/fj-viewer/Cargo.toml index 9c18ed9e9..58b8b6e2f 100644 --- a/crates/fj-viewer/Cargo.toml +++ b/crates/fj-viewer/Cargo.toml @@ -12,6 +12,7 @@ categories.workspace = true [dependencies] bytemuck = "1.12.1" +crossbeam-channel = "0.5.6" egui = "0.19.0" egui-wgpu = "0.19.0" fj-interop.workspace = true @@ -21,6 +22,11 @@ thiserror = "1.0.35" tracing = "0.1.37" wgpu_glyph = "0.17.0" +[dependencies.rfd] +version = "0.10.0" +default_features = false +features = ["xdg-portal"] + [dependencies.wgpu] version = "0.13.1" features = ["webgl"] diff --git a/crates/fj-viewer/src/graphics/renderer.rs b/crates/fj-viewer/src/graphics/renderer.rs index cea4a85ce..4912ab30d 100644 --- a/crates/fj-viewer/src/graphics/renderer.rs +++ b/crates/fj-viewer/src/graphics/renderer.rs @@ -1,5 +1,6 @@ -use std::{io, mem::size_of}; +use std::{io, mem::size_of, path::PathBuf}; +use crossbeam_channel::{Receiver, Sender}; use thiserror::Error; use tracing::debug; use wgpu::util::DeviceExt as _; @@ -171,8 +172,12 @@ impl Renderer { }) } - pub(crate) fn init_gui(&self) -> Gui { - Gui::new(&self.device, self.surface_config.format) + pub(crate) fn init_gui( + &self, + event_rx: Receiver<()>, + event_tx: Sender, + ) -> Gui { + Gui::new(&self.device, self.surface_config.format, event_rx, event_tx) } /// Updates the geometry of the model being rendered. diff --git a/crates/fj-viewer/src/gui.rs b/crates/fj-viewer/src/gui.rs index 056e5b92d..6c1fad6d3 100644 --- a/crates/fj-viewer/src/gui.rs +++ b/crates/fj-viewer/src/gui.rs @@ -14,22 +14,47 @@ //! //! +use std::path::PathBuf; + +#[cfg(not(target_arch = "wasm32"))] +use std::env::current_dir; + +use crossbeam_channel::{Receiver, Sender}; + +#[cfg(not(target_arch = "wasm32"))] +use rfd::FileDialog; + use fj_interop::status_report::StatusReport; use fj_math::{Aabb, Scalar}; use crate::graphics::DrawConfig; +struct GuiState { + has_model: bool, +} + +impl Default for GuiState { + fn default() -> Self { + Self { has_model: true } + } +} + /// The GUI pub struct Gui { context: egui::Context, render_pass: egui_wgpu::renderer::RenderPass, options: Options, + event_rx: Receiver<()>, + event_tx: Sender, + state: GuiState, } impl Gui { pub(crate) fn new( device: &wgpu::Device, texture_format: wgpu::TextureFormat, + event_rx: Receiver<()>, + event_tx: Sender, ) -> Self { // The implementation of the integration with `egui` is likely to need // to change "significantly" depending on what architecture approach is @@ -69,6 +94,9 @@ impl Gui { context, render_pass, options: Default::default(), + event_rx, + event_tx, + state: Default::default(), } } @@ -86,6 +114,23 @@ impl Gui { status: &StatusReport, line_drawing_available: bool, ) { + loop { + let gui_event = self + .event_rx + .try_recv() + .map_err(|err| { + if err.is_disconnected() { + panic!("Expected channel to never disconnect"); + } + }) + .ok(); + + match gui_event { + Some(_) => self.state.has_model = false, + None => break, + }; + } + self.context.set_pixels_per_point(pixels_per_point); self.context.begin_frame(egui_input); @@ -243,6 +288,32 @@ impl Gui { )) }) }); + + if !self.state.has_model { + egui::Area::new("ask-model") + .anchor(egui::Align2::CENTER_CENTER, [0_f32, -5_f32]) + .show(&self.context, |ui| { + ui.vertical_centered(|ui| { + ui.label(egui::RichText::new( + "No model selected please choose a model to view.", + ).color(egui::Color32::BLACK) + .background_color(egui::Color32::WHITE)); + if ui + .button(egui::RichText::new("Pick a model")) + .clicked() + { + let model_dir = show_file_dialog(); + if let Some(model_dir) = model_dir { + self.event_tx + .send(model_dir) + .expect("Channel is disconnected"); + + self.state.has_model = true; + } + } + }) + }); + } } pub(crate) fn draw( @@ -281,6 +352,16 @@ impl Gui { } } +fn show_file_dialog() -> Option { + #[cfg(not(target_arch = "wasm32"))] + return FileDialog::new() + .set_directory(current_dir().unwrap_or_else(|_| PathBuf::from("/"))) + .pick_folder(); + + #[cfg(target_arch = "wasm32")] + todo!("Picking folders does not work on wasm32") +} + impl std::fmt::Debug for Gui { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("Gui {}") diff --git a/crates/fj-viewer/src/viewer.rs b/crates/fj-viewer/src/viewer.rs index 7f53e9d5c..c0520084f 100644 --- a/crates/fj-viewer/src/viewer.rs +++ b/crates/fj-viewer/src/viewer.rs @@ -1,9 +1,13 @@ +use std::path::PathBuf; + use fj_interop::{ processed_shape::ProcessedShape, status_report::StatusReport, }; use fj_math::Aabb; use tracing::warn; +use crossbeam_channel::{Receiver, Sender}; + use crate::{ camera::FocusPoint, gui::Gui, Camera, DrawConfig, InputEvent, InputHandler, NormalizedScreenPosition, Renderer, RendererInitError, Screen, ScreenSize, @@ -38,9 +42,13 @@ pub struct Viewer { impl Viewer { /// Construct a new instance of `Viewer` - pub async fn new(screen: &impl Screen) -> Result { + pub async fn new( + screen: &impl Screen, + event_rx: Receiver<()>, + event_tx: Sender, + ) -> Result { let renderer = Renderer::new(screen).await?; - let gui = renderer.init_gui(); + let gui = renderer.init_gui(event_rx, event_tx); Ok(Self { camera: Camera::default(), diff --git a/crates/fj-window/Cargo.toml b/crates/fj-window/Cargo.toml index 551c4e8ea..684269adb 100644 --- a/crates/fj-window/Cargo.toml +++ b/crates/fj-window/Cargo.toml @@ -15,6 +15,7 @@ fj-host.workspace = true fj-operations.workspace = true fj-viewer.workspace = true fj-interop.workspace = true +crossbeam-channel = "0.5.6" futures = "0.3.25" thiserror = "1.0.35" tracing = "0.1.37" diff --git a/crates/fj-window/src/run.rs b/crates/fj-window/src/run.rs index a47c38ec5..4bc91f38b 100644 --- a/crates/fj-window/src/run.rs +++ b/crates/fj-window/src/run.rs @@ -3,9 +3,9 @@ //! Provides the functionality to create a window and perform basic viewing //! with programmed models. -use std::error; +use std::{error, path::PathBuf}; -use fj_host::{Host, Model, ModelEvent}; +use fj_host::{Host, Model, ModelEvent, Parameters}; use fj_interop::status_report::StatusReport; use fj_operations::shape_processor::ShapeProcessor; use fj_viewer::{ @@ -27,23 +27,31 @@ use crate::window::{self, Window}; /// Initializes a model viewer for a given model and enters its process loop. pub fn run( - model: Model, + model: Option, shape_processor: ShapeProcessor, invert_zoom: bool, ) -> Result<(), Error> { + let (send_gui, gui_event_rx) = crossbeam_channel::bounded::<()>(1); + let (gui_event_tx, recv_gui) = crossbeam_channel::bounded::(1); + let mut status = StatusReport::new(); - let host = Host::from_model(model)?; let event_loop = EventLoop::new(); let window = Window::new(&event_loop)?; - let mut viewer = block_on(Viewer::new(&window))?; - - let events = host.events(); + let mut viewer = + block_on(Viewer::new(&window, gui_event_rx, gui_event_tx))?; let mut held_mouse_button = None; let mut egui_winit_state = egui_winit::State::new(&event_loop); + let mut host = None; + if let Some(model) = model { + host = Some(Host::from_model(model)?); + } else { + send_gui.send(()).expect("Channel is disconnected"); + } + // Only handle resize events once every frame. This filters out spurious // resize events that can lead to wgpu warnings. See this issue for some // context: @@ -53,52 +61,90 @@ pub fn run( event_loop.run(move |event, _, control_flow| { trace!("Handling event: {:?}", event); - loop { - let event = events - .try_recv() - .map_err(|err| { - if err.is_disconnected() { - panic!("Expected channel to never disconnect"); - } - }) - .ok(); + let gui_event = recv_gui + .try_recv() + .map_err(|err| { + if err.is_disconnected() { + panic!("Expected channel to never disconnect"); + } + }) + .ok(); + + if let Some(model_path) = gui_event { + let model = Model::new(model_path, Parameters::empty()).unwrap(); + match Host::from_model(model) { + Ok(new_host) => { + host = Some(new_host); + } + Err(_) => { + status.update_status("Error creating host."); + send_gui.send(()).expect("Channel is disconnected"); + } + } + } - let event = match event { - Some(status_update) => status_update, - None => break, - }; + if let Some(host) = &host { + loop { + let events = host.events(); + let event = events + .try_recv() + .map_err(|err| { + if err.is_disconnected() { + panic!("Expected channel to never disconnect"); + } + }) + .ok(); + + let event = match event { + Some(status_update) => status_update, + None => break, + }; + + match event { + ModelEvent::Evaluation(evaluation) => { + status.update_status(&format!( + "Model compiled successfully in {}!", + evaluation.compile_time + )); + + match shape_processor.process(&evaluation.shape) { + Ok(shape) => { + viewer.handle_shape_update(shape); + } + Err(err) => { + // Can be cleaned up, once `Report` is stable: + // https://doc.rust-lang.org/std/error/struct.Report.html - match event { - ModelEvent::Evaluation(evaluation) => { - status.update_status(&format!( - "Model compiled successfully in {}!", - evaluation.compile_time - )); + println!("Shape processing error: {}", err); - match shape_processor.process(&evaluation.shape) { - Ok(shape) => { - viewer.handle_shape_update(shape); + let mut current_err = &err as &dyn error::Error; + while let Some(err) = current_err.source() { + println!(); + println!("Caused by:"); + println!(" {}", err); + + current_err = err; + } + } } - Err(err) => { - // Can be cleaned up, once `Report` is stable: - // https://doc.rust-lang.org/std/error/struct.Report.html + } - println!("Shape processing error: {}", err); + ModelEvent::Error(err) => { + // Can be cleaned up, once `Report` is stable: + // https://doc.rust-lang.org/std/error/struct.Report.html - let mut current_err = &err as &dyn error::Error; - while let Some(err) = current_err.source() { - println!(); - println!("Caused by:"); - println!(" {}", err); + println!("Error receiving updated shape: {}", err); - current_err = err; - } + let mut current_err = &err as &dyn error::Error; + while let Some(err) = current_err.source() { + println!(); + println!("Caused by:"); + println!(" {}", err); + + current_err = err; } } } - ModelEvent::Error(err) => { - status.update_status(&err.to_string()); - } } }