151 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Rust
		
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Rust
		
	
	
	
| use glam::Vec3;
 | |
| 
 | |
| use crate::{
 | |
|     aabb::Aabb,
 | |
|     math,
 | |
|     plane::{Plane, PlaneIntersection},
 | |
| };
 | |
| 
 | |
| #[derive(Default, Debug, Clone)]
 | |
| pub struct MaterialId(pub String);
 | |
| 
 | |
| #[derive(Debug, Clone, Copy)]
 | |
| pub struct TextureProjection {
 | |
|     pub u: Plane,
 | |
|     pub v: Plane,
 | |
| }
 | |
| 
 | |
| impl Default for TextureProjection {
 | |
|     fn default() -> Self {
 | |
|         Self {
 | |
|             u: Plane {
 | |
|                 normal: glam::vec3(1.0, 0.0, 0.0),
 | |
|                 offset: 0.0,
 | |
|             },
 | |
|             v: Plane {
 | |
|                 normal: glam::vec3(0.0, 1.0, 0.0),
 | |
|                 offset: 0.0,
 | |
|             },
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[derive(Default, Debug, Clone)]
 | |
| pub struct BrushPlane {
 | |
|     pub plane: Plane,
 | |
|     pub material: MaterialId,
 | |
|     pub tex_projection: TextureProjection,
 | |
| }
 | |
| 
 | |
| pub struct Brush {
 | |
|     pub planes: Vec<BrushPlane>,
 | |
|     raw_vertices: Vec<PlaneIntersection>,
 | |
|     vertices: Vec<Vec3>,
 | |
|     aabb: Aabb,
 | |
| }
 | |
| 
 | |
| impl Brush {
 | |
|     pub fn new(planes: &[BrushPlane]) -> Self {
 | |
|         Self {
 | |
|             planes: planes.to_vec(),
 | |
|             raw_vertices: vec![],
 | |
|             vertices: vec![],
 | |
|             aabb: Aabb::new(),
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub fn rebuild(&mut self) {
 | |
|         if self.planes.len() < 4 {
 | |
|             panic!("Invalid number of planes. Minimum 4 planes required.");
 | |
|         }
 | |
| 
 | |
|         self.calculate_raw_vertices();
 | |
|         self.merge_vertices();
 | |
|         self.aabb = Aabb::from_positions(&self.vertices);
 | |
|     }
 | |
| 
 | |
|     pub fn aabb_intersects_with(&self, other: &Brush) -> bool {
 | |
|         self.aabb.intersects(other.get_aabb())
 | |
|     }
 | |
| 
 | |
|     pub fn planes_intersect_with(&self, other: &Brush) -> bool {
 | |
|         // Check our vertices against their planes
 | |
|         for v in &self.vertices {
 | |
|             let mut iter = other.planes.iter();
 | |
|             if iter.all(|bp| bp.plane.point_in_halfspace(*v)) {
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Check their vertices against our planes
 | |
|         for v in &other.vertices {
 | |
|             let mut iter = self.planes.iter();
 | |
|             if iter.all(|bp| bp.plane.point_in_halfspace(*v)) {
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         false
 | |
|     }
 | |
| 
 | |
|     pub fn get_vertices(&self) -> Vec<Vec3> {
 | |
|         self.vertices.clone()
 | |
|     }
 | |
| 
 | |
|     pub fn get_intersections(&self) -> Vec<PlaneIntersection> {
 | |
|         self.raw_vertices.clone()
 | |
|     }
 | |
| 
 | |
|     pub fn get_aabb(&self) -> &Aabb {
 | |
|         &self.aabb
 | |
|     }
 | |
| 
 | |
|     fn calculate_raw_vertices(&mut self) {
 | |
|         // Test all combinations of brush planes for intersections
 | |
|         // I experimented with Itertools::(tuple_)combinations instead of this nested loop
 | |
|         // but it was about 2x slower
 | |
|         // TODO: Experiment more
 | |
|         let mut intersections = vec![];
 | |
|         let len = self.planes.len();
 | |
|         for i in 0..(len - 2) {
 | |
|             for j in (i + 1)..(len - 1) {
 | |
|                 for k in (j + 1)..len {
 | |
|                     if let Some(intersection) = PlaneIntersection::from_planes(
 | |
|                         self.planes[i].plane,
 | |
|                         self.planes[j].plane,
 | |
|                         self.planes[k].plane,
 | |
|                     ) {
 | |
|                         intersections.push(intersection)
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Validate intersections against other brush planes
 | |
|         // Intersections only produce vertices if they're in the half-space of every
 | |
|         // plane in the brush.
 | |
|         // TODO: No need to check against planes that are part of the intersection
 | |
|         let mut raw_vertices = vec![];
 | |
|         for intersection in &intersections {
 | |
|             let mut iter = self.planes.iter();
 | |
|             if iter.all(|bplane| intersection.in_halfspace_mat(&bplane.plane)) {
 | |
|                 raw_vertices.push(*intersection);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         self.raw_vertices = raw_vertices;
 | |
|     }
 | |
| 
 | |
|     fn merge_vertices(&mut self) {
 | |
|         let mut vs: Vec<Vec3> = vec![];
 | |
|         for intersection in &self.raw_vertices {
 | |
|             let point = intersection.get_intersection_point();
 | |
|             if !vs.iter().any(|v| v.abs_diff_eq(point, math::EPSILON)) {
 | |
|                 vs.push(point);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         self.vertices = vs;
 | |
|     }
 | |
| }
 |