figments_sample_shaders/
lib.rs

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