Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions crates/urath-core/src/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,30 @@ impl Chunk {
count
}

/// Fill a column at (x, z) from y=0 to y=height-1 with a block ID.
///
/// More efficient than calling `set()` in a loop because it computes
/// the base index once and increments by stride, and batches the
/// `non_air_count` update.
pub fn fill_column(&mut self, x: usize, z: usize, height: usize, block_id: u16) {
if x >= self.size || z >= self.size {
return;
}
let max = height.min(self.size);
let base = x + z * self.size * self.size;
let stride = self.size; // y stride in the x + y*size + z*size*size layout
for y in 0..max {
let idx = base + y * stride;
let old = self.blocks[idx];
if old == 0 && block_id != 0 {
self.non_air_count += 1;
} else if old != 0 && block_id == 0 {
self.non_air_count -= 1;
}
self.blocks[idx] = block_id;
}
}

/// Check if (x, y, z) is air (block ID 0).
#[inline]
pub fn is_air(&self, x: usize, y: usize, z: usize) -> bool {
Expand All @@ -208,6 +232,12 @@ impl Chunk {
self.non_air_count == 0
}

/// Number of non-air blocks in the chunk. O(1).
#[inline]
pub fn non_air_blocks(&self) -> u32 {
self.non_air_count
}

/// True if every block is non-air. O(1).
#[inline]
pub fn is_solid(&self) -> bool {
Expand Down Expand Up @@ -465,4 +495,28 @@ mod tests {
let data = vec![0u16; 10]; // wrong size
assert!(chunk.replace_blocks(&data).is_err());
}

#[test]
fn fill_column_basic() {
let mut chunk = Chunk::new(4).unwrap();
chunk.fill_column(1, 2, 3, 5);
assert_eq!(chunk.get(1, 0, 2), 5);
assert_eq!(chunk.get(1, 1, 2), 5);
assert_eq!(chunk.get(1, 2, 2), 5);
assert_eq!(chunk.get(1, 3, 2), 0); // height=3, so y=3 is air
assert!(!chunk.is_empty());
}

#[test]
fn fill_column_overwrite() {
let mut chunk = Chunk::new(4).unwrap();
chunk.fill_column(0, 0, 4, 1);
assert_eq!(chunk.non_air_blocks(), 4);
chunk.fill_column(0, 0, 2, 0); // clear first 2
assert_eq!(chunk.non_air_blocks(), 2);
assert_eq!(chunk.get(0, 0, 0), 0);
assert_eq!(chunk.get(0, 1, 0), 0);
assert_eq!(chunk.get(0, 2, 0), 1);
assert_eq!(chunk.get(0, 3, 0), 1);
}
}
29 changes: 7 additions & 22 deletions crates/urath-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,7 @@ impl WasmChunk {

/// Fill a column from y=0 to y=height-1 with a block ID.
pub fn fill_column(&mut self, x: usize, z: usize, height: usize, block_id: u16) {
let max = height.min(self.inner.size());
for y in 0..max {
self.inner.set(x, y, z, block_id);
}
self.inner.fill_column(x, z, height, block_id);
}

/// Copy all block data into a new Uint16Array.
Expand Down Expand Up @@ -216,15 +213,9 @@ impl WasmMeshResult {
js_sys::Float32Array::from(self.opaque.ao())
}

/// Opaque block IDs (Float32Array, cast from u16).
pub fn block_ids(&self) -> js_sys::Float32Array {
let f32_vec: Vec<f32> = self
.opaque
.block_ids()
.iter()
.map(|&id| id as f32)
.collect();
js_sys::Float32Array::from(&f32_vec[..])
/// Opaque block IDs (Uint16Array).
pub fn block_ids(&self) -> js_sys::Uint16Array {
js_sys::Uint16Array::from(self.opaque.block_ids())
}

/// Opaque UV coordinates (Float32Array, 2 floats per vertex).
Expand Down Expand Up @@ -269,15 +260,9 @@ impl WasmMeshResult {
js_sys::Float32Array::from(self.transparent.ao())
}

/// Transparent block IDs (Float32Array, cast from u16).
pub fn transparent_block_ids(&self) -> js_sys::Float32Array {
let f32_vec: Vec<f32> = self
.transparent
.block_ids()
.iter()
.map(|&id| id as f32)
.collect();
js_sys::Float32Array::from(&f32_vec[..])
/// Transparent block IDs (Uint16Array).
pub fn transparent_block_ids(&self) -> js_sys::Uint16Array {
js_sys::Uint16Array::from(self.transparent.block_ids())
}

/// Transparent UV coordinates (Float32Array, 2 floats per vertex).
Expand Down
Loading