Skip to main content

modelio/
light.rs

1use std::ptr;
2
3use crate::error::Result;
4use crate::ffi;
5use crate::handle::ObjectHandle;
6use crate::object::Object;
7use crate::types::{LightInfo, LightType};
8use crate::util::{c_string, parse_json, required_handle};
9
10#[derive(Debug, Clone)]
11/// Wraps the corresponding Model I/O light counterpart.
12pub struct Light {
13    handle: ObjectHandle,
14}
15
16impl Light {
17    /// Builds this wrapper from the retained handle of the wrapped Model I/O light counterpart.
18    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
19        Self { handle }
20    }
21
22    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O light counterpart.
23    pub fn new() -> Result<Self> {
24        let mut out_light = ptr::null_mut();
25        let mut out_error = ptr::null_mut();
26        // SAFETY: Output pointers are initialized and managed; FFI function is called safely.
27        let status = unsafe { ffi::mdl_light_new(&mut out_light, &mut out_error) };
28        crate::util::status_result(status, out_error)?;
29        Ok(Self::from_handle(required_handle(out_light, "MDLLight")?))
30    }
31
32    /// Calls the corresponding Model I/O method on the wrapped Model I/O light counterpart.
33    pub fn info(&self) -> Result<LightInfo> {
34        parse_json(
35            // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
36            unsafe { ffi::mdl_light_info_json(self.handle.as_ptr()) },
37            "MDLLight",
38        )
39    }
40
41    /// Calls the corresponding Model I/O method on the wrapped Model I/O light counterpart.
42    pub fn set_light_type(&self, light_type: LightType) {
43        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
44        unsafe { ffi::mdl_light_set_light_type(self.handle.as_ptr(), light_type.as_raw()) };
45    }
46
47    /// Calls the corresponding Model I/O method on the wrapped Model I/O light counterpart.
48    pub fn set_color_space(&self, color_space: &str) -> Result<()> {
49        let color_space = c_string(color_space)?;
50        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
51        unsafe { ffi::mdl_light_set_color_space(self.handle.as_ptr(), color_space.as_ptr()) };
52        Ok(())
53    }
54
55    #[must_use]
56    /// Calls the corresponding Model I/O method on the wrapped Model I/O light counterpart.
57    pub fn irradiance_at_point(&self, point: [f32; 3]) -> [f32; 4] {
58        let mut components = [0.0_f32; 4];
59        // SAFETY: The unsafe operation is valid in this context.
60        unsafe {
61            ffi::mdl_light_irradiance_at_point(
62                self.handle.as_ptr(),
63                point[0],
64                point[1],
65                point[2],
66                &mut components[0],
67                &mut components[1],
68                &mut components[2],
69                &mut components[3],
70            );
71        }
72        components
73    }
74
75    #[must_use]
76    /// Calls the corresponding Model I/O method on the wrapped Model I/O light counterpart.
77    pub fn as_object(&self) -> Object {
78        Object::from_handle(self.handle.clone())
79    }
80}