#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; } }