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

◆ mapAndAllocateRgbwwQ16()

void fl::mapAndAllocateRgbwwQ16 ( const GamutMapRgbwwQ16 & map,
const i32(&) xyz[3],
i32(&) drives[5] )

One pixel: XYZ in s16.16 to five in-gamut drives – red, green, blue, white1, white2.

Same shape as the other two paths: one forward OKLab transform, one lightness comparison, then eight halvings, with every feasibility test going through the two-white allocation so the hull is the device's real one.

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

747 {
748 if (allocateTwoWhiteDrivesQ16(map.allocation, xyz, drives)) {
749 // Already inside the device's hull, which with two whites is larger
750 // again than the one-white one.
751 return;
752 }
753
754 i32 lab[3];
755 xyzToOklabQ16(xyz, lab);
756 i32 lightness = lab[0];
757 if (lightness < 0) {
758 lightness = 0;
759 }
760
761 // And again for two whites (#4245).
762 if (lightness > map.max_neutral_lightness) {
763 i32 low_edge = 0;
764 i32 high_edge = 0;
765 if (feasibleChromaInterval(lab, lightness, RgbwwFeasible{map.allocation},
766 &low_edge, &high_edge)) {
767 i32 candidate_xyz[3];
768 chromaCandidateXyz(lab, lightness, clampChromaFactor(low_edge, high_edge),
769 candidate_xyz);
770 if (allocateTwoWhiteDrivesQ16(map.allocation, candidate_xyz, drives)) {
771 return;
772 }
773 }
774
775 // Same walk-down as the RGB path: dropping straight to the cap when
776 // the probes stop landing is a step, not a mapping.
777 const i32 reachable = highestReachableLightness(
778 lab, map.max_neutral_lightness, lightness,
779 RgbwwFeasible{map.allocation});
780 i32 edge_low = 0;
781 i32 edge_high = 0;
782 if (reachable > map.max_neutral_lightness &&
783 feasibleChromaInterval(lab, reachable, RgbwwFeasible{map.allocation},
784 &edge_low, &edge_high)) {
785 i32 edge_xyz[3];
786 chromaCandidateXyz(lab, reachable,
787 clampChromaFactor(edge_low, edge_high), edge_xyz);
788 if (allocateTwoWhiteDrivesQ16(map.allocation, edge_xyz, drives)) {
789 return;
790 }
791 }
792 lightness = map.max_neutral_lightness;
793 }
794
795 const i32 factor =
796 largestFeasibleChroma(lab, lightness, RgbwwFeasible{map.allocation});
797 i32 mapped_xyz[3];
798 chromaCandidateXyz(lab, lightness, factor, mapped_xyz);
799 if (allocateTwoWhiteDrivesQ16(map.allocation, mapped_xyz, drives)) {
800 return;
801 }
802 // Same last resort as the other paths: the accepted candidate can fall a
803 // few ULP outside on the final re-solve, and the neutral at this
804 // lightness is guaranteed reachable by the bound above.
805 const i32 neutral_lab[3] = {lightness, 0, 0};
806 i32 neutral_xyz[3];
807 oklabToXyzQ16(neutral_lab, neutral_xyz);
808 if (!allocateTwoWhiteDrivesQ16(map.allocation, neutral_xyz, drives)) {
809 for (int i = 0; i < 5; ++i) {
810 drives[i] = 0;
811 }
812 }
813}
i32 clampChromaFactor(i32 low, i32 high) FL_NO_EXCEPT
The target's chroma clamped into [low, high], in factor space.
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.
i32 largestFeasibleChroma(const i32(&lab)[3], i32 lightness, Feasible feasible) FL_NO_EXCEPT
Largest chroma factor the hull accepts, by a fixed count of halvings.
i32 highestReachableLightness(const i32(&lab)[3], i32 cap, i32 requested, Feasible feasible) FL_NO_EXCEPT
The highest lightness at or below requested whose feasible chroma interval the probe scan can still f...
bool feasibleChromaInterval(const i32(&lab)[3], i32 lightness, Feasible feasible, i32 *out_low, i32 *out_high) FL_NO_EXCEPT
The feasible chroma interval at the target's own lightness, as factors of the target's chroma.
MapRedBlackTree< Key, T, Compare, fl::allocator_slab< char > > map
Definition map.h:283
bool allocateTwoWhiteDrivesQ16(const TwoWhiteAllocationQ16 &allocation, const i32(&xyz)[3], i32(&drives)[5]) FL_NO_EXCEPT
One pixel: XYZ in s16.16 to five drives – red, green, blue, white1, white2 – at whichever end of the ...
void oklabToXyzQ16(const i32(&lab)[3], i32(&out_xyz)[3]) FL_NO_EXCEPT
OKLab (s16.16) -> XYZ (s16.16).
void xyzToOklabQ16(const i32(&xyz)[3], i32(&out_lab)[3]) FL_NO_EXCEPT
XYZ (s16.16, D65-relative) -> OKLab (s16.16), L then a then b.

References allocateTwoWhiteDrivesQ16(), FL_NO_EXCEPT, oklabToXyzQ16(), and xyzToOklabQ16().

Referenced by processPixelWideLinearQ16().

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