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}