graphics: update to use figments Fract8 type

This commit is contained in:
2026-02-28 16:47:25 +01:00
parent 95ebc7820a
commit 319c812a61
5 changed files with 36 additions and 35 deletions

View File

@@ -1,6 +1,6 @@
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal, watch::{Receiver, Watch}};
use figments::prelude::*;
use core::{fmt::Debug, sync::atomic::{AtomicBool, AtomicU8}};
use figments::{liber8tion::interpolate::Fract8, prelude::*};
use core::{fmt::Debug, ops::Mul, sync::atomic::{AtomicBool, AtomicU8}};
use alloc::sync::Arc;
//use super::{Output};
@@ -201,8 +201,8 @@ impl DisplayControls {
self.data.on.load(core::sync::atomic::Ordering::Relaxed)
}
pub fn brightness(&self) -> u8 {
self.data.brightness.load(core::sync::atomic::Ordering::Relaxed)
pub fn brightness(&self) -> Fract8 {
Fract8::from_raw(self.data.brightness.load(core::sync::atomic::Ordering::Relaxed))
}
pub async fn wait_until_display_is_on(&self) {
@@ -228,8 +228,8 @@ impl GammaCorrected for DisplayControls {
}
impl Brightness for DisplayControls {
fn set_brightness(&mut self, brightness: u8) {
self.data.brightness.store(brightness, core::sync::atomic::Ordering::Relaxed);
fn set_brightness(&mut self, brightness: Fract8) {
self.data.brightness.store(brightness.to_raw(), core::sync::atomic::Ordering::Relaxed);
}
fn set_on(&mut self, is_on: bool) {

View File

@@ -145,9 +145,9 @@ impl Screen {
Image::new(&images::BOOT_LOGO, Point::zero()).draw(sampler).unwrap();
const SPARKLE_COUNT: i32 = 8;
for n in 0..SPARKLE_COUNT {
let sparkle_center = Point::new(128u8.scale8(cos8(state.frame.wrapping_mul(n as usize))) as i32, 64u8.scale8(sin8(state.frame.wrapping_mul(n as usize) as u8)) as i32);
let sparkle_center = Point::new((128u8 * state.frame.wrapping_mul(n as usize).cos8()) as i32, (64u8 * state.frame.wrapping_mul(n as usize).sin8()) as i32);
let offset = (state.frame / 2 % 32) as i32 - 16;
let rotation = PI * 2.0 * (sin8(state.frame) as f32 / 255.0);
let rotation = PI * 2.0 * state.frame.sin8();
let normal = Point::new((rotation.cos() * offset as f32) as i32, (rotation.sin() * offset as f32) as i32);
let cross_normal = Point::new((rotation.sin() * offset as f32) as i32, (rotation.cos() * offset as f32) as i32);
// Draw horizontal

View File

@@ -1,6 +1,7 @@
use core::cmp::max;
use figments::{liber8tion::{interpolate::{ease_in_out_quad}, noise::inoise8, trig::{cos8, sin8}}, prelude::*};
use figments::{liber8tion::{interpolate::{Fract8, ease_in_out_quad}, noise::inoise8, trig::Trig8}, prelude::*};
use num_traits::WrappingAdd;
use rgb::Rgba;
use crate::graphics::display::{SegmentSpace, Uniforms};
@@ -25,8 +26,8 @@ impl Shader<Uniforms, SegmentSpace, Rgba<u8>> for Movement {
} else {
uniforms.frame.wrapping_sub(surface_coords.x)
};
let idx = sin8(offset).wrapping_add(uniforms.primary_color.hue);
Rgba::new(idx, idx.wrapping_mul(2), idx.wrapping_div(2), 128)
let idx = offset.sin8().wrapping_add(&Fract8::from_raw(uniforms.primary_color.hue));
Rgba::new(idx.to_raw(), idx.to_raw().wrapping_mul(2), idx.to_raw() / 2, 128)
}
}
@@ -45,12 +46,12 @@ impl Background {
impl Shader<Uniforms, SegmentSpace, Rgba<u8>> for Background {
fn draw(&self, coords: &Coordinates<SegmentSpace>, uniforms: &Uniforms) -> Rgba<u8> {
let noise_x = sin8(uniforms.frame % 255) as i16;
let noise_y = cos8(uniforms.frame % 255) as i16;
let noise_x = (uniforms.frame % 255).sin8().to_raw() as i16;
let noise_y = (uniforms.frame % 255).cos8().to_raw() as i16;
let brightness = inoise8(noise_x.wrapping_add(coords.x as i16), noise_y.wrapping_add(coords.y as i16));
let saturation = inoise8(noise_y.wrapping_add(coords.y as i16), noise_x.wrapping_add(coords.x as i16));
let rgb: Rgb<u8> = match self.color {
None => Hsv::new(uniforms.primary_color.hue, max(128, saturation), brightness).into(),
None => Hsv::new(uniforms.primary_color.hue, max(128, saturation.to_raw()), brightness.to_raw()).into(),
Some(c) => c
};
@@ -62,9 +63,9 @@ impl Shader<Uniforms, SegmentSpace, Rgba<u8>> for Background {
pub struct Tail {}
impl Shader<Uniforms, SegmentSpace, Rgba<u8>> for Tail {
fn draw(&self, coords: &Coordinates<SegmentSpace>, uniforms: &Uniforms) -> Rgba<u8> {
let hue_offset: u8 = 32.scale8(sin8(uniforms.frame.wrapping_sub(coords.x)));
let value = max(30, inoise8(coords.x.wrapping_add(uniforms.frame) as i16, coords.y.wrapping_add(uniforms.frame) as i16));
Hsv::new(uniforms.primary_color.hue.wrapping_sub(hue_offset), max(210, sin8(uniforms.frame.wrapping_add(coords.x))), value).into()
let hue_offset: u8 = 32u8 * Fract8::from_raw(uniforms.frame.wrapping_sub(coords.x) as u8);
let value = max(30, inoise8(coords.x.wrapping_add(uniforms.frame) as i16, coords.y.wrapping_add(uniforms.frame) as i16).to_raw());
Hsv::new(uniforms.primary_color.hue.wrapping_sub(hue_offset), max(210, uniforms.frame.wrapping_add(coords.x).sin8().to_raw()), value).into()
}
}
@@ -96,10 +97,10 @@ impl Shader<Uniforms, SegmentSpace, Rgba<u8>> for Brakelight {
let distance_from_end = Self::end() - coords.x;
if distance_from_end < Self::safety_length() {
Rgba::new(max(128, sin8(uniforms.frame.wrapping_sub(coords.x))), 0, 0, 255)
Rgba::new(max(128, uniforms.frame.wrapping_sub(coords.x).sin8().to_raw()), 0, 0, 255)
} else {
let pct = (distance_from_end as f32 / Self::length() as f32) * 255f32;
Rgba::new(max(100, ease_in_out_quad((pct as u8).wrapping_add(uniforms.frame as u8))), 0, 0, ease_in_out_quad(255 - pct as u8))
Rgba::new(max(100, ease_in_out_quad(Fract8::from_raw(pct as u8).wrapping_add(&Fract8::from_raw(uniforms.frame as u8))).to_raw()), 0, 0, ease_in_out_quad(Fract8::from_raw(255 - pct as u8)).to_raw())
}
}
}
@@ -108,7 +109,7 @@ impl Shader<Uniforms, SegmentSpace, Rgba<u8>> for Brakelight {
pub struct Headlight {}
impl Shader<Uniforms, SegmentSpace, Rgba<u8>> for Headlight {
fn draw(&self, coords: &Coordinates<SegmentSpace>, uniforms: &Uniforms) -> Rgba<u8> {
Hsv::new(0, 0, max(130, ease_in_out_quad(sin8(uniforms.frame.wrapping_sub(coords.x))))).into()
Hsv::new(0, 0, max(130, ease_in_out_quad(uniforms.frame.wrapping_sub(coords.x).sin8()).to_raw())).into()
}
}
@@ -116,14 +117,14 @@ impl Shader<Uniforms, SegmentSpace, Rgba<u8>> for Headlight {
pub struct Panel {}
impl Shader<Uniforms, SegmentSpace, Rgba<u8>> for Panel {
fn draw(&self, coords: &Coordinates<SegmentSpace>, uniforms: &Uniforms) -> Rgba<u8> {
let noise_offset = max(180, inoise8(coords.x.wrapping_add(uniforms.frame) as i16, coords.y.wrapping_add(uniforms.frame) as i16));
let noise_offset = max(180, inoise8(coords.x.wrapping_add(uniforms.frame) as i16, coords.y.wrapping_add(uniforms.frame) as i16).to_raw());
let pct = (coords.x as f32 / 18f32) * 255f32;
let shift = match coords.y {
1..=2 => 106, // 150 degrees
3..=4 => 148, // 210 degrees
_ => 0
};
Hsv::new(uniforms.primary_color.hue.wrapping_add(shift), noise_offset, max(100, sin8(pct as u8).wrapping_add(uniforms.frame as u8))).into()
Hsv::new(uniforms.primary_color.hue.wrapping_add(shift), noise_offset, max(100, pct.sin8().wrapping_add(&Fract8::from_raw(uniforms.frame as u8)).to_raw())).into()
}
}
@@ -134,15 +135,15 @@ impl Shader<Uniforms, SegmentSpace, Rgba<u8>> for Thinking {
fn draw(&self, coords: &Coordinates<SegmentSpace>, uniforms: &Uniforms) -> Rgba<u8> {
//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(uniforms.frame.wrapping_add(coords.x));
let offset_y = cos8(uniforms.frame.wrapping_add(coords.y));
let offset_x = uniforms.frame.wrapping_add(coords.x).sin8();
let offset_y = uniforms.frame.wrapping_add(coords.y).cos8();
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(
inoise8(offset_x as i16, offset_y as i16),
128_u8.saturating_add(inoise8(noise_y.into(), noise_x.into())),
inoise8(offset_x.to_raw() as i16, offset_y.to_raw() as i16).to_raw(),
128_u8.saturating_add(inoise8(noise_y.to_raw().into(), noise_x.to_raw().into()).to_raw()),
255
).into()
}

View File

@@ -4,7 +4,7 @@ use core::{cmp::min, ops::{BitAnd, Shr}};
use display_interface::DisplayError;
use embedded_graphics::prelude::*;
use esp_hal::{gpio::Output, i2c::master::I2c, Async};
use figments::{liber8tion::{interpolate::Fract8, noise}, mappings::embedded_graphics::Matrix2DSpace, prelude::*};
use figments::{liber8tion::{interpolate::Fract8}, mappings::embedded_graphics::Matrix2DSpace, prelude::*};
use embedded_graphics::pixelcolor::BinaryColor;
use figments::pixels::AdditivePixelSink;
use figments_render::output::OutputAsync;
@@ -59,8 +59,8 @@ const DITHER_MAP: [u16;15] = [
impl AdditivePixelSink<BinaryColor> for SsdPixel {
fn add(&mut self, pixel: BinaryColor, opacity: Fract8) {
match opacity {
0 => (),
255 => self.set_pixel(pixel),
Fract8::MIN => (),
Fract8::MAX => self.set_pixel(pixel),
_ => {
let dither_value = DITHER_MAP[opacity as usize / 17];
let dither_x = self.coords.x % 4;
@@ -108,7 +108,7 @@ pub struct SsdOutput {
target: ssd1306::Ssd1306Async<ssd1306::prelude::I2CInterface<esp_hal::i2c::master::I2c<'static, esp_hal::Async>>, ssd1306::prelude::DisplaySize128x64, ssd1306::mode::BasicMode>,
controls: DisplayControls,
is_on: bool,
last_brightness: u8,
last_brightness: Fract8,
reset_pin: Output<'static>
}
@@ -132,7 +132,7 @@ impl SsdOutput {
pixbuf: [0; 128 * 64 / 8],
target,
controls,
last_brightness: 255,
last_brightness: Fract8::MAX,
is_on: true,
reset_pin
}

View File

@@ -2,7 +2,7 @@ use alloc::sync::Arc;
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, mutex::Mutex, pubsub::DynSubscriber};
use embassy_time::{Duration, Timer};
use embedded_graphics::pixelcolor::BinaryColor;
use figments::{mappings::embedded_graphics::Matrix2DSpace, prelude::{Coordinates, Rectangle}, render::Shader, surface::{BufferedSurfacePool, NullBufferPool, Surface, SurfaceBuilder, Surfaces}};
use figments::{liber8tion::interpolate::Fract8, mappings::embedded_graphics::Matrix2DSpace, prelude::{Coordinates, Rectangle}, render::Shader, surface::{Surface, SurfaceBuilder, Surfaces}};
use figments_render::output::Brightness;
use log::*;
@@ -37,7 +37,7 @@ impl<S: core::fmt::Debug + Surface<CoordinateSpace = Matrix2DSpace, Pixel = Bina
overlay: SurfaceBuilder::build(surfaces)
.rect(Rectangle::everything())
.shader(OverlayShader{})
.opacity(0)
.opacity(Fract8::MIN)
.finish().unwrap(),
controls,
uniforms
@@ -45,8 +45,8 @@ impl<S: core::fmt::Debug + Surface<CoordinateSpace = Matrix2DSpace, Pixel = Bina
}
pub async fn screen_transition(&mut self, next_screen: Screen) {
const FADE_IN: Animation = Animation::new().from(0).to(255).duration(Duration::from_millis(300));
const FADE_OUT: Animation = Animation::new().from(255).to(0).duration(Duration::from_millis(300));
const FADE_IN: Animation<Fract8> = Animation::new().from(Fract8::MIN).to(Fract8::MAX).duration(Duration::from_millis(300));
const FADE_OUT: Animation<Fract8> = Animation::new().from(Fract8::MAX).to(Fract8::MIN).duration(Duration::from_millis(300));
info!("Fading in to screen {next_screen:?}");
FADE_IN.apply(&mut self.overlay).await;
{