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 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<Rc<Window>>,
surface: Option<Surface<OwnedDisplayHandle, Rc<Window>>>,
image: DynamicImage,
resized_image: RgbImage,
image: RgbaImage,
// animated images stuff
animation: Option<Animation>,
@ -31,8 +30,6 @@ struct App {
#[derive(Default)]
struct Animation {
frames: Vec<Frame>,
resized_frames: Vec<Option<RgbImage>>,
frame_dur: Vec<Delay>,
//current frame
frame: usize,
last_update: Option<Instant>,
@ -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)?;