Skip to content
Snippets Groups Projects
s5_fractals.rs 4.74 KiB
Newer Older
mod circle;
mod mandelbrot;
mod rectangle;

use crate::component::code::{pseudocode, Code};
Finn Bear's avatar
Finn Bear committed
use crate::component::grid::Grid;
use crate::egui::{Color32, Context, Frame, Ui};
use crate::slide::s5_fractals::circle::circle;
use crate::slide::s5_fractals::mandelbrot::mandelbrot;
use crate::slide::s5_fractals::rectangle::rectangle;
Finn Bear's avatar
Finn Bear committed
use crate::Slide;
use eframe::egui::style::Margin;

Finn Bear's avatar
Finn Bear committed
/// Mandelbrot, etc.
Finn Bear's avatar
Finn Bear committed
pub struct Fractals {
Finn Bear's avatar
Finn Bear committed
    /// Where we are in the transitions.
    state: FractalsState,
Finn Bear's avatar
Finn Bear committed
    /// Pseudocode display.
Finn Bear's avatar
Finn Bear committed
    code: Code,
Finn Bear's avatar
Finn Bear committed
    /// Persistent grid state.
Finn Bear's avatar
Finn Bear committed
    grid: Grid,
}

#[derive(Default)]
#[allow(unused)]
enum FractalsState {
Finn Bear's avatar
Finn Bear committed
    /// Nothing on screen (except header).
    #[default]
    Before,
Finn Bear's avatar
Finn Bear committed
    /// Fading in grid.
    Grid {
Finn Bear's avatar
Finn Bear committed
        /// When we started fading in the grid.
        fade_start: f64,
    },
    Rectangle {
Finn Bear's avatar
Finn Bear committed
        /// TODO(finnb): How many pixels of the grid we've filled in.
        pixel: usize,
    },
    Circle {
Finn Bear's avatar
Finn Bear committed
        /// TODO(finnb): How many pixels of the grid we've filled in.
        pixel: usize,
    },
    Mandelbrot {
Finn Bear's avatar
Finn Bear committed
        /// TODO(finnb): How many pixels of the grid we've filled in.
        pixel: usize,
    },
}

Finn Bear's avatar
Finn Bear committed
impl Default for Fractals {
    fn default() -> Self {
        const HORIZONTAL_OFFSET: f32 = 275.0;

Finn Bear's avatar
Finn Bear committed
        // Code goes on the left.
Finn Bear's avatar
Finn Bear committed
        let mut code = Code::default();
        code.name = "fractal_code";
        code.offset_x = -HORIZONTAL_OFFSET;
Finn Bear's avatar
Finn Bear committed

Finn Bear's avatar
Finn Bear committed
        // Grid goes on the right.
        let mut grid = Grid::default();
        grid.name = "fractal_grid";
        grid.offset_x = HORIZONTAL_OFFSET;
Finn Bear's avatar
Finn Bear committed

        grid.size_cells = 256;
Finn Bear's avatar
Finn Bear committed

        // Grid cell stroke aliases too much at this resolution.
        grid.stroke_width = 0.0;

        Self {
            state: FractalsState::default(),
            code,
            grid,
        }
    }
Finn Bear's avatar
Finn Bear committed
}

impl Slide for Fractals {
    fn transition(&mut self, ctx: &Context) -> bool {
        // Increment state by one.
        match self.state {
            FractalsState::Before => {
                self.state = FractalsState::Grid {
                    fade_start: ctx.input().time,
                }
            }
Finn Bear's avatar
Finn Bear committed
            FractalsState::Grid { .. } => {
                // Make sure we finished fading in.
                self.code.alpha = 1.0;
                self.grid.alpha = 1.0;

                self.state = FractalsState::Rectangle { pixel: 0 }
            }
            FractalsState::Rectangle { .. } => self.state = FractalsState::Circle { pixel: 0 },
            FractalsState::Circle { .. } => self.state = FractalsState::Mandelbrot { pixel: 0 },
            FractalsState::Mandelbrot { .. } => return true,
        }
        false
    }
Finn Bear's avatar
Finn Bear committed

    fn show(&mut self, ui: &mut Ui) {
        Frame::none().margin(Margin::same(20.0)).show(ui, |ui| {
            ui.vertical_centered(|ui| {
                ui.heading("Fractals");
            });
        });
Finn Bear's avatar
Finn Bear committed

        ui.ctx().request_repaint();

Finn Bear's avatar
Finn Bear committed
        // The function that will be used to color the grid.
        let algo: Box<dyn Fn(f32, f32) -> bool>;

        match self.state {
            FractalsState::Before => {
Finn Bear's avatar
Finn Bear committed
                // Don't proceed to render the code/grid.
                return;
            }
            FractalsState::Grid { fade_start } => {
Finn Bear's avatar
Finn Bear committed
                // Fade in the code and grid.
                let elapsed = ui.ctx().input().time - fade_start;
                let alpha = (elapsed * 2.0).min(1.0) as f32;
                self.code.alpha = alpha;
                self.grid.alpha = alpha;
                algo = Box::new(|_, _| false);
            }
            FractalsState::Rectangle { .. } => {
                self.code.code = pseudocode(include_str!("s5_fractals/rectangle.rs"));
                algo = Box::new(rectangle);
            }
            FractalsState::Circle { .. } => {
                self.code.code = pseudocode(include_str!("s5_fractals/circle.rs"));
                algo = Box::new(circle);
            }
            FractalsState::Mandelbrot { .. } => {
                self.code.code = pseudocode(include_str!("s5_fractals/mandelbrot.rs"));
                algo = Box::new(mandelbrot);
            }
        }
Finn Bear's avatar
Finn Bear committed

Finn Bear's avatar
Finn Bear committed
        // TODO: Different demos may need different resolutions.
        const RESOLUTION: usize = 256;
Finn Bear's avatar
Finn Bear committed

Finn Bear's avatar
Finn Bear committed
        // Paint the grid.
        // TODO(finnb): Paint pixel by pixel.
        for (gx, gy, c) in self.grid.iter_mut() {
Finn Bear's avatar
Finn Bear committed
            // 0 to 1.
            let nx = (gx as f32 + 0.5) / RESOLUTION as f32;
            let ny = (gy as f32 + 0.5) / RESOLUTION as f32;

            // -4 to 4.
            let x = nx * 4.0 - 2.0;
            let y = ny * 4.0 - 2.0;

            *c = if algo(x, y) {
Finn Bear's avatar
Finn Bear committed
                Color32::BLACK
            } else {
                Color32::TRANSPARENT
            };
        }

        self.code.show(ui.ctx());
        self.grid.show(ui.ctx());
Finn Bear's avatar
Finn Bear committed
    }
}