#![allow(clippy::many_single_char_names)] use rand; use rand::Rng; use crate::texture::Texture; use crate::vec3::Vec3; pub struct Mandelbrot { palette: Vec, } // HSV values in [0..1] // returns [r, g, b] values from 0 to 255 //From https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/ fn hsv_to_rgb(h: f32, s: f32, v: f32) -> Vec3 { let h_i = (h * 6.) as i32; let f = h * 6. - h_i as f32; let p = v * (1. - s); let q = v * (1. - f * s); let t = v * (1. - (1. - f) * s); match h_i { 0 => Vec3::new(v, t, p), 1 => Vec3::new(q, v, p), 2 => Vec3::new(p, v, t), 3 => Vec3::new(p, q, v), 4 => Vec3::new(t, p, v), 5 => Vec3::new(v, p, q), _ => panic!("Unknown H value {}", h_i), } } fn generate_palette(num: usize) -> Vec { let mut rng = rand::thread_rng(); let mut random = || rng.gen(); // use golden ratio let golden_ratio_conjugate = 0.618_034; let mut h = random(); (0..num) .map(|_| { h += golden_ratio_conjugate; h %= 1.0; hsv_to_rgb(h, 0.99, 0.99) }) .collect() } impl Default for Mandelbrot { fn default() -> Self { Mandelbrot { palette: generate_palette(10), } } } impl Texture for Mandelbrot { fn value(&self, u: f32, v: f32, _p: Vec3) -> Vec3 { // scaled x coordinate of pixel (scaled to lie in the Mandelbrot X scale (-2.5, 1)) let x0 = u * 3.5 - 2.5; // scaled y coordinate of pixel (scaled to lie in the Mandelbrot Y scale (-1, 1)) let y0 = v * 2.0 - 1.0; let mut x = 0.0; let mut y = 0.0; let mut iteration = 0; let max_iteration = 1000; while (x * x + y * y) <= 2. * 2. && iteration < max_iteration { let xtemp = x * x - y * y + x0; y = 2. * x * y + y0; x = xtemp; iteration += 1; } if iteration == max_iteration { return Vec3::default(); } self.palette[iteration % self.palette.len()] } }