use crate::{Aabb, Chunk, Plane, Point, RayHit, Triangle, Uv};
use crate::triangle::{triangle_aabb, triangle_plane};
use cam::CameraPerspective;
#[derive(Copy, Clone, Debug)]
pub struct FrustumPlanes<T = f32> {
pub near: Plane<T>,
pub far: Plane<T>,
pub left: Plane<T>,
pub right: Plane<T>,
pub top: Plane<T>,
pub bottom: Plane<T>,
}
pub fn near_plane(persp: &CameraPerspective) -> Plane {
([0.0, 0.0, 1.0], -persp.near_clip)
}
pub fn far_plane(persp: &CameraPerspective) -> Plane {
([0.0, 0.0, -1.0], persp.far_clip)
}
pub fn near_dim(persp: &CameraPerspective) -> Uv {
use vecmath::traits::Radians;
let fov = persp.fov.deg_to_rad();
let near_height = 2.0 * persp.near_clip * (fov / 2.0).tan();
let near_width = near_height * persp.aspect_ratio;
[near_width, near_height]
}
pub fn near_uv_pos(persp: &CameraPerspective, dim: Uv, uv: Uv) -> Point {
[0.5 * dim[0] * uv[0], 0.5 * dim[1] * uv[1], persp.near_clip]
}
pub fn left_plane(persp: &CameraPerspective, dim: Uv, uv_x: f32) -> Plane {
let eye = [0.0; 3];
let top = near_uv_pos(persp, dim, [uv_x, -1.0]);
let bottom = near_uv_pos(persp, dim, [uv_x, 1.0]);
triangle_plane((eye, bottom, top))
}
pub fn right_plane(persp: &CameraPerspective, dim: Uv, uv_x: f32) -> Plane {
let eye = [0.0; 3];
let top = near_uv_pos(persp, dim, [uv_x, -1.0]);
let bottom = near_uv_pos(persp, dim, [uv_x, 1.0]);
triangle_plane((eye, top, bottom))
}
pub fn top_plane(persp: &CameraPerspective, dim: Uv, uv_y: f32) -> Plane {
let eye = [0.0; 3];
let left = near_uv_pos(persp, dim, [-1.0, uv_y]);
let right = near_uv_pos(persp, dim, [1.0, uv_y]);
triangle_plane((eye, right, left))
}
pub fn bottom_plane(persp: &CameraPerspective, dim: Uv, uv_y: f32) -> Plane {
let eye = [0.0; 3];
let left = near_uv_pos(persp, dim, [-1.0, uv_y]);
let right = near_uv_pos(persp, dim, [1.0, uv_y]);
triangle_plane((eye, left, right))
}
pub fn frustum_planes_tile(persp: &CameraPerspective, dim: Uv, tile_pos: Uv, tile_size: Uv) -> FrustumPlanes {
FrustumPlanes {
near: near_plane(persp),
far: far_plane(persp),
left: left_plane(persp, dim, tile_pos[0]),
right: right_plane(persp, dim, tile_pos[0] + tile_size[0]),
top: top_plane(persp, dim, tile_pos[1] + tile_size[1]),
bottom: bottom_plane(persp, dim, tile_pos[1]),
}
}
pub fn plane_point_front((n, d): Plane, p: Point) -> bool {
use vecmath::vec3_dot as dot;
let d2 = dot(n, p) + d;
d2 >= 0.0
}
pub fn plane_aabb_front_or_intersect(p: Plane, (mi, ma): Aabb) -> bool {
plane_point_front(p, mi) ||
plane_point_front(p, [ma[0], mi[1], mi[2]]) ||
plane_point_front(p, [mi[0], ma[1], mi[2]]) ||
plane_point_front(p, [ma[0], ma[1], mi[2]]) ||
plane_point_front(p, [mi[0], mi[1], ma[2]]) ||
plane_point_front(p, [ma[0], mi[1], ma[2]]) ||
plane_point_front(p, [mi[0], ma[1], ma[2]]) ||
plane_point_front(p, ma)
}
pub fn frustum_planes_aabb_intersect(fr: &FrustumPlanes, a: Aabb) -> bool {
plane_aabb_front_or_intersect(fr.near, a) &&
plane_aabb_front_or_intersect(fr.far, a) &&
plane_aabb_front_or_intersect(fr.left, a) &&
plane_aabb_front_or_intersect(fr.right, a) &&
plane_aabb_front_or_intersect(fr.top, a) &&
plane_aabb_front_or_intersect(fr.bottom, a)
}
pub fn frustum_planes_triangle_chunk_mask(
fr: &FrustumPlanes,
chunk: &Chunk<Triangle>,
bits: u64
) -> u64 {
if bits == 0 {return 0};
let mut mask: u64 = 0;
for i in 0..64 {
if (bits >> i) & 1 != 1 {continue};
if frustum_planes_aabb_intersect(fr, triangle_aabb(chunk[i])) {
mask |= 1 << i;
}
}
mask
}
pub fn depth_linear(persp: &CameraPerspective, depth: RayHit) -> f32 {
if let Some((t, _)) = depth {
(t - persp.near_clip) / (persp.far_clip - persp.near_clip)
} else {
1.0
}
}