vss_rs/
lib.rs

1use crate::bsvo::{read_bsvo, write_bsvo, write_empty_bsvo, BsvoHeader};
2use crate::bvox::{append_to_bvox, read_bvox, write_bvox, write_empty_bvox, BvoxHeader, DEFAULT_CHUNK_RES, DEFAULT_CHUNK_SIZE};
3use crate::svo::{DEFAULT_SVO_MAX_DEPTH, SVO};
4use crate::vox::{morton_decode_3d_grid, morton_encode_3d_grid, pos_to_index, DEFAULT_VOX_MAT};
5use glam::Vec3;
6use rand::distributions::{Bernoulli, Distribution};
7use rand::thread_rng;
8use std::error::Error;
9
10pub mod bsvo;
11pub mod svo;
12pub mod vox;
13pub mod bvox;
14pub mod rle;
15
16//
17// testing modules
18//
19
20const CHUNK_RES: u32 = DEFAULT_CHUNK_RES;
21const CHUNK_SIZE: u32 = DEFAULT_CHUNK_SIZE;
22const SVO_MAX_DEPTH: u8 = DEFAULT_SVO_MAX_DEPTH;
23
24pub fn gen_rand_vox_grid(size: usize, probability_of_one: f64) -> Vec<u8> {
25    let mut rng = thread_rng();
26    let dist = Bernoulli::new(probability_of_one).unwrap();
27    (0..size).map(|_| dist.sample(&mut rng) as u8).collect()
28}
29
30pub fn test_empty_bsvo_and_bvox() -> Result<(), Box<dyn Error>> {
31    let bvox_header = BvoxHeader::default();
32    write_empty_bvox("output/empty.bvox", bvox_header)?;
33
34    let bsvo_header = BsvoHeader::default();
35    write_empty_bsvo("output/empty.bsvo", bsvo_header)?;
36
37    Ok(())
38}
39
40pub fn test_bvox_read_write() -> Result<(), Box<dyn Error>> {
41    let chunk = gen_rand_vox_grid(CHUNK_SIZE as usize, 0.1);
42
43    let mut morton_chunk = vec![0; CHUNK_SIZE as usize];
44    morton_encode_3d_grid(&chunk, CHUNK_RES, CHUNK_SIZE, &mut morton_chunk);
45
46    let chunk_data = vec![morton_chunk.clone()];
47
48    let header = BvoxHeader::new(CHUNK_RES, CHUNK_SIZE, true, true);
49    write_bvox("output/test_bvox_rw.bvox", &chunk_data, header)?;
50
51    let (_, read_chunk_data) = read_bvox("output/test_bvox_rw.bvox")?;
52
53    let mut decoded_morton = vec![0; CHUNK_SIZE as usize];
54    morton_decode_3d_grid(&read_chunk_data[0], CHUNK_RES, CHUNK_SIZE, &mut decoded_morton);
55
56    for i in 0..CHUNK_SIZE {
57        assert_eq!(chunk[i as usize], decoded_morton[i as usize]);
58    }
59
60    Ok(())
61}
62
63pub fn test_bvox_append() -> Result<(), Box<dyn Error>> {
64    let chunk = gen_rand_vox_grid(CHUNK_SIZE as usize, 0.1);
65
66    let mut morton_chunk = vec![0; CHUNK_SIZE as usize];
67    morton_encode_3d_grid(&chunk, CHUNK_RES, CHUNK_SIZE, &mut morton_chunk);
68
69    let header = BvoxHeader::new(CHUNK_RES, CHUNK_SIZE, true, true);
70    write_empty_bvox("output/test_bvox_append.bvox", header)?;
71    append_to_bvox("output/test_bvox_append.bvox", &morton_chunk)?;
72
73    let (_, read_chunk_data) = read_bvox("output/test_bvox_append.bvox")?;
74
75    let mut decoded_morton = vec![0; CHUNK_SIZE as usize];
76    morton_decode_3d_grid(&read_chunk_data[0], CHUNK_RES, CHUNK_SIZE, &mut decoded_morton);
77
78    for i in 0..CHUNK_SIZE {
79        assert_eq!(chunk[i as usize], decoded_morton[i as usize]);
80    }
81
82    Ok (())
83}
84
85pub fn test_bvox_compression() -> Result<(), Box<dyn Error>> {
86    let chunk = gen_rand_vox_grid(CHUNK_SIZE as usize, 0.1);
87    let chunk_data = vec![chunk];
88
89    let header_normal = BvoxHeader::new(CHUNK_RES, CHUNK_SIZE, false, false);
90    write_bvox("output/test_bvox_compression_base.bvox", &chunk_data, header_normal)?;
91
92    let header_rle = BvoxHeader::new(CHUNK_RES, CHUNK_SIZE, true, false);
93    write_bvox("output/test_bvox_compression_rle.bvox", &chunk_data, header_rle)?;
94
95    let (_, read_normal) = read_bvox("output/test_bvox_compression_base.bvox")?;
96    let (_, read_rle) = read_bvox("output/test_bvox_compression_rle.bvox")?;
97
98    for i in 0..CHUNK_SIZE {
99        assert_eq!(read_normal[0][i as usize], read_rle[0][i as usize]);
100    }
101
102    Ok(())
103}
104
105pub fn test_bsvo_read_write() -> Result<(), Box<dyn Error>> {
106    let chunk = gen_rand_vox_grid(CHUNK_SIZE as usize, 0.1);
107
108    let mut morton_chunk = vec![0u8; CHUNK_SIZE as usize];
109    morton_encode_3d_grid(&chunk, CHUNK_RES, CHUNK_SIZE, &mut morton_chunk);
110
111    let chunk_data = vec![morton_chunk.clone()];
112
113    let header = BvoxHeader::new(CHUNK_RES, CHUNK_SIZE, true, true);
114    write_bvox("output/test_bsvo_rw.bvox", &chunk_data, header)?;
115
116    let (_, read_chunk_data) = read_bvox("output/test_bsvo_rw.bvox")?;
117
118    let svo = SVO::from_grid(&read_chunk_data[0], CHUNK_RES, SVO_MAX_DEPTH);
119
120    let bsvo_header = BsvoHeader::new(svo.depth, svo.root_span, true);
121    write_bsvo("output/test_bsvo_rw.bsvo", &svo, bsvo_header)?;
122
123    let (_, read_svo) = read_bsvo("output/test_bsvo_rw.bsvo")?;
124
125    for i in 0..read_svo.nodes.len() {
126        assert_eq!(svo.nodes[i], read_svo.nodes[i]);
127    }
128
129    let svo_node_count = svo.count_leaf_nodes();
130    let chunk_node_count = chunk.iter().filter(|&&v| v > 0).count() as u32;
131    assert_eq!(svo_node_count, chunk_node_count);
132
133    Ok(())
134}
135
136pub fn test_gen_random_svo() -> Result<(), Box<dyn Error>> {
137    let mut svo = SVO::new(SVO_MAX_DEPTH);
138    svo.gen_random_svo(0);
139
140    let bsvo_header = BsvoHeader::new(svo.depth, svo.root_span, false);
141    write_bsvo("output/random_svo.bsvo", &svo, bsvo_header)?;
142
143    let (_, read_svo) = read_bsvo("output/random_svo.bsvo")?;
144
145    for i in 0..svo.nodes.len() {
146        assert_eq!(svo.nodes[i], read_svo.nodes[i]);
147    }
148
149    Ok(())
150}
151
152pub fn cube_grid_and_svo() -> Result<(), Box<dyn Error>> {
153    let mut chunk = vec![0; CHUNK_SIZE as usize];
154    let min = CHUNK_RES / 4;
155    let max = 3 * CHUNK_RES / 4;
156
157    for x in min..max {
158        for y in min..max {
159            for z in min..max {
160                chunk[pos_to_index(x, y, z, CHUNK_RES) as usize] = DEFAULT_VOX_MAT;
161            }
162        }
163    }
164
165    let mut morton_chunk = vec![0u8; CHUNK_SIZE as usize];
166    morton_encode_3d_grid(&chunk, CHUNK_RES, CHUNK_SIZE, &mut morton_chunk);
167
168    let chunk_data = vec![morton_chunk.clone()];
169
170    let header = BvoxHeader::new(CHUNK_RES, CHUNK_SIZE, true, true);
171    write_bvox("output/cube.bvox", &chunk_data, header)?;
172
173    let (_, read_chunk_data) = read_bvox("output/cube.bvox")?;
174
175    let svo = SVO::from_grid(&read_chunk_data[0], CHUNK_RES, SVO_MAX_DEPTH);
176
177    let bsvo_header = BsvoHeader::new(svo.depth, svo.root_span, true);
178    write_bsvo("output/cube.bsvo", &svo, bsvo_header)?;
179
180    Ok (())
181}
182
183pub fn tiny_grid_and_svo() -> Result<(), Box<dyn Error>> {
184    let chunk_res = 8;
185    let chunk_size = chunk_res * chunk_res * chunk_res;
186    let depth = 3;
187
188    let mut chunk = vec![0; chunk_size as usize];
189    let min = 2;
190    let max = 4;
191
192    for x in min..max {
193        for y in min..max {
194            for z in min..max {
195                chunk[pos_to_index(x, y, z, chunk_res) as usize] = DEFAULT_VOX_MAT;
196            }
197        }
198    }
199
200    let mut morton_chunk = vec![0; chunk_size as usize];
201    morton_encode_3d_grid(&chunk, chunk_res, chunk_size, &mut morton_chunk);
202
203    let chunk_data = vec![morton_chunk.clone()];
204
205    let header = BvoxHeader::new(chunk_res, chunk_size, true, true);
206    write_bvox("output/tiny_grid.bvox", &chunk_data, header)?;
207
208    let (_, read_chunk_data) = read_bvox("output/tiny_grid.bvox")?;
209
210    let svo = SVO::from_grid(&read_chunk_data[0], chunk_res, depth);
211
212    let bsvo_header = BsvoHeader::new(svo.depth, svo.root_span, true);
213    write_bsvo("output/tiny_svo.bsvo", &svo, bsvo_header)?;
214
215    Ok(())
216}
217
218pub fn test_svo_simplest() {
219    let mut svo = SVO::new(1);
220    svo.insert_node(Vec3::splat(0.0));
221
222    let bsvo_header = BsvoHeader::new(svo.depth, svo.root_span, false);
223    write_bsvo("output/simplest.bsvo", &svo, bsvo_header).unwrap();
224}
225
226#[cfg(test)]
227mod tests {
228    use super::*;
229
230    #[test]
231    fn gen_empty() {
232        test_empty_bsvo_and_bvox().unwrap();
233    }
234
235    #[test]
236    fn bvox_append() {
237        test_bvox_append().unwrap();
238    }
239
240    #[test]
241    fn random_svo() {
242        test_gen_random_svo().unwrap();
243    }
244
245    #[test]
246    fn bvox_rw() {
247        test_bvox_read_write().unwrap();
248    }
249
250    #[test]
251    fn bvox_compression() {
252        test_bvox_compression().unwrap();
253    }
254
255    #[test]
256    fn bsvo_rw() {
257        test_bsvo_read_write().unwrap();
258    }
259
260    #[test]
261    fn cube() {
262        cube_grid_and_svo().unwrap();
263    }
264
265    #[test]
266    fn tiny_grid_and_svo_for_testing() {
267        tiny_grid_and_svo().unwrap();
268    }
269
270    #[test]
271    fn simplest() {
272        test_svo_simplest();
273    }
274}