diff --git a/src/main.rs b/src/main.rs index 09fc110..6631314 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,12 @@ -use rayon::prelude::*; -use std::arch::x86_64::*; +#![feature(core_intrinsics)] +use std::f64::consts::PI; +use std::{arch::x86_64::*, intrinsics::powf64}; + use std::time::Duration; use minifb::{Key, Window, WindowOptions}; use num::Complex; +use rayon::prelude::*; struct Timer { pub fps: f64, @@ -58,7 +61,7 @@ struct Mandlebrot { impl Mandlebrot { fn new() -> Mandlebrot { - let height: usize = 600; + let height: usize = 800; let width: usize = 800; Mandlebrot { view_width: width, @@ -87,35 +90,97 @@ impl Mandlebrot { Complex { re: cx, im: cy } } - fn mandlebrot(&self, c: Complex, limit: u32) -> Option { + fn mandlebrot( + &self, + c: Complex, + limit: u32, + ) -> Option<(u32, Complex)> { let mut z = Complex { re: 0.0, im: 0.0 }; + for i in 0..limit { z = z * z + c; - if z.norm() > 2.0 { - return Some(i); + if z.norm() > 2.0 { + return Some((i, z)); } } None } fn get_pixel_color(&self, x: u32, y: u32) -> u32 { + let lerp = |a: u8, b: u8, t: f32| -> u8 { ((a + (b - b)) as f32 * t) as u32 as u16 as u8 }; + + let lerp_col = |a: (u8, u8, u8), b: (u8, u8, u8), t: f32| -> (u8, u8, u8) { + (lerp(a.0, b.0, t), lerp(a.1, b.1, t), lerp(a.2, b.2, t)) + }; + + let cyclic_shading = |value: u32, upper: u32| -> (u8, u8, u8) { + let scaled_v: u8 = ((value * upper) / 255) as u8; + (scaled_v, scaled_v, scaled_v) + }; + + let cyclic_rgb = |z: Complex, + iterations: u32, + upper: u32| + -> (u8, u8, u8) { + let theta = z.re.atan2(z.im) + PI; + let r = theta.cos(); + let b = theta.sin(); + let g = (r + b) / 2.0; + let rgb = (r.abs(), g.abs(), b.abs()); + + // let s: f64 = i as f64 / limit as f64; + // let v: f64 = unsafe { 1.0 - powf64((PI * s).cos(), 2.0) }; + + let rgb: (u8, u8, u8) = ( + ((rgb.0) * 255.) as u8, + ((rgb.1) * 255.) as u8, + ((rgb.2) * 255.) as u8, + ); + rgb + }; + + let composite = |composites: &[(u8, u8, u8)]| -> (u8, u8, u8) { + let new_col: (u32, u32, u32) = composites.iter().fold((0, 0, 0), |new, col| { + let col = (col.0 as u32, col.1 as u32, col.2 as u32); + (new.0 + col.0, new.1 + col.1, new.2 + col.2) + }); + let new_col: (u8, u8, u8) = ( + (new_col.0 / composites.len() as u32) as u8, + (new_col.1 / composites.len() as u32) as u8, + (new_col.2 / composites.len() as u32) as u8, + ); + new_col + }; + let c = self.get_pixel(x, y); match self.mandlebrot(c, self.max_iterations) { None => 0, - Some(count) => 255 << 16 | count << 8 | 255, + Some((count, z)) => { + // let col = cyclic_rgb(z, potential_colour, count, self.max_iterations); + // let col = cyclic_shading(count, self.max_iterations); + // let col = composite(&[col, rgb]); + let col = cyclic_rgb(z, count, self.max_iterations); + // let rgb = cyclic_rgb(z, count + 1, self.max_iterations); + // let lerp_factor: f32 = count as f32 / self.max_iterations as f32 * 100.0; + // let col = lerp_col(rgb, col, lerp_factor); + (col.0 as u32) << 16 | (col.1 as u32) << 8 | col.2 as u32 + } } } fn get_buffer(&self) -> Vec { let mut buffer: Vec = vec![0; self.view_width as usize * self.view_height as usize]; - buffer.par_chunks_exact_mut(100).enumerate().for_each(|(i, pixel)| { - for (j, p) in pixel.iter_mut().enumerate() { - let x = (i * 100 + j) % self.view_width as usize; - let y = (i * 100 + j) / self.view_width as usize; - *p = self.get_pixel_color(x as u32, y as u32); - } - }); + buffer + .par_chunks_exact_mut(100) + .enumerate() + .for_each(|(i, pixel)| { + for (j, p) in pixel.iter_mut().enumerate() { + let x = (i * 100 + j) % self.view_width as usize; + let y = (i * 100 + j) / self.view_width as usize; + *p = self.get_pixel_color(x as u32, y as u32); + } + }); buffer } @@ -177,5 +242,4 @@ fn main() { .update_with_buffer(&buffer, mandlebrot.view_width, mandlebrot.view_height) .unwrap(); } - }