use std::ptr::null_mut;
use anyhow::{bail, Result};
use embree4_sys::{RTCBounds, RTCIntersectArguments};
use crate::{device_error_raw, geometry::Geometry, Device};
pub struct Scene {
pub device: Device,
handle: embree4_sys::RTCScene,
}
impl Scene {
pub fn try_new(device: Device, options: SceneOptions) -> Result<Self> {
let handle = unsafe { embree4_sys::rtcNewScene(device.handle) };
if handle.is_null() {
let error = device_error_raw(device.handle);
bail!("Could not create scene: {:?}", error);
}
let scene = Scene { device, handle };
if options.build_quality != Default::default() {
scene.set_build_quality(options.build_quality)?;
}
if options.flags != Default::default() {
scene.set_flags(options.flags)?;
}
Ok(scene)
}
pub fn set_build_quality(&self, quality: embree4_sys::RTCBuildQuality) -> Result<()> {
unsafe {
embree4_sys::rtcSetSceneBuildQuality(self.handle, quality);
}
self.device
.error_or((), "Could not set scene build quality")
}
pub fn set_flags(&self, flags: embree4_sys::RTCSceneFlags) -> Result<()> {
unsafe {
embree4_sys::rtcSetSceneFlags(self.handle, flags);
}
self.device.error_or((), "Could not set scene flags")
}
pub fn attach_geometry(&self, geometry: &dyn Geometry) -> Result<u32> {
let geom_id = unsafe { embree4_sys::rtcAttachGeometry(self.handle, *geometry.handle()) };
self.device.error_or(geom_id, "Could not attach geometry")
}
pub fn commit(self) -> Result<CommittedScene> {
unsafe {
embree4_sys::rtcCommitScene(self.handle);
}
self.device.error_or((), "Could not commit scene")?;
Ok(CommittedScene { scene: self })
}
}
impl Drop for Scene {
fn drop(&mut self) {
unsafe {
embree4_sys::rtcReleaseScene(self.handle);
}
}
}
#[derive(Default)]
pub struct SceneOptions {
pub build_quality: embree4_sys::RTCBuildQuality,
pub flags: embree4_sys::RTCSceneFlags,
}
pub struct CommittedScene {
pub scene: Scene,
}
unsafe impl Sync for CommittedScene {}
impl CommittedScene {
pub fn intersect_1(
&self,
ray: embree4_sys::RTCRay,
args: Option<&RTCIntersectArguments>,
) -> Result<Option<embree4_sys::RTCRayHit>> {
let mut ray_hit = embree4_sys::RTCRayHit {
ray,
hit: Default::default(),
};
unsafe {
match args {
Some(args) => {
embree4_sys::rtcIntersect1(
self.scene.handle,
&mut ray_hit,
args as *const _ as _,
);
}
None => embree4_sys::rtcIntersect1(self.scene.handle, &mut ray_hit, null_mut()),
}
}
self.scene.device.error_or((), "Could not intersect ray")?;
Ok(
if ray_hit.hit.geomID != embree4_sys::RTC_INVALID_GEOMETRY_ID {
Some(ray_hit)
} else {
None
},
)
}
pub fn bounds(&self) -> Result<embree4_sys::RTCBounds> {
let bounds = RTCBounds::default();
unsafe { embree4_sys::rtcGetSceneBounds(self.scene.handle, &bounds as *const _ as *mut _) }
self.scene
.device
.error_or(bounds, "Could not get scene bounds")
}
}