Bind a four-emitter map from an effective RGB solve and a white column already adapted into the same D65 working coordinates.
437 {
438 if (out == nullptr) {
439 return false;
440 }
443 return false;
444 }
445
446 i32 neutral_drives[3];
448 for (int i = 0; i < 3; ++i) {
449
450 if (neutral_drives[i] <= 0) {
451 return false;
452 }
453 }
454
455
456
457
458 i32 largest_neutral_drive = neutral_drives[0];
459 for (int i = 1; i < 3; ++i) {
460 if (neutral_drives[i] > largest_neutral_drive) {
461 largest_neutral_drive = neutral_drives[i];
462 }
463 }
465 static_cast<i64>(largest_neutral_drive);
466
467
468
469
470
471
472
473
474
477 }
478
479
480
481
482
483
484
486 for (int i = 0; i < 3; ++i) {
489 (per_white > 0 ?
static_cast<i64>(per_white) : 0);
490 const i64 candidate =
491 (numerator << 16) /
static_cast<i64>(neutral_drives[i]);
492 if (candidate < optimistic) {
493 optimistic = candidate;
494 }
495 }
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510 if (optimistic > reachable) {
512 i64 high = optimistic;
514 const i64 middle = (low + high) / 2;
515 const i32 trial_scale = static_cast<i32>(middle);
516 const i32 trial[3] = {
520 };
521 i32 trial_drives[4];
523 low = middle;
524 } else {
525 high = middle;
526 }
527 }
528 reachable = low;
529 }
530
531 const i32
scale =
static_cast<i32
>(reachable);
532 const i32 brightest_neutral[3] = {
536 };
537 i32 lab[3];
540 return true;
541}
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.
constexpr i32 kOklabQ16MaxMagnitude
Largest magnitude either direction accepts, as an s16.16 raw value (64.0).
bool allocateEmitterDrivesQ16(const WhiteAllocationQ16 &allocation, const i32(&xyz)[3], i32(&drives)[4]) FL_NO_EXCEPT
One pixel: XYZ in s16.16 to four drives, in the order red, green, blue, white, at whichever end of th...
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
bool buildWhiteAllocationFromSolveQ16(const colorimetric_response::EmitterProfile &profile, const EmitterSolveMatrixQ16 &solve, const i32(&white_xyz)[3], WhiteAllocationPolicy policy, WhiteAllocationQ16 *out) FL_NO_EXCEPT
Bind from an RGB solve already adapted to the D65 working domain.
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.
WhiteAllocationQ16 allocation
i32 max_neutral_lightness
OKLab lightness of the brightest D65 neutral this device can reach.
EmitterSolveMatrixQ16 rgb_solve
Inverse RGB emitter matrix.