use crate::list::{InstanceList, VertexList}; use rfw::prelude::*; use std::sync::Arc; #[derive(Debug)] pub struct InstanceList2D { instance_capacity: usize, instances: u32, pub instances_buffer: Arc>, } impl Default for InstanceList2D { fn default() -> Self { Self { instance_capacity: 0, instances: 0, instances_buffer: Arc::new(None), } } } impl Clone for InstanceList2D { fn clone(&self) -> Self { Self { instance_capacity: self.instance_capacity, instances: self.instances, instances_buffer: self.instances_buffer.clone(), } } } #[allow(dead_code)] impl InstanceList2D { const DEFAULT_CAPACITY: usize = 4; pub fn new(device: &wgpu::Device) -> Self { let instances_buffer = Some(device.create_buffer(&wgpu::BufferDescriptor { label: None, size: (Self::DEFAULT_CAPACITY * std::mem::size_of::()) as _, usage: wgpu::BufferUsage::STORAGE | wgpu::BufferUsage::COPY_DST, mapped_at_creation: false, })); Self { instance_capacity: Self::DEFAULT_CAPACITY as _, instances: 0, instances_buffer: Arc::new(instances_buffer), } } pub fn len(&self) -> u32 { self.instances } pub fn is_empty(&self) -> bool { self.instances == 0 } } #[derive(Debug)] pub struct Renderer { // pipeline: wgpu::RenderPipeline, pipeline_list: wgpu::RenderPipeline, // layout: wgpu::PipelineLayout, layout_list: wgpu::PipelineLayout, } impl Renderer { pub fn new( device: &wgpu::Device, camera_layout: &wgpu::BindGroupLayout, textures_bind_group_layout: &wgpu::BindGroupLayout, ) -> Self { let layout_list = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("2d-layout"), bind_group_layouts: &[camera_layout, &textures_bind_group_layout], push_constant_ranges: &[], }); let vert = include_bytes!("../shaders/2d_list.vert.spv"); let frag = include_bytes!("../shaders/2d_list.frag.spv"); let vert = &vert[0..vert.len()]; let frag = &frag[0..frag.len()]; let vertex = wgpu::ShaderModuleDescriptor { flags: Default::default(), label: None, source: wgpu::ShaderSource::SpirV(vert.as_quad_bytes().into()), }; let frag = wgpu::ShaderModuleDescriptor { flags: Default::default(), label: None, source: wgpu::ShaderSource::SpirV(frag.as_quad_bytes().into()), }; let pipeline_list = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("2d-pipeline"), layout: Some(&layout_list), vertex: wgpu::VertexState { buffers: &[wgpu::VertexBufferLayout { array_stride: std::mem::size_of::() as wgpu::BufferAddress, attributes: &[ wgpu::VertexAttribute { offset: 0, format: wgpu::VertexFormat::Float32x3, shader_location: 0, }, wgpu::VertexAttribute { offset: 12, format: wgpu::VertexFormat::Uint32, shader_location: 1, }, wgpu::VertexAttribute { offset: 16, format: wgpu::VertexFormat::Float32x2, shader_location: 2, }, wgpu::VertexAttribute { offset: 24, format: wgpu::VertexFormat::Float32x4, shader_location: 3, }, ], step_mode: wgpu::InputStepMode::Vertex, }], entry_point: "main", module: &device.create_shader_module(&vertex), }, fragment: Some(wgpu::FragmentState { entry_point: "main", module: &device.create_shader_module(&frag), targets: &[wgpu::ColorTargetState { format: super::output::WgpuOutput::OUTPUT_FORMAT, write_mask: wgpu::ColorWrite::ALL, blend: Some(wgpu::BlendState { color: wgpu::BlendComponent { src_factor: wgpu::BlendFactor::SrcAlpha, dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, operation: wgpu::BlendOperation::Add, }, alpha: wgpu::BlendComponent { src_factor: wgpu::BlendFactor::SrcAlpha, dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, operation: wgpu::BlendOperation::Add, }, }), }], }), primitive: wgpu::PrimitiveState { front_face: wgpu::FrontFace::Ccw, cull_mode: None, polygon_mode: wgpu::PolygonMode::Fill, strip_index_format: None, topology: wgpu::PrimitiveTopology::TriangleList, clamp_depth: false, conservative: false, }, depth_stencil: Some(wgpu::DepthStencilState { format: super::output::WgpuOutput::DEPTH_FORMAT, depth_write_enabled: true, depth_compare: wgpu::CompareFunction::Always, bias: wgpu::DepthBiasState::default(), stencil: wgpu::StencilState::default(), }), multisample: wgpu::MultisampleState { count: 1, mask: !0, alpha_to_coverage_enabled: false, }, }); Self { // pipeline, pipeline_list, // layout, layout_list, } } #[allow(clippy::too_many_arguments)] pub fn render_list( &self, encoder: &mut wgpu::CommandEncoder, camera_bg: &wgpu::BindGroup, textures_bg: &wgpu::BindGroup, list: &VertexList, instances: &InstanceList, output: &wgpu::TextureView, depth_view: &wgpu::TextureView, ) { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: None, color_attachments: &[wgpu::RenderPassColorAttachment { resolve_target: None, ops: wgpu::Operations { load: wgpu::LoadOp::Load, store: true, }, view: output, }], depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { view: depth_view, depth_ops: Some(wgpu::Operations { load: wgpu::LoadOp::Clear(1.0_f32), store: true, }), stencil_ops: None, }), }); render_pass.set_pipeline(&self.pipeline_list); render_pass.set_vertex_buffer(0, list.get_vertex_buffer().buffer().slice(..)); render_pass.set_bind_group(0, camera_bg, &[]); render_pass.set_bind_group(1, textures_bg, &[]); let v_ranges = list.get_ranges(); let ranges = instances.get_ranges(); for (i, r) in ranges.iter() { let v = v_ranges.get(i).unwrap(); render_pass.draw(v.start..v.end, r.start..r.end); } } } #[derive(Debug, Copy, Clone)] #[repr(C)] pub struct InstanceDescriptor { aux: [u32; 4], // Additional data (currently only texture id & mesh id), } impl Default for InstanceDescriptor { fn default() -> Self { Self { aux: [0; 4] } } } #[allow(dead_code)] impl InstanceDescriptor { pub fn tex_id(&self) -> Option { if self.aux[0] > 0 { Some(self.aux[0]) } else { None } } pub fn mesh_id(&self) -> u32 { self.aux[1] } } #[derive(Debug)] pub struct Mesh { pub tex_id: Option, pub bind_group: Option>, } impl Clone for Mesh { fn clone(&self) -> Self { Self { tex_id: self.tex_id, bind_group: self.bind_group.clone(), } } } impl Default for Mesh { fn default() -> Self { Self { tex_id: None, bind_group: None, } } } #[allow(dead_code)] impl Mesh { pub fn new(mesh: MeshData2D) -> Self { Self { tex_id: mesh.tex_id, bind_group: None, } } pub fn update_bind_group( &mut self, device: &wgpu::Device, layout: &wgpu::BindGroupLayout, texture: &wgpu::TextureView, sampler: &wgpu::Sampler, ) { self.bind_group = Some(Arc::new(device.create_bind_group( &wgpu::BindGroupDescriptor { label: None, layout, entries: &[ wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::TextureView(texture), }, wgpu::BindGroupEntry { binding: 1, resource: wgpu::BindingResource::Sampler(sampler), }, ], }, ))); } }