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

Computation slide MVP.

parent babe06d6
No related branches found
No related tags found
No related merge requests found
......@@ -4,4 +4,5 @@
pub mod arrow;
pub mod code;
pub mod grid;
pub mod image;
pub mod triangle;
use crate::color::{set_alpha, set_style_alpha};
use crate::egui::{Color32, TextureHandle, Ui};
use eframe::egui;
use eframe::egui::style::Margin;
use eframe::egui::{Frame, Pos2, Vec2, Widget, Window};
/// A bitmap image i.e. an example of generative art.
pub struct Image {
/// How many pixels of height the images should occupy.
pub height: f32,
/// How opaque the image is.
pub alpha: f32,
/// Center position.
pub position: Option<Pos2>,
}
impl Default for Image {
fn default() -> Self {
Self::new(128.0, 1.0, None)
}
}
impl Image {
pub fn new(height: f32, alpha: f32, position: Option<Pos2>) -> Self {
Self {
height,
alpha,
position,
}
}
/// Change the height of the image.
pub fn height(mut self, height: f32) -> Self {
self.height = height;
self
}
/// Change the alpha of the image.
pub fn alpha(mut self, alpha: f32) -> Self {
self.alpha = alpha;
self
}
/// Change the position of the image.
pub fn position(mut self, position: Pos2) -> Self {
// We assume that, if you call this method, you don't want [`None`].
self.position = Some(position);
self
}
pub fn show(&mut self, ui: &mut Ui, texture: &TextureHandle) {
let mut window = Window::new(texture.name())
.title_bar(false)
.resizable(false)
// Reduce margin of images.
.frame(
Frame::window(&set_style_alpha(ui.style(), self.alpha)).margin(Margin::same(5.0)),
);
if let Some(position) = self.position {
window = window.default_pos(position).fixed_pos(position);
}
window.show(ui.ctx(), |ui| {
// TODO: Support non-square images.
egui::Image::new(texture, Vec2::splat(self.height))
.tint(set_alpha(Color32::WHITE, self.alpha))
.ui(ui);
});
}
}
......@@ -10,7 +10,7 @@ pub fn fade_in<R>(
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
let since_transition = ui.ctx().input().time - fade_start;
let alpha = (since_transition * (1.0 / FADE_DURATION)).min(1.0) as f32;
let alpha = (since_transition * (1.0 / FADE_DURATION)).clamp(0.0, 1.0) as f32;
if alpha < 1.0 {
// The fade isn't done yet, so schedule another render.
ui.ctx().request_repaint();
......
src/image/fluid0.png

90.5 KiB

src/image/raytracing0.png

19.9 KiB

use crate::component::image::Image;
use crate::egui::{Align2, Context};
use crate::fade_in::fade_in;
use crate::slide::Slide;
......@@ -47,14 +48,7 @@ impl Slide for Title {
}
for example in &self.examples {
Window::new(example.name())
.title_bar(false)
.resizable(false)
// Reduce margin of example images.
.frame(Frame::window(&ui.style()).margin(Margin::same(5.0)))
.show(ui.ctx(), |ui| {
ui.image(example, Vec2::splat(128.0));
});
Image::default().show(ui, example);
}
if let &TitleState::Title { fade_start } = &self.state {
......
use crate::color::set_alpha;
use crate::component::arrow::Arrow;
use crate::component::grid::Grid;
use crate::component::image::Image;
use crate::ctx_img;
use crate::egui::{Align2, Context, TextureHandle, Vec2, Window};
use crate::fade_in::{fade_in, fade_in_manual};
......@@ -119,17 +120,11 @@ impl Slide for Automata {
});
// TODO: Fade/move/position as appropriate.
Window::new("portrait")
.title_bar(false)
.resizable(false)
.frame(Frame::window(&ui.style()).margin(Margin::same(5.0)))
.show(ui.ctx(), |ui| {
ui.image(
self.conway_portrait
.get_or_insert_with(|| ctx_img!(ui.ctx(), "conway_portrait.png")),
Vec2::splat(128.0),
);
});
Image::default().show(
ui,
self.conway_portrait
.get_or_insert_with(|| ctx_img!(ui.ctx(), "conway_portrait.png")),
);
// Need to continuously animate the grid, or at least poll the governor.
ui.ctx().request_repaint();
......@@ -156,7 +151,7 @@ impl Slide for Automata {
} => {
// Iterate grid ~5 times a second.
if self.governor.ready(ui.ctx().input().time, 0.2) {
// Schedule some special events at some interation counts.
// Schedule some special events at some iteration counts.
match *iterations {
10 => {
// Automatically begin expansion.
......@@ -201,7 +196,9 @@ impl Slide for Automata {
}
if let Some(rules_fade) = rules_fade {
fade_in(ui, rules_fade, |ui| {
// Give some time for the grid to slide left.
const RULES_DELAY: f64 = 0.3;
fade_in(ui, rules_fade + RULES_DELAY, |ui| {
Window::new("conway_rules")
.frame(Frame::window(&ui.style()))
.anchor(Align2::CENTER_CENTER, Vec2::new(HORIZONTAL_OFFSET, 0.0))
......@@ -209,7 +206,7 @@ impl Slide for Automata {
.resizable(false)
.show(ui.ctx(), |ui| {
// Nested fade in since fade doesn't propagate from [`Window`] to children.
fade_in(ui, rules_fade, |ui| {
fade_in(ui, rules_fade + RULES_DELAY, |ui| {
ui.label(" ⏵ Cells with fewer than two neighbors die");
ui.label(" ⏵ Cells with more than three neighbors die");
ui.label(" ⏵ Cells with three neighbors become alive");
......
use crate::egui::{Frame, Ui};
use crate::component::image::Image;
use crate::ctx_img;
use crate::egui::{Context, Frame, Ui};
use crate::fade_in::{fade_in, fade_in_manual};
use crate::slide::Slide;
use eframe::egui::style::Margin;
use eframe::egui::{Pos2, TextureHandle};
#[derive(Default)]
pub struct Computation {}
pub struct Computation {
/// Will fade in one by one.
examples: Vec<ComputationExample>,
}
/// One bullet point and texture combination.
struct ComputationExample {
/// Bullet point text.
label: &'static str,
/// Texture handle to render on the right side.
texture: TextureHandle,
/// When we started fading it ([`None`] if we haven't started yet).
fade_start: Option<f64>,
}
impl ComputationExample {
pub fn new(label: &'static str, texture: TextureHandle) -> Self {
Self {
label,
texture,
fade_start: None,
}
}
}
impl Slide for Computation {
fn transition(&mut self, ctx: &Context) -> bool {
for example in &mut self.examples {
if example.fade_start.is_none() {
// If any image has not yet started fading in, fade it in and don't go to next slide.
example.fade_start = Some(ctx.input().time);
return false;
}
}
true
}
fn show(&mut self, ui: &mut Ui) {
if self.examples.is_empty() {
// For now, these images are somewhat like placeholders.
self.examples = vec![
ComputationExample::new("Raytracing", ctx_img!(ui.ctx(), "raytracing0.png")),
ComputationExample::new("Raymarching", ctx_img!(ui.ctx(), "raymarching1.png")),
ComputationExample::new("Particle simulation", ctx_img!(ui.ctx(), "atom0.png")),
ComputationExample::new("Fluid simulation", ctx_img!(ui.ctx(), "fluid0.png")),
]
}
const IMAGE_SCALE: f32 = 256.0;
let window_width = ui.available_width();
let window_height = ui.available_height();
let window_width_per_image = window_width / self.examples.len() as f32;
Frame::none().margin(Margin::same(20.0)).show(ui, |ui| {
ui.heading("More Computation-based Art");
ui.add_space(8.0);
ui.label(" ⏵ Raytracing");
ui.label(" ⏵ Raymarching");
ui.label(" ⏵ Particle simulations");
ui.label(" ⏵ Fluid simulations");
for (i, example) in self.examples.iter().enumerate() {
if let Some(fade_start) = example.fade_start {
fade_in(ui, fade_start, |ui| {
ui.label(format!(" ⏵ {}", example.label));
});
fade_in_manual(ui, fade_start, |ui, alpha| {
let position = Pos2::new(
(window_width_per_image - IMAGE_SCALE) * 0.5
+ window_width * (i as f32) / self.examples.len() as f32,
window_height - IMAGE_SCALE * 1.1,
);
Image::default()
.height(IMAGE_SCALE)
.position(position)
.alpha(alpha)
.show(ui, &example.texture);
});
}
}
});
}
}
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