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::*;