179 lines
5.1 KiB
Rust
179 lines
5.1 KiB
Rust
//use std::io;
|
|
use tri_mesh::prelude::*;
|
|
|
|
enum Rule {
|
|
// Recurse further:
|
|
Recurse(fn (Vec<Mesh>) -> Vec<RuleStep>),
|
|
// Stop recursing here:
|
|
EmptyRule,
|
|
}
|
|
// TODO: Rename rules?
|
|
|
|
struct RuleStep {
|
|
// The geometry generated at this step
|
|
geom: Mesh,
|
|
// The next rule to run on this geometry
|
|
rule: Box<Rule>,
|
|
// The transformation to apply to any results of 'rule' (if
|
|
// applicable)
|
|
xform: Mat4,
|
|
}
|
|
|
|
fn test_rule(_v: Vec<Mesh>) -> Vec<RuleStep> {
|
|
|
|
let mesh = MeshBuilder::new().cube().build().unwrap();
|
|
|
|
// Quarter-turn in radians:
|
|
let qtr = Rad::turn_div_4();
|
|
|
|
// Each element of this turns to a branch for the recursion:
|
|
let turns: Vec<Mat4> = vec![
|
|
Matrix4::identity(),
|
|
Matrix4::from_angle_y(qtr),
|
|
Matrix4::from_angle_y(qtr * 2.0),
|
|
Matrix4::from_angle_y(qtr * 3.0),
|
|
];
|
|
|
|
let gen_rulestep = |rot: &Mat4| -> RuleStep {
|
|
let m: Mat4 = rot *
|
|
Matrix4::from_translation(vec3(1.5, 0.0, 0.0)) *
|
|
Matrix4::from_scale(0.6);
|
|
let r = Rule::Recurse(test_rule);
|
|
RuleStep { geom: mesh.clone(), rule: Box::new(r), xform: m }
|
|
};
|
|
|
|
turns.iter().map(gen_rulestep).collect()
|
|
}
|
|
|
|
// TODO: Do I want to make 'geom' shared somehow, maybe with Rc? I
|
|
// could end up having a lot of identical geometry that need not be
|
|
// duplicated until it is transformed into the global space
|
|
|
|
// Bigger TODO: either rule_to_mesh or test_rule is doing something
|
|
// totally wrong here (look at the generated mesh). I suspect it is
|
|
// appending geometry multiple times because my semantics are vague.
|
|
|
|
fn rule_to_mesh(rule: &Rule, xform: Mat4, iter_num: u32) -> Mesh {
|
|
|
|
let max_iters: u32 = 4;
|
|
let mut mesh = MeshBuilder::new().with_indices(vec![]).with_positions(vec![]).build().unwrap();
|
|
|
|
if iter_num >= max_iters {
|
|
return mesh;
|
|
}
|
|
|
|
match rule {
|
|
Rule::Recurse(func) => {
|
|
for step in func(vec![]) {
|
|
let subrule: Rule = *step.rule;
|
|
let subxform: Mat4 = step.xform;
|
|
let geom: Mesh = step.geom;
|
|
|
|
mesh.append(&geom);
|
|
|
|
let mut submesh: Mesh = rule_to_mesh(&subrule, subxform, iter_num + 1);
|
|
submesh.apply_transformation(xform);
|
|
|
|
mesh.append(&submesh);
|
|
}
|
|
mesh
|
|
}
|
|
Rule::EmptyRule => {
|
|
mesh
|
|
}
|
|
}
|
|
}
|
|
|
|
// This isn't kosher:
|
|
//type Rule = fn (Vec<Mesh>) -> (Mesh, Vec<(Mesh, Box<Rule>)>);
|
|
|
|
fn mesh_builder_example() -> Result<Mesh, tri_mesh::mesh_builder::Error> {
|
|
let indices: Vec<u32> = vec![0, 1, 2,
|
|
0, 2, 3,
|
|
0, 3, 1];
|
|
let positions: Vec<f64> = vec![0.0, 0.0, 0.0,
|
|
1.0, 0.0, -0.5,
|
|
-1.0, 0.0, -0.5,
|
|
0.0, 0.0, 1.0];
|
|
let mesh = MeshBuilder::new().
|
|
with_indices(indices).
|
|
with_positions(positions).
|
|
build()?;
|
|
|
|
assert_eq!(mesh.no_faces(), 3);
|
|
assert_eq!(mesh.no_vertices(), 4);
|
|
|
|
Ok(mesh)
|
|
}
|
|
|
|
fn print_vector(v: &Vec4) -> String {
|
|
return format!("{},{},{},{}", v.x, v.y, v.z, v.w);
|
|
}
|
|
|
|
fn print_matrix(m: &Mat4) {
|
|
let mt = m.transpose();
|
|
println!("[{}]\n[{}]\n[{}]\n[{}]",
|
|
print_vector(&mt.x), print_vector(&mt.y),
|
|
print_vector(&mt.z), print_vector(&mt.w));
|
|
}
|
|
|
|
fn main() {
|
|
// Construct any mesh, this time, we will construct a simple icosahedron
|
|
let mesh = MeshBuilder::new().icosahedron().build().unwrap();
|
|
|
|
// Is there a better way to do this?
|
|
let _empty_mesh = MeshBuilder::new().with_indices(vec![]).with_positions(vec![]).build().unwrap();
|
|
|
|
// Compute the extreme coordinates which defines the axis aligned bounding box..
|
|
let (_min_coordinates, _max_coordinates) = mesh.extreme_coordinates();
|
|
|
|
// .. or construct an actual mesh representing the axis aligned bounding box
|
|
let _aabb = mesh.axis_aligned_bounding_box();
|
|
|
|
// Export the bounding box to an obj file
|
|
std::fs::write("foo.obj", mesh.parse_as_obj()).unwrap();
|
|
|
|
// Try some vector stuff:
|
|
|
|
let m: Mat4 = Matrix4::from_translation(vec3(5.0, 0.0, 0.0));
|
|
println!("translation: ");
|
|
print_matrix(&m);
|
|
/*print_vector(&m.x);
|
|
print_vector(&m.y);
|
|
print_vector(&m.z);
|
|
print_vector(&m.w);*/
|
|
|
|
let m2: Mat4 = Matrix4::from_scale(2.0);
|
|
println!("scale: ");
|
|
print_matrix(&m2);
|
|
let m3 = m * m2;
|
|
println!("translation * scale: ");
|
|
print_matrix(&m3);
|
|
let m4 = m2 * m;
|
|
println!("scale * translation: ");
|
|
print_matrix(&m4);
|
|
|
|
let mut mesh2 = mesh_builder_example().unwrap();
|
|
std::fs::write("foo2.obj", mesh2.parse_as_obj()).unwrap();
|
|
|
|
mesh2.apply_transformation(m);
|
|
|
|
mesh2.append(&mesh);
|
|
|
|
std::fs::write("foo3.obj", mesh2.parse_as_obj()).unwrap();
|
|
|
|
let r = Rule::Recurse(test_rule);
|
|
|
|
match r {
|
|
Rule::Recurse(f) => {
|
|
let _v = f(vec![]);
|
|
}
|
|
Rule::EmptyRule => {
|
|
println!("Empty");
|
|
}
|
|
}
|
|
|
|
let cubemesh: Mesh = rule_to_mesh(&r, Matrix4::identity(), 0);
|
|
std::fs::write("cubemesh.obj", cubemesh.parse_as_obj()).unwrap();
|
|
}
|