50 const float T =
static_cast<float>(
51 (cct < 1500) ? 1500 : ((cct > 15000) ? 15000 : cct));
52 const float T2 = T * T;
53 const float u_num = 0.860117757f + 1.54118254e-4f * T + 1.28641212e-7f * T2;
54 const float u_den = 1.0f + 8.42420235e-4f * T + 7.08145163e-7f * T2;
55 const float v_num = 0.317398726f + 4.22806245e-5f * T + 4.20481691e-8f * T2;
56 const float v_den = 1.0f - 2.89741816e-5f * T + 1.61456053e-7f * T2;
57 const float u = u_num / u_den;
58 const float v = v_num / v_den;
59 const float den = 2.0f * u - 8.0f * v + 4.0f;
60 out[0] = 3.0f * u / den;
61 out[1] = 2.0f * v / den;
66 out[0] = out[1] = out[2] = 0.0f;
69 const float inv_y = 1.0f /
y;
70 out[0] =
x * Y * inv_y;
72 out[2] = (1.0f -
x -
y) * Y * inv_y;
76 const float a = in[0][0], b = in[0][1], c = in[0][2];
77 const float d = in[1][0], e = in[1][1], f = in[1][2];
78 const float g = in[2][0], h = in[2][1], i = in[2][2];
79 const float det = a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g);
83 const float inv_det = 1.0f / det;
84 out[0][0] = (e * i - f * h) * inv_det;
85 out[0][1] = (c * h - b * i) * inv_det;
86 out[0][2] = (b * f - c * e) * inv_det;
87 out[1][0] = (f * g - d * i) * inv_det;
88 out[1][1] = (a * i - c * g) * inv_det;
89 out[1][2] = (c * d - a * f) * inv_det;
90 out[2][0] = (d * h - e * g) * inv_det;
91 out[2][1] = (b * g - a * h) * inv_det;
92 out[2][2] = (a * e - b * d) * inv_det;
97 out[0] = M[0][0] * v[0] + M[0][1] * v[1] + M[0][2] * v[2];
98 out[1] = M[1][0] * v[0] + M[1][1] * v[1] + M[1][2] * v[2];
99 out[2] = M[2][0] * v[0] + M[2][1] * v[1] + M[2][2] * v[2];
104 const float v0x =
B[0] - A[0], v0y =
B[1] - A[1];
105 const float v1x = C[0] - A[0], v1y = C[1] - A[1];
106 const float v2x =
t[0] - A[0], v2y =
t[1] - A[1];
107 const float d00 = v0x * v0x + v0y * v0y;
108 const float d01 = v0x * v1x + v0y * v1y;
109 const float d11 = v1x * v1x + v1y * v1y;
110 const float d20 = v2x * v0x + v2y * v0y;
111 const float d21 = v2x * v1x + v2y * v1y;
112 const float den = d00 * d11 - d01 * d01;
116 const float inv_den = 1.0f / den;
117 const float u = (d11 * d20 - d01 * d21) * inv_den;
118 const float v = (d00 * d21 - d01 * d20) * inv_den;
119 bary[0] = 1.0f - u - v;
126 const float scaled = v * 255.0f + 0.5f;
127 if (scaled <= 0.0f)
return 0;
128 if (scaled >= 255.0f)
return 255;
129 return static_cast<u8>(scaled);
140 const float xy_b[2],
const float xy_w[2],
142 float xyz_R[3], xyz_G[3], xyz_B[3], xyz_W[3];
149 P[0][0] = xyz_R[0];
P[0][1] = xyz_G[0];
P[0][2] = xyz_B[0];
150 P[1][0] = xyz_R[1];
P[1][1] = xyz_G[1];
P[1][2] = xyz_B[1];
151 P[2][0] = xyz_R[2];
P[2][1] = xyz_G[2];
P[2][2] = xyz_B[2];
160 M_out[0][0] = k[0] * xyz_R[0]; M_out[0][1] = k[1] * xyz_G[0]; M_out[0][2] = k[2] * xyz_B[0];
161 M_out[1][0] = k[0] * xyz_R[1]; M_out[1][1] = k[1] * xyz_G[1]; M_out[1][2] = k[2] * xyz_B[1];
162 M_out[2][0] = k[0] * xyz_R[2]; M_out[2][1] = k[1] * xyz_G[2]; M_out[2][2] = k[2] * xyz_B[2];
191 constexpr float kPrimaryEps = 1e-6f;
192 auto close = [](
const float a[2],
const float b[2])
FL_NOEXCEPT {
193 const float dx = a[0] - b[0];
194 const float dy = a[1] - b[1];
195 return (dx * dx + dy * dy) < kPrimaryEps;
197 return close(p.input_xy_r, p.xy_r)
198 && close(p.input_xy_g, p.xy_g)
199 && close(p.input_xy_b, p.xy_b);
211 constexpr float kTopoEps = 1.0f / 65535.0f;
213 if (s_r > kTopoEps) ++n;
214 if (s_g > kTopoEps) ++n;
215 if (s_b > kTopoEps) ++n;
226inline void nnls3(
const float M[3][3],
const float b[3],
228 float t[3] = {0.0f, 0.0f, 0.0f};
229 constexpr float kStep = 0.01f;
230 constexpr int kIters = 500;
231 for (
int it = 0; it < kIters; ++it) {
233 r[0] = M[0][0]*
t[0] + M[0][1]*
t[1] + M[0][2]*
t[2] - b[0];
234 r[1] = M[1][0]*
t[0] + M[1][1]*
t[1] + M[1][2]*
t[2] - b[1];
235 r[2] = M[2][0]*
t[0] + M[2][1]*
t[1] + M[2][2]*
t[2] - b[2];
238 g[0] = M[0][0]*r[0] + M[1][0]*r[1] + M[2][0]*r[2];
239 g[1] = M[0][1]*r[0] + M[1][1]*r[1] + M[2][1]*r[2];
240 g[2] = M[0][2]*r[0] + M[1][2]*r[1] + M[2][2]*r[2];
241 for (
int j = 0; j < 3; ++j) {
242 float v =
t[j] - kStep * g[j];
243 t[j] = v > 0.0f ? v : 0.0f;
246 if (residual_out !=
nullptr) {
248 r[0] = M[0][0]*
t[0] + M[0][1]*
t[1] + M[0][2]*
t[2] - b[0];
249 r[1] = M[1][0]*
t[0] + M[1][1]*
t[1] + M[1][2]*
t[2] - b[1];
250 r[2] = M[2][0]*
t[0] + M[2][1]*
t[1] + M[2][2]*
t[2] - b[2];
251 *residual_out =
fl::sqrt(r[0]*r[0] + r[1]*r[1] + r[2]*r[2]);
253 t_out[0] =
t[0]; t_out[1] =
t[1]; t_out[2] =
t[2];
320 const float t2 =
t *
t;
321 const float t3 = t2 *
t;
322 out[0] = 2.0f * t3 - 3.0f * t2 + 1.0f;
323 out[1] = -2.0f * t3 + 3.0f * t2;
324 out[2] = t3 - 2.0f * t2 +
t;
346 const float scaled = v *
static_cast<float>(
kLutQ) + 0.5f;
347 if (scaled <= -32768.0f)
return -32768;
348 if (scaled >= 32767.0f)
return 32767;
349 return static_cast<i16
>(scaled);
356 if (cool_cct == warm_cct)
return 0.5f;
357 const float t = (
static_cast<float>(target_cct) - warm_cct)
358 / (
static_cast<float>(cool_cct) - warm_cct);
393 float s_g,
float s_b,
402 const float xy_t[2],
float Y_t,
429 float s_b,
float overdrive_ratio,
Functions for red, green, blue, white (RGBW) output.
bool solve_wx_lp_legacy(const ProfileCache &cache, float s_r, float s_g, float s_b, float out_rgbw[4]) FL_NOEXCEPT
constexpr int kLutStrideHermite
void xyY_to_XYZ(float x, float y, float Y, float out[3]) FL_NOEXCEPT
void cct_to_xy(int cct, float out[2]) FL_NOEXCEPT
i16 quantize_lut_cell(float v) FL_NOEXCEPT
LutTable build_lut(const ProfileCache &cache, int grid_n, LutInterp interp) FL_NOEXCEPT
bool build_source_matrix(const float xy_r[2], const float xy_g[2], const float xy_b[2], const float xy_w[2], float M_out[3][3]) FL_NOEXCEPT
bool solve_strict_subgamut_xy(const ProfileCache &cache, const float xy_t[2], float Y_t, float out_rgbw[4]) FL_NOEXCEPT
void matvec3(const float M[3][3], const float v[3], float out[3]) FL_NOEXCEPT
void solve_wx_overdrive(const ProfileCache &cache, float s_r, float s_g, float s_b, float overdrive_ratio, float out_rgbw[4]) FL_NOEXCEPT
constexpr float kDefaultOverdriveRatio
void build_profile_cache(const DiodeProfile *p, int cct_override, ProfileCache *cache) FL_NOEXCEPT
void lookup_lut(const LutTable &lut, const float xy_t[2], float Y_t, float out_rgbw[4]) FL_NOEXCEPT
void nnls3(const float M[3][3], const float b[3], float t_out[3], float *residual_out) FL_NOEXCEPT
float rgbcct_eta_for_cct(int target_cct, int warm_cct, int cool_cct) FL_NOEXCEPT
bool invert3x3(const float in[3][3], float out[3][3]) FL_NOEXCEPT
bool barycentric_xy(const float t[2], const float A[2], const float B[2], const float C[2], float bary[3]) FL_NOEXCEPT
u8 quantize_u8(float v) FL_NOEXCEPT
bool solve_strict_subgamut(const ProfileCache &cache, float s_r, float s_g, float s_b, float out_rgbw[4]) FL_NOEXCEPT
bool is_native_input_gamut(const DiodeProfile &p) FL_NOEXCEPT
void solve_rgbcct(const RgbcctProfile &profile, float s_r, float s_g, float s_b, float eta, float out[5]) FL_NOEXCEPT
constexpr int kLutStrideBilinear
int count_active_channels(float s_r, float s_g, float s_b) FL_NOEXCEPT
void hermite_basis(float t, float out[4]) FL_NOEXCEPT
fl::unique_ptr< i16[]> cells
const DiodeProfile * profile
double fabs(double value) FL_NOEXCEPT
FL_DISABLE_WARNING_PUSH unsigned char * B
constexpr enable_if< is_fixed_point< T >::value, T >::type sqrt(T x) FL_NOEXCEPT
FASTLED_FORCE_INLINE fl::u8 P(fl::u8 x)
constexpr enable_if< is_fixed_point< T >::value, T >::type clamp(T x, T lo, T hi) FL_NOEXCEPT
Base definition for an LED controller.