FastLED 3.10.8
Loading...
Searching...
No Matches
ease.cpp.hpp
Go to the documentation of this file.
1#ifndef FASTLED_INTERNAL
2#define FASTLED_INTERNAL
3#endif
4
5#include "fl/system/fastled.h"
6
7#include "fl/math/ease.h"
8#include "lib8tion.h" // This is the problematic header that's hard to include
9
10#include "fl/math/math.h"
11#include "fl/math/intmap.h"
12#include "fl/math/sin32.h"
13#include "fl/stl/int.h"
14#include "fl/math/math.h"
15#include "fl/stl/weak_ptr.h"
16#include "fl/stl/flat_map.h"
17#include "fl/stl/align.h"
18#include "fl/math/fixed_point.h"
19#include "fl/stl/noexcept.h"
20
21namespace fl {
22
23// Static PROGMEM lookup table for gamma 2.8 correction (8-bit -> 16-bit).
24// Generated by: round(pow(i / 255.0, 2.8) * 65535.0) for i in 0..255.
25// Uses flash storage on AVR/ESP, zero heap allocation on all platforms.
26FL_ALIGN_PROGMEM(64) const u16 GAMMA_2_8_LUT[256] FL_PROGMEM = {
27 0, 0, 0, 0, 1, 1, 2, 3, 4, 6,
28 8, 10, 13, 16, 19, 24, 28, 33, 39, 46,
29 53, 60, 69, 78, 88, 98, 110, 122, 135, 149,
30 164, 179, 196, 214, 232, 252, 273, 295, 317, 341,
31 366, 393, 420, 449, 478, 510, 542, 575, 610, 647,
32 684, 723, 764, 806, 849, 894, 940, 988, 1037, 1088,
33 1140, 1194, 1250, 1307, 1366, 1427, 1489, 1553, 1619, 1686,
34 1756, 1827, 1900, 1975, 2051, 2130, 2210, 2293, 2377, 2463,
35 2552, 2642, 2734, 2829, 2925, 3024, 3124, 3227, 3332, 3439,
36 3548, 3660, 3774, 3890, 4008, 4128, 4251, 4376, 4504, 4634,
37 4766, 4901, 5038, 5177, 5319, 5464, 5611, 5760, 5912, 6067,
38 6224, 6384, 6546, 6711, 6879, 7049, 7222, 7397, 7576, 7757,
39 7941, 8128, 8317, 8509, 8704, 8902, 9103, 9307, 9514, 9723,
40 9936, 10151, 10370, 10591, 10816, 11043, 11274, 11507, 11744, 11984,
41 12227, 12473, 12722, 12975, 13230, 13489, 13751, 14017, 14285, 14557,
42 14833, 15111, 15393, 15678, 15967, 16259, 16554, 16853, 17155, 17461,
43 17770, 18083, 18399, 18719, 19042, 19369, 19700, 20034, 20372, 20713,
44 21058, 21407, 21759, 22115, 22475, 22838, 23206, 23577, 23952, 24330,
45 24713, 25099, 25489, 25884, 26282, 26683, 27089, 27499, 27913, 28330,
46 28752, 29178, 29608, 30041, 30479, 30921, 31367, 31818, 32272, 32730,
47 33193, 33660, 34131, 34606, 35085, 35569, 36057, 36549, 37046, 37547,
48 38052, 38561, 39075, 39593, 40116, 40643, 41175, 41711, 42251, 42796,
49 43346, 43899, 44458, 45021, 45588, 46161, 46737, 47319, 47905, 48495,
50 49091, 49691, 50295, 50905, 51519, 52138, 52761, 53390, 54023, 54661,
51 55303, 55951, 56604, 57261, 57923, 58590, 59262, 59939, 60621, 61308,
52 62000, 62697, 63399, 64106, 64818, 65535};
53
57
58// 8-bit easing functions
60 // Simple quadratic ease-in: i^2 scaled to 8-bit range
61 // Using scale8(i, i) which computes (i * i) / 255
62 return scale8(i, i);
63}
64
66 constexpr u16 MAX = 0xFF; // 255
67 constexpr u16 HALF = (MAX + 1) >> 1; // 128
68 constexpr u16 DENOM = MAX; // divisor for scaling
69 constexpr u16 ROUND = DENOM >> 1; // for rounding
70
71 if (i < HALF) {
72 // first half: y = 2·(i/MAX)² → y_i = 2·i² / MAX
73 u32 t = i;
74 u32 num = 2 * t * t + ROUND; // 2*i², +half for rounding
75 return u8(num / DENOM);
76 } else {
77 // second half: y = 1 − 2·(1−i/MAX)²
78 // → y_i = MAX − (2·(MAX−i)² / MAX)
79 u32 d = MAX - i;
80 u32 num = 2 * d * d + ROUND; // 2*(MAX−i)², +half for rounding
81 return u8(MAX - (num / DENOM));
82 }
83}
84
86 constexpr u16 MAX = 0xFF; // 255
87 constexpr u16 HALF = (MAX + 1) >> 1; // 128
88 constexpr u32 DENOM = (u32)MAX * MAX; // 255*255 = 65025
89 constexpr u32 ROUND = DENOM >> 1; // for rounding
90
91 if (i < HALF) {
92 // first half: y = 4·(i/MAX)³ → y_i = 4·i³ / MAX²
93 u32 ii = i;
94 u32 cube = ii * ii * ii; // i³
95 u32 num = 4 * cube + ROUND; // 4·i³, +half denom for rounding
96 return u8(num / DENOM);
97 } else {
98 // second half: y = 1 − ((−2·t+2)³)/2
99 // where t = i/MAX; equivalently:
100 // y_i = MAX − (4·(MAX−i)³ / MAX²)
101 u32 d = MAX - i;
102 u32 cube = d * d * d; // (MAX−i)³
103 u32 num = 4 * cube + ROUND;
104 return u8(MAX - (num / DENOM));
105 }
106}
107
109 // ease-out is the inverse of ease-in: 1 - (1-t)²
110 // For 8-bit: y = MAX - (MAX-i)² / MAX
111 constexpr u16 MAX = 0xFF;
112 u32 d = MAX - i; // (MAX - i)
113 u32 num = d * d + (MAX >> 1); // (MAX-i)² + rounding
114 return u8(MAX - (num / MAX));
115}
116
118 // Simple cubic ease-in: i³ scaled to 8-bit range
119 // y = i³ / MAX²
120 constexpr u16 MAX = 0xFF;
121 constexpr u32 DENOM = (u32)MAX * MAX;
122 constexpr u32 ROUND = DENOM >> 1;
123
124 u32 ii = i;
125 u32 cube = ii * ii * ii; // i³
126 u32 num = cube + ROUND;
127 return u8(num / DENOM);
128}
129
131 // ease-out cubic: 1 - (1-t)³
132 // For 8-bit: y = MAX - (MAX-i)³ / MAX²
133 constexpr u16 MAX = 0xFF;
134 constexpr u32 DENOM = (u32)MAX * MAX;
135 constexpr u32 ROUND = DENOM >> 1;
136
137 u32 d = MAX - i; // (MAX - i)
138 u32 cube = d * d * d; // (MAX-i)³
139 u32 num = cube + ROUND;
140 return u8(MAX - (num / DENOM));
141}
142
144
145 static const u8 easeInSineTable[256] FL_PROGMEM = {
146 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
147 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4,
148 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8,
149 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13, 14, 14,
150 15, 16, 16, 17, 17, 18, 18, 19, 20, 20, 21, 21, 22, 23,
151 23, 24, 25, 25, 26, 27, 27, 28, 29, 30, 30, 31, 32, 33,
152 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 42, 43, 44,
153 45, 46, 47, 48, 49, 50, 51, 52, 52, 53, 54, 55, 56, 57,
154 58, 59, 60, 61, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72,
155 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 86, 87, 88,
156 89, 90, 91, 93, 94, 95, 96, 98, 99, 100, 101, 103, 104, 105,
157 106, 108, 109, 110, 112, 113, 114, 115, 117, 118, 119, 121, 122, 123,
158 125, 126, 127, 129, 130, 132, 133, 134, 136, 137, 139, 140, 141, 143,
159 144, 146, 147, 148, 150, 151, 153, 154, 156, 157, 159, 160, 161, 163,
160 164, 166, 167, 169, 170, 172, 173, 175, 176, 178, 179, 181, 182, 184,
161 185, 187, 188, 190, 191, 193, 194, 196, 197, 199, 200, 202, 204, 205,
162 207, 208, 210, 211, 213, 214, 216, 217, 219, 221, 222, 224, 225, 227,
163 228, 230, 231, 233, 235, 236, 238, 239, 241, 242, 244, 246, 247, 249,
164 250, 252, 253, 255};
165
166 // ease-in sine: 1 - cos(t * π/2)
167 // Handle boundary conditions explicitly
168 return FL_PGM_READ_BYTE_NEAR(&easeInSineTable[i]);
169}
170
172 // ease-out sine: sin(t * π/2)
173 // Delegate to 16-bit version for consistency and accuracy
174 // Scale 8-bit input to 16-bit range, call 16-bit function, scale result back
175 u16 input16 = map8_to_16(i);
176 u16 result16 = easeOutSine16(input16);
177 return map16_to_8(result16);
178}
179
181 // ease-in-out sine: -(cos(π*t) - 1) / 2
182 // Delegate to 16-bit version for consistency and accuracy
183 // Scale 8-bit input to 16-bit range, call 16-bit function, scale result back
184 u16 input16 = map8_to_16(i);
185 u16 result16 = easeInOutSine16(input16);
186 return map16_to_8(result16);
187}
188
189// 16-bit easing functions
191 // Simple quadratic ease-in: i^2 scaled to 16-bit range
192 // Using scale16(i, i) which computes (i * i) / 65535
193 return scale16(i, i);
194}
195
197 // 16-bit quadratic ease-in / ease-out function
198 constexpr u32 MAX = 0xFFFF; // 65535
199 constexpr u32 HALF = (MAX + 1) >> 1; // 32768
200 constexpr u32 DENOM = MAX; // divisor
201 constexpr u32 ROUND = DENOM >> 1; // for rounding
202
203 if (x < HALF) {
204 // first half: y = 2·(x/MAX)² → y_i = 2·x² / MAX
205 fl::u64 xi = x;
206 fl::u64 num = 2 * xi * xi + ROUND; // 2*x², +half for rounding
207 return u16(num / DENOM);
208 } else {
209 // second half: y = 1 − 2·(1−x/MAX)² → y_i = MAX − (2·(MAX−x)² / MAX)
210 fl::u64 d = MAX - x;
211 fl::u64 num = 2 * d * d + ROUND; // 2*(MAX−x)², +half for rounding
212 return u16(MAX - (num / DENOM));
213 }
214}
215
217 const u32 MAX = 0xFFFF; // 65535
218 const u32 HALF = (MAX + 1) >> 1; // 32768
219 const fl::u64 M2 = (fl::u64)MAX * MAX; // 65535² = 4 294 836 225
220
221 if (x < HALF) {
222 // first half: y = 4·(x/MAX)³ → y_i = 4·x³ / MAX²
223 fl::u64 xi = x;
224 fl::u64 cube = xi * xi * xi; // x³
225 // add M2/2 for rounding
226 fl::u64 num = 4 * cube + (M2 >> 1);
227 return (u16)(num / M2);
228 } else {
229 // second half: y = 1 − ((2·(1−x/MAX))³)/2
230 // → y_i = MAX − (4·(MAX−x)³ / MAX²)
231 fl::u64 d = MAX - x;
232 fl::u64 cube = d * d * d; // (MAX−x)³
233 fl::u64 num = 4 * cube + (M2 >> 1);
234 return (u16)(MAX - (num / M2));
235 }
236}
237
239 // ease-out quadratic: 1 - (1-t)²
240 // For 16-bit: y = MAX - (MAX-i)² / MAX
241 constexpr u32 MAX = 0xFFFF; // 65535
242 constexpr u32 ROUND = MAX >> 1; // for rounding
243
244 fl::u64 d = MAX - i; // (MAX - i)
245 fl::u64 num = d * d + ROUND; // (MAX-i)² + rounding
246 return u16(MAX - (num / MAX));
247}
248
250 // Simple cubic ease-in: i³ scaled to 16-bit range
251 // y = i³ / MAX²
252 constexpr u32 MAX = 0xFFFF; // 65535
253 constexpr fl::u64 DENOM = (fl::u64)MAX * MAX; // 65535²
254 constexpr fl::u64 ROUND = DENOM >> 1; // for rounding
255
256 fl::u64 ii = i;
257 fl::u64 cube = ii * ii * ii; // i³
258 fl::u64 num = cube + ROUND;
259 return u16(num / DENOM);
260}
261
263 // ease-out cubic: 1 - (1-t)³
264 // For 16-bit: y = MAX - (MAX-i)³ / MAX²
265 constexpr u32 MAX = 0xFFFF; // 65535
266 constexpr fl::u64 DENOM = (fl::u64)MAX * MAX; // 65535²
267 constexpr fl::u64 ROUND = DENOM >> 1; // for rounding
268
269 fl::u64 d = MAX - i; // (MAX - i)
270 fl::u64 cube = d * d * d; // (MAX-i)³
271 fl::u64 num = cube + ROUND;
272 return u16(MAX - (num / DENOM));
273}
274
276 // ease-in sine: 1 - cos(t * π/2)
277 // Handle boundary conditions explicitly
278 if (i == 0)
279 return 0;
280 // Remove the hard-coded boundary for 65535 and let math handle it
281
282 // For 16-bit: use cos32 for efficiency and accuracy
283 // Map i from [0,65535] to [0,4194304] in cos32 space (zero to quarter wave)
284 // Formula: 1 - cos(t * π/2) where t goes from 0 to 1
285 // sin32/cos32 quarter cycle is 16777216/4 = 4194304
286 u32 angle = ((fl::u64)i * 4194304ULL) / 65535ULL;
287 i32 cos_result = fl::cos32(angle);
288
289 // Convert cos32 output and apply easing formula: 1 - cos(t * π/2)
290 // cos32 output range is [-2147418112, 2147418112]
291 // At t=0: cos(0) = 2147418112, result should be 0
292 // At t=1: cos(π/2) = 0, result should be 65535
293
294 const fl::i64 MAX_COS32 = 2147418112LL;
295
296 // Calculate: (MAX_COS32 - cos_result) and scale to [0, 65535]
297 fl::i64 adjusted = MAX_COS32 - (fl::i64)cos_result;
298
299 // Scale from [0, 2147418112] to [0, 65535]
300 fl::u64 result = (fl::u64)adjusted * 65535ULL + (MAX_COS32 >> 1); // Add half for rounding
301 u16 final_result = (u16)(result / (fl::u64)MAX_COS32);
302
303 return final_result;
304}
305
307 // ease-out sine: sin(t * π/2)
308 // Handle boundary conditions explicitly
309 if (i == 0)
310 return 0;
311 if (i == 65535)
312 return 65535;
313
314 // For 16-bit: use sin32 for efficiency and accuracy
315 // Map i from [0,65535] to [0,4194304] in sin32 space (zero to quarter wave)
316 // Formula: sin(t * π/2) where t goes from 0 to 1
317 // sin32 quarter cycle is 16777216/4 = 4194304
318 u32 angle = ((fl::u64)i * 4194304ULL) / 65535ULL;
319 i32 sin_result = fl::sin32(angle);
320
321 // Convert sin32 output range [-2147418112, 2147418112] to [0, 65535]
322 // sin32 output is in range -32767*65536 to +32767*65536
323 // For ease-out sine, we only use positive portion [0, 2147418112] -> [0, 65535]
324 return (u16)((fl::u64)sin_result * 65535ULL / 2147418112ULL);
325}
326
328 // ease-in-out sine: -(cos(π*t) - 1) / 2
329 // Handle boundary conditions explicitly
330 if (i == 0)
331 return 0;
332 if (i == 65535)
333 return 65535;
334
335 // For 16-bit: use cos32 for efficiency and accuracy
336 // Map i from [0,65535] to [0,8388608] in cos32 space (0 to half wave)
337 // Formula: (1 - cos(π*t)) / 2 where t goes from 0 to 1
338 // sin32/cos32 half cycle is 16777216/2 = 8388608
339 u32 angle = ((fl::u64)i * 8388608ULL) / 65535ULL;
340 i32 cos_result = fl::cos32(angle);
341
342 // Convert cos32 output and apply easing formula: (1 - cos(π*t)) / 2
343 // cos32 output range is [-2147418112, 2147418112]
344 // We want: (2147418112 - cos_result) / 2, then scale to [0, 65535]
345 fl::i64 adjusted = (2147418112LL - (fl::i64)cos_result) / 2;
346 return (u16)((fl::u64)adjusted * 65535ULL / 2147418112ULL);
347}
348
349// --- Gamma8 implementation ---
350
351// Fixed-point key for gamma cache: unsigned 4.12 (range [0, 15.999], 1/4096 resolution).
353
354class Gamma8Impl : public Gamma8 {
355public:
356 explicit Gamma8Impl(float gamma) FL_NO_EXCEPT {
357 // i=0 is mathematically exact regardless of gamma: pow(0, any) = 0.
358 // The s8x24::pow short-circuit covers exact 0 input, but we set it
359 // here directly anyway because (a) the loop below avoids the
360 // round-trip math and (b) `mLut` is otherwise uninitialized.
361 // i=255 used to need a workaround for the log2(1+t) endpoint
362 // residual; that snap is now handled inside s8x24::pow itself
363 // (see #2969).
364 mLut[0] = 0;
365 // Compute the 256-entry u16 gamma LUT in fixed-point so we don't
366 // pull `__ieee754_pow` (libm, ~2.7 KB) into release builds — the
367 // double-precision pow chain dominates the top-9 bytes attributed
368 // to libm in the post-#2908 ESP32-S3 NEOPIXEL Blink audit
369 // (see #2886 / #2910).
370 //
371 // `s8x24` is 8-integer + 24-fractional bits (same 32-bit storage as
372 // s16x16, but 256× the sub-LSB resolution). Both log2_fp/exp2_fp use
373 // the same 4-term minimax polynomial, but s8x24 carries the full
374 // 24-bit intermediate precision end-to-end instead of truncating
375 // back to 16 frac bits at each stage — bringing the runtime output
376 // within ~1 LSB of true float pow() at the u16 output. Combined
377 // with the special-case for gamma=2.8 in Gamma8::getOrCreate(),
378 // this closes the divergence with the precomputed GAMMA_2_8_LUT
379 // (see #2963 audit + ucs7604 "default gamma 2.8" subcase).
380 //
381 // Bit budget check: max intermediate is exp*log2_fp(1/255) =
382 // 16 * -7.994 ≈ -127.9, fits in s8x24's signed [-128, 128) range.
383 // (GammaKey caps user gamma at 16.)
384 //
385 // libm-free: log2_fp/exp2_fp are pure integer-polynomial impls.
386 // The only float kept is the one-shot s8x24(gamma) constructor
387 // call (pulls __mulsf3 / __fixsfsi helpers, both << 100 B).
388 const fl::s8x24 gamma_fp(gamma);
389 constexpr fl::s8x24 inv_255_fp(1.0f / 255.0f);
390 for (int i = 1; i < 256; ++i) {
391 const fl::s8x24 x = static_cast<i32>(i) * inv_255_fp; // (0, 1]
392 const fl::s8x24 r = fl::s8x24::pow(x, gamma_fp); // (0, 1]
393 // r.raw() is the s8x24 raw with FRAC_BITS=24, range [0, 2^24].
394 // Scale to u16 [0, 65535] with round-half-up. 24+16 bit
395 // multiplication needs a u64 intermediate:
396 // result = ((u64)raw * 65535 + (1<<23)) >> 24
397 const fl::u64 scaled =
398 (static_cast<fl::u64>(static_cast<fl::u32>(r.raw())) * 65535ull
399 + (1ull << 23)) >> 24;
400 mLut[i] = static_cast<u16>(scaled > 65535u ? 65535u : scaled);
401 }
402 }
403
404 // Construct a Gamma8Impl by copying a precomputed PROGMEM LUT directly
405 // into mLut. Used by Gamma8::getOrCreate(2.8f) to alias GAMMA_2_8_LUT,
406 // guaranteeing bit-identical output with fl::gamma_2_8() and skipping
407 // the runtime pow chain entirely. The `from_progmem_lut_tag` tag
408 // disambiguates from the float ctor; we can't add a ctor taking just
409 // `const u16*` because that would silently bind to integer-literal
410 // gammas (`Gamma8::getOrCreate(2)` would be a footgun).
413 for (int i = 0; i < 256; ++i) {
414 mLut[i] = FL_PGM_READ_WORD_ALIGNED(&progmem_lut[i]);
415 }
416 }
417
419 fl::span<u16> output) const FL_NO_EXCEPT override {
420 const int n =
421 input.size() < output.size() ? input.size() : output.size();
422 for (int i = 0; i < n; ++i) {
423 output[i] = mLut[input[i]];
424 }
425 }
426
428 fl::span<u16> output) const FL_NO_EXCEPT override {
429 const int n =
430 input.size() < output.size() ? input.size() : output.size();
431 for (int i = 0; i < n; ++i) {
432 output[i] = lerpLut(input[i]);
433 }
434 }
435
437 fl::span<fl::ufixed_point<8, 8>> output) const FL_NO_EXCEPT override {
438 using FP = fl::ufixed_point<8, 8>;
439 const int n =
440 input.size() < output.size() ? input.size() : output.size();
441 for (int i = 0; i < n; ++i) {
442 output[i] = FP::from_raw(lerpLut(input[i]));
443 }
444 }
445
446private:
448 u16 raw = fp.raw();
449 u8 idx = static_cast<u8>(raw >> 8); // integer part (LUT index)
450 u8 frac = static_cast<u8>(raw & 0xFF); // fractional part (0-255)
451 u16 a = mLut[idx];
452 u16 b = (idx < 255) ? mLut[idx + 1] : mLut[idx];
453 i32 diff = static_cast<i32>(b) - static_cast<i32>(a);
454 return static_cast<u16>(a + ((diff * frac) >> 8));
455 }
456
457 FL_ALIGNAS(64) u16 mLut[256];
458};
459
461 // Clamp gamma to the cache-key domain BEFORE deriving the key and
462 // before feeding it to s8x24. `GammaKey` is `ufixed_point<4, 12>`,
463 // so its representable range is [0, ~16). A negative input would
464 // wrap unsigned in the GammaKey ctor; an input ≥ 16 would either
465 // saturate or wrap. Clamping up-front also keeps the s8x24 bit
466 // budget safe: `exp * log2_fp(1/255) ≈ -7.994 * gamma` must stay
467 // within s8x24's signed [-128, 128) integer range — gamma ≤ 16
468 // gives -127.9, right at the edge.
469 constexpr float kGammaMax = 15.99975f; // just under 4.12 ufixed max
470 const float gamma_clamped = (gamma < 0.0f) ? 0.0f
471 : (gamma > kGammaMax) ? kGammaMax
472 : gamma;
473 GammaKey key(gamma_clamped);
474
475 // Fast path: gamma 2.8 is the canonical default (every legacy
476 // `addLeds<NEOPIXEL>` flow, every WS281x chipset). We have a
477 // precomputed `GAMMA_2_8_LUT` already in .rodata (used by the
478 // free function `fl::gamma_2_8`). Construct a Gamma8 instance
479 // that copies that table directly instead of recomputing 256
480 // fixed-point pow operations (which would diverge from the
481 // precomputed values by ~30-50 LSB). Cached via weak_ptr to
482 // match the documented `getOrCreate` lifetime contract — the
483 // instance disappears once all callers drop their shared_ptr,
484 // and the next call rebuilds it.
485 constexpr GammaKey k28(2.8f);
486 if (key == k28) {
487 static fl::weak_ptr<const Gamma8> s28_weak;
488 if (auto existing = s28_weak.lock()) {
489 return existing;
490 }
493 s28_weak = ptr;
494 return ptr;
495 }
496
497 // Slow path: arbitrary gamma. Single-entry weak_ptr cache. Users
498 // who switch gamma values at runtime pay one extra `Gamma8Impl`
499 // reconstruction per switch (256 fixed-point pow operations +
500 // ~512 B alloc). See #2928 / #2886.
501 static GammaKey sCachedKey{};
502 static fl::weak_ptr<const Gamma8> sCachedPtr;
503 static bool sCacheValid = false;
504
505 if (sCacheValid && key == sCachedKey) {
506 if (auto existing = sCachedPtr.lock()) {
507 return existing;
508 }
509 }
510
511 // Use the clamped gamma so the LUT we build matches the cache key
512 // (otherwise out-of-range inputs would keep missing the cache).
514 fl::make_shared<Gamma8Impl>(gamma_clamped);
515 sCachedKey = key;
516 sCachedPtr = ptr;
517 sCacheValid = true;
518 return ptr;
519}
520
521} // namespace fl
Alignment macros and utilities for FastLED.
static fl::shared_ptr< const Gamma8 > getOrCreate(float gamma) FL_NO_EXCEPT
Definition ease.cpp.hpp:460
Gamma8Impl(from_progmem_lut_tag, const u16 *progmem_lut) FL_NO_EXCEPT
Definition ease.cpp.hpp:412
FL_ALIGNAS(64) u16 mLut[256]
void convert(fl::span< const fl::ufixed_point< 8, 8 > > input, fl::span< fl::ufixed_point< 8, 8 > > output) const FL_NO_EXCEPT override
Definition ease.cpp.hpp:436
void convert(fl::span< const u8 > input, fl::span< u16 > output) const FL_NO_EXCEPT override
Definition ease.cpp.hpp:418
Gamma8Impl(float gamma) FL_NO_EXCEPT
Definition ease.cpp.hpp:356
u16 lerpLut(const fl::ufixed_point< 8, 8 > &fp) const FL_NO_EXCEPT
Definition ease.cpp.hpp:447
void convert(fl::span< const fl::ufixed_point< 8, 8 > > input, fl::span< u16 > output) const FL_NO_EXCEPT override
Definition ease.cpp.hpp:427
static FASTLED_FORCE_INLINE s8x24 pow(s8x24 base, s8x24 exp) FL_NO_EXCEPT
Definition s8x24.h:216
constexpr i32 raw() const FL_NO_EXCEPT
Definition s8x24.h:59
shared_ptr< T > lock() const FL_NO_EXCEPT
Definition weak_ptr.h:140
#define FL_ALIGN_PROGMEM(N)
Force N-byte alignment for platforms with unaligned access or cache-line optimization.
#define FL_PGM_READ_BYTE_NEAR(x)
Read a byte (8-bit) from PROGMEM memory.
#define FL_PGM_READ_WORD_ALIGNED(addr)
#define FL_PROGMEM
PROGMEM keyword for storage.
Integer mapping functions between different integer sizes.
Internal FastLED header for implementation files.
u16 map8_to_16(u8 x) FL_NO_EXCEPT
Definition intmap.h:48
u8 map16_to_8(u16 x) FL_NO_EXCEPT
Definition intmap.h:66
Fast, efficient 8-bit math functions specifically designed for high-performance LED programming.
shared_ptr< T > make_shared(Args &&... args) FL_NO_EXCEPT
Definition shared_ptr.h:423
FASTLED_FORCE_INLINE i32 sin32(u32 angle) FL_NO_EXCEPT
Definition sin32.h:57
unsigned char u8
Definition stdint.h:131
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
constexpr int type_rank< T >::value
u16 gamma_2_8(u8 value) FL_NO_EXCEPT
Definition ease.cpp.hpp:54
u16 easeInOutCubic16(u16 x) FL_NO_EXCEPT
16-bit cubic ease-in/ease-out function Takes an input value 0-65535 and returns an eased value 0-6553...
Definition ease.cpp.hpp:216
constexpr u32 gamma(float g) FL_NO_EXCEPT
Definition gamma_lut.h:36
u16 easeInQuad16(u16 i) FL_NO_EXCEPT
16-bit quadratic ease-in function Takes an input value 0-65535 and returns an eased value 0-65535
Definition ease.cpp.hpp:190
u16 easeOutSine16(u16 i) FL_NO_EXCEPT
16-bit sine ease-out function Takes an input value 0-65535 and returns an eased value 0-65535
Definition ease.cpp.hpp:306
u8 easeInOutCubic8(u8 i) FL_NO_EXCEPT
8-bit cubic ease-in/ease-out function Takes an input value 0-255 and returns an eased value 0-255 Mor...
Definition ease.cpp.hpp:85
u8 easeInQuad8(u8 i) FL_NO_EXCEPT
8-bit quadratic ease-in function Takes an input value 0-255 and returns an eased value 0-255 The curv...
Definition ease.cpp.hpp:59
fl::ufixed_point< 4, 12 > GammaKey
Definition ease.cpp.hpp:352
const u16 GAMMA_2_8_LUT[256]
u8 easeInOutSine8(u8 i) FL_NO_EXCEPT
8-bit sine ease-in/ease-out function Takes an input value 0-255 and returns an eased value 0-255 Smoo...
Definition ease.cpp.hpp:180
u8 easeInSine8(u8 i) FL_NO_EXCEPT
8-bit sine ease-in function Takes an input value 0-255 and returns an eased value 0-255 Smooth sinuso...
Definition ease.cpp.hpp:143
FASTLED_FORCE_INLINE i32 cos32(u32 angle) FL_NO_EXCEPT
Definition sin32.h:79
u16 easeInOutQuad16(u16 x) FL_NO_EXCEPT
16-bit quadratic ease-in/ease-out function Takes an input value 0-65535 and returns an eased value 0-...
Definition ease.cpp.hpp:196
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
u8 easeInCubic8(u8 i) FL_NO_EXCEPT
8-bit cubic ease-in function Takes an input value 0-255 and returns an eased value 0-255 More pronoun...
Definition ease.cpp.hpp:117
u8 easeOutQuad8(u8 i) FL_NO_EXCEPT
8-bit quadratic ease-out function Takes an input value 0-255 and returns an eased value 0-255 The cur...
Definition ease.cpp.hpp:108
u16 easeInCubic16(u16 i) FL_NO_EXCEPT
16-bit cubic ease-in function Takes an input value 0-65535 and returns an eased value 0-65535
Definition ease.cpp.hpp:249
u16 easeOutCubic16(u16 i) FL_NO_EXCEPT
16-bit cubic ease-out function Takes an input value 0-65535 and returns an eased value 0-65535
Definition ease.cpp.hpp:262
u8 easeOutSine8(u8 i) FL_NO_EXCEPT
8-bit sine ease-out function Takes an input value 0-255 and returns an eased value 0-255 Smooth sinus...
Definition ease.cpp.hpp:171
u8 easeOutCubic8(u8 i) FL_NO_EXCEPT
8-bit cubic ease-out function Takes an input value 0-255 and returns an eased value 0-255 More pronou...
Definition ease.cpp.hpp:130
u16 easeInOutSine16(u16 i) FL_NO_EXCEPT
16-bit sine ease-in/ease-out function Takes an input value 0-65535 and returns an eased value 0-65535
Definition ease.cpp.hpp:327
u16 easeInSine16(u16 i) FL_NO_EXCEPT
16-bit sine ease-in function Takes an input value 0-65535 and returns an eased value 0-65535
Definition ease.cpp.hpp:275
u8 easeInOutQuad8(u8 i) FL_NO_EXCEPT
8-bit quadratic ease-in/ease-out function Takes an input value 0-255 and returns an eased value 0-255...
Definition ease.cpp.hpp:65
ufixed_integer< IntBits, FracBits > ufixed_point
u16 easeOutQuad16(u16 i) FL_NO_EXCEPT
16-bit quadratic ease-out function Takes an input value 0-65535 and returns an eased value 0-65535
Definition ease.cpp.hpp:238
Base definition for an LED controller.
Definition crgb.hpp:179