diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 8df86bd1265ec..c18a7aab7f39c 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -20,7 +20,10 @@ use bevy_ecs::{ system::{IntoExclusiveSystem, IntoSystem, Res}, }; use bevy_transform::TransformSystem; -use bevy_utils::{tracing::warn, HashMap}; +use bevy_utils::{ + tracing::{error, warn}, + HashMap, +}; use bevy_window::{WindowIcon, WindowIconBytes, WindowId, Windows}; use draw::{OutsideFrustum, Visible}; @@ -286,12 +289,24 @@ fn window_icon_changed( match asset_server.get_load_state(handle) { LoadState::Loaded => { if let Some(texture) = textures.get(handle) { - let window_icon = WindowIcon::from(WindowIconBytes { - bytes: texture.data.clone(), - width: texture.size.width, - height: texture.size.height, - }); - window.set_icon(window_icon); + /* TODO: Not actually sure if we need to check the error here + Whatever Texture gives us might be fine */ + let window_icon_bytes = WindowIconBytes::new( + texture.data.clone(), + texture.size.width, + texture.size.height, + ); + + match window_icon_bytes { + Ok(window_icon_bytes) => { + let window_icon = WindowIcon::from(window_icon_bytes); + window.set_icon(window_icon); + } + Err(e) => error!( + "For handle {:?} the following error was produced: {}", + handle, e + ), + } o.remove(); } diff --git a/crates/bevy_window/Cargo.toml b/crates/bevy_window/Cargo.toml index 1939fd326a252..0d0b453bb22d1 100644 --- a/crates/bevy_window/Cargo.toml +++ b/crates/bevy_window/Cargo.toml @@ -21,6 +21,7 @@ bevy_utils = { path = "../bevy_utils", version = "0.5.0" } bevy_asset = { path = "../bevy_asset", version = "0.5.0" } # other +thiserror = "1.0" [target.'cfg(target_arch = "wasm32")'.dependencies] web-sys = "0.3" diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index f715fbf9ea548..4f8e301373bf5 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -1,5 +1,6 @@ use bevy_math::{IVec2, Vec2}; use bevy_utils::{tracing::warn, Uuid}; +use thiserror::Error; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct WindowId(Uuid); @@ -92,9 +93,20 @@ impl WindowResizeConstraints { #[derive(Debug, Clone)] pub struct WindowIconBytes { - pub bytes: Vec, - pub width: u32, - pub height: u32, + bytes: Vec, + width: u32, + height: u32, +} + +#[derive(Error, Debug)] +pub enum WindowIconBytesError { + #[error("32bpp RGBA image buffer expected, but {bytes_length} is not divisible by 4")] + NotRGBA { bytes_length: usize }, + #[error("Buffer size {bytes_length} does not match the expected size based on the dimensions {pixel_bytes_length}")] + SizeMismatch { + pixel_bytes_length: usize, + bytes_length: usize, + }, } #[derive(Debug, Clone)] @@ -118,6 +130,41 @@ impl From for WindowIcon { } } +impl WindowIconBytes { + pub fn new(bytes: Vec, width: u32, height: u32) -> Result { + let pixel_count = (width * height) as usize; + let pixel_bytes_length = pixel_count * 4; + let bytes_length = bytes.len(); + + if bytes_length % 4 != 0 { + Err(WindowIconBytesError::NotRGBA { bytes_length }) + } else if pixel_bytes_length != bytes_length { + Err(WindowIconBytesError::SizeMismatch { + pixel_bytes_length, + bytes_length, + }) + } else { + Ok(Self { + bytes, + width, + height, + }) + } + } + + pub fn bytes(&self) -> &[u8] { + &self.bytes + } + + pub fn width(&self) -> u32 { + self.width + } + + pub fn height(&self) -> u32 { + self.height + } +} + /// An operating system window that can present content and receive user input. /// /// ## Window Sizes diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index a013c6c9c76e6..8d3ad733b5b3e 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -163,17 +163,15 @@ fn change_window(world: &mut World) { bevy_window::WindowCommand::SetIcon { window_icon_bytes } => { let window = winit_windows.get_window(id).unwrap(); - match Icon::from_rgba( - window_icon_bytes.bytes, - window_icon_bytes.width, - window_icon_bytes.height, - ) { - Ok(winit_icon) => window.set_window_icon(Some(winit_icon)), - Err(e) => { - error!("Unable to create window icon: {}", e); - return; - } - } + /* Failures should already be covered in WindowIconBytes constructor */ + window.set_window_icon( + Icon::from_rgba( + window_icon_bytes.bytes().to_vec(), + window_icon_bytes.width(), + window_icon_bytes.height(), + ) + .ok(), + ); } bevy_window::WindowCommand::ClearIcon => { let window = winit_windows.get_window(id).unwrap();