use crate::{Vec3, Vec3i, Vec3u};
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct Plane {
pub normal: Vec3,
pub bias: f32,
}
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct Ray {
pub origin: Vec3,
pub direction: Vec3,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct Planeu {
pub normal: Vec3u,
pub bias: u32,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct Rayu {
pub origin: Vec3u,
pub direction: Vec3u,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct Planei {
pub normal: Vec3i,
pub bias: i32,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct Rayi {
pub origin: Vec3i,
pub direction: Vec3i,
}
macro_rules! impl_plane_ray {
($($pn:ident, $rn:ident, $v3t:ident => $t:ident),+) => {
$(
impl $rn {
#[inline]
pub fn intersect_plane(&self, plane: $pn) -> Option<$t> {
plane.intersect_ray(*self)
}
#[inline]
pub fn at_distance(&self, z: $t) -> $v3t {
self.direction.mul_add($v3t::broadcast(z), self.origin)
}
}
impl $pn {
#[inline]
pub fn new(normal: $v3t, bias: $t) -> Self {
$pn { normal, bias }
}
#[inline]
pub fn from_point_normal(point: $v3t, normal: $v3t) -> Self {
Self {
normal,
bias: point.dot(normal),
}
}
#[inline]
pub fn from_point_vectors(point: $v3t, v1: $v3t, v2: $v3t) -> Self {
Self::from_point_normal(point, v1.cross(v2))
}
#[inline]
pub fn with_x(x: $t) -> Self {
Self::from_point_normal($v3t::new(x, 0 as $t, 0 as $t), $v3t::new(1 as $t, 0 as $t, 0 as $t,))
}
#[inline]
pub fn with_y(y: $t) -> Self {
Self::from_point_normal($v3t::new(0 as $t, y, 0 as $t), $v3t::new(0 as $t, 1 as $t, 0 as $t))
}
#[inline]
pub fn with_z(z: $t) -> Self {
Self::from_point_normal($v3t::new(0 as $t, 0 as $t, z), $v3t::new(0 as $t, 0 as $t, 1 as $t))
}
#[inline]
pub fn normal(&self) -> $v3t {
self.normal
}
#[inline]
pub fn normalize(&mut self) {
let distance = self.normal.mag();
self.normal /= distance;
self.bias /= distance;
}
#[inline]
pub fn normalized(&self) -> Self {
let distance = self.normal.mag();
Self {
normal: self.normal / distance,
bias: self.bias / distance,
}
}
#[inline]
pub fn dot_point(&self, point: $v3t) -> $t {
self.normal.x * point.x + self.normal.y * point.y + self.normal.z * point.z + self.bias
}
#[inline]
pub fn dot(&self, point: $v3t) -> $t {
self.normal.x * point.x + self.normal.y * point.y + self.normal.z * point.z
}
#[inline]
pub fn dot_plane(&self, plane: $pn) -> $t {
self.normal.x * plane.normal.x
+ self.normal.y * plane.normal.y
+ self.normal.z * plane.normal.z
+ self.bias * plane.bias
}
#[inline]
pub fn intersect_line(&self, point: $v3t, direction: $v3t) -> Option<$t> {
let fv = self.dot(direction);
let distance = self.dot_point(point) / fv;
Some(distance)
}
#[inline]
pub fn intersect_ray(&self, ray: $rn) -> Option<$t> {
self.intersect_line(ray.origin, ray.direction)
}
}
)+
}
}
impl_plane_ray!(Plane, Ray, Vec3 => f32);
impl_plane_ray!(Planeu, Rayu, Vec3u => u32);
impl_plane_ray!(Planei, Rayi, Vec3i => i32);
#[derive(Default, Debug, Copy, Clone)]
#[repr(C)]
pub struct Aabb {
pub min: Vec3,
pub max: Vec3,
}
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct Aabbu {
pub min: Vec3u,
pub max: Vec3u,
}
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct Aabbi {
pub min: Vec3i,
pub max: Vec3i,
}
macro_rules! impl_aabb {
($($n:ident, $iter:ident, $v3t:ident => $t:ident),+) => {
$(
impl $n {
#[must_use]
pub fn new(min: $v3t, max: $v3t) -> Self {
Self { min, max }
}
#[inline]
#[must_use]
pub fn contains(&self, target: $v3t) -> bool {
target.x >= self.min.x
&& target.x <= self.max.x
&& target.y >= self.min.y
&& target.y <= self.max.y
&& target.z >= self.min.z
&& target.z <= self.max.z
}
#[inline]
#[must_use]
pub fn intersects(&self, other: &Self) -> bool {
(self.min.x <= other.max.x && self.max.x >= other.min.x)
&& (self.min.y <= other.max.y && self.max.y >= other.min.y)
&& (self.min.z <= other.max.z && self.max.z >= other.min.z)
}
#[inline]
#[must_use]
pub fn size(&self) -> $v3t {
self.max - self.min
}
#[inline]
#[must_use]
pub fn volume(&self) -> $t {
self.size().x * self.size().y * self.size().z
}
#[inline]
#[must_use]
pub fn iter_stride(&self, stride: $t) -> $iter {
$iter::new(*self, stride)
}
}
pub struct $iter {
stride: $t,
track: $v3t,
region: $n,
}
impl $iter {
#[must_use]
pub fn new(region: $n, stride: $t) -> Self {
Self {
track: region.min,
region,
stride,
}
}
}
impl Iterator for $iter {
type Item = $v3t;
fn next(&mut self) -> Option<Self::Item> {
let ret = self.track;
if self.track.z >= self.region.max.z {
return None;
}
if self.track.x >= self.region.max.x - (1 as $t) {
self.track.y += self.stride;
self.track.x = self.region.min.x;
} else {
self.track.x += self.stride;
return Some(ret);
}
if self.track.y >= self.region.max.y {
self.track.z += self.stride;
self.track.y = self.region.min.y;
}
Some(ret)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let cur_volume = ($n::new(self.track, self.region.max).volume() / self.stride / self.stride / self.stride) as usize;
let volume = (self.region.volume() / self.stride / self.stride / self.stride) as usize;
(volume - cur_volume, Some(volume))
}
}
impl ExactSizeIterator for $iter {}
)+
}
}
impl Aabb {
#[inline]
#[must_use]
pub fn iter(&self) -> AabbLinearIterator {
self.iter_stride(1.0)
}
}
impl Aabbu {
#[inline]
#[must_use]
pub fn iter(&self) -> AabbuLinearIterator {
self.iter_stride(1)
}
}
impl Aabbi {
#[inline]
#[must_use]
pub fn iter(&self) -> AabbiLinearIterator {
self.iter_stride(1)
}
}
impl_aabb!(Aabb, AabbLinearIterator, Vec3 => f32, Aabbu, AabbuLinearIterator, Vec3u => u32, Aabbi, AabbiLinearIterator, Vec3i => i32);