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)]
13pub struct Mesh {
15 handle: ObjectHandle,
16}
17
18impl Mesh {
19 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
21 Self { handle }
22 }
23
24 pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
26 self.handle.as_ptr()
27 }
28
29 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 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 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 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 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 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 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 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 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 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 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 pub fn vertex_count(&self) -> usize {
197 unsafe { ffi::mdl_mesh_vertex_count(self.handle.as_ptr()) as usize }
199 }
200
201 #[must_use]
202 pub fn vertex_buffer_count(&self) -> usize {
204 unsafe { ffi::mdl_mesh_vertex_buffer_count(self.handle.as_ptr()) as usize }
206 }
207
208 #[must_use]
209 pub fn vertex_buffer(&self, index: usize) -> Option<MeshBuffer> {
211 let ptr = unsafe { ffi::mdl_mesh_vertex_buffer_at(self.handle.as_ptr(), index as u64) };
213 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBuffer::from_handle)
215 }
216
217 #[must_use]
218 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 pub fn submesh_count(&self) -> usize {
228 unsafe { ffi::mdl_mesh_submesh_count(self.handle.as_ptr()) as usize }
230 }
231
232 #[must_use]
233 pub fn submesh(&self, index: usize) -> Option<Submesh> {
235 let ptr = unsafe { ffi::mdl_mesh_submesh_at(self.handle.as_ptr(), index as u64) };
237 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(Submesh::from_handle)
239 }
240
241 #[must_use]
242 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 pub fn bounding_box(&self) -> BoundingBox {
252 let mut min = [0.0_f32; 3];
253 let mut max = [0.0_f32; 3];
254 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 pub fn vertex_descriptor(&self) -> Option<VertexDescriptor> {
272 let ptr = unsafe { ffi::mdl_mesh_vertex_descriptor(self.handle.as_ptr()) };
274 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(VertexDescriptor::from_handle)
276 }
277
278 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 let ptr = unsafe {
286 ffi::mdl_mesh_vertex_attribute_data(self.handle.as_ptr(), attribute_name.as_ptr())
287 };
288 Ok(unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(VertexAttributeData::from_handle))
290 }
291
292 #[must_use]
293 pub fn as_object(&self) -> Object {
295 Object::from_handle(self.handle.clone())
296 }
297}
298
299#[derive(Debug, Clone)]
300pub struct MeshBuffer {
302 handle: ObjectHandle,
303}
304
305impl MeshBuffer {
306 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
308 Self { handle }
309 }
310
311 pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
313 self.handle.as_ptr()
314 }
315
316 pub fn info(&self) -> Result<MeshBufferInfo> {
318 parse_json(
319 unsafe { ffi::mdl_mesh_buffer_info_json(self.handle.as_ptr()) },
321 "MDLMeshBuffer",
322 )
323 }
324
325 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 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)]
346pub struct VertexAttributeData {
348 handle: ObjectHandle,
349}
350
351impl VertexAttributeData {
352 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
354 Self { handle }
355 }
356
357 pub fn info(&self) -> Result<VertexAttributeInfo> {
359 parse_json(
360 unsafe { ffi::mdl_vertex_attribute_data_info_json(self.handle.as_ptr()) },
362 "MDLVertexAttributeData",
363 )
364 }
365
366 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 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}