1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
//! # Crate ray_tracing_show_image
//!
//! GitHub page [rabbid76.github.io/ray-tracing-with-rust](https://rabbid76.github.io/ray-tracing-with-rust/)
//! GitHub repository [Rabbid76/ray-tracing-with-rust](https://github.com/Rabbid76/ray-tracing-with-rust)
//!
//! A very simple viewer of ray tracing progress
//!
//! Shows the ray tracing progress in a window. The window is updated every second.
//! When "F1" is pressed, a callback is invoked with the intermediate rendering result.
//! This can be used to save the rendering.
//! The returned image is in RGB format and is stored in a tightly packed `Vec<u8>` object.
//!
//! # Examples
//!
//! ```rust
//! use ray_tracing_core::test::TestSceneSimple;
//! use ray_tracing_utility::view;
//! use ray_tracing_utility::view::{Viewer, ViewModel};
//! use std::error::Error;
//! use std::sync::Arc;
//!
//! #[show_image::main]
//! fn main() -> Result<(), Box<dyn Error>> {
//! let view_model = ViewModel {
//! cx: 400,
//! cy: 200,
//! repetitions_threads: 2,
//! repetitions: 5,
//! samples: 2,
//! };
//! let window = ray_tracing_show_image::ShowImageWindow::new(view_model.cx, view_model.cy);
//! let mut viewer = Viewer::new(
//! view_model,
//! Arc::new(TestSceneSimple::new().scene),
//! window.clone(),
//! Box::new(|image_number, cx, cy, pixel_data| {
//!
//! // Save the intermediate rendering here ...
//! }),
//! )?;
//!
//! match viewer.run() {
//! Ok((cx, cy, pixel_data)) => {
//!
//! // Save the final rendering here ...
//! }
//! _ => (),
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! ![TestSceneSimple_800x400_10000_samples](https://raw.githubusercontent.com/Rabbid76/ray-tracing-with-rust/main/rendering/TestSceneSimple_800x400_10000_samples.png)
use ray_tracing_utility::view;
use show_image::event;
use show_image::{ImageInfo, ImageView, WindowOptions, WindowProxy};
use std::error::Error;
use std::rc::Rc;
use std::sync::mpsc::Receiver;
use std::sync::Arc;
pub struct ShowImageWindow {
cx: usize,
cy: usize,
window: WindowProxy,
event_channel: Rc<Receiver<event::WindowEvent>>,
}
impl ShowImageWindow {
pub fn new(cx: usize, cy: usize) -> Arc<dyn view::View> {
let window_options = WindowOptions {
preserve_aspect_ratio: true,
background_color: show_image::Color::rgb(0.0, 0.0, 0.0),
start_hidden: false,
size: Some([cx as u32, cy as u32]),
resizable: false,
borderless: false,
overlays_visible: false,
default_controls: false,
};
let window = show_image::create_window("ray trace", window_options).unwrap();
let event_channel = Rc::new(window.event_channel().unwrap());
Arc::new(ShowImageWindow {
cx,
cy,
window,
event_channel,
})
}
fn handle_event(&self, event: event::WindowEvent) -> Result<view::Event, Box<dyn Error>> {
if let event::WindowEvent::CloseRequested(_) = event {
println!("window closed");
return Ok(view::Event::Close);
}
if let event::WindowEvent::KeyboardInput(event) = event {
if event.input.state.is_pressed() {
if event.input.key_code == Some(event::VirtualKeyCode::Escape) {
println!("ESC");
return Ok(view::Event::Close);
}
if event.input.key_code == Some(event::VirtualKeyCode::F1) {
return Ok(view::Event::Save);
}
}
}
Ok(view::Event::None)
}
pub fn event_loop(&self) -> Result<view::Event, Box<dyn Error>> {
// Print keyboard events until Escape is pressed, then exit.
// If the user closes the window, the channel is closed and the loop also exits.
for event in self.window.event_channel().unwrap() {
match self.handle_event(event) {
Ok(event) => {
if event != view::Event::None {
return Ok(event);
}
}
Err(_) => break,
}
}
Err("error".into())
}
}
impl view::View for ShowImageWindow {
fn update(&self, pixel_data: &Vec<u8>) -> Result<(), Box<dyn Error>> {
let image = ImageView::new(ImageInfo::rgba8(self.cx as u32, self.cy as u32), pixel_data);
self.window.set_image("image-001", image)?;
Ok(())
}
fn handle_events(&self) -> Result<view::Event, Box<dyn Error>> {
match self.event_channel.try_recv() {
Ok(event) => self.handle_event(event),
_ => Ok(view::Event::None),
}
}
}