use crate::mesh::Mesh;
use crate::utils::{ObjectId, LibraryId};
use na::{Vec3, Vec2, Vec4, zero, ToPnt};
use crate::material;
use hashbrown::HashMap;
use crate::scene::SceneData;
use std::mem;
use std::iter;
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(C)]
pub struct Vertex{
pub position: Vec3,
pub normal: Vec3,
pub texcoord: Vec2,
pub original_idx: u32,
pub padding: u32,
}
fn vertex(position: Vec3, normal: Vec3, texcoord: Vec2, original_idx: u32) -> Vertex{
Vertex{
position: position,
normal: normal,
texcoord: texcoord,
original_idx: original_idx,
padding: 0,
}
}
pub trait VertexExt {
fn position(&self) -> &Vec3;
fn normal(&self) -> &Vec3;
fn texcoord(&self) -> &Vec2;
fn position_mut(&mut self) -> &mut Vec3;
fn normal_mut(&mut self) -> &mut Vec3;
fn texcoord_mut(&mut self) -> &mut Vec2;
}
impl VertexExt for Vertex {
fn position(&self) -> &Vec3 {
&self.position
}
fn normal(&self) -> &Vec3{
&self.normal
}
fn texcoord(&self) -> &Vec2{
&self.texcoord
}
fn position_mut(&mut self) -> &mut Vec3{
&mut self.position
}
fn normal_mut(&mut self) -> &mut Vec3{
&mut self.normal
}
fn texcoord_mut(&mut self) -> &mut Vec2{
&mut self.texcoord
}
}
pub trait Vertex4Ext {
fn position(&self) -> &Vec4;
fn normal(&self) -> &Vec4;
fn texcoord(&self) -> &Vec2;
fn position_mut(&mut self) -> &mut Vec4;
fn normal_mut(&mut self) -> &mut Vec4;
fn texcoord_mut(&mut self) -> &mut Vec2;
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub struct TriMesh{
flattened_meshes: Vec<Vec<Vertex>>,
flattened_indices: Option<Vec<Vec<u32>>>,
original_vertices: Vec<Vertex>,
original_indices: Vec<u32>,
materials: Vec<Option<ObjectId>>,
key: Option<ObjectId>,
}
impl TriMesh{
pub fn from(
blend_mesh: &blender::Object,
library_id: LibraryId,
mesh: &Mesh,
libraries: &HashMap<LibraryId, blender::File>,
scene_data: &mut SceneData) -> TriMesh
{
let mut mesh = mesh.clone();
mesh.triangulate_no_edges();
mesh.recalculate_normals();
let submeshes = parse_uvs_and_submeshes(&mesh);
let no_texture_and_smooth = submeshes.iter()
.fold(true, |has_texture_or_flat, submesh|{
has_texture_or_flat && (submesh.is_all_smooth() && submesh.uvs.is_empty())
});
let flattened_meshes;
let flattened_indices;
let num_submeshes;
if no_texture_and_smooth{
let mesh = mesh.mvert.iter().enumerate().map(|(idx, v)|{
vertex(v.position, v.normal, zero(), idx as u32)
}).collect::<Vec<_>>();
flattened_meshes = vec![mesh];
let indices = submeshes.iter()
.map(|submesh| submesh.indices.to_vec()).collect::<Vec<_>>();
num_submeshes = indices.len();
flattened_indices = Some(indices);
} else {
flattened_meshes = flatten(&mesh, &submeshes);
flattened_indices = None;
num_submeshes = flattened_meshes.len();
}
let materials = blend_mesh
.get_ptr_slice("mat", num_submeshes)
.map(|mesh_materials| {
mesh_materials.iter().map(|material_obj| {
let mat_id;
let material;
if let Some(lib_id) = library_id.linked_library_id(material_obj) {
mat_id = ObjectId::new(lib_id.clone(), material_obj.name().unwrap());
if scene_data.materials.contains_key(&mat_id) {
return Some(mat_id)
}
let library = &libraries[&lib_id];
let material_obj = library
.object_by_name(material_obj.name().unwrap())
.unwrap();
material = material::parse_material(
material_obj,
library_id.clone(),
libraries,
&mut scene_data.images,
);
}else{
mat_id = ObjectId::new(library_id.clone(), material_obj.name().unwrap());
if scene_data.materials.contains_key(&mat_id) {
return Some(mat_id)
}
material = material::parse_material(
material_obj.clone(),
library_id.clone(),
libraries,
&mut scene_data.images,
);
}
scene_data.materials.insert(mat_id.clone(), material.unwrap());
Some(mat_id)
}).collect()
}).unwrap_or(vec![None; num_submeshes]);
let original_vertices = flattened_meshes.iter()
.flat_map(|mesh| mesh.iter().cloned())
.collect::<Vec<_>>();
let original_indices = flattened_indices.as_ref().map(|flattened_indices| flattened_indices
.iter()
.flat_map(|indices| indices).cloned()
.collect::<Vec<_>>()
).unwrap_or(vec![]);
let key = blend_mesh
.get_object("key")
.ok()
.map(|key| library_id.object_id(&key));
TriMesh{
flattened_meshes,
flattened_indices,
original_vertices,
original_indices,
materials,
key,
}
}
pub fn original_vertices(&self) -> &[Vertex]{
&self.original_vertices
}
pub fn original_indices(&self) -> &[u32]{
&self.original_indices
}
pub fn submeshes(&self) -> SubMeshIter{
SubMeshIter{
trimesh: self,
next: 0,
}
}
pub fn submeshes_vertices<'s>(&self) -> &[Vec<Vertex>]{
&self.flattened_meshes
}
pub fn submeshes_indices<'s>(&self) -> Option<&Vec<Vec<u32>>>{
self.flattened_indices.as_ref()
}
pub fn materials(&self) -> &[Option<ObjectId>]{
&self.materials
}
pub fn key(&self) -> Option<&ObjectId>{
self.key.as_ref()
}
}
pub struct SubMesh<'a>{
pub material: Option<&'a ObjectId>,
pub vertices: &'a [Vertex],
pub indices: Option<&'a [u32]>,
}
pub struct SubMeshIter<'a>{
trimesh: &'a TriMesh,
next: usize,
}
impl<'a> Iterator for SubMeshIter<'a>{
type Item = SubMesh<'a>;
fn next(&mut self) -> Option<SubMesh<'a>>{
if self.trimesh.materials.len() == self.next {
return None;
}
let next = self.next;
self.next += 1;
let material = self.trimesh.materials[next].as_ref();
if let Some(ref indices) = self.trimesh.flattened_indices{
Some(SubMesh{
material,
vertices: &self.trimesh.original_vertices,
indices: Some(&indices[next]),
})
}else{
Some(SubMesh{
material,
vertices: &self.trimesh.flattened_meshes[next],
indices: None,
})
}
}
}
struct UvsIndices{
indices: Vec<u32>,
uvs: Vec<Vec2>,
normals: Vec<Vec3>,
smooth: Vec<bool>
}
impl UvsIndices{
fn is_all_smooth(&self) -> bool{
self.smooth.iter().all(|s| *s)
}
}
fn parse_uvs_and_submeshes(blend_mesh: &Mesh) -> Vec<UvsIndices>{
if blend_mesh.mvert.is_empty() || blend_mesh.mloop.is_empty(){
return Vec::new();
}
let loops = &blend_mesh.mloop;
let uv_loops = &blend_mesh.mloopuv;
const SMOOTH: u8 = 1;
let has_uv = !uv_loops.is_empty();
let mut submeshes = Vec::new();
if !blend_mesh.mpoly.is_empty(){
for poly in blend_mesh.mpoly.iter(){
let loopstart = poly.loopstart as usize;
let mat_nr = poly.mat_nr as usize;
while mat_nr + 1 > submeshes.len() {
submeshes.push(UvsIndices{ indices: vec![], uvs: vec![], smooth: vec![], normals: vec![]});
}
let submesh = &mut submeshes[mat_nr];
let indices = &mut submesh.indices;
let uvs = &mut submesh.uvs;
let normals = &mut submesh.normals;
let smooth = &mut submesh.smooth;
let v0 = loops[loopstart].v;
let v1 = loops[loopstart+1].v;
let v2 = loops[loopstart+2].v;
let pos0 = blend_mesh.mvert[v0 as usize].position.to_pnt();
let pos1 = blend_mesh.mvert[v1 as usize].position.to_pnt();
let pos2 = blend_mesh.mvert[v2 as usize].position.to_pnt();
indices.push(v0);
indices.push(v1);
indices.push(v2);
if has_uv{
uvs.push(uv_loops[loopstart].uv);
uvs.push(uv_loops[loopstart + 1].uv);
uvs.push(uv_loops[loopstart + 2].uv);
}
if poly.flag & SMOOTH != 0{
normals.push(blend_mesh.mvert[v0 as usize].normal);
normals.push(blend_mesh.mvert[v1 as usize].normal);
normals.push(blend_mesh.mvert[v2 as usize].normal);
}else{
let normal = (pos1 - pos0).cross(&(pos2 - pos0));
normals.push(normal);
normals.push(normal);
normals.push(normal);
}
smooth.push(poly.flag & SMOOTH != 0);
}
}
submeshes
}
#[allow(dead_code)]
fn parse_wireframe_indices(blend_mesh: &blender::Object) -> Vec<u32>{
let mut wireframe_indices = Vec::new();
let num_edges = *blend_mesh.get::<i32>("totedge").unwrap() as usize;
if num_edges > 0{
let edges = blend_mesh.get_ptr_slice("medge", num_edges).unwrap();
for edge in edges{
let from = edge.get::<u32>("v1").unwrap();
let to = edge.get::<u32>("v2").unwrap();
wireframe_indices.push(*from);
wireframe_indices.push(*to);
}
}
wireframe_indices
}
fn flatten(blend_mesh: &Mesh, submeshes: &[UvsIndices]) -> Vec<Vec<Vertex>>{
let zero = [zero(), zero(), zero()];
submeshes.iter().map(|submesh|{
let uvs: Box<dyn Iterator<Item=&[Vec2]>> = if submesh.uvs.is_empty(){
Box::new(iter::repeat(zero.as_ref()))
}else{
Box::new(submesh.uvs.chunks(3))
};
submesh.indices
.chunks(3)
.zip(uvs)
.zip(submesh.smooth.iter())
.zip(submesh.normals.chunks(3))
.flat_map(|(((face, uvs), smooth), normals)|{
let p1 = blend_mesh.mvert[face[0] as usize].position;
let p2 = blend_mesh.mvert[face[1] as usize].position;
let p3 = blend_mesh.mvert[face[2] as usize].position;
if *smooth {
let n1 = blend_mesh.mvert[face[0] as usize].normal;
let n2 = blend_mesh.mvert[face[1] as usize].normal;
let n3 = blend_mesh.mvert[face[2] as usize].normal;
vec![
vertex(p1, n1, uvs[0], face[0]),
vertex(p2, n2, uvs[1], face[1]),
vertex(p3, n3, uvs[2], face[2]),
]
}else{
vec![
vertex(p1, normals[0], uvs[0], face[0]),
vertex(p2, normals[1], uvs[1], face[1]),
vertex(p3, normals[2], uvs[2], face[2]),
]
}
}).collect()
}).collect()
}
#[allow(dead_code)]
fn parse_faces(blend_mesh: &blender::Object) -> Vec<Vec<u32>>{
let num_faces = *blend_mesh.get::<i32>("totface").unwrap() as usize;
if num_faces > 0{
}else{
}
Vec::new()
}