Skip to content
Snippets Groups Projects
Commit c7349784 authored by Finn Bear's avatar Finn Bear
Browse files

Document the slides.

parent 2b1c00ea
No related branches found
No related tags found
No related merge requests found
...@@ -3,6 +3,7 @@ use crate::{ctx_img, img, Margin, Slide}; ...@@ -3,6 +3,7 @@ use crate::{ctx_img, img, Margin, Slide};
use eframe::egui; use eframe::egui;
use eframe::egui::{Frame, Ui, Vec2, Window}; use eframe::egui::{Frame, Ui, Vec2, Window};
/// The first slide in the cartoon.
#[derive(Default)] #[derive(Default)]
pub struct Title { pub struct Title {
examples: Vec<egui::TextureHandle>, examples: Vec<egui::TextureHandle>,
...@@ -11,6 +12,7 @@ pub struct Title { ...@@ -11,6 +12,7 @@ pub struct Title {
impl Slide for Title { impl Slide for Title {
fn show(&mut self, ui: &mut Ui) { fn show(&mut self, ui: &mut Ui) {
if self.examples.is_empty() { if self.examples.is_empty() {
// For now, these images are somewhat like placeholders.
self.examples = vec![ self.examples = vec![
ctx_img!(ui.ctx(), "raymarching0.png"), ctx_img!(ui.ctx(), "raymarching0.png"),
ctx_img!(ui.ctx(), "raymarching1.png"), ctx_img!(ui.ctx(), "raymarching1.png"),
...@@ -20,19 +22,16 @@ impl Slide for Title { ...@@ -20,19 +22,16 @@ impl Slide for Title {
]; ];
} }
ui.scope(|ui| { for example in &self.examples {
ui.style_mut().spacing.window_margin = Margin::same(4.0); Window::new(example.name())
.title_bar(false)
for example in &self.examples { .resizable(false)
Window::new(example.name()) // Reduce margin of example images.
.title_bar(false) .frame(Frame::window(&ui.style()).margin(Margin::same(5.0)))
.resizable(false) .show(ui.ctx(), |ui| {
.frame(Frame::window(&ui.style()).margin(Margin::same(5.0))) ui.image(example, Vec2::splat(128.0));
.show(ui.ctx(), |ui| { });
ui.image(example, Vec2::splat(128.0)); }
});
}
});
Window::new("title") Window::new("title")
.title_bar(false) .title_bar(false)
......
use crate::{fade_in, Margin, Slide}; use crate::{fade_in, Margin, Slide};
use eframe::egui::{Context, Frame, Ui}; use eframe::egui::{Context, Frame, Ui};
/// A slide that sets some expectations about generative art.
#[derive(Default)] #[derive(Default)]
pub struct Introduction { pub struct Introduction {
state: IntroductionState, state: IntroductionState,
...@@ -11,6 +12,7 @@ enum IntroductionState { ...@@ -11,6 +12,7 @@ enum IntroductionState {
#[default] #[default]
Weaknesses, Weaknesses,
Strengths { Strengths {
/// What time we started fading in the strengths.
transition_time: f64, transition_time: f64,
}, },
} }
......
...@@ -4,27 +4,36 @@ use eframe::egui::text_edit::{CCursorRange, TextEditState}; ...@@ -4,27 +4,36 @@ use eframe::egui::text_edit::{CCursorRange, TextEditState};
use eframe::egui::{Align2, Frame, TextEdit, Vec2, Widget}; use eframe::egui::{Align2, Frame, TextEdit, Vec2, Widget};
use eframe::epaint::text::cursor::CCursor; use eframe::epaint::text::cursor::CCursor;
/// Introduction for emergent complexity.
#[derive(Default)] #[derive(Default)]
pub struct Complexity { pub struct Complexity {
state: ComplexityState, state: ComplexityState,
last_time: f64, last_time: f64,
} }
/// What state we are in, with respect to the action of selecting "Complex" and replacing it
/// with "Simple."
#[derive(Default, Eq, PartialEq, Debug)] #[derive(Default, Eq, PartialEq, Debug)]
enum ComplexityState { enum ComplexityState {
/// Haven't started the transition yet.
#[default] #[default]
Before, Before,
/// Selected this many characters of "Complex."
Selecting(usize), Selecting(usize),
/// Typed this many characters of "Simple."
Typing(usize), Typing(usize),
/// Animation over.
After, After,
} }
impl Slide for Complexity { impl Slide for Complexity {
fn transition(&mut self, _ctx: &Context) -> bool { fn transition(&mut self, _ctx: &Context) -> bool {
if self.state == ComplexityState::Before { if self.state == ComplexityState::Before {
// If we haven't started the animation, start it.
self.state = ComplexityState::Selecting(0); self.state = ComplexityState::Selecting(0);
false false
} else { } else {
// Otherwise, continue to next slide.
true true
} }
} }
...@@ -33,11 +42,15 @@ impl Slide for Complexity { ...@@ -33,11 +42,15 @@ impl Slide for Complexity {
Window::new("complexity") Window::new("complexity")
.title_bar(false) .title_bar(false)
.resizable(false) .resizable(false)
// Don't show window background.
.frame(Frame::none()) .frame(Frame::none())
.anchor(Align2::CENTER_CENTER, Vec2::ZERO) .anchor(Align2::CENTER_CENTER, Vec2::ZERO)
// Width was determined anecdotally. Height is arbitrary.
.fixed_size(Vec2::new(440.0, 100.0)) .fixed_size(Vec2::new(440.0, 100.0))
.show(ui.ctx(), |ui| { .show(ui.ctx(), |ui| {
ui.ctx().request_repaint(); ui.ctx().request_repaint();
// TODO(finnb) replace with [`Governor`].
let time = ui.input().time; let time = ui.input().time;
let time_delta = (time - self.last_time).min(1.0); let time_delta = (time - self.last_time).min(1.0);
let made_progress = time_delta > 0.1; let made_progress = time_delta > 0.1;
...@@ -85,8 +98,10 @@ impl Slide for Complexity { ...@@ -85,8 +98,10 @@ impl Slide for Complexity {
.desired_width(f32::INFINITY) .desired_width(f32::INFINITY)
.ui(ui); .ui(ui);
if state.ccursor_range().is_some() { if state.ccursor_range().is_some() {
// Necessary to render selecting.
text_edit.request_focus(); text_edit.request_focus();
} else { } else {
// We're done selecting.
text_edit.surrender_focus(); text_edit.surrender_focus();
} }
TextEdit::store_state(ui.ctx(), text_edit.id, state); TextEdit::store_state(ui.ctx(), text_edit.id, state);
......
...@@ -5,15 +5,21 @@ use eframe::egui::style::Margin; ...@@ -5,15 +5,21 @@ use eframe::egui::style::Margin;
use eframe::egui::{Color32, Frame, Ui}; use eframe::egui::{Color32, Frame, Ui};
use rand::Rng; use rand::Rng;
/// Conway's Game of Life, etc.
pub struct Automata { pub struct Automata {
/// Persistent state of the grid.
life: Grid, life: Grid,
/// For knowing when to advance the simulation.
governor: Governor, governor: Governor,
} }
impl Default for Automata { impl Default for Automata {
fn default() -> Self { fn default() -> Self {
let mut life = Grid::default(); let mut life = Grid::default();
// Unique identifier for the grid.
life.name = "life"; life.name = "life";
// Fill grid with random cells.
for y in 0..life.size_cells { for y in 0..life.size_cells {
for x in 0..life.size_cells { for x in 0..life.size_cells {
if rand::thread_rng().gen_bool(0.5) { if rand::thread_rng().gen_bool(0.5) {
...@@ -22,6 +28,7 @@ impl Default for Automata { ...@@ -22,6 +28,7 @@ impl Default for Automata {
} }
} }
// This would replace the grid with a single oscillator.
/* /*
life.clear_fill(); life.clear_fill();
life.set_fill(5, 5, Color32::BLACK); life.set_fill(5, 5, Color32::BLACK);
...@@ -44,7 +51,9 @@ impl Slide for Automata { ...@@ -44,7 +51,9 @@ impl Slide for Automata {
}); });
}); });
// Need to continuously animate the grid, or at least poll the governor.
ui.ctx().request_repaint(); ui.ctx().request_repaint();
if self.governor.ready(ui.ctx().input().time, 0.2) { if self.governor.ready(ui.ctx().input().time, 0.2) {
self.life = conways_game_of_life(&self.life); self.life = conways_game_of_life(&self.life);
} }
...@@ -52,6 +61,7 @@ impl Slide for Automata { ...@@ -52,6 +61,7 @@ impl Slide for Automata {
} }
} }
/// Run one iteration of Conway's Game of Life on the grid, producing a new grid.
fn conways_game_of_life(grid: &Grid) -> Grid { fn conways_game_of_life(grid: &Grid) -> Grid {
let mut new = grid.clone(); let mut new = grid.clone();
new.clear_fill(); new.clear_fill();
......
...@@ -11,27 +11,37 @@ use crate::slide::s5_fractals::rectangle::rectangle; ...@@ -11,27 +11,37 @@ use crate::slide::s5_fractals::rectangle::rectangle;
use crate::Slide; use crate::Slide;
use eframe::egui::style::Margin; use eframe::egui::style::Margin;
/// Mandelbrot, etc.
pub struct Fractals { pub struct Fractals {
/// Where we are in the transitions.
state: FractalsState, state: FractalsState,
/// Pseudocode display.
code: Code, code: Code,
/// Persistent grid state.
grid: Grid, grid: Grid,
} }
#[derive(Default)] #[derive(Default)]
#[allow(unused)] #[allow(unused)]
enum FractalsState { enum FractalsState {
/// Nothing on screen (except header).
#[default] #[default]
Before, Before,
/// Fading in grid.
Grid { Grid {
/// When we started fading in the grid.
fade_start: f64, fade_start: f64,
}, },
Rectangle { Rectangle {
/// TODO(finnb): How many pixels of the grid we've filled in.
pixel: usize, pixel: usize,
}, },
Circle { Circle {
/// TODO(finnb): How many pixels of the grid we've filled in.
pixel: usize, pixel: usize,
}, },
Mandelbrot { Mandelbrot {
/// TODO(finnb): How many pixels of the grid we've filled in.
pixel: usize, pixel: usize,
}, },
} }
...@@ -40,15 +50,19 @@ impl Default for Fractals { ...@@ -40,15 +50,19 @@ impl Default for Fractals {
fn default() -> Self { fn default() -> Self {
const HORIZONTAL_OFFSET: f32 = 275.0; const HORIZONTAL_OFFSET: f32 = 275.0;
// Code goes on the left.
let mut code = Code::default(); let mut code = Code::default();
code.name = "fractal_code"; code.name = "fractal_code";
code.offset_x = -HORIZONTAL_OFFSET; code.offset_x = -HORIZONTAL_OFFSET;
// Grid goes on the right.
let mut grid = Grid::default(); let mut grid = Grid::default();
grid.name = "fractal_grid"; grid.name = "fractal_grid";
grid.offset_x = HORIZONTAL_OFFSET; grid.offset_x = HORIZONTAL_OFFSET;
grid.size_cells = 256; grid.size_cells = 256;
// Grid cell stroke aliases too much at this resolution.
grid.stroke_width = 0.0; grid.stroke_width = 0.0;
Self { Self {
...@@ -68,7 +82,13 @@ impl Slide for Fractals { ...@@ -68,7 +82,13 @@ impl Slide for Fractals {
fade_start: ctx.input().time, fade_start: ctx.input().time,
} }
} }
FractalsState::Grid { .. } => self.state = FractalsState::Rectangle { pixel: 0 }, 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::Rectangle { .. } => self.state = FractalsState::Circle { pixel: 0 },
FractalsState::Circle { .. } => self.state = FractalsState::Mandelbrot { pixel: 0 }, FractalsState::Circle { .. } => self.state = FractalsState::Mandelbrot { pixel: 0 },
FractalsState::Mandelbrot { .. } => return true, FractalsState::Mandelbrot { .. } => return true,
...@@ -85,13 +105,16 @@ impl Slide for Fractals { ...@@ -85,13 +105,16 @@ impl Slide for Fractals {
ui.ctx().request_repaint(); ui.ctx().request_repaint();
// The function that will be used to color the grid.
let algo: Box<dyn Fn(f32, f32) -> bool>; let algo: Box<dyn Fn(f32, f32) -> bool>;
match self.state { match self.state {
FractalsState::Before => { FractalsState::Before => {
// Don't proceed to render the code/grid.
return; return;
} }
FractalsState::Grid { fade_start } => { FractalsState::Grid { fade_start } => {
// Fade in the code and grid.
let elapsed = ui.ctx().input().time - fade_start; let elapsed = ui.ctx().input().time - fade_start;
let alpha = (elapsed * 2.0).min(1.0) as f32; let alpha = (elapsed * 2.0).min(1.0) as f32;
self.code.alpha = alpha; self.code.alpha = alpha;
...@@ -112,8 +135,11 @@ impl Slide for Fractals { ...@@ -112,8 +135,11 @@ impl Slide for Fractals {
} }
} }
// TODO: Different demos may need different resolutions.
const RESOLUTION: usize = 256; const RESOLUTION: usize = 256;
// Paint the grid.
// TODO(finnb): Paint pixel by pixel.
for (gx, gy, c) in self.grid.iter_mut() { for (gx, gy, c) in self.grid.iter_mut() {
// 0 to 1. // 0 to 1.
let nx = (gx as f32 + 0.5) / RESOLUTION as f32; let nx = (gx as f32 + 0.5) / RESOLUTION as f32;
......
...@@ -8,6 +8,7 @@ pub struct Mosaic {} ...@@ -8,6 +8,7 @@ pub struct Mosaic {}
impl Slide for Mosaic { impl Slide for Mosaic {
fn show(&mut self, ui: &mut Ui) { fn show(&mut self, ui: &mut Ui) {
// TODO: Finish this slide.
Frame::none().margin(Margin::same(20.0)).show(ui, |ui| { Frame::none().margin(Margin::same(20.0)).show(ui, |ui| {
ui.heading("Going Further"); ui.heading("Going Further");
ui.add_space(8.0); ui.add_space(8.0);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment