#![allow(
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_sign_loss
)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Cube {
Air,
UnexposedSolid,
Color(u32),
}
#[must_use]
pub fn getcube(slab_buf: &[u8], column_offsets: &[u32], vsid: u32, x: i32, y: i32, z: i32) -> Cube {
if x < 0 || y < 0 || (x as u32) >= vsid || (y as u32) >= vsid {
return Cube::Air;
}
let col_idx = (y as u32 * vsid + x as u32) as usize;
let col_start = column_offsets[col_idx] as usize;
let col = &slab_buf[col_start..];
let mut pos: usize = 0;
loop {
let nextptr = i32::from(col[pos]);
let z1 = i32::from(col[pos + 1]);
let z1c = i32::from(col[pos + 2]);
if z <= z1c {
if z < z1 {
return Cube::Air;
}
let off = pos + (z - z1) as usize * 4 + 4;
return Cube::Color(read_color(col, off));
}
let ceilnum = z1c - z1 - nextptr + 2;
if nextptr == 0 {
return Cube::UnexposedSolid;
}
pos += nextptr as usize * 4;
let next_z0 = i32::from(col[pos + 3]);
if z < next_z0 {
let dz = z - next_z0; if dz < ceilnum {
return Cube::UnexposedSolid;
}
let off = (pos as isize + (dz * 4) as isize) as usize;
return Cube::Color(read_color(col, off));
}
}
}
#[inline]
fn read_color(col: &[u8], off: usize) -> u32 {
u32::from_le_bytes([col[off], col[off + 1], col[off + 2], col[off + 3]])
}
#[cfg(test)]
mod tests {
use super::*;
fn single_slab_5_to_14() -> Vec<u8> {
let mut col = vec![0u8, 5, 14, 0];
for z in 5..=14u8 {
col.extend_from_slice(&[z, 0xaa, 0xbb, 0x80]);
}
col
}
fn two_slabs_with_ceiling() -> Vec<u8> {
let mut col = vec![9u8, 10, 14, 0];
for z in 10..=14u8 {
col.extend_from_slice(&[z, 0x10, 0x20, 0x80]);
}
for z in 26..=28u8 {
col.extend_from_slice(&[z, 0x30, 0x40, 0x80]);
}
col.extend_from_slice(&[0u8, 30, 39, 29]);
for z in 30..=39u8 {
col.extend_from_slice(&[z, 0x50, 0x60, 0x80]);
}
col
}
fn world_with(col: Vec<u8>) -> (Vec<u8>, Vec<u32>) {
let len = col.len() as u32;
(col, vec![0, len])
}
#[test]
fn out_of_bounds_xy_returns_air() {
let (buf, off) = world_with(single_slab_5_to_14());
assert_eq!(getcube(&buf, &off, 1, -1, 0, 7), Cube::Air);
assert_eq!(getcube(&buf, &off, 1, 0, -1, 7), Cube::Air);
assert_eq!(getcube(&buf, &off, 1, 1, 0, 7), Cube::Air);
assert_eq!(getcube(&buf, &off, 1, 0, 1, 7), Cube::Air);
}
#[test]
fn above_first_slab_returns_air() {
let (buf, off) = world_with(single_slab_5_to_14());
for z in 0..5 {
assert_eq!(getcube(&buf, &off, 1, 0, 0, z), Cube::Air, "z={z}");
}
}
#[test]
fn floor_color_returned_for_visible_voxels() {
let (buf, off) = world_with(single_slab_5_to_14());
for z in 5..=14 {
let want = u32::from_le_bytes([z as u8, 0xaa, 0xbb, 0x80]);
assert_eq!(getcube(&buf, &off, 1, 0, 0, z), Cube::Color(want), "z={z}");
}
}
#[test]
fn below_last_slab_returns_unexposed_solid() {
let (buf, off) = world_with(single_slab_5_to_14());
for z in 15..40 {
assert_eq!(
getcube(&buf, &off, 1, 0, 0, z),
Cube::UnexposedSolid,
"z={z}"
);
}
}
#[test]
fn second_slab_floor_resolved() {
let (buf, off) = world_with(two_slabs_with_ceiling());
for z in 30..=39 {
let want = u32::from_le_bytes([z as u8, 0x50, 0x60, 0x80]);
assert_eq!(getcube(&buf, &off, 1, 0, 0, z), Cube::Color(want), "z={z}");
}
}
#[test]
fn slab0_ceiling_colors_resolved() {
let (buf, off) = world_with(two_slabs_with_ceiling());
for z in 26..=28 {
let want = u32::from_le_bytes([z as u8, 0x30, 0x40, 0x80]);
assert_eq!(getcube(&buf, &off, 1, 0, 0, z), Cube::Color(want), "z={z}");
}
}
#[test]
fn slab0_hidden_interior_returns_unexposed() {
let (buf, off) = world_with(two_slabs_with_ceiling());
for z in 15..=25 {
assert_eq!(
getcube(&buf, &off, 1, 0, 0, z),
Cube::UnexposedSolid,
"z={z}"
);
}
}
#[test]
fn air_pocket_between_slabs_returns_air() {
let (buf, off) = world_with(two_slabs_with_ceiling());
assert_eq!(getcube(&buf, &off, 1, 0, 0, 29), Cube::Air);
}
#[test]
fn deep_below_last_slab_unexposed() {
let (buf, off) = world_with(two_slabs_with_ceiling());
for z in 40..50 {
assert_eq!(
getcube(&buf, &off, 1, 0, 0, z),
Cube::UnexposedSolid,
"z={z}"
);
}
}
}