Skip to main content

modelio/
mesh_buffer.rs

1use std::ptr;
2
3use crate::error::{ModelIoError, Result};
4use crate::ffi;
5use crate::handle::ObjectHandle;
6use crate::mesh::MeshBuffer;
7use crate::types::MeshBufferType;
8use crate::util::required_handle;
9
10#[derive(Debug, Clone)]
11pub struct MeshBufferMap {
12    handle: ObjectHandle,
13    length: usize,
14}
15
16impl MeshBufferMap {
17    fn from_handle(handle: ObjectHandle, length: usize) -> Self {
18        Self { handle, length }
19    }
20
21    pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
22        self.handle.as_ptr()
23    }
24
25    #[must_use]
26    pub fn length(&self) -> usize {
27        self.length
28    }
29
30    #[must_use]
31    pub fn bytes(&self) -> Vec<u8> {
32        let mut bytes = vec![0_u8; self.length];
33        if bytes.is_empty() {
34            return bytes;
35        }
36        let written = unsafe {
37            ffi::mdl_mesh_buffer_map_copy_bytes(
38                self.as_ptr(),
39                self.length as u64,
40                bytes.as_mut_ptr(),
41                bytes.len() as u64,
42            )
43        } as usize;
44        bytes.truncate(written);
45        bytes
46    }
47
48    pub fn write(&self, offset: usize, bytes: &[u8]) -> usize {
49        unsafe {
50            ffi::mdl_mesh_buffer_map_write_bytes(
51                self.as_ptr(),
52                self.length as u64,
53                bytes.as_ptr(),
54                bytes.len() as u64,
55                offset as u64,
56            ) as usize
57        }
58    }
59}
60
61#[derive(Debug, Clone)]
62pub struct MeshBufferAllocator {
63    handle: ObjectHandle,
64}
65
66impl MeshBufferAllocator {
67    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
68        Self { handle }
69    }
70
71    pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
72        self.handle.as_ptr()
73    }
74
75    pub fn new_zone(&self, capacity: usize) -> Result<MeshBufferZone> {
76        let mut out_zone = ptr::null_mut();
77        let mut out_error = ptr::null_mut();
78        let status = unsafe {
79            ffi::mdl_mesh_buffer_allocator_new_zone(
80                self.as_ptr(),
81                capacity as u64,
82                &mut out_zone,
83                &mut out_error,
84            )
85        };
86        crate::util::status_result(status, out_error)?;
87        Ok(MeshBufferZone::from_handle(required_handle(
88            out_zone,
89            "MDLMeshBufferZone",
90        )?))
91    }
92
93    pub fn new_zone_for_buffers(
94        &self,
95        sizes: &[usize],
96        types: &[MeshBufferType],
97    ) -> Result<MeshBufferZone> {
98        if sizes.len() != types.len() {
99            return Err(ModelIoError::new(
100                ffi::status::INVALID_ARGUMENT,
101                "mesh buffer sizes and types must have the same length",
102            ));
103        }
104        let raw_sizes = sizes.iter().map(|size| *size as u64).collect::<Vec<_>>();
105        let raw_types = types.iter().map(|buffer_type| buffer_type.as_raw()).collect::<Vec<_>>();
106        let mut out_zone = ptr::null_mut();
107        let mut out_error = ptr::null_mut();
108        let status = unsafe {
109            ffi::mdl_mesh_buffer_allocator_new_zone_for_buffers_with_size(
110                self.as_ptr(),
111                raw_sizes.as_ptr(),
112                raw_types.as_ptr(),
113                raw_sizes.len() as u64,
114                &mut out_zone,
115                &mut out_error,
116            )
117        };
118        crate::util::status_result(status, out_error)?;
119        Ok(MeshBufferZone::from_handle(required_handle(
120            out_zone,
121            "MDLMeshBufferZone",
122        )?))
123    }
124
125    pub fn new_buffer(&self, length: usize, buffer_type: MeshBufferType) -> Result<MeshBuffer> {
126        let mut out_buffer = ptr::null_mut();
127        let mut out_error = ptr::null_mut();
128        let status = unsafe {
129            ffi::mdl_mesh_buffer_allocator_new_buffer(
130                self.as_ptr(),
131                length as u64,
132                buffer_type.as_raw(),
133                &mut out_buffer,
134                &mut out_error,
135            )
136        };
137        crate::util::status_result(status, out_error)?;
138        Ok(MeshBuffer::from_handle(required_handle(
139            out_buffer,
140            "MDLMeshBuffer",
141        )?))
142    }
143
144    pub fn new_buffer_with_data(&self, data: &[u8], buffer_type: MeshBufferType) -> Result<MeshBuffer> {
145        let mut out_buffer = ptr::null_mut();
146        let mut out_error = ptr::null_mut();
147        let status = unsafe {
148            ffi::mdl_mesh_buffer_allocator_new_buffer_with_data(
149                self.as_ptr(),
150                data.as_ptr(),
151                data.len() as u64,
152                buffer_type.as_raw(),
153                &mut out_buffer,
154                &mut out_error,
155            )
156        };
157        crate::util::status_result(status, out_error)?;
158        Ok(MeshBuffer::from_handle(required_handle(
159            out_buffer,
160            "MDLMeshBuffer",
161        )?))
162    }
163
164    pub fn new_buffer_from_zone(
165        &self,
166        zone: Option<&MeshBufferZone>,
167        length: usize,
168        buffer_type: MeshBufferType,
169    ) -> Result<Option<MeshBuffer>> {
170        let mut out_buffer = ptr::null_mut();
171        let mut out_error = ptr::null_mut();
172        let status = unsafe {
173            ffi::mdl_mesh_buffer_allocator_new_buffer_from_zone_length(
174                self.as_ptr(),
175                zone.map_or(ptr::null_mut(), MeshBufferZone::as_ptr),
176                length as u64,
177                buffer_type.as_raw(),
178                &mut out_buffer,
179                &mut out_error,
180            )
181        };
182        crate::util::status_result(status, out_error)?;
183        Ok(unsafe { ObjectHandle::from_retained_ptr(out_buffer) }.map(MeshBuffer::from_handle))
184    }
185
186    pub fn new_buffer_from_zone_with_data(
187        &self,
188        zone: Option<&MeshBufferZone>,
189        data: &[u8],
190        buffer_type: MeshBufferType,
191    ) -> Result<Option<MeshBuffer>> {
192        let mut out_buffer = ptr::null_mut();
193        let mut out_error = ptr::null_mut();
194        let status = unsafe {
195            ffi::mdl_mesh_buffer_allocator_new_buffer_from_zone_data(
196                self.as_ptr(),
197                zone.map_or(ptr::null_mut(), MeshBufferZone::as_ptr),
198                data.as_ptr(),
199                data.len() as u64,
200                buffer_type.as_raw(),
201                &mut out_buffer,
202                &mut out_error,
203            )
204        };
205        crate::util::status_result(status, out_error)?;
206        Ok(unsafe { ObjectHandle::from_retained_ptr(out_buffer) }.map(MeshBuffer::from_handle))
207    }
208}
209
210#[derive(Debug, Clone)]
211pub struct MeshBufferZone {
212    handle: ObjectHandle,
213}
214
215impl MeshBufferZone {
216    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
217        Self { handle }
218    }
219
220    pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
221        self.handle.as_ptr()
222    }
223
224    #[must_use]
225    pub fn capacity(&self) -> usize {
226        unsafe { ffi::mdl_mesh_buffer_zone_capacity(self.as_ptr()) as usize }
227    }
228
229    #[must_use]
230    pub fn allocator(&self) -> Option<MeshBufferAllocator> {
231        let ptr = unsafe { ffi::mdl_mesh_buffer_zone_allocator(self.as_ptr()) };
232        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBufferAllocator::from_handle)
233    }
234
235    #[must_use]
236    pub fn as_default(&self) -> Option<MeshBufferZoneDefault> {
237        (unsafe { ffi::mdl_mesh_buffer_zone_is_default(self.as_ptr()) != 0 })
238            .then(|| MeshBufferZoneDefault::from_handle(self.handle.clone()))
239    }
240}
241
242#[derive(Debug, Clone)]
243pub struct MeshBufferZoneDefault {
244    handle: ObjectHandle,
245}
246
247impl MeshBufferZoneDefault {
248    fn from_handle(handle: ObjectHandle) -> Self {
249        Self { handle }
250    }
251
252    pub fn new() -> Result<Self> {
253        let mut out_zone = ptr::null_mut();
254        let mut out_error = ptr::null_mut();
255        let status = unsafe { ffi::mdl_mesh_buffer_zone_default_new(&mut out_zone, &mut out_error) };
256        crate::util::status_result(status, out_error)?;
257        Ok(Self::from_handle(required_handle(
258            out_zone,
259            "MDLMeshBufferZoneDefault",
260        )?))
261    }
262
263    #[must_use]
264    pub fn capacity(&self) -> usize {
265        unsafe { ffi::mdl_mesh_buffer_zone_capacity(self.handle.as_ptr()) as usize }
266    }
267
268    #[must_use]
269    pub fn allocator(&self) -> Option<MeshBufferAllocator> {
270        let ptr = unsafe { ffi::mdl_mesh_buffer_zone_allocator(self.handle.as_ptr()) };
271        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBufferAllocator::from_handle)
272    }
273
274    #[must_use]
275    pub fn as_mesh_buffer_zone(&self) -> MeshBufferZone {
276        MeshBufferZone::from_handle(self.handle.clone())
277    }
278}
279
280#[derive(Debug, Clone)]
281pub struct MeshBufferData {
282    handle: ObjectHandle,
283}
284
285impl MeshBufferData {
286    fn from_handle(handle: ObjectHandle) -> Self {
287        Self { handle }
288    }
289
290    pub fn new(length: usize, buffer_type: MeshBufferType) -> Result<Self> {
291        let mut out_buffer = ptr::null_mut();
292        let mut out_error = ptr::null_mut();
293        let status = unsafe {
294            ffi::mdl_mesh_buffer_data_new(
295                length as u64,
296                buffer_type.as_raw(),
297                &mut out_buffer,
298                &mut out_error,
299            )
300        };
301        crate::util::status_result(status, out_error)?;
302        Ok(Self::from_handle(required_handle(
303            out_buffer,
304            "MDLMeshBufferData",
305        )?))
306    }
307
308    pub fn from_bytes(data: &[u8], buffer_type: MeshBufferType) -> Result<Self> {
309        let mut out_buffer = ptr::null_mut();
310        let mut out_error = ptr::null_mut();
311        let status = unsafe {
312            ffi::mdl_mesh_buffer_data_new_with_bytes(
313                data.as_ptr(),
314                data.len() as u64,
315                buffer_type.as_raw(),
316                &mut out_buffer,
317                &mut out_error,
318            )
319        };
320        crate::util::status_result(status, out_error)?;
321        Ok(Self::from_handle(required_handle(
322            out_buffer,
323            "MDLMeshBufferData",
324        )?))
325    }
326
327    #[must_use]
328    pub fn data(&self) -> Vec<u8> {
329        let info = self.as_mesh_buffer().info().ok();
330        let mut bytes = vec![0_u8; info.map_or(0, |buffer| buffer.length)];
331        if bytes.is_empty() {
332            return bytes;
333        }
334        let written = unsafe {
335            ffi::mdl_mesh_buffer_data_copy_data(
336                self.handle.as_ptr(),
337                bytes.as_mut_ptr(),
338                bytes.len() as u64,
339            )
340        } as usize;
341        bytes.truncate(written);
342        bytes
343    }
344
345    pub fn map(&self) -> Result<MeshBufferMap> {
346        self.as_mesh_buffer().map()
347    }
348
349    #[must_use]
350    pub fn as_mesh_buffer(&self) -> MeshBuffer {
351        MeshBuffer::from_handle(self.handle.clone())
352    }
353}
354
355#[derive(Debug, Clone)]
356pub struct MeshBufferDataAllocator {
357    handle: ObjectHandle,
358}
359
360impl MeshBufferDataAllocator {
361    pub fn new() -> Result<Self> {
362        let mut out_allocator = ptr::null_mut();
363        let mut out_error = ptr::null_mut();
364        let status = unsafe {
365            ffi::mdl_mesh_buffer_data_allocator_new(&mut out_allocator, &mut out_error)
366        };
367        crate::util::status_result(status, out_error)?;
368        Ok(Self {
369            handle: required_handle(out_allocator, "MDLMeshBufferDataAllocator")?,
370        })
371    }
372
373    #[must_use]
374    pub fn as_mesh_buffer_allocator(&self) -> MeshBufferAllocator {
375        MeshBufferAllocator::from_handle(self.handle.clone())
376    }
377
378    pub fn new_default_zone(&self, capacity: usize) -> Result<MeshBufferZoneDefault> {
379        self.as_mesh_buffer_allocator()
380            .new_zone(capacity)?
381            .as_default()
382            .ok_or_else(|| {
383                ModelIoError::new(
384                    ffi::status::NULL_RESULT,
385                    "MDLMeshBufferDataAllocator zone was not MDLMeshBufferZoneDefault",
386                )
387            })
388    }
389}
390
391impl MeshBuffer {
392    pub fn fill_data(&self, data: &[u8], offset: usize) {
393        unsafe {
394            ffi::mdl_mesh_buffer_fill_data(
395                self.as_ptr(),
396                data.as_ptr(),
397                data.len() as u64,
398                offset as u64,
399            );
400        }
401    }
402
403    pub fn map(&self) -> Result<MeshBufferMap> {
404        let length = self.info()?.length;
405        let ptr = unsafe { ffi::mdl_mesh_buffer_map(self.as_ptr()) };
406        Ok(MeshBufferMap::from_handle(required_handle(ptr, "MDLMeshBufferMap")?, length))
407    }
408
409    #[must_use]
410    pub fn allocator(&self) -> Option<MeshBufferAllocator> {
411        let ptr = unsafe { ffi::mdl_mesh_buffer_allocator(self.as_ptr()) };
412        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBufferAllocator::from_handle)
413    }
414
415    #[must_use]
416    pub fn zone(&self) -> Option<MeshBufferZone> {
417        let ptr = unsafe { ffi::mdl_mesh_buffer_zone(self.as_ptr()) };
418        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBufferZone::from_handle)
419    }
420
421    #[must_use]
422    pub fn as_data_buffer(&self) -> Option<MeshBufferData> {
423        if unsafe { ffi::mdl_mesh_buffer_is_data(self.as_ptr()) == 0 } {
424            return None;
425        }
426        let retained = unsafe { ffi::mdl_object_retain(self.as_ptr()) };
427        unsafe { ObjectHandle::from_retained_ptr(retained) }.map(MeshBufferData::from_handle)
428    }
429}