use std::{
any::Any, cell::UnsafeCell, collections::HashMap, marker::PhantomData, ptr, sync::Mutex,
};
use crate::{
buffer::required_layout_bytes, callback::ErasedFn, sys::*, Bounds, Buffer, BufferData,
BufferLayout, BufferSize, BufferSource, BufferUsage, BufferView, BufferViewMut, BuildQuality,
Device, Error, Format, GeometryKind, Hit, HitN, IntersectContext, QuaternionDecomposition, Ray,
RayN, Scene, SoAHit, SubdivisionMode, UserData,
};
use std::{
borrow::Cow,
ops::{Bound, Deref, DerefMut, Index, IndexMut, RangeBounds},
os::raw::c_void,
sync::Arc,
};
#[derive(Debug)]
pub(crate) enum AttachedBuffer<'buf> {
Managed {
buffer: Buffer,
byte_offset: usize,
layout: BufferLayout,
},
Shared {
data: &'buf [u8],
layout: BufferLayout,
},
Local {
size: BufferSize,
layout: BufferLayout,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(usize)]
pub enum CbKind {
IntersectFilter,
OccludedFilter,
UserIntersect,
UserOccluded,
UserBounds,
Displacement,
}
impl CbKind {
pub const COUNT: usize = 6;
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub(crate) struct Slot {
pub closure: *const (), pub user_data: *const (), }
impl Slot {
const EMPTY: Slot = Slot {
closure: ptr::null(),
user_data: ptr::null(),
};
}
#[derive(Debug, Clone, Copy)]
#[repr(C, align(64))]
pub(crate) struct CallSite {
pub slots: [Slot; CbKind::COUNT],
}
impl CallSite {
const EMPTY: CallSite = CallSite {
slots: [Slot::EMPTY; CbKind::COUNT],
};
}
#[derive(Debug, Default)]
pub(crate) struct CallbackOwners {
pub closures: [Option<ErasedFn>; CbKind::COUNT],
pub owned_data: [Option<Box<dyn Any + Send + Sync>>; CbKind::COUNT],
}
#[derive(Debug)]
pub(crate) struct GeometryData {
pub call_site: UnsafeCell<CallSite>,
pub owners: UnsafeCell<CallbackOwners>,
}
impl Default for GeometryData {
fn default() -> Self {
Self {
call_site: UnsafeCell::new(CallSite::EMPTY),
owners: UnsafeCell::new(CallbackOwners::default()),
}
}
}
#[derive(Debug)]
pub(crate) struct GeometryShared<'buf> {
pub(crate) device: Device,
pub(crate) handle: RTCGeometry,
pub(crate) kind: GeometryKind,
pub(crate) attachments: Mutex<HashMap<(BufferUsage, u32), AttachedBuffer<'buf>>>,
pub(crate) data: GeometryData,
}
impl<'buf> Drop for GeometryShared<'buf> {
fn drop(&mut self) {
unsafe {
rtcReleaseGeometry(self.handle);
}
}
}
unsafe impl Sync for GeometryShared<'_> {}
impl<'buf> GeometryShared<'buf> {
fn buffer_source(&self, usage: BufferUsage, slot: u32) -> Option<BufferSource<'buf>> {
let attachments = self.attachments.lock().unwrap();
attachments.get(&(usage, slot)).map(|a| match a {
AttachedBuffer::Managed {
buffer,
byte_offset,
layout,
} => BufferSource::Managed {
buffer: buffer.clone(),
byte_offset: *byte_offset,
layout: *layout,
},
AttachedBuffer::Shared { data, layout } => BufferSource::Shared {
data,
layout: *layout,
},
AttachedBuffer::Local { size, layout } => BufferSource::Local {
size: *size,
layout: *layout,
},
})
}
pub(crate) fn map_local<T: BufferData>(
&self,
usage: BufferUsage,
slot: u32,
) -> Result<(*mut T, usize), Error> {
let byte_size = {
let attachments = self.attachments.lock().unwrap();
match attachments.get(&(usage, slot)) {
Some(AttachedBuffer::Local { size, .. }) => size.get(),
_ => return Err(Error::INVALID_ARGUMENT),
}
};
let ptr = unsafe { rtcGetGeometryBufferData(self.handle, usage, slot) } as *mut T;
let t_size = std::mem::size_of::<T>();
if ptr.is_null()
|| t_size == 0
|| byte_size % t_size != 0
|| (ptr as usize) & (std::mem::align_of::<T>() - 1) != 0
{
return Err(Error::INVALID_ARGUMENT);
}
Ok((ptr, byte_size / t_size))
}
unsafe fn data_mut(&self) -> (&mut CallSite, &mut CallbackOwners) {
(
&mut *self.data.call_site.get(),
&mut *self.data.owners.get(),
)
}
}
#[derive(Debug)]
pub struct GeometryBuilder<'buf> {
pub(crate) shared: Arc<GeometryShared<'buf>>,
}
unsafe impl<'buf> Send for GeometryBuilder<'buf> {}
impl<'buf> GeometryBuilder<'buf> {
pub fn set_shared_buffer(
&mut self,
usage: BufferUsage,
slot: u32,
format: Format,
data: &'buf [u8],
stride: usize,
count: usize,
) -> Result<(), Error> {
if usage == BufferUsage::VERTEX_ATTRIBUTE {
self.check_vertex_attribute()?;
}
let vertex = matches!(usage, BufferUsage::VERTEX | BufferUsage::VERTEX_ATTRIBUTE);
let req =
required_layout_bytes(format, stride, count, vertex).ok_or(Error::INVALID_ARGUMENT)?;
if data.len() < req || (data.as_ptr() as usize) & 3 != 0 {
return Err(Error::INVALID_ARGUMENT);
}
unsafe {
rtcSetSharedGeometryBuffer(
self.shared.handle,
usage,
slot,
format,
data.as_ptr() as *const c_void,
0, stride,
count,
);
}
let layout = BufferLayout {
format,
stride,
count,
};
self.shared
.attachments
.lock()
.unwrap()
.insert((usage, slot), AttachedBuffer::Shared { data, layout });
Ok(())
}
pub fn set_shared_slice<T: BufferData>(
&mut self,
usage: BufferUsage,
slot: u32,
format: Format,
data: &'buf [T],
) -> Result<(), Error> {
let bytes: &'buf [u8] = unsafe {
std::slice::from_raw_parts(data.as_ptr() as *const u8, std::mem::size_of_val(data))
};
self.set_shared_buffer(
usage,
slot,
format,
bytes,
std::mem::size_of::<T>(),
data.len(),
)
}
#[allow(clippy::too_many_arguments)]
pub fn set_managed_buffer<S: RangeBounds<usize>>(
&mut self,
usage: BufferUsage,
slot: u32,
format: Format,
buffer: &Buffer,
byte_range: S,
stride: usize,
count: usize,
) -> Result<(), Error> {
if usage == BufferUsage::VERTEX_ATTRIBUTE {
self.check_vertex_attribute()?;
}
let byte_offset = match byte_range.start_bound() {
Bound::Included(&n) => n,
Bound::Excluded(&n) => n + 1,
Bound::Unbounded => 0,
};
let end = match byte_range.end_bound() {
Bound::Included(&n) => n + 1,
Bound::Excluded(&n) => n,
Bound::Unbounded => buffer.size.get(),
};
let vertex = matches!(usage, BufferUsage::VERTEX | BufferUsage::VERTEX_ATTRIBUTE);
let req =
required_layout_bytes(format, stride, count, vertex).ok_or(Error::INVALID_ARGUMENT)?;
if byte_offset % 4 != 0
|| byte_offset > end
|| end > buffer.size.get()
|| end - byte_offset < req
{
return Err(Error::INVALID_ARGUMENT);
}
unsafe {
rtcSetGeometryBuffer(
self.shared.handle,
usage,
slot,
format,
buffer.handle,
byte_offset,
stride,
count,
);
}
let layout = BufferLayout {
format,
stride,
count,
};
self.shared.attachments.lock().unwrap().insert(
(usage, slot),
AttachedBuffer::Managed {
buffer: buffer.clone(), byte_offset,
layout,
},
);
Ok(())
}
pub fn set_managed_slice<T: BufferData, S: RangeBounds<usize>>(
&mut self,
usage: BufferUsage,
slot: u32,
format: Format,
buffer: &Buffer,
elem_range: S,
) -> Result<(), Error> {
let stride = std::mem::size_of::<T>();
if stride == 0 {
return Err(Error::INVALID_ARGUMENT);
}
let start = match elem_range.start_bound() {
Bound::Included(&n) => n,
Bound::Excluded(&n) => n + 1,
Bound::Unbounded => 0,
};
let end = match elem_range.end_bound() {
Bound::Included(&n) => n + 1,
Bound::Excluded(&n) => n,
Bound::Unbounded => buffer.size.get() / stride,
};
let count = end.checked_sub(start).ok_or(Error::INVALID_ARGUMENT)?;
let byte_offset = start.checked_mul(stride).ok_or(Error::INVALID_ARGUMENT)?;
let byte_end = end.checked_mul(stride).ok_or(Error::INVALID_ARGUMENT)?;
self.set_managed_buffer(
usage,
slot,
format,
buffer,
byte_offset..byte_end,
stride,
count,
)
}
pub fn set_new_buffer<T: BufferData>(
&mut self,
usage: BufferUsage,
slot: u32,
format: Format,
stride: usize,
count: usize,
) -> Result<BufferViewMut<'_, T>, Error> {
if usage == BufferUsage::VERTEX_ATTRIBUTE {
self.check_vertex_attribute()?;
}
let vertex = matches!(usage, BufferUsage::VERTEX | BufferUsage::VERTEX_ATTRIBUTE);
required_layout_bytes(format, stride, count, vertex).ok_or(Error::INVALID_ARGUMENT)?;
let size = stride.checked_mul(count).ok_or(Error::INVALID_ARGUMENT)?;
let t_size = std::mem::size_of::<T>();
if t_size == 0 || size % t_size != 0 {
return Err(Error::INVALID_ARGUMENT);
}
let raw_ptr = unsafe {
rtcSetNewGeometryBuffer(self.shared.handle, usage, slot, format, stride, count)
};
if raw_ptr.is_null() {
return Err(self.shared.device.get_error());
}
if (raw_ptr as usize) & (std::mem::align_of::<T>() - 1) != 0 {
return Err(Error::INVALID_ARGUMENT);
}
let layout = BufferLayout {
format,
stride,
count,
};
self.shared.attachments.lock().unwrap().insert(
(usage, slot),
AttachedBuffer::Local {
size: BufferSize::new(size).ok_or(Error::INVALID_ARGUMENT)?,
layout,
},
);
Ok(unsafe { BufferViewMut::from_raw_parts(raw_ptr as *mut T, size / t_size) })
}
pub fn update_buffer(&mut self, usage: BufferUsage, slot: u32) {
unsafe {
rtcUpdateGeometryBuffer(self.shared.handle, usage, slot);
}
}
pub fn disable(&mut self) {
unsafe {
rtcDisableGeometry(self.shared.handle);
}
}
pub fn enable(&mut self) {
unsafe {
rtcEnableGeometry(self.shared.handle);
}
}
pub fn set_vertex_attribute_count(&mut self, count: u32) {
match self.shared.kind {
GeometryKind::GRID | GeometryKind::USER | GeometryKind::INSTANCE => {}
_ => {
unsafe {
rtcSetGeometryVertexAttributeCount(self.shared.handle, count);
}
}
}
}
pub fn set_build_quality(&mut self, quality: BuildQuality) {
unsafe {
rtcSetGeometryBuildQuality(self.shared.handle, quality);
}
}
pub fn set_tessellation_rate(&mut self, rate: f32) {
match self.shared.kind {
GeometryKind::SUBDIVISION
| GeometryKind::FLAT_LINEAR_CURVE
| GeometryKind::FLAT_BEZIER_CURVE
| GeometryKind::ROUND_LINEAR_CURVE
| GeometryKind::ROUND_BEZIER_CURVE => unsafe {
rtcSetGeometryTessellationRate(self.shared.handle, rate);
},
_ => panic!(
"GeometryBuilder::set_tessellation_rate is only supported for subdivision meshes \
and flat curves"
),
}
}
pub fn set_max_radius_scale(&mut self, scale: f32) -> Result<(), Error> {
let _ = self.shared.device.get_error();
unsafe { rtcSetGeometryMaxRadiusScale(self.shared.handle, scale) };
match self.shared.device.get_error() {
Error::NONE => Ok(()),
error => Err(error),
}
}
pub fn set_mask(&mut self, mask: u32) {
unsafe {
rtcSetGeometryMask(self.shared.handle, mask);
}
}
pub fn set_time_step_count(&mut self, count: u32) {
unsafe {
rtcSetGeometryTimeStepCount(self.shared.handle, count);
}
}
pub fn set_time_range(&mut self, start: f32, end: f32) {
unsafe {
rtcSetGeometryTimeRange(self.shared.handle, start, end);
}
}
pub fn set_intersect_filter_function<F, D>(&mut self, filter: F)
where
D: UserData,
F: for<'a> Fn(RayN<'a>, HitN<'a>, ValidityN<'a>, &mut IntersectContext, Option<&D>)
+ Send
+ Sync
+ 'static,
{
unsafe {
rtcSetGeometryIntersectFilterFunction(
self.shared.handle,
trampoline::intersect_filter_function::<F, D>(),
);
self.install_callback(
CbKind::IntersectFilter,
ErasedFn::new(filter),
std::ptr::null(),
None,
);
}
}
pub fn set_intersect_filter_function_owned<F, D>(&mut self, filter: F, data: D)
where
D: UserData,
F: for<'a> Fn(RayN<'a>, HitN<'a>, ValidityN<'a>, &mut IntersectContext, Option<&D>)
+ Send
+ Sync
+ 'static,
{
let boxed = Box::new(data);
let ptr = &*boxed as *const D as *const ();
unsafe {
rtcSetGeometryIntersectFilterFunction(
self.shared.handle,
trampoline::intersect_filter_function::<F, D>(),
);
self.install_callback(
CbKind::IntersectFilter,
ErasedFn::new(filter),
ptr,
Some(boxed),
);
}
}
pub fn set_intersect_filter_function_borrowed<F, D>(&mut self, filter: F, data: &'buf D)
where
D: UserData,
F: for<'a> Fn(RayN<'a>, HitN<'a>, ValidityN<'a>, &mut IntersectContext, Option<&D>)
+ Send
+ Sync
+ 'static,
{
let ptr = data as *const D as *const ();
unsafe {
rtcSetGeometryIntersectFilterFunction(
self.shared.handle,
trampoline::intersect_filter_function::<F, D>(),
);
self.install_callback(CbKind::IntersectFilter, ErasedFn::new(filter), ptr, None);
}
}
pub fn unset_intersect_filter_function(&mut self) {
unsafe {
rtcSetGeometryIntersectFilterFunction(self.shared.handle, None);
self.clear_callback(CbKind::IntersectFilter);
}
}
pub fn set_occluded_filter_function<F, D>(&mut self, filter: F)
where
D: UserData,
F: for<'a> Fn(RayN<'a>, HitN<'a>, ValidityN<'a>, &mut IntersectContext, Option<&D>)
+ Send
+ Sync
+ 'static,
{
unsafe {
rtcSetGeometryOccludedFilterFunction(
self.shared.handle,
trampoline::occluded_filter_function::<F, D>(),
);
self.install_callback(
CbKind::OccludedFilter,
ErasedFn::new(filter),
std::ptr::null(),
None,
);
}
}
pub fn set_occluded_filter_function_owned<F, D>(&mut self, filter: F, data: D)
where
D: UserData,
F: for<'a> Fn(RayN<'a>, HitN<'a>, ValidityN<'a>, &mut IntersectContext, Option<&D>)
+ Send
+ Sync
+ 'static,
{
let boxed = Box::new(data);
let ptr = &*boxed as *const D as *const ();
unsafe {
rtcSetGeometryOccludedFilterFunction(
self.shared.handle,
trampoline::occluded_filter_function::<F, D>(),
);
self.install_callback(
CbKind::OccludedFilter,
ErasedFn::new(filter),
ptr,
Some(boxed),
);
}
}
pub fn set_occluded_filter_function_borrowed<F, D>(&mut self, filter: F, data: &'buf D)
where
D: UserData,
F: for<'a> Fn(RayN<'a>, HitN<'a>, ValidityN<'a>, &mut IntersectContext, Option<&D>)
+ Send
+ Sync
+ 'static,
{
let ptr = data as *const D as *const ();
unsafe {
rtcSetGeometryOccludedFilterFunction(
self.shared.handle,
trampoline::occluded_filter_function::<F, D>(),
);
self.install_callback(CbKind::OccludedFilter, ErasedFn::new(filter), ptr, None);
}
}
pub fn unset_occluded_filter_function(&mut self) {
unsafe {
rtcSetGeometryOccludedFilterFunction(self.shared.handle, None);
self.clear_callback(CbKind::OccludedFilter);
}
}
pub fn set_bounds_function<F, D>(&mut self, bounds: F)
where
D: UserData,
F: Fn(&mut Bounds, u32, u32, Option<&D>) + Send + Sync + 'static,
{
if self.shared.kind == GeometryKind::USER {
unsafe {
rtcSetGeometryBoundsFunction(
self.shared.handle,
trampoline::bounds_function::<F, D>(),
ptr::null_mut(),
);
self.install_callback(
CbKind::UserBounds,
ErasedFn::new(bounds),
std::ptr::null(),
None,
);
}
}
}
pub fn set_bounds_function_owned<F, D>(&mut self, bounds: F, data: D)
where
D: UserData,
F: Fn(&mut Bounds, u32, u32, Option<&D>) + Send + Sync + 'static,
{
if self.shared.kind == GeometryKind::USER {
let boxed = Box::new(data);
let ptr = &*boxed as *const D as *const ();
unsafe {
rtcSetGeometryBoundsFunction(
self.shared.handle,
trampoline::bounds_function::<F, D>(),
ptr::null_mut(),
);
}
self.install_callback(CbKind::UserBounds, ErasedFn::new(bounds), ptr, Some(boxed));
}
}
pub fn set_bounds_function_borrowed<F, D>(&mut self, bounds: F, data: &'buf D)
where
D: UserData,
F: Fn(&mut Bounds, u32, u32, Option<&D>) + Send + Sync + 'static,
{
if self.shared.kind == GeometryKind::USER {
let ptr = data as *const D as *const ();
unsafe {
rtcSetGeometryBoundsFunction(
self.shared.handle,
trampoline::bounds_function::<F, D>(),
ptr::null_mut(),
);
}
self.install_callback(CbKind::UserBounds, ErasedFn::new(bounds), ptr, None);
}
}
pub fn unset_bounds_function(&mut self) {
if self.shared.kind == GeometryKind::USER {
unsafe {
rtcSetGeometryBoundsFunction(self.shared.handle, None, ptr::null_mut());
self.clear_callback(CbKind::UserBounds);
}
}
}
pub fn set_intersect_function<F, D>(&mut self, intersect: F)
where
D: UserData,
F: for<'a> Fn(&mut IntersectFunctionNArgs<'a, D>) + Send + Sync + 'static,
{
if self.shared.kind == GeometryKind::USER {
unsafe {
rtcSetGeometryIntersectFunction(
self.shared.handle,
trampoline::intersect_function::<F, D>(),
);
self.install_callback(
CbKind::UserIntersect,
ErasedFn::new(intersect),
std::ptr::null(),
None,
);
}
}
}
pub fn set_intersect_function_owned<F, D>(&mut self, intersect: F, data: D)
where
D: UserData,
F: for<'a> Fn(&mut IntersectFunctionNArgs<'a, D>) + Send + Sync + 'static,
{
if self.shared.kind == GeometryKind::USER {
let boxed = Box::new(data);
let ptr = &*boxed as *const D as *const ();
unsafe {
rtcSetGeometryIntersectFunction(
self.shared.handle,
trampoline::intersect_function::<F, D>(),
);
}
self.install_callback(
CbKind::UserIntersect,
ErasedFn::new(intersect),
ptr,
Some(boxed),
);
}
}
pub fn set_intersect_function_borrowed<F, D>(&mut self, intersect: F, data: &'buf D)
where
D: UserData,
F: for<'a> Fn(&mut IntersectFunctionNArgs<'a, D>) + Send + Sync + 'static,
{
if self.shared.kind == GeometryKind::USER {
unsafe {
let ptr = data as *const D as *const ();
rtcSetGeometryIntersectFunction(
self.shared.handle,
trampoline::intersect_function::<F, D>(),
);
self.install_callback(CbKind::UserIntersect, ErasedFn::new(intersect), ptr, None);
}
}
}
pub fn unset_intersect_function(&mut self) {
if self.shared.kind == GeometryKind::USER {
unsafe {
rtcSetGeometryIntersectFunction(self.shared.handle, None);
}
self.clear_callback(CbKind::UserIntersect);
}
}
pub fn set_occluded_function<F, D>(&mut self, occluded: F)
where
D: UserData,
F: for<'a> Fn(&mut OccludedFunctionNArgs<'a, D>) + Send + Sync + 'static,
{
if self.shared.kind == GeometryKind::USER {
unsafe {
rtcSetGeometryOccludedFunction(
self.shared.handle,
trampoline::occluded_function::<F, D>(),
)
};
self.install_callback(
CbKind::UserOccluded,
ErasedFn::new(occluded),
std::ptr::null(),
None,
);
}
}
pub fn set_occluded_function_owned<F, D>(&mut self, occluded: F, data: D)
where
D: UserData,
F: for<'a> Fn(&mut OccludedFunctionNArgs<'a, D>) + Send + Sync + 'static,
{
if self.shared.kind == GeometryKind::USER {
let boxed = Box::new(data);
let ptr = &*boxed as *const D as *const ();
unsafe {
rtcSetGeometryOccludedFunction(
self.shared.handle,
trampoline::occluded_function::<F, D>(),
)
};
self.install_callback(
CbKind::UserOccluded,
ErasedFn::new(occluded),
ptr,
Some(boxed),
);
}
}
pub fn set_occluded_function_borrowed<F, D>(&mut self, occluded: F, data: &'buf D)
where
D: UserData,
F: for<'a> Fn(&mut OccludedFunctionNArgs<'a, D>) + Send + Sync + 'static,
{
if self.shared.kind == GeometryKind::USER {
let ptr = data as *const D as *const ();
unsafe {
rtcSetGeometryOccludedFunction(
self.shared.handle,
trampoline::occluded_function::<F, D>(),
)
};
self.install_callback(CbKind::UserOccluded, ErasedFn::new(occluded), ptr, None);
}
}
pub fn unset_occluded_function(&mut self) {
if self.shared.kind == GeometryKind::USER {
unsafe {
rtcSetGeometryOccludedFunction(self.shared.handle, None);
self.clear_callback(CbKind::UserOccluded);
}
}
}
pub fn set_primitive_count(&mut self, count: u32) {
match self.shared.kind {
GeometryKind::USER => unsafe {
rtcSetGeometryUserPrimitiveCount(self.shared.handle, count);
},
_ => panic!("Only user geometries can have a primitive count!"),
}
}
pub fn set_subdivision_mode(&mut self, topology_id: u32, mode: SubdivisionMode) {
match self.shared.kind {
GeometryKind::SUBDIVISION => unsafe {
rtcSetGeometrySubdivisionMode(self.shared.handle, topology_id, mode)
},
_ => panic!("Only subdivision geometries can have a subdivision mode!"),
}
}
pub fn set_topology_count(&mut self, count: u32) {
match self.shared.kind {
GeometryKind::SUBDIVISION => unsafe {
rtcSetGeometryTopologyCount(self.shared.handle, count);
},
_ => panic!("Only subdivision geometries can have multiple topologies!"),
}
}
pub fn kind(&self) -> GeometryKind { self.shared.kind }
pub unsafe fn handle(&self) -> RTCGeometry { self.shared.handle }
pub fn get_buffer(&self, usage: BufferUsage, slot: u32) -> Option<BufferSource<'_>> {
self.shared.buffer_source(usage, slot)
}
pub fn map_buffer_mut<T: BufferData>(
&mut self,
usage: BufferUsage,
slot: u32,
) -> Result<BufferViewMut<'_, T>, Error> {
let (ptr, len) = self.shared.map_local::<T>(usage, slot)?;
Ok(unsafe { BufferViewMut::from_raw_parts(ptr, len) })
}
pub fn map_buffer<T: BufferData>(
&self,
usage: BufferUsage,
slot: u32,
) -> Result<BufferView<'_, T>, Error> {
let (ptr, len) = self.shared.map_local::<T>(usage, slot)?;
Ok(unsafe { BufferView::from_raw_parts(ptr, len) })
}
pub fn set_user_primitive_count(&mut self, count: u32) {
if self.shared.kind == GeometryKind::USER {
unsafe {
rtcSetGeometryUserPrimitiveCount(self.shared.handle, count);
}
}
}
pub fn set_vertex_attribute_topology(&mut self, vertex_attribute_id: u32, topology_id: u32) {
unsafe {
rtcSetGeometryVertexAttributeTopology(
self.shared.handle,
vertex_attribute_id,
topology_id,
);
}
}
pub unsafe fn set_displacement_function<F, D>(&mut self, displacement: F)
where
D: UserData,
F: for<'a> Fn(RTCGeometry, Vertices<'a>, u32, u32, Option<&D>) + Send + Sync + 'static,
{
if self.shared.kind == GeometryKind::SUBDIVISION {
unsafe {
rtcSetGeometryDisplacementFunction(
self.shared.handle,
trampoline::displacement_function::<F, D>(),
)
}
self.install_callback(
CbKind::Displacement,
ErasedFn::new(displacement),
std::ptr::null(),
None,
);
}
}
pub unsafe fn set_displacement_function_owned<F, D>(&mut self, displacement: F, data: D)
where
D: UserData,
F: for<'a> Fn(RTCGeometry, Vertices<'a>, u32, u32, Option<&D>) + Send + Sync + 'static,
{
if self.shared.kind == GeometryKind::SUBDIVISION {
let boxed = Box::new(data);
let ptr = &*boxed as *const D as *const ();
unsafe {
rtcSetGeometryDisplacementFunction(
self.shared.handle,
trampoline::displacement_function::<F, D>(),
)
}
self.install_callback(
CbKind::Displacement,
ErasedFn::new(displacement),
ptr,
Some(boxed),
);
}
}
pub unsafe fn set_displacement_function_borrowed<F, D>(
&mut self,
displacement: F,
data: &'buf D,
) where
D: UserData,
F: for<'a> Fn(RTCGeometry, Vertices<'a>, u32, u32, Option<&D>) + Send + Sync + 'static,
{
if self.shared.kind == GeometryKind::SUBDIVISION {
let ptr = data as *const D as *const ();
unsafe {
rtcSetGeometryDisplacementFunction(
self.shared.handle,
trampoline::displacement_function::<F, D>(),
)
}
self.install_callback(CbKind::Displacement, ErasedFn::new(displacement), ptr, None);
}
}
pub fn unset_displacement_function(&mut self) {
match self.shared.kind {
GeometryKind::SUBDIVISION => unsafe {
rtcSetGeometryDisplacementFunction(self.shared.handle, None);
self.clear_callback(CbKind::Displacement);
},
_ => panic!("Only subdivision geometries can have displacement functions!"),
}
}
pub fn set_instanced_scene(&mut self, scene: &Scene) {
match self.shared.kind {
GeometryKind::INSTANCE => unsafe {
rtcSetGeometryInstancedScene(self.shared.handle, scene.handle)
},
_ => panic!("Only instance geometries can have instanced scenes!"),
}
}
pub fn set_transform(&mut self, time_step: u32, transform: &[f32; 16]) {
match self.shared.kind {
GeometryKind::INSTANCE => unsafe {
rtcSetGeometryTransform(
self.shared.handle,
time_step,
Format::FLOAT4X4_COLUMN_MAJOR,
transform.as_ptr() as *const _,
);
},
_ => panic!("Only instance geometries can have instanced scenes!"),
}
}
pub fn set_transform_quaternion(
&mut self,
time_step: u32,
transform: &QuaternionDecomposition,
) {
match self.shared.kind {
GeometryKind::INSTANCE => unsafe {
rtcSetGeometryTransformQuaternion(
self.shared.handle,
time_step,
transform as &QuaternionDecomposition as *const _,
);
},
_ => panic!("Only instance geometries can have instanced scenes!"),
}
}
fn check_vertex_attribute(&self) -> Result<(), Error> {
match self.shared.kind {
GeometryKind::GRID | GeometryKind::USER | GeometryKind::INSTANCE => {
Err(Error::INVALID_OPERATION)
}
_ => Ok(()),
}
}
pub fn commit(self) -> Geometry<'buf> {
unsafe {
rtcCommitGeometry(self.shared.handle);
}
Geometry {
shared: self.shared,
}
}
pub fn callback_data<D: UserData>(&self, kind: CbKind) -> Option<&D> {
unsafe {
(*self.shared.data.owners.get()).owned_data[kind as usize]
.as_ref()?
.downcast_ref::<D>()
}
}
pub fn callback_data_mut<D: UserData>(&mut self, kind: CbKind) -> Option<&mut D> {
unsafe {
(*self.shared.data.owners.get()).owned_data[kind as usize]
.as_mut()?
.downcast_mut::<D>()
}
}
fn install_callback(
&mut self,
kind: CbKind,
erased: ErasedFn,
user_data: *const (),
owned_data: Option<Box<dyn Any + Send + Sync>>,
) {
unsafe {
let (site, owners) = self.shared.data_mut();
let i = kind as usize;
site.slots[i].closure = erased.as_ptr() as *const ();
site.slots[i].user_data = user_data;
owners.closures[i] = Some(erased);
owners.owned_data[i] = owned_data;
}
}
fn clear_callback(&mut self, kind: CbKind) {
unsafe {
let (site, owners) = self.shared.data_mut();
let i = kind as usize;
site.slots[i] = Slot::EMPTY;
owners.closures[i] = None;
owners.owned_data[i] = None;
}
}
}
#[derive(Debug, Clone)]
pub struct Geometry<'buf> {
pub(crate) shared: Arc<GeometryShared<'buf>>,
}
unsafe impl<'buf> Send for Geometry<'buf> {}
unsafe impl<'buf> Sync for Geometry<'buf> {}
impl<'buf> Geometry<'buf> {
#[allow(clippy::new_ret_no_self)]
pub fn new<'dev>(device: &'dev Device, kind: GeometryKind) -> GeometryBuilder<'buf> {
let handle = unsafe { rtcNewGeometry(device.handle, kind) };
#[allow(clippy::arc_with_non_send_sync)]
let shared = Arc::new(GeometryShared {
device: device.clone(),
handle,
kind,
attachments: Mutex::new(HashMap::new()),
data: GeometryData::default(),
});
unsafe {
rtcSetGeometryUserData(handle, shared.data.call_site.get() as *mut _);
}
GeometryBuilder { shared }
}
pub fn try_edit(mut self) -> Result<GeometryBuilder<'buf>, Geometry<'buf>> {
if Arc::get_mut(&mut self.shared).is_some() {
Ok(GeometryBuilder {
shared: self.shared,
})
} else {
Err(self)
}
}
pub unsafe fn handle(&self) -> RTCGeometry { self.shared.handle }
pub fn get_buffer(&self, usage: BufferUsage, slot: u32) -> Option<BufferSource<'_>> {
self.shared.buffer_source(usage, slot)
}
pub fn map_buffer<T: BufferData>(
&self,
usage: BufferUsage,
slot: u32,
) -> Result<BufferView<'_, T>, Error> {
let (ptr, len) = self.shared.map_local::<T>(usage, slot)?;
Ok(unsafe { BufferView::from_raw_parts(ptr, len) })
}
pub fn kind(&self) -> GeometryKind { self.shared.kind }
pub fn callback_data<D: UserData>(&self, kind: CbKind) -> Option<&D> {
unsafe {
(*self.shared.data.owners.get()).owned_data[kind as usize]
.as_ref()?
.downcast_ref::<D>()
}
}
pub fn interpolate(&self, input: InterpolateInput, output: &mut InterpolateOutput) {
let args = RTCInterpolateArguments {
geometry: self.shared.handle,
primID: input.prim_id,
u: input.u,
v: input.v,
bufferType: input.usage,
bufferSlot: input.slot,
P: output
.p_mut()
.map(|p| p.as_mut_ptr())
.unwrap_or(ptr::null_mut()),
dPdu: output
.dp_du_mut()
.map(|p| p.as_mut_ptr())
.unwrap_or(ptr::null_mut()),
dPdv: output
.dp_dv_mut()
.map(|p| p.as_mut_ptr())
.unwrap_or(ptr::null_mut()),
ddPdudu: output
.ddp_du_du_mut()
.map(|p| p.as_mut_ptr())
.unwrap_or(ptr::null_mut()),
ddPdvdv: output
.ddp_dv_dv_mut()
.map(|p| p.as_mut_ptr())
.unwrap_or(ptr::null_mut()),
ddPdudv: output
.ddp_du_dv_mut()
.map(|p| p.as_mut_ptr())
.unwrap_or(ptr::null_mut()),
valueCount: output.value_count(),
};
unsafe {
rtcInterpolate(&args as _);
}
}
pub fn interpolate_n(&self, input: InterpolateNInput, output: &mut InterpolateOutput) {
assert_eq!(input.n % 4, 0, "N must be a multiple of 4!");
let args = RTCInterpolateNArguments {
geometry: self.shared.handle,
N: input.n,
valid: input
.valid
.as_ref()
.map(|v| v.as_ptr() as *const _)
.unwrap_or(ptr::null()),
primIDs: input.prim_id.as_ptr(),
u: input.u.as_ptr(),
v: input.v.as_ptr(),
bufferType: input.usage,
bufferSlot: input.slot,
P: output
.p_mut()
.map(|p| p.as_mut_ptr())
.unwrap_or(ptr::null_mut()),
dPdu: output
.dp_du_mut()
.map(|p| p.as_mut_ptr())
.unwrap_or(ptr::null_mut()),
dPdv: output
.dp_dv_mut()
.map(|p| p.as_mut_ptr())
.unwrap_or(ptr::null_mut()),
ddPdudu: output
.ddp_du_du_mut()
.map(|p| p.as_mut_ptr())
.unwrap_or(ptr::null_mut()),
ddPdvdv: output
.ddp_dv_dv_mut()
.map(|p| p.as_mut_ptr())
.unwrap_or(ptr::null_mut()),
ddPdudv: output
.ddp_du_dv_mut()
.map(|p| p.as_mut_ptr())
.unwrap_or(ptr::null_mut()),
valueCount: output.value_count(),
};
unsafe {
rtcInterpolateN(&args as _);
}
}
pub fn get_first_half_edge(&self, face_id: u32) -> u32 {
match self.shared.kind {
GeometryKind::SUBDIVISION => unsafe {
rtcGetGeometryFirstHalfEdge(self.shared.handle, face_id)
},
_ => panic!("Only subdivision geometries can have half edges!"),
}
}
pub fn get_face(&self, half_edge_id: u32) -> u32 {
match self.shared.kind {
GeometryKind::SUBDIVISION => unsafe {
rtcGetGeometryFace(self.shared.handle, half_edge_id)
},
_ => panic!("Only subdivision geometries can have half edges!"),
}
}
pub fn get_next_half_edge(&self, half_edge_id: u32) -> u32 {
match self.shared.kind {
GeometryKind::SUBDIVISION => unsafe {
rtcGetGeometryNextHalfEdge(self.shared.handle, half_edge_id)
},
_ => panic!("Only subdivision geometries can have half edges!"),
}
}
pub fn get_previous_half_edge(&self, half_edge_id: u32) -> u32 {
match self.shared.kind {
GeometryKind::SUBDIVISION => unsafe {
rtcGetGeometryPreviousHalfEdge(self.shared.handle, half_edge_id)
},
_ => panic!("Only subdivision geometries can have half edges!"),
}
}
pub fn get_opposite_half_edge(&self, topology_id: u32, edge_id: u32) -> u32 {
match self.shared.kind {
GeometryKind::SUBDIVISION => unsafe {
rtcGetGeometryOppositeHalfEdge(self.shared.handle, topology_id, edge_id)
},
_ => panic!("Only subdivision geometries can have half edges!"),
}
}
pub fn get_transform(&mut self, time: f32) -> [f32; 16] {
match self.shared.kind {
GeometryKind::INSTANCE => unsafe {
let mut transform = [0.0; 16];
rtcGetGeometryTransform(
self.shared.handle,
time,
Format::FLOAT4X4_COLUMN_MAJOR,
transform.as_mut_ptr() as *mut _,
);
transform
},
_ => panic!("Only instance geometries can have instanced scenes!"),
}
}
}
pub struct InterpolateInput {
pub prim_id: u32,
pub u: f32,
pub v: f32,
pub usage: BufferUsage,
pub slot: u32,
}
pub struct InterpolateNInput<'a> {
pub valid: Option<Cow<'a, [u32]>>,
pub prim_id: Cow<'a, [u32]>,
pub u: Cow<'a, [f32]>,
pub v: Cow<'a, [f32]>,
pub usage: BufferUsage,
pub slot: u32,
pub n: u32,
}
pub struct InterpolateOutput {
buffer: Vec<f32>,
count_per_attribute: u32,
p_offset: Option<u32>,
dp_du_offset: Option<u32>,
dp_dv_offset: Option<u32>,
ddp_du_du_offset: Option<u32>,
ddp_dv_dv_offset: Option<u32>,
ddp_du_dv_offset: Option<u32>,
}
impl InterpolateOutput {
pub fn new(count: u32, zeroth_order: bool, first_order: bool, second_order: bool) -> Self {
assert!(
count > 0,
"The number of interpolated values must be greater than 0!"
);
assert!(
zeroth_order || first_order || second_order,
"At least one of the origin value, first order derivative, or second order derivative \
must be true!"
);
let mut offset = 0;
let p_offset = zeroth_order.then(|| {
let _offset = offset;
offset += count;
_offset
});
let dp_du_offset = first_order.then(|| {
let _offset = offset;
offset += count;
_offset
});
let dp_dv_offset = first_order.then(|| {
let _offset = offset;
offset += count;
_offset
});
let ddp_du_du_offset = second_order.then(|| {
let _offset = offset;
offset += count;
_offset
});
let ddp_dv_dv_offset = second_order.then(|| {
let _offset = offset;
offset += count;
_offset
});
let ddp_du_dv_offset = second_order.then(|| {
let _offset = offset;
offset += count;
_offset
});
Self {
buffer: vec![0.0; (offset + count) as usize],
count_per_attribute: count,
p_offset,
dp_du_offset,
dp_dv_offset,
ddp_du_du_offset,
ddp_dv_dv_offset,
ddp_du_dv_offset,
}
}
pub fn p(&self) -> Option<&[f32]> {
self.p_offset.map(|offset| {
&self.buffer[offset as usize..(offset + self.count_per_attribute) as usize]
})
}
pub fn p_mut(&mut self) -> Option<&mut [f32]> {
self.p_offset.map(move |offset| {
&mut self.buffer[offset as usize..(offset + self.count_per_attribute) as usize]
})
}
pub fn dp_du(&self) -> Option<&[f32]> {
self.dp_du_offset.map(|offset| {
&self.buffer[offset as usize..(offset + self.count_per_attribute) as usize]
})
}
pub fn dp_du_mut(&mut self) -> Option<&mut [f32]> {
self.dp_du_offset.map(|offset| {
&mut self.buffer[offset as usize..(offset + self.count_per_attribute) as usize]
})
}
pub fn dp_dv(&self) -> Option<&[f32]> {
self.dp_dv_offset.map(|offset| {
&self.buffer[offset as usize..(offset + self.count_per_attribute) as usize]
})
}
pub fn dp_dv_mut(&mut self) -> Option<&mut [f32]> {
self.dp_dv_offset.map(|offset| {
&mut self.buffer[offset as usize..(offset + self.count_per_attribute) as usize]
})
}
pub fn ddp_du_du(&self) -> Option<&[f32]> {
self.ddp_du_du_offset.map(|offset| {
&self.buffer[offset as usize..(offset + self.count_per_attribute) as usize]
})
}
pub fn ddp_du_du_mut(&mut self) -> Option<&mut [f32]> {
self.ddp_du_du_offset.map(|offset| {
&mut self.buffer[offset as usize..(offset + self.count_per_attribute) as usize]
})
}
pub fn ddp_dv_dv(&self) -> Option<&[f32]> {
self.ddp_dv_dv_offset.map(|offset| {
&self.buffer[offset as usize..(offset + self.count_per_attribute) as usize]
})
}
pub fn ddp_dv_dv_mut(&mut self) -> Option<&mut [f32]> {
self.ddp_dv_dv_offset.map(move |offset| {
&mut self.buffer[offset as usize..(offset + self.count_per_attribute) as usize]
})
}
pub fn ddp_du_dv(&self) -> Option<&[f32]> {
self.ddp_du_dv_offset.map(|offset| {
&self.buffer[offset as usize..(offset + self.count_per_attribute) as usize]
})
}
pub fn ddp_du_dv_mut(&mut self) -> Option<&mut [f32]> {
self.ddp_du_dv_offset.map(move |offset| {
&mut self.buffer[offset as usize..(offset + self.count_per_attribute) as usize]
})
}
pub fn value_count(&self) -> u32 { self.count_per_attribute }
}
macro_rules! impl_geometry_type {
($name:ident, $kind:path, $(#[$meta:meta])*) => {
#[derive(Debug)]
pub struct $name<'a>(GeometryBuilder<'a>);
impl<'a> Deref for $name<'a> {
type Target = GeometryBuilder<'a>;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl<'a> DerefMut for $name<'a> {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}
$(#[$meta])*
impl<'a> $name<'a> {
pub fn new(device: &Device) -> Result<Self, Error> {
Ok(Self(Geometry::new(device, $kind)))
}
pub fn commit(self) -> Geometry<'a> { self.0.commit() }
}
};
}
impl_geometry_type!(TriangleMeshBuilder, GeometryKind::TRIANGLE,
);
impl_geometry_type!(QuadMeshBuilder, GeometryKind::QUAD,
);
impl_geometry_type!(UserGeometryBuilder, GeometryKind::USER,
);
impl_geometry_type!(InstanceGeometryBuilder, GeometryKind::INSTANCE,
);
pub struct IntersectFunctionNArgs<'a, D: UserData> {
raw: *const RTCIntersectFunctionNArguments,
valid_n: ValidityN<'a>,
context: &'a mut IntersectContext,
geom_id: u32,
prim_id: u32,
user_data: Option<&'a D>,
}
impl<'a, D: UserData> IntersectFunctionNArgs<'a, D> {
pub fn len(&self) -> usize {
unsafe { (*self.raw).N as usize }
}
pub fn is_empty(&self) -> bool { self.len() == 0 }
pub fn valid_n(&self) -> &ValidityN<'a> { &self.valid_n }
pub fn valid_n_mut(&mut self) -> &mut ValidityN<'a> { &mut self.valid_n }
pub fn context(&self) -> &IntersectContext { self.context }
pub fn context_mut(&mut self) -> &mut IntersectContext { self.context }
pub unsafe fn context_ext<T>(&self) -> &T { self.context.ext::<T>() }
pub unsafe fn context_ext_mut<T>(&mut self) -> &mut T { self.context.ext_mut::<T>() }
pub fn geom_id(&self) -> u32 { self.geom_id }
pub fn prim_id(&self) -> u32 { self.prim_id }
pub fn user_data(&self) -> Option<&D> { self.user_data }
#[inline]
fn rays(&self) -> RayN<'a> {
RayN {
ptr: unsafe { (*self.raw).rayhit as *mut RTCRayN },
len: self.len(),
marker: PhantomData,
}
}
#[inline]
fn hits(&self) -> HitN<'a> {
let n = self.len();
HitN {
ptr: unsafe { ((*self.raw).rayhit as *const u32).add(12 * n) as *mut RTCHitN },
len: n,
marker: PhantomData,
}
}
pub fn ray(&self, i: usize) -> Ray {
assert!(i < self.len(), "ray index out of bounds");
unsafe { self.ray_unchecked(i) }
}
pub fn filter_intersection(&mut self, ray: &mut Ray, hit: &mut Hit) -> bool {
let mut valid: i32 = -1;
let fargs = RTCFilterFunctionNArguments {
valid: &mut valid,
geometryUserPtr: unsafe { (*self.raw).geometryUserPtr },
context: unsafe { (*self.raw).context },
ray: ray as *mut Ray as *mut RTCRayN,
hit: hit as *mut Hit as *mut RTCHitN,
N: 1,
};
unsafe { rtcFilterIntersection(self.raw, &fargs) };
valid != 0
}
pub fn commit_hit(&mut self, i: usize, ray: &Ray, hit: &Hit) {
assert!(i < self.len(), "commit index out of bounds");
unsafe { self.commit_hit_unchecked(i, ray, hit) }
}
pub fn filter_and_commit_hit(&mut self, i: usize, ray: &mut Ray, hit: &mut Hit) -> bool {
if self.filter_intersection(ray, hit) {
self.commit_hit(i, ray, hit);
true
} else {
false
}
}
pub fn set_tfar(&mut self, i: usize, tfar: f32) {
assert!(i < self.len(), "tfar index out of bounds");
unsafe { self.set_tfar_unchecked(i, tfar) }
}
#[inline(always)]
unsafe fn ray_unchecked(&self, i: usize) -> Ray { self.rays().gather_unchecked(i) }
#[inline(always)]
unsafe fn commit_hit_unchecked(&mut self, i: usize, ray: &Ray, hit: &Hit) {
self.rays().set_tfar_unchecked(i, ray.tfar);
self.hits().scatter_unchecked(i, hit);
}
#[inline(always)]
unsafe fn set_tfar_unchecked(&mut self, i: usize, tfar: f32) {
self.rays().set_tfar_unchecked(i, tfar);
}
#[inline(always)]
pub fn for_each_active_lane(&mut self, mut f: impl for<'b> FnMut(IntersectLane<'a, 'b, D>)) {
let n = self.len();
for i in 0..n {
if unsafe { *self.valid_n.ptr.add(i) } != 0 {
f(IntersectLane {
args: &mut *self,
i,
});
}
}
}
pub fn filter_intersection_n(&mut self, hits: &mut [Hit], valid: &mut [i32]) {
let n = self.len();
assert_eq!(hits.len(), n, "hits length must equal packet width");
assert_eq!(valid.len(), n, "valid length must equal packet width");
let mut scratch = [0u32; 8 * 16];
{
let mut hn = HitN {
ptr: scratch.as_mut_ptr() as *mut RTCHitN,
len: n,
marker: PhantomData,
};
for i in 0..n {
if valid[i] == 0 {
continue;
}
hn.set_normal(i, [hits[i].Ng_x, hits[i].Ng_y, hits[i].Ng_z]);
hn.set_uv(i, [hits[i].u, hits[i].v]);
hn.set_prim_id(i, hits[i].primID);
hn.set_geom_id(i, hits[i].geomID);
hn.set_inst_id(i, hits[i].instID[0]);
}
}
let fargs = RTCFilterFunctionNArguments {
valid: valid.as_mut_ptr(),
geometryUserPtr: unsafe { (*self.raw).geometryUserPtr },
context: unsafe { (*self.raw).context },
ray: unsafe { (*self.raw).rayhit as *mut RTCRayN },
hit: scratch.as_mut_ptr() as *mut RTCHitN,
N: n as u32,
};
unsafe { rtcFilterIntersection(self.raw, &fargs) };
let hn = HitN {
ptr: scratch.as_mut_ptr() as *mut RTCHitN,
len: n,
marker: PhantomData,
};
for i in 0..n {
if valid[i] == 0 {
continue;
}
let ng = hn.normal(i);
hits[i].Ng_x = ng[0];
hits[i].Ng_y = ng[1];
hits[i].Ng_z = ng[2];
hits[i].u = hn.u(i);
hits[i].v = hn.v(i);
hits[i].primID = hn.prim_id(i);
hits[i].geomID = hn.geom_id(i);
hits[i].instID[0] = hn.inst_id(i);
}
}
}
pub struct IntersectLane<'a, 'b, D: UserData> {
args: &'b mut IntersectFunctionNArgs<'a, D>,
i: usize,
}
impl<'a, 'b, D: UserData> IntersectLane<'a, 'b, D> {
pub fn index(&self) -> usize { self.i }
#[inline(always)]
pub fn ray(&self) -> Ray {
unsafe { self.args.ray_unchecked(self.i) }
}
#[inline(always)]
pub fn filter_intersection(&mut self, ray: &mut Ray, hit: &mut Hit) -> bool {
self.args.filter_intersection(ray, hit)
}
#[inline(always)]
pub fn commit_hit(&mut self, ray: &Ray, hit: &Hit) {
unsafe { self.args.commit_hit_unchecked(self.i, ray, hit) }
}
#[inline(always)]
pub fn set_tfar(&mut self, tfar: f32) {
unsafe { self.args.set_tfar_unchecked(self.i, tfar) }
}
pub fn geom_id(&self) -> u32 { self.args.geom_id() }
pub fn prim_id(&self) -> u32 { self.args.prim_id() }
pub fn user_data(&self) -> Option<&D> { self.args.user_data() }
}
pub struct OccludedFunctionNArgs<'a, D: UserData> {
raw: *const RTCOccludedFunctionNArguments,
valid_n: ValidityN<'a>,
context: &'a mut IntersectContext,
geom_id: u32,
prim_id: u32,
user_data: Option<&'a D>,
}
impl<'a, D: UserData> OccludedFunctionNArgs<'a, D> {
pub fn len(&self) -> usize {
unsafe { (*self.raw).N as usize }
}
pub fn is_empty(&self) -> bool { self.len() == 0 }
pub fn valid_n(&self) -> &ValidityN<'a> { &self.valid_n }
pub fn valid_n_mut(&mut self) -> &mut ValidityN<'a> { &mut self.valid_n }
pub fn context(&self) -> &IntersectContext { self.context }
pub fn context_mut(&mut self) -> &mut IntersectContext { self.context }
pub unsafe fn context_ext<T>(&self) -> &T { self.context.ext::<T>() }
pub unsafe fn context_ext_mut<T>(&mut self) -> &mut T { self.context.ext_mut::<T>() }
pub fn geom_id(&self) -> u32 { self.geom_id }
pub fn prim_id(&self) -> u32 { self.prim_id }
pub fn user_data(&self) -> Option<&D> { self.user_data }
#[inline]
fn rays(&self) -> RayN<'a> {
RayN {
ptr: unsafe { (*self.raw).ray },
len: self.len(),
marker: PhantomData,
}
}
pub fn ray(&self, i: usize) -> Ray {
assert!(i < self.len(), "ray index out of bounds");
unsafe { self.ray_unchecked(i) }
}
pub fn filter_occlusion(&mut self, ray: &mut Ray, hit: &mut Hit) -> bool {
let mut valid: i32 = -1;
let fargs = RTCFilterFunctionNArguments {
valid: &mut valid,
geometryUserPtr: unsafe { (*self.raw).geometryUserPtr },
context: unsafe { (*self.raw).context },
ray: ray as *mut Ray as *mut RTCRayN,
hit: hit as *mut Hit as *mut RTCHitN,
N: 1,
};
unsafe { rtcFilterOcclusion(self.raw, &fargs) };
valid != 0
}
pub fn set_occluded(&mut self, i: usize) {
assert!(i < self.len(), "occluded index out of bounds");
unsafe { self.set_occluded_unchecked(i) }
}
pub fn filter_and_set_occluded(&mut self, i: usize, ray: &mut Ray, hit: &mut Hit) -> bool {
if self.filter_occlusion(ray, hit) {
self.set_occluded(i);
true
} else {
false
}
}
pub fn set_tfar(&mut self, i: usize, tfar: f32) {
assert!(i < self.len(), "tfar index out of bounds");
unsafe { self.set_tfar_unchecked(i, tfar) }
}
#[inline(always)]
unsafe fn ray_unchecked(&self, i: usize) -> Ray { self.rays().gather_unchecked(i) }
#[inline(always)]
unsafe fn set_occluded_unchecked(&mut self, i: usize) {
self.rays().set_tfar_unchecked(i, f32::NEG_INFINITY);
}
#[inline(always)]
unsafe fn set_tfar_unchecked(&mut self, i: usize, tfar: f32) {
self.rays().set_tfar_unchecked(i, tfar);
}
#[inline(always)]
pub fn for_each_active_lane(&mut self, mut f: impl for<'b> FnMut(OccludedLane<'a, 'b, D>)) {
let n = self.len();
for i in 0..n {
if unsafe { *self.valid_n.ptr.add(i) } != 0 {
f(OccludedLane {
args: &mut *self,
i,
});
}
}
}
pub fn filter_occlusion_n(&mut self, hits: &mut [Hit], valid: &mut [i32]) {
let n = self.len();
assert_eq!(hits.len(), n, "hits length must equal packet width");
assert_eq!(valid.len(), n, "valid length must equal packet width");
let mut scratch = [0u32; 8 * 16];
{
let mut hn = HitN {
ptr: scratch.as_mut_ptr() as *mut RTCHitN,
len: n,
marker: PhantomData,
};
for i in 0..n {
if valid[i] == 0 {
continue;
}
hn.set_normal(i, [hits[i].Ng_x, hits[i].Ng_y, hits[i].Ng_z]);
hn.set_uv(i, [hits[i].u, hits[i].v]);
hn.set_prim_id(i, hits[i].primID);
hn.set_geom_id(i, hits[i].geomID);
hn.set_inst_id(i, hits[i].instID[0]);
}
}
let fargs = RTCFilterFunctionNArguments {
valid: valid.as_mut_ptr(),
geometryUserPtr: unsafe { (*self.raw).geometryUserPtr },
context: unsafe { (*self.raw).context },
ray: unsafe { (*self.raw).ray },
hit: scratch.as_mut_ptr() as *mut RTCHitN,
N: n as u32,
};
unsafe { rtcFilterOcclusion(self.raw, &fargs) };
let hn = HitN {
ptr: scratch.as_mut_ptr() as *mut RTCHitN,
len: n,
marker: PhantomData,
};
for i in 0..n {
if valid[i] == 0 {
continue;
}
let ng = hn.normal(i);
hits[i].Ng_x = ng[0];
hits[i].Ng_y = ng[1];
hits[i].Ng_z = ng[2];
hits[i].u = hn.u(i);
hits[i].v = hn.v(i);
hits[i].primID = hn.prim_id(i);
hits[i].geomID = hn.geom_id(i);
hits[i].instID[0] = hn.inst_id(i);
}
}
}
pub struct OccludedLane<'a, 'b, D: UserData> {
args: &'b mut OccludedFunctionNArgs<'a, D>,
i: usize,
}
impl<'a, 'b, D: UserData> OccludedLane<'a, 'b, D> {
pub fn index(&self) -> usize { self.i }
#[inline(always)]
pub fn ray(&self) -> Ray {
unsafe { self.args.ray_unchecked(self.i) }
}
#[inline(always)]
pub fn filter_occlusion(&mut self, ray: &mut Ray, hit: &mut Hit) -> bool {
self.args.filter_occlusion(ray, hit)
}
#[inline(always)]
pub fn set_occluded(&mut self) {
unsafe { self.args.set_occluded_unchecked(self.i) }
}
#[inline(always)]
pub fn set_tfar(&mut self, tfar: f32) {
unsafe { self.args.set_tfar_unchecked(self.i, tfar) }
}
pub fn geom_id(&self) -> u32 { self.args.geom_id() }
pub fn prim_id(&self) -> u32 { self.args.prim_id() }
pub fn user_data(&self) -> Option<&D> { self.args.user_data() }
}
mod trampoline {
use super::*;
pub(crate) fn intersect_filter_function<F, D>() -> RTCFilterFunctionN
where
D: UserData,
F: for<'a> Fn(RayN<'a>, HitN<'a>, ValidityN<'a>, &mut IntersectContext, Option<&D>)
+ Send
+ Sync
+ 'static,
{
unsafe extern "C" fn inner<F, D>(args: *const RTCFilterFunctionNArguments)
where
D: UserData,
F: for<'a> Fn(RayN<'a>, HitN<'a>, ValidityN<'a>, &mut IntersectContext, Option<&D>)
+ Send
+ Sync
+ 'static,
{
let site = &*((*args).geometryUserPtr as *const CallSite);
let slot = site.slots[CbKind::IntersectFilter as usize];
if slot.closure.is_null() {
return;
}
let cb = &*(slot.closure as *const F);
let user_data = if slot.user_data.is_null() {
None
} else {
Some(&*(slot.user_data as *const D))
};
let len = (*args).N as usize;
cb(
RayN {
ptr: (*args).ray,
len,
marker: PhantomData,
},
HitN {
ptr: (*args).hit,
len,
marker: PhantomData,
},
ValidityN {
ptr: (*args).valid,
len,
marker: PhantomData,
},
&mut *((*args).context as *mut IntersectContext),
user_data,
);
}
Some(inner::<F, D>)
}
pub(crate) fn occluded_filter_function<F, D>() -> RTCFilterFunctionN
where
D: UserData,
F: for<'a> Fn(RayN<'a>, HitN<'a>, ValidityN<'a>, &mut IntersectContext, Option<&D>)
+ Send
+ Sync
+ 'static,
{
unsafe extern "C" fn inner<F, D>(args: *const RTCFilterFunctionNArguments)
where
D: UserData,
F: for<'a> Fn(RayN<'a>, HitN<'a>, ValidityN<'a>, &mut IntersectContext, Option<&D>)
+ Send
+ Sync
+ 'static,
{
let site = &*((*args).geometryUserPtr as *const CallSite);
let slot = site.slots[CbKind::OccludedFilter as usize];
if slot.closure.is_null() {
return;
}
let cb = &*(slot.closure as *const F);
let user_data = if slot.user_data.is_null() {
None
} else {
Some(&*(slot.user_data as *const D))
};
let len = (*args).N as usize;
cb(
RayN {
ptr: (*args).ray,
len,
marker: PhantomData,
},
HitN {
ptr: (*args).hit,
len,
marker: PhantomData,
},
ValidityN {
ptr: (*args).valid,
len,
marker: PhantomData,
},
&mut *((*args).context as *mut IntersectContext),
user_data,
);
}
Some(inner::<F, D>)
}
pub(crate) fn intersect_function<F, D>() -> RTCIntersectFunctionN
where
D: UserData,
F: for<'a> Fn(&mut IntersectFunctionNArgs<'a, D>) + Send + Sync + 'static,
{
unsafe extern "C" fn inner<F, D>(args: *const RTCIntersectFunctionNArguments)
where
D: UserData,
F: for<'a> Fn(&mut IntersectFunctionNArgs<'a, D>) + Send + Sync + 'static,
{
let site = &*((*args).geometryUserPtr as *const CallSite);
let slot = site.slots[CbKind::UserIntersect as usize];
if slot.closure.is_null() {
return;
}
let cb = &*(slot.closure as *const F);
let user_data = if slot.user_data.is_null() {
None
} else {
Some(&*(slot.user_data as *const D))
};
let len = (*args).N as usize;
cb(&mut IntersectFunctionNArgs {
raw: args,
valid_n: ValidityN {
ptr: (*args).valid,
len,
marker: PhantomData,
},
context: &mut *((*args).context as *mut IntersectContext),
geom_id: (*args).geomID,
prim_id: (*args).primID,
user_data,
})
}
Some(inner::<F, D>)
}
pub(crate) fn bounds_function<F, D>() -> RTCBoundsFunction
where
D: UserData,
F: Fn(&mut Bounds, u32, u32, Option<&D>) + Send + Sync + 'static,
{
unsafe extern "C" fn inner<F, D>(args: *const RTCBoundsFunctionArguments)
where
D: UserData,
F: Fn(&mut Bounds, u32, u32, Option<&D>) + Send + Sync + 'static,
{
let site = &*((*args).geometryUserPtr as *const CallSite);
let slot = site.slots[CbKind::UserBounds as usize];
if slot.closure.is_null() {
return;
}
let cb = &*(slot.closure as *const F);
let user_data = if slot.user_data.is_null() {
None
} else {
Some(&*(slot.user_data as *const D))
};
cb(
&mut *(*args).bounds_o,
(*args).primID,
(*args).timeStep,
user_data,
);
}
Some(inner::<F, D>)
}
pub(crate) fn occluded_function<F, D>() -> RTCOccludedFunctionN
where
D: UserData,
F: for<'a> Fn(&mut OccludedFunctionNArgs<'a, D>) + Send + Sync + 'static,
{
unsafe extern "C" fn inner<F, D>(args: *const RTCOccludedFunctionNArguments)
where
D: UserData,
F: for<'a> Fn(&mut OccludedFunctionNArgs<'a, D>) + Send + Sync + 'static,
{
let site = &*((*args).geometryUserPtr as *const CallSite);
let slot = site.slots[CbKind::UserOccluded as usize];
if slot.closure.is_null() {
return;
}
let cb = &*(slot.closure as *const F);
let user_data = if slot.user_data.is_null() {
None
} else {
Some(&*(slot.user_data as *const D))
};
cb(&mut OccludedFunctionNArgs {
raw: args,
valid_n: ValidityN {
ptr: (*args).valid,
len: (*args).N as usize,
marker: PhantomData,
},
context: &mut *((*args).context as *mut IntersectContext),
geom_id: (*args).geomID,
prim_id: (*args).primID,
user_data,
})
}
Some(inner::<F, D>)
}
pub(crate) fn displacement_function<F, D>() -> RTCDisplacementFunctionN
where
D: UserData,
F: for<'a> Fn(RTCGeometry, Vertices<'a>, u32, u32, Option<&D>) + Send + Sync + 'static,
{
unsafe extern "C" fn inner<F, D>(args: *const RTCDisplacementFunctionNArguments)
where
D: UserData,
F: for<'a> Fn(RTCGeometry, Vertices<'a>, u32, u32, Option<&D>) + Send + Sync + 'static,
{
let site = &*((*args).geometryUserPtr as *const CallSite);
let slot = site.slots[CbKind::Displacement as usize];
if slot.closure.is_null() {
return;
}
let cb = &*(slot.closure as *const F);
let user_data = if slot.user_data.is_null() {
None
} else {
Some(&*(slot.user_data as *const D))
};
let len = (*args).N as usize;
let vertices = Vertices {
len,
u: (*args).u,
v: (*args).v,
ng_x: (*args).Ng_x,
ng_y: (*args).Ng_y,
ng_z: (*args).Ng_z,
p_x: (*args).P_x,
p_y: (*args).P_y,
p_z: (*args).P_z,
marker: PhantomData,
};
cb(
(*args).geometry,
vertices,
(*args).primID,
(*args).timeStep,
user_data,
);
}
Some(inner::<F, D>)
}
}
pub struct Vertices<'a> {
len: usize,
u: *const f32,
v: *const f32,
ng_x: *const f32,
ng_y: *const f32,
ng_z: *const f32,
p_x: *mut f32,
p_y: *mut f32,
p_z: *mut f32,
marker: PhantomData<&'a mut f32>,
}
impl<'a> Vertices<'a> {
pub fn into_iter_mut(self) -> VerticesIterMut<'a> {
VerticesIterMut {
inner: self,
cur: 0,
}
}
}
pub struct VerticesIterMut<'a> {
inner: Vertices<'a>,
cur: usize,
}
impl<'a> Iterator for VerticesIterMut<'a> {
type Item = ([f32; 2], [f32; 3], [&'a mut f32; 3]);
fn next(&mut self) -> Option<Self::Item> {
if self.cur < self.inner.len {
unsafe {
let u = *self.inner.u.add(self.cur);
let v = *self.inner.v.add(self.cur);
let ng_x = *self.inner.ng_x.add(self.cur);
let ng_y = *self.inner.ng_y.add(self.cur);
let ng_z = *self.inner.ng_z.add(self.cur);
let p_x = self.inner.p_x.add(self.cur);
let p_y = self.inner.p_y.add(self.cur);
let p_z = self.inner.p_z.add(self.cur);
self.cur += 1;
Some((
[u, v],
[ng_x, ng_y, ng_z],
[&mut *p_x, &mut *p_y, &mut *p_z],
))
}
} else {
None
}
}
}
impl<'a> ExactSizeIterator for VerticesIterMut<'a> {
fn len(&self) -> usize { self.inner.len - self.cur }
}
pub struct ValidityN<'a> {
ptr: *const i32,
len: usize,
marker: PhantomData<&'a [i32]>,
}
pub struct ValidityNIter<'a, 'b> {
inner: &'b ValidityN<'a>,
cur: usize,
}
impl<'a> ValidityN<'a> {
pub fn iter<'b>(&'b self) -> ValidityNIter<'a, 'b> {
ValidityNIter {
inner: self,
cur: 0,
}
}
pub fn iter_mut(&mut self) -> ValidityNIterMut<'_> {
ValidityNIterMut {
ptr: self.ptr as *mut i32,
len: self.len,
cur: 0,
_marker: PhantomData,
}
}
pub const fn len(&self) -> usize { self.len }
pub const fn is_empty(&self) -> bool { self.len == 0 }
#[inline(always)]
pub unsafe fn get_unchecked(&self, i: usize) -> i32 { *self.ptr.add(i) }
#[inline(always)]
pub unsafe fn set_unchecked(&mut self, i: usize, valid: i32) {
*(self.ptr.add(i) as *mut i32) = valid;
}
}
impl<'a> Index<usize> for ValidityN<'a> {
type Output = i32;
fn index(&self, index: usize) -> &Self::Output {
assert!(index < self.len, "index out of bounds");
unsafe { &*self.ptr.add(index) }
}
}
impl<'a> IndexMut<usize> for ValidityN<'a> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
assert!(index < self.len, "index out of bounds");
unsafe { &mut *(self.ptr.add(index) as *mut i32) }
}
}
impl<'a, 'b> Iterator for ValidityNIter<'a, 'b> {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
if self.cur < self.inner.len {
unsafe {
let valid = *self.inner.ptr.add(self.cur);
self.cur += 1;
Some(valid)
}
} else {
None
}
}
}
pub struct ValidityNIterMut<'b> {
ptr: *mut i32,
len: usize,
cur: usize,
_marker: PhantomData<&'b mut i32>,
}
impl<'b> Iterator for ValidityNIterMut<'b> {
type Item = &'b mut i32;
fn next(&mut self) -> Option<Self::Item> {
if self.cur < self.len {
unsafe {
let p = self.ptr.add(self.cur);
self.cur += 1;
Some(&mut *p)
}
} else {
None
}
}
}
#[cfg(test)]
mod validity_oob_tests {
use super::*;
fn validity_over(buf: &[i32]) -> ValidityN<'_> {
ValidityN {
ptr: buf.as_ptr(),
len: buf.len(),
marker: PhantomData,
}
}
#[test]
#[should_panic(expected = "index out of bounds")]
fn validity_index_out_of_bounds_panics() {
let buf = [-1i32; 4];
let v = validity_over(&buf);
let _ = v[4];
}
#[test]
#[should_panic(expected = "index out of bounds")]
fn validity_index_mut_out_of_bounds_panics() {
let buf = [-1i32; 4];
let mut v = validity_over(&buf);
v[4] = 0; }
#[test]
fn validity_index_in_bounds_ok() {
let buf = [-1i32, 0, -1, 0];
let v = validity_over(&buf);
assert_eq!(v[0], -1);
assert_eq!(v[3], 0);
}
fn validity_over_mut(buf: &mut [i32]) -> ValidityN<'_> {
ValidityN {
ptr: buf.as_mut_ptr() as *const i32,
len: buf.len(),
marker: PhantomData,
}
}
#[test]
fn iter_mut_writes_each_lane_once() {
let mut buf = [-1i32; 4];
{
let mut v = validity_over_mut(&mut buf);
for (k, lane) in v.iter_mut().enumerate() {
*lane = k as i32;
}
}
assert_eq!(buf, [0, 1, 2, 3]);
}
#[test]
fn get_set_unchecked_matches_checked() {
let mut buf = [-1i32, 0, -1, 0];
let mut v = validity_over_mut(&mut buf);
for i in 0..v.len() {
assert_eq!(unsafe { v.get_unchecked(i) }, v[i]);
}
unsafe { v.set_unchecked(1, -1) };
unsafe { v.set_unchecked(2, 0) };
assert_eq!(v[1], -1);
assert_eq!(v[2], 0);
assert_eq!(buf, [-1, -1, 0, 0]);
}
}