use blender;
use na::{Vec3, vec3, Vec2, zero, Pnt2, ToPnt};
use color::Rgba;
use hashbrown::{HashMap, hash_map::Entry};
use std::i16;
use std::iter;
use std::mem;
#[cfg(feature="rayon")]
use rayon::prelude::*;
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(C)]
struct MVertBlender {
co: Vec3,
no: Vec3<i16>,
flag: u8,
bweight: u8,
}
impl MVertBlender{
#[inline]
fn normal(&self) -> Vec3{
vec3(self.no.x as f32,
self.no.y as f32,
self.no.z as f32) / i16::MAX as f32
}
#[inline]
pub fn to_mvert(&self) -> MVert{
MVert{
position: self.co,
normal: self.normal(),
flag: self.flag,
bweight: self.bweight,
pad: [0;6]
}
}
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(C)]
pub struct MVert {
pub position: Vec3,
pub normal: Vec3,
pub flag: u8,
pub bweight: u8,
pub pad: [u8; 6]
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(C)]
pub struct MDeformWeight {
pub def_nr: i32,
pub weight: f32,
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
pub struct MDeformVert {
pub dw_start: usize,
pub dw_end: usize,
pub flag: i32,
}
pub struct MDeformVertRef<'a>{
pub dw: &'a [MDeformWeight],
pub flag: i32,
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(C)]
pub struct MLoop{
pub v: u32,
pub e: u32,
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(C)]
pub struct MLoopUV{
pub uv: Vec2,
pub flag: i32,
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(C)]
pub struct MPoly {
pub loopstart: u32,
pub totloop: u32,
pub mat_nr: i16,
pub flag: u8,
pub pad: u8,
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(C)]
pub struct MTexPoly {
tpage: u64,
flag: u8,
transp: u8,
mode: u16,
tile: u16,
pad: u16,
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(C)]
pub struct MLoopCol {
r: u8,
g: u8,
b: u8,
a: u8,
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(C)]
pub struct MFace {
v1: u32,
v2: u32,
v3: u32,
v4: u32,
mat_nr: u16,
edcode: u8,
flag: u8,
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(C)]
pub struct MTFace {
uv: [Vec2;4],
tpage: u64,
flag: u8,
transp: u8,
mode: u16,
tile: u16,
unwrap: u16,
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(C)]
pub struct TFace {
tpage: u64,
uv: [Vec2;4],
col: [i32;4],
flag: u8,
transp: u8,
mode: u16,
tile: u16,
unwrap: u16,
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug,Copy)]
#[repr(C)]
pub struct MEdge {
pub v1: u32,
pub v2: u32,
pub crease: u8,
pub bweight: u8,
pub flag: u16,
}
bitflags!{
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct Flag: i16{
const TWOSIDED = 1 << 2;
const UVEFFECT = 1 << 3;
const VCOLEFFECT = 1 << 4;
const AUTOSMOOTH = 1 << 5;
const SMESH = 1 << 6;
const SUBSURF = 1 << 7;
const OPT_EDGES = 1 << 8;
const DS_EXPAND = 1 << 9;
const SCULPT_DYNAMIC_TOPOLOGY = 1 << 10;
}
}
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone,Debug)]
pub struct Mesh {
pub name: String,
pub key: Option<String>,
pub address: u64,
pub mpoly: Vec<MPoly>,
pub mloop: Vec<MLoop>,
pub mloopuv: Vec<MLoopUV>,
pub mloopcol: Vec<Rgba<u8>>,
pub mface: Vec<MFace>,
pub mvert: Vec<MVert>,
pub medge: Vec<MEdge>,
pub dvert: Vec<MDeformVert>,
pub mcol: Vec<Rgba<u8>>,
pub dweights: Vec<MDeformWeight>,
pub loc: [f32;3],
pub size: [f32;3],
pub rot: Option<[f32;3]>,
pub drawflag: Option<i32>,
pub texflag: i16,
pub flag: Flag,
pub smoothresh: f32,
pub cd_flag: u8,
pub subdiv: u8,
pub subdivr: u8,
pub subsurftype: u8,
}
impl Mesh{
pub fn parse(blend_mesh: &blender::Object, version: u32) -> blender::Result<Mesh>{
if blend_mesh.structure().name() != "Mesh"{
return Err(blender::Error::from("Object is not a mesh".to_string()));
}
let name = blend_mesh.name().unwrap();
let address = blend_mesh.addr();
let totvert: i32 = *blend_mesh.get("totvert").unwrap();
let mvert = blend_mesh.get_data_slice::<MVertBlender>("mvert", totvert as usize)
.unwrap_or(&[])
.iter()
.map(|v| v.to_mvert())
.collect();
let mut dweights: Vec<MDeformWeight> = vec![];
let dvert = match blend_mesh.get_ptr_slice("dvert", totvert as usize){
Ok(dvert) => {
dvert.iter().map(|deformvert| {
let num_weights: i32 = *deformvert.get("totweight").unwrap();
let start_vert = dweights.len();
if let Ok(mut mdeformweights) = deformvert.get_vec("dw", num_weights as usize){
dweights.append(&mut mdeformweights);
};
let flag = *deformvert.get("flag").unwrap();
MDeformVert{
dw_start: start_vert,
dw_end: dweights.len(),
flag: flag,
}
}).collect()
},
_ => vec![]
};
let totedge: i32 = *blend_mesh.get("totedge").unwrap();
let medge = blend_mesh.get_vec("medge", totedge as usize).unwrap_or(vec![]);
let totface: i32 = *blend_mesh.get("totface").unwrap();
let mface = blend_mesh.get_vec("mface", totface as usize).unwrap_or(vec![]);
let totpoly: i32 = *blend_mesh.get("totpoly").unwrap();
let mpoly = blend_mesh.get_vec("mpoly", totpoly as usize).unwrap_or(vec![]);
let totloop: i32 = *blend_mesh.get("totloop").unwrap();
let mloop = blend_mesh.get_vec("mloop", totloop as usize).unwrap_or(vec![]);
let mloopuv = blend_mesh.get_vec("mloopuv", totloop as usize).unwrap_or(vec![]);
let mloopcol = blend_mesh.get_vec("mloopcol", totloop as usize).unwrap_or(vec![]);
let totcol: u16 = *blend_mesh.get("totcol").unwrap();
let mcol = blend_mesh.get_vec("mcol", totcol as usize).unwrap_or(vec![]);
let loc = *blend_mesh.get("loc").unwrap();
let size = *blend_mesh.get("size").unwrap();
let rot = blend_mesh.get("rot").ok().copied();
let drawflag = blend_mesh.get("drawflag").ok().copied();
let texflag = *blend_mesh.get("texflag").unwrap();
let mut flag: Flag = *blend_mesh.get("flag").unwrap();
if version >= 280 {
flag.remove(Flag::TWOSIDED);
}
let smoothresh = *blend_mesh.get("smoothresh").unwrap();
let cd_flag = *blend_mesh.get("cd_flag").unwrap();
let subdiv = *blend_mesh.get("subdiv").unwrap();
let subdivr = *blend_mesh.get("subdivr").unwrap();
let subsurftype = *blend_mesh.get("subsurftype").unwrap();
let key = blend_mesh.get_object("key").ok()
.map(|key| key.name().unwrap().to_owned());
Ok(Mesh {
name: name.to_string(),
key,
address: address,
mpoly: mpoly,
mloop: mloop,
mloopuv: mloopuv,
mloopcol: mloopcol,
mface: mface,
mvert: mvert,
medge: medge,
dvert: dvert,
dweights,
mcol: mcol,
loc: loc,
size: size,
rot: rot,
drawflag: drawflag,
texflag: texflag,
flag: flag,
smoothresh: smoothresh,
cd_flag: cd_flag,
subdiv: subdiv,
subdivr: subdivr,
subsurftype: subsurftype,
})
}
#[cfg(not(feature="rayon"))]
pub fn recalculate_normals(&mut self){
#[inline]
fn newell(prev: &Vec3, curr: &Vec3) -> Vec3{
vec3(
(prev.y - curr.y) * (prev.z + curr.z),
(prev.z - curr.z) * (prev.x + curr.x),
(prev.x - curr.x) * (prev.y + curr.y)
)
}
let zero3: Vec3 = zero();
for v in self.mvert.iter_mut(){
v.normal = zero3;
}
for poly in self.mpoly.iter(){
let start = poly.loopstart as usize;
let num_loops = poly.totloop as usize;
let end = start + num_loops;
let face_loops = &self.mloop[start..end];
let last = [*face_loops.last().unwrap(), *face_loops.first().unwrap()];
let normal = face_loops.windows(2)
.chain(iter::once(last.as_ref()))
.fold(zero3, |normal, prev_curr|{
let prev = prev_curr[0].v as usize;
let curr = prev_curr[1].v as usize;
let prev = &self.mvert[prev];
let curr = &self.mvert[curr];
let new = newell(&prev.position, &curr.position);
normal + new
});
for mloop in face_loops.iter(){
self.mvert[mloop.v as usize].normal += normal;
}
}
for mvert in self.mvert.iter_mut(){
let normal = mvert.normal.normalize();
mvert.normal = normal;
}
}
#[cfg(feature="rayon")]
pub fn recalculate_normals(&mut self){
#[inline]
fn newell(prev: &Vec3, curr: &Vec3) -> Vec3{
vec3(
(prev.y - curr.y) * (prev.z + curr.z),
(prev.z - curr.z) * (prev.x + curr.x),
(prev.x - curr.x) * (prev.y + curr.y)
)
}
let zero3: Vec3 = zero();
self.mvert.par_iter_mut().for_each(|v|{
v.normal = zero3;
});
let faces_normals = self.mpoly.par_iter().map(|poly|{
let start = poly.loopstart as usize;
let num_loops = poly.totloop as usize;
let end = start + num_loops;
let face_loops = &self.mloop[start..end];
let last = [*face_loops.last().unwrap(), *face_loops.first().unwrap()];
face_loops.windows(2)
.chain(iter::once(last.as_ref()))
.fold(zero3, |normal, prev_curr|{
let prev = prev_curr[0].v as usize;
let curr = prev_curr[1].v as usize;
let prev = &self.mvert[prev];
let curr = &self.mvert[curr];
let new = newell(&prev.position, &curr.position);
normal + new
})
}).collect::<Vec<_>>();
for (poly, normal) in self.mpoly.iter().zip(faces_normals) {
let start = poly.loopstart as usize;
let num_loops = poly.totloop as usize;
let end = start + num_loops;
let face_loops = &self.mloop[start..end];
for mloop in face_loops {
self.mvert[mloop.v as usize].normal += normal;
}
}
self.mvert.par_iter_mut().for_each(|mvert| {
let normal = mvert.normal.normalize();
mvert.normal = normal;
});
}
pub fn dimensions(&self) -> Vec3{
let zero: Vec3 = zero();
let max = self.mvert.iter().fold(zero, |max, v| {
let v = v.position;
vec3!(max.x.max(v.x), max.y.max(v.y), max.z.max(v.z))
});
let min = self.mvert.iter().fold(max, |min, v| {
let v = v.position;
vec3!(min.x.min(v.x), min.y.min(v.y), min.z.min(v.z))
});
max - min
}
pub fn dvert(&self, idx: usize) -> &[MDeformWeight]{
let dvert = &self.dvert[idx];
&self.dweights[dvert.dw_start..dvert.dw_end]
}
pub fn triangulate(&mut self){
self.triangulate_(true)
}
pub fn triangulate_no_edges(&mut self) {
self.triangulate_(false)
}
fn triangulate_(&mut self, calculate_edges: bool) {
#[derive(Debug, Copy, Clone)]
enum Axis {
X, Y, Z,
XNeg, YNeg, ZNeg,
}
impl Axis {
fn is_negative(self) -> bool {
match self {
Axis::XNeg | Axis::YNeg | Axis::ZNeg => true,
_ => false,
}
}
}
trait GeometryIterator{
fn signed_area(self) -> f32;
}
impl<I: Iterator<Item = Pnt2>> GeometryIterator for I {
fn signed_area(mut self) -> f32 {
let mut area = 0.;
let first = self.next();
let mut next = first.clone();
loop {
let p0 = next.take();
let p1 = self.next();
if let (Some(p0), Some(p1)) = (p0, p1) {
area = area + (p0.x * p1.y - p1.x * p0.y);
next = Some(p1);
}else {
if p0.is_some() {
next = p0;
}
break;
}
}
if let (Some(p0), Some(p1)) = (next, first) {
area = area + (p0.x * p1.y - p1.x * p0.y);
}
area = area * 0.5;
area
}
}
fn find_max_area_axis(poly: &[&MVert]) -> Axis {
let z_area = poly
.iter()
.map(|v| v.position.xy().to_pnt())
.signed_area();
let y_area = poly
.iter()
.map(|v| v.position.xz().to_pnt())
.signed_area();
let x_area = poly
.iter()
.map(|v| v.position.yz().to_pnt())
.signed_area();
if z_area.abs() >= y_area.abs() && z_area.abs() >= x_area.abs() {
if z_area >= 0. {
Axis::Z
}else{
Axis::ZNeg
}
}else if y_area.abs() >= z_area.abs() && y_area.abs() >= x_area.abs() {
if y_area >= 0. {
Axis::Y
}else{
Axis::YNeg
}
}else{
if x_area >= 0. {
Axis::X
}else{
Axis::XNeg
}
}
}
let mut new_edges_index = HashMap::new();
let mut medges = vec![];
let mut edge_index_or_insert = |edge: MEdge|{
let hash = hash(edge.v1, edge.v2);
match new_edges_index.entry(hash){
Entry::Occupied(e) => *e.get(),
vacant => {
let edge_idx = medges.len() as u32;
medges.push(edge);
*vacant.or_insert(edge_idx)
}
}
};
#[inline]
fn hash(x: u32, y: u32) -> u64{
let d = x as i32 - y as i32;
let min = y as i32 + (d & d>>31);
let max = x as i32 - (d & d>>31);
(max as u64) << 32 | min as u64
}
let mut mpolys = vec![];
let mut mloops = vec![];
let mut mloopsuv = vec![];
for poly in &self.mpoly {
let start = poly.loopstart as usize;
let end = (poly.loopstart + poly.totloop) as usize;
let mloop = &self.mloop[start .. end];
if poly.totloop == 3 {
mpolys.push(MPoly{
loopstart: mloops.len() as u32,
totloop: 3,
mat_nr: poly.mat_nr,
flag: poly.flag,
pad: poly.pad,
});
mloops.extend(mloop.iter().copied());
if !self.mloopuv.is_empty() {
mloopsuv.extend(self.mloopuv[start .. end].iter().copied());
}
continue;
}
let face = mloop
.iter()
.map(|mloop| &self.mvert[mloop.v as usize])
.collect::<Vec<_>>();
let axis = find_max_area_axis(&face);
let data = match axis {
Axis::Z => {
face.iter().map(|v| [v.position.x, v.position.y]).collect::<Vec<_>>()
},
Axis::ZNeg => {
face.iter().rev().map(|v| [v.position.x, v.position.y]).collect::<Vec<_>>()
}
Axis::Y => {
face.iter().map(|v| [v.position.x, v.position.z]).collect::<Vec<_>>()
},
Axis::YNeg => {
face.iter().rev().map(|v| [v.position.x, v.position.z]).collect::<Vec<_>>()
}
Axis::X => {
face.iter().map(|v| [v.position.y, v.position.z]).collect::<Vec<_>>()
},
Axis::XNeg => {
face.iter().rev().map(|v| [v.position.y, v.position.z]).collect::<Vec<_>>()
}
};
let triangles = polygon2::triangulate(&data);
for triangle in triangles.chunks(3) {
mpolys.push(MPoly{
loopstart: mloops.len() as u32,
totloop: 3,
mat_nr: poly.mat_nr,
flag: poly.flag,
pad: poly.pad,
});
if axis.is_negative() {
mloops.extend(triangle.iter().rev().map(|i| mloop[face.len() - 1 - *i]));
}else{
mloops.extend(triangle.iter().map(|i| mloop[*i]));
}
if calculate_edges {
if axis.is_negative() {
for edge in triangle
.windows(2)
.rev()
.chain(Some(vec![triangle[0], triangle[2]].as_slice()))
{
let old_edge = self.medge[mloop[edge[1]].e as usize];
edge_index_or_insert(MEdge{
v1: mloop[edge[1]].v,
v2: mloop[edge[0]].v,
crease: old_edge.crease,
bweight: old_edge.bweight,
flag: old_edge.flag,
});
}
}else{
for edge in triangle
.windows(2)
.chain(Some(vec![triangle[0], triangle[2]].as_slice()))
{
let old_edge = self.medge[mloop[edge[0]].e as usize];
edge_index_or_insert(MEdge{
v1: mloop[edge[0]].v,
v2: mloop[edge[1]].v,
crease: old_edge.crease,
bweight: old_edge.bweight,
flag: old_edge.flag,
});
}
}
}
}
if !self.mloopuv.is_empty() {
let mloopuv = &self.mloopuv[start .. end];
for triangle in triangles.chunks(3) {
if axis.is_negative() {
mloopsuv.extend(triangle.iter().rev().map(|i| mloopuv[face.len() - 1 - *i]));
}else{
mloopsuv.extend(triangle.iter().map(|i| mloopuv[*i]));
}
}
}
}
self.mpoly = mpolys;
self.mloop = mloops;
self.mloopuv = mloopsuv;
self.medge = medges;
}
pub fn subdivide_simple(&mut self, subdivide_uvs: bool) {
let subdivide_uvs = subdivide_uvs && !self.mloopuv.is_empty();
let mut new_loops = vec![];
let mut new_uvloops = vec![];
let mut new_polys = vec![];
let mut new_edges = vec![];
let mut new_edges_index = HashMap::new();
let mut edge_index_or_insert = |edge: MEdge|{
let hash = hash(edge.v1, edge.v2);
match new_edges_index.entry(hash){
Entry::Occupied(e) => *e.get(),
vacant => {
let edge_idx = new_edges.len() as u32;
new_edges.push(edge);
*vacant.or_insert(edge_idx)
}
}
};
#[inline]
fn hash(x: u32, y: u32) -> u64{
let d = x as i32 - y as i32;
let min = y as i32 + (d & d>>31);
let max = x as i32 - (d & d>>31);
(max as u64) << 32 | min as u64
}
let edges_index: HashMap<_,_> = self.medge.iter().enumerate().map(|(idx, edge)| {
let key = hash(edge.v1, edge.v2);
(key, idx)
}).collect();
for poly in &self.mpoly {
if poly.totloop == 3 {
let v1 = self.mvert[self.mloop[poly.loopstart as usize].v as usize];
let v2 = self.mvert[self.mloop[poly.loopstart as usize + 1].v as usize];
let v3 = self.mvert[self.mloop[poly.loopstart as usize + 2].v as usize];
let p4 = (v1.position + v2.position) / 2.;
let p5 = (v2.position + v3.position) / 2.;
let p6 = (v3.position + v1.position) / 2.;
self.mvert.extend(vec![
MVert{
position: p4,
normal: vec3!(0.),
flag: v1.flag,
bweight: v1.bweight,
pad: unsafe{ mem::MaybeUninit::uninit().assume_init() },
},
MVert{
position: p5,
normal: vec3!(0.),
flag: v2.flag,
bweight: v2.bweight,
pad: unsafe{ mem::MaybeUninit::uninit().assume_init() },
},
MVert{
position: p6,
normal: vec3!(0.),
flag: v3.flag,
bweight: v3.bweight,
pad: unsafe{ mem::MaybeUninit::uninit().assume_init() },
}
]);
let i1 = self.mloop[poly.loopstart as usize].v;
let i2 = self.mloop[poly.loopstart as usize + 1].v;
let i3 = self.mloop[poly.loopstart as usize + 2].v;
let i1_2 = (self.mvert.len() - 3) as u32;
let i2_3 = (self.mvert.len() - 2) as u32;
let i3_1 = (self.mvert.len() - 1) as u32;
let e1 = self.medge[edges_index[&hash(i1, i2)]];
let e2 = self.medge[edges_index[&hash(i2, i3)]];
let e3 = self.medge[edges_index[&hash(i3, i1)]];
let new_edge_indices = vec![
edge_index_or_insert(MEdge{
v1: i1,
v2: i1_2,
crease: e1.crease,
bweight: e1.bweight,
flag: e1.flag,
}),
edge_index_or_insert(MEdge{
v1: i1_2,
v2: i3_1,
crease: e1.crease | e3.crease,
bweight: (e1.bweight + e3.bweight) / 2,
flag: e1.flag | e3.flag,
}),
edge_index_or_insert(MEdge{
v1: i3_1,
v2: i1,
crease: e3.crease,
bweight: e3.bweight,
flag: e3.flag,
}),
edge_index_or_insert(MEdge{
v1: i1_2,
v2: i2,
crease: e1.crease,
bweight: e1.bweight,
flag: e1.flag,
}),
edge_index_or_insert(MEdge{
v1: i2,
v2: i2_3,
crease: e2.crease,
bweight: e2.bweight,
flag: e2.flag,
}),
edge_index_or_insert(MEdge{
v1: i2_3,
v2: i1_2,
crease: e1.crease | e2.crease,
bweight: (e1.bweight + e2.bweight) / 2,
flag: e1.flag | e2.flag,
}),
edge_index_or_insert(MEdge{
v1: i1_2,
v2: i2_3,
crease: e1.crease | e2.crease,
bweight: (e1.bweight + e2.bweight) / 2,
flag: e1.flag | e2.flag,
}),
edge_index_or_insert(MEdge{
v1: i2_3,
v2: i3_1,
crease: e2.crease | e3.crease,
bweight: (e2.bweight + e3.bweight) / 2,
flag: e2.flag | e3.flag,
}),
edge_index_or_insert(MEdge{
v1: i3_1,
v2: i1_2,
crease: e1.crease | e3.crease,
bweight: (e1.bweight + e3.bweight) / 2,
flag: e1.flag | e3.flag,
}),
edge_index_or_insert(MEdge{
v1: i3_1,
v2: i2_3,
crease: e2.crease | e3.crease,
bweight: (e2.bweight + e3.bweight) / 2,
flag: e2.flag | e3.flag,
}),
edge_index_or_insert(MEdge{
v1: i2_3,
v2: i3,
crease: e2.crease,
bweight: e2.bweight,
flag: e2.flag,
}),
edge_index_or_insert(MEdge{
v1: i3,
v2: i3_1,
crease: e3.crease,
bweight: e3.bweight,
flag: e3.flag,
}),
];
let i1 = MLoop{ v: i1, e: 0 };
let i2 = MLoop{ v: i2, e: 0 };
let i3 = MLoop{ v: i3, e: 0 };
let i1_2 = MLoop{ v: i1_2, e: 0 };
let i2_3 = MLoop{ v: i2_3, e: 0 };
let i3_1 = MLoop{ v: i3_1, e: 0 };
new_loops.extend(vec![
i1, i1_2, i3_1,
i1_2, i2, i2_3,
i1_2, i2_3, i3_1,
i3_1, i2_3, i3
]);
let start = new_loops.len() - 12;
for (edge, mloop) in new_loops[start .. ].iter_mut().enumerate() {
mloop.e = new_edge_indices[edge];
}
if subdivide_uvs {
let uv1 = self.mloopuv[poly.loopstart as usize];
let uv2 = self.mloopuv[poly.loopstart as usize + 1];
let uv3 = self.mloopuv[poly.loopstart as usize + 2];
let uv1_2 = MLoopUV{uv: (uv1.uv + uv2.uv) / 2., flag: uv1.flag};
let uv2_3 = MLoopUV{uv: (uv2.uv + uv3.uv) / 2., flag: uv2.flag};
let uv3_1 = MLoopUV{uv: (uv3.uv + uv1.uv) / 2., flag: uv3.flag};
new_uvloops.extend(vec![
uv1, uv1_2, uv3_1,
uv1_2, uv2, uv2_3,
uv1_2, uv2_3, uv3_1,
uv3_1, uv2_3, uv3
]);
}
new_polys.extend(vec![
MPoly{
loopstart: new_loops.len() as u32 - 12,
totloop: 3,
mat_nr: poly.mat_nr,
flag: poly.flag,
pad: 0,
},
MPoly{
loopstart: new_loops.len() as u32 - 9,
totloop: 3,
mat_nr: poly.mat_nr,
flag: poly.flag,
pad: 0,
},
MPoly{
loopstart: new_loops.len() as u32 - 6,
totloop: 3,
mat_nr: poly.mat_nr,
flag: poly.flag,
pad: 0,
},
MPoly{
loopstart: new_loops.len() as u32 - 3,
totloop: 3,
mat_nr: poly.mat_nr,
flag: poly.flag,
pad: 0,
},
]);
}else if poly.totloop == 4 {
let v1 = self.mvert[self.mloop[poly.loopstart as usize].v as usize];
let v2 = self.mvert[self.mloop[poly.loopstart as usize + 1].v as usize];
let v3 = self.mvert[self.mloop[poly.loopstart as usize + 2].v as usize];
let v4 = self.mvert[self.mloop[poly.loopstart as usize + 3].v as usize];
let centroid = (v1.position + v2.position + v3.position + v4.position) / 4.;
let p4 = (v1.position + v2.position) / 2.;
let p5 = (v2.position + v3.position) / 2.;
let p6 = (v3.position + v4.position) / 2.;
let p7 = (v4.position + v1.position) / 2.;
self.mvert.push(MVert{
position: centroid,
normal: vec3!(0.),
flag: self.mvert[self.mloop[poly.loopstart as usize].v as usize].flag,
bweight: self.mvert[self.mloop[poly.loopstart as usize].v as usize].bweight,
pad: unsafe{ mem::MaybeUninit::uninit().assume_init() },
});
self.mvert.extend(vec![
MVert{
position: p4,
normal: vec3!(0.),
flag: v1.flag,
bweight: v1.bweight,
pad: unsafe{ mem::MaybeUninit::uninit().assume_init() },
},
MVert{
position: p5,
normal: vec3!(0.),
flag: v2.flag,
bweight: v2.bweight,
pad: unsafe{ mem::MaybeUninit::uninit().assume_init() },
},
MVert{
position: p6,
normal: vec3!(0.),
flag: v3.flag,
bweight: v3.bweight,
pad: unsafe{ mem::MaybeUninit::uninit().assume_init() },
},
MVert{
position: p7,
normal: vec3!(0.),
flag: v4.flag,
bweight: v4.bweight,
pad: unsafe{ mem::MaybeUninit::uninit().assume_init() },
}
]);
let i1 = self.mloop[poly.loopstart as usize].v;
let i2 = self.mloop[poly.loopstart as usize + 1].v;
let i3 = self.mloop[poly.loopstart as usize + 2].v;
let i4 = self.mloop[poly.loopstart as usize + 3].v;
let ic = (self.mvert.len() - 5) as u32;
let i1_2 = (self.mvert.len() - 4) as u32;
let i2_3 = (self.mvert.len() - 3) as u32;
let i3_4 = (self.mvert.len() - 2) as u32;
let i4_1 = (self.mvert.len() - 1) as u32;
let e1 = self.medge[edges_index[&hash(i1, i2)]];
let e2 = self.medge[edges_index[&hash(i2, i3)]];
let e3 = self.medge[edges_index[&hash(i3, i4)]];
let e4 = self.medge[edges_index[&hash(i4, i1)]];
let new_edge_indices = vec![
edge_index_or_insert(MEdge{
v1: i1,
v2: i1_2,
crease: e1.crease,
bweight: e1.bweight,
flag: e1.flag,
}),
edge_index_or_insert(MEdge{
v1: i1_2,
v2: ic,
crease: e1.crease,
bweight: e1.bweight,
flag: e1.flag,
}),
edge_index_or_insert(MEdge{
v1: ic,
v2: i4_1,
crease: e4.crease,
bweight: e4.bweight,
flag: e4.flag,
}),
edge_index_or_insert(MEdge{
v1: i4_1,
v2: i1,
crease: e4.crease,
bweight: e4.bweight,
flag: e4.flag,
}),
edge_index_or_insert(MEdge{
v1: i1_2,
v2: i2,
crease: e1.crease,
bweight: e1.bweight,
flag: e1.flag,
}),
edge_index_or_insert(MEdge{
v1: i2,
v2: i2_3,
crease: e2.crease,
bweight: e2.bweight,
flag: e2.flag,
}),
edge_index_or_insert(MEdge{
v1: i2_3,
v2: ic,
crease: e2.crease,
bweight: e2.bweight,
flag: e2.flag,
}),
edge_index_or_insert(MEdge{
v1: ic,
v2: i1_2,
crease: e1.crease,
bweight: e1.bweight,
flag: e1.flag,
}),
edge_index_or_insert(MEdge{
v1: ic,
v2: i2_3,
crease: e2.crease,
bweight: e2.bweight,
flag: e2.flag,
}),
edge_index_or_insert(MEdge{
v1: i2_3,
v2: i3,
crease: e2.crease,
bweight: e2.bweight,
flag: e2.flag,
}),
edge_index_or_insert(MEdge{
v1: i3,
v2: i3_4,
crease: e3.crease,
bweight: e3.bweight,
flag: e3.flag,
}),
edge_index_or_insert(MEdge{
v1: i3_4,
v2: ic,
crease: e3.crease,
bweight: e3.bweight,
flag: e3.flag,
}),
edge_index_or_insert(MEdge{
v1: i4_1,
v2: ic,
crease: e4.crease,
bweight: e4.bweight,
flag: e4.flag,
}),
edge_index_or_insert(MEdge{
v1: ic,
v2: i3_4,
crease: e3.crease,
bweight: e3.bweight,
flag: e3.flag,
}),
edge_index_or_insert(MEdge{
v1: i3_4,
v2: i4,
crease: e3.crease,
bweight: e3.bweight,
flag: e3.flag,
}),
edge_index_or_insert(MEdge{
v1: i4,
v2: i4_1,
crease: e4.crease,
bweight: e4.bweight,
flag: e4.flag,
}),
];
let i1 = MLoop{ v: i1, e: 0 };
let i2 = MLoop{ v: i2, e: 0 };
let i3 = MLoop{ v: i3, e: 0 };
let i4 = MLoop{ v: i4, e: 0 };
let ic = MLoop{ v: ic, e: 0 };
let i1_2 = MLoop{ v: i1_2, e: 0 };
let i2_3 = MLoop{ v: i2_3, e: 0 };
let i3_4 = MLoop{ v: i3_4, e: 0 };
let i4_1 = MLoop{ v: i4_1, e: 0 };
new_loops.extend(vec![
i1, i1_2, ic, i4_1,
i1_2, i2, i2_3, ic,
ic, i2_3, i3, i3_4,
i4_1, ic, i3_4, i4
]);
let start = new_loops.len() - 16;
for (edge, mloop) in new_loops[start .. ].iter_mut().enumerate() {
mloop.e = new_edge_indices[edge];
}
if subdivide_uvs {
let uv1 = self.mloopuv[poly.loopstart as usize];
let uv2 = self.mloopuv[poly.loopstart as usize + 1];
let uv3 = self.mloopuv[poly.loopstart as usize + 2];
let uv4 = self.mloopuv[poly.loopstart as usize + 3];
let uvc = MLoopUV{uv: (uv1.uv + uv2.uv + uv3.uv + uv4.uv) / 4., flag: uv1.flag};
let uv1_2 = MLoopUV{uv: (uv1.uv + uv2.uv) / 2., flag: uv1.flag};
let uv2_3 = MLoopUV{uv: (uv2.uv + uv3.uv) / 2., flag: uv1.flag};
let uv3_4 = MLoopUV{uv: (uv3.uv + uv4.uv) / 2., flag: uv1.flag};
let uv4_1 = MLoopUV{uv: (uv4.uv + uv1.uv) / 2., flag: uv1.flag};
new_uvloops.extend(vec![
uv1, uv1_2, uvc, uv4_1,
uv1_2, uv2, uv2_3, uvc,
uvc, uv2_3, uv3, uv3_4,
uv4_1, uvc, uv3_4, uv4
]);
}
new_polys.extend(vec![
MPoly{
loopstart: new_loops.len() as u32 - 16,
totloop: 4,
mat_nr: poly.mat_nr,
flag: poly.flag,
pad: 0,
},
MPoly{
loopstart: new_loops.len() as u32 - 12,
totloop: 4,
mat_nr: poly.mat_nr,
flag: poly.flag,
pad: 0,
},
MPoly{
loopstart: new_loops.len() as u32 - 8,
totloop: 4,
mat_nr: poly.mat_nr,
flag: poly.flag,
pad: 0,
},
MPoly{
loopstart: new_loops.len() as u32 - 4,
totloop: 4,
mat_nr: poly.mat_nr,
flag: poly.flag,
pad: 0,
},
]);
}else if poly.totloop >= 4 {
let mut centroid = (poly.loopstart .. poly.loopstart + poly.totloop)
.fold(vec3!(0.), |acc, i|{
acc + self.mvert[self.mloop[i as usize].v as usize].position
});
centroid /= poly.totloop as f32;
self.mvert.push(MVert{
position: centroid,
normal: vec3!(0.),
flag: self.mvert[self.mloop[poly.loopstart as usize].v as usize].flag,
bweight: self.mvert[self.mloop[poly.loopstart as usize].v as usize].bweight,
pad: unsafe{ mem::MaybeUninit::uninit().assume_init() },
});
let uv_centroid = if subdivide_uvs {
let mut uv_centroid = (poly.loopstart .. poly.loopstart + poly.totloop)
.fold(vec2!(0.), |acc, i|{
acc + self.mloopuv[i as usize].uv
});
uv_centroid /= poly.totloop as f32;
Some(MLoopUV{
uv: uv_centroid,
flag: self.mloopuv[poly.loopstart as usize].flag
})
}else{
None
};
for i in poly.loopstart .. poly.loopstart + poly.totloop {
let next = (i - poly.loopstart + 1) % poly.totloop + poly.loopstart;
let v1 = self.mloop[i as usize].v;
let v2 = self.mloop[next as usize].v;
let e = self.medge[edges_index[&hash(v1, v2)]];
let new_edges_indices = vec![
edge_index_or_insert(MEdge{
v1,
v2,
crease: e.crease,
bweight: e.bweight,
flag: e.flag,
}),
edge_index_or_insert(MEdge{
v1: v2,
v2: (self.mvert.len() - 1) as u32,
crease: e.crease,
bweight: e.bweight,
flag: e.flag,
}),
edge_index_or_insert(MEdge{
v1: (self.mvert.len() - 1) as u32,
v2: v1,
crease: e.crease,
bweight: e.bweight,
flag: e.flag,
}),
];
new_loops.extend(vec![
MLoop {
v: v1,
e: new_edges_indices[0],
},
MLoop {
v: v2,
e: new_edges_indices[1],
},
MLoop {
v: (self.mvert.len() - 1) as u32,
e: new_edges_indices[2],
},
]);
if subdivide_uvs {
new_uvloops.extend(vec![
self.mloopuv[i as usize],
self.mloopuv[next as usize],
uv_centroid.unwrap(),
]);
}
new_polys.push(MPoly{
loopstart: new_loops.len() as u32 - 3,
totloop: 3,
mat_nr: poly.mat_nr,
flag: poly.flag,
pad: 0,
});
}
}
}
self.mloop = new_loops;
self.mpoly = new_polys;
self.mloopuv = new_uvloops;
self.medge = new_edges;
}
}