retrofire_core/math/
vary.rs

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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//! Types that can be interpolated across a face when rendering.
//!
//! Common varying types include colors, texture coordinates,
//! and vertex normals.

use core::mem;

/// A trait for types that can be linearly interpolated and distributed
/// between two endpoints.
///
/// This trait is designed particularly for *varyings:* types that are
/// meant to be interpolated across the face of a polygon when rendering,
/// but the methods are useful for various purposes.
pub trait Vary: Sized + Clone {
    /// The iterator returned by the [vary][Self::vary] method.
    type Iter: Iterator<Item = Self>;
    /// The difference type of `Self`.
    type Diff: Clone;

    /// Returns an iterator that yields values such that the first value
    /// equals `self`, and each subsequent value is offset by `step` from its
    /// predecessor using the [step][Self::step] method. If `max` is `Some(n)`,
    /// stops after `n` steps, otherwise infinite.
    ///
    /// # Examples
    /// ```
    /// # use retrofire_core::math::vary::Vary;
    /// let mut iter = 0.0f32.vary(0.2, Some(5));
    /// assert_eq!(iter.next(), Some(0.0));
    /// assert_eq!(iter.next(), Some(0.2));
    /// assert_eq!(iter.next(), Some(0.4));
    /// assert_eq!(iter.next(), Some(0.6));
    /// assert_eq!(iter.next(), Some(0.8));
    /// assert_eq!(iter.next(), None);
    /// ```
    fn vary(self, step: Self::Diff, max: Option<u32>) -> Self::Iter;

    /// Linearly distributes values between `self` and `other` *inclusive*.
    #[inline]
    fn vary_to(self, other: Self, n: u32) -> Self::Iter {
        let step = self.dv_dt(&other, 1.0 / n as f32);
        self.vary(step, Some(n + 1))
    }

    /// Returns, conceptually, `(other - self) / dt`.
    fn dv_dt(&self, other: &Self, recip_dt: f32) -> Self::Diff;

    /// Returns the result of offsetting `self` by `delta`, conceptually
    /// `self + delta`.
    #[must_use]
    fn step(&self, delta: &Self::Diff) -> Self;

    /// Performs perspective division.
    #[must_use]
    fn z_div(&self, z: f32) -> Self;

    /// Linearly interpolates between `self` and `other`.
    ///
    /// This method does not panic if `t < 0.0` or `t > 1.0`, or if `t`
    /// is a `NaN`, but the return value in those cases is unspecified.
    /// Individual implementations may offer stronger guarantees.
    ///
    /// # Examples
    /// ```
    /// # use retrofire_core::math::vary::Vary;
    /// assert_eq!(2.0.lerp(&5.0, 0.0), 2.0);
    /// assert_eq!(2.0.lerp(&5.0, 0.5), 3.5);
    /// assert_eq!(2.0.lerp(&5.0, 1.0), 5.0);
    /// ```
    #[inline]
    fn lerp(&self, other: &Self, t: f32) -> Self {
        self.step(&self.dv_dt(other, t))
    }
}

#[derive(Copy, Clone, Debug)]
pub struct Iter<T: Vary> {
    pub val: T,
    pub step: T::Diff,
    pub n: Option<u32>,
}

#[inline]
pub fn lerp<V: Vary>(t: f32, from: V, to: V) -> V {
    from.lerp(&to, t)
}

impl Vary for () {
    type Iter = Iter<()>;
    type Diff = ();

    fn vary(self, _: Self::Diff, n: Option<u32>) -> Self::Iter {
        Iter { val: (), step: (), n }
    }
    fn dv_dt(&self, _: &Self, _: f32) {}
    fn step(&self, _: &Self::Diff) {}

    fn z_div(&self, _: f32) {}
}

impl<T: Vary, U: Vary> Vary for (T, U) {
    type Iter = Iter<Self>;
    type Diff = (T::Diff, U::Diff);

    fn vary(self, step: Self::Diff, n: Option<u32>) -> Self::Iter {
        Iter { val: self, step, n }
    }
    fn dv_dt(&self, other: &Self, recip_dt: f32) -> Self::Diff {
        (
            self.0.dv_dt(&other.0, recip_dt),
            self.1.dv_dt(&other.1, recip_dt),
        )
    }
    fn step(&self, (d0, d1): &Self::Diff) -> Self {
        (self.0.step(d0), self.1.step(d1))
    }

    fn z_div(&self, z: f32) -> Self {
        (self.0.z_div(z), self.1.z_div(z))
    }
}

impl<T: Vary> Iterator for Iter<T> {
    type Item = T;

    #[inline]
    fn next(&mut self) -> Option<T> {
        match &mut self.n {
            Some(0) => return None,
            Some(n) => *n -= 1,
            None => (),
        }
        let new = self.val.step(&self.step);
        Some(mem::replace(&mut self.val, new))
    }
}

#[cfg(test)]
mod tests {
    use crate::assert_approx_eq;

    use super::*;

    #[test]
    fn vary_f32() {
        use alloc::vec::Vec;
        let varying = (-6.0f32).vary(1.2, Some(10));
        assert_approx_eq!(
            varying.collect::<Vec<_>>()[..],
            [-6.0, -4.8, -3.6, -2.4, -1.2, 0.0, 1.2, 2.4, 3.6, 4.8]
        );
    }
}