├── .gitignore ├── Cargo.toml ├── src └── main.rs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | *.racertmp 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "rust-ascii-march" 4 | version = "0.1.0" 5 | authors = ["Peter Jacobs "] 6 | 7 | [dependencies] 8 | noise = "0.5" 9 | rustbox = "0.11" 10 | 11 | [[bin]] 12 | name = "ascii-march" 13 | path = "src/main.rs" 14 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(slice_patterns)] 2 | extern crate noise; 3 | extern crate rustbox; 4 | 5 | use std::default::Default; 6 | 7 | use noise::NoiseFn; 8 | use rustbox::{RustBox, Event, Key, Color}; 9 | 10 | // Cells are sampled sampled clockwise, like so: 11 | // 12 | // 12 13 | // 43 14 | // 15 | const CASES: [[&'static str; 2]; 16] = [ 16 | // 00 17 | // 00 18 | [" ", 19 | " "], 20 | 21 | // 00 22 | // 10 23 | [r" ", 24 | r". ",], 25 | 26 | // 00 27 | // 01 28 | [" ", 29 | " ."], 30 | 31 | // 00 32 | // 11 33 | [" ", 34 | "--"], 35 | 36 | // 01 37 | // 00 38 | [r" .", 39 | r" "], 40 | 41 | // 01 42 | // 10 43 | [r" .", 44 | r". "], 45 | 46 | // 01 47 | // 01 48 | [" |", 49 | " |"], 50 | 51 | // 01 52 | // 11 53 | [" /", 54 | "/#"], 55 | 56 | // 10 57 | // 00 58 | [". ", 59 | " "], 60 | 61 | // 10 62 | // 10 63 | ["| ", 64 | "| "], 65 | 66 | // 10 67 | // 01 68 | [". ", 69 | " ."], 70 | 71 | // 10 72 | // 11 73 | [r"\ ", 74 | r"#\"], 75 | 76 | // 11 77 | // 00 78 | ["--", 79 | " "], 80 | 81 | // 11 82 | // 10 83 | ["#/", 84 | "/ "], 85 | 86 | // 11 87 | // 01 88 | [r"\#", 89 | r" \"], 90 | 91 | // 11 92 | // 11 93 | ["##", 94 | "##"], 95 | ]; 96 | 97 | const CASES_UNICODE: [[&'static str; 2]; 16] = [ 98 | // 00 99 | // 00 100 | [" ", 101 | " "], 102 | 103 | // 00 104 | // 10 105 | [r" ", 106 | r"╮ ",], 107 | 108 | // 00 109 | // 01 110 | [" ", 111 | " ╭"], 112 | 113 | // 00 114 | // 11 115 | [" ", 116 | "──"], 117 | 118 | // 01 119 | // 00 120 | [r" ╰", 121 | r" "], 122 | 123 | // 01 124 | // 10 125 | [r" ╰", 126 | r"╮ "], 127 | 128 | // 01 129 | // 01 130 | [" │", 131 | " │"], 132 | 133 | // 01 134 | // 11 135 | ["╭╯", 136 | "╯#"], 137 | 138 | // 10 139 | // 00 140 | ["╯ ", 141 | " "], 142 | 143 | // 10 144 | // 10 145 | ["│ ", 146 | "│ "], 147 | 148 | // 10 149 | // 01 150 | ["╯ ", 151 | " ╭"], 152 | 153 | // 10 154 | // 11 155 | [r"╰╮", 156 | r"#╰"], 157 | 158 | // 11 159 | // 00 160 | ["──", 161 | " "], 162 | 163 | // 11 164 | // 10 165 | ["#╭", 166 | "╭╯"], 167 | 168 | // 11 169 | // 01 170 | [r"╮#", 171 | r"╰╮"], 172 | 173 | // 11 174 | // 11 175 | ["##", 176 | "##"], 177 | ]; 178 | 179 | fn corners(x: f64, y: f64, width: f64) -> [[f64; 2]; 4] { 180 | let w = width / 2.0; 181 | [[x - w, y - w], [x + w, y - w], [x + w, y + w], [x - w, y + w]] 182 | } 183 | 184 | fn samples_to_idx(samples: &[f64; 4], threshold: f64) -> usize { 185 | let bits = [if samples[0] > threshold { 1 } else { 0 }, 186 | if samples[1] > threshold { 1 } else { 0 }, 187 | if samples[2] > threshold { 1 } else { 0 }, 188 | if samples[3] > threshold { 1 } else { 0 }]; 189 | bits[0] << 3 | bits[1] << 2 | bits[2] << 1 | bits[3] 190 | } 191 | 192 | fn main() { 193 | let rb = match RustBox::init(Default::default()) { 194 | Result::Ok(v) => v, 195 | Result::Err(e) => panic!("{}", e), 196 | }; 197 | 198 | // use the noise crate to set up a combination noise generator 199 | 200 | let billow = noise::Billow::new(); 201 | 202 | let checkerboard = noise::Checkerboard::new(); 203 | let scale_point = noise::ScalePoint::new( 204 | &checkerboard 205 | ).set_x_scale(0.1).set_y_scale(0.1); 206 | let turbulence = noise::Turbulence::new(&scale_point).set_power(0.3); 207 | 208 | let worley = noise::Worley::new(); 209 | 210 | let noise_fn = noise::Blend::new(&billow, &turbulence, &worley); 211 | 212 | let mut running = true; 213 | let mut unicode = false; 214 | let mut step = 0.1f64; 215 | let mut threshold = 0.25; 216 | let (mut startx, mut starty) = (0.0f64, 0.0f64); 217 | 218 | while running { 219 | let (rows, cols) = (rb.height() / 2, rb.width() / 2); 220 | let (mut x, mut y) = (startx - cols as f64 * step / 2.0, 221 | starty - rows as f64 * step / 2.0); 222 | 223 | for oy in 0..rows { 224 | for ox in 0..cols { 225 | let points = corners(x, y, step); 226 | let samples: [f64; 4] = [noise_fn.get(points[0]), 227 | noise_fn.get(points[1]), 228 | noise_fn.get(points[2]), 229 | noise_fn.get(points[3])]; 230 | 231 | let case_rows = if unicode { 232 | CASES_UNICODE[samples_to_idx(&samples, threshold)] 233 | } else { 234 | CASES[samples_to_idx(&samples, threshold)] 235 | }; 236 | 237 | rb.print(ox * 2, oy * 2, 238 | rustbox::RB_NORMAL, Color::White, Color::Black, 239 | case_rows[0]); 240 | rb.print(ox * 2, (oy * 2)+1, 241 | rustbox::RB_NORMAL, Color::White, Color::Black, 242 | case_rows[1]); 243 | 244 | x += step; 245 | } 246 | y += step; 247 | x = startx - cols as f64 * step / 2.0; 248 | } 249 | 250 | rb.present(); 251 | 252 | if let Ok(Event::KeyEvent(key)) = rb.poll_event(false) { 253 | match key { 254 | Key::Char('w') | Key::Up => starty -= step, 255 | Key::Char('s') | Key::Down => starty += step, 256 | Key::Char('a') | Key::Left => startx -= step, 257 | Key::Char('d') | Key::Right => startx += step, 258 | 259 | Key::Char('+') if step > 0.01 => step -= 0.002, 260 | Key::Char('-') => step += 0.002, 261 | Key::Char('[') => threshold -= 0.005, 262 | Key::Char(']') => threshold += 0.005, 263 | 264 | Key::Char('u') => unicode = !unicode, 265 | 266 | Key::Esc | Key::Char('q') => running = false, 267 | 268 | _ => {} 269 | } 270 | } 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ASCII March 2 | 3 | A simple interactive demonstration of three wonderful things: 4 | * [RustBox](https://github.com/gchp/rustbox) 5 | * [Perlin Noise](http://en.wikipedia.org/wiki/Perlin_noise) (via https://github.com/bjz/noise-rs) 6 | * [Marching Squares](http://en.wikipedia.org/wiki/Marching_squares) 7 | 8 | Keys: press `ESC` or `q` to quit, arrow keys to move around, `+` or `-` to increase/decrease zoom, and `[` or `]` to adjust boundary threshold. 9 | If your terminal supports unicode line/block drawing characters, you can press `u` for fancier rendering. 10 | 11 | Stand-in "screenshot" until I get a chance to make a real one: 12 | ``` 13 | | ###### | | ############################## __/ __/ ### | _ 14 | \________/ | ############################## | \__ ### | | 15 | | ############################## \_ \_____ \_/ 16 | __/ ################################# | | ### 17 | | ################################# __/ __/ ### 18 | | ################################# \_ | ###### 19 | | #################################### \_______ __/ ###### 20 | | ############################################# | | ######### 21 | | ############################################# \__________/ ######### 22 | | ######################################################### _____ ### 23 | \__ ################################################### __/ \____ 24 | | ########################################## __ __/ 25 | | ################################# ________/ \__/ 26 | | ##################### ___________/ 27 | \__ ######### ________/ ___________ 28 | | ### _____/ _____/ ######### \_______ 29 | \_____/ | ######################## | 30 | ________ | ######################## | 31 | | ###### \_ __/ ######################## \_ 32 | __/ ######### \____ _____/ ############################## | 33 | | ################## \__________/ #################################### | 34 | _____ __/ ################################################################## __/ 35 | _____/ ### \_ | ##################################################################### | 36 | _____/ ############ \_______ __/ ##################################################################### \_ 37 | __/ ########################### \_ | ######################################################################## __ \ 38 | ___________________/ ################################# \_ | ######################################################################## \_/ 39 | ######################################################### | \__ ########################################################################### 40 | ######################################################### | | ########################################################################### 41 | ######################## ___________ ################## \_ | ########################################################################### 42 | ##################### __/ \_____ ######### _____/ __/ ################################################ __ ##################### 43 | ################## __/ \___________/ __ | ############################################# __ \/ ________ ############ 44 | ################## | | | | ############################################# \_/ ### | \_____________ 45 | ############### __/ \__/ | ###################################################### | 46 | ############ __/ | ###################################################### | 47 | ### ________/ | ###################################################### \____ 48 | ### | \__ ######################################################### | _____ 49 | __/ __/ ######################################################### \____/ ### | 50 | \_ | ######### __ ######################################################### \_ 51 | ### | \__ ###### | \_____ ###################################################### \ 52 | ### \_ ________ | ###### | \__ ###################################################### 53 | ###### | | ###### \____ | ###### \_ | ###################################################### 54 | ###### \_ | ############ \____ __/ ######### \_______/ ###################################################### 55 | 56 | ``` --------------------------------------------------------------------------------