74 lines
1.9 KiB
C
74 lines
1.9 KiB
C
#include "light/nl_color.h"
|
|
|
|
uint16_t nl_cie_level(uint16_t bri)
|
|
{
|
|
float lightness, y;
|
|
uint32_t v;
|
|
|
|
if (bri == 0)
|
|
return 0;
|
|
if (bri >= NL_BRI_SCALE)
|
|
return 65535;
|
|
lightness = (float)bri / 100.0f; /* 0..100 */
|
|
if (lightness <= 8.0f) {
|
|
y = lightness / 903.3f;
|
|
} else {
|
|
float t = (lightness + 16.0f) / 116.0f;
|
|
y = t * t * t;
|
|
}
|
|
v = (uint32_t)(y * 65535.0f + 0.5f);
|
|
return (uint16_t)(v == 0 ? 1 : (v > 65535 ? 65535 : v));
|
|
}
|
|
|
|
uint16_t nl_ct_cw_fraction(uint16_t ct, uint16_t ct_min, uint16_t ct_max)
|
|
{
|
|
uint32_t m, mw, mc;
|
|
|
|
if (ct <= ct_min)
|
|
return 0;
|
|
if (ct >= ct_max)
|
|
return 65535;
|
|
m = 1000000u / ct;
|
|
mw = 1000000u / ct_min;
|
|
mc = 1000000u / ct_max;
|
|
return (uint16_t)(((mw - m) * 65535u) / (mw - mc));
|
|
}
|
|
|
|
static uint8_t to8(uint32_t lin)
|
|
{
|
|
return (uint8_t)((lin * 255u + 32767u) / 65535u);
|
|
}
|
|
|
|
void nl_visual_to_channels(const nl_visual_t *v, uint16_t ct_min, uint16_t ct_max, uint8_t out[NL_CH_COUNT])
|
|
{
|
|
uint32_t level = nl_cie_level(v->bri);
|
|
|
|
for (int i = 0; i < NL_CH_COUNT; i++)
|
|
out[i] = 0;
|
|
if (level == 0)
|
|
return;
|
|
|
|
if (v->mode == NL_MODE_COLOR) {
|
|
uint32_t lin[3];
|
|
int maxi = 0;
|
|
lin[0] = level * v->r / 255u;
|
|
lin[1] = level * v->g / 255u;
|
|
lin[2] = level * v->b / 255u;
|
|
for (int i = 0; i < 3; i++) {
|
|
out[NL_CH_R + i] = to8(lin[i]);
|
|
if (lin[i] > lin[maxi])
|
|
maxi = i;
|
|
}
|
|
/* keep the lowest brightness step visible */
|
|
if (!out[NL_CH_R] && !out[NL_CH_G] && !out[NL_CH_B] && lin[maxi] > 0)
|
|
out[NL_CH_R + maxi] = 1;
|
|
} else {
|
|
uint32_t cw = level * nl_ct_cw_fraction(v->ct, ct_min, ct_max) / 65535u;
|
|
uint32_t ww = level - cw;
|
|
out[NL_CH_CW] = to8(cw);
|
|
out[NL_CH_WW] = to8(ww);
|
|
if (!out[NL_CH_CW] && !out[NL_CH_WW])
|
|
out[cw >= ww ? NL_CH_CW : NL_CH_WW] = 1;
|
|
}
|
|
}
|