refactor + big performance improvements

This commit is contained in:
Veneficium 2025-11-08 22:27:30 +01:00
parent 82ae18ce43
commit d114cba193

View file

@ -7,8 +7,8 @@ use std::{env, time::*};
use anyhow::Context; use anyhow::Context;
use image::codecs::gif::GifDecoder; use image::codecs::gif::GifDecoder;
use image::{AnimationDecoder, Delay, Frame, RgbImage}; use image::{AnimationDecoder, Frame, RgbaImage};
use image::{DynamicImage, ImageFormat, ImageReader, imageops::FilterType}; use image::{ImageFormat, ImageReader};
use winit::application::ApplicationHandler; use winit::application::ApplicationHandler;
use winit::event::WindowEvent; use winit::event::WindowEvent;
@ -21,8 +21,7 @@ use softbuffer::Surface;
struct App { struct App {
window: Option<Rc<Window>>, window: Option<Rc<Window>>,
surface: Option<Surface<OwnedDisplayHandle, Rc<Window>>>, surface: Option<Surface<OwnedDisplayHandle, Rc<Window>>>,
image: DynamicImage, image: RgbaImage,
resized_image: RgbImage,
// animated images stuff // animated images stuff
animation: Option<Animation>, animation: Option<Animation>,
@ -31,8 +30,6 @@ struct App {
#[derive(Default)] #[derive(Default)]
struct Animation { struct Animation {
frames: Vec<Frame>, frames: Vec<Frame>,
resized_frames: Vec<Option<RgbImage>>,
frame_dur: Vec<Delay>,
//current frame //current frame
frame: usize, frame: usize,
last_update: Option<Instant>, last_update: Option<Instant>,
@ -45,17 +42,8 @@ impl ApplicationHandler for App {
let context = softbuffer::Context::new(event_loop.owned_display_handle()).unwrap(); let context = softbuffer::Context::new(event_loop.owned_display_handle()).unwrap();
let surface = Surface::new(&context, window.clone()).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() { 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.last_update = Some(Instant::now());
anim.resized_frames = vec![None; anim.frames.len()];
} }
self.surface = Some(surface); self.surface = Some(surface);
@ -79,44 +67,61 @@ impl ApplicationHandler for App {
.expect("redraw request without a surface"); .expect("redraw request without a surface");
let size = window.inner_size(); 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 mut buffer = surface.buffer_mut().unwrap();
let x_offset = ((size.width - self.resized_image.width()) / 2) as usize; let mut img_ref = &self.image;
let y_offset = ((size.height - self.resized_image.height()) / 2) as usize;
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() { 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); row.fill(0);
continue; continue;
} }
let old_y = ((y - y_offset) as f32 * y_scaling) as u32;
for (x, buf_pix) in row.iter_mut().enumerate() { 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; *buf_pix = 0;
continue; continue;
} }
let img_pix = self let old_x = ((x - x_offset) as f32 * x_scaling) as u32;
.resized_image
.get_pixel((x - x_offset) as u32, (y - y_offset) as u32); let img_pix = img_ref.get_pixel(old_x, old_y);
*buf_pix = *buf_pix =
u32::from_be_bytes([0, img_pix.0[0], img_pix.0[1], img_pix.0[2]]); 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(); buffer.present().unwrap();
if let Some(anim) = self.animation.as_mut() { if self.animation.is_some() {
if anim.last_update.unwrap().elapsed() > anim.frame_dur[anim.frame].into() { //TODO DONT SPAM REDRAWS
anim.last_update = Some(Instant::now());
anim.frame += 1;
if anim.frame >= anim.frames.len() {
anim.frame = 0;
}
}
//TODO don't fucking spam redraws
window.request_redraw(); window.request_redraw();
} }
} }
@ -151,15 +149,6 @@ impl ApplicationHandler for App {
NonZeroU32::new(new_size.height).unwrap(), NonZeroU32::new(new_size.height).unwrap(),
) )
.expect("surface resize gone wrong"); .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.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)?; event_loop.run_app(&mut app)?;