diff --git a/lib/bsp_loader/src/brush.rs b/lib/bsp_loader/src/brush.rs index a14a9b2..2eed980 100644 --- a/lib/bsp_loader/src/brush.rs +++ b/lib/bsp_loader/src/brush.rs @@ -34,6 +34,7 @@ pub enum BrushToMeshError{ InvalidFaceCount{ count:usize, }, + InvalidPlanes, } impl std::fmt::Display for BrushToMeshError{ fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ @@ -43,6 +44,7 @@ impl std::fmt::Display for BrushToMeshError{ impl core::error::Error for BrushToMeshError{} fn planes_to_faces(face_list:Vec<Face>)->Option<Faces>{ + let mut faces=Vec::new(); // for each face, determine one edge at a time until you complete the face let mut dedup=std::collections::HashSet::new(); 'face: for face0 in &face_list{ @@ -136,33 +138,58 @@ fn planes_to_faces(face_list:Vec<Face>)->Option<Faces>{ } // === follow edges around face === - // Note that we chose face2 so that the faces create a particular winding order. + // Note that we chose face2 such that the 3 faces create a particular winding order. // If we choose a consistent face to follow (face1, face2) it will always wind with a consistent chirality + // keep looping until we meet this face again + let face1=face1; + let mut face=Vec::new(); loop{ + // push point onto vertices + face.push(intersection.divide().fix_1()); + // the measure let edge_dir=face0.normal.cross(face1.normal); // the dot product to beat let d_intersection=edge_dir.dot(intersection.num)/intersection.den; - for new_face in &face_list{ - if core::ptr::eq(face0,new_face){ - continue; + // find the next face moving clockwise around face0 + let (new_face,new_intersection,_)=face_list.iter().filter_map(|new_face|{ + // ignore faces we've seen before + if core::ptr::eq(face0,new_face) + |core::ptr::eq(face2,new_face){ + return None; } - if core::ptr::eq(face1,new_face){ - continue; - } - if core::ptr::eq(face2,new_face){ - continue; - } - if let Some(new_intersection)=solve3(new_face,face1,face2){ + let new_intersection=solve3(face0,face2,new_face)?; + + // the d value must be larger + let d_new_intersection=edge_dir.dot(new_intersection.num)/new_intersection.den; + if d_new_intersection.le_ratio(d_intersection){ + return None; } + Some((new_face,new_intersection,d_new_intersection)) + }).min_by_key(|&(_,_,d)|d)?; + + // we looped back around to face1, we're done! + if core::ptr::eq(face1,new_face){ + break; } + + face2=new_face; + intersection=new_intersection; } + + faces.push(face); } - None + if faces.is_empty(){ + None + }else{ + Some(Faces{ + faces, + }) + } } pub fn brush_to_mesh(bsp:&vbsp::Bsp,brush:&vbsp::Brush)->Result<model::Mesh,BrushToMeshError>{ @@ -181,7 +208,7 @@ pub fn brush_to_mesh(bsp:&vbsp::Bsp,brush:&vbsp::Brush)->Result<model::Mesh,Brus return Err(BrushToMeshError::InvalidFaceCount{count:face_list.len()}); } - let faces=planes_to_faces(face_list)?; + let faces=planes_to_faces(face_list).ok_or(BrushToMeshError::InvalidPlanes)?; // generate the mesh let mut polygon_list=Vec::new();