Mandelbrot
This commit is contained in:
parent
07d05aba84
commit
bb38f954dc
7 changed files with 345 additions and 66 deletions
80
Cargo.lock
generated
80
Cargo.lock
generated
|
@ -2,6 +2,12 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
@ -24,6 +30,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
name = "fractals"
|
name = "fractals"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"num",
|
||||||
"sdl2",
|
"sdl2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -39,6 +46,79 @@ version = "0.2.159"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||||
|
dependencies = [
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.46"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sdl2"
|
name = "sdl2"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
|
|
|
@ -6,4 +6,5 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
num = "0.4.3"
|
||||||
sdl2 = { version = "0.37", features = ["gfx"] }
|
sdl2 = { version = "0.37", features = ["gfx"] }
|
||||||
|
|
4
README.md
Normal file
4
README.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
## rust-sdl2-fractals
|
||||||
|
|
||||||
|
[![mandelbrot](./examples/mandelbrot.png?raw=true)](https://en.wikipedia.org/wiki/Mandelbrot_set)
|
||||||
|
[![snowflake](./examples/snowflake.png?raw=true)](https://en.wikipedia.org/wiki/Koch_snowflake)
|
BIN
examples/mandelbrot.png
Normal file
BIN
examples/mandelbrot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 263 KiB |
BIN
examples/snowflake.png
Normal file
BIN
examples/snowflake.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
133
src/koch_snowflake.rs
Normal file
133
src/koch_snowflake.rs
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
extern crate sdl2;
|
||||||
|
|
||||||
|
use std::cmp::min;
|
||||||
|
|
||||||
|
use sdl2::event::Event;
|
||||||
|
use sdl2::keyboard::Keycode;
|
||||||
|
use sdl2::pixels::{self, Color};
|
||||||
|
|
||||||
|
use sdl2::gfx::primitives::DrawRenderer;
|
||||||
|
use sdl2::render::WindowCanvas;
|
||||||
|
|
||||||
|
const SCREEN_WIDTH: i16 = 800; // i15
|
||||||
|
const SCREEN_HEIGHT: i16 = 600; // i15
|
||||||
|
|
||||||
|
fn atan(a: f32, b: f32) -> f32 {
|
||||||
|
if b == 0.0 {
|
||||||
|
return 0.0
|
||||||
|
} else if b < 0.0 {
|
||||||
|
return (a/b).atan() + std::f32::consts::PI;
|
||||||
|
} else {
|
||||||
|
return (a/b).atan();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** for each zoomlevel, lines are replaced by 4 new lines of length a/3 **/
|
||||||
|
fn koch_line(canvas: &WindowCanvas, x0: i16, y0: i16, x4: i16, y4: i16, color: Color, zoom: i16) {
|
||||||
|
|
||||||
|
if zoom == 1 {
|
||||||
|
let _ = canvas.line(x0, y0, x4, y4, color);
|
||||||
|
} else {
|
||||||
|
/* the outer two lines */
|
||||||
|
let x1 = x0 + (x4-x0) / 3;
|
||||||
|
let y1 = y0 + (y4-y0) / 3;
|
||||||
|
let x3 = x0 + 2* (x4-x0) / 3;
|
||||||
|
let y3 = y0 + 2* (y4-y0) / 3;
|
||||||
|
koch_line(canvas, x0, y0, x1, y1, color, zoom-1);
|
||||||
|
koch_line(canvas, x3, y3, x4, y4, color, zoom-1);
|
||||||
|
|
||||||
|
/* the inner two lines (arms of an equilateral triangle) */
|
||||||
|
let dx = x3 - x1;
|
||||||
|
let dy = y3 - y1;
|
||||||
|
let a = ((dx*dx + dy*dy) as f32).sqrt();
|
||||||
|
let angle = atan((-dy).into(), dx.into()); // angle of the original line
|
||||||
|
const INTERNAL_ANGLE: f32 = std::f32::consts::FRAC_PI_3; // 60_f32.to_radians();
|
||||||
|
let x2 = x1 + ((a * (angle - INTERNAL_ANGLE).cos()) as i16);
|
||||||
|
let y2 = y1 - ((a * (angle - INTERNAL_ANGLE).sin()) as i16);
|
||||||
|
koch_line(canvas, x1, y1, x2, y2, color, zoom-1);
|
||||||
|
koch_line(canvas, x2, y2, x3, y3, color, zoom-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn koch_snowflake(canvas: &WindowCanvas, x: i16, y: i16, a: i16, color: Option<Color>, zoom: i16) {
|
||||||
|
let max_zoom = (a as f32).log(3.0).ceil() as i16;
|
||||||
|
let effective_zoom = min(zoom, max_zoom);
|
||||||
|
println!("zoom: {}/{}", effective_zoom, max_zoom);
|
||||||
|
|
||||||
|
let c = (255 * (effective_zoom-1) / (max_zoom-1)) as u8;
|
||||||
|
let color = color.unwrap_or(Color::RGB(c, c, 127+c/2));
|
||||||
|
|
||||||
|
let h = (a as f32 * 3.0_f32.sqrt() / 2.0) as i16; // height of equilateral triangle
|
||||||
|
|
||||||
|
let x1 = x;
|
||||||
|
let y1 = y - h/2;
|
||||||
|
let x2 = x - a/2;
|
||||||
|
let y2 = y + h/2;
|
||||||
|
let x3 = x + a/2;
|
||||||
|
let y3 = y + h/2;
|
||||||
|
koch_line(&canvas, x1, y1, x2, y2, color, effective_zoom);
|
||||||
|
koch_line(&canvas, x2, y2, x3, y3, color, effective_zoom);
|
||||||
|
koch_line(&canvas, x3, y3, x1, y1, color, effective_zoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<(), String> {
|
||||||
|
let sdl_context = sdl2::init()?;
|
||||||
|
let video_subsys = sdl_context.video()?;
|
||||||
|
let window = video_subsys
|
||||||
|
.window(
|
||||||
|
"rust-sdl2_gfx: draw line & FPSManager",
|
||||||
|
(SCREEN_WIDTH as u16).into(),
|
||||||
|
(SCREEN_HEIGHT as u16).into(),
|
||||||
|
)
|
||||||
|
.position_centered()
|
||||||
|
.opengl()
|
||||||
|
.build()
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
canvas.set_draw_color(pixels::Color::RGB(0, 0, 0));
|
||||||
|
canvas.clear();
|
||||||
|
canvas.present();
|
||||||
|
println!("Welcome :)");
|
||||||
|
println!("[Klick] into canvas to draw a koch snowflake…");
|
||||||
|
println!("Press [Space] to clear the canvas…");
|
||||||
|
println!("Press [Backspace] to reset the zoom…");
|
||||||
|
|
||||||
|
let mut events = sdl_context.event_pump()?;
|
||||||
|
|
||||||
|
let mut zoom = 1;
|
||||||
|
|
||||||
|
'main: loop {
|
||||||
|
for event in events.poll_iter() {
|
||||||
|
match event {
|
||||||
|
Event::Quit { .. } => break 'main,
|
||||||
|
|
||||||
|
Event::KeyDown {
|
||||||
|
keycode: Some(keycode),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
if keycode == Keycode::Escape {
|
||||||
|
break 'main;
|
||||||
|
} else if keycode == Keycode::Space {
|
||||||
|
canvas.set_draw_color(pixels::Color::RGB(0, 0, 0));
|
||||||
|
canvas.clear();
|
||||||
|
canvas.present();
|
||||||
|
} else if keycode == Keycode::BACKSPACE {
|
||||||
|
zoom = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Event::MouseButtonDown { x, y, .. } => {
|
||||||
|
koch_snowflake(&canvas, x.try_into().unwrap(), y.try_into().unwrap(), SCREEN_HEIGHT/3, None, zoom);
|
||||||
|
canvas.present();
|
||||||
|
zoom += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
189
src/main.rs
189
src/main.rs
|
@ -1,6 +1,9 @@
|
||||||
extern crate sdl2;
|
extern crate sdl2;
|
||||||
|
|
||||||
use std::cmp::min;
|
use core::f32;
|
||||||
|
use std::i32;
|
||||||
|
|
||||||
|
use num::complex::{Complex, Complex32, ComplexFloat};
|
||||||
|
|
||||||
use sdl2::event::Event;
|
use sdl2::event::Event;
|
||||||
use sdl2::keyboard::Keycode;
|
use sdl2::keyboard::Keycode;
|
||||||
|
@ -9,65 +12,120 @@ use sdl2::pixels::{self, Color};
|
||||||
use sdl2::gfx::primitives::DrawRenderer;
|
use sdl2::gfx::primitives::DrawRenderer;
|
||||||
use sdl2::render::WindowCanvas;
|
use sdl2::render::WindowCanvas;
|
||||||
|
|
||||||
const SCREEN_WIDTH: i16 = 800; // i15
|
fn bound(n: f32, min: f32, max: f32) -> f32 {
|
||||||
const SCREEN_HEIGHT: i16 = 600; // i15
|
let mut vals = [min, n, max];
|
||||||
|
vals.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
|
||||||
|
vals[1]
|
||||||
|
}
|
||||||
|
|
||||||
fn atan(a: f32, b: f32) -> f32 {
|
fn norm(n: f32, min: f32, max: f32) -> f32 {
|
||||||
if b == 0.0 {
|
let n_bound = bound(n, min, max);
|
||||||
return 0.0
|
(n_bound-min) / (max-min)
|
||||||
} else if b < 0.0 {
|
}
|
||||||
return (a/b).atan() + std::f32::consts::PI;
|
|
||||||
} else {
|
fn norm_u8(n: f32, min: f32, max: f32) -> u8 {
|
||||||
return (a/b).atan();
|
(255.0 * norm(n, min, max)) as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
const SCREEN_WIDTH: i16 = 800;
|
||||||
|
const SCREEN_HEIGHT: i16 = 600;
|
||||||
|
const WIDTH: usize = SCREEN_WIDTH as usize;
|
||||||
|
const HEIGHT: usize = SCREEN_HEIGHT as usize;
|
||||||
|
|
||||||
|
fn xy2complex(x: f32, y: f32) -> Complex32 {
|
||||||
|
let x_min = -2.0;
|
||||||
|
let x_max = 1.0;
|
||||||
|
let y_min = -2.0;
|
||||||
|
let y_max = 2.0;
|
||||||
|
|
||||||
|
Complex::new(x_min + (x_max-x_min) * x / WIDTH as f32,
|
||||||
|
-(y_min + (y_max-y_min) * y / HEIGHT as f32))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Mandelbrot {
|
||||||
|
pub divergence: Vec<Vec<i32>>, // iteration when diverged (if not diverged: i32::MAX)
|
||||||
|
pub projections: Vec<Vec<Complex<f32>>>,
|
||||||
|
pub cs: Vec<Vec<Complex32>>,
|
||||||
|
pub iteration: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mandelbrot {
|
||||||
|
fn new() -> Mandelbrot {
|
||||||
|
let divergence = vec![vec![i32::MAX; WIDTH]; HEIGHT];
|
||||||
|
let projections = vec![vec![Complex::new(0.0,0.0); WIDTH]; HEIGHT];
|
||||||
|
let mut cs = vec![vec![Complex::new(0.0,0.0); WIDTH]; HEIGHT];
|
||||||
|
|
||||||
|
for y in 0..cs.len() {
|
||||||
|
for x in 0..cs[y].len() {
|
||||||
|
cs[y][x] = xy2complex((x as i16).into(), (y as i16).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** for each zoomlevel, lines are replaced by 4 new lines of length a/3 **/
|
let iteration = 0;
|
||||||
fn koch_line(canvas: &WindowCanvas, x0: i16, y0: i16, x4: i16, y4: i16, color: Color, zoom: i16) {
|
|
||||||
|
|
||||||
if zoom == 1 {
|
Mandelbrot {
|
||||||
let _ = canvas.line(x0, y0, x4, y4, color);
|
divergence,
|
||||||
} else {
|
projections,
|
||||||
/* the outer two lines */
|
cs,
|
||||||
let x1 = x0 + (x4-x0) / 3;
|
iteration,
|
||||||
let y1 = y0 + (y4-y0) / 3;
|
|
||||||
let x3 = x0 + 2* (x4-x0) / 3;
|
|
||||||
let y3 = y0 + 2* (y4-y0) / 3;
|
|
||||||
koch_line(canvas, x0, y0, x1, y1, color, zoom-1);
|
|
||||||
koch_line(canvas, x3, y3, x4, y4, color, zoom-1);
|
|
||||||
|
|
||||||
/* the inner two lines (arms of an equilateral triangle) */
|
|
||||||
let dx = x3 - x1;
|
|
||||||
let dy = y3 - y1;
|
|
||||||
let a = ((dx*dx + dy*dy) as f32).sqrt();
|
|
||||||
let angle = atan((-dy).into(), dx.into()); // angle of the original line
|
|
||||||
const INTERNAL_ANGLE: f32 = std::f32::consts::FRAC_PI_3; // 60_f32.to_radians();
|
|
||||||
let x2 = x1 + ((a * (angle - INTERNAL_ANGLE).cos()) as i16);
|
|
||||||
let y2 = y1 - ((a * (angle - INTERNAL_ANGLE).sin()) as i16);
|
|
||||||
koch_line(canvas, x1, y1, x2, y2, color, zoom-1);
|
|
||||||
koch_line(canvas, x2, y2, x3, y3, color, zoom-1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn koch_snowflake(canvas: &WindowCanvas, x: i16, y: i16, a: i16, color: Option<Color>, zoom: i16) {
|
fn iter(&mut self) {
|
||||||
let max_zoom = (a as f32).log(3.0).ceil() as i16;
|
self.iteration += 1;
|
||||||
let effective_zoom = min(zoom, max_zoom);
|
println!("iteration={}", self.iteration);
|
||||||
println!("zoom: {}/{}", effective_zoom, max_zoom);
|
|
||||||
|
|
||||||
let c = (255 * (effective_zoom-1) / (max_zoom-1)) as u8;
|
let projections = &mut self.projections;
|
||||||
let color = color.unwrap_or(Color::RGB(c, c, 127+c/2));
|
let divergence = &mut self.divergence;
|
||||||
|
for y in 0..projections.len() {
|
||||||
|
for x in 0..projections[y].len() {
|
||||||
|
if divergence[y][x] > self.iteration {
|
||||||
|
projections[y][x] = projections[y][x] * projections[y][x] + self.cs[y][x];
|
||||||
|
|
||||||
let h = (a as f32 * 3.0_f32.sqrt() / 2.0) as i16; // height of equilateral triangle
|
if projections[y][x].abs().is_nan() { // or greater bounds
|
||||||
|
divergence[y][x] = self.iteration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_divergence<'a>(&self, canvas: &'a mut WindowCanvas) {
|
||||||
|
let values = &self.divergence;
|
||||||
|
for y in 0..values.len() {
|
||||||
|
for x in 0..values[y].len() {
|
||||||
|
let v = values[y][x];
|
||||||
|
let r = norm_u8(0.0 - v.abs_diff(20) as f32, -10.0, 10.0);
|
||||||
|
let g = norm_u8(0.0 - v.abs_diff(30) as f32, -10.0, 10.0);
|
||||||
|
let b = norm_u8(v as f32, 0.0, 50.0);
|
||||||
|
let color = Color::RGB(r, g, b);
|
||||||
|
let _ = canvas.box_(x as i16, y as i16, x as i16, y as i16, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
canvas.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_projections<'a>(&self, canvas: &'a mut WindowCanvas) {
|
||||||
|
let values = &self.projections;
|
||||||
|
for y in 0..values.len() {
|
||||||
|
for x in 0..values[y].len() {
|
||||||
|
let v = values[y][x];
|
||||||
|
let im = norm_u8(v.im, -2.0, 2.0);
|
||||||
|
let re = norm_u8(v.re, -2.0, 2.0);
|
||||||
|
let color = Color::RGB(0, re, im);
|
||||||
|
let _ = canvas.box_(x as i16, y as i16, x as i16, y as i16, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
canvas.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn debug(&self, x: usize, y: usize) {
|
||||||
|
println!("");
|
||||||
|
println!("y={}, x={}, c={}", y, x, self.cs[y][x]); // xy2complex((x as i16).into(), (y as i16).into())
|
||||||
|
println!("projection={}, abs={}", self.projections[y][x], self.projections[y][x].abs());
|
||||||
|
println!("divergence={}", self.divergence[y][x]);
|
||||||
|
}
|
||||||
|
|
||||||
let x1 = x;
|
|
||||||
let y1 = y - h/2;
|
|
||||||
let x2 = x - a/2;
|
|
||||||
let y2 = y + h/2;
|
|
||||||
let x3 = x + a/2;
|
|
||||||
let y3 = y + h/2;
|
|
||||||
koch_line(&canvas, x1, y1, x2, y2, color, effective_zoom);
|
|
||||||
koch_line(&canvas, x2, y2, x3, y3, color, effective_zoom);
|
|
||||||
koch_line(&canvas, x3, y3, x1, y1, color, effective_zoom);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), String> {
|
fn main() -> Result<(), String> {
|
||||||
|
@ -75,7 +133,7 @@ fn main() -> Result<(), String> {
|
||||||
let video_subsys = sdl_context.video()?;
|
let video_subsys = sdl_context.video()?;
|
||||||
let window = video_subsys
|
let window = video_subsys
|
||||||
.window(
|
.window(
|
||||||
"rust-sdl2_gfx: draw line & FPSManager",
|
"rust-sdl2-fractals",
|
||||||
(SCREEN_WIDTH as u16).into(),
|
(SCREEN_WIDTH as u16).into(),
|
||||||
(SCREEN_HEIGHT as u16).into(),
|
(SCREEN_HEIGHT as u16).into(),
|
||||||
)
|
)
|
||||||
|
@ -89,16 +147,20 @@ fn main() -> Result<(), String> {
|
||||||
canvas.set_draw_color(pixels::Color::RGB(0, 0, 0));
|
canvas.set_draw_color(pixels::Color::RGB(0, 0, 0));
|
||||||
canvas.clear();
|
canvas.clear();
|
||||||
canvas.present();
|
canvas.present();
|
||||||
println!("Welcome :)");
|
|
||||||
println!("[Klick] into canvas to draw a koch snowflake…");
|
let mut mandelbrot = Mandelbrot::new();
|
||||||
println!("Press [Space] to clear the canvas…");
|
|
||||||
println!("Press [Backspace] to reset the zoom…");
|
|
||||||
|
|
||||||
let mut events = sdl_context.event_pump()?;
|
let mut events = sdl_context.event_pump()?;
|
||||||
|
|
||||||
let mut zoom = 1;
|
println!("Press [Space] to show next iteration (projections)…");
|
||||||
|
println!("Press [Enter] to show next iteration (divergence)…");
|
||||||
|
println!("[Klick] any coordinate for debug output…");
|
||||||
|
|
||||||
|
mandelbrot.iter();
|
||||||
|
mandelbrot.show_projections(&mut canvas);
|
||||||
|
|
||||||
'main: loop {
|
'main: loop {
|
||||||
|
|
||||||
for event in events.poll_iter() {
|
for event in events.poll_iter() {
|
||||||
match event {
|
match event {
|
||||||
Event::Quit { .. } => break 'main,
|
Event::Quit { .. } => break 'main,
|
||||||
|
@ -109,21 +171,20 @@ fn main() -> Result<(), String> {
|
||||||
} => {
|
} => {
|
||||||
if keycode == Keycode::Escape {
|
if keycode == Keycode::Escape {
|
||||||
break 'main;
|
break 'main;
|
||||||
} else if keycode == Keycode::Space {
|
} else if keycode == Keycode::SPACE {
|
||||||
canvas.set_draw_color(pixels::Color::RGB(0, 0, 0));
|
mandelbrot.iter();
|
||||||
canvas.clear();
|
mandelbrot.show_projections(&mut canvas);
|
||||||
canvas.present();
|
} else if keycode == Keycode::RETURN {
|
||||||
|
mandelbrot.show_divergence(&mut canvas);
|
||||||
|
mandelbrot.iter();
|
||||||
} else if keycode == Keycode::BACKSPACE {
|
} else if keycode == Keycode::BACKSPACE {
|
||||||
zoom = 1
|
mandelbrot.show_projections(&mut canvas);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::MouseButtonDown { x, y, .. } => {
|
Event::MouseButtonDown { x, y, .. } => {
|
||||||
koch_snowflake(&canvas, x.try_into().unwrap(), y.try_into().unwrap(), SCREEN_HEIGHT/3, None, zoom);
|
mandelbrot.debug(x.try_into().unwrap(), y.try_into().unwrap());
|
||||||
canvas.present();
|
|
||||||
zoom += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue