vek/
transform.rs

1//! A convenient position + orientation + scale container, backed by two `Vec3` and a `Quaternion.`
2
3macro_rules! transform_complete_mod {
4    ($mod:ident) => {
5
6        // WISH:
7        // forward_rh, forward_lh, etc etc
8        // look_at
9        // rotate_around
10
11        use std::ops::Add;
12        use $crate::num_traits::{Zero, One, real::Real};
13        use $crate::ops::*;
14        use crate::vec::$mod::*;
15        use crate::quaternion::$mod::*;
16
17        /// A convenient position + orientation + scale container, backed by two `Vec3` and a `Quaternion.`
18        ///
19        /// It can be easily interpolated and converted to a `Mat4` of any layout.
20        ///
21        /// ```
22        /// # extern crate vek;
23        /// # #[macro_use] extern crate approx;
24        /// # use vek::{Transform, Mat4, Quaternion, Vec3};
25        /// # fn main() {
26        /// let (p, rz, s) = (Vec3::unit_x(), 3.0_f32, 5.0_f32);
27        /// let a = Mat4::scaling_3d(s).rotated_z(rz).translated_3d(p);
28        /// let b = Mat4::from(Transform {
29        ///     position: p, 
30        ///     orientation: Quaternion::rotation_z(rz),
31        ///     scale: Vec3::broadcast(s),
32        /// });
33        /// assert_relative_eq!(a, b);
34        /// # }
35        /// ```
36        // Name decided by looking at this thread:
37        // https://www.gamedev.net/forums/topic/611925-is-there-a-name-for-position-orientation/
38        #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, /*Ord, PartialOrd*/)]
39        #[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
40        pub struct Transform<P,O,S> {
41            /// Local position.
42            pub position: Vec3<P>,
43            /// Local orientation; It is not named `rotation` because `rotation` denotes an
44            /// operation, but not a current state.
45            pub orientation: Quaternion<O>,
46            /// Local scale.
47            pub scale: Vec3<S>,
48        }
49
50        /// The default `Transform` has a zero position, identity orientation and unit scale.
51        ///
52        /// ```
53        /// # use vek::{Transform, Quaternion, Vec3};
54        /// let a = Transform {
55        ///     position: Vec3::<f32>::zero(),
56        ///     orientation: Quaternion::<f32>::identity(),
57        ///     scale: Vec3::<f32>::one(),
58        /// };
59        /// assert_eq!(a, Transform::default());
60        /// ```
61        impl<P: Zero, O: Zero + One, S: One> Default for Transform<P,O,S> {
62            fn default() -> Self {
63                Self {
64                    position: Vec3::zero(),
65                    orientation: Quaternion::identity(),
66                    scale: Vec3::one(),
67                }
68            }
69        }
70
71        /// LERP on a `Transform` is defined as LERP-ing between the positions and scales, 
72        /// and performing SLERP between the orientations.
73        impl<P,O,S,Factor> Lerp<Factor> for Transform<P,O,S> 
74            where Factor: Copy + Into<O>,
75                  P: Lerp<Factor,Output=P>,
76                  S: Lerp<Factor,Output=S>,
77                  O: Lerp<O,Output=O> + Real + Add<Output=O>,
78        {
79            type Output = Self;
80            fn lerp_unclamped(a: Self, b: Self, t: Factor) -> Self {
81                Transform {
82                    position: Lerp::lerp_unclamped(a.position, b.position, t),
83                    orientation: Slerp::slerp_unclamped(a.orientation, b.orientation, t),
84                    scale: Lerp::lerp_unclamped(a.scale, b.scale, t),
85                }
86            }
87            fn lerp_unclamped_precise(a: Self, b: Self, t: Factor) -> Self {
88                Transform {
89                    position: Lerp::lerp_unclamped_precise(a.position, b.position, t),
90                    orientation: Slerp::slerp_unclamped(a.orientation, b.orientation, t),
91                    scale: Lerp::lerp_unclamped_precise(a.scale, b.scale, t),
92                }
93            }
94        }
95
96        /// LERP on a `Transform` is defined as LERP-ing between the positions and scales, 
97        /// and performing SLERP between the orientations.
98        impl<'a,P,O,S,Factor> Lerp<Factor> for &'a Transform<P,O,S> 
99            where Factor: Copy + Into<O>,
100                  &'a P: Lerp<Factor,Output=P>,
101                  &'a S: Lerp<Factor,Output=S>,
102                  O: Lerp<O,Output=O> + Real + Add<Output=O>,
103        {
104            type Output = Transform<P,O,S>;
105            fn lerp_unclamped(a: Self, b: Self, t: Factor) -> Self::Output {
106                Transform {
107                    position: Lerp::lerp_unclamped(&a.position, &b.position, t),
108                    orientation: Slerp::slerp_unclamped(&a.orientation, &b.orientation, t),
109                    scale: Lerp::lerp_unclamped(&a.scale, &b.scale, t),
110                }
111            }
112            fn lerp_unclamped_precise(a: Self, b: Self, t: Factor) -> Self::Output {
113                Transform {
114                    position: Lerp::lerp_unclamped_precise(&a.position, &b.position, t),
115                    orientation: Slerp::slerp_unclamped(&a.orientation, &b.orientation, t),
116                    scale: Lerp::lerp_unclamped_precise(&a.scale, &b.scale, t),
117                }
118            }
119        }
120    }     
121}         
122
123#[cfg(all(nightly, feature="repr_simd"))]
124pub mod repr_simd {
125    //! `Transform` struct that uses `#[repr(simd)]` vectors and quaternions.
126    transform_complete_mod!(repr_simd);
127}
128pub mod repr_c {
129    //! `Transform` struct that uses `#[repr(C)]` vectors and quaternions.
130    transform_complete_mod!(repr_c);
131}
132pub use self::repr_c::*;