use genmesh::{generators::Cube, Quad, MapToVertices, Vertices, Vertex};
use obj;
use cgmath::{Quaternion, Euler, Deg, Vector3};
use crate::robocraft;
const SCALE: f32 = 0.5;
const ROTATIONS: [Euler<Deg<f32>>; 24] = [
Euler{x: Deg(0.0), y: Deg(0.0), z: Deg(0.0)}, Euler{x: Deg(0.0), y: Deg(0.0), z: Deg(90.0)},
Euler{x: Deg(0.0), y: Deg(0.0), z: Deg(180.0)}, Euler{x: Deg(0.0), y: Deg(0.0), z: Deg(-90.0)},
Euler{x: Deg(0.0), y: Deg(90.0), z: Deg(0.0)}, Euler{x: Deg(0.0), y: Deg(90.0), z: Deg(90.0)},
Euler{x: Deg(-90.0), y: Deg(-90.0), z: Deg(0.0)}, Euler{x: Deg(0.0), y: Deg(90.0), z: Deg(-90.0)},
Euler{x: Deg(0.0), y: Deg(-90.0), z: Deg(90.0)}, Euler{x: Deg(0.0), y: Deg(-90.0), z: Deg(-90.0)},
Euler{x: Deg(90.0), y: Deg(-90.0), z: Deg(0.0)}, Euler{x: Deg(90.0), y: Deg(90.0), z: Deg(0.0)},
Euler{x: Deg(-90.0), y: Deg(90.0), z: Deg(0.0)}, Euler{x: Deg(0.0), y: Deg(90.0), z: Deg(180.0)},
Euler{x: Deg(0.0), y: Deg(180.0), z: Deg(0.0)}, Euler{x: Deg(0.0), y: Deg(180.0), z: Deg(90.0)},
Euler{x: Deg(0.0), y: Deg(180.0), z: Deg(0.0)}, Euler{x: Deg(0.0), y: Deg(180.0), z: Deg(180.0)},
Euler{x: Deg(0.0), y: Deg(-90.0), z: Deg(-90.0)}, Euler{x: Deg(0.0), y: Deg(-90.0), z: Deg(0.0)},
Euler{x: Deg(90.0), y: Deg(0.0), z: Deg(180.0)}, Euler{x: Deg(90.0), y: Deg(180.0), z: Deg(0.0)},
Euler{x: Deg(-90.0), y: Deg(0.0), z: Deg(0.0)}, Euler{x: Deg(-90.0), y: Deg(180.0), z: Deg(0.0)}, ];
pub fn cube_rotation_to_quat(orientation: u8) -> Quaternion<f32> {
ROTATIONS[orientation as usize].into()
}
pub fn cubes_to_model(robot: robocraft::Cubes) -> obj::Obj {
cubes_to_model_with_lut(robot, default_model_lut)
}
pub fn cubes_to_model_with_lut<F: FnMut(u32) -> Vec<Quad<Vertex>>>(robot: robocraft::Cubes, mut lut: F) -> obj::Obj {
let mut positions = Vec::<[f32; 3]>::new(); let mut normals = Vec::<[f32; 3]>::new(); let mut objects = Vec::<obj::Object>::new(); let mut last = 0;
for cube in robot.into_iter() {
let vertices = lut(cube.id); let rotation: Quaternion<_> = cube_rotation_to_quat(cube.orientation);
positions.extend::<Vec::<[f32; 3]>>(
vertices.clone().into_iter().vertex(|v|
{
let rotated = rotation * Vector3{x: v.pos.x * SCALE, y: v.pos.y * SCALE, z: v.pos.z * SCALE};
[rotated.x + (cube.x as f32), rotated.y + (cube.y as f32), rotated.z + (cube.z as f32)]
})
.vertices()
.collect()
);
normals.extend::<Vec::<[f32; 3]>>(
vertices.clone().into_iter().vertex(|v|
{
let rotated = rotation * Vector3{x: v.normal.x * SCALE, y: v.normal.y * SCALE, z: v.normal.z * SCALE};
[rotated.x + (cube.x as f32), rotated.y + (cube.y as f32), rotated.z + (cube.z as f32)]
})
.vertices()
.collect()
);
let polys = vertices.clone().into_iter().vertex(|_| {last+=1; return last-1;})
.map(|Quad{x: v0, y: v1, z: v2, w: v3}|
obj::SimplePolygon(vec![
obj::IndexTuple(v0, Some(0), Some(v0)),
obj::IndexTuple(v1, Some(0), Some(v1)),
obj::IndexTuple(v2, Some(0), Some(v2)),
obj::IndexTuple(v3, Some(0), Some(v3))
])
).collect();
objects.push(
obj::Object{
name: format!("Cube-ID{}-NUM{}", cube.id, objects.len()),
groups: vec![
obj::Group {
name: format!("Cube-ID{}-NUM{}-0", cube.id, objects.len()),
index: 0,
material: None,
polys: polys
},
]
}
);
}
println!("Last (index): {}, Vertices (len): {}", last, positions.len());
obj::Obj{
data: obj::ObjData {
position: positions,
texture: vec![[0.0, 0.0]],
normal: normals,
objects: objects,
material_libs: Vec::new(),
},
path: std::path::PathBuf::new(),
}
}
pub fn default_model_lut(id: u32) -> Vec<Quad<Vertex>> {
match id {
_ => Cube::new().collect(),
}
}