mirror of
https://github.com/kristoferssolo/mandelbrot-gui.git
synced 2025-10-21 20:00:34 +00:00
Initial commit
This commit is contained in:
commit
3412648b2c
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
4367
Cargo.lock
generated
Normal file
4367
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "mandelbrot-gui"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
eframe = "0.31.0"
|
||||||
|
egui = "0.31.0"
|
||||||
|
image = "0.25.5"
|
||||||
|
num-complex = "0.4.6"
|
||||||
153
src/main.rs
Normal file
153
src/main.rs
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
use eframe::{App, Error, NativeOptions};
|
||||||
|
use egui::{CentralPanel, Color32, ColorImage, Image, PointerButton, Pos2, Vec2, ViewportBuilder};
|
||||||
|
use image::{ImageBuffer, Rgb};
|
||||||
|
use num_complex::Complex;
|
||||||
|
|
||||||
|
const MAX_ITER: u32 = 256;
|
||||||
|
|
||||||
|
fn mandelbrot(c: Complex<f64>) -> u32 {
|
||||||
|
let mut z = Complex::new(0., 0.);
|
||||||
|
for i in 0..MAX_ITER {
|
||||||
|
if z.norm_sqr() > 4. {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
z = z * z + c;
|
||||||
|
}
|
||||||
|
MAX_ITER
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MandelbrotApp {
|
||||||
|
image: ColorImage,
|
||||||
|
texture_handle: Option<egui::TextureHandle>,
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
zoom: f64,
|
||||||
|
center_x: f64,
|
||||||
|
center_y: f64,
|
||||||
|
dragging: bool,
|
||||||
|
last_mouse_pos: Option<Pos2>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MandelbrotApp {
|
||||||
|
fn new(width: usize, height: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
image: ColorImage::new([width, height], Color32::BLACK),
|
||||||
|
texture_handle: None,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
zoom: 1.,
|
||||||
|
center_x: -0.5,
|
||||||
|
center_y: 0.,
|
||||||
|
dragging: false,
|
||||||
|
last_mouse_pos: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_mandelbrot(&mut self) {
|
||||||
|
let width = self.width;
|
||||||
|
let height = self.height;
|
||||||
|
let zoom = self.zoom;
|
||||||
|
let center_x = self.center_x;
|
||||||
|
let center_y = self.center_y;
|
||||||
|
|
||||||
|
let mut img_buf: ImageBuffer<Rgb<u8>, Vec<u8>> =
|
||||||
|
ImageBuffer::new(width as u32, height as u32);
|
||||||
|
|
||||||
|
for (x, y, pixel) in img_buf.enumerate_pixels_mut() {
|
||||||
|
let x_val = center_x + (x as f64 - width as f64 / 2.0) / (width as f64 / 2.0) * zoom;
|
||||||
|
let y_val = center_y + (y as f64 - height as f64 / 2.0) / (height as f64 / 2.0) * zoom;
|
||||||
|
let c = Complex::new(x_val, y_val);
|
||||||
|
|
||||||
|
let i = mandelbrot(c);
|
||||||
|
let color_value = (i % 256) as u8;
|
||||||
|
*pixel = Rgb([color_value, color_value, color_value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the `image` crate's `ImageBuffer` to `egui::ColorImage`
|
||||||
|
let pixels = img_buf
|
||||||
|
.into_raw()
|
||||||
|
.chunks(3)
|
||||||
|
.map(|chunk| Color32::from_rgb(chunk[0], chunk[1], chunk[2]))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
self.image.pixels = pixels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl App for MandelbrotApp {
|
||||||
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
|
CentralPanel::default().show(ctx, |ui| {
|
||||||
|
ui.heading("Solo Mandlebort Set");
|
||||||
|
|
||||||
|
// Handle mouse wheel for zooming
|
||||||
|
let scroll_delta = ctx.input(|i| i.raw_scroll_delta);
|
||||||
|
if scroll_delta.y != 0.0 {
|
||||||
|
let zoom_factor = 1.1;
|
||||||
|
if scroll_delta.y > 0.0 {
|
||||||
|
self.zoom /= zoom_factor; // Zoom in
|
||||||
|
} else {
|
||||||
|
self.zoom *= zoom_factor; // Zoom out
|
||||||
|
}
|
||||||
|
self.generate_mandelbrot();
|
||||||
|
self.texture_handle = None; // Invalidate the texture
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle mouse dragging for panning
|
||||||
|
if ui.input(|i| i.pointer.button_down(PointerButton::Primary)) {
|
||||||
|
if let Some(pos) = ctx.pointer_interact_pos() {
|
||||||
|
dbg!(&pos);
|
||||||
|
if self.dragging {
|
||||||
|
if let Some(last_pos) = self.last_mouse_pos {
|
||||||
|
let delta_x = (pos.x - last_pos.x) as f64 / self.zoom;
|
||||||
|
let delta_y = (pos.y - last_pos.y) as f64 / self.zoom;
|
||||||
|
self.center_x -= delta_x;
|
||||||
|
self.center_y -= delta_y;
|
||||||
|
self.generate_mandelbrot();
|
||||||
|
self.texture_handle = None; // Invalidate the texture
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.last_mouse_pos = Some(pos);
|
||||||
|
self.dragging = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.dragging = false;
|
||||||
|
self.last_mouse_pos = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the texture only if it's not already loaded or if the image has changed
|
||||||
|
if self.texture_handle.is_none() {
|
||||||
|
self.texture_handle =
|
||||||
|
Some(ctx.load_texture("mandelbrot", self.image.clone(), Default::default()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the image
|
||||||
|
if let Some(texture_handle) = &self.texture_handle {
|
||||||
|
let pixels_per_point = ctx.pixels_per_point();
|
||||||
|
ui.add(Image::new(texture_handle).fit_to_original_size(pixels_per_point));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), Error> {
|
||||||
|
let width = 800;
|
||||||
|
let height = 600;
|
||||||
|
|
||||||
|
let mut app = MandelbrotApp::new(width, height);
|
||||||
|
app.generate_mandelbrot();
|
||||||
|
|
||||||
|
let native_options = NativeOptions {
|
||||||
|
viewport: ViewportBuilder::default()
|
||||||
|
.with_inner_size(Vec2::new(width as f32, height as f32)),
|
||||||
|
vsync: true,
|
||||||
|
multisampling: 0,
|
||||||
|
depth_buffer: 0,
|
||||||
|
stencil_buffer: 0,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
eframe::run_native(
|
||||||
|
"Solo Mandlebort Set",
|
||||||
|
native_options,
|
||||||
|
Box::new(|_cc| Ok(Box::new(app))),
|
||||||
|
)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user