animations: rewrite animations with improved surface capabilities
This commit is contained in:
parent
d17baa754f
commit
3783bc60b2
@ -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) {
|
||||||
|
@ -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)),
|
||||||
]);
|
]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user