#ifndef FASTLED_INTERNAL #define FASTLED_INTERNAL #endif #include "FastLED.h" #include "fl/ease.h" #include "lib8tion.h" // This is the problematic header that's hard to include #include "fl/map_range.h" #include "lib8tion/intmap.h" #include "fl/sin32.h" #include "fl/int.h" namespace fl { // Gamma 2.8 lookup table for 8-bit to 16-bit gamma correction // This table converts linear 8-bit values to gamma-corrected 16-bit values // using a gamma curve of 2.8 (commonly used for LED brightness correction) const u16 gamma_2_8[256] FL_PROGMEM = { 0, 0, 0, 1, 1, 2, 4, 6, 8, 11, 14, 18, 23, 29, 35, 41, 49, 57, 67, 77, 88, 99, 112, 126, 141, 156, 173, 191, 210, 230, 251, 274, 297, 322, 348, 375, 404, 433, 464, 497, 531, 566, 602, 640, 680, 721, 763, 807, 853, 899, 948, 998, 1050, 1103, 1158, 1215, 1273, 1333, 1394, 1458, 1523, 1590, 1658, 1729, 1801, 1875, 1951, 2029, 2109, 2190, 2274, 2359, 2446, 2536, 2627, 2720, 2816, 2913, 3012, 3114, 3217, 3323, 3431, 3541, 3653, 3767, 3883, 4001, 4122, 4245, 4370, 4498, 4627, 4759, 4893, 5030, 5169, 5310, 5453, 5599, 5747, 5898, 6051, 6206, 6364, 6525, 6688, 6853, 7021, 7191, 7364, 7539, 7717, 7897, 8080, 8266, 8454, 8645, 8838, 9034, 9233, 9434, 9638, 9845, 10055, 10267, 10482, 10699, 10920, 11143, 11369, 11598, 11829, 12064, 12301, 12541, 12784, 13030, 13279, 13530, 13785, 14042, 14303, 14566, 14832, 15102, 15374, 15649, 15928, 16209, 16493, 16781, 17071, 17365, 17661, 17961, 18264, 18570, 18879, 19191, 19507, 19825, 20147, 20472, 20800, 21131, 21466, 21804, 22145, 22489, 22837, 23188, 23542, 23899, 24260, 24625, 24992, 25363, 25737, 26115, 26496, 26880, 27268, 27659, 28054, 28452, 28854, 29259, 29667, 30079, 30495, 30914, 31337, 31763, 32192, 32626, 33062, 33503, 33947, 34394, 34846, 35300, 35759, 36221, 36687, 37156, 37629, 38106, 38586, 39071, 39558, 40050, 40545, 41045, 41547, 42054, 42565, 43079, 43597, 44119, 44644, 45174, 45707, 46245, 46786, 47331, 47880, 48432, 48989, 49550, 50114, 50683, 51255, 51832, 52412, 52996, 53585, 54177, 54773, 55374, 55978, 56587, 57199, 57816, 58436, 59061, 59690, 60323, 60960, 61601, 62246, 62896, 63549, 64207, 64869, 65535}; // 8-bit easing functions u8 easeInQuad8(u8 i) { // Simple quadratic ease-in: i^2 scaled to 8-bit range // Using scale8(i, i) which computes (i * i) / 255 return scale8(i, i); } u8 easeInOutQuad8(u8 i) { constexpr u16 MAX = 0xFF; // 255 constexpr u16 HALF = (MAX + 1) >> 1; // 128 constexpr u16 DENOM = MAX; // divisor for scaling constexpr u16 ROUND = DENOM >> 1; // for rounding if (i < HALF) { // first half: y = 2·(i/MAX)² → y_i = 2·i² / MAX u32 t = i; u32 num = 2 * t * t + ROUND; // 2*i², +half for rounding return u8(num / DENOM); } else { // second half: y = 1 − 2·(1−i/MAX)² // → y_i = MAX − (2·(MAX−i)² / MAX) u32 d = MAX - i; u32 num = 2 * d * d + ROUND; // 2*(MAX−i)², +half for rounding return u8(MAX - (num / DENOM)); } } u8 easeInOutCubic8(u8 i) { constexpr u16 MAX = 0xFF; // 255 constexpr u16 HALF = (MAX + 1) >> 1; // 128 constexpr u32 DENOM = (u32)MAX * MAX; // 255*255 = 65025 constexpr u32 ROUND = DENOM >> 1; // for rounding if (i < HALF) { // first half: y = 4·(i/MAX)³ → y_i = 4·i³ / MAX² u32 ii = i; u32 cube = ii * ii * ii; // i³ u32 num = 4 * cube + ROUND; // 4·i³, +half denom for rounding return u8(num / DENOM); } else { // second half: y = 1 − ((−2·t+2)³)/2 // where t = i/MAX; equivalently: // y_i = MAX − (4·(MAX−i)³ / MAX²) u32 d = MAX - i; u32 cube = d * d * d; // (MAX−i)³ u32 num = 4 * cube + ROUND; return u8(MAX - (num / DENOM)); } } u8 easeOutQuad8(u8 i) { // ease-out is the inverse of ease-in: 1 - (1-t)² // For 8-bit: y = MAX - (MAX-i)² / MAX constexpr u16 MAX = 0xFF; u32 d = MAX - i; // (MAX - i) u32 num = d * d + (MAX >> 1); // (MAX-i)² + rounding return u8(MAX - (num / MAX)); } u8 easeInCubic8(u8 i) { // Simple cubic ease-in: i³ scaled to 8-bit range // y = i³ / MAX² constexpr u16 MAX = 0xFF; constexpr u32 DENOM = (u32)MAX * MAX; constexpr u32 ROUND = DENOM >> 1; u32 ii = i; u32 cube = ii * ii * ii; // i³ u32 num = cube + ROUND; return u8(num / DENOM); } u8 easeOutCubic8(u8 i) { // ease-out cubic: 1 - (1-t)³ // For 8-bit: y = MAX - (MAX-i)³ / MAX² constexpr u16 MAX = 0xFF; constexpr u32 DENOM = (u32)MAX * MAX; constexpr u32 ROUND = DENOM >> 1; u32 d = MAX - i; // (MAX - i) u32 cube = d * d * d; // (MAX-i)³ u32 num = cube + ROUND; return u8(MAX - (num / DENOM)); } u8 easeInSine8(u8 i) { static const u8 easeInSineTable[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13, 14, 14, 15, 16, 16, 17, 17, 18, 18, 19, 20, 20, 21, 21, 22, 23, 23, 24, 25, 25, 26, 27, 27, 28, 29, 30, 30, 31, 32, 33, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83, 84, 86, 87, 88, 89, 90, 91, 93, 94, 95, 96, 98, 99, 100, 101, 103, 104, 105, 106, 108, 109, 110, 112, 113, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126, 127, 129, 130, 132, 133, 134, 136, 137, 139, 140, 141, 143, 144, 146, 147, 148, 150, 151, 153, 154, 156, 157, 159, 160, 161, 163, 164, 166, 167, 169, 170, 172, 173, 175, 176, 178, 179, 181, 182, 184, 185, 187, 188, 190, 191, 193, 194, 196, 197, 199, 200, 202, 204, 205, 207, 208, 210, 211, 213, 214, 216, 217, 219, 221, 222, 224, 225, 227, 228, 230, 231, 233, 235, 236, 238, 239, 241, 242, 244, 246, 247, 249, 250, 252, 253, 255}; // ease-in sine: 1 - cos(t * π/2) // Handle boundary conditions explicitly return easeInSineTable[i]; } u8 easeOutSine8(u8 i) { // ease-out sine: sin(t * π/2) // Delegate to 16-bit version for consistency and accuracy // Scale 8-bit input to 16-bit range, call 16-bit function, scale result back u16 input16 = map8_to_16(i); u16 result16 = easeOutSine16(input16); return map16_to_8(result16); } u8 easeInOutSine8(u8 i) { // ease-in-out sine: -(cos(π*t) - 1) / 2 // Delegate to 16-bit version for consistency and accuracy // Scale 8-bit input to 16-bit range, call 16-bit function, scale result back u16 input16 = map8_to_16(i); u16 result16 = easeInOutSine16(input16); return map16_to_8(result16); } // 16-bit easing functions u16 easeInQuad16(u16 i) { // Simple quadratic ease-in: i^2 scaled to 16-bit range // Using scale16(i, i) which computes (i * i) / 65535 return scale16(i, i); } u16 easeInOutQuad16(u16 x) { // 16-bit quadratic ease-in / ease-out function constexpr u32 MAX = 0xFFFF; // 65535 constexpr u32 HALF = (MAX + 1) >> 1; // 32768 constexpr u32 DENOM = MAX; // divisor constexpr u32 ROUND = DENOM >> 1; // for rounding if (x < HALF) { // first half: y = 2·(x/MAX)² → y_i = 2·x² / MAX fl::u64 xi = x; fl::u64 num = 2 * xi * xi + ROUND; // 2*x², +half for rounding return u16(num / DENOM); } else { // second half: y = 1 − 2·(1−x/MAX)² → y_i = MAX − (2·(MAX−x)² / MAX) fl::u64 d = MAX - x; fl::u64 num = 2 * d * d + ROUND; // 2*(MAX−x)², +half for rounding return u16(MAX - (num / DENOM)); } } u16 easeInOutCubic16(u16 x) { const u32 MAX = 0xFFFF; // 65535 const u32 HALF = (MAX + 1) >> 1; // 32768 const fl::u64 M2 = (fl::u64)MAX * MAX; // 65535² = 4 294 836 225 if (x < HALF) { // first half: y = 4·(x/MAX)³ → y_i = 4·x³ / MAX² fl::u64 xi = x; fl::u64 cube = xi * xi * xi; // x³ // add M2/2 for rounding fl::u64 num = 4 * cube + (M2 >> 1); return (u16)(num / M2); } else { // second half: y = 1 − ((2·(1−x/MAX))³)/2 // → y_i = MAX − (4·(MAX−x)³ / MAX²) fl::u64 d = MAX - x; fl::u64 cube = d * d * d; // (MAX−x)³ fl::u64 num = 4 * cube + (M2 >> 1); return (u16)(MAX - (num / M2)); } } u16 easeOutQuad16(u16 i) { // ease-out quadratic: 1 - (1-t)² // For 16-bit: y = MAX - (MAX-i)² / MAX constexpr u32 MAX = 0xFFFF; // 65535 constexpr u32 ROUND = MAX >> 1; // for rounding fl::u64 d = MAX - i; // (MAX - i) fl::u64 num = d * d + ROUND; // (MAX-i)² + rounding return u16(MAX - (num / MAX)); } u16 easeInCubic16(u16 i) { // Simple cubic ease-in: i³ scaled to 16-bit range // y = i³ / MAX² constexpr u32 MAX = 0xFFFF; // 65535 constexpr fl::u64 DENOM = (fl::u64)MAX * MAX; // 65535² constexpr fl::u64 ROUND = DENOM >> 1; // for rounding fl::u64 ii = i; fl::u64 cube = ii * ii * ii; // i³ fl::u64 num = cube + ROUND; return u16(num / DENOM); } u16 easeOutCubic16(u16 i) { // ease-out cubic: 1 - (1-t)³ // For 16-bit: y = MAX - (MAX-i)³ / MAX² constexpr u32 MAX = 0xFFFF; // 65535 constexpr fl::u64 DENOM = (fl::u64)MAX * MAX; // 65535² constexpr fl::u64 ROUND = DENOM >> 1; // for rounding fl::u64 d = MAX - i; // (MAX - i) fl::u64 cube = d * d * d; // (MAX-i)³ fl::u64 num = cube + ROUND; return u16(MAX - (num / DENOM)); } u16 easeInSine16(u16 i) { // ease-in sine: 1 - cos(t * π/2) // Handle boundary conditions explicitly if (i == 0) return 0; // Remove the hard-coded boundary for 65535 and let math handle it // For 16-bit: use cos32 for efficiency and accuracy // Map i from [0,65535] to [0,4194304] in cos32 space (zero to quarter wave) // Formula: 1 - cos(t * π/2) where t goes from 0 to 1 // sin32/cos32 quarter cycle is 16777216/4 = 4194304 u32 angle = ((fl::u64)i * 4194304ULL) / 65535ULL; i32 cos_result = fl::cos32(angle); // Convert cos32 output and apply easing formula: 1 - cos(t * π/2) // cos32 output range is [-2147418112, 2147418112] // At t=0: cos(0) = 2147418112, result should be 0 // At t=1: cos(π/2) = 0, result should be 65535 const fl::i64 MAX_COS32 = 2147418112LL; // Calculate: (MAX_COS32 - cos_result) and scale to [0, 65535] fl::i64 adjusted = MAX_COS32 - (fl::i64)cos_result; // Scale from [0, 2147418112] to [0, 65535] fl::u64 result = (fl::u64)adjusted * 65535ULL + (MAX_COS32 >> 1); // Add half for rounding u16 final_result = (u16)(result / (fl::u64)MAX_COS32); return final_result; } u16 easeOutSine16(u16 i) { // ease-out sine: sin(t * π/2) // Handle boundary conditions explicitly if (i == 0) return 0; if (i == 65535) return 65535; // For 16-bit: use sin32 for efficiency and accuracy // Map i from [0,65535] to [0,4194304] in sin32 space (zero to quarter wave) // Formula: sin(t * π/2) where t goes from 0 to 1 // sin32 quarter cycle is 16777216/4 = 4194304 u32 angle = ((fl::u64)i * 4194304ULL) / 65535ULL; i32 sin_result = fl::sin32(angle); // Convert sin32 output range [-2147418112, 2147418112] to [0, 65535] // sin32 output is in range -32767*65536 to +32767*65536 // For ease-out sine, we only use positive portion [0, 2147418112] -> [0, 65535] return (u16)((fl::u64)sin_result * 65535ULL / 2147418112ULL); } u16 easeInOutSine16(u16 i) { // ease-in-out sine: -(cos(π*t) - 1) / 2 // Handle boundary conditions explicitly if (i == 0) return 0; if (i == 65535) return 65535; // For 16-bit: use cos32 for efficiency and accuracy // Map i from [0,65535] to [0,8388608] in cos32 space (0 to half wave) // Formula: (1 - cos(π*t)) / 2 where t goes from 0 to 1 // sin32/cos32 half cycle is 16777216/2 = 8388608 u32 angle = ((fl::u64)i * 8388608ULL) / 65535ULL; i32 cos_result = fl::cos32(angle); // Convert cos32 output and apply easing formula: (1 - cos(π*t)) / 2 // cos32 output range is [-2147418112, 2147418112] // We want: (2147418112 - cos_result) / 2, then scale to [0, 65535] fl::i64 adjusted = (2147418112LL - (fl::i64)cos_result) / 2; return (u16)((fl::u64)adjusted * 65535ULL / 2147418112ULL); } } // namespace fl