use crate::utils::{self, Property, LibraryId, ObjectId};
use crate::mesh::Mesh;
use blender;
use crate::catmullclark;
use crate::enum_set::*;
use na::Vec3;
use crate::loader;
use crate::scene::SceneData;
use crate::modifiers;
use crate::curves;
use crate::trimesh::{self, TriMesh};
use hashbrown::HashMap;
use std::mem;
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(u16)]
pub enum RigidBodyType{
Active=0,
Passive,
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(u16)]
pub enum RigidBodyShape{
Cuboid,
Sphere,
Capsule,
Cylinder,
Cone,
ConvexHull,
Mesh,
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(C)]
pub struct RigidBody{
pub ty: RigidBodyType,
pub shape: RigidBodyShape,
pub friction: f32,
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone)]
pub struct Model{
name: ObjectId,
node: utils::Transformations,
blend_mesh_id: ObjectId,
skeleton_name: Option<ObjectId>,
vertex_groups: Vec<String>,
vertex_groups_index: Vec<Option<usize>>,
default_group: Option<String>,
rigid_body: Option<RigidBody>,
selectable: bool,
visible: bool,
default_action_name: Option<ObjectId>,
custom_properties: Vec<Property>,
animated_vertices: Vec<trimesh::Vertex>,
drivers: Vec<curves::FCurve>,
deformflag: ArmatureDeformFlag,
}
bitflags!{
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct ArmatureDeformFlag: u16 {
const VGROUP = 1;
const ENVELOPE = 2;
const QUATERNIONS = 4;
const INVERT_VGROUP = 8;
}
}
#[repr(u16)]
#[allow(dead_code)]
#[derive(Copy,Debug,Clone,PartialEq)]
pub enum ParentType{
Type = (1 << 4) - 1,
Object = 0,
Skeleton = 4,
Vert1 = 5,
Vert3 = 6,
Bone = 7,
Slow = 16,
}
#[repr(u16)]
#[derive(Copy,Debug,Clone,PartialEq)]
pub enum SubdivisionTy {
CatmullClark,
Simple,
}
fn modifiers_suffix(modifiers: &blender::List, has_skeleton: bool) -> String{
modifiers.iter().fold("".to_owned(), |mut modifiers_suffix, modifier|{
let modifier_type = modifier.structure().name();
match modifier_type{
"MirrorModifierData" => {
let flag: u16 = *modifier.get("flag").unwrap();
if flag & modifiers::MirrorFlags::AxisX as u16 != 0 {
modifiers_suffix += "_mx";
}
if flag & modifiers::MirrorFlags::AxisY as u16 != 0 {
modifiers_suffix += "_my";
}
if flag & modifiers::MirrorFlags::AxisZ as u16 != 0 {
modifiers_suffix += "_mz";
}
}
"SubsurfModifierData" => {
if !has_skeleton {
let flag: u16 = *modifier.get("flags").unwrap();
let subdivision_ty: SubdivisionTy = *modifier.get("subdivType").unwrap();
let subdivide_uvs = flag & modifiers::SubsurfModifierFlag::SubsurfUv as u16 != 0;
let subdivide_levels = *modifier.get::<u16>("levels").unwrap();
if subdivide_uvs {
modifiers_suffix += &format!("_ssuv{}_{:?}", subdivide_levels, subdivision_ty);
}else{
modifiers_suffix += &format!("_ss{}_{:?}", subdivide_levels, subdivision_ty);
}
}
}
"ArrayModifierData" => {
let offset: Vec3 = *modifier.get("offset").unwrap();
let scale: Vec3 = *modifier.get("scale").unwrap();
let length: f32 = *modifier.get("length").unwrap();
let merge_dist: f32 = *modifier.get("merge_dist").unwrap();
let fit_type: i32 = *modifier.get("fit_type").unwrap();
let offset_type: i32 = *modifier.get("offset_type").unwrap();
let flags: i32 = *modifier.get("flags").unwrap();
let count: u32 = *modifier.get("count").unwrap();
modifiers_suffix += &format!("_array{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}",
offset.x, offset.y, offset.z,
scale.x, scale.y, scale.z,
length,
merge_dist,
fit_type,
offset_type,
flags,
count);
}
_ => ()
}
modifiers_suffix
})
}
fn apply_modifiers(obj: &blender::Object, mut mesh: Mesh, modifiers: &blender::List, vertex_groups: &[String], has_skeleton: bool) -> Mesh{
for modifier in modifiers.iter(){
let modifier_type = modifier.structure().name().to_string();
if modifier_type == "MirrorModifierData"{
let flag: u16 = *modifier.get("flag").unwrap();
if flag & modifiers::MirrorFlags::AxisX as u16 != 0{
modifiers::mirror_mesh(&modifier, obj, &mut mesh, vertex_groups, modifiers::MirrorAxis::X);
}
if flag & modifiers::MirrorFlags::AxisY as u16 != 0{
modifiers::mirror_mesh(&modifier, obj, &mut mesh, vertex_groups, modifiers::MirrorAxis::Y);
}
if flag & modifiers::MirrorFlags::AxisZ as u16 != 0{
modifiers::mirror_mesh(&modifier, obj, &mut mesh, vertex_groups, modifiers::MirrorAxis::Z);
}
}else if modifier_type == "SubsurfModifierData"{
time!("Subdivide", {
if !has_skeleton {
let flag: u16 = *modifier.get("flags").unwrap();
let subdivide_uvs = flag & modifiers::SubsurfModifierFlag::SubsurfUv as u16 != 0;
let subdivision_ty: SubdivisionTy = *modifier.get("subdivType").unwrap();
if subdivision_ty == SubdivisionTy::CatmullClark {
for _ in 0u16..*modifier.get("levels").unwrap(){
catmullclark::subdivide(&mut mesh, subdivide_uvs);
}
}else{
for _ in 0u16..*modifier.get("levels").unwrap(){
mesh.subdivide_simple(subdivide_uvs);
}
}
time!("recalculate normals", {
mesh.recalculate_normals();
});
}
});
}else if modifier_type == "ArrayModifierData"{
modifiers::array_mesh(&modifier, &mut mesh);
}
}
mesh
}
impl Model{
pub fn parse(
obj: &blender::Object,
library_id: LibraryId,
blend_mesh: &blender::Object,
visible: bool,
scene_data: &mut SceneData,
libraries: &HashMap<LibraryId, blender::File>) -> blender::Result<Model>
{
let ty = *obj.get("type").unwrap();
let name = ObjectId::new(library_id.clone(), obj.name().unwrap());
if blender::ObjectType::Mesh != ty{
return Err(blender::Error(format!("Object {:?} is not a mesh", name)));
}
let rigid_body = obj.get_object("rigidbody_object").ok().map(|rigid|{
RigidBody{
ty: *rigid.get("type").unwrap(),
shape: *rigid.get("shape").unwrap(),
friction: *rigid.get("friction").unwrap(),
}
});
let restrictflag: u8 = *obj.get("restrictflag").unwrap();
let selectable = (restrictflag & loader::ObjectRestrict::Select as u8) == 0;
let vertex_groups: Vec<String> = obj.get_list("defbase").unwrap().iter()
.map(|deformation| {
let vertex_group = deformation.name().unwrap().to_string();
vertex_group
}).collect();
let trafos = utils::transformations(&obj);
let modifiers = obj.get_list("modifiers").unwrap();
let skeleton_group = modifiers.iter()
.find(|modifier| modifier.structure().name() == "ArmatureModifierData")
.and_then(|modifier| {
let deformflag = *modifier.get::<ArmatureDeformFlag>("deformflag").unwrap();
modifier.get_object("object").ok()
.map(|armature|{
let lib_id = if let Some(lib_id) = library_id.linked_library_id(&armature) {
lib_id
}else{
library_id.clone()
};
let skeleton_name = armature.name().ok()
.map(|n| ObjectId::new(lib_id.clone(), n));
let default_group = modifier
.get_str("defgrp_name")
.ok()
.map(|n| n.to_owned());
(skeleton_name, default_group, deformflag)
})
});
let (skeleton_name, default_group, deformflag) = if let Some(sg) = skeleton_group {
sg
}else{
(None, None, ArmatureDeformFlag::empty())
};
let modifiers_suffix = modifiers_suffix(&modifiers, skeleton_name.is_some());
let mesh_id = library_id.object_id( blend_mesh);
let mesh_name = blend_mesh.name().unwrap().to_owned() + &modifiers_suffix;
let blend_mesh_id = ObjectId::new(mesh_id.source_file.clone(), &mesh_name);
if scene_data.meshes.get(&blend_mesh_id).is_none(){
let mesh = scene_data.meshes[&mesh_id].clone();
let mesh = apply_modifiers(
obj,
mesh,
&modifiers,
&vertex_groups,
skeleton_name.is_some()
);
let trimesh = TriMesh::from(
&blend_mesh,
mesh_id.source_file.clone(),
&mesh,
libraries,
scene_data,
);
scene_data.trimeshes.insert(blend_mesh_id.clone(), trimesh);
scene_data.meshes.insert(blend_mesh_id.clone(), mesh);
}
let animated_vertices = if skeleton_name.is_some() || blend_mesh.get_object("key").is_ok(){
scene_data.trimeshes[&blend_mesh_id].original_vertices().to_vec()
}else{
vec![]
};
let default_action_name = curves::default_action_name_for(
obj,
&library_id,
libraries
);
let drivers = curves::parse_drivers_for(obj);
Ok(Model{
name,
visible,
node: trafos,
animated_vertices,
skeleton_name,
blend_mesh_id,
vertex_groups,
vertex_groups_index: vec![],
default_group,
rigid_body,
selectable,
default_action_name,
custom_properties: utils::custom_properties(&blend_mesh),
drivers,
deformflag,
})
}
pub fn skeleton(&self) -> Option<&ObjectId> {
self.skeleton_name.as_ref()
}
pub fn default_action(&self) -> Option<&ObjectId>{
self.default_action_name.as_ref()
}
pub fn name(&self) -> &ObjectId{
&self.name
}
pub fn mesh(&self) -> &ObjectId {
&self.blend_mesh_id
}
pub fn rigid_body(&self) -> Option<&RigidBody>{
self.rigid_body.as_ref()
}
pub fn is_selectable(&self) -> bool{
self.selectable
}
pub fn is_visible(&self) -> bool{
self.visible
}
pub fn animated_vertices(&self) -> &[trimesh::Vertex]{
&self.animated_vertices
}
pub fn transformations(&self) -> &utils::Transformations{
&self.node
}
pub fn vertex_groups(&self) -> &[String]{
&self.vertex_groups
}
pub fn default_group(&self) -> Option<&String>{
self.default_group.as_ref()
}
pub fn custom_properties(&self) -> &[Property]{
&self.custom_properties
}
pub fn drivers(&self) -> &[curves::FCurve] {
&self.drivers
}
pub fn skeleton_deformflag(&self) -> ArmatureDeformFlag {
self.deformflag
}
}
pub struct TriModel<'a>{
model: &'a Model,
trimesh: &'a TriMesh,
mesh: &'a Mesh,
}
impl<'a> TriModel<'a>{
pub(crate) fn from(model: &'a Model, scene_data: &'a SceneData) -> TriModel<'a>{
TriModel{
trimesh: &scene_data.trimeshes[&model.mesh()],
mesh: &scene_data.meshes[&model.mesh()],
model,
}
}
pub fn skeleton(&self) -> Option<&ObjectId>{
self.model.skeleton()
}
pub fn default_action(&self) -> Option<&ObjectId>{
self.model.default_action()
}
pub fn name(&self) -> &ObjectId{
self.model.name()
}
pub fn mesh_name(&self) -> &ObjectId {
self.model.mesh()
}
pub fn mesh(&self) -> &'a Mesh{
self.mesh
}
pub fn rigid_body(&self) -> Option<&RigidBody>{
self.model.rigid_body()
}
pub fn is_selectable(&self) -> bool{
self.model.is_selectable()
}
pub fn is_visible(&self) -> bool{
self.model.is_visible()
}
pub fn animated_vertices(&self) -> &[trimesh::Vertex]{
self.model.animated_vertices()
}
pub fn animated_mesh(&self) -> (&[trimesh::Vertex], &[u32]){
(self.model.animated_vertices(), self.trimesh.original_indices())
}
pub fn transformations(&self) -> &utils::Transformations{
self.model.transformations()
}
pub fn vertex_groups(&self) -> &[String]{
self.model.vertex_groups()
}
pub fn default_group(&self) -> Option<&String>{
self.model.default_group()
}
pub fn custom_properties(&self) -> &[Property]{
self.model.custom_properties()
}
pub fn original_vertices(&self) -> &[trimesh::Vertex]{
self.trimesh.original_vertices()
}
pub fn original_indices(&self) -> &[u32]{
self.trimesh.original_indices()
}
pub fn submeshes(&self) -> trimesh::SubMeshIter{
self.trimesh.submeshes()
}
pub fn submeshes_vertices<'s>(&self) -> &[Vec<trimesh::Vertex>]{
self.trimesh.submeshes_vertices()
}
pub fn submeshes_indices<'s>(&self) -> Option<&Vec<Vec<u32>>>{
self.trimesh.submeshes_indices()
}
pub fn materials(&self) -> &[Option<ObjectId>]{
self.trimesh.materials()
}
pub fn skeleton_deformflag(&self) -> ArmatureDeformFlag {
self.model.deformflag
}
}