diff --git a/src/canvas.rs b/src/canvas.rs index c9216c1..e93196f 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -27,9 +27,10 @@ pub trait Application { //--Canvas struct----------------------------------------------------------------------------------- pub struct Canvas { - renderer: WgpuRenderer, - clear_color: Pixel, default_texture: TextureHandle, + clear_color: Pixel, + + renderer: WgpuRenderer, } impl Canvas { diff --git a/src/main.rs b/src/main.rs index 29b709e..d842145 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,7 +30,7 @@ fn setup_logger() -> Result<(), fern::InitError> { message )) }) - .level(log::LevelFilter::Info) + .level(log::LevelFilter::Debug) .chain(std::io::stdout()) .chain(fern::log_file("output.log")?) .apply()?; Ok(()) diff --git a/src/renderer.rs b/src/renderer.rs index ff8e644..7e7a61b 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -22,21 +22,22 @@ pub use matrix::ModelMatrix as ModelMatrix; //--Renderer struct--------------------------------------------------------------------------------- pub struct WgpuRenderer { - surface: wgpu::Surface, - pub device: wgpu::Device, - pub queue: wgpu::Queue, - pub config: wgpu::SurfaceConfiguration, - - surface_size: Size, - pub output: Option, - - pub matrix_layout: wgpu::BindGroupLayout, - pub texture_layout: wgpu::BindGroupLayout, #[allow(dead_code)] shape_render_pipeline: wgpu::RenderPipeline, #[allow(dead_code)] quad_mesh: GpuMesh, //TODO temporary, to be moved to shapes.rs + + pub texture_layout: wgpu::BindGroupLayout, + pub matrix_layout: wgpu::BindGroupLayout, + + frame: Option, + surface: wgpu::Surface, + surface_size: Size, + + pub config: wgpu::SurfaceConfiguration, + pub queue: wgpu::Queue, + pub device: wgpu::Device, } impl WgpuRenderer { @@ -92,8 +93,8 @@ impl WgpuRenderer { // Matrix3::from_nonuniform_scale(1.0, 1.0) //}; - let output = Some(surface.get_current_texture() - .map_err(|_| "Failed to create SurfaceTexture")?); + let frame = Some(surface.get_current_texture() + .map_err(|_| "Failed to create frame")?); let matrix_layout = utils::new_matrix_layout(&device); let texture_layout = utils::new_texture_layout(&device); @@ -174,16 +175,19 @@ impl WgpuRenderer { }; Ok(Self { - surface, - device, - queue, - config, - surface_size, - output, - matrix_layout, - texture_layout, shape_render_pipeline, quad_mesh, + + texture_layout, + matrix_layout, + + frame, + surface, + surface_size, + + config, + queue, + device, }) } @@ -193,15 +197,7 @@ impl WgpuRenderer { pub fn clear(&mut self, color: Pixel) { - let output = match &self.output { - Some(out) => out, - None => { - self.create_output(); - &self.output.as_ref().unwrap() - }, - }; - - let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default()); + let view = self.create_texture_view(); let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Clear Encoder"), }); @@ -224,37 +220,86 @@ impl WgpuRenderer { self.queue.submit(std::iter::once(encoder.finish())); } + /// Resizes the render area to fit the given size. + /// + /// The current frame is dropped, clearing any of the rendering done. The underlying surface is + /// then reconfigured to the right size before a new frame can be created. + /// + /// # Panics + /// + /// The function will panic is the given size has any of its values equal to 0 or if the + /// renderer fails to create a new frame pub fn resize(&mut self, size: Size) { + + trace!("resizing render area..."); + + // check for valid size if size.w == 0 || size.h == 0 { panic!("window has zero as at least one of its dimensions"); } - self.surface_size = size; - //self.aspect_matrix = { - // use cgmath::{Basis3, Rotation3, Deg}; + //destroy current frame + match self.frame.take() { + Some(out) => drop(out), + None => {}//nothing to do + } - // //Matrix3::from(Basis3::from_angle_x(Deg(-0.0))) - // //* Matrix3::identity() - // // * Matrix3::from_nonuniform_scale(1.0 / size.w as f32, 1.0 / size.h as f32) - // Matrix3::from_nonuniform_scale(1.0, 1.0) - - //}; + //reconfigure surface self.config.width = size.w; self.config.height = size.h; self.surface.configure(&self.device, &self.config); + + //generate new frame from new surface + let frame = self.create_frame(); + let _ = self.frame.insert(frame); + + debug!("render area resized !"); } + /// Presents the current frame to the screen. + /// + /// The current frame is presented and a new one is created for the future renders + /// + /// # Panics + /// + /// The function will panic if the renderer fails to create a new frame pub fn present(&mut self) { - match self.output.take() { + trace!("presenting frame..."); + match self.frame.take() { Some(out) => out.present(), - None => { - }//nothing to do + None => {}//nothing to do } + debug!("frame presented !"); + + //generate next frame + let frame = self.create_frame(); + let _ = self.frame.insert(frame); } - pub fn create_output(&mut self) { - self.output = Some( + pub fn create_texture_view(&self) -> wgpu::TextureView { + + self.frame + .as_ref() + .unwrap() + .texture + .create_view(&wgpu::TextureViewDescriptor::default()) + } + + /// Creates a new frame to be rendered on. + /// + /// In case of a lost surface, will try to reconfigure it before creating the frame. + /// + /// #Panics + /// + /// The underlying backend will panic if a new frame is created while the previous one is still + /// alive. Only call this function after the previous frame was either dropped or presented. + /// + /// The function will panic if the frame can't be created. + fn create_frame(&mut self) -> wgpu::SurfaceTexture { + + trace!("creating new frame..."); + let surface_texture = { self.surface.get_current_texture() .map_err(|err| match err { wgpu::SurfaceError::Lost => { @@ -263,8 +308,13 @@ impl WgpuRenderer { self.surface.get_current_texture() }, _ => Err(err) - }).unwrap() - ); + }) + .map_err(|_| "Failed to acquire to SurfaceTexture, giving up") + .unwrap() + }; + debug!("frame created !"); + + surface_texture } } diff --git a/src/sprite/texture_sprite.rs b/src/sprite/texture_sprite.rs index 1b9eb0b..fec02e8 100644 --- a/src/sprite/texture_sprite.rs +++ b/src/sprite/texture_sprite.rs @@ -1,7 +1,9 @@ #[allow(unused_imports)] use log::{debug, error, info, trace, warn}; -use wgpu; +//--Internal imports-------------------------------------------------------------------------------- + +use super::Sprite; use crate::{ texture::TextureHandle, @@ -12,8 +14,9 @@ use crate::{ utils::{Size, Position, Pixel}, }; -use super::Sprite; +//--External imports-------------------------------------------------------------------------------- +use wgpu; use std::cell::RefCell; thread_local!(static PIPELINE : RefCell> = RefCell::new(None)); @@ -118,11 +121,6 @@ impl TextureSprite { //TODO take scale into account self.texture.for_each_in_area(func, self.texture_offset, self.inner_size); } - - pub fn render(&mut self) - { - todo!(); - } } fn initialize_pipeline(renderer: &WgpuRenderer) -> wgpu::RenderPipeline { @@ -196,7 +194,7 @@ impl Sprite for TextureSprite { } fn set_alpha(&mut self, _alpha: u8) { - unimplemented!(); + todo!(); } fn set_scale(&mut self, scale: f32) { @@ -205,19 +203,7 @@ impl Sprite for TextureSprite { fn render(&mut self, renderer: &mut WgpuRenderer) { - let output = match &renderer.output { - Some(out) => out, - None => { - renderer.create_output(); - &renderer.output.as_ref().unwrap() - }, - }; - - //TODO move that to output struct ? - let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default()); - let texture = &self.texture.texture(); - if texture.borrow().is_synced == false { //TODO modify that texture.borrow_mut().update(&mut renderer.queue); @@ -236,6 +222,7 @@ impl Sprite for TextureSprite { let pipeline = pipeline.borrow(); let texture_bind_group = &texture.borrow().bind_group; + let view = renderer.create_texture_view(); let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: Some("Render Pass"), color_attachments: &[Some(wgpu::RenderPassColorAttachment {