modelio-rs 0.2.4

Safe Rust bindings for Apple's ModelIO framework — assets, meshes, materials, lights, cameras, voxels, textures, and animation on macOS
Documentation
use std::ptr;

use crate::error::Result;
use crate::ffi;
use crate::handle::ObjectHandle;
use crate::object::Object;
use crate::texture::Texture;
use crate::types::{BoundingBox, CameraInfo, CameraProjection, StereoscopicCameraInfo};
use crate::util::{parse_json, required_handle};

#[derive(Debug, Clone)]
/// Wraps the corresponding Model I/O camera counterpart.
pub struct Camera {
    handle: ObjectHandle,
}

impl Camera {
    /// Builds this wrapper from the retained handle of the wrapped Model I/O camera counterpart.
    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
        Self { handle }
    }

    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O camera counterpart.
    pub fn new() -> Result<Self> {
        let mut out_camera = ptr::null_mut();
        let mut out_error = ptr::null_mut();
        // SAFETY: Output pointers are initialized and managed; FFI function is called safely.
        let status = unsafe { ffi::mdl_camera_new(&mut out_camera, &mut out_error) };
        crate::util::status_result(status, out_error)?;
        Ok(Self::from_handle(required_handle(out_camera, "MDLCamera")?))
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O camera counterpart.
    pub fn info(&self) -> Result<CameraInfo> {
        parse_json(
            // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
            unsafe { ffi::mdl_camera_info_json(self.handle.as_ptr()) },
            "MDLCamera",
        )
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O camera counterpart.
    pub fn set_projection(&self, projection: CameraProjection) {
        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
        unsafe { ffi::mdl_camera_set_projection(self.handle.as_ptr(), projection.as_raw()) };
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O camera counterpart.
    pub fn set_near_visibility_distance(&self, value: f32) {
        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
        unsafe { ffi::mdl_camera_set_near_visibility_distance(self.handle.as_ptr(), value) };
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O camera counterpart.
    pub fn set_far_visibility_distance(&self, value: f32) {
        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
        unsafe { ffi::mdl_camera_set_far_visibility_distance(self.handle.as_ptr(), value) };
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O camera counterpart.
    pub fn set_world_to_meters_conversion_scale(&self, value: f32) {
        // SAFETY: The unsafe operation is valid in this context.
        unsafe {
            ffi::mdl_camera_set_world_to_meters_conversion_scale(self.handle.as_ptr(), value);
        };
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O camera counterpart.
    pub fn set_focal_length(&self, value: f32) {
        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
        unsafe { ffi::mdl_camera_set_focal_length(self.handle.as_ptr(), value) };
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O camera counterpart.
    pub fn set_focus_distance(&self, value: f32) {
        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
        unsafe { ffi::mdl_camera_set_focus_distance(self.handle.as_ptr(), value) };
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O camera counterpart.
    pub fn set_field_of_view(&self, value: f32) {
        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
        unsafe { ffi::mdl_camera_set_field_of_view(self.handle.as_ptr(), value) };
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O camera counterpart.
    pub fn look_at(&self, focus_position: [f32; 3]) {
        // SAFETY: The unsafe operation is valid in this context.
        unsafe {
            ffi::mdl_camera_look_at(
                self.handle.as_ptr(),
                focus_position[0],
                focus_position[1],
                focus_position[2],
            );
        };
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O camera counterpart.
    pub fn look_at_from(&self, focus_position: [f32; 3], camera_position: [f32; 3]) {
        // SAFETY: The unsafe operation is valid in this context.
        unsafe {
            ffi::mdl_camera_look_at_from(
                self.handle.as_ptr(),
                focus_position[0],
                focus_position[1],
                focus_position[2],
                camera_position[0],
                camera_position[1],
                camera_position[2],
            );
        };
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O camera counterpart.
    pub fn frame_bounding_box(&self, bounding_box: BoundingBox, set_near_and_far: bool) {
        // SAFETY: The unsafe operation is valid in this context.
        unsafe {
            ffi::mdl_camera_frame_bounding_box(
                self.handle.as_ptr(),
                bounding_box.min[0],
                bounding_box.min[1],
                bounding_box.min[2],
                bounding_box.max[0],
                bounding_box.max[1],
                bounding_box.max[2],
                i32::from(set_near_and_far),
            );
        };
    }

    #[must_use]
    /// Calls the corresponding Model I/O method on the wrapped Model I/O camera counterpart.
    pub fn ray_to(&self, pixel: [i32; 2], viewport: [i32; 2]) -> [f32; 3] {
        let mut ray = [0.0_f32; 3];
        // SAFETY: The unsafe operation is valid in this context.
        unsafe {
            ffi::mdl_camera_ray_to(
                self.handle.as_ptr(),
                pixel[0],
                pixel[1],
                viewport[0],
                viewport[1],
                &mut ray[0],
                &mut ray[1],
                &mut ray[2],
            );
        };
        ray
    }

    #[must_use]
    /// Calls the corresponding Model I/O method on the wrapped Model I/O camera counterpart.
    pub fn bokeh_kernel(&self, size: [i32; 2]) -> Option<Texture> {
        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
        let ptr = unsafe { ffi::mdl_camera_bokeh_kernel(self.handle.as_ptr(), size[0], size[1]) };
        // SAFETY: The unsafe operation is valid in this context.
        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(Texture::from_handle)
    }

    #[must_use]
    /// Calls the corresponding Model I/O method on the wrapped Model I/O camera counterpart.
    pub fn as_object(&self) -> Object {
        Object::from_handle(self.handle.clone())
    }
}

#[derive(Debug, Clone)]
/// Wraps the corresponding Model I/O stereoscopic camera counterpart.
pub struct StereoscopicCamera {
    handle: ObjectHandle,
}

impl StereoscopicCamera {
    /// Builds this wrapper from the retained handle of the wrapped Model I/O stereoscopic camera counterpart.
    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
        Self { handle }
    }

    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O stereoscopic camera counterpart.
    pub fn new() -> Result<Self> {
        let mut out_camera = ptr::null_mut();
        let mut out_error = ptr::null_mut();
        // SAFETY: Output pointers are initialized and managed; FFI function is called safely.
        let status = unsafe { ffi::mdl_stereoscopic_camera_new(&mut out_camera, &mut out_error) };
        crate::util::status_result(status, out_error)?;
        Ok(Self::from_handle(required_handle(
            out_camera,
            "MDLStereoscopicCamera",
        )?))
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O stereoscopic camera counterpart.
    pub fn info(&self) -> Result<StereoscopicCameraInfo> {
        parse_json(
            // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
            unsafe { ffi::mdl_stereoscopic_camera_info_json(self.handle.as_ptr()) },
            "MDLStereoscopicCamera",
        )
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O stereoscopic camera counterpart.
    pub fn set_inter_pupillary_distance(&self, value: f32) {
        // SAFETY: The unsafe operation is valid in this context.
        unsafe {
            ffi::mdl_stereoscopic_camera_set_inter_pupillary_distance(self.handle.as_ptr(), value);
        };
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O stereoscopic camera counterpart.
    pub fn set_left_vergence(&self, value: f32) {
        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
        unsafe { ffi::mdl_stereoscopic_camera_set_left_vergence(self.handle.as_ptr(), value) };
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O stereoscopic camera counterpart.
    pub fn set_right_vergence(&self, value: f32) {
        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
        unsafe { ffi::mdl_stereoscopic_camera_set_right_vergence(self.handle.as_ptr(), value) };
    }

    /// Calls the corresponding Model I/O method on the wrapped Model I/O stereoscopic camera counterpart.
    pub fn set_overlap(&self, value: f32) {
        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
        unsafe { ffi::mdl_stereoscopic_camera_set_overlap(self.handle.as_ptr(), value) };
    }

    #[must_use]
    /// Calls the corresponding Model I/O method on the wrapped Model I/O stereoscopic camera counterpart.
    pub fn as_camera(&self) -> Camera {
        Camera::from_handle(self.handle.clone())
    }

    #[must_use]
    /// Calls the corresponding Model I/O method on the wrapped Model I/O stereoscopic camera counterpart.
    pub fn as_object(&self) -> Object {
        Object::from_handle(self.handle.clone())
    }
}