Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle no model argument being passed #1286

Merged
merged 7 commits into from
Oct 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
497 changes: 492 additions & 5 deletions Cargo.lock

Large diffs are not rendered by default.

15 changes: 12 additions & 3 deletions crates/fj-app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)?;
Expand All @@ -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."
)
}
21 changes: 4 additions & 17 deletions crates/fj-app/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -14,10 +14,7 @@ pub struct ModelPath {
}

impl ModelPath {
pub fn from_args_and_config(
args: &Args,
config: &Config,
) -> anyhow::Result<Self> {
pub fn from_args_and_config(args: &Args, config: &Config) -> Option<Self> {
let default_path = config.default_path.clone();

let model_path_from_args = args
Expand All @@ -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,
})
Expand Down Expand Up @@ -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."
)
}
5 changes: 4 additions & 1 deletion crates/fj-host/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ impl Host {
pub fn from_model(model: Model) -> Result<Self, Error> {
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),
};
hannobraun marked this conversation as resolved.
Show resolved Hide resolved

Ok(Self {
evaluator,
Expand Down
6 changes: 6 additions & 0 deletions crates/fj-viewer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"]
Expand Down
11 changes: 8 additions & 3 deletions crates/fj-viewer/src/graphics/renderer.rs
Original file line number Diff line number Diff line change
@@ -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 _;
Expand Down Expand Up @@ -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<PathBuf>,
) -> Gui {
Gui::new(&self.device, self.surface_config.format, event_rx, event_tx)
}

/// Updates the geometry of the model being rendered.
Expand Down
81 changes: 81 additions & 0 deletions crates/fj-viewer/src/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,47 @@
//!
//! <https://github.com/gfx-rs/wgpu/issues/1492>
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<PathBuf>,
state: GuiState,
}

impl Gui {
pub(crate) fn new(
device: &wgpu::Device,
texture_format: wgpu::TextureFormat,
event_rx: Receiver<()>,
event_tx: Sender<PathBuf>,
) -> Self {
// The implementation of the integration with `egui` is likely to need
// to change "significantly" depending on what architecture approach is
Expand Down Expand Up @@ -69,6 +94,9 @@ impl Gui {
context,
render_pass,
options: Default::default(),
event_rx,
event_tx,
state: Default::default(),
}
}

Expand All @@ -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);

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -281,6 +352,16 @@ impl Gui {
}
}

fn show_file_dialog() -> Option<PathBuf> {
#[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")
Comment on lines +361 to +362
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This (and the other cfgs) aren't great, but I can't think of a better way to do it right now. Maybe the file picking feature should move out of fj-viewer and into fj-window or fj-app? No idea. We'll figure it out at some point!

}

impl std::fmt::Debug for Gui {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Gui {}")
Expand Down
12 changes: 10 additions & 2 deletions crates/fj-viewer/src/viewer.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -38,9 +42,13 @@ pub struct Viewer {

impl Viewer {
/// Construct a new instance of `Viewer`
pub async fn new(screen: &impl Screen) -> Result<Self, RendererInitError> {
pub async fn new(
screen: &impl Screen,
event_rx: Receiver<()>,
event_tx: Sender<PathBuf>,
) -> Result<Self, RendererInitError> {
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(),
Expand Down
1 change: 1 addition & 0 deletions crates/fj-window/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Loading