nova_math/
gradient.rs

1/*
2 *
3 * This file is a part of NovaEngine
4 * https://gitlab.com/MindSpunk/NovaEngine
5 *
6 *
7 * MIT License
8 *
9 * Copyright (c) 2018 Nathan Voglsam
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in all
19 * copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 */
29
30use crate::traits::{Lerp, Real};
31use crate::vector::{TVec2, TVec3};
32
33// TODO: Document these structs
34
35pub struct LinearGradientBuilder<T: Real> {
36    start_pos: TVec2<T>,
37    start_col: TVec3<T>,
38
39    end_pos: TVec2<T>,
40    end_col: TVec3<T>,
41}
42
43impl<T: Real> LinearGradientBuilder<T> {
44    pub fn new() -> Self {
45        LinearGradientBuilder {
46            start_pos: TVec2::zero(),
47            start_col: TVec3::zero(),
48            end_pos: TVec2::zero(),
49            end_col: TVec3::zero(),
50        }
51    }
52
53    pub fn start(mut self, pos: TVec2<T>, color: TVec3<T>) -> Self {
54        self.start_pos = pos;
55        self.start_col = color;
56        self
57    }
58
59    pub fn end(mut self, pos: TVec2<T>, color: TVec3<T>) -> Self {
60        self.end_pos = pos;
61        self.end_col = color;
62        self
63    }
64
65    pub fn build(self) -> LinearGradient<T> {
66        let a = self.end_pos[0] - self.start_pos[0];
67        let b = self.end_pos[1] - self.start_pos[1];
68        LinearGradient {
69            start_col: self.start_col,
70            end_col: self.end_col,
71            a,
72            b,
73            c1: (a * self.start_pos[0]) + (b * self.start_pos[1]),
74            c2: (a * self.end_pos[0]) + (b * self.end_pos[1]),
75        }
76    }
77}
78
79impl<T: Real> Default for LinearGradientBuilder<T> {
80    fn default() -> Self {
81        Self::new()
82    }
83}
84
85#[derive(Clone)]
86pub struct LinearGradient<T: Real> {
87    start_col: TVec3<T>,
88    end_col: TVec3<T>,
89
90    a: T,
91    b: T,
92
93    c1: T,
94    c2: T,
95}
96
97impl<T: Real> LinearGradient<T> {
98    pub fn builder() -> LinearGradientBuilder<T> {
99        LinearGradientBuilder::new()
100    }
101
102    pub fn sample(&self, point: TVec2<T>) -> TVec3<T> {
103        let c = self.a * point[0] + self.b * point[1];
104        if c <= self.c1 {
105            self.start_col
106        } else if c >= self.c2 {
107            self.end_col
108        } else {
109            let factor =
110                (T::zero() * (self.c2 - c)) + (T::one() * (c - self.c1)) / (self.c2 - self.c1);
111            self.start_col.lerp(&self.end_col, factor)
112        }
113    }
114}