1use std::ptr::null_mut;
2
3use anyhow::{bail, Result};
4use embree4_sys::{RTCBounds, RTCIntersectArguments};
5
6use crate::{device_error_raw, geometry::Geometry, Device};
7
8pub struct Scene {
9 pub device: Device,
10 handle: embree4_sys::RTCScene,
11}
12
13impl Scene {
14 pub fn try_new(device: Device, options: SceneOptions) -> Result<Self> {
36 let handle = unsafe { embree4_sys::rtcNewScene(device.handle) };
37
38 if handle.is_null() {
39 let error = device_error_raw(device.handle);
40 bail!("Could not create scene: {:?}", error);
41 }
42
43 let scene = Scene { device, handle };
44
45 if options.build_quality != Default::default() {
46 scene.set_build_quality(options.build_quality)?;
47 }
48
49 if options.flags != Default::default() {
50 scene.set_flags(options.flags)?;
51 }
52
53 Ok(scene)
54 }
55
56 pub fn set_build_quality(&self, quality: embree4_sys::RTCBuildQuality) -> Result<()> {
64 unsafe {
65 embree4_sys::rtcSetSceneBuildQuality(self.handle, quality);
66 }
67 self.device
68 .error_or((), "Could not set scene build quality")
69 }
70
71 pub fn set_flags(&self, flags: embree4_sys::RTCSceneFlags) -> Result<()> {
79 unsafe {
80 embree4_sys::rtcSetSceneFlags(self.handle, flags);
81 }
82 self.device.error_or((), "Could not set scene flags")
83 }
84
85 pub fn attach_geometry(&self, geometry: &dyn Geometry) -> Result<u32> {
93 let geom_id = unsafe { embree4_sys::rtcAttachGeometry(self.handle, *geometry.handle()) };
94 self.device.error_or(geom_id, "Could not attach geometry")
95 }
96
97 pub fn commit(self) -> Result<CommittedScene> {
113 unsafe {
114 embree4_sys::rtcCommitScene(self.handle);
115 }
116 self.device.error_or((), "Could not commit scene")?;
117 Ok(CommittedScene { scene: self })
118 }
119}
120
121impl Drop for Scene {
122 fn drop(&mut self) {
123 unsafe {
124 embree4_sys::rtcReleaseScene(self.handle);
125 }
126 }
127}
128
129#[derive(Default)]
130pub struct SceneOptions {
131 pub build_quality: embree4_sys::RTCBuildQuality,
132 pub flags: embree4_sys::RTCSceneFlags,
133}
134
135pub struct CommittedScene {
136 pub scene: Scene,
137}
138
139unsafe impl Sync for CommittedScene {}
140
141impl CommittedScene {
142 pub fn intersect_1(
143 &self,
144 ray: embree4_sys::RTCRay,
145 args: Option<&RTCIntersectArguments>,
146 ) -> Result<Option<embree4_sys::RTCRayHit>> {
147 let mut ray_hit = embree4_sys::RTCRayHit {
148 ray,
149 hit: Default::default(),
150 };
151
152 unsafe {
153 match args {
154 Some(args) => {
155 embree4_sys::rtcIntersect1(
156 self.scene.handle,
157 &mut ray_hit,
158 args as *const _ as _,
159 );
160 }
161 None => embree4_sys::rtcIntersect1(self.scene.handle, &mut ray_hit, null_mut()),
162 }
163 }
164 self.scene.device.error_or((), "Could not intersect ray")?;
165
166 Ok(
167 if ray_hit.hit.geomID != embree4_sys::RTC_INVALID_GEOMETRY_ID {
168 Some(ray_hit)
169 } else {
170 None
171 },
172 )
173 }
174
175 pub fn bounds(&self) -> Result<embree4_sys::RTCBounds> {
176 let bounds = RTCBounds::default();
177 unsafe { embree4_sys::rtcGetSceneBounds(self.scene.handle, &bounds as *const _ as *mut _) }
178 self.scene
179 .device
180 .error_or(bounds, "Could not get scene bounds")
181 }
182}