diff options
| author | Kai Stevenson <kai@kaistevenson.com> | 2026-08-16 17:29:42 -0700 |
|---|---|---|
| committer | Kai Stevenson <kai@kaistevenson.com> | 2026-08-16 17:29:42 -0700 |
| commit | f177cc716c5f2aa5b50b14ccbb421de89e3a7854 (patch) | |
| tree | db06f9f44251d6d90e5e9709d47e6cc4397b9443 /src | |
| parent | 40e9d818195824749293dff3afcfdd5c1432adbe (diff) | |
wip
Diffstat (limited to 'src')
| -rw-r--r-- | src/config.rs | 2 | ||||
| -rw-r--r-- | src/main.rs | 32 | ||||
| -rw-r--r-- | src/renderer/mod.rs | 250 | ||||
| -rw-r--r-- | src/renderer/ui.rs | 2 | ||||
| -rw-r--r-- | src/sim/cell/cell.rs (renamed from src/sim/cell.rs) | 2 | ||||
| -rw-r--r-- | src/sim/cell/materials/fire.rs (renamed from src/sim/materials/fire.rs) | 5 | ||||
| -rw-r--r-- | src/sim/cell/materials/gas.rs (renamed from src/sim/materials/gas.rs) | 2 | ||||
| -rw-r--r-- | src/sim/cell/materials/mod.rs (renamed from src/sim/materials/mod.rs) | 2 | ||||
| -rw-r--r-- | src/sim/cell/materials/sand.rs (renamed from src/sim/materials/sand.rs) | 2 | ||||
| -rw-r--r-- | src/sim/cell/materials/smoke.rs (renamed from src/sim/materials/smoke.rs) | 2 | ||||
| -rw-r--r-- | src/sim/cell/materials/water.rs (renamed from src/sim/materials/water.rs) | 2 | ||||
| -rw-r--r-- | src/sim/cell/mod.rs | 2 | ||||
| -rw-r--r-- | src/sim/cell_sim/chunk.rs (renamed from src/sim/chunk.rs) | 2 | ||||
| -rw-r--r-- | src/sim/cell_sim/mod.rs | 4 | ||||
| -rw-r--r-- | src/sim/cell_sim/overlay.rs (renamed from src/sim/overlay.rs) | 2 | ||||
| -rw-r--r-- | src/sim/cell_sim/sim.rs (renamed from src/sim/sim.rs) | 5 | ||||
| -rw-r--r-- | src/sim/cell_sim/world.rs (renamed from src/sim/world.rs) | 2 | ||||
| -rw-r--r-- | src/sim/mod.rs | 7 | ||||
| -rw-r--r-- | src/sim/rb_sim/mod.rs | 131 | ||||
| -rw-r--r-- | src/sim/rb_sim/rb_entity.rs | 24 |
20 files changed, 393 insertions, 89 deletions
diff --git a/src/config.rs b/src/config.rs index 6a9d392..8739c53 100644 --- a/src/config.rs +++ b/src/config.rs @@ -6,6 +6,6 @@ pub const CELLS_IN_CHUNK: usize = (CHUNK_SIZE * CHUNK_SIZE) as usize; pub const CAMERA_MOVEMENT_SPEED: f32 = 40.0; pub const SIM_FPS: u32 = 120; -pub const SIM_DELTA_TIME: f32 = 1.0 / SIM_FPS as f32; +// pub const SIM_DELTA_TIME: f32 = 1.0 / SIM_FPS as f32; pub const PHYSICS_FPS: u32 = 60; pub const PHYSICS_DELTA_TIME: f32 = 1.0 / PHYSICS_FPS as f32; diff --git a/src/main.rs b/src/main.rs index bb4cb27..a01dbbd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,9 +19,13 @@ use winit::{ use crate::{ camera::Camera, - config::{PHYSICS_DELTA_TIME, PHYSICS_FPS, SIM_DELTA_TIME, SIM_FPS, WINDOW_TITLE}, + config::{PHYSICS_DELTA_TIME, PHYSICS_FPS, SIM_FPS, WINDOW_TITLE}, renderer::RendererState, - sim::{cell::Cell, materials::MaterialId, sim::sim_tick, world::World}, + sim::{ + cell::{cell::Cell, materials::MaterialId}, + cell_sim::{sim::sim_tick, world::World}, + rb_sim::{PhysicsManager, RbSimManager}, + }, }; pub type Error = Box<dyn std::error::Error>; @@ -58,8 +62,12 @@ struct App { camera: Option<Camera>, + // grid world: Option<World>, + // physics + rb_sim_manager: Option<RbSimManager>, + // sim state // the last/current (not yet completed) seqno sim_seqno: u64, @@ -122,8 +130,7 @@ impl App { // called SIM_FPS times per second // will be called before the render and before the physics update(s) // may be called multiple times if the sim time is behind - // sim_delta_time is statically 1/SIM_FPS - fn sim_update(&mut self, _sim_delta_time: f32) { + fn sim_update(&mut self) { if let Some(world) = &mut self.world { sim_tick(world, self.sim_seqno, self.config.use_threading); self.sim_seqno += 1; @@ -133,7 +140,11 @@ impl App { // will be called before the render // may be called multiple times if the physics time is behind // physics_delta_time is statically 1/PHYSICS_FPS - fn physics_update(&mut self, _physics_delta_time: f32) {} + fn physics_update(&mut self, physics_delta_time: f32) { + if let Some(physics_manager) = &mut self.rb_sim_manager { + physics_manager.rb_tick(physics_delta_time); + } + } } impl Default for App { @@ -157,6 +168,8 @@ impl Default for App { world: Some(World::from_default_size()), + rb_sim_manager: Some(RbSimManager::new()), + sim_seqno: 0, sim_paused: false, ignore_pause_next_tick: false, @@ -191,6 +204,9 @@ impl ApplicationHandler for App { self.window = Some(window.clone()); self.renderer_state = Some(executor::block_on(RendererState::new(window.clone()))); + if let Some(rbsm) = &mut self.rb_sim_manager { + rbsm.test(); + } let size = window.inner_size(); self.camera = Some(Camera::new((size.width as i32, size.height as i32))); @@ -300,7 +316,7 @@ impl ApplicationHandler for App { self.last_sim_update = now; if self.sim_paused && self.ignore_pause_next_tick { - self.sim_update(SIM_DELTA_TIME); + self.sim_update(); self.ignore_pause_next_tick = false; } else if !self.sim_paused { self.sim_updates_due += @@ -308,7 +324,7 @@ impl ApplicationHandler for App { let mut updates_done = 0; // don't ever update more than 3 times per frame, or else we can get a pseudo deadlock while self.sim_updates_due >= 1.0 && updates_done < 3 { - self.sim_update(SIM_DELTA_TIME); + self.sim_update(); updates_done += 1; } self.sim_updates_due -= updates_done as f32; @@ -333,10 +349,12 @@ impl ApplicationHandler for App { if let Some(renderer_state) = &mut self.renderer_state && let Some(world) = &mut self.world + && let Some(rb_sim_manager) = &mut self.rb_sim_manager && let Some(camera) = &mut self.camera { renderer_state.render( world, + rb_sim_manager, camera, &mut self.config, &self.diagnostics, diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 5231bc3..e022fe7 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -2,6 +2,7 @@ mod ui; use std::sync::Arc; +use fxhash::FxHashMap; use winit::window::Window; use crate::{ @@ -9,7 +10,7 @@ use crate::{ camera::Camera, config::{CELLS_IN_CHUNK, CHUNK_SIZE}, renderer::ui::draw_egui, - sim::world::World, + sim::{cell_sim::world::World, rb_sim::RbSimManager}, }; struct RendererChunk { @@ -17,6 +18,11 @@ struct RendererChunk { bind_group: wgpu::BindGroup, } +struct RendererRbEntity { + texture: wgpu::Texture, + bind_group: wgpu::BindGroup, +} + #[repr(C)] #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] struct ChunkData { @@ -42,6 +48,8 @@ pub struct RendererState { pixels_pipeline: wgpu::RenderPipeline, camera_uniform_buffer: wgpu::Buffer, camera_uniform_bind_group: wgpu::BindGroup, + + renderer_rb_entities: FxHashMap<u32, RendererRbEntity>, } impl RendererState { @@ -270,6 +278,8 @@ impl RendererState { pixels_pipeline, camera_uniform_bind_group, camera_uniform_buffer, + + renderer_rb_entities: FxHashMap::default(), } } @@ -285,6 +295,7 @@ impl RendererState { pub fn render( &mut self, world: &mut World, + rb_sim_manager: &RbSimManager, camera: &mut Camera, config: &mut Config, diagnostics: &Diagnostics, @@ -420,81 +431,192 @@ impl RendererState { } { - puffin::profile_scope!("Main render pass"); - let mut render_pass: wgpu::RenderPass<'_> = - encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Render Pass"), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &view, - resolve_target: None, - depth_slice: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color { - r: 0.0, - g: 0.0, - b: 0.0, - a: 1.0, - }), - store: wgpu::StoreOp::Store, + puffin::profile_scope!("Upload entity textures"); + for entity in rb_sim_manager.rb_entities.values() { + // TODO add "needs texture update"? + + // TODO use material palette to improve bandwidth of upload + for i in 0..CELLS_IN_CHUNK { + let material = entity.cells[i].material.def(); + chunk_buffer[i * 4] = material.color.0; + chunk_buffer[i * 4 + 1] = material.color.1; + chunk_buffer[i * 4 + 2] = material.color.2; + chunk_buffer[i * 4 + 3] = material.color.3; + } + + let render_entity = &self.renderer_rb_entities.entry(entity.id).or_insert({ + let texture = self.device.create_texture(&wgpu::TextureDescriptor { + label: None, + mip_level_count: 1, + sample_count: 1, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, + format: wgpu_types::TextureFormat::Rgba8UnormSrgb, + size: wgpu::Extent3d { + width: CHUNK_SIZE as u32, + height: CHUNK_SIZE as u32, + depth_or_array_layers: 1, }, - })], - depth_stencil_attachment: None, - occlusion_query_set: None, - timestamp_writes: None, - multiview_mask: None, + dimension: wgpu::TextureDimension::D2, + view_formats: &[], + }); + + let bind_group_layout = + self.device + .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: None, + entries: &[wgpu::BindGroupLayoutEntry { + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { + filterable: true, + }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + binding: 0, + count: None, + visibility: wgpu::ShaderStages::FRAGMENT, + }], + }); + + let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&texture.create_view( + &wgpu::TextureViewDescriptor { + dimension: Some(wgpu::TextureViewDimension::D2), + usage: Some( + wgpu::TextureUsages::TEXTURE_BINDING + | wgpu::TextureUsages::COPY_DST, + ), + ..wgpu::TextureViewDescriptor::default() + }, + )), + }], + }); + + RendererRbEntity { + texture, + bind_group, + } }); - render_pass.set_pipeline(&self.pixels_pipeline); + self.queue.write_texture( + wgpu::TexelCopyTextureInfo { + texture: &render_entity.texture, + aspect: wgpu::TextureAspect::All, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + }, + &chunk_buffer, + wgpu::TexelCopyBufferLayout { + bytes_per_row: Some(CHUNK_SIZE as u32 * 4), + offset: 0, + rows_per_image: Some(CHUNK_SIZE as u32), + }, + wgpu::Extent3d { + width: CHUNK_SIZE as u32, + height: CHUNK_SIZE as u32, + depth_or_array_layers: 1, + }, + ); + } + + { + puffin::profile_scope!("Main render pass"); + let mut render_pass: wgpu::RenderPass<'_> = + encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Render Pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + depth_slice: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 1.0, + }), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + occlusion_query_set: None, + timestamp_writes: None, + multiview_mask: None, + }); - render_pass.set_bind_group(0, &self.camera_uniform_bind_group, &[]); + render_pass.set_pipeline(&self.pixels_pipeline); - let (xl, xu, yl, yu) = camera.viewport_bounds_world(); - let ((cxl, cyl), _) = World::split_game_position(xl.floor() as i32, yl.floor() as i32); - let ((cxu, cyu), _) = World::split_game_position(xu.floor() as i32, yu.floor() as i32); + render_pass.set_bind_group(0, &self.camera_uniform_bind_group, &[]); - // TODO only visible chunks - for cx in cxl..=cxu { - for cy in cyl..=cyu { - if let Some(idx) = world.chunk_position_to_chunk_idx.get(&(cx, cy)) { - let render_chunk = &self.renderer_chunks[*idx]; - render_pass.set_bind_group(1, &render_chunk.bind_group, &[]); - render_pass - .set_immediates(0, bytemuck::bytes_of(&ChunkData { origin: [cx, cy] })); - render_pass.draw(0..4, 0..1); + let (xl, xu, yl, yu) = camera.viewport_bounds_world(); + let ((cxl, cyl), _) = + World::split_game_position(xl.floor() as i32, yl.floor() as i32); + let ((cxu, cyu), _) = + World::split_game_position(xu.floor() as i32, yu.floor() as i32); + + for cx in cxl..=cxu { + for cy in cyl..=cyu { + if let Some(idx) = world.chunk_position_to_chunk_idx.get(&(cx, cy)) { + let render_chunk = &self.renderer_chunks[*idx]; + render_pass.set_bind_group(1, &render_chunk.bind_group, &[]); + render_pass.set_immediates( + 0, + bytemuck::bytes_of(&ChunkData { origin: [cx, cy] }), + ); + render_pass.draw(0..4, 0..1); + } } } + + // TODO this is inefficient + for rb_entity in rb_sim_manager.rb_entities.keys() { + let renderer_rb_entity = self.renderer_rb_entities.get(rb_entity).unwrap(); + let (x, y) = rb_sim_manager.get_rb_entity_position(*rb_entity).unwrap(); + render_pass.set_bind_group(1, &renderer_rb_entity.bind_group, &[]); + render_pass.set_immediates( + 0, + bytemuck::bytes_of(&ChunkData { + origin: [x.round() as i32, y.round() as i32], + }), + ); + render_pass.draw(0..4, 0..1); + } } - } - { - puffin::profile_scope!("Egui render pass"); - let mut egui_pass = encoder - .begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("egui pass"), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &view, - resolve_target: None, - depth_slice: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Load, - store: wgpu::StoreOp::Store, - }, - })], - depth_stencil_attachment: None, - timestamp_writes: None, - occlusion_query_set: None, - multiview_mask: None, - }) - .forget_lifetime(); + { + puffin::profile_scope!("Egui render pass"); + let mut egui_pass = encoder + .begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("egui pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + depth_slice: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + multiview_mask: None, + }) + .forget_lifetime(); - self.egui_renderer - .render(&mut egui_pass, &clipped_primitives, &screen_descriptor); - } + self.egui_renderer + .render(&mut egui_pass, &clipped_primitives, &screen_descriptor); + } - { - puffin::profile_scope!("Submit queue and present"); - self.queue.submit(std::iter::once(encoder.finish())); - output.present(); + { + puffin::profile_scope!("Submit queue and present"); + self.queue.submit(std::iter::once(encoder.finish())); + output.present(); + } } } } diff --git a/src/renderer/ui.rs b/src/renderer/ui.rs index 2e4ebc4..77af59d 100644 --- a/src/renderer/ui.rs +++ b/src/renderer/ui.rs @@ -2,7 +2,7 @@ use egui::{Color32, Stroke, Ui, epaint::CircleShape}; use crate::{ Camera, Config, Diagnostics, Input, - sim::{materials::MaterialId, world::World}, + sim::{cell::materials::MaterialId, cell_sim::world::World}, }; pub fn draw_egui<'a>( diff --git a/src/sim/cell.rs b/src/sim/cell/cell.rs index d3ca302..d35fa76 100644 --- a/src/sim/cell.rs +++ b/src/sim/cell/cell.rs @@ -1,4 +1,4 @@ -use crate::sim::materials::MaterialId; +use crate::sim::cell::materials::MaterialId; #[derive(Clone, Copy)] pub struct Cell { diff --git a/src/sim/materials/fire.rs b/src/sim/cell/materials/fire.rs index 97027d5..e0416b0 100644 --- a/src/sim/materials/fire.rs +++ b/src/sim/cell/materials/fire.rs @@ -1,6 +1,9 @@ use rand::RngExt; -use crate::sim::{cell::Cell, materials::MaterialId, sim::UpdateCtx}; +use crate::sim::{ + cell::{cell::Cell, materials::MaterialId}, + cell_sim::sim::UpdateCtx, +}; trait FireCellView { fn get_ticks_lived(self) -> u16; diff --git a/src/sim/materials/gas.rs b/src/sim/cell/materials/gas.rs index 8d9f42b..c0cd9f9 100644 --- a/src/sim/materials/gas.rs +++ b/src/sim/cell/materials/gas.rs @@ -1,4 +1,4 @@ -use crate::sim::sim::UpdateCtx; +use crate::sim::cell_sim::sim::UpdateCtx; #[inline] pub fn sim_update(ctx: &mut UpdateCtx) { diff --git a/src/sim/materials/mod.rs b/src/sim/cell/materials/mod.rs index 10f0a06..a55ed51 100644 --- a/src/sim/materials/mod.rs +++ b/src/sim/cell/materials/mod.rs @@ -1,4 +1,4 @@ -use crate::sim::sim::UpdateCtx; +use crate::sim::cell_sim::sim::UpdateCtx; mod fire; mod gas; diff --git a/src/sim/materials/sand.rs b/src/sim/cell/materials/sand.rs index ac8889f..d2d1265 100644 --- a/src/sim/materials/sand.rs +++ b/src/sim/cell/materials/sand.rs @@ -1,4 +1,4 @@ -use crate::sim::sim::UpdateCtx; +use crate::sim::cell_sim::sim::UpdateCtx; #[inline] pub fn sim_update(ctx: &mut UpdateCtx) { diff --git a/src/sim/materials/smoke.rs b/src/sim/cell/materials/smoke.rs index 5240bc9..2ee7c00 100644 --- a/src/sim/materials/smoke.rs +++ b/src/sim/cell/materials/smoke.rs @@ -1,6 +1,6 @@ use rand::RngExt; -use crate::sim::sim::UpdateCtx; +use crate::sim::cell_sim::sim::UpdateCtx; #[inline] pub fn sim_update(ctx: &mut UpdateCtx) { diff --git a/src/sim/materials/water.rs b/src/sim/cell/materials/water.rs index 1ba8eb4..4b848fb 100644 --- a/src/sim/materials/water.rs +++ b/src/sim/cell/materials/water.rs @@ -1,4 +1,4 @@ -use crate::sim::sim::UpdateCtx; +use crate::sim::cell_sim::sim::UpdateCtx; #[inline] pub fn sim_update(ctx: &mut UpdateCtx) { diff --git a/src/sim/cell/mod.rs b/src/sim/cell/mod.rs new file mode 100644 index 0000000..2d2175c --- /dev/null +++ b/src/sim/cell/mod.rs @@ -0,0 +1,2 @@ +pub mod cell; +pub mod materials; diff --git a/src/sim/chunk.rs b/src/sim/cell_sim/chunk.rs index 478af12..116a38a 100644 --- a/src/sim/chunk.rs +++ b/src/sim/cell_sim/chunk.rs @@ -1,6 +1,6 @@ use crate::{ config::{CELLS_IN_CHUNK, CHUNK_SIZE}, - sim::cell::Cell, + sim::cell::cell::Cell, }; pub struct Chunk { diff --git a/src/sim/cell_sim/mod.rs b/src/sim/cell_sim/mod.rs new file mode 100644 index 0000000..a1db2a1 --- /dev/null +++ b/src/sim/cell_sim/mod.rs @@ -0,0 +1,4 @@ +pub mod chunk; +pub mod overlay; +pub mod sim; +pub mod world; diff --git a/src/sim/overlay.rs b/src/sim/cell_sim/overlay.rs index c9fdf17..ee494ae 100644 --- a/src/sim/overlay.rs +++ b/src/sim/cell_sim/overlay.rs @@ -1,4 +1,4 @@ -use crate::{Config, Input, sim::world::World}; +use crate::{Config, Input, sim::cell_sim::world::World}; pub fn create_compute_combined_overlay_offset( world: &World, diff --git a/src/sim/sim.rs b/src/sim/cell_sim/sim.rs index b9f4b76..fd9b6c9 100644 --- a/src/sim/sim.rs +++ b/src/sim/cell_sim/sim.rs @@ -6,7 +6,10 @@ use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use crate::{ config::CHUNK_SIZE, - sim::{cell::Cell, chunk::Chunk, materials::MaterialDef, world::World}, + sim::{ + cell::{cell::Cell, materials::MaterialDef}, + cell_sim::{chunk::Chunk, world::World}, + }, }; struct ChunkAccess<'a> { diff --git a/src/sim/world.rs b/src/sim/cell_sim/world.rs index d54906c..924639a 100644 --- a/src/sim/world.rs +++ b/src/sim/cell_sim/world.rs @@ -2,7 +2,7 @@ use fxhash::FxHashMap; use crate::{ config::CHUNK_SIZE, - sim::{cell::Cell, chunk::Chunk}, + sim::{cell::cell::Cell, cell_sim::chunk::Chunk}, }; pub struct World { diff --git a/src/sim/mod.rs b/src/sim/mod.rs index 7553f89..63a9c56 100644 --- a/src/sim/mod.rs +++ b/src/sim/mod.rs @@ -1,6 +1,3 @@ pub mod cell; -pub mod chunk; -pub mod materials; -pub mod overlay; -pub mod sim; -pub mod world; +pub mod cell_sim; +pub mod rb_sim; diff --git a/src/sim/rb_sim/mod.rs b/src/sim/rb_sim/mod.rs new file mode 100644 index 0000000..1818052 --- /dev/null +++ b/src/sim/rb_sim/mod.rs @@ -0,0 +1,131 @@ +pub mod rb_entity; + +use fxhash::FxHashMap; +use rapier2d::{ + dynamics::{self}, + geometry, + glamx::vec2, + math, prelude, +}; + +use crate::{ + config::{CELLS_IN_CHUNK, PHYSICS_DELTA_TIME}, + sim::{ + cell::{cell::Cell, materials::MaterialId}, + rb_sim::rb_entity::RbEntity, + }, +}; + +pub struct PhysicsManager { + rigid_body_set: prelude::RigidBodySet, + collider_set: prelude::ColliderSet, + physics_pipeline: prelude::PhysicsPipeline, + integration_parameters: prelude::IntegrationParameters, + island_manager: prelude::IslandManager, + broad_phase: prelude::DefaultBroadPhase, + narrow_phase: prelude::NarrowPhase, + impulse_joint_set: prelude::ImpulseJointSet, + multibody_joint_set: prelude::MultibodyJointSet, + ccd_solver: prelude::CCDSolver, +} + +impl PhysicsManager { + pub fn new() -> Self { + PhysicsManager { + rigid_body_set: prelude::RigidBodySet::new(), + collider_set: prelude::ColliderSet::new(), + physics_pipeline: prelude::PhysicsPipeline::new(), + integration_parameters: prelude::IntegrationParameters { + // 20 pixels = 1 meter + length_unit: 20.0, + dt: PHYSICS_DELTA_TIME, + ..prelude::IntegrationParameters::default() + }, + island_manager: prelude::IslandManager::new(), + broad_phase: prelude::DefaultBroadPhase::new(), + narrow_phase: prelude::NarrowPhase::new(), + impulse_joint_set: prelude::ImpulseJointSet::new(), + multibody_joint_set: prelude::MultibodyJointSet::new(), + ccd_solver: prelude::CCDSolver::new(), + } + } +} + +pub struct RbSimManager { + physics_manager: PhysicsManager, + pub rb_entities: FxHashMap<u32, RbEntity>, +} + +impl RbSimManager { + pub fn rb_tick(&mut self, delta_time: f32) { + let gravity = vec2(0.0, -9.81); + + self.physics_manager.physics_pipeline.step( + gravity, + &self.physics_manager.integration_parameters, + &mut self.physics_manager.island_manager, + &mut self.physics_manager.broad_phase, + &mut self.physics_manager.narrow_phase, + &mut self.physics_manager.rigid_body_set, + &mut self.physics_manager.collider_set, + &mut self.physics_manager.impulse_joint_set, + &mut self.physics_manager.multibody_joint_set, + &mut self.physics_manager.ccd_solver, + &(), + &(), + ); + } + + pub fn get_rb_entity_position(&self, entity_id: u32) -> Option<(f32, f32)> { + let entity = self.rb_entities.get(&entity_id); + match entity { + Some(entity) => { + let rb = self.physics_manager.rigid_body_set.get(entity.rb_parent); + rb.map(|rb| (rb.position().translation.x, rb.position().translation.y)) + } + None => return None, + } + } + + pub fn test(&mut self) { + /* Create the ground. */ + let collider = geometry::ColliderBuilder::cuboid(100.0, 0.1).build(); + self.physics_manager.collider_set.insert(collider); + + /* Create the bouncing ball. */ + let rigid_body = dynamics::RigidBodyBuilder::dynamic() + .translation(math::Vector::new(0.0, 10.0)) + .build(); + let collider = geometry::ColliderBuilder::ball(0.5) + .restitution(0.7) + .build(); + let ball_body_handle = self.physics_manager.rigid_body_set.insert(rigid_body); + self.physics_manager.collider_set.insert_with_parent( + collider, + ball_body_handle, + &mut self.physics_manager.rigid_body_set, + ); + + let test_cells = Box::new([Cell::void(); CELLS_IN_CHUNK]); + let mut rb_entity = RbEntity { + id: 0, + cells: test_cells, + rb_parent: ball_body_handle, + }; + + for x in 0..10 { + for y in 0..10 { + rb_entity.set_cell_at_local_position(x, y, Cell::from_material(MaterialId::Wood)); + } + } + + self.rb_entities.insert(0, rb_entity); + } + + pub fn new() -> Self { + RbSimManager { + physics_manager: PhysicsManager::new(), + rb_entities: FxHashMap::default(), + } + } +} diff --git a/src/sim/rb_sim/rb_entity.rs b/src/sim/rb_sim/rb_entity.rs new file mode 100644 index 0000000..50243bc --- /dev/null +++ b/src/sim/rb_sim/rb_entity.rs @@ -0,0 +1,24 @@ +use rapier2d::prelude; + +use crate::{ + config::{CELLS_IN_CHUNK, CHUNK_SIZE}, + sim::cell::cell::Cell, +}; + +pub struct RbEntity { + pub id: u32, + // TODO resizable + pub cells: Box<[Cell; CELLS_IN_CHUNK]>, + pub rb_parent: prelude::RigidBodyHandle, +} + +impl RbEntity { + #[inline] + pub fn get_cell_at_local_position(&self, x: u8, y: u8) -> Cell { + self.cells[x as usize + y as usize * CHUNK_SIZE as usize] + } + #[inline] + pub fn set_cell_at_local_position(&mut self, x: u8, y: u8, cell: Cell) { + self.cells[x as usize + y as usize * CHUNK_SIZE as usize] = cell; + } +} |
