FastLED 3.10.6
Loading...
Searching...
No Matches

◆ buildBradfordMatrixQ16()

bool fl::buildBradfordMatrixQ16 ( Chromaticity source_white,
Chromaticity destination_white,
AdaptationMatrixQ16 * out )

Build the Bradford transform from source_white to destination_white.

False if either white has a zero cone response, which no real white does but a corrupt profile might.

Definition at line 83 of file chromatic_adaptation.cpp.hpp.

85 {
86 if (out == nullptr) {
87 return false;
88 }
89 // In s16.16 throughout (FastLED#4458). The same construction as the
90 // float build it replaces: both whites to XYZ at Y = 1, into cone space,
91 // the per-cone ratio as a diagonal, and B^-1 * diag * B collapsed once.
92 i32 source_xy[2];
93 i32 destination_xy[2];
94 if (!adaptationWhiteQ16(source_white, source_xy) ||
95 !adaptationWhiteQ16(destination_white, destination_xy)) {
96 return false;
97 }
98 i64 source_xyz[3];
99 i64 destination_xyz[3];
100 if (!detail::xyzColumnQ16(source_xy, kAdaptationQ16One, source_xyz) ||
101 !detail::xyzColumnQ16(destination_xy, kAdaptationQ16One, destination_xyz)) {
102 return false;
103 }
104 const i32 source_v[3] = {static_cast<i32>(source_xyz[0]), static_cast<i32>(source_xyz[1]),
105 static_cast<i32>(source_xyz[2])};
106 const i32 destination_v[3] = {static_cast<i32>(destination_xyz[0]),
107 static_cast<i32>(destination_xyz[1]),
108 static_cast<i32>(destination_xyz[2])};
109 i64 scale[3];
110 for (int i = 0; i < 3; ++i) {
111 const i32 source_cone = detail::dotRowQ16(detail::kBradfordQ16[i], source_v);
112 const i32 destination_cone =
113 detail::dotRowQ16(detail::kBradfordQ16[i], destination_v);
114 // A zero cone response would divide by zero. No physical white does
115 // this; a corrupt profile can.
116 if (source_cone == 0) {
117 return false;
118 }
120 static_cast<i64>(destination_cone) * kAdaptationQ16One, source_cone);
121 }
122 for (int row = 0; row < 3; ++row) {
123 for (int col = 0; col < 3; ++col) {
124 // sum_k Binv[row][k] * scale[k] * B[k][col]: each term is Q48,
125 // brought back to Q16 once at the end rather than per product.
126 i64 sum_q32 = 0;
127 for (int k = 0; k < 3; ++k) {
128 const i64 inv_scale_q16 = detail::roundedDivideQ16(
129 static_cast<i64>(detail::kBradfordInverseQ16[row][k]) * scale[k],
130 kAdaptationQ16One);
131 sum_q32 += inv_scale_q16 * detail::kBradfordQ16[k][col];
132 }
133 const i64 value = detail::roundedDivideQ16(sum_q32, kAdaptationQ16One);
134 if (value > 2147483647LL || value < -2147483648LL) {
135 return false;
136 }
137 out->m[row][col] = static_cast<i32>(value);
138 }
139 }
140 return true;
141}
fl::UISlider scale("Scale", 4,.1, 4,.1)
i32 dotRowQ16(const i32(&row)[3], const i32(&v)[3]) FL_NO_EXCEPT
One s16.16 matrix row against a vector, rounded and saturated.
i64 roundedDivideQ16(i64 numerator, i64 denominator) FL_NO_EXCEPT
The s16.16 building blocks the bind-time builders share.
const i32 kBradfordInverseQ16[3][3]
const i32 kBradfordQ16[3][3]
The two matrices above in s16.16, rounded from the float32 values, so the bind-time build needs no fl...
bool xyzColumnQ16(const i32(&xy)[2], i32 luminance, i64(&column)[3]) FL_NO_EXCEPT
XYZ of chromaticity xy at luminance luminance, all s16.16; false for a non-positive or out-of-simplex...
constexpr int type_rank< T >::value
fl::i64 i64
Definition stdint.h:221

References fl::detail::dotRowQ16(), FL_NO_EXCEPT, fl::detail::kBradfordInverseQ16, fl::detail::kBradfordQ16, fl::detail::roundedDivideQ16(), scale, type_rank< T >::value, and fl::detail::xyzColumnQ16().

Referenced by buildStreamingPipelineQ16(), and fl::anonymous_namespace{pipeline.cpp.hpp}::buildWidePipelineQ16().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: