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 {
14 handle: ObjectHandle,
15}
16
17impl Mesh {
18 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
19 Self { handle }
20 }
21
22 pub fn new_box(
23 extent: [f32; 3],
24 segments: [u32; 3],
25 inward_normals: bool,
26 geometry_type: GeometryType,
27 ) -> Result<Self> {
28 let mut out_mesh = ptr::null_mut();
29 let mut out_error = ptr::null_mut();
30 let status = unsafe {
31 ffi::mdl_mesh_new_box(
32 extent[0],
33 extent[1],
34 extent[2],
35 segments[0],
36 segments[1],
37 segments[2],
38 i32::from(inward_normals),
39 geometry_type.as_raw(),
40 &mut out_mesh,
41 &mut out_error,
42 )
43 };
44 crate::util::status_result(status, out_error)?;
45 Ok(Self::from_handle(required_handle(out_mesh, "MDLMesh box")?))
46 }
47
48 pub fn new_ellipsoid(
49 extent: [f32; 3],
50 segments: [u32; 2],
51 inward_normals: bool,
52 hemisphere: bool,
53 geometry_type: GeometryType,
54 ) -> Result<Self> {
55 let mut out_mesh = ptr::null_mut();
56 let mut out_error = ptr::null_mut();
57 let status = unsafe {
58 ffi::mdl_mesh_new_ellipsoid(
59 extent[0],
60 extent[1],
61 extent[2],
62 segments[0],
63 segments[1],
64 i32::from(inward_normals),
65 i32::from(hemisphere),
66 geometry_type.as_raw(),
67 &mut out_mesh,
68 &mut out_error,
69 )
70 };
71 crate::util::status_result(status, out_error)?;
72 Ok(Self::from_handle(required_handle(
73 out_mesh,
74 "MDLMesh ellipsoid",
75 )?))
76 }
77
78 pub fn new_sphere(
79 radius: f32,
80 segments: [u32; 2],
81 inward_normals: bool,
82 geometry_type: GeometryType,
83 ) -> Result<Self> {
84 Self::new_ellipsoid(
85 [radius, radius, radius],
86 segments,
87 inward_normals,
88 false,
89 geometry_type,
90 )
91 }
92
93 pub fn new_cylinder(
94 extent: [f32; 3],
95 segments: [u32; 2],
96 inward_normals: bool,
97 top_cap: bool,
98 bottom_cap: bool,
99 geometry_type: GeometryType,
100 ) -> Result<Self> {
101 let mut out_mesh = ptr::null_mut();
102 let mut out_error = ptr::null_mut();
103 let status = unsafe {
104 ffi::mdl_mesh_new_cylinder(
105 extent[0],
106 extent[1],
107 extent[2],
108 segments[0],
109 segments[1],
110 i32::from(inward_normals),
111 i32::from(top_cap),
112 i32::from(bottom_cap),
113 geometry_type.as_raw(),
114 &mut out_mesh,
115 &mut out_error,
116 )
117 };
118 crate::util::status_result(status, out_error)?;
119 Ok(Self::from_handle(required_handle(
120 out_mesh,
121 "MDLMesh cylinder",
122 )?))
123 }
124
125 pub fn new_plane(
126 extent: [f32; 3],
127 segments: [u32; 2],
128 geometry_type: GeometryType,
129 ) -> Result<Self> {
130 let mut out_mesh = ptr::null_mut();
131 let mut out_error = ptr::null_mut();
132 let status = unsafe {
133 ffi::mdl_mesh_new_plane(
134 extent[0],
135 extent[1],
136 extent[2],
137 segments[0],
138 segments[1],
139 geometry_type.as_raw(),
140 &mut out_mesh,
141 &mut out_error,
142 )
143 };
144 crate::util::status_result(status, out_error)?;
145 Ok(Self::from_handle(required_handle(
146 out_mesh,
147 "MDLMesh plane",
148 )?))
149 }
150
151 pub fn new_icosahedron(
152 extent: [f32; 3],
153 inward_normals: bool,
154 geometry_type: GeometryType,
155 ) -> Result<Self> {
156 let mut out_mesh = ptr::null_mut();
157 let mut out_error = ptr::null_mut();
158 let status = unsafe {
159 ffi::mdl_mesh_new_icosahedron(
160 extent[0],
161 extent[1],
162 extent[2],
163 i32::from(inward_normals),
164 geometry_type.as_raw(),
165 &mut out_mesh,
166 &mut out_error,
167 )
168 };
169 crate::util::status_result(status, out_error)?;
170 Ok(Self::from_handle(required_handle(
171 out_mesh,
172 "MDLMesh icosahedron",
173 )?))
174 }
175
176 #[must_use]
177 pub fn vertex_count(&self) -> usize {
178 unsafe { ffi::mdl_mesh_vertex_count(self.handle.as_ptr()) as usize }
179 }
180
181 #[must_use]
182 pub fn vertex_buffer_count(&self) -> usize {
183 unsafe { ffi::mdl_mesh_vertex_buffer_count(self.handle.as_ptr()) as usize }
184 }
185
186 #[must_use]
187 pub fn vertex_buffer(&self, index: usize) -> Option<MeshBuffer> {
188 let ptr = unsafe { ffi::mdl_mesh_vertex_buffer_at(self.handle.as_ptr(), index as u64) };
189 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBuffer::from_handle)
190 }
191
192 #[must_use]
193 pub fn vertex_buffers(&self) -> Vec<MeshBuffer> {
194 (0..self.vertex_buffer_count())
195 .filter_map(|index| self.vertex_buffer(index))
196 .collect()
197 }
198
199 #[must_use]
200 pub fn submesh_count(&self) -> usize {
201 unsafe { ffi::mdl_mesh_submesh_count(self.handle.as_ptr()) as usize }
202 }
203
204 #[must_use]
205 pub fn submesh(&self, index: usize) -> Option<Submesh> {
206 let ptr = unsafe { ffi::mdl_mesh_submesh_at(self.handle.as_ptr(), index as u64) };
207 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(Submesh::from_handle)
208 }
209
210 #[must_use]
211 pub fn submeshes(&self) -> Vec<Submesh> {
212 (0..self.submesh_count())
213 .filter_map(|index| self.submesh(index))
214 .collect()
215 }
216
217 #[must_use]
218 pub fn bounding_box(&self) -> BoundingBox {
219 let mut min = [0.0_f32; 3];
220 let mut max = [0.0_f32; 3];
221 unsafe {
222 ffi::mdl_mesh_bounding_box(
223 self.handle.as_ptr(),
224 &mut min[0],
225 &mut min[1],
226 &mut min[2],
227 &mut max[0],
228 &mut max[1],
229 &mut max[2],
230 );
231 }
232 BoundingBox { min, max }
233 }
234
235 #[must_use]
236 pub fn vertex_descriptor(&self) -> Option<VertexDescriptor> {
237 let ptr = unsafe { ffi::mdl_mesh_vertex_descriptor(self.handle.as_ptr()) };
238 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(VertexDescriptor::from_handle)
239 }
240
241 pub fn vertex_attribute_data_named(
242 &self,
243 attribute_name: &str,
244 ) -> Result<Option<VertexAttributeData>> {
245 let attribute_name = c_string(attribute_name)?;
246 let ptr = unsafe {
247 ffi::mdl_mesh_vertex_attribute_data(self.handle.as_ptr(), attribute_name.as_ptr())
248 };
249 Ok(unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(VertexAttributeData::from_handle))
250 }
251
252 #[must_use]
253 pub fn as_object(&self) -> Object {
254 Object::from_handle(self.handle.clone())
255 }
256}
257
258#[derive(Debug, Clone)]
259pub struct MeshBuffer {
260 handle: ObjectHandle,
261}
262
263impl MeshBuffer {
264 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
265 Self { handle }
266 }
267
268 pub fn info(&self) -> Result<MeshBufferInfo> {
269 parse_json(
270 unsafe { ffi::mdl_mesh_buffer_info_json(self.handle.as_ptr()) },
271 "MDLMeshBuffer",
272 )
273 }
274
275 pub fn bytes(&self) -> Result<Vec<u8>> {
276 let info = self.info()?;
277 let mut bytes = vec![0_u8; info.length];
278 if bytes.is_empty() {
279 return Ok(bytes);
280 }
281 let written = unsafe {
282 ffi::mdl_mesh_buffer_copy_bytes(
283 self.handle.as_ptr(),
284 bytes.as_mut_ptr(),
285 bytes.len() as u64,
286 )
287 } as usize;
288 bytes.truncate(written);
289 Ok(bytes)
290 }
291}
292
293#[derive(Debug, Clone)]
294pub struct VertexAttributeData {
295 handle: ObjectHandle,
296}
297
298impl VertexAttributeData {
299 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
300 Self { handle }
301 }
302
303 pub fn info(&self) -> Result<VertexAttributeInfo> {
304 parse_json(
305 unsafe { ffi::mdl_vertex_attribute_data_info_json(self.handle.as_ptr()) },
306 "MDLVertexAttributeData",
307 )
308 }
309
310 pub fn bytes(&self) -> Result<Vec<u8>> {
311 let info = self.info()?;
312 let mut bytes = vec![0_u8; info.buffer_size];
313 if bytes.is_empty() {
314 return Ok(bytes);
315 }
316 let written = unsafe {
317 ffi::mdl_vertex_attribute_data_copy_bytes(
318 self.handle.as_ptr(),
319 bytes.as_mut_ptr(),
320 bytes.len() as u64,
321 )
322 } as usize;
323 bytes.truncate(written);
324 Ok(bytes)
325 }
326}