Skip to main content

tinybvh_rs/
lib.rs

1#![cfg_attr(not(doctest), doc = include_str!("../README.md"))]
2
3//! Safe rust wrapper for the C++ [tinybvh](https://github.com/jbikker/tinybvh) library.
4//!
5//! # Notes
6//!
7//! BVH layouts are splitted into:
8//! - `BVHData`: read-only operations
9//!     - Read nodes, and primitives slice
10//!     - SAH cost, etc...
11//! - `BVH`: Read-write operations
12//!     - Building, converting, refitting, etc...
13//!     - Implements `Deref` to access `BVHData` directly
14//!
15//! This is a pattern used throughout this crate to ensure maximum safety,
16//! since the tinybvh library stores reference to primitives and original BVH upon
17//! build and conversion.
18//!
19//! BVH layouts that manage their own primitives have no lifetime constraint.
20//! This is for instance the case for [`cwbvh::BVH`] and [`bvh8_cpu::BVH`].
21
22mod cxx_ffi;
23mod layouts;
24mod ray;
25mod traversal;
26
27use std::u32;
28
29pub(crate) use cxx_ffi::ffi;
30pub use layouts::*;
31pub use ray::*;
32pub use traversal::*;
33
34/// Infinite value used for intersection.
35///
36/// **NOTE**: This is not the same as `f32::MAX`.
37pub const INFINITE: f32 = 1e30; // Actual valid ieee range: 3.40282347E+38
38
39/// Alias for a strided slice of positions.
40///
41/// Positions do not need to be strided, but the API accepts a strided
42/// slice to support both use cases.
43///
44/// tinybvh-rs internally requires positions to be vectors of size **4**
45/// and not **3**. This is a requirement of the underlying tinybvh library.
46pub type Positions<'a> = pas::Slice<'a, [f32; 4]>;
47
48/// Error type for Wald BVH operations.
49#[derive(Clone, Copy, Debug, PartialEq)]
50pub enum Error {
51    /// Positions slice wasn't triangulated. Provided positions must be a multiple of 3.
52    PrimitiveTriangulated(usize),
53    /// BVH can only be re-bound to a positions slice with the same size.
54    BindInvalidPositionsLen(u32, u32),
55    /// BVH must have a maximum primitive count per leaf.
56    InvalidLeafCount(u32, u32),
57}
58
59impl Error {
60    pub(crate) fn validate_triangulated(prim_len: usize) -> Result<(), Error> {
61        if prim_len % 3 != 0 {
62            Err(Error::PrimitiveTriangulated(prim_len as usize))
63        } else {
64            Ok(())
65        }
66    }
67    pub(crate) fn validate_primitives_len(expected: u32, prim_count: u32) -> Result<(), Error> {
68        if expected != prim_count {
69            Err(Error::BindInvalidPositionsLen(expected, prim_count))
70        } else {
71            Ok(())
72        }
73    }
74    pub(crate) fn validate_leaf_count(expected: u32, count: Option<u32>) -> Result<(), Error> {
75        if Some(expected) != count {
76            Err(Error::InvalidLeafCount(expected, count.unwrap_or(u32::MAX)))
77        } else {
78            Ok(())
79        }
80    }
81}
82
83impl std::fmt::Display for Error {
84    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        match self {
86            Error::PrimitiveTriangulated(size) => {
87                write!(
88                    f,
89                    "primitives slice must triangulated (size multiple of 3), got {}",
90                    size
91                )
92            }
93            Error::BindInvalidPositionsLen(expected, size) => {
94                write!(
95                    f,
96                    "binding positions expected size {}, got {}",
97                    expected, size
98                )
99            }
100            Error::InvalidLeafCount(expected, size) => {
101                write!(f, "expected at most {} per leaf, got {}", expected, size)
102            }
103        }
104    }
105}