const NUM_CELLS_PER_CHUNK_SIDE: usize = 8;
const NUM_CHUNKS_PER_WORLD_SIDE: usize = 128;
#[inline(always)]
fn translate_coordinates(x: usize, y: usize) -> (usize, usize, usize, usize) {
let y_chunk = y / NUM_CELLS_PER_CHUNK_SIDE;
let y_cell = y % NUM_CELLS_PER_CHUNK_SIDE;
let x_chunk = x / NUM_CELLS_PER_CHUNK_SIDE;
let x_cell = x % NUM_CELLS_PER_CHUNK_SIDE;
(y_chunk, y_cell, x_chunk, x_cell)
}
pub struct WorldComponentBitSlice(
[[[u8; NUM_CELLS_PER_CHUNK_SIDE]; NUM_CHUNKS_PER_WORLD_SIDE]; NUM_CHUNKS_PER_WORLD_SIDE],
);
impl WorldComponentBitSlice {
#[inline(always)]
pub fn get(&self, x: usize, y: usize) -> bool {
let (y_chunk, y_cell, x_chunk, x_cell) = translate_coordinates(x, y);
let chunk = self.0[y_chunk][x_chunk];
let row = chunk[y_cell];
let i = x_cell;
let val = (row & (0b10000000 >> i)) != 0;
val
}
pub fn put(&mut self, val: bool, x: usize, y: usize) {
let (y_chunk, y_cell, x_chunk, x_cell) = translate_coordinates(x, y);
let row = self.0[y_chunk][x_chunk][y_cell];
let inversion_mask = 0b11111111 ^ (0b10000000 >> x_cell);
let row_with_zeroed_x_cell = row & inversion_mask;
let modifier = (val as u8) >> x_cell;
let new_row = row_with_zeroed_x_cell | modifier;
self.0[y_chunk][x_chunk][y_cell] = new_row;
}
pub fn is_byte_set(&self, x: usize, y: usize) -> bool {
let (y_chunk, y_cell, x_chunk, _) = translate_coordinates(x, y);
self.0[y_chunk][x_chunk][y_cell] != 0
}
}
type Chunk<T> = [[T; NUM_CELLS_PER_CHUNK_SIDE]; NUM_CELLS_PER_CHUNK_SIDE];
pub struct WorldComponentSlice<T: Copy> {
values: [[Chunk<T>; NUM_CHUNKS_PER_WORLD_SIDE]; NUM_CHUNKS_PER_WORLD_SIDE],
}
impl<T: Copy> WorldComponentSlice<T> {
pub fn get(&self, x: usize, y: usize) -> T {
let (y_chunk, y_cell, x_chunk, x_cell) = translate_coordinates(x, y);
self.values[y_chunk][x_chunk][y_cell][x_cell]
}
pub fn put(&mut self, val: T, x: usize, y: usize) {
let (y_chunk, y_cell, x_chunk, x_cell) = translate_coordinates(x, y);
self.values[y_chunk][x_chunk][y_cell][x_cell] = val;
}
}
const NUM_CELLS_PER_WORLD_SIDE: usize = NUM_CELLS_PER_CHUNK_SIDE * NUM_CHUNKS_PER_WORLD_SIDE;
const NUM_CELLS_IN_WORLD: usize = NUM_CELLS_PER_WORLD_SIDE * NUM_CELLS_PER_WORLD_SIDE;
pub struct ComponentIterator {
index: usize,
}
impl ComponentIterator {
pub fn skip_8(&mut self) {
self.index += 8;
}
}
impl Iterator for ComponentIterator {
type Item = (usize, usize);
fn next(&mut self) -> Option<Self::Item> {
if self.index >= NUM_CELLS_IN_WORLD {
None
} else {
let x = self.index % NUM_CELLS_PER_WORLD_SIDE;
let y = self.index / NUM_CELLS_PER_WORLD_SIDE;
self.index += 1;
Some((x, y))
}
}
}
#[macro_export]
macro_rules! define_world {
($($x:ident: $y:ident,)*) => {
pub struct World {
$($x: wrap_type!($y),)*
}
impl World {
pub fn new() -> Box<World> {
unsafe {
let layout = std::alloc::Layout::new::<World>();
let ptr = std::alloc::alloc_zeroed(layout) as *mut World;
Box::from_raw(ptr)
}
}
}
};
($($x:ident: $y:tt,)*) => {
pub struct World {
$($x: wrap_type!($y),)*
}
impl World {
pub fn new() -> Box<World> {
unsafe {
let layout = std::alloc::Layout::new::<World>();
let ptr = std::alloc::alloc_zeroed(layout) as *mut World;
Box::from_raw(ptr)
}
}
}
}
}
#[macro_export]
macro_rules! wrap_type {
(bool) => {
WorldComponentBitSlice
};
($t:ident) => {WorldComponentSlice<$t>};
($t:tt) => {WorldComponentSlice<$t>};
}