Unravel Engine C++ Reference
Loading...
Searching...
No Matches
gradient.hpp
Go to the documentation of this file.
1#pragma once
2#include "gradient.h"
3
4namespace math
5{
6
7template<typename T>
8auto gradient<T>::add_point(const T& element, float progress) -> size_t
9{
11 point.element = element;
12 point.progress = progress;
13 points_.emplace_back(point);
14
15 std::sort(points_.begin(), points_.end());
16
17 auto it = std::find(points_.begin(), points_.end(), point);
18
19 mark_lut_dirty(); // Invalidate LUT when gradient changes
20 return std::distance(points_.begin(), it);
21}
22
23template<typename T>
25{
26 if(index >= int(points_.size()))
27 {
28 return;
29 }
30
31 points_.erase(points_.begin() + index);
32 std::sort(points_.begin(), points_.end());
33 mark_lut_dirty(); // Invalidate LUT when gradient changes
34}
35
36template<typename T>
38{
39 points_ = points;
40 std::sort(points_.begin(), points_.end());
41 mark_lut_dirty(); // Invalidate LUT when gradient changes
42}
43
44template<typename T>
45auto gradient<T>::get_points() const noexcept -> const points_t&
46{
47 return points_;
48}
49
50template<typename T>
52{
53 for(auto& p : points_)
54 {
55 p.progress = 1.0f - p.progress;
56 }
57 std::sort(points_.begin(), points_.end());
58 mark_lut_dirty(); // Invalidate LUT when gradient changes
59}
61template<typename T>
62void gradient<T>::set_progress(int index, float progress)
64 if(index >= int(points_.size()))
65 {
66 return;
67 }
69 points_[index].progress = progress;
70 std::sort(points_.begin(), points_.end());
71 mark_lut_dirty(); // Invalidate LUT when gradient changes
73
74template<typename T>
75auto gradient<T>::get_progress(int index) -> float
77 if(index >= int(points_.size()))
78 {
79 return 0.0f;
80 }
81
82 return points_[index].progress;
83}
84
85template<typename T>
86void gradient<T>::set_element(int index, const T& element)
87{
88 if(index >= int(points_.size()))
89 {
90 return;
91 }
92
93 points_[index].element = element;
94 mark_lut_dirty(); // Invalidate LUT when gradient changes
95}
96
97template<typename T>
98auto gradient<T>::get_element(int index) -> T
99{
100 if(index >= int(points_.size()))
101 {
102 return {};
103 }
104
105 return points_[index].element;
106}
107
108template<typename T>
109auto gradient<T>::is_valid() const noexcept -> bool
110{
111 return (false == points_.empty());
112}
113
114template<typename T>
115auto gradient<T>::sample(float progress) const -> T
116{
117 // Use LUT if available, otherwise fall back to original implementation
118 if(has_lut())
119 {
120 regenerate_lut_if_needed();
121 return sample_from_lut(progress);
122 }
123 else
124 {
125 return sample_original(progress);
126 }
127}
128
129template<typename T>
130auto gradient<T>::sample_original(float progress) const -> T
131{
132 if(false == is_valid())
133 {
134 return {};
135 }
136
137 int low = 0;
138 int high = points_.size() - 1;
139 int middle = 0;
140
141 while(low <= high)
142 {
143 middle = (low + high) / 2;
144 const auto& point = points_[middle];
145 if(point.progress > progress)
146 {
147 high = middle - 1;
148 }
149 else if(point.progress < progress)
150 {
151 low = middle + 1;
152 }
153 else
154 {
155 return point.element;
156 }
157 }
158
159 if(points_[middle].progress > progress)
160 {
161 middle--;
162 }
163
164 int first = middle;
165 int second = middle + 1;
166
167 if(second >= 0 && size_t(second) >= points_.size())
168 {
169 return points_.back().element;
170 }
171
172 if(first < 0)
173 {
174 return points_.front().element;
175 }
176
177 const auto& point_first = points_[first];
178 const auto& point_second = points_[second];
179
180 switch(interpolation_mode_)
181 {
183 {
184 return point_first.element;
185 }
187 {
188 const auto abs_progress = (progress - point_first.progress) / (point_second.progress - point_first.progress);
189 return gradient_lerp(point_first.element, point_second.element, abs_progress);
190 }
191 }
192
193 return point_first.element;
194}
195
196template<typename T>
198{
199 interpolation_mode_ = mode;
200 mark_lut_dirty(); // Invalidate LUT when interpolation mode changes
201}
202
203template<typename T>
205{
206 return interpolation_mode_;
207}
208
209template<typename T>
210auto gradient<T>::operator==(const gradient<T>& other) const -> bool
211{
212 if(interpolation_mode_ != other.interpolation_mode_)
213 {
214 return false;
215 }
216
217 return points_ == other.points_;
218}
219
220// LUT Implementation
221template<typename T>
222void gradient<T>::generate_lut(size_t lut_size)
223{
224 lut_size_ = lut_size;
225 lut_.resize(lut_size_);
226
227 // Pre-sample the gradient into the LUT
228 for(size_t i = 0; i < lut_size_; ++i)
229 {
230 const float progress = float(i) / float(lut_size_ - 1);
231 lut_[i] = sample_original(progress);
232 }
233
234 lut_dirty_ = false;
235}
236
237template<typename T>
239{
240 lut_.clear();
241 lut_size_ = 0;
242 lut_dirty_ = true;
243}
244
245template<typename T>
247{
248 if(lut_dirty_ && !lut_.empty())
249 {
250 // Regenerate LUT using current settings
251 const_cast<gradient<T>*>(this)->generate_lut(lut_size_);
252 }
253}
254
255template<typename T>
256auto gradient<T>::sample_from_lut(float progress) const -> T
257{
258 if(lut_.empty())
259 {
260 return {};
261 }
262
263 // Clamp progress to [0, 1]
264 progress = std::max(0.0f, std::min(1.0f, progress));
265
266 // Calculate LUT index with fractional part
267 const float index_f = progress * float(lut_size_ - 1);
268 const size_t index = size_t(index_f);
269 const float frac = index_f - float(index);
270
271 // Handle edge case
272 if(index >= lut_size_ - 1)
273 {
274 return lut_.back();
275 }
276
277 // Linear interpolation between LUT entries for smooth results
278 return gradient_lerp(lut_[index], lut_[index + 1], frac);
279}
280
281} // namespace math
void set_progress(int index, float progress)
Definition gradient.hpp:62
auto get_points() const noexcept -> const points_t &
Definition gradient.hpp:45
auto get_progress(int index) -> float
Definition gradient.hpp:75
auto is_valid() const noexcept -> bool
Definition gradient.hpp:109
auto operator==(const gradient< T > &other) const -> bool
Definition gradient.hpp:210
void set_element(int index, const T &element)
Definition gradient.hpp:86
auto add_point(const T &element, float progress) -> size_t
Definition gradient.hpp:8
std::vector< point_t > points_t
Definition gradient.h:52
auto get_interpolation_mode() const noexcept -> gradient_interpolation_mode_t
Definition gradient.hpp:204
void generate_lut(size_t lut_size=256)
Definition gradient.hpp:222
void set_interpolation_mode(gradient_interpolation_mode_t mode)
Definition gradient.hpp:197
auto get_element(int index) -> T
Definition gradient.hpp:98
void set_points(const points_t &points)
Definition gradient.hpp:37
void remove_point(int index)
Definition gradient.hpp:24
auto sample(float progress) const -> T
Definition gradient.hpp:115
Definition bbox.cpp:5
auto gradient_lerp(const vec4 &start, const vec4 &end, float progress) -> vec4
Definition gradient.cpp:8
gradient_interpolation_mode_t
Definition gradient.h:22
managed_vector3 point