diff options
| -rw-r--r-- | racer-tracer/config.yml | 2 | ||||
| -rw-r--r-- | racer-tracer/src/config.rs | 32 | ||||
| -rw-r--r-- | racer-tracer/src/image_action.rs | 7 | ||||
| -rw-r--r-- | racer-tracer/src/image_action/png.rs | 1 | ||||
| -rw-r--r-- | racer-tracer/src/image_action/wait_for_signal.rs | 5 | ||||
| -rw-r--r-- | racer-tracer/src/key_inputs.rs | 67 | ||||
| -rw-r--r-- | racer-tracer/src/main.rs | 177 | ||||
| -rw-r--r-- | racer-tracer/src/renderer.rs | 22 | ||||
| -rw-r--r-- | racer-tracer/src/renderer/cpu.rs | 3 | ||||
| -rw-r--r-- | racer-tracer/src/renderer/cpu_scaled.rs | 3 | ||||
| -rw-r--r-- | racer-tracer/src/scene_controller.rs | 37 | ||||
| -rw-r--r-- | racer-tracer/src/scene_controller/interactive.rs | 209 |
12 files changed, 412 insertions, 153 deletions
diff --git a/racer-tracer/config.yml b/racer-tracer/config.yml index e658c1c..e0f42bf 100644 --- a/racer-tracer/config.yml +++ b/racer-tracer/config.yml @@ -23,4 +23,4 @@ loader: image_output_dir: "../" image_action: - SavePng # (SavePng, WaitForSignal) + WaitForSignal # (SavePng, WaitForSignal) diff --git a/racer-tracer/src/config.rs b/racer-tracer/src/config.rs index 3992176..7d28ebe 100644 --- a/racer-tracer/src/config.rs +++ b/racer-tracer/src/config.rs @@ -6,13 +6,13 @@ use structopt::StructOpt; use crate::error::TracerError; -#[derive(Default, Debug, Deserialize)] +#[derive(Default, Clone, Debug, Deserialize)] pub struct Screen { pub height: usize, pub width: usize, } -#[derive(Default, Debug, Deserialize)] +#[derive(Default, Clone, Debug, Deserialize)] pub struct RenderConfigData { pub samples: usize, pub max_depth: usize, @@ -93,6 +93,23 @@ pub enum ImageAction { SavePng, } +#[derive(StructOpt, Debug, Clone, Deserialize, Default)] +pub enum ConfigSceneController { + #[default] + Interactive, +} + +#[derive(StructOpt, Debug, Clone, Deserialize, Default)] +pub enum Renderer { + #[default] + Cpu, + CpuPreview, +} + +fn default_preview_renderer() -> Renderer { + Renderer::CpuPreview +} + impl FromStr for ImageAction { type Err = TracerError; @@ -105,7 +122,7 @@ impl FromStr for ImageAction { } } -#[derive(Default, Debug, Deserialize)] +#[derive(Default, Clone, Debug, Deserialize)] pub struct Config { #[serde(default)] pub preview: RenderConfigData, @@ -124,6 +141,15 @@ pub struct Config { #[serde(default)] pub image_output_dir: Option<PathBuf>, + + #[serde(default)] + pub scene_controller: ConfigSceneController, + + #[serde(default)] + pub renderer: Renderer, + + #[serde(default = "default_preview_renderer")] + pub preview_renderer: Renderer, } impl Config { diff --git a/racer-tracer/src/image_action.rs b/racer-tracer/src/image_action.rs index 3f984a1..9156b6d 100644 --- a/racer-tracer/src/image_action.rs +++ b/racer-tracer/src/image_action.rs @@ -18,6 +18,7 @@ pub trait ImageAction: Send + Sync { fn action( &self, screen_buffer: &RwLock<Vec<u32>>, + cancel_event: &SignalEvent, event: &SignalEvent, config: &Config, log: Logger, @@ -25,11 +26,11 @@ pub trait ImageAction: Send + Sync { ) -> Result<(), TracerError>; } -impl From<&CImageAction> for Box<dyn ImageAction> { +impl From<&CImageAction> for &dyn ImageAction { fn from(image_action: &CImageAction) -> Self { match image_action { - CImageAction::WaitForSignal => Box::new(WaitForSignal {}), - CImageAction::SavePng => Box::new(SavePng {}), + CImageAction::WaitForSignal => &WaitForSignal {} as &dyn ImageAction, + CImageAction::SavePng => &SavePng {} as &dyn ImageAction, } } } diff --git a/racer-tracer/src/image_action/png.rs b/racer-tracer/src/image_action/png.rs index dbed285..5b2bf1a 100644 --- a/racer-tracer/src/image_action/png.rs +++ b/racer-tracer/src/image_action/png.rs @@ -14,6 +14,7 @@ impl ImageAction for SavePng { fn action( &self, screen_buffer: &RwLock<Vec<u32>>, + _cancel_event: &SignalEvent, event: &SignalEvent, config: &Config, log: Logger, diff --git a/racer-tracer/src/image_action/wait_for_signal.rs b/racer-tracer/src/image_action/wait_for_signal.rs index 0ffe5e7..1e31200 100644 --- a/racer-tracer/src/image_action/wait_for_signal.rs +++ b/racer-tracer/src/image_action/wait_for_signal.rs @@ -1,4 +1,4 @@ -use std::sync::RwLock; +use std::{sync::RwLock, time::Duration}; use slog::Logger; use synchronoise::SignalEvent; @@ -17,6 +17,7 @@ impl ImageAction for WaitForSignal { fn action( &self, _screen_buffer: &RwLock<Vec<u32>>, + cancel_event: &SignalEvent, event: &SignalEvent, _config: &Config, _log: Logger, @@ -24,7 +25,7 @@ impl ImageAction for WaitForSignal { ) -> Result<(), TracerError> { if !event.status() { write_term!(term, "Press R to resume."); - event.wait(); + while !event.wait_timeout(Duration::from_secs(1)) && !cancel_event.status() {} } event.reset(); Ok(()) diff --git a/racer-tracer/src/key_inputs.rs b/racer-tracer/src/key_inputs.rs index 1e3505e..9a7bde5 100644 --- a/racer-tracer/src/key_inputs.rs +++ b/racer-tracer/src/key_inputs.rs @@ -5,15 +5,20 @@ use slog::Logger; use crate::error::TracerError; -pub type KeyClosure<'a> = &'a (dyn Fn(f64) -> Result<(), TracerError> + Send + Sync); +pub enum KeyEvent { + Release, + Down, +} -pub struct KeyInputs<'a> { - is_down_callbacks: HashMap<Key, Vec<KeyClosure<'a>>>, - is_released_callbacks: HashMap<Key, Vec<KeyClosure<'a>>>, +type Callback<'func> = Box<dyn Fn(f64) -> Result<(), TracerError> + Send + Sync + 'func>; +pub type KeyCallback<'func> = (KeyEvent, Key, Callback<'func>); +pub struct KeyInputs<'func> { + is_down_callbacks: HashMap<Key, Vec<Callback<'func>>>, + is_released_callbacks: HashMap<Key, Vec<Callback<'func>>>, log: Logger, } -impl<'a> KeyInputs<'a> { +impl<'func, 'window> KeyInputs<'func> { pub fn new(log: Logger) -> Self { KeyInputs { is_down_callbacks: HashMap::new(), @@ -22,35 +27,69 @@ impl<'a> KeyInputs<'a> { } } - pub fn release(&mut self, key: Key, closure: KeyClosure<'a>) { + pub fn input( + event: KeyEvent, + key: Key, + callback: impl Fn(f64) -> Result<(), TracerError> + Send + Sync + 'func, + ) -> KeyCallback<'func> { + (event, key, Box::new(callback)) + } + + pub fn register_inputs(&mut self, inputs: Vec<KeyCallback<'func>>) { + inputs.into_iter().for_each(|(ev, key, closure)| match ev { + KeyEvent::Release => { + let callbacks = self + .is_released_callbacks + .entry(key) + .or_insert_with(Vec::new); + callbacks.push(closure); + } + KeyEvent::Down => { + let callbacks = self.is_down_callbacks.entry(key).or_insert_with(Vec::new); + callbacks.push(closure); + } + }) + } + + #[allow(dead_code)] + pub fn release( + &mut self, + key: Key, + closure: impl Fn(f64) -> Result<(), TracerError> + Send + Sync + 'func, + ) { let callbacks = self .is_released_callbacks .entry(key) .or_insert_with(Vec::new); - callbacks.push(closure); + callbacks.push(Box::new(closure)); } - pub fn down(&mut self, key: Key, closure: KeyClosure<'a>) { + #[allow(dead_code)] + pub fn down( + &mut self, + key: Key, + closure: impl Fn(f64) -> Result<(), TracerError> + Send + Sync + 'func, + ) { let callbacks = self.is_down_callbacks.entry(key).or_insert_with(Vec::new); - callbacks.push(closure); + callbacks.push(Box::new(closure)); } - pub fn update(&mut self, window: &Window, dt: f64) { + pub fn update(&self, window: &'window Window, dt: f64) { self.is_down_callbacks - .iter_mut() + .iter() .filter(|(key, _callbacks)| window.is_key_down(**key)) .for_each(|(_key, callbacks)| { - callbacks.iter_mut().for_each(|callback| { + callbacks.iter().for_each(|callback| { if let Err(e) = callback(dt) { error!(self.log, "Key callback error: {}", e); } }) }); self.is_released_callbacks - .iter_mut() + .iter() .filter(|(key, _callbacks)| window.is_key_released(**key)) .for_each(|(_key, callbacks)| { - callbacks.iter_mut().for_each(|callback| { + callbacks.iter().for_each(|callback| { if let Err(e) = callback(dt) { error!(self.log, "Key callback error: {}", e); } diff --git a/racer-tracer/src/main.rs b/racer-tracer/src/main.rs index f950000..c31f09b 100644 --- a/racer-tracer/src/main.rs +++ b/racer-tracer/src/main.rs @@ -10,6 +10,7 @@ mod material; mod ray; mod renderer; mod scene; +mod scene_controller; mod terminal; mod util; mod vec3; @@ -25,9 +26,7 @@ use std::{ convert::TryFrom, fs::OpenOptions, path::Path, - sync::RwLock, time::{Duration, Instant}, - vec::Vec, }; use minifb::{Key, Window, WindowOptions}; @@ -37,7 +36,7 @@ use synchronoise::SignalEvent; use terminal::Terminal; use crate::{ - renderer::{RenderData, Renderer}, + scene_controller::{interactive::InteractiveScene, SceneController, SceneData}, vec3::Vec3, }; @@ -45,22 +44,16 @@ use crate::{ camera::Camera, config::{Args, Config}, error::TracerError, - image_action::ImageAction, key_inputs::KeyInputs, - renderer::{cpu::CpuRenderer, cpu_scaled::CpuRendererScaled}, scene::Scene, }; fn run(config: Config, log: Logger, term: Terminal) -> Result<(), TracerError> { info!(log, "Starting racer-tracer {}", env!("CARGO_PKG_VERSION")); - let renderer: &dyn Renderer = &CpuRenderer {} as &dyn Renderer; - let renderer_preview: &dyn Renderer = &CpuRendererScaled {} as &dyn Renderer; let image = image::Image::new(config.screen.width, config.screen.height); - let screen_buffer: RwLock<Vec<u32>> = RwLock::new(vec![0; image.width * image.height]); let look_from = Vec3::new(13.0, 2.0, 3.0); let look_at = Vec3::new(0.0, 0.0, 0.0); - let camera_speed = 2.0; - let camera = RwLock::new(Camera::new( + let camera = Camera::new( look_from, look_at, Vec3::new(0.0, 1.0, 0.0), @@ -68,120 +61,42 @@ fn run(config: Config, log: Logger, term: Terminal) -> Result<(), TracerError> { &image, 0.1, 10.0, - )); - + ); let scene = Scene::try_new(&config.loader)?; - let mut window_res: Result<(), TracerError> = Ok(()); let mut render_res: Result<(), TracerError> = Ok(()); - - let render_image = SignalEvent::manual(false); let exit = SignalEvent::manual(false); - let image_action: Box<dyn ImageAction> = (&config.image_action).into(); - - // Setting up controls - let mut key_inputs = KeyInputs::new(log.new(o!("scope" => "key-intputs"))); - let render_image_fn = |_| { - render_image.signal(); - Ok(()) - }; - key_inputs.release(Key::R, &render_image_fn); - - let go_forward = |dt: f64| { - camera - .write() - .map_err(|e| TracerError::KeyError(e.to_string())) - .map(|mut cam| { - cam.go_forward(-dt * camera_speed); - }) - }; - key_inputs.down(Key::W, &go_forward); - - let go_back = |dt: f64| { - camera - .write() - .map_err(|e| TracerError::KeyError(e.to_string())) - .map(|mut cam| { - cam.go_forward(dt * camera_speed); - }) + let scene_controller = { + match &config.scene_controller { + config::ConfigSceneController::Interactive => { + let camera_speed = 0.000002; + InteractiveScene::new( + SceneData { + log: log.new(o!("scope" => "scene-controller")), + term, + config: config.clone(), + scene, + camera, + image: image.clone(), + }, + camera_speed, + ) + } + } }; - key_inputs.down(Key::S, &go_back); - let go_left = |dt: f64| { - camera - .write() - .map_err(|e| TracerError::KeyError(e.to_string())) - .map(|mut cam| { - cam.go_right(-dt * camera_speed); - }) - }; - key_inputs.down(Key::A, &go_left); - - let go_right = |dt: f64| { - camera - .write() - .map_err(|e| TracerError::KeyError(e.to_string())) - .map(|mut cam| { - cam.go_right(dt * camera_speed); - }) - }; - key_inputs.down(Key::D, &go_right); + let mut inputs = KeyInputs::new(log.new(o!("scope" => "key-inputs"))); + inputs.register_inputs(scene_controller.get_inputs()); rayon::scope(|s| { + // Render s.spawn(|_| { while render_res.is_ok() { render_res = (!exit.wait_timeout(Duration::from_secs(0))) .then_some(|| ()) .ok_or(TracerError::ExitEvent) - .and_then(|_| { - render_image - .wait_timeout(Duration::from_secs(0)) - .then_some(|| ()) - .map_or_else( - || { - render_image.reset(); - // Render preview - renderer_preview.render(RenderData { - buffer: &screen_buffer, - camera: &camera, - image: &image, - scene: &scene, - config: &config, - cancel_event: None, - }) - }, - |_| { - render_image.reset(); - let render_time = Instant::now(); - renderer - .render(RenderData { - buffer: &screen_buffer, - camera: &camera, - image: &image, - scene: &scene, - config: &config, - cancel_event: Some(&render_image), - }) - .and_then(|_| { - info!( - log, - "It took {} seconds to render the image.", - Instant::now() - .duration_since(render_time) - .as_secs() - ); - image_action.action( - &screen_buffer, - &render_image, - &config, - log.new(o!("scope" => "image-action")), - &term, - ) - }) - }, - ) - }); + .and_then(|_| scene_controller.render()); } if render_res.is_err() { @@ -189,6 +104,7 @@ fn run(config: Config, log: Logger, term: Terminal) -> Result<(), TracerError> { } }); + // Update s.spawn(|_| { window_res = Window::new( "racer-tracer", @@ -201,27 +117,32 @@ fn run(config: Config, log: Logger, term: Terminal) -> Result<(), TracerError> { window.limit_update_rate(Some(std::time::Duration::from_micros(16600))); window }) - .and_then(|mut window| { + .map(|mut window| { let mut t = Instant::now(); - while window.is_open() && !window.is_key_down(Key::Escape) && !exit.status() { - let dt = t.elapsed().as_micros() as f64 / 1000000.0; + while window_res.is_ok() + && window.is_open() + && !window.is_key_down(Key::Escape) + && !exit.status() + { + let dt = t.elapsed().as_micros() as f64; t = Instant::now(); - key_inputs.update(&window, dt); - // Sleep a bit to not hog the lock on the buffer all the time. - std::thread::sleep(std::time::Duration::from_millis(1)); - - screen_buffer - .read() - .map_err(|e| TracerError::FailedToUpdateWindow(e.to_string())) - .and_then(|buf| { - window - .update_with_buffer(&buf, image.width, image.height) - .map_err(|e| TracerError::FailedToUpdateWindow(e.to_string())) - })? + inputs.update(&window, dt); + + window_res = + scene_controller + .get_buffer() + .and_then(|maybe_buf| match maybe_buf { + Some(buf) => window + .update_with_buffer(&buf, image.width, image.height) + .map_err(|e| TracerError::FailedToUpdateWindow(e.to_string())), + None => { + window.update(); + Ok(()) + } + }); } exit.signal(); - render_image.signal(); - Ok(()) + scene_controller.stop() }); }); }); @@ -265,7 +186,7 @@ fn main() { Err(TracerError::ExitEvent) => {} Ok(_) => {} Err(e) => { - error!(log, "{}", e); + error!(log, "Error: {}", e); let exit_code = i32::from(e); error!(log, "Exiting with: {}", exit_code); std::process::exit(exit_code) diff --git a/racer-tracer/src/renderer.rs b/racer-tracer/src/renderer.rs index 162dc4b..0c351c9 100644 --- a/racer-tracer/src/renderer.rs +++ b/racer-tracer/src/renderer.rs @@ -3,10 +3,18 @@ use std::{sync::RwLock, time::Duration}; use synchronoise::SignalEvent; use crate::{ - camera::Camera, config::Config, error::TracerError, geometry::Hittable, image::Image, ray::Ray, - vec3::Color, vec3::Vec3, + camera::Camera, + config::{Config, Renderer as ConfigRenderer}, + error::TracerError, + geometry::Hittable, + image::Image, + ray::Ray, + vec3::Color, + vec3::Vec3, }; +use self::{cpu::CpuRenderer, cpu_scaled::CpuRendererScaled}; + pub mod cpu; pub mod cpu_scaled; @@ -44,8 +52,18 @@ pub struct RenderData<'a> { pub scene: &'a dyn Hittable, pub config: &'a Config, pub cancel_event: Option<&'a SignalEvent>, + pub buffer_updated: Option<&'a SignalEvent>, } pub trait Renderer: Send + Sync { fn render(&self, render_data: RenderData) -> Result<(), TracerError>; } + +impl From<&ConfigRenderer> for &dyn Renderer { + fn from(r: &ConfigRenderer) -> Self { + match r { + ConfigRenderer::Cpu => &CpuRenderer {} as &dyn Renderer, + ConfigRenderer::CpuPreview => &CpuRendererScaled {} as &dyn Renderer, + } + } +} diff --git a/racer-tracer/src/renderer/cpu.rs b/racer-tracer/src/renderer/cpu.rs index f97ad9c..48e9528 100644 --- a/racer-tracer/src/renderer/cpu.rs +++ b/racer-tracer/src/renderer/cpu.rs @@ -59,6 +59,9 @@ impl CpuRenderer { buf[offset + row * image.screen_width + col] = color; } } + if let Some(updated) = rd.buffer_updated { + updated.signal() + } }) } diff --git a/racer-tracer/src/renderer/cpu_scaled.rs b/racer-tracer/src/renderer/cpu_scaled.rs index 44e73fa..3cbbaab 100644 --- a/racer-tracer/src/renderer/cpu_scaled.rs +++ b/racer-tracer/src/renderer/cpu_scaled.rs @@ -81,6 +81,9 @@ impl CpuRendererScaled { } } } + if let Some(updated) = rd.buffer_updated { + updated.signal() + } }) } } diff --git a/racer-tracer/src/scene_controller.rs b/racer-tracer/src/scene_controller.rs new file mode 100644 index 0000000..4a867f5 --- /dev/null +++ b/racer-tracer/src/scene_controller.rs @@ -0,0 +1,37 @@ +pub mod interactive; + +use slog::Logger; + +use crate::{ + camera::Camera, config::Config, error::TracerError, image::Image, key_inputs::KeyCallback, + scene::Scene, terminal::Terminal, +}; + +pub fn create_screen_buffer(image: &Image) -> Vec<u32> { + vec![0; image.width * image.height] +} + +pub struct SceneData { + pub log: Logger, + pub term: Terminal, + pub config: Config, + pub scene: Scene, + pub camera: Camera, + pub image: Image, +} + +pub trait SceneController: Send + Sync { + // Return a vector of key callbacks. The provided closure will be + // called when the corresponding key is release/pressed. + fn get_inputs(&self) -> Vec<KeyCallback>; + + // Render function + fn render(&self) -> Result<(), TracerError>; + + // Returns the screen buffer produced by the scene controller. + // Returns None if no new buffer is available + fn get_buffer(&self) -> Result<Option<Vec<u32>>, TracerError>; + + // Called when the application wants to exit. + fn stop(&self); +} diff --git a/racer-tracer/src/scene_controller/interactive.rs b/racer-tracer/src/scene_controller/interactive.rs new file mode 100644 index 0000000..4624ba1 --- /dev/null +++ b/racer-tracer/src/scene_controller/interactive.rs @@ -0,0 +1,209 @@ +use std::{ + sync::RwLock, + time::{Duration, Instant}, +}; + +use minifb::Key; +use slog::Logger; +use synchronoise::SignalEvent; + +use crate::{ + camera::Camera, + config::Config, + error::TracerError, + image::Image, + image_action::ImageAction, + key_inputs::{KeyCallback, KeyEvent, KeyInputs}, + renderer::{RenderData, Renderer}, + scene::Scene, + terminal::Terminal, +}; + +use super::{create_screen_buffer, SceneController, SceneData}; + +pub struct InteractiveScene<'renderer, 'action> { + screen_buffer: RwLock<Vec<u32>>, + preview_buffer: RwLock<Vec<u32>>, + camera_speed: f64, + render_image_event: SignalEvent, + buffer_updated: SignalEvent, + stop_event: SignalEvent, + + log: Logger, + term: Terminal, + image_action: &'action dyn ImageAction, + config: Config, + scene: Scene, + camera: RwLock<Camera>, + image: Image, + renderer: &'renderer dyn Renderer, + renderer_preview: &'renderer dyn Renderer, +} + +impl<'renderer, 'action> InteractiveScene<'renderer, 'action> { + pub fn new(scene_data: SceneData, camera_speed: f64) -> Self { + Self { + screen_buffer: RwLock::new(create_screen_buffer(&scene_data.image)), + preview_buffer: RwLock::new(create_screen_buffer(&scene_data.image)), + camera_speed, + render_image_event: SignalEvent::manual(false), + buffer_updated: SignalEvent::manual(false), + stop_event: SignalEvent::manual(false), + + log: scene_data.log, + term: scene_data.term, + image_action: (&scene_data.config.image_action).into(), + scene: scene_data.scene, + camera: RwLock::new(scene_data.camera), + image: scene_data.image, + renderer: (&scene_data.config.renderer).into(), + renderer_preview: (&scene_data.config.preview_renderer).into(), + config: scene_data.config, + } + } +} + +impl<'renderer, 'action> SceneController for InteractiveScene<'renderer, 'action> { + fn get_inputs(&self) -> Vec<KeyCallback> { + vec![ + KeyInputs::input(KeyEvent::Release, Key::R, |_| { + self.render_image_event.signal(); + Ok(()) + }), + KeyInputs::input(KeyEvent::Down, Key::W, |dt| { + self.camera + .write() + .map_err(|e| TracerError::KeyError(e.to_string())) + .map(|mut cam| { + cam.go_forward(-dt * self.camera_speed); + }) + }), + KeyInputs::input(KeyEvent::Down, Key::S, |dt| { + self.camera + .write() + .map_err(|e| TracerError::KeyError(e.to_string())) + .map(|mut cam| { + cam.go_forward(dt * self.camera_speed); + }) + }), + KeyInputs::input(KeyEvent::Down, Key::A, |dt| { + self.camera + .write() + .map_err(|e| TracerError::KeyError(e.to_string())) + .map(|mut cam| { + cam.go_right(-dt * self.camera_speed); + }) + }), + KeyInputs::input(KeyEvent::Down, Key::D, |dt| { + self.camera + .write() + .map_err(|e| TracerError::KeyError(e.to_string())) + .map(|mut cam| { + cam.go_right(dt * self.camera_speed); + }) + }), + ] + } + + fn get_buffer(&self) -> Result<Option<Vec<u32>>, TracerError> { + self.buffer_updated + .wait_timeout(Duration::from_secs(0)) + .then_some(|| ()) + .map_or(Ok(None), |_| { + self.screen_buffer + .read() + .map_err(|e| TracerError::FailedToAcquireLock(e.to_string())) + .map(|v| Some(v.to_owned())) + }) + } + + fn render(&self) -> Result<(), TracerError> { + self.render_image_event + .wait_timeout(Duration::from_secs(0)) + .then_some(|| ()) + .map_or_else( + || { + // Render preview + self.render_image_event.reset(); + + // We do not want partial screen updates for the preview. + // Which is why we send in a different buffer. + self.renderer_preview + .render(RenderData { + buffer: &self.preview_buffer, + camera: &self.camera, + image: &self.image, + scene: &self.scene, + config: &self.config, + cancel_event: None, + buffer_updated: None, + }) + .and_then(|_| { + self.screen_buffer + .write() + .map_err(|e| TracerError::FailedToAcquireLock(e.to_string())) + }) + .and_then(|w_buffer| { + self.preview_buffer + .read() + .map_err(|e| TracerError::FailedToAcquireLock(e.to_string())) + .map(|r_buffer| (r_buffer, w_buffer)) + }) + .map(|(r_buffer, mut w_buffer)| { + // For the preview we want the complete image + // result before signaling the image is done. + *w_buffer = r_buffer.to_owned(); + self.buffer_updated.signal(); + }) + }, + |_| { + let render_time = Instant::now(); + self.render_image_event.reset(); + + // When we render the final image we want partial + // updates to the screen buffer. We send in our + // original screen_buffer and the buffer_updated + // signal. This will ensure that the window will + // get updated with a new buffer as soon as a + // thread finishes writing a block and we get + // partial updates of the rendered image. + self.renderer + .render(RenderData { + buffer: &self.screen_buffer, + camera: &self.camera, + image: &self.image, + scene: &self.scene, + config: &self.config, + cancel_event: Some(&self.render_image_event), + buffer_updated: Some(&self.buffer_updated), + }) + .and_then(|_| { + if !self.render_image_event.status() { + info!( + self.log, + "It took {} seconds to render the image.", + Instant::now().duration_since(render_time).as_secs() + ); + } else { + info!(self.log, "Image render cancelled."); + } + + self.image_action.action( + &self.screen_buffer, + &self.stop_event, + &self.render_image_event, + &self.config, + self.log.new(o!("scope" => "image-action")), + &self.term, + ) + }) + }, + ) + } + + fn stop(&self) { + // If we are currently rendering anything we try to cancel it + self.render_image_event.signal(); + self.stop_event.signal(); + } +} |
