diff --git a/src/examples.rs b/src/examples.rs index da97f39..3b754af 100644 --- a/src/examples.rs +++ b/src/examples.rs @@ -303,12 +303,13 @@ impl Twist { pub fn init() -> (Twist, Rule) { let subdiv = 2; + let xf = geometry::Rotation3::from_axis_angle(&Vector3::x_axis(), -0.7).to_homogeneous(); let seed = vec![ vertex(-0.5, 0.0, -0.5), vertex( 0.5, 0.0, -0.5), vertex( 0.5, 0.0, 0.5), vertex(-0.5, 0.0, 0.5), - ]; + ].iter().map(|v| xf * v).collect(); let seed_sub = util::subdivide_cycle(&seed, subdiv); let t = Twist { dx0: 2.0, @@ -342,23 +343,23 @@ impl Twist { Child { rule: Rule { eval: Self::recur }, xf: xf, - vmap: (n*i..n*(i+self.count)).collect(), // N.B. + vmap: ((n+1)*i..(n+1)*(i+self.count)).collect(), // N.B. + // note n+1, not n. the +1 is for the centroid below } }).collect(); // Use byproducts of this to make 'count' copies of 'seed' with // this same transform: - let mut verts = vec![]; - for child in &children { - verts.extend(self.seed_sub.iter().map(|v| child.xf * v)); - } + let meshes = children.iter().map(|child| { + let mut vs = self.seed_sub.iter().map(|v| child.xf * v).collect(); + // and in the process, generate faces for these seeds: + let (centroid, f) = util::connect_convex(&vs, false); + vs.push(centroid); + OpenMesh { verts: vs, faces: f } + }); RuleEval { - geom: OpenMesh { - verts: verts, - faces: vec![], - // TODO: Close these initial faces off - }, + geom: OpenMesh::append(meshes), final_geom: prim::empty_mesh(), children: children, } @@ -373,13 +374,15 @@ impl Twist { let seed_orig = self.seed.iter().map(|v| incr * v).collect(); let seed_sub = util::subdivide_cycle(&seed_orig, self.subdiv); let n = seed_sub.len(); + + let (vc, faces) = util::connect_convex(&seed_sub, true); RuleEval { geom: OpenMesh { verts: seed_sub, faces: util::parallel_zigzag_faces(n), }, - final_geom: prim::empty_mesh(), // TODO: Close properly + final_geom: OpenMesh { verts: vec![vc], faces }, children: vec![ Child { rule: Rule { eval: Self::recur }, @@ -439,5 +442,5 @@ pub fn main() { // TODO: If I increase the above from 100 to ~150, Blender reports // that the very tips are non-manifold. I am wondering if this is // some sort of numerical precision issue. - run_test_iter(Twist::init(), 200, "twist2"); + run_test_iter(Twist::init(), 100, "twist2"); } diff --git a/src/openmesh.rs b/src/openmesh.rs index c28104c..fa9b90c 100644 --- a/src/openmesh.rs +++ b/src/openmesh.rs @@ -39,6 +39,31 @@ pub struct OpenMesh { impl OpenMesh { + pub fn append(meshes: T) -> OpenMesh + where T: IntoIterator + { + let mut v: Vec = vec![]; + let mut f: Vec = vec![]; + for mesh in meshes { + // Position in 'verts' at which we're appending + // mesh.verts, which we need to know to shift indices: + let offset = v.len(); + + // Copy all vertices: + v.append(&mut mesh.verts.clone()); + // Append its faces, applying offset: + f.extend(mesh.faces.iter().map(|t| { + match t { + Tag::Body(n) => Tag::Body(n + offset), + Tag::Parent(_) => panic!("Cannot append() if mesh has parent references!"), + // TODO: Handle the above + } + })); + } + + OpenMesh { verts: v, faces: f } + } + /// Returns a new `OpenMesh` whose vertices have been transformed. pub fn transform(&self, xfm: &Mat4) -> OpenMesh { OpenMesh { diff --git a/src/rule.rs b/src/rule.rs index 265ef37..7088ac7 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -150,6 +150,12 @@ impl Rule { // s = the 'current' state: let s = &mut stack[n-1]; let depth = s.depth; + + if s.rules.is_empty() { + stack.pop(); + n -= 1; + continue; + } // Evaluate the rule: let child = &s.rules[s.next]; diff --git a/src/util.rs b/src/util.rs index be77f06..0359f8a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -29,3 +29,29 @@ pub fn parallel_zigzag_faces(count: usize) -> Vec { ] }).flatten().collect() } + +pub fn connect_convex(verts: &Vec, as_parent: bool) -> (Vertex, Vec) { + let n = verts.len(); + let mut centroid = Vertex::new(0.0, 0.0, 0.0, 0.0); + for v in verts { + centroid += v; + } + centroid /= n as f32; + + let faces: Vec = { + if as_parent { + (0..n).map(|f1| { + let f2 = (f1 + 1) % n; + vec![Tag::Parent(f2), Tag::Parent(f1), Tag::Body(0)] + }).flatten().collect() + } else { + (0..n).map(|f1| { + let f2 = (f1 + 1) % n; + // n is used for new center vertex + vec![Tag::Body(f1), Tag::Body(f2), Tag::Body(n)] + }).flatten().collect() + } + }; + + (centroid, faces) +}