mirror of
https://github.com/CrispyPin/julia-fractal-renderer.git
synced 2024-11-25 11:30:28 +01:00
save settings between sessions
This commit is contained in:
parent
0068e6fe88
commit
a2c1acd24d
5 changed files with 116 additions and 36 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
/target
|
/target
|
||||||
*.png
|
*.png
|
||||||
!images/*.png
|
!images/*.png
|
||||||
|
fractal_settings.json
|
||||||
|
|
25
Cargo.lock
generated
25
Cargo.lock
generated
|
@ -1183,6 +1183,12 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni"
|
name = "jni"
|
||||||
version = "0.21.1"
|
version = "0.21.1"
|
||||||
|
@ -1230,6 +1236,8 @@ dependencies = [
|
||||||
"eframe",
|
"eframe",
|
||||||
"image",
|
"image",
|
||||||
"native-dialog",
|
"native-dialog",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1866,6 +1874,12 @@ dependencies = [
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
|
@ -1920,6 +1934,17 @@ dependencies = [
|
||||||
"syn 2.0.25",
|
"syn 2.0.25",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.102"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_repr"
|
name = "serde_repr"
|
||||||
version = "0.1.14"
|
version = "0.1.14"
|
||||||
|
|
|
@ -9,6 +9,8 @@ edition = "2021"
|
||||||
eframe = "0.22.0"
|
eframe = "0.22.0"
|
||||||
image = { version = "0.24.6", default_features = false, features = ["png"] }
|
image = { version = "0.24.6", default_features = false, features = ["png"] }
|
||||||
native-dialog = "0.6.4"
|
native-dialog = "0.6.4"
|
||||||
|
serde = "1.0.171"
|
||||||
|
serde_json = "1.0.102"
|
||||||
|
|
||||||
# Enable high optimizations for dependencies
|
# Enable high optimizations for dependencies
|
||||||
[profile.dev.package."*"]
|
[profile.dev.package."*"]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use image::{Rgb, RgbImage};
|
use image::{Rgb, RgbImage};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct RenderOptions {
|
pub struct RenderOptions {
|
||||||
pub width: u32,
|
pub width: u32,
|
||||||
pub height: u32,
|
pub height: u32,
|
||||||
|
@ -11,12 +12,26 @@ pub struct RenderOptions {
|
||||||
pub fill_style: FillStyle,
|
pub fill_style: FillStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone)]
|
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum FillStyle {
|
pub enum FillStyle {
|
||||||
Bright,
|
Bright,
|
||||||
Black,
|
Black,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for RenderOptions {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
width: 512,
|
||||||
|
height: 512,
|
||||||
|
unit_width: 4.0,
|
||||||
|
max_iterations: 128,
|
||||||
|
cx: -0.8,
|
||||||
|
cy: -0.27,
|
||||||
|
fill_style: FillStyle::Bright,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn render(q: &RenderOptions, color: (u8, u8, u8)) -> RgbImage {
|
pub fn render(q: &RenderOptions, color: (u8, u8, u8)) -> RgbImage {
|
||||||
let mut img = RgbImage::new(q.width, q.height);
|
let mut img = RgbImage::new(q.width, q.height);
|
||||||
|
|
||||||
|
|
105
src/main.rs
105
src/main.rs
|
@ -1,5 +1,10 @@
|
||||||
#![windows_subsystem = "windows"]
|
#![windows_subsystem = "windows"]
|
||||||
use std::{env, time::SystemTime};
|
use std::{
|
||||||
|
env,
|
||||||
|
fs::{self, File},
|
||||||
|
io::Write,
|
||||||
|
time::SystemTime,
|
||||||
|
};
|
||||||
|
|
||||||
use eframe::{
|
use eframe::{
|
||||||
egui::{self, DragValue, RichText, Slider, TextureOptions},
|
egui::{self, DragValue, RichText, Slider, TextureOptions},
|
||||||
|
@ -9,9 +14,12 @@ use eframe::{
|
||||||
use generate::{render, FillStyle, RenderOptions};
|
use generate::{render, FillStyle, RenderOptions};
|
||||||
use image::EncodableLayout;
|
use image::EncodableLayout;
|
||||||
use native_dialog::FileDialog;
|
use native_dialog::FileDialog;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
mod generate;
|
mod generate;
|
||||||
|
|
||||||
|
const SETTINGS_FILE: &str = "fractal_settings.json";
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let native_options = NativeOptions {
|
let native_options = NativeOptions {
|
||||||
initial_window_size: Some(Vec2::new(1280.0, 720.0)),
|
initial_window_size: Some(Vec2::new(1280.0, 720.0)),
|
||||||
|
@ -26,58 +34,77 @@ fn main() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
struct JuliaGUI {
|
struct JuliaGUI {
|
||||||
color: (u8, u8, u8),
|
color: (u8, u8, u8),
|
||||||
preview: TextureHandle,
|
#[serde(skip)]
|
||||||
|
preview: Option<TextureHandle>,
|
||||||
render_options: RenderOptions,
|
render_options: RenderOptions,
|
||||||
|
#[serde(skip)]
|
||||||
preview_render_ms: f64,
|
preview_render_ms: f64,
|
||||||
|
#[serde(skip)]
|
||||||
export_render_ms: f64,
|
export_render_ms: f64,
|
||||||
export_res_multiplier: u32,
|
export_res_multiplier: u32,
|
||||||
export_iterations: u32,
|
export_iterations: u32,
|
||||||
export_name: String,
|
export_name: String,
|
||||||
|
#[serde(skip)]
|
||||||
settings_changed: bool,
|
settings_changed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for JuliaGUI {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
color: (12, 5, 10),
|
||||||
|
preview: None,
|
||||||
|
render_options: RenderOptions::default(),
|
||||||
|
preview_render_ms: 0.0,
|
||||||
|
export_render_ms: f64::NAN,
|
||||||
|
export_res_multiplier: 8,
|
||||||
|
export_iterations: 512,
|
||||||
|
export_name: String::from("julia_fractal.png"),
|
||||||
|
settings_changed: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl JuliaGUI {
|
impl JuliaGUI {
|
||||||
fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||||
|
let mut n: Self = fs::read_to_string(SETTINGS_FILE)
|
||||||
|
.map(|s| serde_json::from_str(&s).ok())
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
let preview = cc.egui_ctx.load_texture(
|
let preview = cc.egui_ctx.load_texture(
|
||||||
"preview_image",
|
"preview_image",
|
||||||
egui::ColorImage::from_rgb([1, 1], &[0, 0, 0]),
|
egui::ColorImage::from_rgb([1, 1], &[0, 0, 0]),
|
||||||
TextureOptions::default(),
|
TextureOptions::default(),
|
||||||
);
|
);
|
||||||
let preview_quality = RenderOptions {
|
|
||||||
width: 512,
|
|
||||||
height: 512,
|
|
||||||
unit_width: 4.0,
|
|
||||||
max_iterations: 128,
|
|
||||||
cx: -0.981,
|
|
||||||
cy: -0.277,
|
|
||||||
fill_style: FillStyle::Bright,
|
|
||||||
};
|
|
||||||
|
|
||||||
Self {
|
n.preview = Some(preview);
|
||||||
color: (12, 5, 10),
|
n.settings_changed = true;
|
||||||
preview,
|
n
|
||||||
render_options: preview_quality,
|
}
|
||||||
preview_render_ms: 0.0,
|
|
||||||
export_render_ms: f64::NAN,
|
fn save_settings(&self) {
|
||||||
export_res_multiplier: 8,
|
let settings = serde_json::to_string_pretty(&self).unwrap();
|
||||||
export_iterations: 512,
|
let mut file = File::create(SETTINGS_FILE).unwrap();
|
||||||
export_name: String::from("julia_set.png"),
|
file.write_all(settings.as_bytes()).unwrap();
|
||||||
settings_changed: true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_preview(&mut self) {
|
fn update_preview(&mut self) {
|
||||||
let start_time = SystemTime::now();
|
let start_time = SystemTime::now();
|
||||||
let preview = render(&self.render_options, self.color);
|
let frame = render(&self.render_options, self.color);
|
||||||
self.preview.set(
|
|
||||||
egui::ColorImage::from_rgb(
|
if let Some(preview) = &mut self.preview {
|
||||||
[preview.width() as usize, preview.height() as usize],
|
preview.set(
|
||||||
preview.as_bytes(),
|
egui::ColorImage::from_rgb(
|
||||||
),
|
[frame.width() as usize, frame.height() as usize],
|
||||||
TextureOptions::default(),
|
frame.as_bytes(),
|
||||||
);
|
),
|
||||||
|
TextureOptions::default(),
|
||||||
|
);
|
||||||
|
}
|
||||||
self.preview_render_ms = start_time.elapsed().unwrap().as_micros() as f64 / 1000.0;
|
self.preview_render_ms = start_time.elapsed().unwrap().as_micros() as f64 / 1000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +121,7 @@ impl JuliaGUI {
|
||||||
println!("Error exporting render: {err}");
|
println!("Error exporting render: {err}");
|
||||||
}
|
}
|
||||||
self.export_render_ms = start_time.elapsed().unwrap().as_micros() as f64 / 1000.0;
|
self.export_render_ms = start_time.elapsed().unwrap().as_micros() as f64 / 1000.0;
|
||||||
|
self.save_settings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +129,7 @@ impl eframe::App for JuliaGUI {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut Frame) {
|
||||||
if self.settings_changed {
|
if self.settings_changed {
|
||||||
self.update_preview();
|
self.update_preview();
|
||||||
|
self.save_settings();
|
||||||
self.settings_changed = false;
|
self.settings_changed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,11 +181,15 @@ impl eframe::App for JuliaGUI {
|
||||||
ui.label("Preview resolution:");
|
ui.label("Preview resolution:");
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let set_width = ui.add(
|
let set_width = ui.add(
|
||||||
DragValue::new(&mut self.render_options.width).clamp_range(128..=16384),
|
DragValue::new(&mut self.render_options.width)
|
||||||
|
.clamp_range(128..=4096)
|
||||||
|
.suffix("px"),
|
||||||
);
|
);
|
||||||
ui.label("x");
|
ui.label("x");
|
||||||
let set_height = ui.add(
|
let set_height = ui.add(
|
||||||
DragValue::new(&mut self.render_options.height).clamp_range(128..=16384),
|
DragValue::new(&mut self.render_options.height)
|
||||||
|
.clamp_range(128..=4096)
|
||||||
|
.suffix("px"),
|
||||||
);
|
);
|
||||||
if set_width.changed() || set_height.changed() {
|
if set_width.changed() || set_height.changed() {
|
||||||
self.settings_changed = true;
|
self.settings_changed = true;
|
||||||
|
@ -207,9 +240,13 @@ impl eframe::App for JuliaGUI {
|
||||||
});
|
});
|
||||||
|
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.image(&self.preview, self.preview.size_vec2());
|
if let Some(texture) = &self.preview {
|
||||||
|
ui.image(texture, texture.size_vec2());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) {}
|
fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) {
|
||||||
|
self.save_settings()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue