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 | |
| parent | 40e9d818195824749293dff3afcfdd5c1432adbe (diff) | |
wip
| -rw-r--r-- | .cargo/config.toml | 1 | ||||
| -rw-r--r-- | Cargo.lock | 281 | ||||
| -rw-r--r-- | Cargo.toml | 7 | ||||
| -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 |
23 files changed, 681 insertions, 90 deletions
diff --git a/.cargo/config.toml b/.cargo/config.toml index 6687bf8..9e23ee1 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,3 +1,4 @@ [alias] +profile-dev = "run --features profiler" profile = "run --release --features profiler" release = "run --release" @@ -152,6 +152,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] name = "arboard" version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -635,6 +644,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] +name = "downcast-rs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc" + +[[package]] name = "dpi" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -724,6 +739,15 @@ dependencies = [ ] [[package]] +name = "ena" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabffdaee24bd1bf95c5ef7cec31260444317e72ea56c4c91750e8b7ee58d5f1" +dependencies = [ + "log", +] + +[[package]] name = "env_filter" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1045,6 +1069,47 @@ dependencies = [ ] [[package]] +name = "glam" +version = "0.30.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9" + +[[package]] +name = "glam" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556f6b2ea90b8d15a74e0e7bb41671c9bdf38cd9f78c284d750b9ce58a2b5be7" + +[[package]] +name = "glam" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f70749695b063ecbf6b62949ccccde2e733ec3ecbbd71d467dca4e5c6c97cca0" + +[[package]] +name = "glam" +version = "0.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360bd2cd76e0cd9032d42cf2922155cecea2685b0cfa4630c3246df030bcfd6" +dependencies = [ + "approx", + "libm", +] + +[[package]] +name = "glamx" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9847f980afb0628849bcd6a406cdffd29eb9d53fca83e1646005901a9acd4c5c" +dependencies = [ + "approx", + "glam 0.33.3", + "nalgebra", + "num-traits", + "simba", +] + +[[package]] name = "glifo" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1561,6 +1626,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef0d4ed8669f8f8826eb00dc878084aa8f253506c4fd5e8f58f5bce72ddb97e" [[package]] +name = "matrixmultiply" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f607c237553f086e7043417a51df26b2eb899d3caff94e6a67592ff992fedc7" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] name = "memchr" version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1622,6 +1697,37 @@ dependencies = [ ] [[package]] +name = "nalgebra" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc43a60c217b0c6ff46e47f26911015ad8d2e5a8be1af668c67e370d99a4346" +dependencies = [ + "approx", + "glam 0.30.10", + "glam 0.31.1", + "glam 0.32.1", + "glam 0.33.3", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "973e7178a678cfd059ccec50887658d482ce16b0aa9da3888ddeab5cd5eb4889" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] name = "ndk" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1658,6 +1764,56 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "num-integer" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2060,6 +2216,32 @@ dependencies = [ ] [[package]] +name = "parry2d" +version = "0.30.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7637d1087885e0bd9421938e79b66b4eb2e08afcb0c717a312ed917daefa528" +dependencies = [ + "approx", + "arrayvec", + "bitflags 2.13.1", + "downcast-rs 2.0.2", + "either", + "ena", + "foldhash 0.2.0", + "glamx", + "hashbrown 0.17.1", + "log", + "num-derive", + "num-traits", + "ordered-float", + "simba", + "slab", + "smallvec", + "spade", + "thiserror 2.0.19", +] + +[[package]] name = "peniko" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2205,6 +2387,19 @@ name = "profiling" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb" +dependencies = [ + "quote", + "syn 2.0.119", +] [[package]] name = "puffin" @@ -2255,6 +2450,7 @@ dependencies = [ "puffin", "puffin_http", "rand", + "rapier2d", "rayon", "wgpu", "wgpu-types", @@ -2321,6 +2517,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca45419789ae5a7899559e9512e58ca889e41f04f1f2445e9f4b290ceccd1d08" [[package]] +name = "rapier2d" +version = "0.35.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cd075f0af5e23449709ef3d2533f0166ad6edff7c1ab89978c4f409a778d3f5" +dependencies = [ + "approx", + "arrayvec", + "bitflags 2.13.1", + "glamx", + "log", + "nalgebra", + "num-traits", + "parry2d", + "profiling", + "serde", + "simba", + "static_assertions", + "thiserror 2.0.19", + "wide", +] + +[[package]] name = "raw-window-handle" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2339,6 +2557,12 @@ dependencies = [ ] [[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] name = "rayon" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2431,6 +2655,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" [[package]] +name = "robust" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e27ee8bb91ca0adcf0ecb116293afa12d393f9c2b9b9cd54d33e8078fe19839" + +[[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2484,6 +2714,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] +name = "safe_arch" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42c6efa15875e6ecb39ca61fb0b0c1a40b84fac5a5ffe71eef7d1000c8eb3f5f" +dependencies = [ + "bytemuck", +] + +[[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2566,6 +2805,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] +name = "simba" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a7200d82ff1c7b4235efd12f11e2537a402c91cf83a5cb97ce80eef787fde7" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "wide", +] + +[[package]] name = "simd-adler32" version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2691,6 +2942,18 @@ dependencies = [ ] [[package]] +name = "spade" +version = "2.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9699399fd9349b00b184f5635b074f9ec93afffef30c853f8c875b32c0f8c7fa" +dependencies = [ + "hashbrown 0.16.1", + "num-traits", + "robust", + "smallvec", +] + +[[package]] name = "spirv" version = "0.4.0+sdk-1.4.341.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2911,6 +3174,12 @@ dependencies = [ ] [[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] name = "unicode-general-category" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3079,7 +3348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "016ccf01d1c58b6f8999612813e17c9b2390f7d70671428869913310f83f54b8" dependencies = [ "cc", - "downcast-rs", + "downcast-rs 1.2.1", "rustix 1.1.4", "scoped-tls", "smallvec", @@ -3428,6 +3697,16 @@ dependencies = [ ] [[package]] +name = "wide" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de2aaf408e58689c2096682331b1f42bb2d9f2ed6b11560407d023cd0a6c634e" +dependencies = [ + "bytemuck", + "safe_arch", +] + +[[package]] name = "winapi-util" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -18,6 +18,13 @@ rayon = "1.12.0" futures = "0.3.34" bytemuck = "1.25.2" fxhash = "0.2.1" +rapier2d = "0.35.2" [features] profiler = [] + +[profile.release] +# lto = true + +[profile.dev.package.rapier2d] +opt-level = 3 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; + } +} |
