Skip to content

Commit 7f21329

Browse files
author
OetkenPurveyorOfCode
committed
first commit
0 parents  commit 7f21329

File tree

2 files changed

+307
-0
lines changed

2 files changed

+307
-0
lines changed

Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "mandelbrot"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
minifb = "0.23"
10+
rayon = "1.5"

src/main.rs

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
extern crate minifb;
2+
3+
use minifb::{Key, MouseButton, MouseMode, Scale, ScaleMode, Window, WindowOptions};
4+
use rayon::prelude::*;
5+
const WIDTH: usize = 640;
6+
const HEIGHT: usize = 360;
7+
8+
#[derive(Default, Debug)]
9+
struct Rect {
10+
x_min: f64,
11+
x_max: f64,
12+
y_min: f64,
13+
y_max: f64,
14+
}
15+
16+
fn transform_pixel_to_coord_x(value: u32, width: usize, rect: &Rect) -> f64 {
17+
let x_coord = value as f64 / width as f64;
18+
let x_coord = (rect.x_max - rect.x_min) * x_coord + rect.x_min;
19+
x_coord
20+
}
21+
22+
fn transform_pixel_to_coord_y(value: u32, height: usize, rect: &Rect) -> f64 {
23+
let y_coord = ((height as u32 - value) as f64) / height as f64;
24+
let y_coord = (rect.y_max - rect.y_min) * y_coord + rect.y_min;
25+
y_coord
26+
}
27+
28+
fn render(buffer: &mut Vec<u32>, width: usize, height: usize, rect: &Rect, iterations: usize) {
29+
*buffer = (0..width * height)
30+
.into_par_iter()
31+
.map(|index| {
32+
// x goes from 0 to WIDTH
33+
let x = index as u32 % width as u32;
34+
let x_coord = transform_pixel_to_coord_x(x, width, rect);
35+
36+
// y goes from 0 to HEIGHT
37+
let y = index as u32 / width as u32;
38+
let y_coord = transform_pixel_to_coord_y(y, height, rect);
39+
40+
let mut z_real: f64 = 0.0;
41+
let mut z_imag: f64 = 0.0;
42+
let mut z_real_tmp: f64;
43+
let c_real: f64 = x_coord;
44+
let c_imag: f64 = y_coord;
45+
let mut iter = 0;
46+
while z_real * z_real + z_imag * z_imag < 4.0 && iter < iterations {
47+
//z = Z**2 + c
48+
//z = (z_real + i * z_imag) **2 + c_real + i*c_imag
49+
//Z = z_real**2 + 2i*z_real*z_imag - z_imag**2 + c_real + i* c_imag
50+
z_real_tmp = z_real * z_real - z_imag * z_imag + c_real;
51+
z_imag = 2.0 * z_real * z_imag + c_imag;
52+
z_real = z_real_tmp;
53+
iter += 1;
54+
}
55+
if iter == iterations {
56+
0x00_00_00_FF
57+
} else {
58+
0x00_FF_FF_FF
59+
}
60+
})
61+
.collect();
62+
}
63+
64+
fn render_mouse_rect(buffer: &mut Vec<u32>, width: usize, rect: &Rect) {
65+
// render left and right lines
66+
for x in (rect.x_min as u32)..(rect.x_max as u32) {
67+
buffer[x as usize + rect.y_min as usize * width] = 0x00_FF_00_00;
68+
buffer[x as usize + rect.y_max as usize * width] = 0x00_FF_00_00;
69+
}
70+
// render top and bottom lines
71+
for y in rect.y_min as usize..rect.y_max as usize {
72+
buffer[rect.x_min as usize + y * width] = 0x00_FF_00_00;
73+
buffer[rect.x_max as usize + y * width] = 0x00_FF_00_00;
74+
}
75+
}
76+
77+
fn main() {
78+
let mut buffer: Vec<u32> = vec![0; WIDTH * HEIGHT];
79+
let options: WindowOptions = WindowOptions {
80+
borderless: false,
81+
title: true,
82+
resize: true,
83+
scale: Scale::X1,
84+
scale_mode: ScaleMode::Center,
85+
topmost: false,
86+
transparency: false,
87+
none: false,
88+
};
89+
let mut window = Window::new(
90+
"Mandelbrot - ESC: EXIT- I/D: ITERATIONS=100 - Arrows: MOVEMENT - +/-: ZOOM",
91+
WIDTH,
92+
HEIGHT,
93+
options,
94+
)
95+
.unwrap_or_else(|e| {
96+
panic!("{}", e);
97+
});
98+
99+
window.limit_update_rate(Some(std::time::Duration::from_micros(16600)));
100+
101+
let mut dirty = true;
102+
let mut oldwidth = 0;
103+
let mut oldheight = 0;
104+
let mut oldmouse_down = false;
105+
let mut oldmouse_pos_x = -1.0;
106+
let mut oldmouse_pos_y = -1.0;
107+
let mut mouse_pos_x = -1.0;
108+
let mut mouse_pos_y = -1.0;
109+
let mut oldbuffer = buffer.clone();
110+
let mut rect = Rect {
111+
x_min: -2.0,
112+
x_max: 1.0,
113+
y_min: -1.0,
114+
y_max: 1.0,
115+
};
116+
let mut iterations = 100;
117+
let zoom = 0.8;
118+
let panning = 0.1;
119+
while window.is_open() && !window.is_key_down(Key::Escape) {
120+
let (width, height): (usize, usize) = window.get_size();
121+
if !(width == oldwidth && height == oldheight) {
122+
dirty = true;
123+
}
124+
let mouse_down = window.get_mouse_down(MouseButton::Left);
125+
//println!("mouse down first {mouse_down}");
126+
match (oldmouse_down, mouse_down) {
127+
(false, false) => {} // no action
128+
(false, true) => {
129+
// first mouse down
130+
let (mouse_x, mouse_y): (f32, f32) = window
131+
.get_mouse_pos(MouseMode::Clamp)
132+
.unwrap_or((-1.0, -1.0)); // FIXME
133+
oldmouse_down = true;
134+
oldmouse_pos_x = mouse_x as f64;
135+
oldmouse_pos_y = mouse_y as f64;
136+
}
137+
(true, false) => {
138+
let selection: Rect = Rect {
139+
x_min: if oldmouse_pos_x < mouse_pos_x {
140+
oldmouse_pos_x
141+
} else {
142+
mouse_pos_x
143+
},
144+
x_max: if oldmouse_pos_x > mouse_pos_x {
145+
oldmouse_pos_x
146+
} else {
147+
mouse_pos_x
148+
},
149+
y_min: if oldmouse_pos_y < mouse_pos_y {
150+
oldmouse_pos_y
151+
} else {
152+
mouse_pos_y
153+
},
154+
y_max: if oldmouse_pos_y > mouse_pos_y {
155+
oldmouse_pos_y
156+
} else {
157+
mouse_pos_y
158+
},
159+
};
160+
rect = Rect {
161+
x_min: transform_pixel_to_coord_x(selection.x_min as u32, width, &rect),
162+
x_max: transform_pixel_to_coord_x(selection.x_max as u32, width, &rect),
163+
y_min: transform_pixel_to_coord_y(selection.y_min as u32, height, &rect),
164+
y_max: transform_pixel_to_coord_y(selection.y_max as u32, height, &rect),
165+
};
166+
// release
167+
dirty = true;
168+
oldmouse_down = false;
169+
}
170+
(true, true) => {
171+
// dragging
172+
let (mouse_x, mouse_y): (f32, f32) = window
173+
.get_mouse_pos(MouseMode::Clamp)
174+
.unwrap_or((-1.0, -1.0)); // FIXME
175+
mouse_pos_x = mouse_x as f64;
176+
mouse_pos_y = mouse_y as f64;
177+
let selection: Rect = Rect {
178+
x_min: if oldmouse_pos_x < mouse_pos_x {
179+
oldmouse_pos_x
180+
} else {
181+
mouse_pos_x
182+
},
183+
x_max: if oldmouse_pos_x > mouse_pos_x {
184+
oldmouse_pos_x
185+
} else {
186+
mouse_pos_x
187+
},
188+
y_min: if oldmouse_pos_y < mouse_pos_y {
189+
oldmouse_pos_y
190+
} else {
191+
mouse_pos_y
192+
},
193+
y_max: if oldmouse_pos_y > mouse_pos_y {
194+
oldmouse_pos_y
195+
} else {
196+
mouse_pos_y
197+
},
198+
};
199+
buffer = oldbuffer.clone();
200+
render_mouse_rect(&mut buffer, width, &selection);
201+
}
202+
};
203+
if window.is_key_down(Key::R) {
204+
rect = Rect {
205+
x_min: -2.0,
206+
x_max: 1.0,
207+
y_min: -1.0,
208+
y_max: 1.0,
209+
};
210+
dirty = true;
211+
}
212+
if window.is_key_down(Key::I) {
213+
let mut increase = 1;
214+
if window.is_key_down(Key::LeftShift) || window.is_key_down(Key::RightShift) {
215+
increase = 10;
216+
}
217+
if iterations < usize::MAX - increase {
218+
iterations += increase;
219+
}
220+
let title = format!("Mandelbrot - ESC: EXIT- I/D: ITERATIONS={iterations} - Arrows: MOVEMENT - +/-: ZOOM");
221+
window.set_title(&title);
222+
dirty = true;
223+
}
224+
if window.is_key_down(Key::D) {
225+
let mut decrease = 1;
226+
if window.is_key_down(Key::LeftShift) || window.is_key_down(Key::RightShift) {
227+
decrease = 10;
228+
}
229+
if iterations > decrease {
230+
iterations -= decrease;
231+
}
232+
let title = format!("Mandelbrot - ESC: EXIT- I/D: ITERATIONS={iterations} - Arrows: MOVEMENT - +/-: ZOOM");
233+
window.set_title(&title);
234+
dirty = true;
235+
}
236+
if window.is_key_down(Key::NumPadPlus) {
237+
let center_x = (rect.x_max + rect.x_min) / 2.0;
238+
let center_y = (rect.y_max + rect.y_min) / 2.0;
239+
let edge_x = (rect.x_max - rect.x_min) / 2.0;
240+
let edge_y = (rect.y_max - rect.y_min) / 2.0;
241+
rect = Rect {
242+
x_min: center_x - edge_x * zoom,
243+
x_max: center_x + edge_x * zoom,
244+
y_min: center_y - edge_y * zoom,
245+
y_max: center_y + edge_y * zoom,
246+
};
247+
dirty = true;
248+
}
249+
if window.is_key_down(Key::NumPadMinus) {
250+
let center_x = (rect.x_max + rect.x_min) / 2.0;
251+
let center_y = (rect.y_max + rect.y_min) / 2.0;
252+
let edge_x = (rect.x_max - rect.x_min) / 2.0;
253+
let edge_y = (rect.y_max - rect.y_min) / 2.0;
254+
rect = Rect {
255+
x_min: center_x - edge_x / zoom,
256+
x_max: center_x + edge_x / zoom,
257+
y_min: center_y - edge_y / zoom,
258+
y_max: center_y + edge_y / zoom,
259+
};
260+
dirty = true;
261+
}
262+
if window.is_key_down(Key::Left) {
263+
let pan = (rect.x_max - rect.x_min) * panning;
264+
rect.x_max -= pan;
265+
rect.x_min -= pan;
266+
dirty = true;
267+
}
268+
if window.is_key_down(Key::Right) {
269+
let pan = (rect.x_max - rect.x_min) * panning;
270+
rect.x_max += pan;
271+
rect.x_min += pan;
272+
dirty = true;
273+
}
274+
if window.is_key_down(Key::Up) {
275+
let pan = (rect.y_max - rect.y_min) * panning;
276+
rect.y_max += pan;
277+
rect.y_min += pan;
278+
dirty = true;
279+
}
280+
if window.is_key_down(Key::Down) {
281+
let pan = (rect.y_max - rect.y_min) * panning;
282+
rect.y_max -= pan;
283+
rect.y_min -= pan;
284+
dirty = true;
285+
}
286+
287+
if dirty {
288+
buffer.resize(width * height, 0);
289+
render(&mut buffer, width, height, &rect, iterations);
290+
oldbuffer = buffer.clone();
291+
dirty = false;
292+
oldwidth = width;
293+
oldheight = height;
294+
}
295+
window.update_with_buffer(&buffer, width, height).unwrap();
296+
}
297+
}

0 commit comments

Comments
 (0)