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

◆ feasibleChromaInterval()

template<typename Feasible>
bool fl::anonymous_namespace{gamut_map.cpp.hpp}::feasibleChromaInterval ( const i32(&) lab[3],
i32 lightness,
Feasible feasible,
i32 * out_low,
i32 * out_high )

The feasible chroma interval at the target's own lightness, as factors of the target's chroma.

Above the brightest neutral the interval is still one run – that much is measured, on this device and on the wide ones – but it no longer contains zero (#4245). largestFeasibleChroma cannot find it: its bracket assumes a feasible low end, and starting infeasible it walks down to zero, which is the clamp this exists to avoid.

So the seed comes first, by a linear scan, and only then are the two edges bisected. Returns false when no probe lands inside, which is the caller's signal to keep the shipped clamp-then-bisect path – the reason this is never worse than what it replaces.

Definition at line 187 of file gamut_map.cpp.hpp.

189 {
190 i32 seed = 0;
191 bool found = false;
192 for (int probe = 1; probe <= kGamutMapProbes; ++probe) {
193 const i32 factor = static_cast<i32>(
194 (static_cast<i64>(kGamutProbeCeilingQ16) * probe) / kGamutMapProbes);
195 i32 candidate_xyz[3];
196 chromaCandidateXyz(lab, lightness, factor, candidate_xyz);
197 if (feasible(candidate_xyz)) {
198 seed = factor;
199 found = true;
200 break;
201 }
202 }
203 if (!found) {
204 return false;
205 }
206
207 // Lower edge: the smallest feasible factor. `high` is feasible throughout,
208 // `low` is not, which is the mirror of the usual invariant.
209 i32 low = 0;
210 i32 high = seed;
211 for (int step = 0; step < kGamutMapHalvings; ++step) {
212 const i32 factor = low + ((high - low) >> 1);
213 i32 candidate_xyz[3];
214 chromaCandidateXyz(lab, lightness, factor, candidate_xyz);
215 if (feasible(candidate_xyz)) {
216 high = factor;
217 } else {
218 low = factor;
219 }
220 }
221 *out_low = high;
222
223 // Upper edge: the largest feasible factor, the usual invariant again.
224 low = seed;
226 for (int step = 0; step < kGamutMapHalvings; ++step) {
227 const i32 factor = low + ((high - low) >> 1);
228 i32 candidate_xyz[3];
229 chromaCandidateXyz(lab, lightness, factor, candidate_xyz);
230 if (feasible(candidate_xyz)) {
231 low = factor;
232 } else {
233 high = factor;
234 }
235 }
236 *out_high = low;
237 return true;
238}
constexpr int kGamutMapProbes
Probes used to find a seed inside the feasible chroma interval when the target is brighter than the d...
void chromaCandidateXyz(const i32(&lab)[3], i32 lightness, i32 factor, i32(&out_xyz)[3]) FL_NO_EXCEPT
XYZ of the candidate at factor of the target's chroma.
constexpr i32 kGamutProbeCeilingQ16
How far above the target's own chroma the probes reach, in Q16.
constexpr int kGamutMapHalvings
Number of chroma halvings the mapper runs, fixed at compile time.
Definition gamut_map.h:40
constexpr enable_if< is_fixed_point< T >::value, T >::type step(T edge, T x) FL_NO_EXCEPT
fl::i64 i64
Definition stdint.h:221

References chromaCandidateXyz(), feasibleChromaInterval(), fl::FL_NO_EXCEPT, fl::kGamutMapHalvings, kGamutMapProbes, kGamutProbeCeilingQ16, and fl::step().

Referenced by feasibleChromaInterval(), and highestReachableLightness().

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