old school music tracker
1use std::sync::Arc;
2
3use winit::{dpi::PhysicalSize, event_loop::ActiveEventLoop, window::Window};
4
5use crate::{
6 coordinates::WINDOW_SIZE,
7 palettes::{Palette, RGB8},
8};
9
10#[cfg(all(feature = "gpu_scaling", feature = "soft_scaling"))]
11compile_error!("it's impossible to have both gpu and software scaling enabled");
12
13#[cfg(not(any(feature = "gpu_scaling", feature = "soft_scaling")))]
14compile_error!("at least one of gpu_scaling or soft_scaling needs to be active");
15
16#[cfg(feature = "gpu_scaling")]
17pub struct RenderBackend {
18 backend: crate::gpu::GPUState,
19}
20
21#[cfg(feature = "gpu_scaling")]
22impl RenderBackend {
23 pub fn new(window: Arc<Window>, palette: Palette<RGB8>) -> Self {
24 let mut backend = smol::block_on(crate::gpu::GPUState::new(window));
25 backend.queue_palette_update(palette.into());
26
27 Self { backend }
28 }
29
30 pub fn resize(&mut self, size: PhysicalSize<u32>) {
31 self.backend.resize(size);
32 }
33
34 pub fn render(
35 &mut self,
36 frame_buffer: &[[u8; WINDOW_SIZE.0]; WINDOW_SIZE.1],
37 event_loop: &ActiveEventLoop,
38 ) {
39 match self.backend.render(frame_buffer) {
40 Ok(_) => {}
41 Err(wgpu::SurfaceError::Lost) => self.backend.reinit_surface(),
42 Err(wgpu::SurfaceError::OutOfMemory) => event_loop.exit(),
43 Err(e) => eprint!("{:?}", e),
44 }
45 }
46}
47
48#[cfg(feature = "soft_scaling")]
49pub struct RenderBackend {
50 backend: softbuffer::Surface<Arc<Window>, Arc<Window>>,
51 width: u32,
52 height: u32,
53 palette: Palette<crate::palettes::ZRGB>,
54}
55
56#[cfg(feature = "soft_scaling")]
57impl RenderBackend {
58 pub fn new(window: Arc<Window>, palette: Palette<RGB8>) -> Self {
59 let size = window.inner_size();
60 let context = softbuffer::Context::new(window.clone()).unwrap();
61 Self {
62 backend: softbuffer::Surface::new(&context, window).unwrap(),
63 width: size.width,
64 height: size.height,
65 palette: palette.into(),
66 }
67 }
68
69 pub fn resize(&mut self, size: PhysicalSize<u32>) {
70 self.width = size.width;
71 self.height = size.height;
72 self.backend
73 .resize(
74 std::num::NonZeroU32::new(size.width).unwrap(),
75 std::num::NonZeroU32::new(size.height).unwrap(),
76 )
77 .unwrap()
78 }
79
80 pub fn render(
81 &mut self,
82 frame_buffer: &[[u8; WINDOW_SIZE.0]; WINDOW_SIZE.1],
83 _: &ActiveEventLoop,
84 ) {
85 let mut buffer = self.backend.buffer_mut().unwrap();
86 assert!(buffer.len() == usize::try_from(self.width * self.height).unwrap());
87 let x_step = WINDOW_SIZE.0 as f32 / self.width as f32;
88 let y_step = WINDOW_SIZE.1 as f32 / self.height as f32;
89 for (y_idx, row) in buffer
90 .chunks_exact_mut(self.width.try_into().unwrap())
91 .enumerate()
92 {
93 for (x_idx, pixel) in row.iter_mut().enumerate() {
94 let x_idx = x_idx as f32 * x_step;
95 let y_idx = y_idx as f32 * y_step;
96 *pixel = self
97 .palette
98 .get_raw(frame_buffer[y_idx.floor() as usize][x_idx.floor() as usize]);
99 }
100 }
101 buffer.present().unwrap();
102 }
103}