pub struct Donut<const WIDTH: u8 = 80, const HEIGHT: u8 = 22, const J_STEP_VALUE: u8 = 7, const J_STEP_DENOM: u8 = 100, const I_STEP_VALUE: u8 = 2, const I_STEP_DENOM: u8 = 100, const CHAR_BRIGHTNESS_0: char = ' ', const CHAR_BRIGHTNESS_1: char = '.', const CHAR_BRIGHTNESS_2: char = ',', const CHAR_BRIGHTNESS_3: char = '-', const CHAR_BRIGHTNESS_4: char = '~', const CHAR_BRIGHTNESS_5: char = ':', const CHAR_BRIGHTNESS_6: char = ';', const CHAR_BRIGHTNESS_7: char = '=', const CHAR_BRIGHTNESS_8: char = '!', const CHAR_BRIGHTNESS_9: char = '*', const CHAR_BRIGHTNESS_10: char = '#', const CHAR_BRIGHTNESS_11: char = '$', const CHAR_BRIGHTNESS_12: char = '@'> {
pub a: f32,
pub b: f32,
}Expand description
A configurable “Donut” that can render ASCII frames without std.
The donut is rendered by sampling points on a torus surface using two angles, and projecting those points into 2D screen space. The brightness of each point is determined by the surface’s orientation relative to a light source.
Fields§
§a: f32Rotation angle A (around the vertical axis)
b: f32Rotation angle B (around the horizontal axis)
Implementations§
Source§impl<const WIDTH: u8, const HEIGHT: u8, const J_STEP_VALUE: u8, const J_STEP_DENOM: u8, const I_STEP_VALUE: u8, const I_STEP_DENOM: u8, const C0: char, const C1: char, const C2: char, const C3: char, const C4: char, const C5: char, const C6: char, const C7: char, const C8: char, const C9: char, const C10: char, const C11: char, const C12: char> Donut<WIDTH, HEIGHT, J_STEP_VALUE, J_STEP_DENOM, I_STEP_VALUE, I_STEP_DENOM, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12>
impl<const WIDTH: u8, const HEIGHT: u8, const J_STEP_VALUE: u8, const J_STEP_DENOM: u8, const I_STEP_VALUE: u8, const I_STEP_DENOM: u8, const C0: char, const C1: char, const C2: char, const C3: char, const C4: char, const C5: char, const C6: char, const C7: char, const C8: char, const C9: char, const C10: char, const C11: char, const C12: char> Donut<WIDTH, HEIGHT, J_STEP_VALUE, J_STEP_DENOM, I_STEP_VALUE, I_STEP_DENOM, C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12>
Sourcepub const fn new() -> Self
pub const fn new() -> Self
Create a new donut with initial rotation angles set to 0.0.
Examples found in repository?
examples/std_console.rs (line 16)
10fn main() {
11 const WIDTH: u8 = 80;
12 const HEIGHT: u8 = 22;
13 const SIZE: usize = (WIDTH as usize) * (HEIGHT as usize);
14
15 // Create the donut instance and pre allocate buffers
16 let mut donut = Donut::<WIDTH, HEIGHT>::new();
17 let mut output = [' '; SIZE];
18 let mut zbuf = [0.0_f32; SIZE];
19
20 // Clear the terminal
21 print!("\x1B[2J");
22 let stdout = stdout();
23 let mut handle = stdout.lock();
24
25 loop {
26 // Start timing this frame
27 let start = Instant::now();
28
29 // Render the donut into output and depth buffers
30 donut.render_frame_in_place(&mut output, &mut zbuf);
31
32 // Reset cursor to top left
33 write!(handle, "\x1B[H").unwrap();
34
35 // Write output buffer
36 for line in output.chunks(WIDTH as usize) {
37 for &ch in line {
38 handle.write_all(&[ch as u8]).unwrap();
39 }
40
41 handle.write_all(b"\n").unwrap();
42 }
43
44 // Write the status line with FPS and memory usage.
45 writeln!(
46 handle,
47 "\nFPS: {:>5.1} | Approx Mem: {}",
48 1.0 / start.elapsed().as_secs_f32().max(0.0001),
49 {
50 let u =
51 mem::size_of_val(&output) + mem::size_of_val(&zbuf) + mem::size_of_val(&donut);
52
53 if u < 1024 {
54 format!("{} bytes", u)
55 } else if u < 1024 * 1024 {
56 format!("{:.1} KB", u as f32 / 1024.0)
57 } else {
58 format!("{:.1} MB", u as f32 / (1024.0 * 1024.0))
59 }
60 }
61 )
62 .unwrap();
63
64 handle.flush().unwrap();
65
66 // Rotate for the next frame and sleep briefly.
67 donut.rotate(0.07, 0.03);
68 sleep(Duration::from_millis(20));
69 }
70}Sourcepub fn rotate(&mut self, da: f32, db: f32)
pub fn rotate(&mut self, da: f32, db: f32)
Increment the rotation angles by da and db.
Rotating the donut creates the animation effect.
Examples found in repository?
examples/std_console.rs (line 67)
10fn main() {
11 const WIDTH: u8 = 80;
12 const HEIGHT: u8 = 22;
13 const SIZE: usize = (WIDTH as usize) * (HEIGHT as usize);
14
15 // Create the donut instance and pre allocate buffers
16 let mut donut = Donut::<WIDTH, HEIGHT>::new();
17 let mut output = [' '; SIZE];
18 let mut zbuf = [0.0_f32; SIZE];
19
20 // Clear the terminal
21 print!("\x1B[2J");
22 let stdout = stdout();
23 let mut handle = stdout.lock();
24
25 loop {
26 // Start timing this frame
27 let start = Instant::now();
28
29 // Render the donut into output and depth buffers
30 donut.render_frame_in_place(&mut output, &mut zbuf);
31
32 // Reset cursor to top left
33 write!(handle, "\x1B[H").unwrap();
34
35 // Write output buffer
36 for line in output.chunks(WIDTH as usize) {
37 for &ch in line {
38 handle.write_all(&[ch as u8]).unwrap();
39 }
40
41 handle.write_all(b"\n").unwrap();
42 }
43
44 // Write the status line with FPS and memory usage.
45 writeln!(
46 handle,
47 "\nFPS: {:>5.1} | Approx Mem: {}",
48 1.0 / start.elapsed().as_secs_f32().max(0.0001),
49 {
50 let u =
51 mem::size_of_val(&output) + mem::size_of_val(&zbuf) + mem::size_of_val(&donut);
52
53 if u < 1024 {
54 format!("{} bytes", u)
55 } else if u < 1024 * 1024 {
56 format!("{:.1} KB", u as f32 / 1024.0)
57 } else {
58 format!("{:.1} MB", u as f32 / (1024.0 * 1024.0))
59 }
60 }
61 )
62 .unwrap();
63
64 handle.flush().unwrap();
65
66 // Rotate for the next frame and sleep briefly.
67 donut.rotate(0.07, 0.03);
68 sleep(Duration::from_millis(20));
69 }
70}Sourcepub fn render_frame_in_place(&self, output: &mut [char], zbuf: &mut [f32])
pub fn render_frame_in_place(&self, output: &mut [char], zbuf: &mut [f32])
Render one ASCII frame in-place:
- output should be (WIDTH*HEIGHT) in length, for storing characters.
- zbuf should also be (WIDTH*HEIGHT) in length, for storing depth.
All these slots will be overwritten with the new frame’s data.
You can then print the output slice as lines of WIDTH characters.
Examples found in repository?
examples/std_console.rs (line 30)
10fn main() {
11 const WIDTH: u8 = 80;
12 const HEIGHT: u8 = 22;
13 const SIZE: usize = (WIDTH as usize) * (HEIGHT as usize);
14
15 // Create the donut instance and pre allocate buffers
16 let mut donut = Donut::<WIDTH, HEIGHT>::new();
17 let mut output = [' '; SIZE];
18 let mut zbuf = [0.0_f32; SIZE];
19
20 // Clear the terminal
21 print!("\x1B[2J");
22 let stdout = stdout();
23 let mut handle = stdout.lock();
24
25 loop {
26 // Start timing this frame
27 let start = Instant::now();
28
29 // Render the donut into output and depth buffers
30 donut.render_frame_in_place(&mut output, &mut zbuf);
31
32 // Reset cursor to top left
33 write!(handle, "\x1B[H").unwrap();
34
35 // Write output buffer
36 for line in output.chunks(WIDTH as usize) {
37 for &ch in line {
38 handle.write_all(&[ch as u8]).unwrap();
39 }
40
41 handle.write_all(b"\n").unwrap();
42 }
43
44 // Write the status line with FPS and memory usage.
45 writeln!(
46 handle,
47 "\nFPS: {:>5.1} | Approx Mem: {}",
48 1.0 / start.elapsed().as_secs_f32().max(0.0001),
49 {
50 let u =
51 mem::size_of_val(&output) + mem::size_of_val(&zbuf) + mem::size_of_val(&donut);
52
53 if u < 1024 {
54 format!("{} bytes", u)
55 } else if u < 1024 * 1024 {
56 format!("{:.1} KB", u as f32 / 1024.0)
57 } else {
58 format!("{:.1} MB", u as f32 / (1024.0 * 1024.0))
59 }
60 }
61 )
62 .unwrap();
63
64 handle.flush().unwrap();
65
66 // Rotate for the next frame and sleep briefly.
67 donut.rotate(0.07, 0.03);
68 sleep(Duration::from_millis(20));
69 }
70}Trait Implementations§
Auto Trait Implementations§
impl<const WIDTH: u8, const HEIGHT: u8, const J_STEP_VALUE: u8, const J_STEP_DENOM: u8, const I_STEP_VALUE: u8, const I_STEP_DENOM: u8, const CHAR_BRIGHTNESS_0: char, const CHAR_BRIGHTNESS_1: char, const CHAR_BRIGHTNESS_2: char, const CHAR_BRIGHTNESS_3: char, const CHAR_BRIGHTNESS_4: char, const CHAR_BRIGHTNESS_5: char, const CHAR_BRIGHTNESS_6: char, const CHAR_BRIGHTNESS_7: char, const CHAR_BRIGHTNESS_8: char, const CHAR_BRIGHTNESS_9: char, const CHAR_BRIGHTNESS_10: char, const CHAR_BRIGHTNESS_11: char, const CHAR_BRIGHTNESS_12: char> Freeze for Donut<WIDTH, HEIGHT, J_STEP_VALUE, J_STEP_DENOM, I_STEP_VALUE, I_STEP_DENOM, CHAR_BRIGHTNESS_0, CHAR_BRIGHTNESS_1, CHAR_BRIGHTNESS_2, CHAR_BRIGHTNESS_3, CHAR_BRIGHTNESS_4, CHAR_BRIGHTNESS_5, CHAR_BRIGHTNESS_6, CHAR_BRIGHTNESS_7, CHAR_BRIGHTNESS_8, CHAR_BRIGHTNESS_9, CHAR_BRIGHTNESS_10, CHAR_BRIGHTNESS_11, CHAR_BRIGHTNESS_12>
impl<const WIDTH: u8, const HEIGHT: u8, const J_STEP_VALUE: u8, const J_STEP_DENOM: u8, const I_STEP_VALUE: u8, const I_STEP_DENOM: u8, const CHAR_BRIGHTNESS_0: char, const CHAR_BRIGHTNESS_1: char, const CHAR_BRIGHTNESS_2: char, const CHAR_BRIGHTNESS_3: char, const CHAR_BRIGHTNESS_4: char, const CHAR_BRIGHTNESS_5: char, const CHAR_BRIGHTNESS_6: char, const CHAR_BRIGHTNESS_7: char, const CHAR_BRIGHTNESS_8: char, const CHAR_BRIGHTNESS_9: char, const CHAR_BRIGHTNESS_10: char, const CHAR_BRIGHTNESS_11: char, const CHAR_BRIGHTNESS_12: char> RefUnwindSafe for Donut<WIDTH, HEIGHT, J_STEP_VALUE, J_STEP_DENOM, I_STEP_VALUE, I_STEP_DENOM, CHAR_BRIGHTNESS_0, CHAR_BRIGHTNESS_1, CHAR_BRIGHTNESS_2, CHAR_BRIGHTNESS_3, CHAR_BRIGHTNESS_4, CHAR_BRIGHTNESS_5, CHAR_BRIGHTNESS_6, CHAR_BRIGHTNESS_7, CHAR_BRIGHTNESS_8, CHAR_BRIGHTNESS_9, CHAR_BRIGHTNESS_10, CHAR_BRIGHTNESS_11, CHAR_BRIGHTNESS_12>
impl<const WIDTH: u8, const HEIGHT: u8, const J_STEP_VALUE: u8, const J_STEP_DENOM: u8, const I_STEP_VALUE: u8, const I_STEP_DENOM: u8, const CHAR_BRIGHTNESS_0: char, const CHAR_BRIGHTNESS_1: char, const CHAR_BRIGHTNESS_2: char, const CHAR_BRIGHTNESS_3: char, const CHAR_BRIGHTNESS_4: char, const CHAR_BRIGHTNESS_5: char, const CHAR_BRIGHTNESS_6: char, const CHAR_BRIGHTNESS_7: char, const CHAR_BRIGHTNESS_8: char, const CHAR_BRIGHTNESS_9: char, const CHAR_BRIGHTNESS_10: char, const CHAR_BRIGHTNESS_11: char, const CHAR_BRIGHTNESS_12: char> Send for Donut<WIDTH, HEIGHT, J_STEP_VALUE, J_STEP_DENOM, I_STEP_VALUE, I_STEP_DENOM, CHAR_BRIGHTNESS_0, CHAR_BRIGHTNESS_1, CHAR_BRIGHTNESS_2, CHAR_BRIGHTNESS_3, CHAR_BRIGHTNESS_4, CHAR_BRIGHTNESS_5, CHAR_BRIGHTNESS_6, CHAR_BRIGHTNESS_7, CHAR_BRIGHTNESS_8, CHAR_BRIGHTNESS_9, CHAR_BRIGHTNESS_10, CHAR_BRIGHTNESS_11, CHAR_BRIGHTNESS_12>
impl<const WIDTH: u8, const HEIGHT: u8, const J_STEP_VALUE: u8, const J_STEP_DENOM: u8, const I_STEP_VALUE: u8, const I_STEP_DENOM: u8, const CHAR_BRIGHTNESS_0: char, const CHAR_BRIGHTNESS_1: char, const CHAR_BRIGHTNESS_2: char, const CHAR_BRIGHTNESS_3: char, const CHAR_BRIGHTNESS_4: char, const CHAR_BRIGHTNESS_5: char, const CHAR_BRIGHTNESS_6: char, const CHAR_BRIGHTNESS_7: char, const CHAR_BRIGHTNESS_8: char, const CHAR_BRIGHTNESS_9: char, const CHAR_BRIGHTNESS_10: char, const CHAR_BRIGHTNESS_11: char, const CHAR_BRIGHTNESS_12: char> Sync for Donut<WIDTH, HEIGHT, J_STEP_VALUE, J_STEP_DENOM, I_STEP_VALUE, I_STEP_DENOM, CHAR_BRIGHTNESS_0, CHAR_BRIGHTNESS_1, CHAR_BRIGHTNESS_2, CHAR_BRIGHTNESS_3, CHAR_BRIGHTNESS_4, CHAR_BRIGHTNESS_5, CHAR_BRIGHTNESS_6, CHAR_BRIGHTNESS_7, CHAR_BRIGHTNESS_8, CHAR_BRIGHTNESS_9, CHAR_BRIGHTNESS_10, CHAR_BRIGHTNESS_11, CHAR_BRIGHTNESS_12>
impl<const WIDTH: u8, const HEIGHT: u8, const J_STEP_VALUE: u8, const J_STEP_DENOM: u8, const I_STEP_VALUE: u8, const I_STEP_DENOM: u8, const CHAR_BRIGHTNESS_0: char, const CHAR_BRIGHTNESS_1: char, const CHAR_BRIGHTNESS_2: char, const CHAR_BRIGHTNESS_3: char, const CHAR_BRIGHTNESS_4: char, const CHAR_BRIGHTNESS_5: char, const CHAR_BRIGHTNESS_6: char, const CHAR_BRIGHTNESS_7: char, const CHAR_BRIGHTNESS_8: char, const CHAR_BRIGHTNESS_9: char, const CHAR_BRIGHTNESS_10: char, const CHAR_BRIGHTNESS_11: char, const CHAR_BRIGHTNESS_12: char> Unpin for Donut<WIDTH, HEIGHT, J_STEP_VALUE, J_STEP_DENOM, I_STEP_VALUE, I_STEP_DENOM, CHAR_BRIGHTNESS_0, CHAR_BRIGHTNESS_1, CHAR_BRIGHTNESS_2, CHAR_BRIGHTNESS_3, CHAR_BRIGHTNESS_4, CHAR_BRIGHTNESS_5, CHAR_BRIGHTNESS_6, CHAR_BRIGHTNESS_7, CHAR_BRIGHTNESS_8, CHAR_BRIGHTNESS_9, CHAR_BRIGHTNESS_10, CHAR_BRIGHTNESS_11, CHAR_BRIGHTNESS_12>
impl<const WIDTH: u8, const HEIGHT: u8, const J_STEP_VALUE: u8, const J_STEP_DENOM: u8, const I_STEP_VALUE: u8, const I_STEP_DENOM: u8, const CHAR_BRIGHTNESS_0: char, const CHAR_BRIGHTNESS_1: char, const CHAR_BRIGHTNESS_2: char, const CHAR_BRIGHTNESS_3: char, const CHAR_BRIGHTNESS_4: char, const CHAR_BRIGHTNESS_5: char, const CHAR_BRIGHTNESS_6: char, const CHAR_BRIGHTNESS_7: char, const CHAR_BRIGHTNESS_8: char, const CHAR_BRIGHTNESS_9: char, const CHAR_BRIGHTNESS_10: char, const CHAR_BRIGHTNESS_11: char, const CHAR_BRIGHTNESS_12: char> UnwindSafe for Donut<WIDTH, HEIGHT, J_STEP_VALUE, J_STEP_DENOM, I_STEP_VALUE, I_STEP_DENOM, CHAR_BRIGHTNESS_0, CHAR_BRIGHTNESS_1, CHAR_BRIGHTNESS_2, CHAR_BRIGHTNESS_3, CHAR_BRIGHTNESS_4, CHAR_BRIGHTNESS_5, CHAR_BRIGHTNESS_6, CHAR_BRIGHTNESS_7, CHAR_BRIGHTNESS_8, CHAR_BRIGHTNESS_9, CHAR_BRIGHTNESS_10, CHAR_BRIGHTNESS_11, CHAR_BRIGHTNESS_12>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more