add window icon

This commit is contained in:
Chance 2025-04-03 01:37:53 -04:00 committed by BitSyndicate
parent d8e6baebf1
commit 841ff739dd
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS.
GPG key ID: 443E4198D6BBA6DE
13 changed files with 659 additions and 113 deletions

View file

@ -13,8 +13,9 @@ use wgpu_text::glyph_brush::ab_glyph::FontRef;
use wgpu_text::glyph_brush::{HorizontalAlign, Layout, OwnedSection, OwnedText, VerticalAlign};
use wgpu_text::{BrushBuilder, TextBrush};
use winit::window::Window;
use crate::error::{ZenyxError, ZenyxErrorKind};
use crate::error::Result;
use crate::error::{ZenyxError, ZenyxErrorKind};
const SHADER_SRC: &str = include_str!("shader.wgsl");
@ -130,7 +131,7 @@ struct Model {
bind_group: wgpu::BindGroup,
index_count: u32,
transform: Matrix4<f32>,
version: u32,
version: u32,
}
impl Model {
@ -174,7 +175,7 @@ impl Model {
bind_group,
index_count: indices.len() as u32,
transform: Matrix4::identity(),
version: 1
version: 1,
}
}
@ -190,7 +191,6 @@ impl Model {
self.version += 1;
}
}
}
pub struct Renderer<'window> {
@ -211,7 +211,7 @@ pub struct Renderer<'window> {
frame_count: u32,
fps: f32,
font_state: FontState,
model_versions: Vec<u32>,
model_versions: Vec<u32>,
}
struct FontState {
@ -370,6 +370,8 @@ impl<'window> Renderer<'window> {
surface.configure(&device, &surface_config);
let (depth_texture, depth_texture_view) =
create_depth_texture(&device, surface_config.width, surface_config.height);
let (depth_texture, depth_texture_view) =
create_depth_texture(&device, surface_config.width, surface_config.height);
let font_bytes = include_bytes!("DejaVuSans.ttf");
let font = FontRef::try_from_slice(font_bytes).map_err(|e| {
@ -385,8 +387,6 @@ impl<'window> Renderer<'window> {
let scale = base_scale * (surface_config.width as f32 / base_width as f32).clamp(0.5, 2.0);
let color = wgpu::Color::WHITE;
let section = OwnedSection::default()
.add_text(OwnedText::new("FPS: 0.00").with_scale(scale).with_color([
color.r as f32,
@ -430,7 +430,7 @@ impl<'window> Renderer<'window> {
scale,
color,
},
model_versions: vec![]
model_versions: vec![],
})
}
@ -475,16 +475,16 @@ impl<'window> Renderer<'window> {
for (i, model) in self.models.iter_mut().enumerate() {
let angle = Rad(elapsed * 0.8 + i as f32 * 0.3);
if i % 2 == 0 {
model.set_transform(Matrix4::from_angle_y(angle));
model.set_transform(Matrix4::from_angle_y(angle));
} else {
model.set_transform(Matrix4::from_angle_x(angle) * Matrix4::from_angle_y(angle));
model.set_transform(Matrix4::from_angle_x(angle) * Matrix4::from_angle_y(angle));
}
}
for (i, model) in self.models.iter().enumerate() {
if model.version > self.model_versions[i] {
model.update(&self.queue);
#[cfg(debug_assertions)]
trace!("Updating model: {:#?}",model);
trace!("Updating model: {:#?}", model);
self.model_versions[i] = model.version;
}
}
@ -604,9 +604,11 @@ impl<'window> Renderer<'window> {
pub fn bg_color(&self) -> &wgpu::Color {
&self.bg_color
}
pub fn text_color(&self) -> &wgpu::Color {
&self.font_state.color
}
pub fn set_text_color(&mut self, color: wgpu::Color) {
self.font_state.color = color;
}

View file

@ -1,21 +1,26 @@
use std::env;
use std::fs;
use std::io::Cursor;
use std::ops::Deref;
use std::path::PathBuf;
use std::sync::Arc;
use ctx::{Renderer, Vertex};
use winit::dpi::LogicalSize;
use winit::dpi::Size;
use std::env;
use std::fs;
use std::path::PathBuf;
use image::ImageDecoder;
use image::ImageFormat;
use tobj::Mesh;
use tobj::{LoadOptions, Model};
use tracing::{debug, error, info, trace, warn};
use wgpu::rwh::HasWindowHandle;
use winit::application::ApplicationHandler;
use winit::dpi::LogicalSize;
use winit::dpi::Size;
use winit::event::{KeyEvent, WindowEvent};
use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
use winit::monitor::MonitorHandle;
use winit::platform::windows::WindowAttributesExtWindows;
use winit::window::Fullscreen;
use winit::window::Icon;
use winit::window::Window;
use winit::window::WindowId;
@ -90,7 +95,14 @@ f 6/11/6 5/10/6 1/1/6 2/13/6
impl App<'_> {
fn create_main_window(&mut self, event_loop: &ActiveEventLoop) {
let win_attr = Window::default_attributes().with_title("Zenyx").with_min_inner_size(Size::Logical(LogicalSize::new(100.0, 100.0)));
let icon = self.load_icon_from_bytes(Self::ICON).unwrap();
let win_attr = Window::default_attributes()
.with_title("Zenyx")
.with_min_inner_size(Size::Logical(LogicalSize::new(100.0, 100.0)))
.with_window_icon(icon.clone())
.with_taskbar_icon(icon);
match event_loop.create_window(win_attr) {
Ok(window) => {
let window = Arc::new(window);
@ -160,7 +172,7 @@ impl App<'_> {
) {
if !key_event.state.is_pressed() || key_event.repeat {
return;
}
}
match key_event.physical_key {
winit::keyboard::PhysicalKey::Code(code) => match code {
winit::keyboard::KeyCode::Space => {
@ -199,6 +211,7 @@ impl App<'_> {
warn!("No window context for toggling background: {:?}", window_id);
}
}
fn toggle_fullscreen(&mut self, window_id: WindowId) {
if let Some(ctx) = self.windows.get_mut(&window_id) {
let is_fullscreen = ctx.window.fullscreen().is_some();
@ -216,13 +229,43 @@ impl App<'_> {
warn!("No window found for fullscreen toggle: {:?}", window_id);
}
}
fn load_icon_from_bytes(&self, bytes: &[u8]) -> Result<Option<Icon>, String> {
const IMAGE_DIR: &str = env!("CARGO_MANIFEST_DIR");
let cursor = Cursor::new(bytes);
let format = image::guess_format(bytes).map_err(|_| "Failed to guess image format")?;
let decoder = match format {
ImageFormat::Png => image::codecs::png::PngDecoder::new(cursor).map_err(|e| format!("Failed to decode PNG: {}", e))?,
_ => {
let img = image::load_from_memory(bytes).map_err(|e| format!("Failed to load image: {}", e))?.into_rgba8();
let (width, height) = img.dimensions();
return Icon::from_rgba(img.into_raw(), width, height)
.map(Some)
.map_err(|e| format!("Failed to create icon from bytes: {}", e));
}
};
let (width, height) = decoder.dimensions();
let mut image_data = vec![0; decoder.total_bytes() as usize];
decoder.read_image(&mut image_data).map_err(|e| format!("Failed to read image data: {}", e))?;
Icon::from_rgba(image_data, width, height)
.map(Some)
.map_err(|e| format!("Failed to create icon from bytes: {}", e))
}
const ICON: &'static [u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/../assets/Badge.png"));
fn spawn_child_window(&mut self, event_loop: &ActiveEventLoop) {
if let Some(main_ctx) = self.windows.values().find(|ctx| ctx.is_main_window()) {
let title = format!("Zenyx - New Window {}", self.windows.len());
// TODO: Verify that this is safe instead of matching on it
let icon = self.load_icon_from_bytes(Self::ICON).unwrap();
let win_attr = unsafe {
let base = Window::default_attributes().with_title(title).with_min_inner_size(Size::Logical(LogicalSize::new(100.0, 100.0)));
let base = Window::default_attributes()
.with_title(title)
.with_min_inner_size(Size::Logical(LogicalSize::new(100.0, 100.0)))
.with_window_icon(icon.clone())
.with_taskbar_icon(icon);
match main_ctx.window_handle() {
Ok(handle) => {
if !cfg!(target_os = "windows") {
@ -230,11 +273,11 @@ impl App<'_> {
} else {
base
}
},
}
Err(e) => {
error!("{e}");
base
},
}
}
};
match event_loop.create_window(win_attr) {