use crate::{render::*, temp::*, asset::*, render::mesh::*}; use legion::prelude::*; use std::{mem, sync::Arc}; use zerocopy::{AsBytes, FromBytes}; use wgpu::{CommandEncoder, Device, BindGroupLayout, VertexBufferDescriptor, SwapChainDescriptor, SwapChainOutput}; #[repr(C)] #[derive(Clone, Copy, AsBytes, FromBytes)] pub struct ForwardUniforms { pub proj: [[f32; 4]; 4], pub num_lights: [u32; 4], } pub struct ForwardPass { pub pipeline: wgpu::RenderPipeline, pub bind_group: wgpu::BindGroup, pub forward_uniform_buffer: wgpu::Buffer, pub light_uniform_buffer: Arc::, pub depth_texture: wgpu::TextureView, } impl Pass for ForwardPass { fn render(&mut self, device: &Device, frame: &SwapChainOutput, encoder: &mut CommandEncoder, world: &mut World) { let mut mesh_query = <(Read, Read>)>::query(); let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { attachment: &frame.view, resolve_target: None, load_op: wgpu::LoadOp::Clear, store_op: wgpu::StoreOp::Store, clear_color: wgpu::Color { r: 0.1, g: 0.2, b: 0.3, a: 1.0, }, }], depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { attachment: &self.depth_texture, depth_load_op: wgpu::LoadOp::Clear, depth_store_op: wgpu::StoreOp::Store, stencil_load_op: wgpu::LoadOp::Clear, stencil_store_op: wgpu::StoreOp::Store, clear_depth: 1.0, clear_stencil: 0, }), }); pass.set_pipeline(&self.pipeline); pass.set_bind_group(0, &self.bind_group, &[]); let mut mesh_storage = world.resources.get_mut::>().unwrap(); for (entity, mesh) in mesh_query.iter_immutable(world) { if let Some(mesh_asset) = mesh_storage.get(*mesh.id) { mesh_asset.setup_buffers(device); pass.set_bind_group(1, entity.bind_group.as_ref().unwrap(), &[]); pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0); pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]); pass.draw_indexed(0 .. mesh_asset.indices.len() as u32, 0, 0 .. 1); }; } } } impl ForwardPass { pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; pub fn new(device: &Device, forward_uniforms: ForwardUniforms, light_uniform_buffer: Arc::, shadow_pass: &shadow::ShadowPass, vertex_buffer_descriptor: VertexBufferDescriptor, local_bind_group_layout: &BindGroupLayout, swap_chain_descriptor: &SwapChainDescriptor) -> ForwardPass { let vs_bytes = shader::load_glsl( include_str!("forward.vert"), shader::ShaderStage::Vertex, ); let fs_bytes = shader::load_glsl( include_str!("forward.frag"), shader::ShaderStage::Fragment, ); let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { bindings: &[ wgpu::BindGroupLayoutBinding { binding: 0, // global visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::UniformBuffer { dynamic: false }, }, wgpu::BindGroupLayoutBinding { binding: 1, // lights visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::UniformBuffer { dynamic: false }, }, wgpu::BindGroupLayoutBinding { binding: 2, visibility: wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::SampledTexture { multisampled: false, dimension: wgpu::TextureViewDimension::D2Array, }, }, wgpu::BindGroupLayoutBinding { binding: 3, visibility: wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::Sampler, }, ], }); let uniform_size = mem::size_of::() as wgpu::BufferAddress; let forward_uniform_buffer = device.create_buffer_with_data( forward_uniforms.as_bytes(), wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, ); // Create bind group let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { layout: &bind_group_layout, bindings: &[ wgpu::Binding { binding: 0, resource: wgpu::BindingResource::Buffer { buffer: &forward_uniform_buffer, range: 0 .. uniform_size, }, }, wgpu::Binding { binding: 1, resource: wgpu::BindingResource::Buffer { buffer: &light_uniform_buffer.buffer, range: 0 .. light_uniform_buffer.size, }, }, wgpu::Binding { binding: 2, resource: wgpu::BindingResource::TextureView(&shadow_pass.shadow_view), }, wgpu::Binding { binding: 3, resource: wgpu::BindingResource::Sampler(&shadow_pass.shadow_sampler), }, ], }); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[&bind_group_layout, local_bind_group_layout], }); let vs_module = device.create_shader_module(&vs_bytes); let fs_module = device.create_shader_module(&fs_bytes); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { layout: &pipeline_layout, vertex_stage: wgpu::ProgrammableStageDescriptor { module: &vs_module, entry_point: "main", }, fragment_stage: Some(wgpu::ProgrammableStageDescriptor { module: &fs_module, entry_point: "main", }), rasterization_state: Some(wgpu::RasterizationStateDescriptor { front_face: wgpu::FrontFace::Ccw, cull_mode: wgpu::CullMode::Back, depth_bias: 0, depth_bias_slope_scale: 0.0, depth_bias_clamp: 0.0, }), primitive_topology: wgpu::PrimitiveTopology::TriangleList, color_states: &[ wgpu::ColorStateDescriptor { format: swap_chain_descriptor.format, color_blend: wgpu::BlendDescriptor::REPLACE, alpha_blend: wgpu::BlendDescriptor::REPLACE, write_mask: wgpu::ColorWrite::ALL, }, ], depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor { format: Self::DEPTH_FORMAT, depth_write_enabled: true, depth_compare: wgpu::CompareFunction::Less, stencil_front: wgpu::StencilStateFaceDescriptor::IGNORE, stencil_back: wgpu::StencilStateFaceDescriptor::IGNORE, stencil_read_mask: 0, stencil_write_mask: 0, }), index_format: wgpu::IndexFormat::Uint16, vertex_buffers: &[vertex_buffer_descriptor], sample_count: 1, sample_mask: !0, alpha_to_coverage_enabled: false, }); ForwardPass { pipeline, bind_group, forward_uniform_buffer, light_uniform_buffer, depth_texture: Self::get_depth_texture(device, swap_chain_descriptor) } } pub fn update_swap_chain_descriptor(&mut self, device: &Device, swap_chain_descriptor: &SwapChainDescriptor) { self.depth_texture = Self::get_depth_texture(device, swap_chain_descriptor); } fn get_depth_texture(device: &Device, swap_chain_descriptor: &SwapChainDescriptor) -> wgpu::TextureView { let texture = device.create_texture(&wgpu::TextureDescriptor { size: wgpu::Extent3d { width: swap_chain_descriptor.width, height: swap_chain_descriptor.height, depth: 1, }, array_layer_count: 1, mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, format: Self::DEPTH_FORMAT, usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, }); texture.create_default_view() } }