1use std::panic::AssertUnwindSafe;
2use std::ptr;
3
4use crate::error::{ModelIoError, Result};
5use crate::ffi;
6use crate::handle::ObjectHandle;
7use crate::mesh::MeshBuffer;
8use crate::types::MeshBufferType;
9use crate::util::required_handle;
10
11type MeshBufferAllocatorCallbackFn =
12 dyn Fn(MeshBufferAllocatorEvent) -> MeshBufferAllocatorResponse + Send + Sync + 'static;
13
14struct MeshBufferAllocatorCallback {
15 callback: Box<MeshBufferAllocatorCallbackFn>,
16}
17
18#[derive(Debug, Clone)]
19pub enum MeshBufferAllocatorEvent {
21 NewZone { capacity: usize },
23 NewZoneForBuffers {
25 sizes: Vec<usize>,
26 types: Vec<MeshBufferType>,
27 },
28 NewBuffer {
30 length: usize,
31 buffer_type: MeshBufferType,
32 },
33 NewBufferWithData {
35 data: Vec<u8>,
36 buffer_type: MeshBufferType,
37 },
38 NewBufferFromZone {
40 zone: Option<MeshBufferZone>,
41 length: usize,
42 buffer_type: MeshBufferType,
43 },
44 NewBufferFromZoneWithData {
46 zone: Option<MeshBufferZone>,
47 data: Vec<u8>,
48 buffer_type: MeshBufferType,
49 },
50}
51
52#[derive(Debug, Clone)]
53pub enum MeshBufferAllocatorResponse {
55 Zone(Option<MeshBufferZone>),
57 Buffer(Option<MeshBuffer>),
59 None,
61}
62
63fn callback_response(
64 context: *mut core::ffi::c_void,
65 event: MeshBufferAllocatorEvent,
66) -> Option<MeshBufferAllocatorResponse> {
67 let context = (!context.is_null()).then_some(context.cast::<MeshBufferAllocatorCallback>())?;
68 std::panic::catch_unwind(AssertUnwindSafe(|| {
69 (unsafe { &*context }.callback)(event)
71 }))
72 .ok()
73}
74
75fn zone_from_retained_ptr(ptr: *mut core::ffi::c_void) -> Option<MeshBufferZone> {
76 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBufferZone::from_handle)
78}
79
80fn zone_ptr_from_response(response: Option<MeshBufferAllocatorResponse>) -> *mut core::ffi::c_void {
81 match response {
82 Some(MeshBufferAllocatorResponse::Zone(Some(zone))) =>
83 unsafe { ffi::mdl_object_retain(zone.as_ptr()) },
85 _ => ptr::null_mut(),
86 }
87}
88
89fn buffer_ptr_from_response(
90 response: Option<MeshBufferAllocatorResponse>,
91) -> *mut core::ffi::c_void {
92 match response {
93 Some(MeshBufferAllocatorResponse::Buffer(Some(buffer))) =>
94 unsafe { ffi::mdl_object_retain(buffer.as_ptr()) },
96 _ => ptr::null_mut(),
97 }
98}
99
100fn mesh_buffer_type(raw: u32) -> Option<MeshBufferType> {
101 MeshBufferType::from_raw(raw)
102}
103
104#[no_mangle]
105pub extern "C" fn mdlx_mesh_buffer_allocator_new_zone(
106 context: *mut core::ffi::c_void,
107 capacity: u64,
108) -> *mut core::ffi::c_void {
109 zone_ptr_from_response(callback_response(
110 context,
111 MeshBufferAllocatorEvent::NewZone {
112 capacity: capacity as usize,
113 },
114 ))
115}
116
117#[no_mangle]
118pub extern "C" fn mdlx_mesh_buffer_allocator_new_zone_for_buffers_with_size(
119 context: *mut core::ffi::c_void,
120 sizes: *const u64,
121 types: *const u32,
122 count: u64,
123) -> *mut core::ffi::c_void {
124 let sizes = if count == 0 {
125 Vec::new()
126 } else if sizes.is_null() {
127 return ptr::null_mut();
128 } else {
129 unsafe { std::slice::from_raw_parts(sizes, count as usize) }
131 .iter()
132 .map(|size| *size as usize)
133 .collect::<Vec<_>>()
134 };
135 let Some(types) = (if count == 0 {
136 Some(Vec::new())
137 } else if types.is_null() {
138 None
139 } else {
140 unsafe { std::slice::from_raw_parts(types, count as usize) }
142 .iter()
143 .copied()
144 .map(mesh_buffer_type)
145 .collect::<Option<Vec<_>>>()
146 }) else {
147 return ptr::null_mut();
148 };
149 zone_ptr_from_response(callback_response(
150 context,
151 MeshBufferAllocatorEvent::NewZoneForBuffers { sizes, types },
152 ))
153}
154
155#[no_mangle]
156pub extern "C" fn mdlx_mesh_buffer_allocator_new_buffer(
157 context: *mut core::ffi::c_void,
158 length: u64,
159 buffer_type: u32,
160) -> *mut core::ffi::c_void {
161 let Some(buffer_type) = mesh_buffer_type(buffer_type) else {
162 return ptr::null_mut();
163 };
164 buffer_ptr_from_response(callback_response(
165 context,
166 MeshBufferAllocatorEvent::NewBuffer {
167 length: length as usize,
168 buffer_type,
169 },
170 ))
171}
172
173#[no_mangle]
174pub extern "C" fn mdlx_mesh_buffer_allocator_new_buffer_with_data(
175 context: *mut core::ffi::c_void,
176 bytes: *const u8,
177 count: u64,
178 buffer_type: u32,
179) -> *mut core::ffi::c_void {
180 let Some(buffer_type) = mesh_buffer_type(buffer_type) else {
181 return ptr::null_mut();
182 };
183 let data = if count == 0 || bytes.is_null() {
184 Vec::new()
185 } else {
186 unsafe { std::slice::from_raw_parts(bytes, count as usize) }.to_vec()
188 };
189 buffer_ptr_from_response(callback_response(
190 context,
191 MeshBufferAllocatorEvent::NewBufferWithData { data, buffer_type },
192 ))
193}
194
195#[no_mangle]
196pub extern "C" fn mdlx_mesh_buffer_allocator_new_buffer_from_zone_length(
197 context: *mut core::ffi::c_void,
198 zone: *mut core::ffi::c_void,
199 length: u64,
200 buffer_type: u32,
201) -> *mut core::ffi::c_void {
202 let Some(buffer_type) = mesh_buffer_type(buffer_type) else {
203 return ptr::null_mut();
204 };
205 buffer_ptr_from_response(callback_response(
206 context,
207 MeshBufferAllocatorEvent::NewBufferFromZone {
208 zone: zone_from_retained_ptr(zone),
209 length: length as usize,
210 buffer_type,
211 },
212 ))
213}
214
215#[no_mangle]
216pub extern "C" fn mdlx_mesh_buffer_allocator_new_buffer_from_zone_data(
217 context: *mut core::ffi::c_void,
218 zone: *mut core::ffi::c_void,
219 bytes: *const u8,
220 count: u64,
221 buffer_type: u32,
222) -> *mut core::ffi::c_void {
223 let Some(buffer_type) = mesh_buffer_type(buffer_type) else {
224 return ptr::null_mut();
225 };
226 let data = if count == 0 || bytes.is_null() {
227 Vec::new()
228 } else {
229 unsafe { std::slice::from_raw_parts(bytes, count as usize) }.to_vec()
231 };
232 buffer_ptr_from_response(callback_response(
233 context,
234 MeshBufferAllocatorEvent::NewBufferFromZoneWithData {
235 zone: zone_from_retained_ptr(zone),
236 data,
237 buffer_type,
238 },
239 ))
240}
241
242#[no_mangle]
243pub extern "C" fn mdlx_mesh_buffer_allocator_release(context: *mut core::ffi::c_void) {
244 if context.is_null() {
245 return;
246 }
247 unsafe { drop(Box::from_raw(context.cast::<MeshBufferAllocatorCallback>())) };
249}
250
251fn release_callback_context(context: *mut core::ffi::c_void) {
252 mdlx_mesh_buffer_allocator_release(context);
253}
254
255#[derive(Debug, Clone)]
256pub struct MeshBufferMap {
258 handle: ObjectHandle,
259 length: usize,
260}
261
262impl MeshBufferMap {
263 fn from_handle(handle: ObjectHandle, length: usize) -> Self {
264 Self { handle, length }
265 }
266
267 pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
269 self.handle.as_ptr()
270 }
271
272 #[must_use]
273 pub fn length(&self) -> usize {
275 self.length
276 }
277
278 #[must_use]
279 pub fn bytes(&self) -> Vec<u8> {
281 let mut bytes = vec![0_u8; self.length];
282 if bytes.is_empty() {
283 return bytes;
284 }
285 let written = unsafe {
287 ffi::mdl_mesh_buffer_map_copy_bytes(
288 self.as_ptr(),
289 self.length as u64,
290 bytes.as_mut_ptr(),
291 bytes.len() as u64,
292 )
293 } as usize;
294 bytes.truncate(written);
295 bytes
296 }
297
298 pub fn write(&self, offset: usize, bytes: &[u8]) -> usize {
300 unsafe {
302 ffi::mdl_mesh_buffer_map_write_bytes(
303 self.as_ptr(),
304 self.length as u64,
305 bytes.as_ptr(),
306 bytes.len() as u64,
307 offset as u64,
308 ) as usize
309 }
310 }
311}
312
313#[derive(Debug, Clone)]
314pub struct MeshBufferAllocator {
316 handle: ObjectHandle,
317}
318
319impl MeshBufferAllocator {
320 pub fn new<F>(callback: F) -> Result<Self>
322 where
323 F: Fn(MeshBufferAllocatorEvent) -> MeshBufferAllocatorResponse + Send + Sync + 'static,
324 {
325 let callback = Box::new(MeshBufferAllocatorCallback {
326 callback: Box::new(callback),
327 });
328 let callback_ptr = Box::into_raw(callback).cast::<core::ffi::c_void>();
329 let mut out_allocator = ptr::null_mut();
330 let mut out_error = ptr::null_mut();
331 let status = unsafe {
333 ffi::mdl_mesh_buffer_allocator_new_with_callback(
334 callback_ptr,
335 &mut out_allocator,
336 &mut out_error,
337 )
338 };
339 if let Err(error) = crate::util::status_result(status, out_error) {
340 release_callback_context(callback_ptr);
341 return Err(error);
342 }
343 match required_handle(out_allocator, "MDLMeshBufferAllocator") {
344 Ok(handle) => Ok(Self::from_handle(handle)),
345 Err(error) => {
346 release_callback_context(callback_ptr);
347 Err(error)
348 }
349 }
350 }
351
352 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
354 Self { handle }
355 }
356
357 pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
359 self.handle.as_ptr()
360 }
361
362 pub fn new_zone(&self, capacity: usize) -> Result<MeshBufferZone> {
364 let mut out_zone = ptr::null_mut();
365 let mut out_error = ptr::null_mut();
366 let status = unsafe {
368 ffi::mdl_mesh_buffer_allocator_new_zone(
369 self.as_ptr(),
370 capacity as u64,
371 &mut out_zone,
372 &mut out_error,
373 )
374 };
375 crate::util::status_result(status, out_error)?;
376 Ok(MeshBufferZone::from_handle(required_handle(
377 out_zone,
378 "MDLMeshBufferZone",
379 )?))
380 }
381
382 pub fn new_zone_for_buffers(
384 &self,
385 sizes: &[usize],
386 types: &[MeshBufferType],
387 ) -> Result<MeshBufferZone> {
388 if sizes.len() != types.len() {
389 return Err(ModelIoError::new(
390 ffi::status::INVALID_ARGUMENT,
391 "mesh buffer sizes and types must have the same length",
392 ));
393 }
394 let raw_sizes = sizes.iter().map(|size| *size as u64).collect::<Vec<_>>();
395 let raw_types = types
396 .iter()
397 .map(|buffer_type| buffer_type.as_raw())
398 .collect::<Vec<_>>();
399 let mut out_zone = ptr::null_mut();
400 let mut out_error = ptr::null_mut();
401 let status = unsafe {
403 ffi::mdl_mesh_buffer_allocator_new_zone_for_buffers_with_size(
404 self.as_ptr(),
405 raw_sizes.as_ptr(),
406 raw_types.as_ptr(),
407 raw_sizes.len() as u64,
408 &mut out_zone,
409 &mut out_error,
410 )
411 };
412 crate::util::status_result(status, out_error)?;
413 Ok(MeshBufferZone::from_handle(required_handle(
414 out_zone,
415 "MDLMeshBufferZone",
416 )?))
417 }
418
419 pub fn new_buffer(&self, length: usize, buffer_type: MeshBufferType) -> Result<MeshBuffer> {
421 let mut out_buffer = ptr::null_mut();
422 let mut out_error = ptr::null_mut();
423 let status = unsafe {
425 ffi::mdl_mesh_buffer_allocator_new_buffer(
426 self.as_ptr(),
427 length as u64,
428 buffer_type.as_raw(),
429 &mut out_buffer,
430 &mut out_error,
431 )
432 };
433 crate::util::status_result(status, out_error)?;
434 Ok(MeshBuffer::from_handle(required_handle(
435 out_buffer,
436 "MDLMeshBuffer",
437 )?))
438 }
439
440 pub fn new_buffer_with_data(
442 &self,
443 data: &[u8],
444 buffer_type: MeshBufferType,
445 ) -> Result<MeshBuffer> {
446 let mut out_buffer = ptr::null_mut();
447 let mut out_error = ptr::null_mut();
448 let status = unsafe {
450 ffi::mdl_mesh_buffer_allocator_new_buffer_with_data(
451 self.as_ptr(),
452 data.as_ptr(),
453 data.len() as u64,
454 buffer_type.as_raw(),
455 &mut out_buffer,
456 &mut out_error,
457 )
458 };
459 crate::util::status_result(status, out_error)?;
460 Ok(MeshBuffer::from_handle(required_handle(
461 out_buffer,
462 "MDLMeshBuffer",
463 )?))
464 }
465
466 pub fn new_buffer_from_zone(
468 &self,
469 zone: Option<&MeshBufferZone>,
470 length: usize,
471 buffer_type: MeshBufferType,
472 ) -> Result<Option<MeshBuffer>> {
473 let mut out_buffer = ptr::null_mut();
474 let mut out_error = ptr::null_mut();
475 let status = unsafe {
477 ffi::mdl_mesh_buffer_allocator_new_buffer_from_zone_length(
478 self.as_ptr(),
479 zone.map_or(ptr::null_mut(), MeshBufferZone::as_ptr),
480 length as u64,
481 buffer_type.as_raw(),
482 &mut out_buffer,
483 &mut out_error,
484 )
485 };
486 crate::util::status_result(status, out_error)?;
487 Ok(unsafe { ObjectHandle::from_retained_ptr(out_buffer) }.map(MeshBuffer::from_handle))
489 }
490
491 pub fn new_buffer_from_zone_with_data(
493 &self,
494 zone: Option<&MeshBufferZone>,
495 data: &[u8],
496 buffer_type: MeshBufferType,
497 ) -> Result<Option<MeshBuffer>> {
498 let mut out_buffer = ptr::null_mut();
499 let mut out_error = ptr::null_mut();
500 let status = unsafe {
502 ffi::mdl_mesh_buffer_allocator_new_buffer_from_zone_data(
503 self.as_ptr(),
504 zone.map_or(ptr::null_mut(), MeshBufferZone::as_ptr),
505 data.as_ptr(),
506 data.len() as u64,
507 buffer_type.as_raw(),
508 &mut out_buffer,
509 &mut out_error,
510 )
511 };
512 crate::util::status_result(status, out_error)?;
513 Ok(unsafe { ObjectHandle::from_retained_ptr(out_buffer) }.map(MeshBuffer::from_handle))
515 }
516}
517
518#[derive(Debug, Clone)]
519pub struct MeshBufferZone {
521 handle: ObjectHandle,
522}
523
524impl MeshBufferZone {
525 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
527 Self { handle }
528 }
529
530 pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
532 self.handle.as_ptr()
533 }
534
535 #[must_use]
536 pub fn capacity(&self) -> usize {
538 unsafe { ffi::mdl_mesh_buffer_zone_capacity(self.as_ptr()) as usize }
540 }
541
542 #[must_use]
543 pub fn allocator(&self) -> Option<MeshBufferAllocator> {
545 let ptr = unsafe { ffi::mdl_mesh_buffer_zone_allocator(self.as_ptr()) };
547 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBufferAllocator::from_handle)
549 }
550
551 #[must_use]
552 pub fn as_default(&self) -> Option<MeshBufferZoneDefault> {
554 (unsafe { ffi::mdl_mesh_buffer_zone_is_default(self.as_ptr()) != 0 })
556 .then(|| MeshBufferZoneDefault::from_handle(self.handle.clone()))
557 }
558}
559
560#[derive(Debug, Clone)]
561pub struct MeshBufferZoneDefault {
563 handle: ObjectHandle,
564}
565
566impl MeshBufferZoneDefault {
567 fn from_handle(handle: ObjectHandle) -> Self {
568 Self { handle }
569 }
570
571 pub fn new() -> Result<Self> {
573 let mut out_zone = ptr::null_mut();
574 let mut out_error = ptr::null_mut();
575 let status =
576 unsafe { ffi::mdl_mesh_buffer_zone_default_new(&mut out_zone, &mut out_error) };
578 crate::util::status_result(status, out_error)?;
579 Ok(Self::from_handle(required_handle(
580 out_zone,
581 "MDLMeshBufferZoneDefault",
582 )?))
583 }
584
585 #[must_use]
586 pub fn capacity(&self) -> usize {
588 unsafe { ffi::mdl_mesh_buffer_zone_capacity(self.handle.as_ptr()) as usize }
590 }
591
592 #[must_use]
593 pub fn allocator(&self) -> Option<MeshBufferAllocator> {
595 let ptr = unsafe { ffi::mdl_mesh_buffer_zone_allocator(self.handle.as_ptr()) };
597 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBufferAllocator::from_handle)
599 }
600
601 #[must_use]
602 pub fn as_mesh_buffer_zone(&self) -> MeshBufferZone {
604 MeshBufferZone::from_handle(self.handle.clone())
605 }
606}
607
608#[derive(Debug, Clone)]
609pub struct MeshBufferData {
611 handle: ObjectHandle,
612}
613
614impl MeshBufferData {
615 fn from_handle(handle: ObjectHandle) -> Self {
616 Self { handle }
617 }
618
619 pub fn new(length: usize, buffer_type: MeshBufferType) -> Result<Self> {
621 let mut out_buffer = ptr::null_mut();
622 let mut out_error = ptr::null_mut();
623 let status = unsafe {
625 ffi::mdl_mesh_buffer_data_new(
626 length as u64,
627 buffer_type.as_raw(),
628 &mut out_buffer,
629 &mut out_error,
630 )
631 };
632 crate::util::status_result(status, out_error)?;
633 Ok(Self::from_handle(required_handle(
634 out_buffer,
635 "MDLMeshBufferData",
636 )?))
637 }
638
639 pub fn from_bytes(data: &[u8], buffer_type: MeshBufferType) -> Result<Self> {
641 let mut out_buffer = ptr::null_mut();
642 let mut out_error = ptr::null_mut();
643 let status = unsafe {
645 ffi::mdl_mesh_buffer_data_new_with_bytes(
646 data.as_ptr(),
647 data.len() as u64,
648 buffer_type.as_raw(),
649 &mut out_buffer,
650 &mut out_error,
651 )
652 };
653 crate::util::status_result(status, out_error)?;
654 Ok(Self::from_handle(required_handle(
655 out_buffer,
656 "MDLMeshBufferData",
657 )?))
658 }
659
660 #[must_use]
661 pub fn data(&self) -> Vec<u8> {
663 let info = self.as_mesh_buffer().info().ok();
664 let mut bytes = vec![0_u8; info.map_or(0, |buffer| buffer.length)];
665 if bytes.is_empty() {
666 return bytes;
667 }
668 let written = unsafe {
670 ffi::mdl_mesh_buffer_data_copy_data(
671 self.handle.as_ptr(),
672 bytes.as_mut_ptr(),
673 bytes.len() as u64,
674 )
675 } as usize;
676 bytes.truncate(written);
677 bytes
678 }
679
680 pub fn map(&self) -> Result<MeshBufferMap> {
682 self.as_mesh_buffer().map()
683 }
684
685 #[must_use]
686 pub fn as_mesh_buffer(&self) -> MeshBuffer {
688 MeshBuffer::from_handle(self.handle.clone())
689 }
690}
691
692#[derive(Debug, Clone)]
693pub struct MeshBufferDataAllocator {
695 handle: ObjectHandle,
696}
697
698impl MeshBufferDataAllocator {
699 pub fn new() -> Result<Self> {
701 let mut out_allocator = ptr::null_mut();
702 let mut out_error = ptr::null_mut();
703 let status =
704 unsafe { ffi::mdl_mesh_buffer_data_allocator_new(&mut out_allocator, &mut out_error) };
706 crate::util::status_result(status, out_error)?;
707 Ok(Self {
708 handle: required_handle(out_allocator, "MDLMeshBufferDataAllocator")?,
709 })
710 }
711
712 #[must_use]
713 pub fn as_mesh_buffer_allocator(&self) -> MeshBufferAllocator {
715 MeshBufferAllocator::from_handle(self.handle.clone())
716 }
717
718 pub fn new_default_zone(&self, capacity: usize) -> Result<MeshBufferZoneDefault> {
720 self.as_mesh_buffer_allocator()
721 .new_zone(capacity)?
722 .as_default()
723 .ok_or_else(|| {
724 ModelIoError::new(
725 ffi::status::NULL_RESULT,
726 "MDLMeshBufferDataAllocator zone was not MDLMeshBufferZoneDefault",
727 )
728 })
729 }
730}
731
732impl MeshBuffer {
733 pub fn fill_data(&self, data: &[u8], offset: usize) {
735 unsafe {
737 ffi::mdl_mesh_buffer_fill_data(
738 self.as_ptr(),
739 data.as_ptr(),
740 data.len() as u64,
741 offset as u64,
742 );
743 }
744 }
745
746 pub fn map(&self) -> Result<MeshBufferMap> {
748 let length = self.info()?.length;
749 let ptr = unsafe { ffi::mdl_mesh_buffer_map(self.as_ptr()) };
751 Ok(MeshBufferMap::from_handle(
752 required_handle(ptr, "MDLMeshBufferMap")?,
753 length,
754 ))
755 }
756
757 #[must_use]
758 pub fn allocator(&self) -> Option<MeshBufferAllocator> {
760 let ptr = unsafe { ffi::mdl_mesh_buffer_allocator(self.as_ptr()) };
762 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBufferAllocator::from_handle)
764 }
765
766 #[must_use]
767 pub fn zone(&self) -> Option<MeshBufferZone> {
769 let ptr = unsafe { ffi::mdl_mesh_buffer_zone(self.as_ptr()) };
771 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(MeshBufferZone::from_handle)
773 }
774
775 #[must_use]
776 pub fn as_data_buffer(&self) -> Option<MeshBufferData> {
778 if unsafe { ffi::mdl_mesh_buffer_is_data(self.as_ptr()) == 0 } {
780 return None;
781 }
782 let retained = unsafe { ffi::mdl_object_retain(self.as_ptr()) };
784 unsafe { ObjectHandle::from_retained_ptr(retained) }.map(MeshBufferData::from_handle)
786 }
787}