From 0ee1423cb267363d0b315ae7572eb2e6f98bfa4a Mon Sep 17 00:00:00 2001 From: Kai Stevenson Date: Sat, 5 Sep 2026 17:23:46 -0700 Subject: refactor renderer to separate passes --- src/renderer/mod.rs | 871 +++------------------------------------------------- 1 file changed, 43 insertions(+), 828 deletions(-) (limited to 'src/renderer/mod.rs') diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 2deb278..3cf340d 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,65 +1,26 @@ +mod debug; +mod instances; +mod particles; mod ui; +mod vfx; use std::sync::Arc; -use fxhash::FxHashMap; use winit::window::Window; use crate::{ Config, Diagnostics, InputManager, camera::Camera, - config::{CELLS_IN_CHUNK, CHUNK_SIZE}, - content::{materials::MaterialId, vfx::VfxMaterialId}, + content::materials::MaterialId, proc_gen::TilesetWorldGenerator, - renderer::ui::draw_egui, - sim::{ - cell_manager::manager::CellManager, entity::EntityId, - rb_manager::debug_render::DebugVertex, sim_manager::SimManager, + renderer::{ + debug::PhysicsDebugRendererState, instances::InstancesRendererState, + particles::ParticlesRendererState, ui::draw_egui, vfx::VfxRendererState, }, + sim::sim_manager::SimManager, vfx::VfxManager, }; -// TODO derive from shared chunk config -const CHUNK_SLOTS: usize = 11 * 200; - -#[repr(C)] -#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] -struct RendererInstance { - centre: [f32; 2], - cos_sin: [f32; 2], - half_size: [f32; 2], - dims: [u32; 2], - cell_offset: u32, - _padding: u32, -} - -#[repr(C)] -#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] -struct RendererParticle { - position: [f32; 2], - data: u32, - life: f32, -} - -#[repr(C)] -#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] -struct RendererVfxMaterial { - color: [f32; 4], - length: f32, - _padding: [u32; 3], -} - -#[repr(C)] -#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] -struct RendererVfxLine { - a: [f32; 2], - b: [f32; 2], - width: f32, - material: u32, - alive_for: f32, - lifetime: f32, -} - fn srgb_to_linear(channel: u8) -> f32 { let channel = channel as f32 / 255.0; if channel <= 0.04045 { @@ -69,54 +30,6 @@ fn srgb_to_linear(channel: u8) -> f32 { } } -const DEBUG_VERTEX_ATTRIBUTES: [wgpu::VertexAttribute; 2] = - wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x4]; - -fn create_debug_vertex_buffer(device: &wgpu::Device, capacity: usize) -> wgpu::Buffer { - device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Debug vertex buffer"), - size: (capacity * size_of::()) as u64, - usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }) -} - -fn create_instance_buffer(device: &wgpu::Device, capacity: usize) -> wgpu::Buffer { - device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Instance buffer"), - size: (capacity * size_of::()) as u64, - usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }) -} - -fn create_cell_buffer(device: &wgpu::Device, capacity: usize) -> wgpu::Buffer { - device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Cell buffer"), - size: (capacity * CELLS_IN_CHUNK) as u64, - usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }) -} - -fn create_particle_buffer(device: &wgpu::Device, capacity: usize) -> wgpu::Buffer { - device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Particle buffer"), - size: (capacity * size_of::()) as u64, - usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }) -} - -fn create_vfx_line_buffer(device: &wgpu::Device, capacity: usize) -> wgpu::Buffer { - device.create_buffer(&wgpu::BufferDescriptor { - label: Some("VFX line buffer"), - size: (capacity * size_of::()) as u64, - usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }) -} - pub struct RendererState { window: Arc, surface: wgpu::Surface<'static>, @@ -134,36 +47,13 @@ pub struct RendererState { // common camera_uniform_buffer: wgpu::Buffer, - // instances - instance_pipeline: wgpu::RenderPipeline, - instance_buffer: wgpu::Buffer, - cell_buffer: wgpu::Buffer, - instance_bind_group: wgpu::BindGroup, - entity_capacity: usize, - - // particles - particle_pipeline: wgpu::RenderPipeline, - particle_buffer: wgpu::Buffer, - particle_bind_group: wgpu::BindGroup, - particle_capacity: usize, - - // vfx - vfx_line_pipeline: wgpu::RenderPipeline, - vfx_line_buffer: wgpu::Buffer, - vfx_line_bind_group: wgpu::BindGroup, - vfx_line_capacity: usize, - - // physics debug lines - debug_pipeline: wgpu::RenderPipeline, - debug_bind_group: wgpu::BindGroup, - debug_vertex_buffer: wgpu::Buffer, - debug_vertex_capacity: usize, - - renderer_rb_entities: FxHashMap, + instances_renderer_state: InstancesRendererState, + particles_renderer_state: ParticlesRendererState, + vfx_renderer_state: VfxRendererState, + physics_debug_renderer_state: PhysicsDebugRendererState, } impl RendererState { - // https://sotrh.github.io/learn-wgpu/beginner/tutorial1-window pub async fn new(window: Arc) -> Self { let size = window.inner_size(); println!("Got window! ({}x{})", size.width, size.height); @@ -253,135 +143,6 @@ impl RendererState { queue.write_buffer(&palette_buffer, 0, bytemuck::cast_slice(&palette)); - // --- VFX materials --- - let mut vfx_material_palette = [RendererVfxMaterial { - color: [0.0f32; 4], - length: 0.0, - _padding: [0; 3], - }; VfxMaterialId::ALL.len()]; - for material in VfxMaterialId::ALL { - let def = material.def(); - let i = material as usize; - vfx_material_palette[i].color = [ - srgb_to_linear(def.color.0), - srgb_to_linear(def.color.1), - srgb_to_linear(def.color.2), - def.color.3 as f32 / 255.0, - ]; - vfx_material_palette[i].length = def.length; - } - - let vfx_material_palette_buffer = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("VFX Material Palette buffer"), - size: size_of_val(&vfx_material_palette) as u64, - usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }); - - queue.write_buffer( - &vfx_material_palette_buffer, - 0, - bytemuck::cast_slice(&vfx_material_palette), - ); - - // --- INSTANCES --- - let instance_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: None, - entries: &[ - // camera uniform - wgpu::BindGroupLayoutEntry { - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - binding: 0, - count: None, - visibility: wgpu::ShaderStages::VERTEX, - }, - // palette - wgpu::BindGroupLayoutEntry { - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: None, - }, - binding: 1, - count: None, - visibility: wgpu::ShaderStages::FRAGMENT, - }, - // instance buffer - wgpu::BindGroupLayoutEntry { - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: None, - }, - binding: 2, - count: None, - visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, - }, - // cells - wgpu::BindGroupLayoutEntry { - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: None, - }, - binding: 3, - count: None, - visibility: wgpu::ShaderStages::FRAGMENT, - }, - ], - }); - - let instance_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("Instance shader"), - source: wgpu::ShaderSource::Wgsl(include_str!("../shader/instance.wgsl").into()), - }); - - let instance_pipeline_layout = - device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: None, - immediate_size: 0, - bind_group_layouts: &[Some(&instance_bind_group_layout)], - }); - - let instance_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: None, - layout: Some(&instance_pipeline_layout), - vertex: wgpu::VertexState { - module: &instance_shader, - entry_point: Some("vs_main"), - buffers: &[], - compilation_options: wgpu::PipelineCompilationOptions::default(), - }, - fragment: Some(wgpu::FragmentState { - module: &instance_shader, - entry_point: Some("fs_main"), - targets: &[Some(wgpu::ColorTargetState { - format: config.format, - blend: Some(wgpu::BlendState::ALPHA_BLENDING), - write_mask: wgpu::ColorWrites::ALL, - })], - compilation_options: wgpu::PipelineCompilationOptions::default(), - }), - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleStrip, - strip_index_format: None, - front_face: wgpu::FrontFace::Ccw, - cull_mode: None, - polygon_mode: wgpu::PolygonMode::Fill, - unclipped_depth: false, - conservative: false, - }, - depth_stencil: None, - multisample: wgpu::MultisampleState::default(), - multiview_mask: None, - cache: None, - }); - let camera_uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: Some("Camera uniform buffer"), size: 16, @@ -389,333 +150,17 @@ impl RendererState { mapped_at_creation: false, }); - let entity_capacity = 2048; - let instance_buffer = create_instance_buffer(&device, CHUNK_SLOTS + entity_capacity); - - let cell_buffer = create_cell_buffer(&device, entity_capacity + CHUNK_SLOTS); - - let instance_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: None, - layout: &instance_bind_group_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: camera_uniform_buffer.as_entire_binding(), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: palette_buffer.as_entire_binding(), - }, - wgpu::BindGroupEntry { - binding: 2, - resource: instance_buffer.as_entire_binding(), - }, - wgpu::BindGroupEntry { - binding: 3, - resource: cell_buffer.as_entire_binding(), - }, - ], - }); - - // --- PARTICLES --- - let particle_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: None, - entries: &[ - // camera uniform - wgpu::BindGroupLayoutEntry { - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - binding: 0, - count: None, - visibility: wgpu::ShaderStages::VERTEX, - }, - // palette - wgpu::BindGroupLayoutEntry { - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: None, - }, - binding: 1, - count: None, - visibility: wgpu::ShaderStages::FRAGMENT, - }, - // instance buffer - wgpu::BindGroupLayoutEntry { - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: None, - }, - binding: 2, - count: None, - visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, - }, - ], - }); - - let particle_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("Particle shader"), - source: wgpu::ShaderSource::Wgsl(include_str!("../shader/particle.wgsl").into()), - }); - - let particle_pipeline_layout = - device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: None, - immediate_size: 0, - bind_group_layouts: &[Some(&particle_bind_group_layout)], - }); - - let particle_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: None, - layout: Some(&particle_pipeline_layout), - vertex: wgpu::VertexState { - module: &particle_shader, - entry_point: Some("vs_main"), - buffers: &[], - compilation_options: wgpu::PipelineCompilationOptions::default(), - }, - fragment: Some(wgpu::FragmentState { - module: &particle_shader, - entry_point: Some("fs_main"), - targets: &[Some(wgpu::ColorTargetState { - format: config.format, - blend: Some(wgpu::BlendState::ALPHA_BLENDING), - write_mask: wgpu::ColorWrites::ALL, - })], - compilation_options: wgpu::PipelineCompilationOptions::default(), - }), - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleStrip, - strip_index_format: None, - front_face: wgpu::FrontFace::Ccw, - cull_mode: None, - polygon_mode: wgpu::PolygonMode::Fill, - unclipped_depth: false, - conservative: false, - }, - depth_stencil: None, - multisample: wgpu::MultisampleState::default(), - multiview_mask: None, - cache: None, - }); - - let particle_capacity = 2048; - let particle_buffer = create_particle_buffer(&device, particle_capacity); - - let particle_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: None, - layout: &particle_bind_group_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: camera_uniform_buffer.as_entire_binding(), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: palette_buffer.as_entire_binding(), - }, - wgpu::BindGroupEntry { - binding: 2, - resource: particle_buffer.as_entire_binding(), - }, - ], - }); - - // --- VFX_LINES --- - let vfx_line_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: None, - entries: &[ - // camera uniform - wgpu::BindGroupLayoutEntry { - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - binding: 0, - count: None, - visibility: wgpu::ShaderStages::VERTEX, - }, - // material palette - wgpu::BindGroupLayoutEntry { - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: None, - }, - binding: 1, - count: None, - // don't need vertex here - visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, - }, - // instance buffer - wgpu::BindGroupLayoutEntry { - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Storage { read_only: true }, - has_dynamic_offset: false, - min_binding_size: None, - }, - binding: 2, - count: None, - visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, - }, - ], - }); - - let vfx_line_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("VFX Line shader"), - source: wgpu::ShaderSource::Wgsl(include_str!("../shader/vfx_line.wgsl").into()), - }); + let instances_renderer_state = + InstancesRendererState::new(&device, &config, &camera_uniform_buffer, &palette_buffer); - let vfx_line_pipeline_layout = - device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: None, - immediate_size: 0, - bind_group_layouts: &[Some(&vfx_line_bind_group_layout)], - }); + let particles_renderer_state = + ParticlesRendererState::new(&device, &config, &camera_uniform_buffer, &palette_buffer); - let vfx_line_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: None, - layout: Some(&vfx_line_pipeline_layout), - vertex: wgpu::VertexState { - module: &vfx_line_shader, - entry_point: Some("vs_main"), - buffers: &[], - compilation_options: wgpu::PipelineCompilationOptions::default(), - }, - fragment: Some(wgpu::FragmentState { - module: &vfx_line_shader, - entry_point: Some("fs_main"), - targets: &[Some(wgpu::ColorTargetState { - format: config.format, - blend: Some(wgpu::BlendState::ALPHA_BLENDING), - write_mask: wgpu::ColorWrites::ALL, - })], - compilation_options: wgpu::PipelineCompilationOptions::default(), - }), - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleStrip, - strip_index_format: None, - front_face: wgpu::FrontFace::Ccw, - cull_mode: None, - polygon_mode: wgpu::PolygonMode::Fill, - unclipped_depth: false, - conservative: false, - }, - depth_stencil: None, - multisample: wgpu::MultisampleState::default(), - multiview_mask: None, - cache: None, - }); + let vfx_renderer_state = + VfxRendererState::new(&device, &queue, &config, &camera_uniform_buffer); - let vfx_line_capacity = 512; - let vfx_line_buffer = create_vfx_line_buffer(&device, vfx_line_capacity); - - let vfx_line_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: None, - layout: &vfx_line_bind_group_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: camera_uniform_buffer.as_entire_binding(), - }, - wgpu::BindGroupEntry { - binding: 1, - resource: vfx_material_palette_buffer.as_entire_binding(), - }, - wgpu::BindGroupEntry { - binding: 2, - resource: vfx_line_buffer.as_entire_binding(), - }, - ], - }); - - // --- DEBUG --- - let debug_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: Some("Debug bind group layout"), - entries: &[ - // camera uniform - wgpu::BindGroupLayoutEntry { - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - binding: 0, - count: None, - visibility: wgpu::ShaderStages::VERTEX, - }, - ], - }); - - let debug_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: Some("Debug bind group"), - layout: &debug_bind_group_layout, - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: camera_uniform_buffer.as_entire_binding(), - }], - }); - - let debug_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("Debug shader"), - source: wgpu::ShaderSource::Wgsl(include_str!("../shader/debug.wgsl").into()), - }); - - let debug_pipeline_layout = - device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Debug pipeline layout"), - immediate_size: 0, - bind_group_layouts: &[Some(&debug_bind_group_layout)], - }); - - let debug_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("Debug pipeline"), - layout: Some(&debug_pipeline_layout), - vertex: wgpu::VertexState { - module: &debug_shader, - entry_point: Some("vs_main"), - buffers: &[wgpu::VertexBufferLayout { - array_stride: size_of::() as wgpu::BufferAddress, - step_mode: wgpu::VertexStepMode::Vertex, - attributes: &DEBUG_VERTEX_ATTRIBUTES, - }], - compilation_options: wgpu::PipelineCompilationOptions::default(), - }, - fragment: Some(wgpu::FragmentState { - module: &debug_shader, - entry_point: Some("fs_main"), - targets: &[Some(wgpu::ColorTargetState { - format: config.format, - blend: Some(wgpu::BlendState::ALPHA_BLENDING), - write_mask: wgpu::ColorWrites::ALL, - })], - compilation_options: wgpu::PipelineCompilationOptions::default(), - }), - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::LineList, - strip_index_format: None, - front_face: wgpu::FrontFace::Ccw, - cull_mode: None, - polygon_mode: wgpu::PolygonMode::Fill, - unclipped_depth: false, - conservative: false, - }, - depth_stencil: None, - multisample: wgpu::MultisampleState::default(), - multiview_mask: None, - cache: None, - }); - - let debug_vertex_capacity = 4096; - let debug_vertex_buffer = create_debug_vertex_buffer(&device, debug_vertex_capacity); + let physics_debug_renderer_state = + PhysicsDebugRendererState::new(&device, &config, &camera_uniform_buffer); RendererState { window, @@ -731,28 +176,10 @@ impl RendererState { camera_uniform_buffer, - instance_pipeline, - instance_buffer, - cell_buffer, - instance_bind_group, - entity_capacity, - - particle_pipeline, - particle_buffer, - particle_bind_group, - particle_capacity, - - vfx_line_pipeline, - vfx_line_buffer, - vfx_line_bind_group, - vfx_line_capacity, - - debug_pipeline, - debug_bind_group, - debug_vertex_buffer, - debug_vertex_capacity, - - renderer_rb_entities: FxHashMap::default(), + instances_renderer_state, + particles_renderer_state, + vfx_renderer_state, + physics_debug_renderer_state, } } @@ -868,207 +295,21 @@ impl RendererState { bytemuck::bytes_of(&camera.to_uniform()), ); - let mut cell_buffer: [u8; CELLS_IN_CHUNK] = [0; CELLS_IN_CHUNK]; - let mut instances: Vec = Vec::new(); - - { - puffin::profile_scope!("Upload chunk cells"); - for &idx in sim.cell_manager.chunk_position_to_chunk_idx.values() { - let chunk = &mut sim.cell_manager.chunks[idx]; - if !chunk.needs_texture_update { - continue; - } - chunk.needs_texture_update = false; - - for (byte, cell) in cell_buffer.iter_mut().zip(chunk.cells.iter()) { - *byte = cell.material as u8; - } - - self.queue.write_buffer( - &self.cell_buffer, - (idx * CELLS_IN_CHUNK) as u64, - &cell_buffer, - ); - } - } - - { - puffin::profile_scope!("Upload entity cells"); - // TODO optimize, this is very inefficient, just build it per frame with positions and skip the lookup? - self.renderer_rb_entities.clear(); - for entity in sim.entities.values() { - // TODO add "needs texture update"? - if let Some(cells) = &entity.data.cells { - for i in 0..cells.cells.len() { - cell_buffer[i] = cells.cells[i].material as u8; - } - - let next_slot = CHUNK_SLOTS + self.renderer_rb_entities.len(); - let slot = *self - .renderer_rb_entities - .entry(entity.data.id) - .or_insert(next_slot); - - self.queue.write_buffer( - &self.cell_buffer, - (slot * CHUNK_SIZE as usize * CHUNK_SIZE as usize) as u64, - &cell_buffer, - ); - } - } - } - - { - puffin::profile_scope!("Build instances"); - let (lower, upper) = camera.viewport_bounds_world(); - let ((cxl, cyl), _) = - CellManager::split_game_position(lower.x.floor() as i32, lower.y.floor() as i32); - let ((cxu, cyu), _) = - CellManager::split_game_position(upper.x.floor() as i32, upper.y.floor() as i32); - - let half_size = [CHUNK_SIZE as f32 / 2.0, CHUNK_SIZE as f32 / 2.0]; - let dims = [CHUNK_SIZE as u32, CHUNK_SIZE as u32]; - - for cx in cxl..=cxu { - for cy in cyl..=cyu { - if let Some(idx) = sim.cell_manager.chunk_position_to_chunk_idx.get(&(cx, cy)) { - instances.push(RendererInstance { - centre: [ - (cx * CHUNK_SIZE) as f32 + half_size[0], - (cy * CHUNK_SIZE) as f32 + half_size[1], - ], - cos_sin: [1.0, 0.0], - half_size, - dims, - cell_offset: (idx * CELLS_IN_CHUNK) as u32, - _padding: 0, - }); - } - } - } - - let mut entities = 0; - for (id, slot) in &self.renderer_rb_entities { - if let Some(entity) = sim.entities.get(id) - && let Some(cells) = &entity.data.cells - && let Some((pos, (cos, sin))) = entity.data._transform(&sim.rb_manager) - { - // TODO access this better - // let sleeping = sim - // .rb_manager - // .physics_manager - // .world - // .bodies - // .get(entity.data.rb_h.unwrap()) - // .unwrap() - // .is_sleeping(); - let sleeping = false; - - entities += 1; - instances.push(RendererInstance { - centre: if sleeping { - pos.round().to_array() - } else { - pos.to_array() - }, - cos_sin: [cos, sin], - half_size: (cells.size / 2).as_vec2().to_array(), - dims: cells.size.as_uvec2().to_array(), - cell_offset: (slot * CHUNK_SIZE as usize * CHUNK_SIZE as usize) as u32, - _padding: 0, - }); - } - } - - if entities > self.entity_capacity { - self.entity_capacity = entities.next_power_of_two(); - self.instance_buffer = - create_instance_buffer(&self.device, self.entity_capacity + CHUNK_SLOTS); - self.cell_buffer = - create_cell_buffer(&self.device, CHUNK_SLOTS + self.entity_capacity); - } - - self.queue - .write_buffer(&self.instance_buffer, 0, bytemuck::cast_slice(&instances)); - } - - let mut particles: Vec = Vec::new(); - - { - puffin::profile_scope!("Build particles"); - // TODO could cull this to visible, maybe it's slower? - particles = sim - .particle_manager - .particles - .iter() - .map(|p| RendererParticle { - position: [p.position.x, p.position.y], - data: p.material as u32, - life: p.life, - }) - .collect(); - - if particles.len() > self.particle_capacity { - self.particle_capacity = particles.len().next_power_of_two(); - self.particle_buffer = create_particle_buffer(&self.device, self.particle_capacity); - } - - self.queue - .write_buffer(&self.particle_buffer, 0, bytemuck::cast_slice(&particles)); - } - - let mut vfx_lines: Vec = Vec::new(); - - { - puffin::profile_scope!("Build VFX lines"); - // TODO could cull this to visible, maybe it's slower? - vfx_lines = vfx_manager - .lines - .iter() - .map(|p| RendererVfxLine { - a: p.a.to_array(), - b: p.b.to_array(), - material: p.material as u32, - width: p.width, - alive_for: p.alive_for, - lifetime: p.lifetime, - }) - .collect(); - - if vfx_lines.len() > self.vfx_line_capacity { - self.vfx_line_capacity = vfx_lines.len().next_power_of_two(); - self.vfx_line_buffer = create_vfx_line_buffer(&self.device, self.vfx_line_capacity); - } - - self.queue - .write_buffer(&self.vfx_line_buffer, 0, bytemuck::cast_slice(&vfx_lines)); + self.instances_renderer_state + .update_buffers(&self.device, &self.queue, sim, camera); + self.particles_renderer_state + .update_buffers(&self.device, &self.queue, sim); + self.vfx_renderer_state + .update_buffers(&self.device, &self.queue, vfx_manager); + if config.debug_render { + self.physics_debug_renderer_state.update_buffers( + &self.device, + &self.queue, + sim, + config.debug_render_mode, + ); } - let debug_vertex_count = if config.debug_render { - puffin::profile_scope!("Build physics debug lines"); - let vertices = sim.rb_manager.debug_render(config.debug_render_mode); - - if vertices.is_empty() { - 0 - } else { - if vertices.len() > self.debug_vertex_capacity { - self.debug_vertex_capacity = vertices.len().next_power_of_two(); - self.debug_vertex_buffer = - create_debug_vertex_buffer(&self.device, self.debug_vertex_capacity); - } - - self.queue.write_buffer( - &self.debug_vertex_buffer, - 0, - bytemuck::cast_slice(vertices), - ); - - vertices.len() as u32 - } - } else { - 0 - }; - { puffin::profile_scope!("Main render pass"); let mut render_pass: wgpu::RenderPass<'_> = @@ -1094,37 +335,11 @@ impl RendererState { multiview_mask: None, }); - // this is kind of a hack - let instances_start = u32::min( - if config.cells_render { - 0 - } else { - CHUNK_SLOTS as u32 - }, - instances.len() as u32 - 1, - ); - - // instances - render_pass.set_pipeline(&self.instance_pipeline); - render_pass.set_bind_group(0, &self.instance_bind_group, &[]); - render_pass.draw(0..4, instances_start..instances.len() as u32); - - // particles - render_pass.set_pipeline(&self.particle_pipeline); - render_pass.set_bind_group(0, &self.particle_bind_group, &[]); - render_pass.draw(0..4, 0..particles.len() as u32); - - // vfx - render_pass.set_pipeline(&self.vfx_line_pipeline); - render_pass.set_bind_group(0, &self.vfx_line_bind_group, &[]); - render_pass.draw(0..4, 0..vfx_lines.len() as u32); - - // debug - if debug_vertex_count > 0 { - render_pass.set_pipeline(&self.debug_pipeline); - render_pass.set_bind_group(0, &self.debug_bind_group, &[]); - render_pass.set_vertex_buffer(0, self.debug_vertex_buffer.slice(..)); - render_pass.draw(0..debug_vertex_count, 0..1); + self.instances_renderer_state.render(&mut render_pass); + self.particles_renderer_state.render(&mut render_pass); + self.vfx_renderer_state.render(&mut render_pass); + if config.debug_render { + self.physics_debug_renderer_state.render(&mut render_pass); } } -- cgit v1.3.1