diff --git a/src/bin/mandelbrot.rs b/src/bin/mandelbrot.rs index bba9ec7d..069b5087 100644 --- a/src/bin/mandelbrot.rs +++ b/src/bin/mandelbrot.rs @@ -3,7 +3,8 @@ extern crate alloc; -//use moros::print; +use moros::{print, println}; +use moros::api::console::Style; use moros::api::fs; use moros::api::io; use moros::api::vga; @@ -11,25 +12,33 @@ use moros::entry_point; entry_point!(main); -fn palette() -> [u8; 768] { +fn palette(color: bool) -> [u8; 768] { let mut palette = [0; 768]; for i in 0..256 { - palette[i * 3 + 0] = i as u8; // R - palette[i * 3 + 1] = i as u8; // G - palette[i * 3 + 2] = i as u8; // B + let mut r = i as u8; + let mut g = i as u8; + let mut b = i as u8; + if i > 0 && color { + let t = i as f32 / 255.0; + r = (9.0 * (1.0 - t) * t * t * t * 255.0) as u8; + g = (15.0 * (1.0 - t) * (1.0 - t) * t * t * 255.0) as u8; + b = (8.5 * (1.0 - t) * (1.0 - t) * (1.0 - t) * t * 255.0) as u8; + } + palette[i * 3 + 0] = r; + palette[i * 3 + 1] = g; + palette[i * 3 + 2] = b; } palette } -fn mandelbrot() -> [u8; 320 * 200] { - let mut buffer = [0; 320 * 200]; - let (x_min, x_max) = (-2.0, 1.0); - let (y_min, y_max) = (-1.0, 1.0); +fn mandelbrot(buffer: &mut [u8], x_offset: f64, y_offset: f64, zoom: f64) { + let x_scale = 3.0 / 320.0 / zoom; + let y_scale = 2.0 / 200.0 / zoom; for y in 0..200 { for x in 0..320 { // Map pixel position to complex plane - let cx = x_min + (x as f32 / 320.0) * (x_max - x_min); - let cy = y_min + (y as f32 / 200.0) * (y_max - y_min); + let cx = x as f64 * x_scale - 2.0 + x_offset; + let cy = y as f64 * y_scale - 1.0 + y_offset; // Compute whether the point is in the Mandelbrot Set let mut zx = 0.0; @@ -37,7 +46,7 @@ fn mandelbrot() -> [u8; 320 * 200] { let mut i = 0; let n = 255; - while zx * zx + zy * zy <= 4.0 && i < n { + while zx * zx + zy * zy < 4.0 && i < n { let tmp = zx * zx - zy * zy + cx; zy = 2.0 * zx * zy + cy; zx = tmp; @@ -48,19 +57,97 @@ fn mandelbrot() -> [u8; 320 * 200] { buffer[y * 320 + x] = i as u8; } } - buffer } -fn wait() { - while io::stdin().read_char().is_none() { - x86_64::instructions::hlt(); +fn main(args: &[&str]) { + let mut color = false; + for arg in args { + match *arg { + "-h" | "--help" => { + help(); + return; + } + "-c" | "--color" => { + color = true; + } + _ => {} + } } -} -fn main(_args: &[&str]) { vga::graphic_mode(); - fs::write("/dev/vga/palette", &palette()).ok(); - fs::write("/dev/vga/buffer", &mandelbrot()).ok(); - wait(); + fs::write("/dev/vga/palette", &palette(color)).ok(); + + let mut x = 0.0; + let mut y = 0.0; + let mut z = 1.0; + + let mut escape = false; + let mut csi = false; + let mut buffer = [0; 320 * 200]; + loop { + mandelbrot(&mut buffer, x, y, z); + fs::write("/dev/vga/buffer", &buffer).ok(); + let c = io::stdin().read_char().unwrap_or('\0'); + match c { + 'q' | '\x11' | '\x03' => { // Ctrl Q or Ctrl C + break; + } + '\0' => { + continue; + } + '\x1B' => { // ESC + escape = true; + continue; + } + '[' if escape => { + csi = true; + continue; + } + 'A' if csi => { // Arrow Up + y -= 0.2 / z; + } + 'B' if csi => { // Arrow Down + y += 0.2 / z; + } + 'C' if csi => { // Arrow Right + x += 0.2 / z; + } + 'D' if csi => { // Arrow Left + x -= 0.2 / z; + } + ' ' => { // Space + let x_center = x + (1.5 / z); + let y_center = y + (1.0 / z); + z *= 1.5; // Increase zoom + x = x_center - (1.5 / z); + y = y_center - (1.0 / z); + } + '\x08' => { // Backspace + let x_center = x + (1.5 / z); + let y_center = y + (1.0 / z); + z /= 1.5; // Increase zoom + x = x_center - (1.5 / z); + y = y_center - (1.0 / z); + } + _ => {} + } + } + vga::text_mode(); } + +fn help() { + let csi_option = Style::color("aqua"); + let csi_title = Style::color("yellow"); + let csi_reset = Style::reset(); + println!( + "{}Usage:{} mandelbrot {}{1}", + csi_title, csi_reset, csi_option + ); + println!(); + println!("{}Options:{}", csi_title, csi_reset); + println!( + " {0}-c{1}, {0}--color{1} Colorize output", + csi_option, csi_reset + ); +} diff --git a/src/usr/render.rs b/src/usr/render.rs index cc295afe..6f847239 100644 --- a/src/usr/render.rs +++ b/src/usr/render.rs @@ -196,7 +196,6 @@ fn render_bmp(path: &str, config: &mut Config) -> Result { fn read_command() -> Command { let mut escape = false; let mut csi = false; - let mut csi_params = String::new(); loop { let c = io::stdin().read_char().unwrap_or('\0'); match c { @@ -212,7 +211,6 @@ fn read_command() -> Command { } '[' if escape => { csi = true; - csi_params.clear(); continue; } 'C' if csi => { // Arrow Right @@ -221,9 +219,8 @@ fn read_command() -> Command { 'D' if csi => { // Arrow Left return Command::Prev; } - c => { + _ => { if csi { - csi_params.push(c); continue; } else { return Command::Next;