Skip to main content

mtl_gpu/types/
mod.rs

1//! Metal types for Rust.
2//!
3//! Corresponds to `Metal/MTLTypes.hpp`.
4//!
5//! # C++ Equivalent
6//!
7//! ```cpp
8//! namespace MTL {
9//! struct Origin { NS::UInteger x, y, z; };
10//! struct Size { NS::UInteger width, height, depth; };
11//! struct Region { MTL::Origin origin; MTL::Size size; };
12//! struct SamplePosition { float x, y; };
13//! struct ResourceID { uint64_t _impl; };
14//! using Coordinate2D = MTL::SamplePosition;
15//! }
16//! ```
17
18use mtl_foundation::UInteger;
19
20/// 3D origin coordinates.
21///
22/// C++ equivalent: `MTL::Origin`
23#[repr(C, packed)]
24#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
25pub struct Origin {
26    pub x: UInteger,
27    pub y: UInteger,
28    pub z: UInteger,
29}
30
31impl Origin {
32    /// Create a new Origin.
33    #[inline]
34    pub const fn new(x: UInteger, y: UInteger, z: UInteger) -> Self {
35        Self { x, y, z }
36    }
37
38    /// Create a new Origin (C++ style factory method).
39    ///
40    /// C++ equivalent: `static Origin Make(NS::UInteger x, NS::UInteger y, NS::UInteger z)`
41    #[inline]
42    pub const fn make(x: UInteger, y: UInteger, z: UInteger) -> Self {
43        Self::new(x, y, z)
44    }
45}
46
47/// 3D size dimensions.
48///
49/// C++ equivalent: `MTL::Size`
50#[repr(C, packed)]
51#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
52pub struct Size {
53    pub width: UInteger,
54    pub height: UInteger,
55    pub depth: UInteger,
56}
57
58impl Size {
59    /// Create a new Size.
60    #[inline]
61    pub const fn new(width: UInteger, height: UInteger, depth: UInteger) -> Self {
62        Self {
63            width,
64            height,
65            depth,
66        }
67    }
68
69    /// Create a new Size (C++ style factory method).
70    ///
71    /// C++ equivalent: `static Size Make(NS::UInteger width, NS::UInteger height, NS::UInteger depth)`
72    #[inline]
73    pub const fn make(width: UInteger, height: UInteger, depth: UInteger) -> Self {
74        Self::new(width, height, depth)
75    }
76}
77
78/// 3D rectangular region (origin + size).
79///
80/// C++ equivalent: `MTL::Region`
81#[repr(C, packed)]
82#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
83pub struct Region {
84    pub origin: Origin,
85    pub size: Size,
86}
87
88impl Region {
89    /// Create a new Region from origin and size.
90    #[inline]
91    pub const fn new(origin: Origin, size: Size) -> Self {
92        Self { origin, size }
93    }
94
95    /// Create a 1D region.
96    ///
97    /// C++ equivalent: `Region(NS::UInteger x, NS::UInteger width)`
98    #[inline]
99    pub const fn new_1d(x: UInteger, width: UInteger) -> Self {
100        Self {
101            origin: Origin::new(x, 0, 0),
102            size: Size::new(width, 1, 1),
103        }
104    }
105
106    /// Create a 2D region.
107    ///
108    /// C++ equivalent: `Region(NS::UInteger x, NS::UInteger y, NS::UInteger width, NS::UInteger height)`
109    #[inline]
110    pub const fn new_2d(x: UInteger, y: UInteger, width: UInteger, height: UInteger) -> Self {
111        Self {
112            origin: Origin::new(x, y, 0),
113            size: Size::new(width, height, 1),
114        }
115    }
116
117    /// Create a 3D region.
118    ///
119    /// C++ equivalent: `Region(NS::UInteger x, NS::UInteger y, NS::UInteger z, NS::UInteger width, NS::UInteger height, NS::UInteger depth)`
120    #[inline]
121    pub const fn new_3d(
122        x: UInteger,
123        y: UInteger,
124        z: UInteger,
125        width: UInteger,
126        height: UInteger,
127        depth: UInteger,
128    ) -> Self {
129        Self {
130            origin: Origin::new(x, y, z),
131            size: Size::new(width, height, depth),
132        }
133    }
134
135    /// Create a 1D region (C++ style factory method).
136    ///
137    /// C++ equivalent: `static Region Make1D(NS::UInteger x, NS::UInteger width)`
138    #[inline]
139    pub const fn make_1d(x: UInteger, width: UInteger) -> Self {
140        Self::new_1d(x, width)
141    }
142
143    /// Create a 2D region (C++ style factory method).
144    ///
145    /// C++ equivalent: `static Region Make2D(NS::UInteger x, NS::UInteger y, NS::UInteger width, NS::UInteger height)`
146    #[inline]
147    pub const fn make_2d(x: UInteger, y: UInteger, width: UInteger, height: UInteger) -> Self {
148        Self::new_2d(x, y, width, height)
149    }
150
151    /// Create a 3D region (C++ style factory method).
152    ///
153    /// C++ equivalent: `static Region Make3D(NS::UInteger x, NS::UInteger y, NS::UInteger z, NS::UInteger width, NS::UInteger height, NS::UInteger depth)`
154    #[inline]
155    pub const fn make_3d(
156        x: UInteger,
157        y: UInteger,
158        z: UInteger,
159        width: UInteger,
160        height: UInteger,
161        depth: UInteger,
162    ) -> Self {
163        Self::new_3d(x, y, z, width, height, depth)
164    }
165}
166
167/// 2D sample position.
168///
169/// C++ equivalent: `MTL::SamplePosition`
170#[repr(C, packed)]
171#[derive(Copy, Clone, Debug, Default, PartialEq)]
172pub struct SamplePosition {
173    pub x: f32,
174    pub y: f32,
175}
176
177impl SamplePosition {
178    /// Create a new SamplePosition.
179    #[inline]
180    pub const fn new(x: f32, y: f32) -> Self {
181        Self { x, y }
182    }
183
184    /// Create a new SamplePosition (C++ style factory method).
185    ///
186    /// C++ equivalent: `static SamplePosition Make(float x, float y)`
187    #[inline]
188    pub const fn make(x: f32, y: f32) -> Self {
189        Self::new(x, y)
190    }
191}
192
193/// 2D coordinate (alias for SamplePosition).
194///
195/// C++ equivalent: `using Coordinate2D = MTL::SamplePosition`
196pub type Coordinate2D = SamplePosition;
197
198/// GPU resource identifier.
199///
200/// C++ equivalent: `MTL::ResourceID`
201#[repr(C, packed)]
202#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
203pub struct ResourceID {
204    pub _impl: u64,
205}
206
207impl ResourceID {
208    /// Create a new ResourceID.
209    #[inline]
210    pub const fn new(value: u64) -> Self {
211        Self { _impl: value }
212    }
213}
214
215/// Scissor rectangle for rendering.
216///
217/// C++ equivalent: `MTL::ScissorRect` (from MTLRenderCommandEncoder.hpp)
218#[repr(C, packed)]
219#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
220pub struct ScissorRect {
221    pub x: UInteger,
222    pub y: UInteger,
223    pub width: UInteger,
224    pub height: UInteger,
225}
226
227impl ScissorRect {
228    /// Create a new ScissorRect.
229    #[inline]
230    pub const fn new(x: UInteger, y: UInteger, width: UInteger, height: UInteger) -> Self {
231        Self {
232            x,
233            y,
234            width,
235            height,
236        }
237    }
238}
239
240/// Rendering viewport.
241///
242/// C++ equivalent: `MTL::Viewport` (from MTLRenderCommandEncoder.hpp)
243#[repr(C, packed)]
244#[derive(Copy, Clone, Debug, Default, PartialEq)]
245pub struct Viewport {
246    pub origin_x: f64,
247    pub origin_y: f64,
248    pub width: f64,
249    pub height: f64,
250    pub znear: f64,
251    pub zfar: f64,
252}
253
254impl Viewport {
255    /// Create a new Viewport.
256    #[inline]
257    pub const fn new(
258        origin_x: f64,
259        origin_y: f64,
260        width: f64,
261        height: f64,
262        znear: f64,
263        zfar: f64,
264    ) -> Self {
265        Self {
266            origin_x,
267            origin_y,
268            width,
269            height,
270            znear,
271            zfar,
272        }
273    }
274}
275
276/// Clear color for render passes.
277///
278/// C++ equivalent: `MTL::ClearColor` (from MTLRenderPass.hpp)
279#[repr(C, packed)]
280#[derive(Copy, Clone, Debug, Default, PartialEq)]
281pub struct ClearColor {
282    pub red: f64,
283    pub green: f64,
284    pub blue: f64,
285    pub alpha: f64,
286}
287
288impl ClearColor {
289    /// Create a new ClearColor.
290    #[inline]
291    pub const fn new(red: f64, green: f64, blue: f64, alpha: f64) -> Self {
292        Self {
293            red,
294            green,
295            blue,
296            alpha,
297        }
298    }
299
300    /// Create a new ClearColor (C++ style factory method).
301    ///
302    /// C++ equivalent: `static ClearColor Make(double red, double green, double blue, double alpha)`
303    #[inline]
304    pub const fn make(red: f64, green: f64, blue: f64, alpha: f64) -> Self {
305        Self::new(red, green, blue, alpha)
306    }
307}
308
309/// Indirect arguments for drawing primitives.
310///
311/// C++ equivalent: `MTL::DrawPrimitivesIndirectArguments`
312#[repr(C, packed)]
313#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
314pub struct DrawPrimitivesIndirectArguments {
315    pub vertex_count: u32,
316    pub instance_count: u32,
317    pub vertex_start: u32,
318    pub base_instance: u32,
319}
320
321/// Indirect arguments for drawing indexed primitives.
322///
323/// C++ equivalent: `MTL::DrawIndexedPrimitivesIndirectArguments`
324#[repr(C, packed)]
325#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
326pub struct DrawIndexedPrimitivesIndirectArguments {
327    pub index_count: u32,
328    pub instance_count: u32,
329    pub index_start: u32,
330    pub base_vertex: i32,
331    pub base_instance: u32,
332}
333
334/// Vertex amplification view mapping.
335///
336/// C++ equivalent: `MTL::VertexAmplificationViewMapping`
337#[repr(C, packed)]
338#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
339pub struct VertexAmplificationViewMapping {
340    pub viewport_array_index_offset: u32,
341    pub render_target_array_index_offset: u32,
342}
343
344/// Indirect arguments for drawing patches.
345///
346/// C++ equivalent: `MTL::DrawPatchIndirectArguments`
347#[repr(C, packed)]
348#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
349pub struct DrawPatchIndirectArguments {
350    pub patch_count: u32,
351    pub instance_count: u32,
352    pub patch_start: u32,
353    pub base_instance: u32,
354}
355
356/// Quad tessellation factors (half precision).
357///
358/// C++ equivalent: `MTL::QuadTessellationFactorsHalf`
359#[repr(C, packed)]
360#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
361pub struct QuadTessellationFactorsHalf {
362    pub edge_tessellation_factor: [u16; 4],
363    pub inside_tessellation_factor: [u16; 2],
364}
365
366/// Triangle tessellation factors (half precision).
367///
368/// C++ equivalent: `MTL::TriangleTessellationFactorsHalf`
369#[repr(C, packed)]
370#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
371pub struct TriangleTessellationFactorsHalf {
372    pub edge_tessellation_factor: [u16; 3],
373    pub inside_tessellation_factor: u16,
374}
375
376// ============================================================================
377// Acceleration Structure Types (from MTLAccelerationStructureTypes.hpp)
378// ============================================================================
379
380use crate::enums::{AccelerationStructureInstanceOptions, MotionBorderMode};
381
382/// Packed 3-component float vector for acceleration structures.
383///
384/// C++ equivalent: `MTL::PackedFloat3`
385#[repr(C, packed)]
386#[derive(Copy, Clone, Debug, Default, PartialEq)]
387pub struct PackedFloat3 {
388    pub x: f32,
389    pub y: f32,
390    pub z: f32,
391}
392
393impl PackedFloat3 {
394    /// Create a new PackedFloat3.
395    #[inline]
396    pub const fn new(x: f32, y: f32, z: f32) -> Self {
397        Self { x, y, z }
398    }
399
400    /// Create from an array.
401    #[inline]
402    pub const fn from_array(arr: [f32; 3]) -> Self {
403        Self {
404            x: arr[0],
405            y: arr[1],
406            z: arr[2],
407        }
408    }
409
410    /// Convert to an array.
411    #[inline]
412    pub const fn to_array(&self) -> [f32; 3] {
413        [self.x, self.y, self.z]
414    }
415}
416
417impl PackedFloat3 {
418    /// Get element at index (0=x, 1=y, 2=z).
419    ///
420    /// Returns `None` if index is out of bounds.
421    ///
422    /// Note: Cannot implement Index trait for packed structs due to alignment.
423    #[inline]
424    pub fn get(&self, idx: usize) -> Option<f32> {
425        match idx {
426            0 => Some(self.x),
427            1 => Some(self.y),
428            2 => Some(self.z),
429            _ => None,
430        }
431    }
432}
433
434/// Packed 4x3 matrix for acceleration structure transforms.
435///
436/// This is a column-major 4x3 matrix (4 columns, 3 rows).
437///
438/// C++ equivalent: `MTL::PackedFloat4x3`
439#[repr(C, packed)]
440#[derive(Copy, Clone, Debug, Default, PartialEq)]
441pub struct PackedFloat4x3 {
442    pub columns: [PackedFloat3; 4],
443}
444
445impl PackedFloat4x3 {
446    /// Create a new PackedFloat4x3.
447    #[inline]
448    pub const fn new(
449        col0: PackedFloat3,
450        col1: PackedFloat3,
451        col2: PackedFloat3,
452        col3: PackedFloat3,
453    ) -> Self {
454        Self {
455            columns: [col0, col1, col2, col3],
456        }
457    }
458
459    /// Create an identity-like transform (3x3 identity + zero translation).
460    #[inline]
461    pub const fn identity() -> Self {
462        Self {
463            columns: [
464                PackedFloat3::new(1.0, 0.0, 0.0),
465                PackedFloat3::new(0.0, 1.0, 0.0),
466                PackedFloat3::new(0.0, 0.0, 1.0),
467                PackedFloat3::new(0.0, 0.0, 0.0),
468            ],
469        }
470    }
471}
472
473impl std::ops::Index<usize> for PackedFloat4x3 {
474    type Output = PackedFloat3;
475    #[inline]
476    fn index(&self, idx: usize) -> &Self::Output {
477        &self.columns[idx]
478    }
479}
480
481impl std::ops::IndexMut<usize> for PackedFloat4x3 {
482    #[inline]
483    fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
484        &mut self.columns[idx]
485    }
486}
487
488/// Axis-aligned bounding box.
489///
490/// C++ equivalent: `MTL::AxisAlignedBoundingBox`
491#[repr(C, packed)]
492#[derive(Copy, Clone, Debug, Default, PartialEq)]
493pub struct AxisAlignedBoundingBox {
494    pub min: PackedFloat3,
495    pub max: PackedFloat3,
496}
497
498impl AxisAlignedBoundingBox {
499    /// Create a new bounding box.
500    #[inline]
501    pub const fn new(min: PackedFloat3, max: PackedFloat3) -> Self {
502        Self { min, max }
503    }
504
505    /// Create a bounding box containing a single point.
506    #[inline]
507    pub const fn from_point(p: PackedFloat3) -> Self {
508        Self { min: p, max: p }
509    }
510}
511
512/// Packed quaternion for rotations.
513///
514/// C++ equivalent: `MTL::PackedFloatQuaternion`
515#[repr(C, packed)]
516#[derive(Copy, Clone, Debug, Default, PartialEq)]
517pub struct PackedFloatQuaternion {
518    pub x: f32,
519    pub y: f32,
520    pub z: f32,
521    pub w: f32,
522}
523
524impl PackedFloatQuaternion {
525    /// Create a new quaternion.
526    #[inline]
527    pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
528        Self { x, y, z, w }
529    }
530
531    /// Create an identity quaternion (no rotation).
532    #[inline]
533    pub const fn identity() -> Self {
534        Self {
535            x: 0.0,
536            y: 0.0,
537            z: 0.0,
538            w: 1.0,
539        }
540    }
541
542    /// Create from an array.
543    #[inline]
544    pub const fn from_array(arr: [f32; 4]) -> Self {
545        Self {
546            x: arr[0],
547            y: arr[1],
548            z: arr[2],
549            w: arr[3],
550        }
551    }
552
553    /// Convert to an array.
554    #[inline]
555    pub const fn to_array(&self) -> [f32; 4] {
556        [self.x, self.y, self.z, self.w]
557    }
558}
559
560impl PackedFloatQuaternion {
561    /// Get element at index (0=x, 1=y, 2=z, 3=w).
562    ///
563    /// Returns `None` if index is out of bounds.
564    ///
565    /// Note: Cannot implement Index trait for packed structs due to alignment.
566    #[inline]
567    pub fn get(&self, idx: usize) -> Option<f32> {
568        match idx {
569            0 => Some(self.x),
570            1 => Some(self.y),
571            2 => Some(self.z),
572            3 => Some(self.w),
573            _ => None,
574        }
575    }
576}
577
578/// Component-based transform for acceleration structures.
579///
580/// C++ equivalent: `MTL::ComponentTransform`
581#[repr(C, packed)]
582#[derive(Copy, Clone, Debug, Default, PartialEq)]
583pub struct ComponentTransform {
584    pub scale: PackedFloat3,
585    pub shear: PackedFloat3,
586    pub pivot: PackedFloat3,
587    pub rotation: PackedFloatQuaternion,
588    pub translation: PackedFloat3,
589}
590
591impl ComponentTransform {
592    /// Create an identity transform.
593    #[inline]
594    pub const fn identity() -> Self {
595        Self {
596            scale: PackedFloat3::new(1.0, 1.0, 1.0),
597            shear: PackedFloat3::new(0.0, 0.0, 0.0),
598            pivot: PackedFloat3::new(0.0, 0.0, 0.0),
599            rotation: PackedFloatQuaternion::identity(),
600            translation: PackedFloat3::new(0.0, 0.0, 0.0),
601        }
602    }
603}
604
605// ============================================================================
606// Device Types (from MTLDevice.hpp)
607// ============================================================================
608
609/// Acceleration structure sizes returned by the device.
610///
611/// C++ equivalent: `MTL::AccelerationStructureSizes`
612#[repr(C, packed)]
613#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
614pub struct AccelerationStructureSizes {
615    pub acceleration_structure_size: UInteger,
616    pub build_scratch_buffer_size: UInteger,
617    pub refit_scratch_buffer_size: UInteger,
618}
619
620/// Size and alignment for resource allocation.
621///
622/// C++ equivalent: `MTL::SizeAndAlign`
623#[repr(C, packed)]
624#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
625pub struct SizeAndAlign {
626    pub size: UInteger,
627    pub align: UInteger,
628}
629
630// ============================================================================
631// Acceleration Structure Instance Descriptors (from MTLAccelerationStructure.hpp)
632// ============================================================================
633
634/// Default instance descriptor for acceleration structures.
635///
636/// C++ equivalent: `MTL::AccelerationStructureInstanceDescriptor`
637#[repr(C, packed)]
638#[derive(Copy, Clone, Debug, PartialEq)]
639pub struct AccelerationStructureInstanceDescriptor {
640    pub transformation_matrix: PackedFloat4x3,
641    pub options: AccelerationStructureInstanceOptions,
642    pub mask: u32,
643    pub intersection_function_table_offset: u32,
644    pub acceleration_structure_index: u32,
645}
646
647impl Default for AccelerationStructureInstanceDescriptor {
648    fn default() -> Self {
649        Self {
650            transformation_matrix: PackedFloat4x3::identity(),
651            options: AccelerationStructureInstanceOptions::NONE,
652            mask: 0xFFFFFFFF,
653            intersection_function_table_offset: 0,
654            acceleration_structure_index: 0,
655        }
656    }
657}
658
659/// Instance descriptor with user ID for acceleration structures.
660///
661/// C++ equivalent: `MTL::AccelerationStructureUserIDInstanceDescriptor`
662#[repr(C, packed)]
663#[derive(Copy, Clone, Debug, PartialEq)]
664pub struct AccelerationStructureUserIDInstanceDescriptor {
665    pub transformation_matrix: PackedFloat4x3,
666    pub options: AccelerationStructureInstanceOptions,
667    pub mask: u32,
668    pub intersection_function_table_offset: u32,
669    pub acceleration_structure_index: u32,
670    pub user_id: u32,
671}
672
673impl Default for AccelerationStructureUserIDInstanceDescriptor {
674    fn default() -> Self {
675        Self {
676            transformation_matrix: PackedFloat4x3::identity(),
677            options: AccelerationStructureInstanceOptions::NONE,
678            mask: 0xFFFFFFFF,
679            intersection_function_table_offset: 0,
680            acceleration_structure_index: 0,
681            user_id: 0,
682        }
683    }
684}
685
686/// Motion instance descriptor for acceleration structures.
687///
688/// C++ equivalent: `MTL::AccelerationStructureMotionInstanceDescriptor`
689#[repr(C, packed)]
690#[derive(Copy, Clone, Debug, PartialEq)]
691pub struct AccelerationStructureMotionInstanceDescriptor {
692    pub options: AccelerationStructureInstanceOptions,
693    pub mask: u32,
694    pub intersection_function_table_offset: u32,
695    pub acceleration_structure_index: u32,
696    pub user_id: u32,
697    pub motion_transforms_start_index: u32,
698    pub motion_transforms_count: u32,
699    pub motion_start_border_mode: MotionBorderMode,
700    pub motion_end_border_mode: MotionBorderMode,
701    pub motion_start_time: f32,
702    pub motion_end_time: f32,
703}
704
705impl Default for AccelerationStructureMotionInstanceDescriptor {
706    fn default() -> Self {
707        Self {
708            options: AccelerationStructureInstanceOptions::NONE,
709            mask: 0xFFFFFFFF,
710            intersection_function_table_offset: 0,
711            acceleration_structure_index: 0,
712            user_id: 0,
713            motion_transforms_start_index: 0,
714            motion_transforms_count: 0,
715            motion_start_border_mode: MotionBorderMode::CLAMP,
716            motion_end_border_mode: MotionBorderMode::CLAMP,
717            motion_start_time: 0.0,
718            motion_end_time: 1.0,
719        }
720    }
721}
722
723/// Indirect instance descriptor for acceleration structures.
724///
725/// C++ equivalent: `MTL::IndirectAccelerationStructureInstanceDescriptor`
726#[repr(C, packed)]
727#[derive(Copy, Clone, Debug, PartialEq)]
728pub struct IndirectAccelerationStructureInstanceDescriptor {
729    pub transformation_matrix: PackedFloat4x3,
730    pub options: AccelerationStructureInstanceOptions,
731    pub mask: u32,
732    pub intersection_function_table_offset: u32,
733    pub user_id: u32,
734    pub acceleration_structure_id: ResourceID,
735}
736
737impl Default for IndirectAccelerationStructureInstanceDescriptor {
738    fn default() -> Self {
739        Self {
740            transformation_matrix: PackedFloat4x3::identity(),
741            options: AccelerationStructureInstanceOptions::NONE,
742            mask: 0xFFFFFFFF,
743            intersection_function_table_offset: 0,
744            user_id: 0,
745            acceleration_structure_id: ResourceID::default(),
746        }
747    }
748}
749
750/// Indirect motion instance descriptor for acceleration structures.
751///
752/// C++ equivalent: `MTL::IndirectAccelerationStructureMotionInstanceDescriptor`
753#[repr(C, packed)]
754#[derive(Copy, Clone, Debug, PartialEq)]
755pub struct IndirectAccelerationStructureMotionInstanceDescriptor {
756    pub options: AccelerationStructureInstanceOptions,
757    pub mask: u32,
758    pub intersection_function_table_offset: u32,
759    pub user_id: u32,
760    pub acceleration_structure_id: ResourceID,
761    pub motion_transforms_start_index: u32,
762    pub motion_transforms_count: u32,
763    pub motion_start_border_mode: MotionBorderMode,
764    pub motion_end_border_mode: MotionBorderMode,
765    pub motion_start_time: f32,
766    pub motion_end_time: f32,
767}
768
769impl Default for IndirectAccelerationStructureMotionInstanceDescriptor {
770    fn default() -> Self {
771        Self {
772            options: AccelerationStructureInstanceOptions::NONE,
773            mask: 0xFFFFFFFF,
774            intersection_function_table_offset: 0,
775            user_id: 0,
776            acceleration_structure_id: ResourceID::default(),
777            motion_transforms_start_index: 0,
778            motion_transforms_count: 0,
779            motion_start_border_mode: MotionBorderMode::CLAMP,
780            motion_end_border_mode: MotionBorderMode::CLAMP,
781            motion_start_time: 0.0,
782            motion_end_time: 1.0,
783        }
784    }
785}
786
787#[cfg(test)]
788mod tests {
789    use super::*;
790
791    #[test]
792    fn test_origin_size() {
793        assert_eq!(
794            std::mem::size_of::<Origin>(),
795            3 * std::mem::size_of::<UInteger>()
796        );
797    }
798
799    #[test]
800    fn test_size_size() {
801        assert_eq!(
802            std::mem::size_of::<Size>(),
803            3 * std::mem::size_of::<UInteger>()
804        );
805    }
806
807    #[test]
808    fn test_region_size() {
809        assert_eq!(
810            std::mem::size_of::<Region>(),
811            6 * std::mem::size_of::<UInteger>()
812        );
813    }
814
815    #[test]
816    fn test_sample_position_size() {
817        assert_eq!(std::mem::size_of::<SamplePosition>(), 2 * 4);
818    }
819
820    #[test]
821    fn test_resource_id_size() {
822        assert_eq!(std::mem::size_of::<ResourceID>(), 8);
823    }
824
825    #[test]
826    fn test_scissor_rect_size() {
827        assert_eq!(
828            std::mem::size_of::<ScissorRect>(),
829            4 * std::mem::size_of::<UInteger>()
830        );
831    }
832
833    #[test]
834    fn test_viewport_size() {
835        assert_eq!(std::mem::size_of::<Viewport>(), 6 * 8);
836    }
837
838    #[test]
839    fn test_clear_color_size() {
840        assert_eq!(std::mem::size_of::<ClearColor>(), 4 * 8);
841    }
842
843    #[test]
844    fn test_origin_make() {
845        let origin = Origin::make(1, 2, 3);
846        let x = { origin.x };
847        let y = { origin.y };
848        let z = { origin.z };
849        assert_eq!(x, 1);
850        assert_eq!(y, 2);
851        assert_eq!(z, 3);
852    }
853
854    #[test]
855    fn test_region_make_2d() {
856        let region = Region::make_2d(10, 20, 100, 200);
857        let ox = { region.origin.x };
858        let oy = { region.origin.y };
859        let oz = { region.origin.z };
860        let sw = { region.size.width };
861        let sh = { region.size.height };
862        let sd = { region.size.depth };
863        assert_eq!(ox, 10);
864        assert_eq!(oy, 20);
865        assert_eq!(oz, 0);
866        assert_eq!(sw, 100);
867        assert_eq!(sh, 200);
868        assert_eq!(sd, 1);
869    }
870
871    // Acceleration Structure Types Tests
872
873    #[test]
874    fn test_packed_float3_size() {
875        assert_eq!(std::mem::size_of::<PackedFloat3>(), 12); // 3 * 4 bytes
876    }
877
878    #[test]
879    fn test_packed_float4x3_size() {
880        assert_eq!(std::mem::size_of::<PackedFloat4x3>(), 48); // 4 * 12 bytes
881    }
882
883    #[test]
884    fn test_axis_aligned_bounding_box_size() {
885        assert_eq!(std::mem::size_of::<AxisAlignedBoundingBox>(), 24); // 2 * 12 bytes
886    }
887
888    #[test]
889    fn test_packed_float_quaternion_size() {
890        assert_eq!(std::mem::size_of::<PackedFloatQuaternion>(), 16); // 4 * 4 bytes
891    }
892
893    #[test]
894    fn test_component_transform_size() {
895        // 3*PackedFloat3 + 1*PackedFloatQuaternion + 1*PackedFloat3 = 4*12 + 16 = 64
896        assert_eq!(std::mem::size_of::<ComponentTransform>(), 64);
897    }
898
899    #[test]
900    fn test_acceleration_structure_sizes_size() {
901        assert_eq!(
902            std::mem::size_of::<AccelerationStructureSizes>(),
903            3 * std::mem::size_of::<UInteger>()
904        );
905    }
906
907    #[test]
908    fn test_size_and_align_size() {
909        assert_eq!(
910            std::mem::size_of::<SizeAndAlign>(),
911            2 * std::mem::size_of::<UInteger>()
912        );
913    }
914
915    #[test]
916    fn test_acceleration_structure_instance_descriptor_size() {
917        // PackedFloat4x3 (48) + options (4) + mask (4) + offset (4) + index (4) = 64
918        assert_eq!(
919            std::mem::size_of::<AccelerationStructureInstanceDescriptor>(),
920            64
921        );
922    }
923
924    #[test]
925    fn test_acceleration_structure_user_id_instance_descriptor_size() {
926        // PackedFloat4x3 (48) + options (4) + mask (4) + offset (4) + index (4) + user_id (4) = 68
927        assert_eq!(
928            std::mem::size_of::<AccelerationStructureUserIDInstanceDescriptor>(),
929            68
930        );
931    }
932
933    #[test]
934    fn test_packed_float3_new() {
935        let v = PackedFloat3::new(1.0, 2.0, 3.0);
936        let x = { v.x };
937        let y = { v.y };
938        let z = { v.z };
939        assert_eq!(x, 1.0);
940        assert_eq!(y, 2.0);
941        assert_eq!(z, 3.0);
942    }
943
944    #[test]
945    fn test_packed_float4x3_identity() {
946        let m = PackedFloat4x3::identity();
947        // Check first column
948        let c0x = { m.columns[0].x };
949        let c0y = { m.columns[0].y };
950        let c0z = { m.columns[0].z };
951        assert_eq!(c0x, 1.0);
952        assert_eq!(c0y, 0.0);
953        assert_eq!(c0z, 0.0);
954        // Check translation column (last column should be zero)
955        let c3x = { m.columns[3].x };
956        let c3y = { m.columns[3].y };
957        let c3z = { m.columns[3].z };
958        assert_eq!(c3x, 0.0);
959        assert_eq!(c3y, 0.0);
960        assert_eq!(c3z, 0.0);
961    }
962
963    #[test]
964    fn test_packed_float_quaternion_identity() {
965        let q = PackedFloatQuaternion::identity();
966        let x = { q.x };
967        let y = { q.y };
968        let z = { q.z };
969        let w = { q.w };
970        assert_eq!(x, 0.0);
971        assert_eq!(y, 0.0);
972        assert_eq!(z, 0.0);
973        assert_eq!(w, 1.0);
974    }
975}