--- ray/src/common/spec_rgb.c 2023/11/21 01:30:20 2.29 +++ ray/src/common/spec_rgb.c 2024/08/14 20:05:23 2.34 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: spec_rgb.c,v 2.29 2023/11/21 01:30:20 greg Exp $"; +static const char RCSid[] = "$Id: spec_rgb.c,v 2.34 2024/08/14 20:05:23 greg Exp $"; #endif /* * Convert colors and spectral ranges. @@ -12,6 +12,7 @@ static const char RCSid[] = "$Id: spec_rgb.c,v 2.29 20 #include #include +#include #include "color.h" #define CEPS 1e-4 /* color epsilon */ @@ -270,13 +271,13 @@ int e COLOR ciecolor; spec_cie(ciecolor, s, e); - cie_rgb(col, ciecolor); + colortrans(col, xyz2rgbmat, ciecolor); } static double spec_dot( /* spectrum dot-product with cumulative observer */ - SCOLOR scol, + const SCOLOR scol, int ncs, const float wlpt[4], const unsigned short cumul[], @@ -311,7 +312,7 @@ spec_dot( /* spectrum dot-product with cumulative ob void scolor2cie( /* accurate conversion from spectrum to XYZ */ COLOR col, - SCOLOR scol, + const SCOLOR scol, int ncs, const float wlpt[4] ) @@ -329,7 +330,7 @@ scolor2cie( /* accurate conversion from spectrum to void scolor2rgb( /* accurate conversion from spectrum to RGB */ COLOR col, - SCOLOR scol, + const SCOLOR scol, int ncs, const float wlpt[4] ) @@ -345,40 +346,130 @@ scolor2rgb( /* accurate conversion from spectrum to } +void +scolor_out( /* prepare (spectral) color for output */ + COLORV *cout, + RGBPRIMS pr, + const SCOLOR cres +) +{ + static COLORMAT xyz2myp; + static RGBPRIMP lastp = NULL; + + if (!pr) { /* output is spectral */ + copyscolor(cout, cres); + } else if (pr == stdprims) { /* output is standard RGB */ + scolor_rgb(cout, cres); + } else if (pr == xyzprims) { /* output is XYZ */ + scolor_cie(cout, cres); + scalecolor(cout, WHTEFFICACY); + } else if (NCSAMP > 3) { /* spectral -> custom RGB */ + COLOR xyz; + if (lastp != pr) + compxyz2rgbWBmat(xyz2myp, lastp=pr); + scolor_cie(xyz, cres); + colortrans(cout, xyz2myp, xyz); + clipgamut(cout, xyz[CIEY], CGAMUT_LOWER, cblack, cwhite); + } else { /* else copy unknown RGB */ + copycolor(cout, cres); + } +} + + double -scolor_photopic( /* compute scotopic integral for spectral color */ - SCOLOR scol +scolor2photopic( /* compute scotopic integral for spectral color */ + const SCOLOR scol, + int ncs, + const float wlpt[4] ) { - if (NCSAMP == 3) + if (ncs == 3) return bright(scol); - return(spec_dot(scol, NCSAMP, WLPART, cie_y_cumul, CIE_Y_WLMIN, CIE_Y_WLMAX)); + return(spec_dot(scol, ncs, wlpt, cie_y_cumul, CIE_Y_WLMIN, CIE_Y_WLMAX)); } double +scolor2scotopic( /* compute Y channel for spectral color */ + const SCOLOR scol, + int ncs, + const float wlpt[4] +) +{ + return(spec_dot(scol, ncs, wlpt, scotopic_cumul, SCOTOPIC_WLMIN, SCOTOPIC_WLMAX)); +} + + +double +scolor2melanopic( /* compute melanopic integral for spectral color */ + const SCOLOR scol, + int ncs, + const float wlpt[4] +) +{ + return(spec_dot(scol, ncs, wlpt, melanopic_cumul, MELANOPIC_WLMIN, MELANOPIC_WLMAX)); +} + + +double +scolor_photopic( /* compute scotopic integral for spectral color */ + const SCOLOR scol +) +{ + return(scolor2photopic(scol, NCSAMP, WLPART)); +} + + +double scolor_scotopic( /* compute Y channel for spectral color */ - SCOLOR scol + const SCOLOR scol ) { - return(spec_dot(scol, NCSAMP, WLPART, scotopic_cumul, SCOTOPIC_WLMIN, SCOTOPIC_WLMAX)); + return(scolor2scotopic(scol, NCSAMP, WLPART)); } double scolor_melanopic( /* compute melanopic integral for spectral color */ - SCOLOR scol + const SCOLOR scol ) { - return(spec_dot(scol, NCSAMP, WLPART, melanopic_cumul, MELANOPIC_WLMIN, MELANOPIC_WLMAX)); + return(scolor2melanopic(scol, NCSAMP, WLPART)); } void +convertscolorcol( /* any uniform spectrum to working */ + SCOLOR rcol, + const COLORV src[], + int snc, + double swl0, + double swl1 +) +{ + if (NCSAMP > 3) { /* spectrum -> spectrum */ + convertscolor(rcol, NCSAMP, WLPART[0], WLPART[3], + src, snc, swl0, swl1); + } else if ((snc <= MAXCSAMP) & (swl0 > swl1)) { + float wlpt[4]; /* no intermediate conversion needed */ + wlpt[0] = swl0; wlpt[3] = swl1; + wlpt[1] = WLPART[1]; wlpt[2] = WLPART[2]; + scolor2rgb(rcol, (COLORV *)src, snc, wlpt); + } else { + SCOLOR dcol; /* else convert spectrum first */ + int dnc = snc*(WLPART[0] - WLPART[3])/fabs(swl0 - swl1) + .99; + if (dnc > MAXCSAMP) dnc = MAXCSAMP; + convertscolor(dcol, dnc, WLPART[0], WLPART[3], src, snc, swl0, swl1); + scolor2rgb(rcol, dcol, dnc, WLPART); + } +} + + +void cie_rgb( /* convert CIE color to standard RGB */ COLOR rgb, -COLOR xyz +const COLOR xyz ) { colortrans(rgb, xyz2rgbmat, xyz); @@ -391,8 +482,8 @@ clipgamut( /* clip to gamut cube */ COLOR col, double brt, int gamut, -COLOR lower, -COLOR upper +const COLOR lower, +const COLOR upper ) { int rflags = 0; @@ -437,8 +528,8 @@ COLOR upper void colortrans( /* convert c1 by mat and put into c2 */ COLOR c2, -COLORMAT mat, -COLOR c1 +const COLORMAT mat, +const COLOR c1 ) { COLOR cout; @@ -454,8 +545,8 @@ COLOR c1 void multcolormat( /* multiply m1 by m2 and put into m3 */ COLORMAT m3, /* m3 can be either m1 or m2 w/o harm */ -COLORMAT m2, -COLORMAT m1 +const COLORMAT m2, +const COLORMAT m1 ) { COLORMAT mt; @@ -647,8 +738,8 @@ RGBPRIMS pr2 int compxyzWBmat( /* CIE von Kries transform from wht1 to wht2 */ COLORMAT mat, -float wht1[2], -float wht2[2] +const float wht1[2], +const float wht2[2] ) { COLOR cw1, cw2;