summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Stevenson <kai@kaistevenson.com>2026-08-16 17:29:42 -0700
committerKai Stevenson <kai@kaistevenson.com>2026-08-16 17:29:42 -0700
commitf177cc716c5f2aa5b50b14ccbb421de89e3a7854 (patch)
treedb06f9f44251d6d90e5e9709d47e6cc4397b9443
parent40e9d818195824749293dff3afcfdd5c1432adbe (diff)
wip
-rw-r--r--.cargo/config.toml1
-rw-r--r--Cargo.lock281
-rw-r--r--Cargo.toml7
-rw-r--r--src/config.rs2
-rw-r--r--src/main.rs32
-rw-r--r--src/renderer/mod.rs250
-rw-r--r--src/renderer/ui.rs2
-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.rs2
-rw-r--r--src/sim/cell_sim/chunk.rs (renamed from src/sim/chunk.rs)2
-rw-r--r--src/sim/cell_sim/mod.rs4
-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.rs7
-rw-r--r--src/sim/rb_sim/mod.rs131
-rw-r--r--src/sim/rb_sim/rb_entity.rs24
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"
diff --git a/Cargo.lock b/Cargo.lock
index 70f52c8..07e4b66 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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"
diff --git a/Cargo.toml b/Cargo.toml
index bd11afe..632876f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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;
+ }
+}