renderer.rs

5.7 kB · rust · 139 lines

1use super::models::Cell3d;2use crate::dim::push_glyph;3use std::collections::HashMap;45/// Renders the cell as one grid of glyph rows per z slice.6pub fn text(cell: &Cell3d, glyphs: Option<&HashMap<u8, char>>) -> Vec<Vec<String>> {7    let shape = &cell.types().shape;8    let mut slices = Vec::with_capacity(shape[2]);9    for z in 0..shape[2] {10        let mut rows = Vec::with_capacity(shape[0]);11        for y in 0..shape[0] {12            let mut row = String::with_capacity(shape[1]);13            for x in 0..shape[1] {14                let v = cell.types().get(&[y, x, z]);15                push_glyph(&mut row, v, glyphs);16            }17            rows.push(row);18        }19        slices.push(rows);20    }21    slices22}2324/// Renders the cell's exposed faces as a Wavefront OBJ string.25pub fn obj(cell: &Cell3d) -> String {26    let grid = cell.types();27    let (dx, dy, dz) = (grid.shape[0], grid.shape[1], grid.shape[2]);28    let mut vertices: Vec<(usize, usize, usize)> = Vec::new();29    let mut vertex_map: HashMap<(usize, usize, usize), usize> = HashMap::new();30    let mut faces: Vec<(usize, usize, usize, usize)> = Vec::new();31    let add = |map: &mut HashMap<(usize, usize, usize), usize>,32               verts: &mut Vec<(usize, usize, usize)>,33               v: (usize, usize, usize)|34     -> usize {35        *map.entry(v).or_insert_with(|| {36            verts.push(v);37            verts.len()38        })39    };40    for i in 0..dx {41        for j in 0..dy {42            for k in 0..dz {43                if grid.get(&[i, j, k]) == 0 {44                    continue;45                }46                let empty = |i: isize, j: isize, k: isize| -> bool {47                    if i < 0 || j < 0 || k < 0 {48                        return true;49                    }50                    let (i, j, k) = (i as usize, j as usize, k as usize);51                    if i >= dx || j >= dy || k >= dz {52                        return true;53                    }54                    grid.get(&[i, j, k]) == 055                };56                let (ii, jj, kk) = (i as isize, j as isize, k as isize);57                if empty(ii - 1, jj, kk) {58                    let v1 = add(&mut vertex_map, &mut vertices, (i, j, k));59                    let v2 = add(&mut vertex_map, &mut vertices, (i, j, k + 1));60                    let v3 = add(&mut vertex_map, &mut vertices, (i, j + 1, k + 1));61                    let v4 = add(&mut vertex_map, &mut vertices, (i, j + 1, k));62                    faces.push((v1, v2, v3, v4));63                }64                if empty(ii + 1, jj, kk) {65                    let v1 = add(&mut vertex_map, &mut vertices, (i + 1, j, k));66                    let v2 = add(&mut vertex_map, &mut vertices, (i + 1, j + 1, k));67                    let v3 = add(&mut vertex_map, &mut vertices, (i + 1, j + 1, k + 1));68                    let v4 = add(&mut vertex_map, &mut vertices, (i + 1, j, k + 1));69                    faces.push((v1, v2, v3, v4));70                }71                if empty(ii, jj - 1, kk) {72                    let v1 = add(&mut vertex_map, &mut vertices, (i, j, k));73                    let v2 = add(&mut vertex_map, &mut vertices, (i + 1, j, k));74                    let v3 = add(&mut vertex_map, &mut vertices, (i + 1, j, k + 1));75                    let v4 = add(&mut vertex_map, &mut vertices, (i, j, k + 1));76                    faces.push((v1, v2, v3, v4));77                }78                if empty(ii, jj + 1, kk) {79                    let v1 = add(&mut vertex_map, &mut vertices, (i, j + 1, k));80                    let v2 = add(&mut vertex_map, &mut vertices, (i, j + 1, k + 1));81                    let v3 = add(&mut vertex_map, &mut vertices, (i + 1, j + 1, k + 1));82                    let v4 = add(&mut vertex_map, &mut vertices, (i + 1, j + 1, k));83                    faces.push((v1, v2, v3, v4));84                }85                if empty(ii, jj, kk - 1) {86                    let v1 = add(&mut vertex_map, &mut vertices, (i, j, k));87                    let v2 = add(&mut vertex_map, &mut vertices, (i, j + 1, k));88                    let v3 = add(&mut vertex_map, &mut vertices, (i + 1, j + 1, k));89                    let v4 = add(&mut vertex_map, &mut vertices, (i + 1, j, k));90                    faces.push((v1, v2, v3, v4));91                }92                if empty(ii, jj, kk + 1) {93                    let v1 = add(&mut vertex_map, &mut vertices, (i, j, k + 1));94                    let v2 = add(&mut vertex_map, &mut vertices, (i + 1, j, k + 1));95                    let v3 = add(&mut vertex_map, &mut vertices, (i + 1, j + 1, k + 1));96                    let v4 = add(&mut vertex_map, &mut vertices, (i, j + 1, k + 1));97                    faces.push((v1, v2, v3, v4));98                }99            }100        }101    }102    let mut out = String::new();103    for (x, y, z) in &vertices {104        out.push_str(&format!("v {x} {z} {}\n", dy - y));105    }106    for (a, b, c, d) in &faces {107        out.push_str(&format!("f {a} {b} {c} {d}\n"));108    }109    out110}111112#[cfg(test)]113mod tests {114    use super::*;115    use crate::three::designs;116    #[test]117    fn single_cube_obj() {118        let c = designs::ones(1, 1).unwrap();119        let o = obj(&c);120        assert_eq!(o.matches("v ").count(), 8);121        assert_eq!(o.matches("f ").count(), 6);122    }123    #[test]124    fn menger_obj_has_interior_faces_culled() {125        let c = designs::carpet(3, 1).unwrap();126        let o = obj(&c);127        let faces = o.matches("f ").count();128        assert!(faces < 20 * 6);129        assert!(faces > 6);130    }131    #[test]132    fn text_slices() {133        let c = designs::ztree(3, 1).unwrap();134        let slices = text(&c, None);135        assert_eq!(slices.len(), 3);136        assert_eq!(slices[0].len(), 3);137        assert_eq!(slices[0][0].len(), 3);138    }139}