retrofire_core/math/
vary.rs

1//! Types that can be interpolated across a face when rendering.
2//!
3//! Common varying types include colors, texture coordinates,
4//! and vertex normals.
5
6use core::mem;
7
8use super::Lerp;
9
10pub trait ZDiv: Sized {
11    #[must_use]
12    fn z_div(self, _z: f32) -> Self {
13        self
14    }
15}
16
17/// A trait for types that can be linearly interpolated and distributed
18/// between two endpoints.
19///
20/// This trait is designed particularly for *varyings:* types that are
21/// meant to be interpolated across the face of a polygon when rendering,
22/// but the methods are useful for various purposes.
23pub trait Vary: Lerp + ZDiv + Sized + Clone {
24    /// The iterator returned by the [vary][Self::vary] method.
25    type Iter: Iterator<Item = Self>;
26    /// The difference type of `Self`.
27    type Diff: Clone;
28
29    /// Returns an iterator that yields values such that the first value
30    /// equals `self`, and each subsequent value is offset by `step` from its
31    /// predecessor using the [step][Self::step] method. If `max` is `Some(n)`,
32    /// stops after `n` steps, otherwise infinite.
33    ///
34    /// # Examples
35    /// ```
36    /// use retrofire_core::math::Vary;
37    ///
38    /// let mut iter = 0.0f32.vary(0.2, Some(5));
39    ///
40    /// assert_eq!(iter.next(), Some(0.0));
41    /// assert_eq!(iter.next(), Some(0.2));
42    /// assert_eq!(iter.next(), Some(0.4));
43    /// assert_eq!(iter.next(), Some(0.6));
44    /// assert_eq!(iter.next(), Some(0.8));
45    /// assert_eq!(iter.next(), None);
46    /// ```
47    fn vary(self, step: Self::Diff, max: Option<u32>) -> Self::Iter;
48
49    /// Linearly distributes `n` values between `self` and `other` *inclusive*.
50    ///
51    /// The first and last items emitted are `self` and `other` respectively.
52    ///
53    /// If `n` = 1, the only item emitted is `self`. If `n` = 0, emits nothing.
54    ///
55    /// # Examples
56    /// ```
57    /// use retrofire_core::math::Vary;
58    ///
59    /// let mut  v = 2.0.vary_to(8.0, 3);
60    ///
61    /// assert_eq!(v.next(), Some(2.0));
62    /// assert_eq!(v.next(), Some(5.0));
63    /// assert_eq!(v.next(), Some(8.0));
64    /// assert_eq!(v.next(), None);
65    #[inline]
66    fn vary_to(self, other: Self, n: u32) -> Self::Iter {
67        let recip_dt = if n <= 1 {
68            // Dummy value, no actual steps taken if n is 0 or 1
69            1.0
70        } else {
71            // Fencepost problem: n - 1 steps to yield n values
72            1.0 / (n - 1) as f32
73        };
74        let step = self.dv_dt(&other, recip_dt); // Borrowck...
75        self.vary(step, Some(n))
76    }
77
78    /// Returns, conceptually, `(other - self) / dt`.
79    fn dv_dt(&self, other: &Self, recip_dt: f32) -> Self::Diff;
80
81    /// Returns the result of offsetting `self` by `delta`, conceptually
82    /// `self + delta`.
83    #[must_use]
84    fn step(&self, delta: &Self::Diff) -> Self;
85}
86
87#[derive(Copy, Clone, Debug)]
88pub struct Iter<T: Vary> {
89    pub val: T,
90    pub step: T::Diff,
91    pub n: Option<u32>,
92}
93
94impl Vary for () {
95    type Iter = Iter<()>;
96    type Diff = ();
97
98    fn vary(self, _: Self::Diff, n: Option<u32>) -> Self::Iter {
99        Iter { val: (), step: (), n }
100    }
101    fn dv_dt(&self, _: &Self, _: f32) {}
102    fn step(&self, _: &Self::Diff) {}
103}
104impl ZDiv for () {}
105
106impl<T: Vary, U: Vary> Vary for (T, U) {
107    type Iter = Iter<Self>;
108    type Diff = (T::Diff, U::Diff);
109
110    fn vary(self, step: Self::Diff, n: Option<u32>) -> Self::Iter {
111        Iter { val: self, step, n }
112    }
113    fn dv_dt(&self, other: &Self, recip_dt: f32) -> Self::Diff {
114        (
115            self.0.dv_dt(&other.0, recip_dt),
116            self.1.dv_dt(&other.1, recip_dt),
117        )
118    }
119    fn step(&self, (d0, d1): &Self::Diff) -> Self {
120        (self.0.step(d0), self.1.step(d1))
121    }
122}
123impl<T: ZDiv, U: ZDiv> ZDiv for (T, U) {
124    fn z_div(self, z: f32) -> Self {
125        (self.0.z_div(z), self.1.z_div(z))
126    }
127}
128
129impl ZDiv for f32 {
130    fn z_div(self, z: f32) -> Self {
131        self / z
132    }
133}
134
135impl<T: Vary> Iterator for Iter<T> {
136    type Item = T;
137
138    #[inline]
139    fn next(&mut self) -> Option<T> {
140        match &mut self.n {
141            Some(0) => return None,
142            Some(n) => *n -= 1,
143            None => (),
144        }
145        let new = self.val.step(&self.step);
146        Some(mem::replace(&mut self.val, new))
147    }
148}
149
150#[cfg(test)]
151mod tests {
152    use crate::assert_approx_eq;
153
154    use super::*;
155
156    #[test]
157    fn vary_f32() {
158        use alloc::vec::Vec;
159        let varying = (-6.0f32).vary(1.2, Some(10));
160        assert_approx_eq!(
161            varying.collect::<Vec<_>>()[..],
162            [-6.0, -4.8, -3.6, -2.4, -1.2, 0.0, 1.2, 2.4, 3.6, 4.8]
163        );
164    }
165
166    #[test]
167    fn vary_to_zero() {
168        assert_eq!(1.0.vary_to(2.0, 0).next(), None);
169    }
170
171    #[test]
172    fn vary_to_one() {
173        let mut v = 1.0.vary_to(2.0, 1);
174        assert_eq!(v.next(), Some(1.0));
175        assert_eq!(v.next(), None);
176    }
177
178    #[test]
179    fn vary_to_two() {
180        let mut v = 1.0.vary_to(2.0, 2);
181        assert_eq!(v.next(), Some(1.0));
182        assert_eq!(v.next(), Some(2.0));
183        assert_eq!(v.next(), None);
184    }
185}