Files
fastvoxel/src/chunk/column.rs
2026-03-12 19:25:03 +03:30

90 lines
2.9 KiB
Rust

use godot::classes::class_macros::private::virtuals::Os::Vector3i;
use super::chunk::{CHUNK_SIZE, Chunk};
pub const CHUNKS_PER_COLUMN: usize = 8;
pub struct ChunkColumn {
// from bottom to top
// TODO: replace with vec![]
pub chunks: [Option<Chunk>; CHUNKS_PER_COLUMN],
pub world_position: (i32, i32), // XZ
pub chunk_size: Vector3i,
}
impl ChunkColumn {
pub fn new(x: i32, z: i32, chunk_size: Vector3i) -> Self {
ChunkColumn {
chunks: [None, None, None, None, None, None, None, None],
world_position: (x, z),
chunk_size,
}
}
#[inline]
pub fn get_chunk_index(chunk_size_y: i32, world_y: i32) -> usize {
(world_y / chunk_size_y) as usize
}
#[inline]
pub fn get_local_y(chunk_size_y: i32, world_y: i32) -> i32 {
world_y % chunk_size_y
}
#[inline]
pub fn get_world_y(chunk_size_y: i32, chunk_index: i32, local_y: i32) -> i32 {
(chunk_index * chunk_size_y) + local_y
}
pub fn get_or_create_chunk(&mut self, chunk_y_index: i32) -> &mut Chunk {
if self.chunks[chunk_y_index as usize].is_none() {
let (world_x, world_z) = self.world_position;
self.chunks[chunk_y_index as usize] = Some(Chunk::new(
world_x as f64,
chunk_y_index as f64,
world_z as f64,
self.chunk_size,
));
}
self.chunks[chunk_y_index as usize].as_mut().unwrap()
}
pub fn get_chunk(&self, chunk_y_index: usize) -> Option<&Chunk> {
self.chunks[chunk_y_index].as_ref()
}
pub fn get_chunk_mut(&mut self, chunk_y_index: usize) -> Option<&mut Chunk> {
self.chunks[chunk_y_index].as_mut()
}
pub fn set_voxel(&mut self, world_pos: Vector3i, is_solid: bool) -> bool {
let chunk_index = Self::get_chunk_index(self.chunk_size.y, world_pos.y);
if chunk_index < CHUNKS_PER_COLUMN {
let size = self.chunk_size.clone();
let chunk = self.get_or_create_chunk(chunk_index as i32);
let local_x = world_pos.x.rem_euclid(size.x);
let local_y = Self::get_local_y(size.y, world_pos.y);
let local_z = world_pos.z.rem_euclid(size.z);
chunk.set_voxel(Vector3i::new(local_x, local_y, local_z), is_solid, size);
true
} else {
false
}
}
pub fn get_voxel(&self, world_pos: Vector3i) -> bool {
let chunk_index = Self::get_chunk_index(self.chunk_size.y, world_pos.y);
if let Some(chunk) = self.get_chunk(chunk_index) {
let local_x = world_pos.x.rem_euclid(CHUNK_SIZE);
let local_y = Self::get_local_y(self.chunk_size.y, world_pos.y);
let local_z = world_pos.z.rem_euclid(CHUNK_SIZE);
chunk.get_voxel(Vector3i::new(local_x, local_y, local_z), self.chunk_size)
} else {
false // Air by default
}
}
}