Skip to main content

figments_sample_shaders/
lib.rs

1#![no_std]
2use figments::prelude::*;
3use figments::liber8tion::trig::*;
4use figments::liber8tion::noise::*;
5use core::cmp::max;
6use rgb::*;
7
8#[cfg(feature="micromath")]
9use micromath::F32Ext;
10
11#[derive(Default, Debug)]
12pub struct FrameNumber(pub usize);
13
14#[derive(Default, Debug)]
15pub struct RgbWaves {}
16
17impl<Space: CoordinateSpace<Data = usize>> Shader<FrameNumber, Space, Rgb<u8>> for RgbWaves {
18    fn draw(&self, coords: &Coordinates<Space>, frame: &FrameNumber) -> Rgb<u8> {
19        // Scroll the entire pattern sideways, so it repeats less often
20        let offset_x = coords.x.wrapping_add(frame.0 / 30);
21        // The color is just some simple wave functions with varying frequencies, with the Y coordinate as a phase offset
22        Rgb::new(
23            offset_x.wrapping_mul(3).wrapping_add(frame.0).sin8().to_raw().wrapping_add(coords.y as u8),
24            offset_x.wrapping_mul(5).wrapping_sub(frame.0).cos8().to_raw().wrapping_add(coords.y as u8),
25            offset_x.wrapping_mul(2).wrapping_add(frame.0).sin8().to_raw().wrapping_add(coords.y as u8)
26        )
27    }
28}
29
30
31#[derive(Default, Debug)]
32pub struct Thinking {}
33
34impl<Space: CoordinateSpace<Data = usize>> Shader<FrameNumber, Space, Rgb<u8>> for Thinking {
35    fn draw(&self, coords: &Coordinates<Space>, uniforms: &FrameNumber) -> Rgb<u8> {
36        //let noise_x = sin8(sin8((frame % 255) as u8).wrapping_add(coords.x));
37        //let noise_y = cos8(cos8((frame % 255) as u8).wrapping_add(coords.y));
38        let offset_x = uniforms.0.wrapping_add(coords.x).sin8().to_raw();
39        let offset_y = uniforms.0.wrapping_add(coords.y).cos8().to_raw();
40        let noise_x = offset_x / 2;
41        let noise_y = offset_y / 2;
42        //let noise_x = coords.x.wrapping_add(offset_x);
43        //let noise_y = coords.y.wrapping_add(offset_y);
44        Hsv::new(
45            inoise8(offset_x as i16, offset_y as i16).to_raw(),
46            128_u8.saturating_add(inoise8(noise_y.into(), noise_x.into()).to_raw()),
47            255
48        ).into()
49    }
50}
51
52#[derive(Default, Debug)]
53pub struct ColorGlow {
54    pub color: Hsv
55}
56
57impl<Space: CoordinateSpace<Data = usize>, Pixel> Shader<FrameNumber, Space, Pixel> for ColorGlow where Hsv: Into<Pixel> {
58    fn draw(&self, coords: &Coordinates<Space>, uniforms: &FrameNumber) -> Pixel {
59        let noise_y = uniforms.0.sin8().to_raw();
60        let noise_x = uniforms.0.cos8().to_raw();
61
62        let brightness = inoise8((noise_x.wrapping_add(coords.x as u8)).into(), (noise_y.wrapping_add(coords.y as u8)).into());
63
64        // Saturation will be +/- 15 from the requested color
65        let saturation_min = self.color.saturation.saturating_sub(15);
66        let saturation_shift = 30u8 * inoise8((noise_y.wrapping_add(coords.y as u8)).into(), (noise_x.wrapping_add(coords.x as u8)).into());
67        let saturation = saturation_min.saturating_add(saturation_shift);
68
69        Hsv::new(self.color.hue.wrapping_add(16u8 * uniforms.0.sin8()).wrapping_sub(8), saturation, brightness.to_raw()).into()
70    }
71}
72
73#[derive(Default, Debug)]
74pub struct RainbowSpiralShader {}
75impl Shader<FrameNumber, Virtual, Rgba<u8>> for RainbowSpiralShader {
76    fn draw(&self, coords: &VirtualCoordinates, uniforms: &FrameNumber) -> Rgba<u8> {
77        let distance = (128f32 - coords.y as f32).hypot(128f32 - coords.x as f32);
78        let angle = (((128f32 - coords.y as f32).atan2(128f32 - coords.x as f32)) * 255f32) as u8;
79        let pixel_value = angle.wrapping_add((uniforms.0 % 255) as u8).wrapping_add(distance as u8);
80
81        Rgba::new(pixel_value.sin8().to_raw(), pixel_value.wrapping_add(64).sin8().to_raw(), pixel_value.wrapping_add(128).sin8().to_raw(), 255)
82    }
83}
84
85#[derive(Default, Debug)]
86pub struct Chimes {}
87impl<Space: CoordinateSpace<Data = usize>, Pixel> Shader<FrameNumber, Space, Pixel> for Chimes where Hsv: Into<Pixel> {
88    fn draw(&self, surface_coords: &Coordinates<Space>, uniforms: &FrameNumber) -> Pixel {
89        const CHIME_LENGTH: usize = 8;
90
91        let animation_frame = uniforms.0 / 5;
92        let local_x = surface_coords.x.wrapping_add(animation_frame / 300);
93
94        let chime_idx = (local_x / CHIME_LENGTH) % 32;
95        let chime_pos = local_x % CHIME_LENGTH;
96
97        let brightness = (animation_frame.wrapping_mul(chime_idx + 1) / 3).sin8();
98        let saturation = (chime_pos.wrapping_add(animation_frame / 3)).sin8();
99        let hue = chime_idx.wrapping_add(animation_frame / 30) as u8;
100
101        Hsv::new(
102            hue,
103            saturation.to_raw(),
104            brightness.to_raw()
105        ).into()
106    }
107}
108
109#[derive(Default, Debug)]
110pub struct Flashlight {}
111
112impl<Pixel, Space: CoordinateSpace<Data = usize>> Shader<FrameNumber, Space, Pixel> for Flashlight where Hsv: Into<Pixel> {
113    fn draw(&self, coords: &Coordinates<Space>, uniforms: &FrameNumber) -> Pixel {
114        let noise_y = uniforms.0.sin8().to_raw();
115        let noise_x = uniforms.0.cos8().to_raw();
116
117        let brightness = inoise8((noise_x.wrapping_add(coords.x as u8)).into(), (noise_y.wrapping_add(coords.y as u8)).into());
118        let saturation = inoise8((noise_y.wrapping_add(coords.y as u8)).into(), (noise_x.wrapping_add(coords.x as u8)).into());
119        let hue = 16u8 * uniforms.0.sin8();
120
121        Hsv::new(hue, max(128, saturation.to_raw()), brightness.to_raw()).into()
122    }
123}