From d114cba193e62ea25e1c67d745273942b4764047 Mon Sep 17 00:00:00 2001 From: Veneficium <85629831+veneficium42@users.noreply.github.com> Date: Sat, 8 Nov 2025 22:27:30 +0100 Subject: [PATCH] refactor + big performance improvements --- src/main.rs | 107 +++++++++++++++++++++++----------------------------- 1 file changed, 48 insertions(+), 59 deletions(-) diff --git a/src/main.rs b/src/main.rs index 8b4acc8..d5e622d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,8 +7,8 @@ use std::{env, time::*}; use anyhow::Context; use image::codecs::gif::GifDecoder; -use image::{AnimationDecoder, Delay, Frame, RgbImage}; -use image::{DynamicImage, ImageFormat, ImageReader, imageops::FilterType}; +use image::{AnimationDecoder, Frame, RgbaImage}; +use image::{ImageFormat, ImageReader}; use winit::application::ApplicationHandler; use winit::event::WindowEvent; @@ -21,8 +21,7 @@ use softbuffer::Surface; struct App { window: Option>, surface: Option>>, - image: DynamicImage, - resized_image: RgbImage, + image: RgbaImage, // animated images stuff animation: Option, @@ -31,8 +30,6 @@ struct App { #[derive(Default)] struct Animation { frames: Vec, - resized_frames: Vec>, - frame_dur: Vec, //current frame frame: usize, last_update: Option, @@ -45,17 +42,8 @@ impl ApplicationHandler for App { let context = softbuffer::Context::new(event_loop.owned_display_handle()).unwrap(); let surface = Surface::new(&context, window.clone()).unwrap(); - let size = window.inner_size(); - - self.resized_image = self - .image - .resize(size.width, size.height, FilterType::Nearest) - .to_rgb8(); - if let Some(anim) = self.animation.as_mut() { - anim.frame_dur = anim.frames.iter().map(|frame| frame.delay()).collect(); anim.last_update = Some(Instant::now()); - anim.resized_frames = vec![None; anim.frames.len()]; } self.surface = Some(surface); @@ -79,44 +67,61 @@ impl ApplicationHandler for App { .expect("redraw request without a surface"); let size = window.inner_size(); - - if let Some(anim) = self.animation.as_mut() { - let curr_frame = anim.frame; - match anim.resized_frames[curr_frame].as_ref() { - Some(frame) => { - self.resized_image = frame.clone(); - } - None => { - let original_buffer = anim.frames[curr_frame].buffer().clone(); - let resized_frame = DynamicImage::ImageRgba8(original_buffer) - .resize(size.width, size.height, FilterType::Nearest) - .into_rgb8(); - anim.resized_frames[curr_frame] = Some(resized_frame); - self.resized_image = anim.resized_frames[curr_frame].clone().unwrap(); - } - } - } - let mut buffer = surface.buffer_mut().unwrap(); - let x_offset = ((size.width - self.resized_image.width()) / 2) as usize; - let y_offset = ((size.height - self.resized_image.height()) / 2) as usize; + let mut img_ref = &self.image; + + if let Some(anim) = self.animation.as_mut() { + if anim.last_update.unwrap().elapsed() > anim.frames[anim.frame].delay().into() + { + anim.last_update = Some(Instant::now()); + anim.frame += 1; + if anim.frame >= anim.frames.len() { + anim.frame = 0; + } + } + + img_ref = anim.frames[anim.frame].buffer(); + } + + let w_ratio = size.width as f32 / img_ref.width() as f32; + let h_ratio = size.height as f32 / img_ref.height() as f32; + + let preferred_size = if w_ratio <= h_ratio { + ( + size.width as f32, + (img_ref.height() as f32 * w_ratio).round(), + ) + } else { + ( + (img_ref.width() as f32 * h_ratio).round(), + size.height as f32, + ) + }; + + let x_scaling = img_ref.width() as f32 / preferred_size.0 as f32; + let y_scaling = img_ref.height() as f32 / preferred_size.1 as f32; + + let x_offset = ((size.width - preferred_size.0 as u32) / 2) as usize; + let y_offset = ((size.height - preferred_size.1 as u32) / 2) as usize; for (y, row) in buffer.chunks_exact_mut(size.width as usize).enumerate() { - if y < y_offset || y >= y_offset + self.resized_image.height() as usize { + if y < y_offset || y >= y_offset + preferred_size.1 as usize { row.fill(0); continue; } + let old_y = ((y - y_offset) as f32 * y_scaling) as u32; + for (x, buf_pix) in row.iter_mut().enumerate() { - if x < x_offset || x >= x_offset + self.resized_image.width() as usize { + if x < x_offset || x >= x_offset + preferred_size.0 as usize { *buf_pix = 0; continue; } - let img_pix = self - .resized_image - .get_pixel((x - x_offset) as u32, (y - y_offset) as u32); + let old_x = ((x - x_offset) as f32 * x_scaling) as u32; + + let img_pix = img_ref.get_pixel(old_x, old_y); *buf_pix = u32::from_be_bytes([0, img_pix.0[0], img_pix.0[1], img_pix.0[2]]); @@ -127,15 +132,8 @@ impl ApplicationHandler for App { buffer.present().unwrap(); - if let Some(anim) = self.animation.as_mut() { - if anim.last_update.unwrap().elapsed() > anim.frame_dur[anim.frame].into() { - anim.last_update = Some(Instant::now()); - anim.frame += 1; - if anim.frame >= anim.frames.len() { - anim.frame = 0; - } - } - //TODO don't fucking spam redraws + if self.animation.is_some() { + //TODO DONT SPAM REDRAWS window.request_redraw(); } } @@ -151,15 +149,6 @@ impl ApplicationHandler for App { NonZeroU32::new(new_size.height).unwrap(), ) .expect("surface resize gone wrong"); - - if let Some(anim) = self.animation.as_mut() { - anim.resized_frames = vec![None; anim.frames.len()]; - } else { - self.resized_image = self - .image - .resize(new_size.width, new_size.height, FilterType::Nearest) - .to_rgb8(); - } } _ => (), } @@ -195,7 +184,7 @@ fn main() -> anyhow::Result<()> { app.animation = Some(animation); } _ => { - app.image = image.decode().context("Failed to decode image")?; + app.image = image.decode().context("Failed to decode image")?.to_rgba8(); } }; event_loop.run_app(&mut app)?;