FastLED 3.10.6
Loading...
Searching...
No Matches
gamut_map.h File Reference
+ Include dependency graph for gamut_map.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  fl::GamutMapQ16
 Everything the per-pixel mapper needs, derived once when a profile binds. More...
 
struct  fl::GamutMapRgbwQ16
 The same mapper for a device with a white emitter. More...
 
struct  fl::GamutMapRgbwwQ16
 The same mapper for a device with two white emitters. More...
 

Namespaces

namespace  fl
 Base definition for an LED controller.
 

Functions

bool fl::buildGamutMapFromSolveQ16 (const EmitterSolveMatrixQ16 &solve, GamutMapQ16 *out) FL_NO_EXCEPT
 Build a mapper from a bind-time solve already transformed into D65 working coordinates.
 
bool fl::buildGamutMapQ16 (const colorimetric_response::EmitterProfile &profile, GamutMapQ16 *out) FL_NO_EXCEPT
 Derive the mapper for a three-emitter profile.
 
bool fl::buildGamutMapRgbwFromSolveQ16 (const colorimetric_response::EmitterProfile &profile, const EmitterSolveMatrixQ16 &solve, const i32(&white_xyz)[3], WhiteAllocationPolicy policy, GamutMapRgbwQ16 *out) FL_NO_EXCEPT
 Bind a four-emitter map from an effective RGB solve and a white column already adapted into the same D65 working coordinates.
 
bool fl::buildGamutMapRgbwQ16 (const colorimetric_response::EmitterProfile &profile, const i32(&white_xyz)[3], WhiteAllocationPolicy policy, GamutMapRgbwQ16 *out) FL_NO_EXCEPT
 Derive the mapper for a three-primary profile plus one white emitter.
 
bool fl::buildGamutMapRgbwwFromSolveQ16 (const colorimetric_response::EmitterProfile &profile, const EmitterSolveMatrixQ16 &solve, const i32(&white1_xyz)[3], const i32(&white2_xyz)[3], WhiteAllocationPolicy policy, GamutMapRgbwwQ16 *out) FL_NO_EXCEPT
 Bind a five-emitter map from one effective RGB solve and two white columns, all in the same D65 working coordinates.
 
bool fl::buildGamutMapRgbwwQ16 (const colorimetric_response::EmitterProfile &profile, const i32(&white1_xyz)[3], const i32(&white2_xyz)[3], WhiteAllocationPolicy policy, GamutMapRgbwwQ16 *out) FL_NO_EXCEPT
 Derive the mapper for a three-primary profile plus two white emitters.
 
void fl::mapAndAllocateRgbwQ16 (const GamutMapRgbwQ16 &map, const i32(&xyz)[3], i32(&drives)[4]) FL_NO_EXCEPT
 One pixel: XYZ in s16.16 to four in-gamut drives, red, green, blue, white.
 
void fl::mapAndAllocateRgbwwQ16 (const GamutMapRgbwwQ16 &map, const i32(&xyz)[3], i32(&drives)[5]) FL_NO_EXCEPT
 One pixel: XYZ in s16.16 to five in-gamut drives – red, green, blue, white1, white2.
 
void fl::mapAndSolveDrivesQ16 (const GamutMapQ16 &map, const i32(&xyz)[3], i32(&drives)[3]) FL_NO_EXCEPT
 One pixel: XYZ in s16.16 to in-gamut emitter drives in s16.16.
 

Variables

constexpr int fl::kGamutMapHalvings = 8
 Number of chroma halvings the mapper runs, fixed at compile time.
 

Class Documentation

◆ fl::GamutMapQ16

struct fl::GamutMapQ16
+ Collaboration diagram for fl::GamutMapQ16:
Class Members
i32 max_neutral_lightness OKLab lightness of the brightest D65 neutral this device can reach.

Chroma compression cannot rescue a target that is too bright: at zero chroma the point is still outside the hull, so a chroma-only bisection converges on an infeasible answer. The reference clamps lightness into the attainable range first, and this is that bound.

It is a device constant rather than a per-pixel search. Along the D65 neutral ray the drives are s * (M^-1 . D65), so the largest feasible s is 1 / max(M^-1 . D65) and the bound follows – exactly, with no iteration. Measured against a 40-step bisection over targets from 1.05x to 50x device white, the two agree to 0 ULP.

EmitterSolveMatrixQ16 solve

◆ fl::GamutMapRgbwQ16

struct fl::GamutMapRgbwQ16
+ Collaboration diagram for fl::GamutMapRgbwQ16:
Class Members
WhiteAllocationQ16 allocation
i32 max_neutral_lightness OKLab lightness of the brightest D65 neutral this device can reach.

Larger than the three-emitter bound by whatever the white emitter adds – 2.398 against 1.398 for a white at D65 and unit luminance, exactly the one unit it contributes.

Derived at bind time by bisecting between two bounds: the three-emitter one, always reachable with the white emitter off, and a relaxation of the problem that ignores the lower limits on the RGB drives. The relaxation is an upper bound but not generally attainable – full white can push a channel negative – so it is tested rather than trusted. The bisection runs once per profile, never per pixel.

◆ fl::GamutMapRgbwwQ16

struct fl::GamutMapRgbwwQ16
+ Collaboration diagram for fl::GamutMapRgbwwQ16:
Class Members
TwoWhiteAllocationQ16 allocation
i32 max_neutral_lightness OKLab lightness of the brightest D65 neutral this device can reach.

Derived the same way as the one-white bound and for the same reason: the relaxation that ignores the lower limits on the RGB drives is an upper bound but not attainable, so it is bisected against the always-reachable three-emitter bound rather than trusted. Once per profile, never per pixel.