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

Work on mosaic.

parent e178ecc7
No related branches found
No related tags found
No related merge requests found
src/image/raymarching0.png

34.4 KiB | W: | H:

src/image/raymarching0.png

51.1 KiB | W: | H:

src/image/raymarching0.png
src/image/raymarching0.png
src/image/raymarching0.png
src/image/raymarching0.png
  • 2-up
  • Swipe
  • Onion skin
src/image/rock1.png

473 KiB | W: | H:

src/image/rock1.png

147 KiB | W: | H:

src/image/rock1.png
src/image/rock1.png
src/image/rock1.png
src/image/rock1.png
  • 2-up
  • Swipe
  • Onion skin
src/rock1.png

147 KiB

......@@ -56,7 +56,9 @@ impl Slide for Title {
}
for example in &self.examples {
Image::default().height(ui.available_height() * 0.295).show(ui, example);
Image::default()
.height(ui.available_height() * 0.295)
.show(ui, example);
}
if let &TitleState::Title { fade_start } = &self.state {
......
......@@ -4,7 +4,7 @@ use crate::component::grid::Grid;
use crate::component::image::Image;
use crate::component::triangle::Triangle;
use crate::egui::{Color32, Context, TextureHandle, Ui, Vec2};
use crate::fade_in::{fade_in, fade_in_manual};
use crate::fade_in::{fade_in, fade_in_manual, fade_out_manual};
use crate::img;
use crate::slide::Slide;
use crate::window::WindowPosition;
......@@ -15,6 +15,7 @@ use eframe::epaint::CircleShape;
use imageproc::drawing::draw_filled_polygon_mut;
use rand::{thread_rng, Rng};
use std::collections::VecDeque;
use std::ops::Range;
pub struct Mosaic {
image: ColorImage,
......@@ -22,7 +23,7 @@ pub struct Mosaic {
grid: Grid,
state: MosaicState,
count: usize,
/// Triangles are briefly GPU rasterized but ultimately CPU rasterized
/// Triangles are briefly GPU rasterized but ultimately CPU rasterized.
triangles: VecDeque<Triangle>,
}
......@@ -52,8 +53,10 @@ enum MosaicState {
Triangles {
/// When we started fading in and using the edge detector.
edges: Option<(f64, Grid)>,
/// If we started using vignette yet.
vignette: bool,
/// When we started fading in the alignment arrows.
alignment: Option<f64>,
/// When we started fading in the vignette effect.
vignette: Option<(f64, Grid)>,
},
}
......@@ -124,10 +127,18 @@ impl Slide for Mosaic {
let (points, color) = triangle.polygon(self.grid.size_cells as u32).unwrap();
draw_filled_polygon_mut(&mut self.grid, &points, color);
} else {
self.state = MosaicState::Triangles { edges: None, vignette: false };
self.state = MosaicState::Triangles {
edges: None,
alignment: None,
vignette: None,
};
}
}
MosaicState::Triangles { edges, vignette } => {
MosaicState::Triangles {
edges,
alignment,
vignette,
} => {
if edges.is_none() {
const EDGE_RESOLUTION: usize = 200;
......@@ -157,8 +168,54 @@ impl Slide for Mosaic {
}
*edges = Some((ctx.input().time, grid));
} else if !*vignette {
*vignette = true;
} else if alignment.is_none() {
*alignment = Some(ctx.input().time);
} else if vignette.is_none() {
const VIGNETTE_RESOLUTION: usize = 200;
let mut grid = Grid {
name: "vignette",
position: WindowPosition::FromCenter(Vec2::new(-404.0, 130.0)),
size_cells: VIGNETTE_RESOLUTION,
size_pixels: VIGNETTE_RESOLUTION as f32,
stroke_width: 0.0,
margin: 8.0,
background: Color32::BLACK,
..Grid::default()
};
for (x, y, c) in grid.iter_mut() {
/// Linearly maps a number from one range to another, optionally clamping to the new range.
pub fn map_ranges(
number: f32,
old: Range<f32>,
new: Range<f32>,
clamp_to_range: bool,
) -> f32 {
let old_range = old.end - old.start;
let new_range = new.end - new.start;
let number_normalized = (number - old.start) / old_range;
let mut mapped = new.start + number_normalized * new_range;
if clamp_to_range {
if new.start <= new.end {
mapped = mapped.clamp(new.start, new.end);
} else {
mapped = mapped.clamp(new.end, new.start);
}
}
mapped
}
// Circle:
let pos_x = x as f32 / VIGNETTE_RESOLUTION as f32;
let pos_y = y as f32 / VIGNETTE_RESOLUTION as f32;
let pos = Pos2::new(pos_x, pos_y);
let distance = pos.distance(Pos2::new(0.5, 0.5));
let b = map_ranges(distance, 0.45..1.0, 255.0..0.0, true) as u8;
*c = Color32::from_rgb(b, b, b);
}
*vignette = Some((ctx.input().time, grid));
} else {
// Done with slide.
return true;
......@@ -280,16 +337,30 @@ impl Slide for Mosaic {
}));
}
}
MosaicState::Triangles { edges, vignette } => {
for _ in 0..(self.count / 8 + 10).min(537) {
MosaicState::Triangles {
edges,
alignment,
vignette,
} => {
for _ in 0..(self.count / 4 + 10).min(537) {
let x: f32 = rng.gen();
let y: f32 = rng.gen();
let mut size: f32 = (rng.gen::<f32>().max(0.5)
/ (5.0 + self.count as f32 * 0.05))
.max(0.015);
let rot = Rot2::from_angle(rng.gen::<f32>() * std::f32::consts::TAU);
let angle = if alignment.is_some() {
// TODO: 0.7 is a kludge.
if x > 0.7 {
-0.75 * std::f32::consts::PI
} else {
-0.25 * std::f32::consts::PI
}
} else {
rng.gen::<f32>() * std::f32::consts::TAU
};
let rot = Rot2::from_angle(angle);
let center = Pos2::new(x, y);
let mut fill = set_alpha(image_lookup(&self.image, center), 0.2);
let mut fill = image_lookup(&self.image, center);
// Use edge detection.
if let Some((_, edges)) = edges.as_ref() {
......@@ -314,24 +385,29 @@ impl Slide for Mosaic {
for c in 0..3 {
fill[c] = fill[c].saturating_add(5);
}
fill = set_alpha(fill, 0.2);
} else {
for c in 0..3 {
fill[c] = fill[c].saturating_sub(5);
}
fill = set_alpha(fill, 0.5);
}
} else {
fill = set_alpha(fill, 0.2);
}
if *vignette {
if vignette.is_some() {
let dist = center.distance(Pos2::new(0.5, 0.5));
for c in 0..3 {
fill[c] = fill[c].saturating_sub(((dist - 0.25).max(0.0) * 50.0) as u8)
fill[c] =
fill[c].saturating_sub(((dist - 0.2).max(0.0) * 50.0) as u8)
}
}
let triangle = Triangle {
points: [
center + rot * Vec2::new(-1.0, -1.0) * size,
center + rot * Vec2::new(1.0, -1.0) * size,
center + rot * Vec2::new(-1.0, 1.0) * size,
center + rot * Vec2::new(1.0, -0.5) * size,
center + rot * Vec2::new(-1.0, 0.0) * size,
center + rot * Vec2::new(1.0, 0.5) * size,
],
stroke_width: 0.0,
fill,
......@@ -347,6 +423,46 @@ impl Slide for Mosaic {
edges.show(ui.ctx());
});
}
if let Some(fade_start) = alignment.as_ref() {
let fade_out = vignette.as_ref().map(|(f, _)| *f).unwrap_or(f64::INFINITY);
fade_in_manual(ui, *fade_start, |ui, fade_in_alpha| {
fade_out_manual(ui, fade_out, |ui, fade_out_alpha| {
for i in 0..3 {
let offset = i as f32 * -0.1;
Arrow {
origin: to_screen * Pos2::new(0.65, 0.35 + offset),
tip: to_screen * Pos2::new(0.25, 0.75 + offset),
stroke: set_alpha(
Color32::WHITE,
fade_in_alpha * fade_out_alpha,
),
stroke_width: 4.0,
..Arrow::default()
}
.show(ui);
Arrow {
origin: to_screen * Pos2::new(0.75, 0.35 + offset),
tip: to_screen * Pos2::new(0.95, 0.55 + offset),
stroke: set_alpha(
Color32::WHITE,
fade_in_alpha * fade_out_alpha,
),
stroke_width: 4.0,
..Arrow::default()
}
.show(ui);
}
});
});
}
if let Some((fade_start, vignette)) = vignette.as_mut() {
fade_in_manual(ui, *fade_start, |ui, alpha| {
vignette.alpha = alpha;
vignette.show(ui.ctx());
});
}
}
_ => {}
}
......
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