Skip to main content

modelio/
mesh.rs

1use std::ptr;
2
3use crate::error::Result;
4use crate::ffi;
5use crate::handle::ObjectHandle;
6use crate::object::Object;
7use crate::submesh::Submesh;
8use crate::types::{BoundingBox, GeometryType, MeshBufferInfo, VertexAttributeInfo};
9use crate::util::{c_string, parse_json, required_handle};
10use crate::vertex_attribute::VertexDescriptor;
11
12#[derive(Debug, Clone)]
13/// Wraps the corresponding Model I/O mesh counterpart.
14pub struct Mesh {
15    handle: ObjectHandle,
16}
17
18impl Mesh {
19    /// Builds this wrapper from the retained handle of the wrapped Model I/O mesh counterpart.
20    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
21        Self { handle }
22    }
23
24    /// Returns the opaque pointer used to call the wrapped Model I/O mesh counterpart.
25    pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
26        self.handle.as_ptr()
27    }
28
29    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh counterpart.
30    pub fn new_box(
31        extent: [f32; 3],
32        segments: [u32; 3],
33        inward_normals: bool,
34        geometry_type: GeometryType,
35    ) -> Result<Self> {
36        let mut out_mesh = ptr::null_mut();
37        let mut out_error = ptr::null_mut();
38        // SAFETY: The unsafe operation is valid in this context.
39        let status = unsafe {
40            ffi::mdl_mesh_new_box(
41                extent[0],
42                extent[1],
43                extent[2],
44                segments[0],
45                segments[1],
46                segments[2],
47                i32::from(inward_normals),
48                geometry_type.as_raw(),
49                &mut out_mesh,
50                &mut out_error,
51            )
52        };
53        crate::util::status_result(status, out_error)?;
54        Ok(Self::from_handle(required_handle(out_mesh, "MDLMesh box")?))
55    }
56
57    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh counterpart.
58    pub fn new_ellipsoid(
59        extent: [f32; 3],
60        segments: [u32; 2],
61        inward_normals: bool,
62        hemisphere: bool,
63        geometry_type: GeometryType,
64    ) -> Result<Self> {
65        let mut out_mesh = ptr::null_mut();
66        let mut out_error = ptr::null_mut();
67        // SAFETY: The unsafe operation is valid in this context.
68        let status = unsafe {
69            ffi::mdl_mesh_new_ellipsoid(
70                extent[0],
71                extent[1],
72                extent[2],
73                segments[0],
74                segments[1],
75                i32::from(inward_normals),
76                i32::from(hemisphere),
77                geometry_type.as_raw(),
78                &mut out_mesh,
79                &mut out_error,
80            )
81        };
82        crate::util::status_result(status, out_error)?;
83        Ok(Self::from_handle(required_handle(
84            out_mesh,
85            "MDLMesh ellipsoid",
86        )?))
87    }
88
89    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh counterpart.
90    pub fn new_sphere(
91        radius: f32,
92        segments: [u32; 2],
93        inward_normals: bool,
94        geometry_type: GeometryType,
95    ) -> Result<Self> {
96        Self::new_ellipsoid(
97            [radius, radius, radius],
98            segments,
99            inward_normals,
100            false,
101            geometry_type,
102        )
103    }
104
105    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh counterpart.
106    pub fn new_cylinder(
107        extent: [f32; 3],
108        segments: [u32; 2],
109        inward_normals: bool,
110        top_cap: bool,
111        bottom_cap: bool,
112        geometry_type: GeometryType,
113    ) -> Result<Self> {
114        let mut out_mesh = ptr::null_mut();
115        let mut out_error = ptr::null_mut();
116        // SAFETY: The unsafe operation is valid in this context.
117        let status = unsafe {
118            ffi::mdl_mesh_new_cylinder(
119                extent[0],
120                extent[1],
121                extent[2],
122                segments[0],
123                segments[1],
124                i32::from(inward_normals),
125                i32::from(top_cap),
126                i32::from(bottom_cap),
127                geometry_type.as_raw(),
128                &mut out_mesh,
129                &mut out_error,
130            )
131        };
132        crate::util::status_result(status, out_error)?;
133        Ok(Self::from_handle(required_handle(
134            out_mesh,
135            "MDLMesh cylinder",
136        )?))
137    }
138
139    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh counterpart.
140    pub fn new_plane(
141        extent: [f32; 3],
142        segments: [u32; 2],
143        geometry_type: GeometryType,
144    ) -> Result<Self> {
145        let mut out_mesh = ptr::null_mut();
146        let mut out_error = ptr::null_mut();
147        // SAFETY: The unsafe operation is valid in this context.
148        let status = unsafe {
149            ffi::mdl_mesh_new_plane(
150                extent[0],
151                extent[1],
152                extent[2],
153                segments[0],
154                segments[1],
155                geometry_type.as_raw(),
156                &mut out_mesh,
157                &mut out_error,
158            )
159        };
160        crate::util::status_result(status, out_error)?;
161        Ok(Self::from_handle(required_handle(
162            out_mesh,
163            "MDLMesh plane",
164        )?))
165    }
166
167    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O mesh counterpart.
168    pub fn new_icosahedron(
169        extent: [f32; 3],
170        inward_normals: bool,
171        geometry_type: GeometryType,
172    ) -> Result<Self> {
173        let mut out_mesh = ptr::null_mut();
174        let mut out_error = ptr::null_mut();
175        // SAFETY: The unsafe operation is valid in this context.
176        let status = unsafe {
177            ffi::mdl_mesh_new_icosahedron(
178                extent[0],
179                extent[1],
180                extent[2],
181                i32::from(inward_normals),
182                geometry_type.as_raw(),
183                &mut out_mesh,
184                &mut out_error,
185            )
186        };
187        crate::util::status_result(status, out_error)?;
188        Ok(Self::from_handle(required_handle(
189            out_mesh,
190            "MDLMesh icosahedron",
191        )?))
192    }
193
194    #[must_use]
195    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh counterpart.
196    pub fn vertex_count(&self) -> usize {
197        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
198        unsafe { ffi::mdl_mesh_vertex_count(self.handle.as_ptr()) as usize }
199    }
200
201    #[must_use]
202    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh counterpart.
203    pub fn vertex_buffer_count(&self) -> usize {
204        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
205        unsafe { ffi::mdl_mesh_vertex_buffer_count(self.handle.as_ptr()) as usize }
206    }
207
208    #[must_use]
209    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh counterpart.
210    pub fn vertex_buffer(&self, index: usize) -> Option<MeshBuffer> {
211        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
212        let ptr = unsafe { ffi::mdl_mesh_vertex_buffer_at(self.handle.as_ptr(), index as u64) };
213        // SAFETY: The unsafe operation is valid in this context.
214        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBuffer::from_handle)
215    }
216
217    #[must_use]
218    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh counterpart.
219    pub fn vertex_buffers(&self) -> Vec<MeshBuffer> {
220        (0..self.vertex_buffer_count())
221            .filter_map(|index| self.vertex_buffer(index))
222            .collect()
223    }
224
225    #[must_use]
226    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh counterpart.
227    pub fn submesh_count(&self) -> usize {
228        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
229        unsafe { ffi::mdl_mesh_submesh_count(self.handle.as_ptr()) as usize }
230    }
231
232    #[must_use]
233    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh counterpart.
234    pub fn submesh(&self, index: usize) -> Option<Submesh> {
235        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
236        let ptr = unsafe { ffi::mdl_mesh_submesh_at(self.handle.as_ptr(), index as u64) };
237        // SAFETY: The unsafe operation is valid in this context.
238        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(Submesh::from_handle)
239    }
240
241    #[must_use]
242    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh counterpart.
243    pub fn submeshes(&self) -> Vec<Submesh> {
244        (0..self.submesh_count())
245            .filter_map(|index| self.submesh(index))
246            .collect()
247    }
248
249    #[must_use]
250    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh counterpart.
251    pub fn bounding_box(&self) -> BoundingBox {
252        let mut min = [0.0_f32; 3];
253        let mut max = [0.0_f32; 3];
254        // SAFETY: The unsafe operation is valid in this context.
255        unsafe {
256            ffi::mdl_mesh_bounding_box(
257                self.handle.as_ptr(),
258                &mut min[0],
259                &mut min[1],
260                &mut min[2],
261                &mut max[0],
262                &mut max[1],
263                &mut max[2],
264            );
265        }
266        BoundingBox { min, max }
267    }
268
269    #[must_use]
270    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh counterpart.
271    pub fn vertex_descriptor(&self) -> Option<VertexDescriptor> {
272        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
273        let ptr = unsafe { ffi::mdl_mesh_vertex_descriptor(self.handle.as_ptr()) };
274        // SAFETY: The unsafe operation is valid in this context.
275        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(VertexDescriptor::from_handle)
276    }
277
278    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh counterpart.
279    pub fn vertex_attribute_data_named(
280        &self,
281        attribute_name: &str,
282    ) -> Result<Option<VertexAttributeData>> {
283        let attribute_name = c_string(attribute_name)?;
284        // SAFETY: The unsafe operation is valid in this context.
285        let ptr = unsafe {
286            ffi::mdl_mesh_vertex_attribute_data(self.handle.as_ptr(), attribute_name.as_ptr())
287        };
288        // SAFETY: The unsafe operation is valid in this context.
289        Ok(unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(VertexAttributeData::from_handle))
290    }
291
292    #[must_use]
293    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh counterpart.
294    pub fn as_object(&self) -> Object {
295        Object::from_handle(self.handle.clone())
296    }
297}
298
299#[derive(Debug, Clone)]
300/// Wraps the corresponding Model I/O mesh buffer counterpart.
301pub struct MeshBuffer {
302    handle: ObjectHandle,
303}
304
305impl MeshBuffer {
306    /// Builds this wrapper from the retained handle of the wrapped Model I/O mesh buffer counterpart.
307    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
308        Self { handle }
309    }
310
311    /// Returns the opaque pointer used to call the wrapped Model I/O mesh buffer counterpart.
312    pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
313        self.handle.as_ptr()
314    }
315
316    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer counterpart.
317    pub fn info(&self) -> Result<MeshBufferInfo> {
318        parse_json(
319            // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
320            unsafe { ffi::mdl_mesh_buffer_info_json(self.handle.as_ptr()) },
321            "MDLMeshBuffer",
322        )
323    }
324
325    /// Calls the corresponding Model I/O method on the wrapped Model I/O mesh buffer counterpart.
326    pub fn bytes(&self) -> Result<Vec<u8>> {
327        let info = self.info()?;
328        let mut bytes = vec![0_u8; info.length];
329        if bytes.is_empty() {
330            return Ok(bytes);
331        }
332        // SAFETY: The unsafe operation is valid in this context.
333        let written = unsafe {
334            ffi::mdl_mesh_buffer_copy_bytes(
335                self.handle.as_ptr(),
336                bytes.as_mut_ptr(),
337                bytes.len() as u64,
338            )
339        } as usize;
340        bytes.truncate(written);
341        Ok(bytes)
342    }
343}
344
345#[derive(Debug, Clone)]
346/// Wraps the corresponding Model I/O vertex attribute data counterpart.
347pub struct VertexAttributeData {
348    handle: ObjectHandle,
349}
350
351impl VertexAttributeData {
352    /// Builds this wrapper from the retained handle of the wrapped Model I/O vertex attribute data counterpart.
353    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
354        Self { handle }
355    }
356
357    /// Calls the corresponding Model I/O method on the wrapped Model I/O vertex attribute data counterpart.
358    pub fn info(&self) -> Result<VertexAttributeInfo> {
359        parse_json(
360            // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
361            unsafe { ffi::mdl_vertex_attribute_data_info_json(self.handle.as_ptr()) },
362            "MDLVertexAttributeData",
363        )
364    }
365
366    /// Calls the corresponding Model I/O method on the wrapped Model I/O vertex attribute data counterpart.
367    pub fn bytes(&self) -> Result<Vec<u8>> {
368        let info = self.info()?;
369        let mut bytes = vec![0_u8; info.buffer_size];
370        if bytes.is_empty() {
371            return Ok(bytes);
372        }
373        // SAFETY: The unsafe operation is valid in this context.
374        let written = unsafe {
375            ffi::mdl_vertex_attribute_data_copy_bytes(
376                self.handle.as_ptr(),
377                bytes.as_mut_ptr(),
378                bytes.len() as u64,
379            )
380        } as usize;
381        bytes.truncate(written);
382        Ok(bytes)
383    }
384}