Skip to main content

tinybvh_rs/layouts/
mbvh.rs

1use std::{fmt::Debug, marker::PhantomData};
2
3use crate::{bvh, ffi, layouts::impl_bvh_deref, Error};
4
5/// M-wide (aka 'shallow') BVH layout.
6///
7/// More information on the tinybvh repository (`MBVH::MBVHNode` struct).
8#[repr(C)]
9#[derive(Clone, Copy, Default, Debug, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
10pub struct Node {
11    pub aabb_min: [f32; 3],
12    pub first_tri: u32,
13    pub aabb_max: [f32; 3],
14    pub tri_count: u32,
15    pub child: [u32; 8],
16    pub child_count: u32,
17    pub dummy: [u32; ((30 - 8) & 3) + 1],
18}
19
20impl Node {
21    /// Returns `true` if the node is a leaf.
22    pub fn is_leaf(&self) -> bool {
23        self.tri_count > 0
24    }
25}
26
27/// Read-write BVH data.
28pub struct BVHData {
29    pub(crate) inner: cxx::UniquePtr<ffi::MBVH8>,
30    pub(crate) max_primitives_per_leaf: Option<u32>,
31    pub(crate) primitives_len: u32,
32}
33
34impl BVHData {
35    /// Number of leaf in the hierarchy starting at `node_index`.
36    pub fn leaf_count(&self, node_index: u32) -> u32 {
37        self.inner.LeafCount(node_index)
38    }
39
40    /// Move this instance into a writable BVH.
41    ///
42    /// More information on [`bvh::BVHData::bvh`].
43    pub fn bvh<'a>(self, original: &'a bvh::BVH<'a>) -> Result<BVH<'a>, Error> {
44        BVH::wrap(self).bind(original)
45    }
46
47    /// Shortcut for:
48    ///
49    /// ```ignore
50    /// mbvh.bvh(&original).convert(&original)
51    /// ```
52    pub fn convert<'a>(self, original: &'a bvh::BVH<'a>) -> BVH<'a> {
53        BVH::wrap(self).convert(original)
54    }
55
56    /// BVH nodes.
57    pub fn nodes(&self) -> &[Node] {
58        ffi::MBVH8_nodes(&self.inner)
59    }
60}
61
62/// Read-write BVH data.
63///
64/// BVH isn't built from primitives but from converting [`bvh::BVH`].
65pub struct BVH<'a> {
66    bvh: BVHData,
67    _phantom: PhantomData<bvh::BVH<'a>>,
68}
69impl_bvh_deref!(BVH<'a>, BVHData);
70
71impl<'a> BVH<'a> {
72    fn wrap(bvh: BVHData) -> Self {
73        Self {
74            bvh,
75            _phantom: PhantomData,
76        }
77    }
78
79    /// Create a new BVH converting `original`.
80    pub fn new(original: &'a bvh::BVH) -> Self {
81        let data = BVHData {
82            inner: ffi::MBVH8_new(),
83            max_primitives_per_leaf: None,
84            primitives_len: 0,
85        };
86        data.convert(original)
87    }
88
89    /// Update the original BVH reference.
90    ///
91    /// Note: At the opposite of [`BVH::convert`], no rebuild is performed.
92    ///
93    /// # Examples
94    ///
95    /// ```rust
96    /// # use tinybvh_rs::{bvh, mbvh};
97    /// # let triangles = vec![[0.0; 4], [0.0; 4], [0.0; 4]];
98    /// let bvh = bvh::BVH::new(triangles.as_slice().into()).unwrap();
99    /// let mbvh = mbvh::BVH::new(&bvh);
100    ///
101    /// let other_bvh = bvh::BVH::new(triangles.as_slice().into()).unwrap();
102    /// let mbvh = mbvh.bind(&other_bvh);
103    /// ```
104    pub fn bind<'b>(self, original: &'b bvh::BVH) -> Result<BVH<'b>, Error> {
105        let mut bvh = self.bvh;
106        crate::Error::validate_primitives_len(bvh.primitives_len, original.primitives_len)?;
107        ffi::MBVH8_setBVH(bvh.inner.pin_mut(), &original.bvh.inner);
108        Ok(BVH::wrap(bvh))
109    }
110
111    /// Convert (i.e., build) the BVH and bind it to `original`.
112    ///
113    /// More information on the tinybvh repository (`MBVH::ConvertFrom()` method).
114    pub fn convert<'b>(self, original: &'b bvh::BVH) -> BVH<'b> {
115        let mut bvh = self.bvh;
116        bvh.inner
117            .pin_mut()
118            .ConvertFrom(original.bvh.inner.as_ref().unwrap(), true);
119        bvh.max_primitives_per_leaf = original.max_primitives_per_leaf;
120        bvh.primitives_len = original.primitives_len;
121        BVH::wrap(bvh)
122    }
123
124    /// Refits the BVH.
125    ///
126    /// More information on the tinybvh repository (`MBVH::Refit()` method).
127    pub fn refit(&mut self, node_index: u32) {
128        self.bvh.inner.pin_mut().Refit(node_index);
129    }
130
131    /// Move the BVH into read-only state.
132    pub fn data(self) -> BVHData {
133        self.bvh
134    }
135}