diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index ac6f1d771..25ae84250 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -144,4 +144,5 @@ jobs: --crate ../fj-kernel \ --crate ../fj-math \ --crate ../fj-operations \ + --crate ../fj-viewer \ --crate ../fj diff --git a/Cargo.lock b/Cargo.lock index e5611164b..660d0fb11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -694,26 +694,17 @@ name = "fj-app" version = "0.5.0" dependencies = [ "anyhow", - "bytemuck", "clap", "figment", "fj", "fj-export", "fj-host", - "fj-interop", "fj-kernel", "fj-math", "fj-operations", - "futures", - "nalgebra", - "parry3d-f64", + "fj-viewer", "serde", - "thiserror", - "tracing", "tracing-subscriber", - "wgpu", - "wgpu_glyph", - "winit", ] [[package]] @@ -786,6 +777,25 @@ dependencies = [ "parry3d-f64", ] +[[package]] +name = "fj-viewer" +version = "0.5.0" +dependencies = [ + "bytemuck", + "fj-host", + "fj-interop", + "fj-math", + "fj-operations", + "futures", + "nalgebra", + "parry3d-f64", + "thiserror", + "tracing", + "wgpu", + "wgpu_glyph", + "winit", +] + [[package]] name = "flate2" version = "1.0.22" diff --git a/Cargo.toml b/Cargo.toml index 8cff3f60c..846e2fa61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ members = [ "fj-kernel", "fj-math", "fj-operations", + "fj-viewer", "models/cuboid", "models/group", @@ -25,4 +26,5 @@ default-members = [ "fj-kernel", "fj-math", "fj-operations", + "fj-viewer", ] diff --git a/fj-app/Cargo.toml b/fj-app/Cargo.toml index 63ad7538c..6fad6b3cd 100644 --- a/fj-app/Cargo.toml +++ b/fj-app/Cargo.toml @@ -13,15 +13,6 @@ categories = ["mathematics", "rendering"] [dependencies] anyhow = "1.0.56" -bytemuck = "1.9.1" -futures = "0.3.21" -nalgebra = "0.30.0" -parry3d-f64 = "0.8.0" -thiserror = "1.0.30" -tracing = "0.1.33" -wgpu = "0.12.0" -wgpu_glyph = "0.16.0" -winit = "0.26.1" [dependencies.clap] version = "3.1.8" @@ -43,10 +34,6 @@ path = "../fj-export" version = "0.5.0" path = "../fj-host" -[dependencies.fj-interop] -version = "0.5.0" -path = "../fj-interop" - [dependencies.fj-kernel] version = "0.5.0" path = "../fj-kernel" @@ -59,6 +46,10 @@ path = "../fj-math" version = "0.5.0" path = "../fj-operations" +[dependencies.fj-viewer] +version = "0.5.0" +path = "../fj-viewer" + [dependencies.serde] version = "1.0.136" features = ["derive"] diff --git a/fj-app/src/main.rs b/fj-app/src/main.rs index 9e770c87e..a252070c8 100644 --- a/fj-app/src/main.rs +++ b/fj-app/src/main.rs @@ -1,33 +1,17 @@ mod args; -mod camera; mod config; -mod graphics; -mod input; -mod window; use std::path::PathBuf; -use std::time::Instant; use anyhow::anyhow; use fj_export::export; use fj_host::{Model, Parameters}; use fj_operations::shape_processor::ShapeProcessor; -use futures::executor::block_on; -use tracing::{trace, warn}; +use fj_viewer::run::run; use tracing_subscriber::fmt::format; use tracing_subscriber::EnvFilter; -use winit::{ - event::{Event, WindowEvent}, - event_loop::{ControlFlow, EventLoop}, -}; -use crate::{ - args::Args, - camera::Camera, - config::Config, - graphics::{DrawConfig, Renderer}, - window::Window, -}; +use crate::{args::Args, config::Config}; fn main() -> anyhow::Result<()> { // Respect `RUST_LOG`. If that's not defined or erroneous, log warnings and @@ -72,133 +56,7 @@ fn main() -> anyhow::Result<()> { } let watcher = model.load_and_watch(parameters)?; + run(watcher, shape_processor)?; - let event_loop = EventLoop::new(); - let window = Window::new(&event_loop); - - let mut previous_time = Instant::now(); - - let mut input_handler = input::Handler::new(previous_time); - let mut renderer = block_on(Renderer::new(&window))?; - - let mut draw_config = DrawConfig::default(); - - let mut shape = None; - let mut camera = None; - - event_loop.run(move |event, _, control_flow| { - trace!("Handling event: {:?}", event); - - let mut actions = input::Actions::new(); - - let now = Instant::now(); - - if let Some(new_shape) = watcher.receive() { - let new_shape = shape_processor.process(&new_shape); - renderer.update_geometry( - (&new_shape.mesh).into(), - (&new_shape.debug_info).into(), - new_shape.aabb, - ); - - if camera.is_none() { - camera = Some(Camera::new(&new_shape.aabb)); - } - - shape = Some(new_shape); - } - - match event { - Event::WindowEvent { - event: WindowEvent::CloseRequested, - .. - } => { - *control_flow = ControlFlow::Exit; - } - Event::WindowEvent { - event: WindowEvent::Resized(size), - .. - } => { - renderer.handle_resize(size); - } - Event::WindowEvent { - event: WindowEvent::KeyboardInput { input, .. }, - .. - } => { - input_handler.handle_keyboard_input(input, &mut actions); - } - Event::WindowEvent { - event: WindowEvent::CursorMoved { position, .. }, - .. - } => { - if let Some(camera) = &mut camera { - input_handler - .handle_cursor_moved(position, camera, &window); - } - } - Event::WindowEvent { - event: WindowEvent::MouseInput { state, button, .. }, - .. - } => { - if let (Some(shape), Some(camera)) = (&shape, &camera) { - let focus_point = camera.focus_point( - &window, - input_handler.cursor(), - &shape.mesh, - ); - - input_handler.handle_mouse_input( - button, - state, - focus_point, - ); - } - } - Event::WindowEvent { - event: WindowEvent::MouseWheel { delta, .. }, - .. - } => { - input_handler.handle_mouse_wheel(delta, now); - } - Event::MainEventsCleared => { - let delta_t = now.duration_since(previous_time); - previous_time = now; - - if let (Some(shape), Some(camera)) = (&shape, &mut camera) { - input_handler.update( - delta_t.as_secs_f64(), - now, - camera, - &window, - &shape.mesh, - ); - } - - window.inner().request_redraw(); - } - Event::RedrawRequested(_) => { - if let (Some(shape), Some(camera)) = (&shape, &mut camera) { - camera.update_planes(&shape.aabb); - - if let Err(err) = renderer.draw(camera, &draw_config) { - warn!("Draw error: {}", err); - } - } - } - _ => {} - } - - if actions.exit { - *control_flow = ControlFlow::Exit; - } - if actions.toggle_model { - draw_config.draw_model = !draw_config.draw_model; - } - if actions.toggle_mesh { - draw_config.draw_mesh = !draw_config.draw_mesh; - } - if actions.toggle_debug { - draw_config.draw_debug = !draw_config.draw_debug; - } - }); + Ok(()) } diff --git a/fj-viewer/Cargo.toml b/fj-viewer/Cargo.toml new file mode 100644 index 000000000..f3bbde29c --- /dev/null +++ b/fj-viewer/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "fj-viewer" +version = "0.5.0" +edition = "2021" + +description = "The world needs another CAD program." +readme = "../README.md" +repository = "https://github.com/hannobraun/fornjot" +license = "0BSD" +keywords = ["cad", "programmatic", "code-cad"] +categories = ["rendering"] + + +[dependencies] +bytemuck = "1.9.1" +futures = "0.3.21" +nalgebra = "0.30.0" +parry3d-f64 = "0.8.0" +thiserror = "1.0.30" +tracing = "0.1.33" +wgpu = "0.12.0" +wgpu_glyph = "0.16.0" +winit = "0.26.1" + +[dependencies.fj-host] +version = "0.5.0" +path = "../fj-host" + +[dependencies.fj-interop] +version = "0.5.0" +path = "../fj-interop" + +[dependencies.fj-math] +version = "0.5.0" +path = "../fj-math" + +[dependencies.fj-operations] +version = "0.5.0" +path = "../fj-operations" diff --git a/fj-app/src/camera.rs b/fj-viewer/src/camera.rs similarity index 100% rename from fj-app/src/camera.rs rename to fj-viewer/src/camera.rs diff --git a/fj-app/src/graphics/config_ui.rs b/fj-viewer/src/graphics/config_ui.rs similarity index 100% rename from fj-app/src/graphics/config_ui.rs rename to fj-viewer/src/graphics/config_ui.rs diff --git a/fj-app/src/graphics/draw_config.rs b/fj-viewer/src/graphics/draw_config.rs similarity index 100% rename from fj-app/src/graphics/draw_config.rs rename to fj-viewer/src/graphics/draw_config.rs diff --git a/fj-app/src/graphics/drawables.rs b/fj-viewer/src/graphics/drawables.rs similarity index 100% rename from fj-app/src/graphics/drawables.rs rename to fj-viewer/src/graphics/drawables.rs diff --git a/fj-app/src/graphics/fonts/B612-Bold.ttf b/fj-viewer/src/graphics/fonts/B612-Bold.ttf similarity index 100% rename from fj-app/src/graphics/fonts/B612-Bold.ttf rename to fj-viewer/src/graphics/fonts/B612-Bold.ttf diff --git a/fj-app/src/graphics/fonts/B612-BoldItalic.ttf b/fj-viewer/src/graphics/fonts/B612-BoldItalic.ttf similarity index 100% rename from fj-app/src/graphics/fonts/B612-BoldItalic.ttf rename to fj-viewer/src/graphics/fonts/B612-BoldItalic.ttf diff --git a/fj-app/src/graphics/fonts/B612-Italic.ttf b/fj-viewer/src/graphics/fonts/B612-Italic.ttf similarity index 100% rename from fj-app/src/graphics/fonts/B612-Italic.ttf rename to fj-viewer/src/graphics/fonts/B612-Italic.ttf diff --git a/fj-app/src/graphics/fonts/B612-Regular.ttf b/fj-viewer/src/graphics/fonts/B612-Regular.ttf similarity index 100% rename from fj-app/src/graphics/fonts/B612-Regular.ttf rename to fj-viewer/src/graphics/fonts/B612-Regular.ttf diff --git a/fj-app/src/graphics/fonts/B612Mono-Bold.ttf b/fj-viewer/src/graphics/fonts/B612Mono-Bold.ttf similarity index 100% rename from fj-app/src/graphics/fonts/B612Mono-Bold.ttf rename to fj-viewer/src/graphics/fonts/B612Mono-Bold.ttf diff --git a/fj-app/src/graphics/fonts/B612Mono-BoldItalic.ttf b/fj-viewer/src/graphics/fonts/B612Mono-BoldItalic.ttf similarity index 100% rename from fj-app/src/graphics/fonts/B612Mono-BoldItalic.ttf rename to fj-viewer/src/graphics/fonts/B612Mono-BoldItalic.ttf diff --git a/fj-app/src/graphics/fonts/B612Mono-Italic.ttf b/fj-viewer/src/graphics/fonts/B612Mono-Italic.ttf similarity index 100% rename from fj-app/src/graphics/fonts/B612Mono-Italic.ttf rename to fj-viewer/src/graphics/fonts/B612Mono-Italic.ttf diff --git a/fj-app/src/graphics/fonts/B612Mono-Regular.ttf b/fj-viewer/src/graphics/fonts/B612Mono-Regular.ttf similarity index 100% rename from fj-app/src/graphics/fonts/B612Mono-Regular.ttf rename to fj-viewer/src/graphics/fonts/B612Mono-Regular.ttf diff --git a/fj-app/src/graphics/fonts/OFL.txt b/fj-viewer/src/graphics/fonts/OFL.txt similarity index 100% rename from fj-app/src/graphics/fonts/OFL.txt rename to fj-viewer/src/graphics/fonts/OFL.txt diff --git a/fj-app/src/graphics/geometries.rs b/fj-viewer/src/graphics/geometries.rs similarity index 100% rename from fj-app/src/graphics/geometries.rs rename to fj-viewer/src/graphics/geometries.rs diff --git a/fj-app/src/graphics/mod.rs b/fj-viewer/src/graphics/mod.rs similarity index 85% rename from fj-app/src/graphics/mod.rs rename to fj-viewer/src/graphics/mod.rs index 9e952ff81..573680aa4 100644 --- a/fj-app/src/graphics/mod.rs +++ b/fj-viewer/src/graphics/mod.rs @@ -11,7 +11,7 @@ mod vertices; pub use self::{ draw_config::DrawConfig, - renderer::{DrawError, Renderer}, + renderer::{DrawError, InitError, Renderer}, }; const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; diff --git a/fj-app/src/graphics/pipelines.rs b/fj-viewer/src/graphics/pipelines.rs similarity index 100% rename from fj-app/src/graphics/pipelines.rs rename to fj-viewer/src/graphics/pipelines.rs diff --git a/fj-app/src/graphics/renderer.rs b/fj-viewer/src/graphics/renderer.rs similarity index 100% rename from fj-app/src/graphics/renderer.rs rename to fj-viewer/src/graphics/renderer.rs diff --git a/fj-app/src/graphics/shader.wgsl b/fj-viewer/src/graphics/shader.wgsl similarity index 100% rename from fj-app/src/graphics/shader.wgsl rename to fj-viewer/src/graphics/shader.wgsl diff --git a/fj-app/src/graphics/shaders.rs b/fj-viewer/src/graphics/shaders.rs similarity index 100% rename from fj-app/src/graphics/shaders.rs rename to fj-viewer/src/graphics/shaders.rs diff --git a/fj-app/src/graphics/transform.rs b/fj-viewer/src/graphics/transform.rs similarity index 100% rename from fj-app/src/graphics/transform.rs rename to fj-viewer/src/graphics/transform.rs diff --git a/fj-app/src/graphics/uniforms.rs b/fj-viewer/src/graphics/uniforms.rs similarity index 100% rename from fj-app/src/graphics/uniforms.rs rename to fj-viewer/src/graphics/uniforms.rs diff --git a/fj-app/src/graphics/vertices.rs b/fj-viewer/src/graphics/vertices.rs similarity index 100% rename from fj-app/src/graphics/vertices.rs rename to fj-viewer/src/graphics/vertices.rs diff --git a/fj-app/src/input/handler.rs b/fj-viewer/src/input/handler.rs similarity index 96% rename from fj-app/src/input/handler.rs rename to fj-viewer/src/input/handler.rs index 42eca7824..3e28f1795 100644 --- a/fj-app/src/input/handler.rs +++ b/fj-viewer/src/input/handler.rs @@ -133,6 +133,7 @@ impl Handler { } } +#[derive(Default)] pub struct Actions { pub exit: bool, @@ -143,12 +144,6 @@ pub struct Actions { impl Actions { pub fn new() -> Self { - Self { - exit: false, - - toggle_model: false, - toggle_mesh: false, - toggle_debug: false, - } + Self::default() } } diff --git a/fj-app/src/input/mod.rs b/fj-viewer/src/input/mod.rs similarity index 100% rename from fj-app/src/input/mod.rs rename to fj-viewer/src/input/mod.rs diff --git a/fj-app/src/input/movement.rs b/fj-viewer/src/input/movement.rs similarity index 100% rename from fj-app/src/input/movement.rs rename to fj-viewer/src/input/movement.rs diff --git a/fj-app/src/input/rotation.rs b/fj-viewer/src/input/rotation.rs similarity index 100% rename from fj-app/src/input/rotation.rs rename to fj-viewer/src/input/rotation.rs diff --git a/fj-app/src/input/zoom.rs b/fj-viewer/src/input/zoom.rs similarity index 100% rename from fj-app/src/input/zoom.rs rename to fj-viewer/src/input/zoom.rs diff --git a/fj-viewer/src/lib.rs b/fj-viewer/src/lib.rs new file mode 100644 index 000000000..672937437 --- /dev/null +++ b/fj-viewer/src/lib.rs @@ -0,0 +1,5 @@ +pub mod camera; +pub mod graphics; +pub mod input; +pub mod run; +pub mod window; diff --git a/fj-viewer/src/run.rs b/fj-viewer/src/run.rs new file mode 100644 index 000000000..1d5551ea7 --- /dev/null +++ b/fj-viewer/src/run.rs @@ -0,0 +1,151 @@ +use std::time::Instant; + +use fj_host::Watcher; +use fj_operations::shape_processor::ShapeProcessor; +use futures::executor::block_on; +use tracing::{trace, warn}; +use winit::{ + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, +}; + +use crate::{ + camera::Camera, + graphics::{self, DrawConfig, Renderer}, + input, + window::Window, +}; + +pub fn run( + watcher: Watcher, + shape_processor: ShapeProcessor, +) -> Result<(), graphics::InitError> { + let event_loop = EventLoop::new(); + let window = Window::new(&event_loop); + + let mut previous_time = Instant::now(); + + let mut input_handler = input::Handler::new(previous_time); + let mut renderer = block_on(Renderer::new(&window))?; + + let mut draw_config = DrawConfig::default(); + + let mut shape = None; + let mut camera = None; + + event_loop.run(move |event, _, control_flow| { + trace!("Handling event: {:?}", event); + + let mut actions = input::Actions::new(); + + let now = Instant::now(); + + if let Some(new_shape) = watcher.receive() { + let new_shape = shape_processor.process(&new_shape); + renderer.update_geometry( + (&new_shape.mesh).into(), + (&new_shape.debug_info).into(), + new_shape.aabb, + ); + + if camera.is_none() { + camera = Some(Camera::new(&new_shape.aabb)); + } + + shape = Some(new_shape); + } + + match event { + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => { + *control_flow = ControlFlow::Exit; + } + Event::WindowEvent { + event: WindowEvent::Resized(size), + .. + } => { + renderer.handle_resize(size); + } + Event::WindowEvent { + event: WindowEvent::KeyboardInput { input, .. }, + .. + } => { + input_handler.handle_keyboard_input(input, &mut actions); + } + Event::WindowEvent { + event: WindowEvent::CursorMoved { position, .. }, + .. + } => { + if let Some(camera) = &mut camera { + input_handler + .handle_cursor_moved(position, camera, &window); + } + } + Event::WindowEvent { + event: WindowEvent::MouseInput { state, button, .. }, + .. + } => { + if let (Some(shape), Some(camera)) = (&shape, &camera) { + let focus_point = camera.focus_point( + &window, + input_handler.cursor(), + &shape.mesh, + ); + + input_handler.handle_mouse_input( + button, + state, + focus_point, + ); + } + } + Event::WindowEvent { + event: WindowEvent::MouseWheel { delta, .. }, + .. + } => { + input_handler.handle_mouse_wheel(delta, now); + } + Event::MainEventsCleared => { + let delta_t = now.duration_since(previous_time); + previous_time = now; + + if let (Some(shape), Some(camera)) = (&shape, &mut camera) { + input_handler.update( + delta_t.as_secs_f64(), + now, + camera, + &window, + &shape.mesh, + ); + } + + window.inner().request_redraw(); + } + Event::RedrawRequested(_) => { + if let (Some(shape), Some(camera)) = (&shape, &mut camera) { + camera.update_planes(&shape.aabb); + + if let Err(err) = renderer.draw(camera, &draw_config) { + warn!("Draw error: {}", err); + } + } + } + _ => {} + } + + if actions.exit { + *control_flow = ControlFlow::Exit; + } + if actions.toggle_model { + draw_config.draw_model = !draw_config.draw_model; + } + if actions.toggle_mesh { + draw_config.draw_mesh = !draw_config.draw_mesh; + } + if actions.toggle_debug { + draw_config.draw_debug = !draw_config.draw_debug; + } + }); +} diff --git a/fj-app/src/window.rs b/fj-viewer/src/window.rs similarity index 100% rename from fj-app/src/window.rs rename to fj-viewer/src/window.rs