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