animations: rewrite animations with improved surface capabilities

This commit is contained in:
Victoria Fischer 2024-11-24 21:55:24 +01:00
parent d17baa754f
commit 3783bc60b2
2 changed files with 128 additions and 52 deletions

View File

@ -3,102 +3,159 @@ use palette::Hsv;
use rgb::RGB8; use rgb::RGB8;
use crate::time::Periodically; use crate::time::Periodically;
use crate::geometry::{Coordinates, VirtualCoordinates}; use crate::geometry::*;
use crate::render::{Shader, Surface}; use crate::render::{Shader, Surface, Surfaces};
use crate::task::Task; use crate::task::Task;
use crate::lib8::IntoRgb8; use crate::lib8::{trig::{sin8, cos8}, interpolate::scale8, noise::inoise8, IntoRgb8};
#[derive(Debug)] #[derive(Debug)]
pub struct IdleTask<T: Surface> { pub struct IdleTask<T: Surface> {
frame: u8, solid: T,
surface: T, surface: T,
updater: Periodically shimmer: T,
} }
#[derive(Debug)] #[derive(Debug)]
struct IdleShader { struct SolidShader {}
frame: u8
impl Shader for SolidShader {
fn draw(&self, _coords: &VirtualCoordinates, frame: usize) -> RGB8 {
Hsv::new_srgb((frame / 4 % 255) as u8, 255, sin8((frame % 64) as u8)).into_rgb8()
}
} }
impl Shader for IdleShader { #[derive(Debug)]
fn draw(&self, coords: &VirtualCoordinates, frame: u8) -> RGB8 { struct ShimmerShader {}
Hsv::new_srgb(frame.wrapping_add(coords.x).wrapping_add(coords.y), 255, 255).into_rgb8()
impl Shader for ShimmerShader {
fn draw(&self, coords: &VirtualCoordinates, frame: usize) -> RGB8 {
Hsv::new_srgb(coords.x.wrapping_add((frame / 3) as u8), coords.y, sin8(frame as u8 % 255).max(75).min(64)).into_rgb8()
}
}
#[derive(Debug)]
struct ThinkingShader {}
impl Shader for ThinkingShader {
fn draw(&self, coords: &VirtualCoordinates, frame: usize) -> RGB8 {
//let noise_x = sin8(sin8((frame % 255) as u8).wrapping_add(coords.x));
//let noise_y = cos8(cos8((frame % 255) as u8).wrapping_add(coords.y));
let offset_x = sin8(((frame % 255) as u8).wrapping_add(coords.x));
let offset_y = cos8(((frame % 255) as u8).wrapping_add(coords.y));
let noise_x = offset_x / 2;
let noise_y = offset_y / 2;
//let noise_x = coords.x.wrapping_add(offset_x);
//let noise_y = coords.y.wrapping_add(offset_y);
Hsv::new_srgb(
inoise8(noise_x as i16, noise_y as i16),
128_u8.saturating_add(inoise8(noise_y as i16, noise_x as i16)),
255
).into_rgb8()
}
}
#[derive(Debug)]
struct GayBarberShader {}
impl Shader for GayBarberShader {
fn draw(&self, coords: &VirtualCoordinates, frame: usize) -> RGB8 {
Hsv::new_srgb((frame as u8).wrapping_add(coords.x).wrapping_add(coords.y), 255, sin8((frame % 128) as u8)).into_rgb8()
} }
} }
impl<T: Surface> IdleTask<T> { impl<T: Surface> IdleTask<T> {
pub fn new(surface: T) -> Self { pub fn new<S: Surfaces<T>>(surfaces: &mut S) -> Self {
IdleTask { IdleTask {
frame: 0, solid: surfaces.new_surface(&Rectangle::everything()).unwrap(),
surface: surface, surface: surfaces.new_surface(&Rectangle::everything()).unwrap(),
updater: Periodically::new_every_n_ms(16) shimmer: surfaces.new_surface(&Rectangle::everything()).unwrap(),
} }
} }
} }
impl<T: Surface> Task for IdleTask<T> { impl<T: Surface> Task for IdleTask<T> {
fn start(&mut self) { fn start(&mut self) {
self.surface.set_shader(Box::new(IdleShader { frame: self.frame })); self.solid.set_shader(Box::new(SolidShader { }));
self.surface.set_shader(Box::new(ThinkingShader { }));
self.shimmer.set_shader(Box::new(ShimmerShader { }));
self.solid.set_opacity(64);
self.surface.set_opacity(128);
self.shimmer.set_opacity(64);
} }
fn tick(&mut self) { fn tick(&mut self) {}
self.updater.run(|| {
self.frame = self.frame.wrapping_add(1);
self.surface.set_shader(Box::new(IdleShader { frame: self.frame }));
})
}
fn stop(&mut self) { fn stop(&mut self) {
self.solid.clear_shader();
self.surface.clear_shader(); self.surface.clear_shader();
self.shimmer.clear_shader();
} }
} }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
enum Pattern { enum TestShader {
Red, Red,
Green, Green,
Blue, Blue,
White, White,
RGB, RGB,
HSV, HSV,
Outline Outline,
SweepX,
SweepY,
SinX,
SinY,
Metaballs
} }
impl Pattern { impl TestShader {
pub fn next(self) -> Pattern { pub fn next(self) -> Self {
match self { match self {
Pattern::Red => Pattern::Green, Self::Red => Self::Green,
Pattern::Green => Pattern::Blue, Self::Green => Self::Blue,
Pattern::Blue => Pattern::White, Self::Blue => Self::White,
Pattern::White => Pattern::RGB, Self::White => Self::RGB,
Pattern::RGB => Pattern::HSV, Self::RGB => Self::HSV,
Pattern::HSV => Pattern::Outline, Self::HSV => Self::Outline,
Pattern::Outline => Pattern::Red Self::Outline => Self::SweepX,
Self::SweepX => Self::SweepY,
Self::SweepY => Self::SinX,
Self::SinX => Self::SinY,
Self::SinY => Self::Metaballs,
Self::Metaballs => Self::RGB
} }
} }
} }
#[derive(Debug)]
struct TestShader {
pattern: Pattern
}
impl Shader for TestShader { impl Shader for TestShader {
fn draw(&self, coords: &VirtualCoordinates, _frame: usize) -> RGB8 { fn draw(&self, coords: &VirtualCoordinates, frame: usize) -> RGB8 {
match self.pattern { match self {
Pattern::Red => RGB8::new(255, 0, 0), Self::Red => RGB8::new(255, 0, 0),
Pattern::Green => RGB8::new(0, 255, 0), Self::Green => RGB8::new(0, 255, 0),
Pattern::Blue => RGB8::new(0, 0, 255), Self::Blue => RGB8::new(0, 0, 255),
Pattern::White => RGB8::new(255, 255, 255), Self::White => RGB8::new(255, 255, 255),
Pattern::RGB => RGB8::new(coords.x, coords.y, 255 - (coords.x / 2 + coords.y / 2)), Self::RGB => RGB8::new(coords.x, coords.y, 255 - (coords.x / 2 + coords.y / 2)),
Pattern::HSV => Hsv::new_srgb(coords.x, coords.y, 255 - (coords.x / 2 + coords.y / 2)).into_rgb8(), Self::HSV => Hsv::new_srgb(coords.x, coords.y, 255).into_rgb8(),
Pattern::Outline => match (coords.x, coords.y) { Self::Outline => match (coords.x, coords.y) {
(0, 0) => RGB8::new(255, 255, 255), (0, 0) => RGB8::new(255, 255, 255),
(0, _) => RGB8::new(255, 0, 0), (0, _) => RGB8::new(255, 0, 0),
(_, 0) => RGB8::new(0, 255, 0), (_, 0) => RGB8::new(0, 255, 0),
(255, _) => RGB8::new(0, 0, 255), (255, _) => RGB8::new(0, 0, 255),
(_, 255) => RGB8::new(0, 0, 255), (_, 255) => RGB8::new(0, 0, 255),
_ => RGB8::new(0, 0, 0) _ => RGB8::new(0, 0, 0)
},
Self::SweepX => RGB8::new(255, 0, 0),
Self::SweepY => RGB8::new(255, 0, 0),
Self::SinX => RGB8::new(sin8(coords.x.wrapping_add((frame % 255) as u8)), 0, 0),
Self::SinY => RGB8::new(sin8(coords.y.wrapping_add((frame % 255) as u8)), 0, 0),
Self::Metaballs => {
let ball_center = Coordinates::new(
scale8(64, sin8(frame)) + 128,
scale8(64, cos8(frame)) + 128
);
let dist = 255 - coords.distance_to(&ball_center);
RGB8::new(dist, 0, 0)
} }
} }
} }
@ -108,26 +165,45 @@ impl Shader for TestShader {
pub struct TestPattern<T: Surface> { pub struct TestPattern<T: Surface> {
surface: T, surface: T,
updater: Periodically, updater: Periodically,
pattern: Pattern stepper: Periodically,
pattern: TestShader,
frame: u8
} }
impl<T: Surface> TestPattern<T> { impl<T: Surface> TestPattern<T> {
pub fn new(surface: T) -> Self { pub fn new(surface: T) -> Self {
TestPattern { surface, updater: Periodically::new_every_n_seconds(10), pattern: Pattern::Red } TestPattern { surface, updater: Periodically::new_every_n_seconds(10), stepper: Periodically::new_every_n_ms(60), pattern: TestShader::HSV, frame: 0 }
} }
} }
impl<T: Surface> Task for TestPattern<T> { impl<T: Surface> Task for TestPattern<T> {
fn start(&mut self) { fn start(&mut self) {
self.surface.set_shader(Box::new(TestShader { pattern: self.pattern })); self.surface.set_shader(Box::new(self.pattern.clone()));
} }
fn tick(&mut self) { fn tick(&mut self) {
self.updater.run(|| { self.updater.run(|| {
self.pattern = self.pattern.next(); self.pattern = self.pattern.next();
log::info!("Test pattern: {:?}", self.pattern); log::info!("Test pattern: {:?}", self.pattern);
self.surface.set_shader(Box::new(TestShader { pattern: self.pattern })); self.frame = 0;
}) self.surface.set_shader(Box::new(self.pattern.clone()));
});
self.stepper.run(|| {
self.frame = self.frame.wrapping_add(1);
self.surface.set_opacity(sin8(self.frame));
//log::info!("Step {}", self.frame);
self.surface.set_rect( &match self.pattern {
TestShader::SweepX => Rectangle::new(
Coordinates::new(self.frame, 0),
Coordinates::new(self.frame, 255)
),
TestShader::SweepY => Rectangle::new(
Coordinates::new(0, self.frame),
Coordinates::new(255, self.frame)
),
_ => Rectangle::everything()
});
});
} }
fn stop(&mut self) { fn stop(&mut self) {

View File

@ -49,7 +49,7 @@ fn main() {
log::info!("Creating runner"); log::info!("Creating runner");
let mut runner = task::Scheduler::new(vec![ let mut runner = task::Scheduler::new(vec![
Box::new(animations::IdleTask::new(display.new_surface(&Rectangle::everything()).unwrap())), Box::new(animations::IdleTask::new(&mut display)),
Box::new(animations::TestPattern::new(display.new_surface(&Rectangle::everything()).unwrap())), Box::new(animations::TestPattern::new(display.new_surface(&Rectangle::everything()).unwrap())),
Box::new(Renderer::new(display)), Box::new(Renderer::new(display)),
]); ]);