use wgpu::RenderPipeline; use crate::wgpuctx::WgpuCtx; use crate::texture::Texture; use crate::vertex::Vertex; use crate::wgpuctx::pipeline::RenderPipelineBuilder; struct CanvasTexture { pub texture: Texture, buffer: wgpu::Buffer } pub struct Canvas { pipeline: wgpu::RenderPipeline, vertex_buffer: wgpu::Buffer, texture: CanvasTexture, position: winit::dpi::LogicalPosition, size: winit::dpi::LogicalSize } impl Canvas { fn create_canvas_texture( wgpuctx: &WgpuCtx, canvas_size: winit::dpi::LogicalSize, window_size: winit::dpi::PhysicalSize) -> CanvasTexture { let canvas_physical_size = winit::dpi::PhysicalSize::::new( (window_size.width as f32 * canvas_size.width).floor() as u32, (window_size.height as f32 * canvas_size.height).floor() as u32 ); CanvasTexture::new(wgpuctx, canvas_physical_size) } pub fn new( wgpuctx: &WgpuCtx, window_size: winit::dpi::PhysicalSize, position: winit::dpi::LogicalPosition, size: winit::dpi::LogicalSize ) -> Result { let pos_x = position.x * 2.0 - 1.0; let pos_y = position.y * 2.0 - 1.0; let size_x = size.width * 2.0; let size_y = size.height * 2.0; let vertices: &[Vertex] = &[ Vertex { position: [ pos_x, pos_y, 0.0 ], uv: [ 0.0, 1.0 ] }, Vertex { position: [ pos_x+size_x, pos_y, 0.0 ], uv: [ 1.0, 1.0 ] }, Vertex { position: [ pos_x+size_x, pos_y+size_y, 0.0 ], uv: [ 1.0, 0.0 ] }, Vertex { position: [ pos_x+size_x, pos_y+size_y, 0.0 ], uv: [ 1.0, 0.0 ] }, Vertex { position: [ pos_x, pos_y+size_y, 0.0 ], uv: [ 0.0, 0.0 ] }, Vertex { position: [ pos_x, pos_y, 0.0 ], uv: [ 0.0, 1.0 ] }, ]; let vertex_buffer = wgpuctx.create_buffer_init( &wgpu::util::BufferInitDescriptor { label: Some("Vertex Buffer"), contents: bytemuck::cast_slice(vertices), usage: wgpu::BufferUsages::VERTEX } ); let shader = wgpuctx.create_shader( wgpu::include_wgsl!(concat!( env!("CARGO_MANIFEST_DIR"), "/assets/shaders/canvas.wgsl") )); let canvas_texture = Canvas::create_canvas_texture(wgpuctx, size, window_size); let render_pipeline = RenderPipelineBuilder::new( &shader) .add_bindgroup(&canvas_texture.texture.bindgrouplayout) .add_vertex_layout(Vertex::descr()) .build(Some("Canvas render pipleine"), wgpuctx); Ok(Self { pipeline: render_pipeline, vertex_buffer: vertex_buffer, texture: canvas_texture, position: position, size: size }) } pub fn resize( &mut self, wgpuctx: &WgpuCtx, width: u32, height: u32) { let window_size = winit::dpi::PhysicalSize::new(width, height); self.texture = Canvas::create_canvas_texture(wgpuctx, self.size, window_size); } pub fn present( &mut self, screen_pass: &mut wgpu::RenderPass ) -> Result<(), wgpu::SurfaceError> { screen_pass.set_pipeline(&self.pipeline); self.texture.texture.use_on_pass(screen_pass, 0); screen_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); screen_pass.draw(0..6,0..1); Ok(()) } pub fn view(&self) -> &wgpu::TextureView { self.texture.texture.view() } } //impl Canvas impl CanvasTexture { pub fn new( wgpuctx: &WgpuCtx, size: winit::dpi::PhysicalSize) -> Self { let u32_size = std::mem::size_of::() as u32; let buffer_size = (u32_size * size.width * size.height) as wgpu::BufferAddress; let buffer_descr = wgpu::BufferDescriptor { size: buffer_size, usage: wgpu::BufferUsages::COPY_DST, label: None, mapped_at_creation: false }; let texture = wgpuctx.new_render_texture(size); let buffer = wgpuctx.create_buffer(&buffer_descr); Self { texture: texture, buffer: buffer } } } impl WgpuCtx { pub fn new_render_texture( &self, size: winit::dpi::PhysicalSize) -> Texture { let descr = wgpu::TextureDescriptor { size: wgpu::Extent3d { width: size.width, height: size.height, depth_or_array_layers: 1 }, mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, format: wgpu::TextureFormat::Bgra8UnormSrgb, view_formats: &[ wgpu::TextureFormat::Bgra8UnormSrgb ], usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::RENDER_ATTACHMENT, label: None }; self.new_texture(descr) } }