use crate::{ffi, layouts::impl_bvh_deref, Error};
use std::{fmt::Debug, marker::PhantomData};
#[repr(C)]
#[derive(Clone, Copy, Default, Debug, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
pub struct Node {
pub min: [f32; 3],
pub left_first: u32,
pub max: [f32; 3],
pub tri_count: u32,
}
impl Node {
pub fn is_leaf(&self) -> bool {
self.tri_count > 0
}
}
pub struct BVHData {
pub(crate) inner: cxx::UniquePtr<ffi::BVH>,
pub(crate) max_primitives_per_leaf: Option<u32>,
pub(crate) primitives_len: u32,
}
impl BVHData {
fn new() -> Self {
Self {
inner: ffi::BVH_new(),
max_primitives_per_leaf: None,
primitives_len: 0,
}
}
pub fn bvh<'a>(self, primitives: crate::Positions<'a>) -> Result<BVH<'a>, Error> {
BVH {
bvh: self,
_phantom: PhantomData,
}
.bind(primitives)
}
pub fn primitive_count(&self, id: u32) -> u32 {
self.inner.PrimCount(id) as u32
}
pub fn sah_cost(&self, id: u32) -> f32 {
self.inner.SAHCost(id)
}
pub fn nodes(&self) -> &[Node] {
ffi::BVH_nodes(&self.inner)
}
pub fn indices(&self) -> &[u32] {
ffi::BVH_indices(&self.inner)
}
pub fn refittable(&self) -> bool {
ffi::BVH_refittable(&self.inner)
}
}
pub struct BVH<'a> {
pub(crate) bvh: BVHData,
_phantom: PhantomData<&'a [f32; 4]>,
}
impl_bvh_deref!(BVH<'a>, BVHData);
impl<'a> BVH<'a> {
pub fn new(primitives: crate::Positions<'a>) -> Result<Self, Error> {
Self {
bvh: BVHData::new(),
_phantom: PhantomData,
}
.build(primitives)
}
pub fn new_hq(primitives: crate::Positions<'a>) -> Result<Self, Error> {
Self {
bvh: BVHData::new(),
_phantom: PhantomData,
}
.build_hq(primitives)
}
pub fn build<'b>(self, primitives: crate::Positions<'b>) -> Result<BVH<'b>, Error> {
Error::validate_triangulated(primitives.len())?;
let slice = primitives.into();
let mut bvh = self.bvh;
bvh.inner.pin_mut().Build(&slice);
Ok(BVH::build_internal(bvh, primitives))
}
pub fn build_hq<'b>(self, primitives: crate::Positions<'b>) -> Result<BVH<'b>, Error> {
Error::validate_triangulated(primitives.len())?;
let slice = primitives.into();
let mut bvh = self.bvh;
bvh.inner.pin_mut().BuildHQ(&slice);
Ok(BVH::build_internal(bvh, primitives))
}
pub fn bind<'b>(self, primitives: crate::Positions<'b>) -> Result<BVH<'b>, Error> {
let mut bvh = self.bvh;
Error::validate_primitives_len(bvh.primitives_len, primitives.len() as u32)?;
let slice = primitives.into();
ffi::BVH_setPrimitives(bvh.inner.pin_mut(), &slice);
Ok(BVH {
bvh,
_phantom: PhantomData,
})
}
pub fn compact(&mut self) {
self.bvh.inner.pin_mut().Compact();
}
pub fn split_leaves(&mut self, max_primitives: u32) {
self.bvh.inner.pin_mut().SplitLeafs(max_primitives);
let max_prim = self.bvh.max_primitives_per_leaf.unwrap_or(u32::MAX);
self.bvh.max_primitives_per_leaf = Some(u32::min(max_prim, max_primitives));
}
pub fn refit(&mut self) {
if self.refittable() {
self.bvh.inner.pin_mut().Refit(0);
}
}
pub fn data(self) -> BVHData {
self.bvh
}
fn build_internal<'b>(mut bvh: BVHData, primitives: crate::Positions<'b>) -> BVH<'b> {
bvh.max_primitives_per_leaf = None;
bvh.primitives_len = primitives.len() as u32;
BVH {
bvh,
_phantom: PhantomData,
}
}
}
impl crate::Intersector for BVH<'_> {
fn intersect(&self, ray: &mut crate::Ray) -> u32 {
self.bvh.inner.Intersect(ray) as u32
}
}