mirror of
https://github.com/CrispyPin/julia-fractal-renderer.git
synced 2024-11-10 04:30:25 +01:00
render c point in preview
This commit is contained in:
parent
cc43258aad
commit
74ccbbb3e2
2 changed files with 55 additions and 28 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
use eframe::epaint::Vec2;
|
||||||
use image::{Rgb, RgbImage};
|
use image::{Rgb, RgbImage};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -32,35 +33,54 @@ impl Default for RenderOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(q: &RenderOptions, color: (u8, u8, u8)) -> RgbImage {
|
pub fn view_point(q: &RenderOptions, image: RgbImage) -> RgbImage {
|
||||||
let mut img = RgbImage::new(q.width, q.height);
|
apply_fn(image, q, |x, y| {
|
||||||
|
let len = (Vec2::new(x as f32, y as f32) - Vec2::new(q.cx as f32, q.cy as f32)).length();
|
||||||
|
if len < 0.04 {
|
||||||
|
Some(Rgb([0, 255, 255]))
|
||||||
|
} else if len < 0.05 {
|
||||||
|
Some(Rgb([255; 3]))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let width: f64 = q.width.into();
|
pub fn render(q: &RenderOptions, color: (u8, u8, u8)) -> RgbImage {
|
||||||
let height: f64 = q.height.into();
|
let img = RgbImage::new(q.width, q.height);
|
||||||
|
apply_fn(img, q, |x, y| {
|
||||||
|
let i = julia(x, y, q.cx, q.cy, q.max_iterations);
|
||||||
|
if q.fill_style == FillStyle::Black && i == q.max_iterations {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let i = i.min(255) as u8;
|
||||||
|
Some(Rgb([
|
||||||
|
i.saturating_mul(color.0),
|
||||||
|
i.saturating_mul(color.1),
|
||||||
|
i.saturating_mul(color.2),
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_fn<F>(mut image: RgbImage, q: &RenderOptions, op: F) -> RgbImage
|
||||||
|
where
|
||||||
|
F: Fn(f64, f64) -> Option<Rgb<u8>>,
|
||||||
|
{
|
||||||
|
let width = q.width as f64;
|
||||||
|
let height = q.height as f64;
|
||||||
let ppu = width / q.unit_width;
|
let ppu = width / q.unit_width;
|
||||||
|
|
||||||
for y in 0..q.height {
|
for y in 0..q.height {
|
||||||
for x in 0..q.width {
|
for x in 0..q.width {
|
||||||
let pixel = {
|
let sx = (x as f64 - width / 2.0) / ppu;
|
||||||
let x = (f64::from(x) - width / 2.0) / ppu;
|
let sy = (y as f64 - height / 2.0) / ppu;
|
||||||
let y = (f64::from(y) - height / 2.0) / ppu;
|
if let Some(pixel) = op(sx, sy) {
|
||||||
|
image.put_pixel(x, y, pixel);
|
||||||
let iter = julia(x, y, q.cx, q.cy, q.max_iterations);
|
}
|
||||||
if q.fill_style == FillStyle::Black && iter == q.max_iterations {
|
|
||||||
Rgb([0, 0, 0])
|
|
||||||
} else {
|
|
||||||
let i = iter.min(255) as u8;
|
|
||||||
Rgb([
|
|
||||||
i.saturating_mul(color.0),
|
|
||||||
i.saturating_mul(color.1),
|
|
||||||
i.saturating_mul(color.2),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
};
|
|
||||||
img.put_pixel(x, y, pixel);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
img
|
image
|
||||||
}
|
}
|
||||||
|
|
||||||
fn julia(mut x: f64, mut y: f64, cx: f64, cy: f64, max_iter: u32) -> u32 {
|
fn julia(mut x: f64, mut y: f64, cx: f64, cy: f64, max_iter: u32) -> u32 {
|
||||||
|
|
19
src/main.rs
19
src/main.rs
|
@ -11,7 +11,7 @@ use eframe::{
|
||||||
epaint::{TextureHandle, Vec2},
|
epaint::{TextureHandle, Vec2},
|
||||||
Frame, NativeOptions,
|
Frame, NativeOptions,
|
||||||
};
|
};
|
||||||
use generate::{render, FillStyle, RenderOptions};
|
use generate::{render, view_point, FillStyle, RenderOptions};
|
||||||
use image::EncodableLayout;
|
use image::EncodableLayout;
|
||||||
use native_dialog::FileDialog;
|
use native_dialog::FileDialog;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -50,6 +50,7 @@ struct JuliaGUI {
|
||||||
export_path: PathBuf,
|
export_path: PathBuf,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
settings_changed: bool,
|
settings_changed: bool,
|
||||||
|
preview_point: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for JuliaGUI {
|
impl Default for JuliaGUI {
|
||||||
|
@ -60,10 +61,11 @@ impl Default for JuliaGUI {
|
||||||
render_options: RenderOptions::default(),
|
render_options: RenderOptions::default(),
|
||||||
preview_render_ms: 0.0,
|
preview_render_ms: 0.0,
|
||||||
export_render_ms: None,
|
export_render_ms: None,
|
||||||
export_res_power: 8,
|
export_res_power: 3,
|
||||||
export_iterations: 512,
|
export_iterations: 512,
|
||||||
export_path: "".into(),
|
export_path: "".into(),
|
||||||
settings_changed: true,
|
settings_changed: true,
|
||||||
|
preview_point: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +98,10 @@ impl JuliaGUI {
|
||||||
|
|
||||||
fn update_preview(&mut self) {
|
fn update_preview(&mut self) {
|
||||||
let start_time = SystemTime::now();
|
let start_time = SystemTime::now();
|
||||||
let frame = render(&self.render_options, self.color);
|
let mut frame = render(&self.render_options, self.color);
|
||||||
|
if self.preview_point {
|
||||||
|
frame = view_point(&self.render_options, frame);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(preview) = &mut self.preview {
|
if let Some(preview) = &mut self.preview {
|
||||||
preview.set(
|
preview.set(
|
||||||
|
@ -129,7 +134,7 @@ impl JuliaGUI {
|
||||||
|
|
||||||
fn export_render_new_path(&mut self) {
|
fn export_render_new_path(&mut self) {
|
||||||
if let Ok(Some(path)) = FileDialog::new()
|
if let Ok(Some(path)) = FileDialog::new()
|
||||||
.set_filename(&self.export_path.to_string_lossy().to_string())
|
.set_filename(&self.export_path.to_string_lossy())
|
||||||
.add_filter("PNG file", &["png"])
|
.add_filter("PNG file", &["png"])
|
||||||
.show_save_single_file()
|
.show_save_single_file()
|
||||||
{
|
{
|
||||||
|
@ -156,6 +161,7 @@ impl eframe::App for JuliaGUI {
|
||||||
self.preview_render_ms
|
self.preview_render_ms
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let set_point_vis = ui.checkbox(&mut self.preview_point, "View C point");
|
||||||
ui.label("CX:");
|
ui.label("CX:");
|
||||||
let set_cx = ui.add(Slider::new(&mut self.render_options.cx, -2.0..=2.0));
|
let set_cx = ui.add(Slider::new(&mut self.render_options.cx, -2.0..=2.0));
|
||||||
ui.label("CY:");
|
ui.label("CY:");
|
||||||
|
@ -242,7 +248,7 @@ impl eframe::App for JuliaGUI {
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
if let Some(ms) = self.export_render_ms {
|
if let Some(ms) = self.export_render_ms {
|
||||||
ui.label(format!("(took {:.2}ms)", ms));
|
ui.label(format!("(took {ms:.2}ms)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if set_cx.changed()
|
if set_cx.changed()
|
||||||
|
@ -250,6 +256,7 @@ impl eframe::App for JuliaGUI {
|
||||||
|| set_iter.changed()
|
|| set_iter.changed()
|
||||||
|| set_red.changed() || set_green.changed()
|
|| set_red.changed() || set_green.changed()
|
||||||
|| set_blue.changed()
|
|| set_blue.changed()
|
||||||
|
|| set_point_vis.changed()
|
||||||
{
|
{
|
||||||
self.settings_changed = true;
|
self.settings_changed = true;
|
||||||
}
|
}
|
||||||
|
@ -263,6 +270,6 @@ 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>) {
|
||||||
self.save_settings()
|
self.save_settings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue