use super::{ElementType, TessStatus, Tessellator, TESS_UNDEF};
use crate::mesh::{F_HEAD, INVALID, V_HEAD};
#[inline]
fn is_boundary_edge(mesh: &crate::mesh::Mesh, e: u32) -> bool {
let rf = mesh.rface(e);
rf == INVALID || !mesh.faces[rf as usize].inside
}
impl Tessellator {
pub(crate) fn output_polymesh(&mut self, element_type: ElementType, poly_size: usize, vertex_size: usize) {
if poly_size > 3 {
if let Some(ref mut mesh) = self.mesh {
if !mesh.merge_convex_faces(poly_size) {
self.status = TessStatus::OutOfMemory;
return;
}
}
}
let mesh = match self.mesh.as_mut() {
Some(m) => m,
None => return,
};
let mut v = mesh.verts[V_HEAD as usize].next;
while v != V_HEAD {
mesh.verts[v as usize].n = TESS_UNDEF;
v = mesh.verts[v as usize].next;
}
let mut max_vert = 0u32;
let mut max_face = 0u32;
let mut f = mesh.faces[F_HEAD as usize].next;
while f != F_HEAD {
mesh.faces[f as usize].n = TESS_UNDEF;
if !mesh.faces[f as usize].inside {
f = mesh.faces[f as usize].next;
continue;
}
let e_start = mesh.faces[f as usize].an_edge;
let mut e = e_start;
loop {
let org = mesh.edges[e as usize].org;
if mesh.verts[org as usize].n == TESS_UNDEF {
mesh.verts[org as usize].n = max_vert;
max_vert += 1;
}
e = mesh.edges[e as usize].lnext;
if e == e_start {
break;
}
}
mesh.faces[f as usize].n = max_face;
max_face += 1;
f = mesh.faces[f as usize].next;
}
self.out_element_count = max_face as usize;
self.out_vertex_count = max_vert as usize;
let stride = if element_type == ElementType::ConnectedPolygons {
poly_size * 2
} else {
poly_size
};
self.out_elements = vec![TESS_UNDEF; max_face as usize * stride];
self.out_vertices = vec![0.0; max_vert as usize * vertex_size];
self.out_vertex_indices = vec![TESS_UNDEF; max_vert as usize];
self.out_edge_flags = vec![0u8; max_face as usize * poly_size];
let mesh = self.mesh.as_ref().unwrap();
let mut v = mesh.verts[V_HEAD as usize].next;
while v != V_HEAD {
let n = mesh.verts[v as usize].n;
if n != TESS_UNDEF {
let base = n as usize * vertex_size;
self.out_vertices[base] = mesh.verts[v as usize].coords[0];
self.out_vertices[base + 1] = mesh.verts[v as usize].coords[1];
if vertex_size > 2 {
self.out_vertices[base + 2] = mesh.verts[v as usize].coords[2];
}
self.out_vertex_indices[n as usize] = mesh.verts[v as usize].idx;
}
v = mesh.verts[v as usize].next;
}
let mut ep = 0;
let mut efp = 0; let mut f = mesh.faces[F_HEAD as usize].next;
while f != F_HEAD {
if !mesh.faces[f as usize].inside {
f = mesh.faces[f as usize].next;
continue;
}
let e_start = mesh.faces[f as usize].an_edge;
let mut e = e_start;
let mut fv = 0;
loop {
let org = mesh.edges[e as usize].org;
self.out_elements[ep] = mesh.verts[org as usize].n;
self.out_edge_flags[efp + fv] = if is_boundary_edge(mesh, e) { 1 } else { 0 };
ep += 1;
fv += 1;
e = mesh.edges[e as usize].lnext;
if e == e_start {
break;
}
}
for _ in fv..poly_size {
self.out_elements[ep] = TESS_UNDEF;
ep += 1;
}
efp += poly_size;
if element_type == ElementType::ConnectedPolygons {
let e_start = mesh.faces[f as usize].an_edge;
let mut e = e_start;
let mut fv2 = 0;
loop {
let rf = mesh.rface(e);
let nf = if rf != INVALID && mesh.faces[rf as usize].inside {
mesh.faces[rf as usize].n
} else {
TESS_UNDEF
};
self.out_elements[ep] = nf;
ep += 1;
fv2 += 1;
e = mesh.edges[e as usize].lnext;
if e == e_start {
break;
}
}
for _ in fv2..poly_size {
self.out_elements[ep] = TESS_UNDEF;
ep += 1;
}
}
f = mesh.faces[f as usize].next;
}
}
pub(crate) fn output_contours(&mut self, vertex_size: usize) {
let mesh = match self.mesh.as_ref() {
Some(m) => m,
None => return,
};
let mut total_verts = 0usize;
let mut total_elems = 0usize;
let mut f = mesh.faces[F_HEAD as usize].next;
while f != F_HEAD {
if mesh.faces[f as usize].inside {
let e_start = mesh.faces[f as usize].an_edge;
let mut e = e_start;
loop {
total_verts += 1;
e = mesh.edges[e as usize].lnext;
if e == e_start {
break;
}
}
total_elems += 1;
}
f = mesh.faces[f as usize].next;
}
self.out_element_count = total_elems;
self.out_vertex_count = total_verts;
self.out_elements = vec![TESS_UNDEF; total_elems * 2];
self.out_vertices = vec![0.0; total_verts * vertex_size];
self.out_vertex_indices = vec![TESS_UNDEF; total_verts];
self.out_edge_flags = Vec::new();
let mesh = self.mesh.as_ref().unwrap();
let mut vp = 0usize;
let mut ep = 0usize;
let mut sv = 0usize;
let mut f = mesh.faces[F_HEAD as usize].next;
while f != F_HEAD {
if !mesh.faces[f as usize].inside {
f = mesh.faces[f as usize].next;
continue;
}
let e_start = mesh.faces[f as usize].an_edge;
let mut e = e_start;
let mut vc = 0usize;
loop {
let org = mesh.edges[e as usize].org;
let base = vp * vertex_size;
self.out_vertices[base] = mesh.verts[org as usize].coords[0];
self.out_vertices[base + 1] = mesh.verts[org as usize].coords[1];
if vertex_size > 2 {
self.out_vertices[base + 2] = mesh.verts[org as usize].coords[2];
}
self.out_vertex_indices[vp] = mesh.verts[org as usize].idx;
vp += 1;
vc += 1;
e = mesh.edges[e as usize].lnext;
if e == e_start {
break;
}
}
self.out_elements[ep] = sv as u32;
self.out_elements[ep + 1] = vc as u32;
ep += 2;
sv += vc;
f = mesh.faces[f as usize].next;
}
}
}