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;
|
|
}
|
|
}
|