Standard CIE primary-matrix construction (#2705). Given source primary chromaticities xy_r/g/b and a source white chromaticity xy_w, build the 3x3 matrix M such that M·[1,1,1]^T = xyY_to_XYZ(xy_w, 1.0). Columns are per-channel scaled XYZ vectors of the primaries at Y=1, with scaling chosen so the (1,1,1) input lands at source white in XYZ. This is the classic linear-sRGB -> XYZ derivation generali
| 137 | // classic linear-sRGB -> XYZ derivation generalized to arbitrary primaries. |
| 138 | // Returns false if the primary matrix is singular (collinear chromaticities). |
| 139 | inline bool build_source_matrix(const float xy_r[2], const float xy_g[2], |
| 140 | const float xy_b[2], const float xy_w[2], |
| 141 | float M_out[3][3]) FL_NOEXCEPT { |
| 142 | float xyz_R[3], xyz_G[3], xyz_B[3], xyz_W[3]; |
| 143 | xyY_to_XYZ(xy_r[0], xy_r[1], 1.0f, xyz_R); |
| 144 | xyY_to_XYZ(xy_g[0], xy_g[1], 1.0f, xyz_G); |
| 145 | xyY_to_XYZ(xy_b[0], xy_b[1], 1.0f, xyz_B); |
| 146 | xyY_to_XYZ(xy_w[0], xy_w[1], 1.0f, xyz_W); |
| 147 | |
| 148 | float P[3][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]; |
| 152 | |
| 153 | float P_inv[3][3]; |
| 154 | if (!invert3x3(P, P_inv)) { |
| 155 | return false; |
| 156 | } |
| 157 | float k[3]; |
| 158 | matvec3(P_inv, xyz_W, k); |
| 159 | |
| 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]; |
| 163 | return true; |
| 164 | } |
| 165 | |
| 166 | // Native-gamut detection (#2748). Returns true when the source primaries |
| 167 | // of `p` (input_xy_r/g/b) match the LED's measured primaries (xy_r/g/b) |
no test coverage detected