Implement fading

This commit is contained in:
Jean-Loup Beaussart 2025-04-14 01:28:25 +02:00
parent bfb3b23d70
commit 581e4263fc
No known key found for this signature in database
GPG Key ID: 582B3C35EAFE46F8
3 changed files with 68 additions and 34 deletions

View File

@ -1,28 +1,34 @@
use crate::dimensions::{calculate_resize_dimensions, Dimensions};
use image::ImageReader;
use macroquad::texture::Texture2D;
use macroquad::texture::{Image, Texture2D};
use std::path::{Path, PathBuf};
use walkdir::WalkDir;
pub struct ImageProvider<'a> {
path: &'a Path,
directory_it: Box<dyn Iterator<Item = Result<walkdir::DirEntry, walkdir::Error>>>,
image: Option<Image>,
texture: Option<Texture2D>,
texture_darkening_factor: f32,
screen_dimension: Dimensions,
}
impl<'a> ImageProvider<'a> {
pub fn new(screen_dimension: Dimensions, path: &'a Path) -> Self {
Self {
directory_it: Box::new(WalkDir::new(&path).max_open(8).into_iter()),
directory_it: Box::new(WalkDir::new(path).max_open(8).into_iter()),
image: None,
texture: None,
screen_dimension,
path,
texture_darkening_factor: 1.0f32,
}
}
pub fn load_next_image(&mut self) -> anyhow::Result<()> {
let path = self.get_next_image_path()?;
println!("Loading image: {path:?}");
let now = chrono::Local::now().time();
let image = ImageReader::open(path)?.decode()?;
let image_dim = Dimensions::new(image.width(), image.height());
@ -34,19 +40,51 @@ impl<'a> ImageProvider<'a> {
image::imageops::FilterType::Lanczos3,
);
self.texture = Some(Texture2D::from_rgba8(
image.width().try_into()?,
image.height().try_into()?,
&image.into_rgba8(),
));
let mut i = Image::empty();
i.width = image.width() as u16;
i.height = image.height() as u16;
i.bytes = image.into_rgba8().into_raw();
self.image = Some(i);
self.texture = None;
let elapsed = chrono::Local::now().time() - now;
println!(
"Loading image elapsed time: {}ms",
elapsed.num_milliseconds()
);
Ok(())
}
pub fn get_current_texture(&self) -> anyhow::Result<&Texture2D> {
self.texture
.as_ref()
.ok_or_else(|| anyhow::anyhow!("No image loaded"))
pub fn get_current_texture(&mut self, darkening_factor: f32) -> anyhow::Result<&Texture2D> {
if (darkening_factor - self.texture_darkening_factor).abs() > f32::EPSILON {
self.texture_darkening_factor = darkening_factor;
self.texture = None;
}
if self.texture.is_none() {
let darken_image = self
.image
.as_ref()
.map(|i| {
let mut darken_image = i.clone();
darken_image.bytes.iter_mut().for_each(|b| {
*b = (f32::from(*b) * darkening_factor) as u8;
});
darken_image
})
.ok_or_else(|| anyhow::anyhow!("No image loaded"))?;
let text =
Texture2D::from_rgba8(darken_image.width, darken_image.height, &darken_image.bytes);
self.texture = Some(text);
}
match self.texture {
Some(ref texture) => Ok(texture),
None => Err(anyhow::anyhow!("No texture available")),
}
}
fn get_next_image_path(&mut self) -> anyhow::Result<PathBuf> {
@ -65,7 +103,7 @@ impl<'a> ImageProvider<'a> {
Some(Err(e)) => return Err(e.into()),
None => {
// Reset the iterator when we reach the end
self.directory_it = Box::new(WalkDir::new(&self.path).max_open(8).into_iter());
self.directory_it = Box::new(WalkDir::new(self.path).max_open(8).into_iter());
}
}
}

View File

@ -31,11 +31,6 @@ fn display_image_centered(texture: &Texture2D) {
);
}
enum Mode {
Black,
Displayed,
}
#[macroquad::main(window_conf)]
async fn main() -> anyhow::Result<()> {
let settings = settings::Settings::new("settings.yml".into())?;
@ -51,37 +46,38 @@ async fn main() -> anyhow::Result<()> {
}
let now = chrono::Local::now().time();
let start_fading = chrono::NaiveTime::from_hms_opt(22, 45, 0).unwrap();
let go_to_bed = chrono::NaiveTime::from_hms_opt(23, 0, 0).unwrap();
let wake_up = chrono::NaiveTime::from_hms_opt(9, 0, 0).unwrap();
let full_brightness = chrono::NaiveTime::from_hms_opt(9, 15, 0).unwrap();
let mode = if now < go_to_bed && now > wake_up {
Mode::Displayed
let darkening_factor = if now < start_fading && now > full_brightness {
1.0f32
} else if now > start_fading && now < go_to_bed {
(go_to_bed - now).num_seconds() as f32 / (go_to_bed - start_fading).num_seconds() as f32
} else if now > wake_up && now < full_brightness {
(now - wake_up).num_seconds() as f32 / (full_brightness - wake_up).num_seconds() as f32
} else {
Mode::Black
0.0f32
};
match mode {
Mode::Black => {
clear_background(BLACK);
}
Mode::Displayed => {
display_frame(&provider)?;
if time.elapsed() > settings.duration {
provider.load_next_image()?;
time = Instant::now();
}
display_frame(&mut provider, darkening_factor)?;
if time.elapsed() > settings.duration {
if darkening_factor > 0.0f32 {
provider.load_next_image()?;
}
time = Instant::now();
}
thread::sleep(Duration::from_millis(250));
thread::sleep(Duration::from_millis(400));
next_frame().await;
}
Ok(())
}
fn display_frame(provider: &ImageProvider) -> anyhow::Result<()> {
let image = provider.get_current_texture()?;
fn display_frame(provider: &mut ImageProvider, darkening_factor: f32) -> anyhow::Result<()> {
let image = provider.get_current_texture(darkening_factor)?;
clear_background(BLACK);
display_image_centered(image);

View File

@ -11,7 +11,7 @@ impl Settings {
.add_source(File::from(settings_file))
.build()?;
let photo_path = settings.get_string("photo_path")?.try_into()?;
let photo_path = settings.get_string("photo_path")?.into();
let duration = settings.get_int("duration")?;
Ok(Self {