1use std::ffi::c_void;
9use std::ptr::NonNull;
10
11use mtl_foundation::{Referencing, UInteger};
12use mtl_sys::{Class, msg_send_0, msg_send_1, msg_send_2, sel};
13
14use crate::enums::{VertexFormat, VertexStepFunction};
15
16pub const BUFFER_LAYOUT_STRIDE_DYNAMIC: UInteger = UInteger::MAX;
20
21#[repr(transparent)]
29pub struct VertexBufferLayoutDescriptor(pub(crate) NonNull<c_void>);
30
31impl VertexBufferLayoutDescriptor {
32 pub fn new() -> Option<Self> {
36 unsafe {
37 let class = Class::get("MTLVertexBufferLayoutDescriptor")?;
38 let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
39 if ptr.is_null() {
40 return None;
41 }
42 let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
43 Self::from_raw(ptr)
44 }
45 }
46
47 #[inline]
53 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
54 NonNull::new(ptr).map(Self)
55 }
56
57 #[inline]
59 pub fn as_raw(&self) -> *mut c_void {
60 self.0.as_ptr()
61 }
62
63 #[inline]
71 pub fn stride(&self) -> UInteger {
72 unsafe { msg_send_0(self.as_ptr(), sel!(stride)) }
73 }
74
75 #[inline]
79 pub fn set_stride(&self, stride: UInteger) {
80 unsafe {
81 let _: () = msg_send_1(self.as_ptr(), sel!(setStride:), stride);
82 }
83 }
84
85 #[inline]
89 pub fn step_function(&self) -> VertexStepFunction {
90 unsafe { msg_send_0(self.as_ptr(), sel!(stepFunction)) }
91 }
92
93 #[inline]
97 pub fn set_step_function(&self, step_function: VertexStepFunction) {
98 unsafe {
99 let _: () = msg_send_1(self.as_ptr(), sel!(setStepFunction:), step_function);
100 }
101 }
102
103 #[inline]
107 pub fn step_rate(&self) -> UInteger {
108 unsafe { msg_send_0(self.as_ptr(), sel!(stepRate)) }
109 }
110
111 #[inline]
115 pub fn set_step_rate(&self, step_rate: UInteger) {
116 unsafe {
117 let _: () = msg_send_1(self.as_ptr(), sel!(setStepRate:), step_rate);
118 }
119 }
120}
121
122impl Clone for VertexBufferLayoutDescriptor {
123 fn clone(&self) -> Self {
124 unsafe {
125 msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
126 }
127 Self(self.0)
128 }
129}
130
131impl Drop for VertexBufferLayoutDescriptor {
132 fn drop(&mut self) {
133 unsafe {
134 msg_send_0::<()>(self.as_ptr(), sel!(release));
135 }
136 }
137}
138
139impl Referencing for VertexBufferLayoutDescriptor {
140 #[inline]
141 fn as_ptr(&self) -> *const c_void {
142 self.0.as_ptr()
143 }
144}
145
146unsafe impl Send for VertexBufferLayoutDescriptor {}
147unsafe impl Sync for VertexBufferLayoutDescriptor {}
148
149impl std::fmt::Debug for VertexBufferLayoutDescriptor {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 f.debug_struct("VertexBufferLayoutDescriptor")
152 .field("stride", &self.stride())
153 .field("step_function", &self.step_function())
154 .field("step_rate", &self.step_rate())
155 .finish()
156 }
157}
158
159#[repr(transparent)]
167pub struct VertexBufferLayoutDescriptorArray(pub(crate) NonNull<c_void>);
168
169impl VertexBufferLayoutDescriptorArray {
170 pub fn new() -> Option<Self> {
174 unsafe {
175 let class = Class::get("MTLVertexBufferLayoutDescriptorArray")?;
176 let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
177 if ptr.is_null() {
178 return None;
179 }
180 let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
181 Self::from_raw(ptr)
182 }
183 }
184
185 #[inline]
191 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
192 NonNull::new(ptr).map(Self)
193 }
194
195 #[inline]
197 pub fn as_raw(&self) -> *mut c_void {
198 self.0.as_ptr()
199 }
200
201 pub fn object(&self, index: UInteger) -> Option<VertexBufferLayoutDescriptor> {
209 unsafe {
210 let ptr: *mut c_void =
211 msg_send_1(self.as_ptr(), sel!(objectAtIndexedSubscript:), index);
212 if ptr.is_null() {
213 return None;
214 }
215 msg_send_0::<*mut c_void>(ptr, sel!(retain));
217 VertexBufferLayoutDescriptor::from_raw(ptr)
218 }
219 }
220
221 pub fn set_object(&self, buffer_desc: &VertexBufferLayoutDescriptor, index: UInteger) {
225 unsafe {
226 let _: () = msg_send_2(
227 self.as_ptr(),
228 sel!(setObject:atIndexedSubscript:),
229 buffer_desc.as_ptr(),
230 index,
231 );
232 }
233 }
234}
235
236impl Clone for VertexBufferLayoutDescriptorArray {
237 fn clone(&self) -> Self {
238 unsafe {
239 msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
240 }
241 Self(self.0)
242 }
243}
244
245impl Drop for VertexBufferLayoutDescriptorArray {
246 fn drop(&mut self) {
247 unsafe {
248 msg_send_0::<()>(self.as_ptr(), sel!(release));
249 }
250 }
251}
252
253impl Referencing for VertexBufferLayoutDescriptorArray {
254 #[inline]
255 fn as_ptr(&self) -> *const c_void {
256 self.0.as_ptr()
257 }
258}
259
260unsafe impl Send for VertexBufferLayoutDescriptorArray {}
261unsafe impl Sync for VertexBufferLayoutDescriptorArray {}
262
263impl std::fmt::Debug for VertexBufferLayoutDescriptorArray {
264 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
265 f.debug_struct("VertexBufferLayoutDescriptorArray").finish()
266 }
267}
268
269#[repr(transparent)]
277pub struct VertexAttributeDescriptor(pub(crate) NonNull<c_void>);
278
279impl VertexAttributeDescriptor {
280 pub fn new() -> Option<Self> {
284 unsafe {
285 let class = Class::get("MTLVertexAttributeDescriptor")?;
286 let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
287 if ptr.is_null() {
288 return None;
289 }
290 let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
291 Self::from_raw(ptr)
292 }
293 }
294
295 #[inline]
301 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
302 NonNull::new(ptr).map(Self)
303 }
304
305 #[inline]
307 pub fn as_raw(&self) -> *mut c_void {
308 self.0.as_ptr()
309 }
310
311 #[inline]
319 pub fn format(&self) -> VertexFormat {
320 unsafe { msg_send_0(self.as_ptr(), sel!(format)) }
321 }
322
323 #[inline]
327 pub fn set_format(&self, format: VertexFormat) {
328 unsafe {
329 let _: () = msg_send_1(self.as_ptr(), sel!(setFormat:), format);
330 }
331 }
332
333 #[inline]
337 pub fn offset(&self) -> UInteger {
338 unsafe { msg_send_0(self.as_ptr(), sel!(offset)) }
339 }
340
341 #[inline]
345 pub fn set_offset(&self, offset: UInteger) {
346 unsafe {
347 let _: () = msg_send_1(self.as_ptr(), sel!(setOffset:), offset);
348 }
349 }
350
351 #[inline]
355 pub fn buffer_index(&self) -> UInteger {
356 unsafe { msg_send_0(self.as_ptr(), sel!(bufferIndex)) }
357 }
358
359 #[inline]
363 pub fn set_buffer_index(&self, buffer_index: UInteger) {
364 unsafe {
365 let _: () = msg_send_1(self.as_ptr(), sel!(setBufferIndex:), buffer_index);
366 }
367 }
368}
369
370impl Clone for VertexAttributeDescriptor {
371 fn clone(&self) -> Self {
372 unsafe {
373 msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
374 }
375 Self(self.0)
376 }
377}
378
379impl Drop for VertexAttributeDescriptor {
380 fn drop(&mut self) {
381 unsafe {
382 msg_send_0::<()>(self.as_ptr(), sel!(release));
383 }
384 }
385}
386
387impl Referencing for VertexAttributeDescriptor {
388 #[inline]
389 fn as_ptr(&self) -> *const c_void {
390 self.0.as_ptr()
391 }
392}
393
394unsafe impl Send for VertexAttributeDescriptor {}
395unsafe impl Sync for VertexAttributeDescriptor {}
396
397impl std::fmt::Debug for VertexAttributeDescriptor {
398 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
399 f.debug_struct("VertexAttributeDescriptor")
400 .field("format", &self.format())
401 .field("offset", &self.offset())
402 .field("buffer_index", &self.buffer_index())
403 .finish()
404 }
405}
406
407#[repr(transparent)]
415pub struct VertexAttributeDescriptorArray(pub(crate) NonNull<c_void>);
416
417impl VertexAttributeDescriptorArray {
418 pub fn new() -> Option<Self> {
422 unsafe {
423 let class = Class::get("MTLVertexAttributeDescriptorArray")?;
424 let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
425 if ptr.is_null() {
426 return None;
427 }
428 let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
429 Self::from_raw(ptr)
430 }
431 }
432
433 #[inline]
439 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
440 NonNull::new(ptr).map(Self)
441 }
442
443 #[inline]
445 pub fn as_raw(&self) -> *mut c_void {
446 self.0.as_ptr()
447 }
448
449 pub fn object(&self, index: UInteger) -> Option<VertexAttributeDescriptor> {
457 unsafe {
458 let ptr: *mut c_void =
459 msg_send_1(self.as_ptr(), sel!(objectAtIndexedSubscript:), index);
460 if ptr.is_null() {
461 return None;
462 }
463 msg_send_0::<*mut c_void>(ptr, sel!(retain));
465 VertexAttributeDescriptor::from_raw(ptr)
466 }
467 }
468
469 pub fn set_object(&self, attribute_desc: &VertexAttributeDescriptor, index: UInteger) {
473 unsafe {
474 let _: () = msg_send_2(
475 self.as_ptr(),
476 sel!(setObject:atIndexedSubscript:),
477 attribute_desc.as_ptr(),
478 index,
479 );
480 }
481 }
482}
483
484impl Clone for VertexAttributeDescriptorArray {
485 fn clone(&self) -> Self {
486 unsafe {
487 msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
488 }
489 Self(self.0)
490 }
491}
492
493impl Drop for VertexAttributeDescriptorArray {
494 fn drop(&mut self) {
495 unsafe {
496 msg_send_0::<()>(self.as_ptr(), sel!(release));
497 }
498 }
499}
500
501impl Referencing for VertexAttributeDescriptorArray {
502 #[inline]
503 fn as_ptr(&self) -> *const c_void {
504 self.0.as_ptr()
505 }
506}
507
508unsafe impl Send for VertexAttributeDescriptorArray {}
509unsafe impl Sync for VertexAttributeDescriptorArray {}
510
511impl std::fmt::Debug for VertexAttributeDescriptorArray {
512 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
513 f.debug_struct("VertexAttributeDescriptorArray").finish()
514 }
515}
516
517#[repr(transparent)]
525pub struct VertexDescriptor(pub(crate) NonNull<c_void>);
526
527impl VertexDescriptor {
528 pub fn new() -> Option<Self> {
532 unsafe {
533 let class = Class::get("MTLVertexDescriptor")?;
534 let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
535 if ptr.is_null() {
536 return None;
537 }
538 let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
539 Self::from_raw(ptr)
540 }
541 }
542
543 pub fn vertex_descriptor() -> Option<Self> {
547 unsafe {
548 let class = Class::get("MTLVertexDescriptor")?;
549 let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(vertexDescriptor));
550 if ptr.is_null() {
551 return None;
552 }
553 msg_send_0::<*mut c_void>(ptr, sel!(retain));
555 Self::from_raw(ptr)
556 }
557 }
558
559 #[inline]
565 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
566 NonNull::new(ptr).map(Self)
567 }
568
569 #[inline]
571 pub fn as_raw(&self) -> *mut c_void {
572 self.0.as_ptr()
573 }
574
575 pub fn layouts(&self) -> VertexBufferLayoutDescriptorArray {
583 unsafe {
584 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(layouts));
585 msg_send_0::<*mut c_void>(ptr, sel!(retain));
587 VertexBufferLayoutDescriptorArray::from_raw(ptr)
588 .expect("vertex descriptor layouts should not be null")
589 }
590 }
591
592 pub fn attributes(&self) -> VertexAttributeDescriptorArray {
596 unsafe {
597 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(attributes));
598 msg_send_0::<*mut c_void>(ptr, sel!(retain));
600 VertexAttributeDescriptorArray::from_raw(ptr)
601 .expect("vertex descriptor attributes should not be null")
602 }
603 }
604
605 #[inline]
613 pub fn reset(&self) {
614 unsafe {
615 msg_send_0::<()>(self.as_ptr(), sel!(reset));
616 }
617 }
618}
619
620impl Clone for VertexDescriptor {
621 fn clone(&self) -> Self {
622 unsafe {
623 msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
624 }
625 Self(self.0)
626 }
627}
628
629impl Drop for VertexDescriptor {
630 fn drop(&mut self) {
631 unsafe {
632 msg_send_0::<()>(self.as_ptr(), sel!(release));
633 }
634 }
635}
636
637impl Referencing for VertexDescriptor {
638 #[inline]
639 fn as_ptr(&self) -> *const c_void {
640 self.0.as_ptr()
641 }
642}
643
644unsafe impl Send for VertexDescriptor {}
645unsafe impl Sync for VertexDescriptor {}
646
647impl std::fmt::Debug for VertexDescriptor {
648 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
649 f.debug_struct("VertexDescriptor").finish()
650 }
651}
652
653#[cfg(test)]
658mod tests {
659 use super::*;
660
661 #[test]
662 fn test_buffer_layout_stride_dynamic() {
663 assert_eq!(BUFFER_LAYOUT_STRIDE_DYNAMIC, UInteger::MAX);
664 }
665
666 #[test]
667 fn test_vertex_descriptor_creation() {
668 let desc = VertexDescriptor::new();
669 assert!(desc.is_some());
670 }
671
672 #[test]
673 fn test_vertex_descriptor_class_method() {
674 let desc = VertexDescriptor::vertex_descriptor();
675 assert!(desc.is_some());
676 }
677
678 #[test]
679 fn test_vertex_buffer_layout_descriptor() {
680 let desc = VertexBufferLayoutDescriptor::new();
681 assert!(desc.is_some());
682
683 let desc = desc.unwrap();
684 assert_eq!(desc.stride(), 0);
686
687 desc.set_stride(32);
688 assert_eq!(desc.stride(), 32);
689
690 assert_eq!(desc.step_function(), VertexStepFunction::PER_VERTEX);
692
693 desc.set_step_function(VertexStepFunction::PER_INSTANCE);
694 assert_eq!(desc.step_function(), VertexStepFunction::PER_INSTANCE);
695
696 assert_eq!(desc.step_rate(), 1);
698
699 desc.set_step_rate(2);
700 assert_eq!(desc.step_rate(), 2);
701 }
702
703 #[test]
704 fn test_vertex_attribute_descriptor() {
705 let desc = VertexAttributeDescriptor::new();
706 assert!(desc.is_some());
707
708 let desc = desc.unwrap();
709 assert_eq!(desc.format(), VertexFormat::INVALID);
711
712 desc.set_format(VertexFormat::FLOAT3);
713 assert_eq!(desc.format(), VertexFormat::FLOAT3);
714
715 assert_eq!(desc.offset(), 0);
717
718 desc.set_offset(16);
719 assert_eq!(desc.offset(), 16);
720
721 assert_eq!(desc.buffer_index(), 0);
723
724 desc.set_buffer_index(1);
725 assert_eq!(desc.buffer_index(), 1);
726 }
727
728 #[test]
729 fn test_vertex_descriptor_layouts_and_attributes() {
730 let desc = VertexDescriptor::new().unwrap();
731
732 let layouts = desc.layouts();
734 let layout = layouts.object(0);
735 assert!(layout.is_some());
736
737 let layout = layout.unwrap();
738 layout.set_stride(32);
739 layout.set_step_function(VertexStepFunction::PER_VERTEX);
740
741 let attributes = desc.attributes();
743 let attr = attributes.object(0);
744 assert!(attr.is_some());
745
746 let attr = attr.unwrap();
747 attr.set_format(VertexFormat::FLOAT3);
748 attr.set_offset(0);
749 attr.set_buffer_index(0);
750 }
751
752 #[test]
753 fn test_vertex_descriptor_reset() {
754 let desc = VertexDescriptor::new().unwrap();
755
756 let attributes = desc.attributes();
758 let attr = attributes.object(0).unwrap();
759 attr.set_format(VertexFormat::FLOAT4);
760 attr.set_offset(16);
761
762 desc.reset();
764
765 let attr = attributes.object(0).unwrap();
766 assert_eq!(attr.format(), VertexFormat::INVALID);
767 assert_eq!(attr.offset(), 0);
768 }
769}