Initial commit: AtomicEngine v0.2

- Rust/WASM physics engine (grid, material, physics, render_buffer)
- 16 material types (stone, sand, water, wood, fire, lava, glass, ice, oil, acid, steam, spark, smoke + player placeholder)
- Fire system (fuel-based, flammability-scaled consumption, spread, smoke/sparks)
- Lighting system (emission, flood-fill propagation, glow, reflection)
- Per-material pixel texturing (wood grain, dirt specks, stone noise, flame variation)
- WebGL2 renderer with camera (WASD move, mouse wheel zoom)
- Native x86 debug binary (identical dimensions, FPS counter)
- Large world 1024x768 with active-region simulation (camera + 200px margin)
- UI material palette + FPS display
This commit is contained in:
2026-07-09 11:13:39 +02:00
commit 1bce9da0c6
21 changed files with 3261 additions and 0 deletions
+112
View File
@@ -0,0 +1,112 @@
pub struct Grid {
pub materials: Vec<u8>,
pub healths: Vec<u8>,
pub temps: Vec<u8>,
pub flags: Vec<u8>,
pub width: u32,
pub height: u32,
}
pub const FLAG_UPDATED: u8 = 0b0000_0001;
pub const FLAG_PLAYER: u8 = 0b0000_0010;
impl Grid {
pub fn new(width: u32, height: u32) -> Self {
let size = (width * height) as usize;
Self {
materials: vec![0; size],
healths: vec![255; size],
temps: vec![0; size],
flags: vec![0; size],
width,
height,
}
}
#[inline]
pub fn index(&self, x: u32, y: u32) -> usize {
(y * self.width + x) as usize
}
pub fn in_bounds(&self, x: i32, y: i32) -> bool {
x >= 0 && x < self.width as i32 && y >= 0 && y < self.height as i32
}
#[inline]
pub fn get(&self, x: u32, y: u32) -> u8 {
self.materials[self.index(x, y)]
}
#[inline]
pub fn get_signed(&self, x: i32, y: i32) -> u8 {
if self.in_bounds(x, y) {
self.materials[self.index(x as u32, y as u32)]
} else {
0
}
}
#[inline]
pub fn set(&mut self, x: u32, y: u32, material: u8) {
let idx = self.index(x, y);
self.materials[idx] = material;
self.flags[idx] |= FLAG_UPDATED;
if material == 6 {
self.temps[idx] = 200;
self.healths[idx] = 255;
} else if material == 9 {
self.temps[idx] = 200;
self.healths[idx] = 200;
} else if material == 11 {
self.temps[idx] = 0;
}
}
#[inline]
pub fn swap(&mut self, x1: u32, y1: u32, x2: u32, y2: u32) {
let i1 = self.index(x1, y1);
let i2 = self.index(x2, y2);
self.materials.swap(i1, i2);
self.healths.swap(i1, i2);
self.temps.swap(i1, i2);
self.flags[i1] |= FLAG_UPDATED;
self.flags[i2] |= FLAG_UPDATED;
}
pub fn is_empty(&self, x: u32, y: u32) -> bool {
self.get(x, y) == 0
}
pub fn clear_flags(&mut self) {
for f in &mut self.flags {
*f &= !FLAG_UPDATED;
}
}
pub fn fill_rect(&mut self, x: u32, y: u32, w: u32, h: u32, material: u8) {
for dy in 0..h {
for dx in 0..w {
let px = x + dx;
let py = y + dy;
if px < self.width && py < self.height {
self.set(px, py, material);
}
}
}
}
pub fn fill_circle(&mut self, cx: u32, cy: u32, radius: u32, material: u8) {
let r = radius as i32;
for dy in -r..=r {
for dx in -r..=r {
if dx * dx + dy * dy <= r * r {
let px = (cx as i32 + dx) as u32;
let py = (cy as i32 + dy) as u32;
if px < self.width && py < self.height {
self.set(px, py, material);
}
}
}
}
}
}