mirror of
https://github.com/CrispyPin/julia-fractal-renderer.git
synced 2024-11-22 10:00:26 +01:00
export renders in separate thread
This commit is contained in:
parent
67168f919a
commit
c5b961a33a
1 changed files with 87 additions and 25 deletions
112
src/main.rs
112
src/main.rs
|
@ -3,6 +3,8 @@ use std::{
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io::Write,
|
io::Write,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
sync::mpsc::{self, Receiver, Sender},
|
||||||
|
thread::{self, JoinHandle},
|
||||||
time::SystemTime,
|
time::SystemTime,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,6 +53,19 @@ struct JuliaGUI {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
settings_changed: bool,
|
settings_changed: bool,
|
||||||
preview_point: bool,
|
preview_point: bool,
|
||||||
|
#[serde(skip)]
|
||||||
|
render_thread_handle: Option<JoinHandle<()>>,
|
||||||
|
#[serde(skip)]
|
||||||
|
render_thread: Option<Sender<RenderJob>>,
|
||||||
|
#[serde(skip)]
|
||||||
|
render_result: Option<Receiver<f64>>,
|
||||||
|
#[serde(skip)]
|
||||||
|
waiting: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RenderJob {
|
||||||
|
Render(PathBuf, RenderOptions, (u8, u8, u8)),
|
||||||
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for JuliaGUI {
|
impl Default for JuliaGUI {
|
||||||
|
@ -65,7 +80,11 @@ impl Default for JuliaGUI {
|
||||||
export_iterations: 512,
|
export_iterations: 512,
|
||||||
export_path: "".into(),
|
export_path: "".into(),
|
||||||
settings_changed: true,
|
settings_changed: true,
|
||||||
preview_point: true,
|
preview_point: false,
|
||||||
|
render_thread_handle: None,
|
||||||
|
render_thread: None,
|
||||||
|
render_result: None,
|
||||||
|
waiting: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,9 +103,34 @@ impl JuliaGUI {
|
||||||
TextureOptions::default(),
|
TextureOptions::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let (job_sender, job_receiver) = mpsc::channel::<RenderJob>();
|
||||||
|
let (result_sender, result_receiver) = mpsc::channel::<f64>();
|
||||||
|
let render_thread = thread::Builder::new()
|
||||||
|
.name("render".into())
|
||||||
|
.spawn(move || loop {
|
||||||
|
if let Ok(job) = job_receiver.recv() {
|
||||||
|
match job {
|
||||||
|
RenderJob::Exit => break,
|
||||||
|
RenderJob::Render(path, options, color) => {
|
||||||
|
let start_time = SystemTime::now();
|
||||||
|
let image = render(&options, color);
|
||||||
|
if let Err(err) = image.save(&path) {
|
||||||
|
println!("Failed to save render: {err}");
|
||||||
|
}
|
||||||
|
let time = start_time.elapsed().unwrap().as_micros() as f64 / 1000.0;
|
||||||
|
result_sender.send(time).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
n.preview = Some(preview);
|
n.preview = Some(preview);
|
||||||
n.settings_changed = true;
|
n.settings_changed = true;
|
||||||
n.export_path = "julia_fractal.png".into();
|
n.export_path = "julia_fractal.png".into();
|
||||||
|
n.render_thread_handle = Some(render_thread);
|
||||||
|
n.render_thread = Some(job_sender);
|
||||||
|
n.render_result = Some(result_receiver);
|
||||||
n
|
n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,20 +160,25 @@ impl JuliaGUI {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn export_render(&mut self) {
|
fn export_render(&mut self) {
|
||||||
let start_time = SystemTime::now();
|
|
||||||
let res_mul = 1 << self.export_res_power;
|
|
||||||
let settings = RenderOptions {
|
|
||||||
width: self.render_options.width * res_mul,
|
|
||||||
height: self.render_options.height * res_mul,
|
|
||||||
max_iterations: self.export_iterations,
|
|
||||||
..self.render_options.clone()
|
|
||||||
};
|
|
||||||
let image = render(&settings, self.color);
|
|
||||||
if let Err(err) = image.save(&self.export_path) {
|
|
||||||
println!("Error exporting render: {err}");
|
|
||||||
}
|
|
||||||
self.export_render_ms = Some(start_time.elapsed().unwrap().as_micros() as f64 / 1000.0);
|
|
||||||
self.save_settings();
|
self.save_settings();
|
||||||
|
if let Some(channel) = &self.render_thread {
|
||||||
|
let res_mul = 1 << self.export_res_power;
|
||||||
|
let settings = RenderOptions {
|
||||||
|
width: self.render_options.width * res_mul,
|
||||||
|
height: self.render_options.height * res_mul,
|
||||||
|
max_iterations: self.export_iterations,
|
||||||
|
..self.render_options.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
channel
|
||||||
|
.send(RenderJob::Render(
|
||||||
|
self.export_path.clone(),
|
||||||
|
settings,
|
||||||
|
self.color,
|
||||||
|
))
|
||||||
|
.expect("failed to start render job");
|
||||||
|
self.waiting = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn export_render_new_path(&mut self) {
|
fn export_render_new_path(&mut self) {
|
||||||
|
@ -152,6 +201,11 @@ impl eframe::App for JuliaGUI {
|
||||||
self.settings_changed = false;
|
self.settings_changed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(result) = self.render_result.as_mut().and_then(|r| r.try_recv().ok()) {
|
||||||
|
self.export_render_ms = Some(result);
|
||||||
|
self.waiting = false;
|
||||||
|
}
|
||||||
|
|
||||||
egui::SidePanel::left("main_left_panel")
|
egui::SidePanel::left("main_left_panel")
|
||||||
.resizable(false)
|
.resizable(false)
|
||||||
.exact_width(200.0)
|
.exact_width(200.0)
|
||||||
|
@ -280,19 +334,23 @@ impl eframe::App for JuliaGUI {
|
||||||
));
|
));
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let export_text = if self.export_path.is_file() {
|
ui.add_enabled_ui(!self.waiting, |ui| {
|
||||||
"Overwrite"
|
let export_text = if self.export_path.is_file() {
|
||||||
} else {
|
"Overwrite"
|
||||||
"Render"
|
} else {
|
||||||
};
|
"Render"
|
||||||
if ui.button(export_text).clicked() {
|
};
|
||||||
self.export_render();
|
if ui.button(export_text).clicked() {
|
||||||
}
|
self.export_render();
|
||||||
if ui.button("Render to").clicked() {
|
}
|
||||||
self.export_render_new_path();
|
if ui.button("Render to").clicked() {
|
||||||
|
self.export_render_new_path();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if self.waiting {
|
||||||
|
ui.spinner();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.label(
|
ui.label(
|
||||||
self.export_path
|
self.export_path
|
||||||
.file_name()
|
.file_name()
|
||||||
|
@ -323,6 +381,10 @@ impl eframe::App for JuliaGUI {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) {
|
fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) {
|
||||||
|
if let Some(channel) = &self.render_thread {
|
||||||
|
channel.send(RenderJob::Exit).unwrap();
|
||||||
|
}
|
||||||
|
self.render_thread_handle.take().unwrap().join().unwrap();
|
||||||
self.save_settings();
|
self.save_settings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue