embree4_rs/
scene.rs

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    /// Constructs a new `Scene` instance from the given options.
15    ///
16    /// # Arguments
17    /// * `device` - A reference to the `Device` instance.
18    /// * `options` - The options for creating the scene.
19    ///
20    /// # Returns
21    /// A `Result` containing the `Scene` instance if successful, or an error if an error occurred.
22    ///
23    /// # Example
24    /// ```
25    /// use embree4_rs::*;
26    /// use embree4_sys::*;
27    ///
28    /// let device = Device::try_new(None).unwrap();
29    /// let options = SceneOptions {
30    ///     build_quality: RTCBuildQuality::HIGH,
31    ///     flags: RTCSceneFlags::COMPACT | RTCSceneFlags::ROBUST,
32    /// };
33    /// let scene = Scene::try_new(&device, options).unwrap();
34    /// ```
35    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    /// Sets the build quality of the scene.
57    ///
58    /// # Arguments
59    /// * `quality` - The build quality to set.
60    ///
61    /// # Returns
62    /// A `Result` indicating success or failure.
63    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    /// Sets the flags of the scene.
72    ///
73    /// # Arguments
74    /// * `flags` - The flags to set.
75    ///
76    /// # Returns
77    /// A `Result` indicating success or failure.
78    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    /// Attaches the given geometry to the scene.
86    ///
87    /// # Arguments
88    /// * `geometry` - A reference to the `Geometry` instance to attach.
89    ///
90    /// # Returns
91    /// * A `Result` containing the geometry ID if successful, or an error if an error occurred.
92    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    /// Commits the scene.
98    ///
99    /// # Returns
100    /// A `Result` containing the `CommittedScene` instance if successful, or an error if an error occurred.
101    ///
102    /// # Example
103    /// ```
104    /// use embree4_rs::*;
105    /// use embree4_sys::*;
106    ///
107    /// let device = Device::try_new(None).unwrap();
108    /// let options = Default::default();
109    /// let scene = Scene::try_new(&device, options).unwrap();
110    /// let scene = scene.commit().unwrap();
111    /// ```
112    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}