1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
use nom::{
multi::count,
number::complete::{le_u32, le_u8},
sequence::tuple,
IResult,
};
use crate::parser::validate_count;
/// A renderable voxel model.
#[derive(Debug, PartialEq, Eq)]
pub struct Model {
/// The size of the model in voxels.
pub size: Size,
/// The voxels to be displayed.
pub voxels: Vec<Voxel>,
}
impl Model {
/// Number of bytes when encoded in `.vox` format.
pub fn num_vox_bytes(&self) -> u32 {
// The number 40 comes from:
// - 24 bytes for the chunk header format (SIZE/XYZI labels, chunk and child sizes, etc.)
// - 12 bytes for the SIZE contents (x, y, z)
// - 4 bytes for the voxel length u32
40 + 4 * self.voxels.len() as u32
}
}
/// The dimensions of a model in voxels.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Size {
/// The width of the model in voxels.
pub x: u32,
/// The height of the model in voxels.
pub y: u32,
/// The depth of the model in voxels.
pub z: u32,
}
/// A voxel.
///
/// A point in 3D space, with an indexed color attached.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Voxel {
/// The X coordinate for the voxel.
pub x: u8,
/// The Y coordinate for the voxel.
pub y: u8,
/// The Z coordinate for the voxel.
pub z: u8,
/// Index in the color palette. Note that this will be oen less than the
/// value stored in the source file, as the palette indices run from
/// 1--255, whereas in memory the indices run from 0--254. Therefore, to
/// make life easier, we store the in-memory index here. Should you
/// require the source file's indices, simply add 1 to this value.
pub i: u8,
}
pub fn parse_size(i: &[u8]) -> IResult<&[u8], Size> {
let (i, (x, y, z)) = tuple((le_u32, le_u32, le_u32))(i)?;
Ok((i, Size { x, y, z }))
}
fn parse_voxel(input: &[u8]) -> IResult<&[u8], Voxel> {
let (input, (x, y, z, i)) = tuple((le_u8, le_u8, le_u8, le_u8))(input)?;
Ok((
input,
Voxel {
x,
y,
z,
i: i.saturating_sub(1),
},
))
}
pub fn parse_voxels(i: &[u8]) -> IResult<&[u8], Vec<Voxel>> {
let (i, n) = le_u32(i)?;
let n = validate_count(i, n, 4)?;
count(parse_voxel, n)(i)
}