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
use building_blocks_core::prelude::*;
use building_blocks_storage::{prelude::*, Local};

use dot_vox::*;

#[derive(Copy, Clone, Eq, PartialEq)]
pub enum VoxColor {
    Color(u8),
    Empty,
}

// TODO: should take a type parameter that implements a trait to access `VoxColor`
pub fn encode_vox(map: &Array3<VoxColor>) -> DotVoxData {
    let global_extent = *map.extent();
    let local_extent = global_extent - global_extent.minimum;
    let shape = local_extent.shape;

    // VOX coordinates are limited to u8.
    assert!(shape <= PointN([std::u8::MAX as i32; 3]));

    let size = dot_vox::Size {
        x: shape.x() as u32,
        y: shape.y() as u32,
        z: shape.z() as u32,
    };

    let mut voxels = Vec::new();
    for p in local_extent.iter_points() {
        if let VoxColor::Color(i) = map.get(&Local(p)) {
            voxels.push(dot_vox::Voxel {
                x: p.x() as u8,
                y: p.y() as u8,
                z: p.z() as u8,
                i,
            });
        }
    }

    let model = dot_vox::Model { size, voxels };

    DotVoxData {
        version: 150,
        models: vec![model],
        palette: Vec::new(),
        materials: Vec::new(),
    }
}

pub fn decode_vox(vox_data: &DotVoxData, model_index: usize) -> Array3<VoxColor> {
    let Model {
        size: Size { x, y, z },
        voxels,
    } = &vox_data.models[model_index];
    let shape = PointN([*x as i32, *y as i32, *z as i32]);
    let extent = Extent3i::from_min_and_shape(PointN([0, 0, 0]), shape);
    let mut map = Array3::fill(extent, VoxColor::Empty);
    for Voxel { x, y, z, i } in voxels.iter() {
        let point = PointN([*x as i32, *y as i32, *z as i32]);
        *map.get_mut(&point) = VoxColor::Color(*i);
    }

    map
}