1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! A convenient position + orientation + scale container, backed by two `Vec3` and a `Quaternion.`

macro_rules! transform_complete_mod {
    ($mod:ident) => {

        // WISH:
        // forward_rh, forward_lh, etc etc
        // look_at
        // rotate_around

        use ::std::iter::Sum;
        use $crate::num_traits::{Zero, One, Float};
        use $crate::ops::*;
        use vec::$mod::*;
        use quaternion::$mod::*;

        /// A convenient position + orientation + scale container, backed by two `Vec3` and a `Quaternion.`
        ///
        /// It can be easily interpolated and converted to a `Mat4` of any layout.
        ///
        /// ```
        /// # extern crate vek;
        /// # #[macro_use] extern crate approx;
        /// # use vek::{Transform, Mat4, Quaternion, Vec3};
        /// # fn main() {
        /// let (p, rz, s) = (Vec3::unit_x(), 3.0_f32, 5.0_f32);
        /// let a = Mat4::scaling_3d(s).rotated_z(rz).translated_3d(p);
        /// let b = Mat4::from(Transform {
        ///     position: p, 
        ///     orientation: Quaternion::rotation_z(rz),
        ///     scale: Vec3::broadcast(s),
        /// });
        /// assert_relative_eq!(a, b);
        /// # }
        /// ```
        // Name decided by looking at this thread:
        // https://www.gamedev.net/forums/topic/611925-is-there-a-name-for-position-orientation/
        #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, /*Ord, PartialOrd*/)]
        #[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
        pub struct Transform<P,O,S> {
            /// Local position.
            pub position: Vec3<P>,
            /// Local orientation; It is not named `rotation` because `rotation` denotes an
            /// operation, but not a current state.
            pub orientation: Quaternion<O>,
            /// Local scale.
            pub scale: Vec3<S>,
        }

        /// The default `Transform` has a zero position, identity orientation and unit scale.
        ///
        /// ```
        /// # use vek::{Transform, Quaternion, Vec3};
        /// let a = Transform {
        ///     position: Vec3::<f32>::zero(),
        ///     orientation: Quaternion::<f32>::identity(),
        ///     scale: Vec3::<f32>::one(),
        /// };
        /// assert_eq!(a, Transform::default());
        /// ```
        impl<P: Zero, O: Zero + One, S: One> Default for Transform<P,O,S> {
            fn default() -> Self {
                Self {
                    position: Vec3::zero(),
                    orientation: Quaternion::identity(),
                    scale: Vec3::one(),
                }
            }
        }

        /// LERP on a `Transform` is defined as LERP-ing between the positions and scales, 
        /// and performing SLERP between the orientations.
        impl<P,O,S,Factor> Lerp<Factor> for Transform<P,O,S> 
            where Factor: Copy + Into<O>,
                  P: Lerp<Factor,Output=P>,
                  S: Lerp<Factor,Output=S>,
                  O: Lerp<O,Output=O> + Float + Sum,
        {
            type Output = Self;
            fn lerp_unclamped(a: Self, b: Self, t: Factor) -> Self {
                Transform {
                    position: Lerp::lerp_unclamped(a.position, b.position, t),
                    orientation: Slerp::slerp_unclamped(a.orientation, b.orientation, t),
                    scale: Lerp::lerp_unclamped(a.scale, b.scale, t),
                }
            }
            fn lerp_unclamped_precise(a: Self, b: Self, t: Factor) -> Self {
                Transform {
                    position: Lerp::lerp_unclamped_precise(a.position, b.position, t),
                    orientation: Slerp::slerp_unclamped(a.orientation, b.orientation, t),
                    scale: Lerp::lerp_unclamped_precise(a.scale, b.scale, t),
                }
            }
        }

        /// LERP on a `Transform` is defined as LERP-ing between the positions and scales, 
        /// and performing SLERP between the orientations.
        impl<'a,P,O,S,Factor> Lerp<Factor> for &'a Transform<P,O,S> 
            where Factor: Copy + Into<O>,
                  &'a P: Lerp<Factor,Output=P>,
                  &'a S: Lerp<Factor,Output=S>,
                  O: Lerp<O,Output=O> + Float + Sum,
        {
            type Output = Transform<P,O,S>;
            fn lerp_unclamped(a: Self, b: Self, t: Factor) -> Self::Output {
                Transform {
                    position: Lerp::lerp_unclamped(&a.position, &b.position, t),
                    orientation: Slerp::slerp_unclamped(&a.orientation, &b.orientation, t),
                    scale: Lerp::lerp_unclamped(&a.scale, &b.scale, t),
                }
            }
            fn lerp_unclamped_precise(a: Self, b: Self, t: Factor) -> Self::Output {
                Transform {
                    position: Lerp::lerp_unclamped_precise(&a.position, &b.position, t),
                    orientation: Slerp::slerp_unclamped(&a.orientation, &b.orientation, t),
                    scale: Lerp::lerp_unclamped_precise(&a.scale, &b.scale, t),
                }
            }
        }
    }     
}         

#[cfg(all(nightly, feature="repr_simd"))]
pub mod repr_simd {
    //! `Transform` struct that uses `#[repr(simd)]` vectors and quaternions.
    transform_complete_mod!(repr_simd);
}
pub mod repr_c {
    //! `Transform` struct that uses `#[repr(C)]` vectors and quaternions.
    transform_complete_mod!(repr_c);
}
pub use self::repr_c::*;