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
133
134
135
136
137
138
139
//! Transformation structure and builder
use dotrix_math::{Mat4, Vec3, Quat, Rotation3, Rad};

/// Agregator for skin transformations
#[derive(Default)]
pub struct Builder {
    /// Optional translation vector
    pub translate: Option<Vec3>,
    /// Optional rotation quaternion
    pub rotate: Option<Quat>,
    /// Optional scale vector
    pub scale: Option<Vec3>,
}

impl Builder {
    /// Constructs the builder from translation vector
    pub fn with_translate(mut self, translate: Vec3) -> Self {
        self.translate = Some(translate);
        self
    }

    /// Constructs the builder from rotation quaternion
    pub fn with_rotate(mut self, rotate: Quat) -> Self {
        self.rotate = Some(rotate);
        self
    }

    /// Constructs the builder from scale vector
    pub fn with_scale(mut self, scale: Vec3) -> Self {
        self.scale = Some(scale);
        self
    }

    /// Builds the transformation
    pub fn build(self) -> Transform {
        let mut transform = Transform::default();
        if let Some(translate) = self.translate {
            transform.translate = translate;
        }
        if let Some(rotate) = self.rotate {
            transform.rotate = rotate;
        }
        if let Some(scale) = self.scale {
            transform.scale = scale;
        }
        transform
    }
}

/// Model transformation structure
#[derive(Debug, Copy, Clone)]
pub struct Transform {
    /// Translation vector
    pub translate: Vec3,
    /// Rotation quaternion
    pub rotate: Quat,
    /// Scale vector
    pub scale: Vec3,
}

impl Transform {
    /// Constructs new transformation with values that won't change the model
    pub fn new() -> Self {
        Self {
            translate: Vec3::new(0.0, 0.0, 0.0),
            rotate: Quat::from_angle_y(Rad(0.0)),
            scale: Vec3::new(1.0, 1.0, 1.0),
        }
    }

    /// Constructs transformation builder
    pub fn builder() -> Builder {
        Builder::default()
    }


    /// Returns transformation matrix
    pub fn matrix(&self) -> Mat4 {
        let t = Mat4::from_translation(self.translate);
        let r = Mat4::from(self.rotate);
        let s = Mat4::from_nonuniform_scale(self.scale.x, self.scale.y, self.scale.z);
        t * r * s
    }

    /// Merge current transformation with values from the [`Builder`] respectively
    pub fn merge(&self, builder: &Builder) -> Self {
        Self {
            translate: builder.translate.unwrap_or(self.translate),
            rotate: builder.rotate.unwrap_or(self.rotate),
            scale: builder.scale.unwrap_or(self.scale),
        }
    }

    /// Constructs new transformation from the translation vector
    pub fn from_translation(translate: Vec3) -> Self {
        Self {
            translate,
            ..Default::default()
        }
    }

    /// Constructs new transformation from the rotation quaternion
    pub fn from_rotation(rotate: Quat) -> Self {
        Self {
            rotate,
            ..Default::default()
        }
    }

    /// Constructs new transformation from the scale vector
    pub fn from_scale(scale: Vec3) -> Self {
        Self {
            scale,
            ..Default::default()
        }
    }

    /// Constructs new transformation from the scale factor
    pub fn from_scale_factor(scale: f32) -> Self {
        Self::from_scale(Vec3::new(scale, scale, scale))
    }
}

impl From<gltf::scene::Transform> for Transform {
    fn from(transform: gltf::scene::Transform) -> Self {
        let (translation, rotation, scale) = transform.decomposed();
        Self {
            translate: Vec3::from(translation),
            rotate: Quat::new(rotation[3], rotation[0], rotation[1], rotation[2]),
            scale: Vec3::from(scale),
        }
    }
}

impl Default for Transform {
    fn default() -> Self {
        Self::new()
    }
}