From: Stephen Seo Date: Wed, 15 Dec 2021 07:34:30 +0000 (+0900) Subject: WIP impl album art display X-Git-Tag: 0.2.0~12 X-Git-Url: https://git.seodisparate.com/stephenseo/LD54_Box_Survival?a=commitdiff_plain;h=9040f8f88e3c73735e857d1329edda8bc9cdb85a;p=mpd_info_screen WIP impl album art display --- diff --git a/src/display.rs b/src/display.rs index c55c036..f1a20ac 100644 --- a/src/display.rs +++ b/src/display.rs @@ -2,9 +2,14 @@ use crate::debug_log::log; use crate::mpd_handler::{InfoFromShared, MPDHandler}; use crate::Opt; use ggez::event::{self, EventHandler}; -use ggez::graphics::{self, Color, DrawParam, Drawable, Text, TextFragment}; +use ggez::graphics::{ + self, Color, DrawParam, Drawable, Image, Rect, Text, TextFragment, Transform, +}; use ggez::Context; use ggez::GameError; +use image::io::Reader as ImageReader; +use image::GenericImageView; +use std::io::Cursor; use std::sync::atomic::AtomicBool; use std::sync::{Arc, RwLock}; use std::thread; @@ -22,6 +27,11 @@ pub struct MPDDisplay { shared: Option, password_entered: bool, dirty_flag: Option>, + album_art: Option, + album_art_draw_transform: Option, + filename_text: Text, + artist_text: Text, + title_text: Text, } impl MPDDisplay { @@ -36,6 +46,11 @@ impl MPDDisplay { shared: None, password_entered: false, dirty_flag: None, + album_art: None, + album_art_draw_transform: None, + filename_text: Text::new(""), + artist_text: Text::new(""), + title_text: Text::new(""), } } @@ -64,10 +79,60 @@ impl MPDDisplay { log("Failed to initialize MPDHandler"); } } + + fn get_album_art_transform(&mut self, ctx: &mut Context, fill: bool) -> () { + if fill { + unimplemented!("filled image not implemented"); + } else { + if let Some(image) = &self.album_art { + let screen_coords: Rect = graphics::screen_coordinates(ctx); + let art_rect: Rect = image.dimensions(); + let offset_x: f32 = (screen_coords.w.abs() - art_rect.w.abs()) / 2.0f32; + let offset_y: f32 = (screen_coords.h.abs() - art_rect.h.abs()) / 2.0f32; + self.album_art_draw_transform = Some(Transform::Values { + dest: [offset_x, offset_y].into(), + rotation: 0.0f32, + scale: [1.0f32, 1.0f32].into(), + offset: [0.0f32, 0.0f32].into(), + }); + } else { + self.album_art_draw_transform = None; + } + } + } + + fn get_image_from_data( + &mut self, + ctx: &mut Context, + data: (Vec, String), + ) -> Result<(), String> { + let mut image_format: image::ImageFormat = image::ImageFormat::Png; + match data.1.as_str() { + "image/png" => image_format = image::ImageFormat::Png, + "image/jpg" | "image/jpeg" => image_format = image::ImageFormat::Jpeg, + "image/gif" => image_format = image::ImageFormat::Gif, + _ => (), + } + let img = ImageReader::with_format(Cursor::new(data.0), image_format) + .decode() + .map_err(|e| format!("ERROR: Failed to decode album art image: {}", e))?; + let rgba8 = img.to_rgba8(); + let ggez_img = Image::from_rgba8( + ctx, + rgba8.width() as u16, + rgba8.height() as u16, + rgba8.as_raw(), + ) + .map_err(|e| format!("ERROR: Failed to load album art image in ggez Image: {}", e))?; + + self.album_art = Some(ggez_img); + + Ok(()) + } } impl EventHandler for MPDDisplay { - fn update(&mut self, _ctx: &mut ggez::Context) -> Result<(), GameError> { + fn update(&mut self, ctx: &mut ggez::Context) -> Result<(), GameError> { if !self.is_valid { return Err(GameError::EventLoopError( "Failed to initialize MPDHandler".into(), @@ -100,7 +165,25 @@ impl EventHandler for MPDDisplay { if let Some(shared) = &self.shared { if self.notice_text.contents() != shared.error_text { self.notice_text = Text::new(TextFragment::new(shared.error_text.clone())); + self.title_text = Text::new(TextFragment::new(shared.title.clone())); + self.artist_text = Text::new(TextFragment::new(shared.artist.clone())); + self.filename_text = Text::new(TextFragment::new(shared.filename.clone())); + } + } + let album_art_data_result = + MPDHandler::get_art_data(self.mpd_handler.clone().unwrap()); + if let Ok(art_data) = album_art_data_result { + let result = self.get_image_from_data(ctx, art_data); + if let Err(e) = result { + log(e); + self.album_art = None; + self.album_art_draw_transform = None; + } else { + self.get_album_art_transform(ctx, false); } + } else { + self.album_art = None; + self.album_art_draw_transform = None; } } } @@ -111,6 +194,17 @@ impl EventHandler for MPDDisplay { fn draw(&mut self, ctx: &mut ggez::Context) -> Result<(), GameError> { graphics::clear(ctx, Color::BLACK); + if self.album_art.is_some() && self.album_art_draw_transform.is_some() { + log("Drawing album_art"); + self.album_art.as_ref().unwrap().draw( + ctx, + DrawParam { + trans: self.album_art_draw_transform.unwrap(), + ..Default::default() + }, + )?; + } + self.notice_text.draw(ctx, DrawParam::default())?; graphics::present(ctx) @@ -157,4 +251,8 @@ impl EventHandler for MPDDisplay { } } } + + fn resize_event(&mut self, ctx: &mut Context, _width: f32, _height: f32) { + self.get_album_art_transform(ctx, false); + } } diff --git a/src/main.rs b/src/main.rs index 46c7401..70c8b16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -98,6 +98,7 @@ fn main() -> Result<(), String> { }, ) .expect("Failed to handle resizing window"); + display.resize_event(ctx, phys_size.width as f32, phys_size.height as f32); } event::winit_event::WindowEvent::ReceivedCharacter(ch) => { display.text_input_event(ctx, ch); diff --git a/src/mpd_handler.rs b/src/mpd_handler.rs index 9f22bbd..eb35af1 100644 --- a/src/mpd_handler.rs +++ b/src/mpd_handler.rs @@ -34,6 +34,7 @@ pub struct InfoFromShared { pub struct MPDHandler { art_data: Vec, art_data_size: usize, + art_data_type: String, current_song_filename: String, current_song_title: String, current_song_artist: String, @@ -251,6 +252,7 @@ impl MPDHandler { let s = Arc::new(RwLock::new(Self { art_data: Vec::new(), art_data_size: 0, + art_data_type: String::new(), current_song_filename: String::new(), current_song_title: String::new(), current_song_artist: String::new(), @@ -294,10 +296,10 @@ impl MPDHandler { Ok(s) } - pub fn get_art_data(h: Arc>) -> Result, ()> { + pub fn get_art_data(h: Arc>) -> Result<(Vec, String), ()> { if let Ok(read_lock) = h.try_read() { if read_lock.art_data.len() == read_lock.art_data_size { - return Ok(read_lock.art_data.clone()); + return Ok((read_lock.art_data.clone(), read_lock.art_data_type.clone())); } } @@ -439,14 +441,17 @@ impl MPDHandler { 'handle_buf: loop { if write_handle.current_binary_size > 0 { - if write_handle.current_binary_size < buf_vec.len() { + if write_handle.current_binary_size <= buf_vec.len() { let count = write_handle.current_binary_size; write_handle.art_data.extend_from_slice(&buf_vec[0..count]); buf_vec = buf_vec.split_off(count + 1); write_handle.current_binary_size = 0; write_handle.poll_state = PollState::None; - write_handle.dirty_flag.store(true, Ordering::Relaxed); - log("Got complete album art chunk"); + log(format!( + "Album art recv progress: {}/{}", + write_handle.art_data.len(), + write_handle.art_data_size + )); } else { write_handle.art_data.extend_from_slice(&buf_vec); write_handle.current_binary_size -= buf_vec.len(); @@ -455,6 +460,9 @@ impl MPDHandler { write_handle.art_data.len(), write_handle.art_data_size )); + if write_handle.art_data.len() == write_handle.art_data_size { + write_handle.dirty_flag.store(true, Ordering::Relaxed); + } break 'handle_buf; } } @@ -583,6 +591,8 @@ impl MPDHandler { write_handle.current_song_title = line.split_off(7); } else if line.starts_with("Artist: ") { write_handle.current_song_artist = line.split_off(8); + } else if line.starts_with("type: ") { + write_handle.art_data_type = line.split_off(6); } else { log(format!("WARNING: Got unrecognized/ignored line: {}", line)); }