Bind a five-emitter map from one effective RGB solve and two white columns, all in the same D65 working coordinates.
629 {
630 if (out == nullptr) {
631 return false;
632 }
635 return false;
636 }
637
638 i32 neutral_drives[3];
640 for (int i = 0; i < 3; ++i) {
641
642 if (neutral_drives[i] <= 0) {
643 return false;
644 }
645 }
646
647
648
649 i32 largest_neutral_drive = neutral_drives[0];
650 for (int i = 1; i < 3; ++i) {
651 if (neutral_drives[i] > largest_neutral_drive) {
652 largest_neutral_drive = neutral_drives[i];
653 }
654 }
656 static_cast<i64>(largest_neutral_drive);
657
658
659
660
661
662
663
664
665
668 }
669
670
671
672
673
674
675
676
677
678
679
681 for (int i = 0; i < 3; ++i) {
685 if (per_white1 > 0) {
686 numerator +=
static_cast<i64>(per_white1);
687 }
688 if (per_white2 > 0) {
689 numerator +=
static_cast<i64>(per_white2);
690 }
691 const i64 candidate =
692 (numerator << 16) /
static_cast<i64>(neutral_drives[i]);
693 if (candidate < optimistic) {
694 optimistic = candidate;
695 }
696 }
697
698
699
700
701
702 if (optimistic > reachable) {
704 i64 high = optimistic;
706 const i64 middle = (low + high) / 2;
707 const i32 trial_scale = static_cast<i32>(middle);
708 const i32 trial[3] = {
712 };
713 i32 trial_drives[5];
715 low = middle;
716 } else {
717 high = middle;
718 }
719 }
720 reachable = low;
721 }
722
723 const i32
scale =
static_cast<i32
>(reachable);
724 const i32 brightest_neutral[3] = {
728 };
729 i32 lab[3];
732 return true;
733}
fl::UISlider scale("Scale", 4,.1, 4,.1)
i32 scaleGamutQ16(i32 value, i32 factor) FL_NO_EXCEPT
Scale an s16.16 value by an s16.16 factor, rounding to nearest.
constexpr i32 kGamutFullDrive
Full drive, as an s16.16 raw value.
bool buildTwoWhiteAllocationFromSolveQ16(const EmitterSolveMatrixQ16 &solve, const i32(&white1_xyz)[3], const i32(&white2_xyz)[3], WhiteAllocationPolicy policy, TwoWhiteAllocationQ16 *out) FL_NO_EXCEPT
Bind two adapted white columns with an RGB solve in the same XYZ domain.
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 ...
constexpr i32 kOklabQ16MaxMagnitude
Largest magnitude either direction accepts, as an s16.16 raw value (64.0).
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.
constexpr enable_if< is_fixed_point< T >::value, T >::type step(T edge, T x) FL_NO_EXCEPT
void solveRgbDrivesQ16(const EmitterSolveMatrixQ16 &matrix, const i32(&xyz)[3], i32(&drives)[3]) FL_NO_EXCEPT
One pixel: XYZ in s16.16 to three emitter drives in s16.16.
i32 per_white2[3]
M^-1 . w2: the RGB drives one unit of the second white replaces.
TwoWhiteAllocationQ16 allocation
i32 max_neutral_lightness
OKLab lightness of the brightest D65 neutral this device can reach.
EmitterSolveMatrixQ16 rgb_solve
Inverse RGB emitter matrix.