Skip to content

Commit

Permalink
Merge pull request #1286 from erenoku/handle_no_model
Browse files Browse the repository at this point in the history
Handle no model argument being passed
  • Loading branch information
hannobraun authored Oct 30, 2022
2 parents 4a7df1e + e564acb commit 6e3f5b3
Show file tree
Hide file tree
Showing 10 changed files with 707 additions and 74 deletions.
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),
};

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")
}

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

0 comments on commit 6e3f5b3

Please sign in to comment.