ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/spec_rgb.c
(Generate patch)

Comparing ray/src/common/spec_rgb.c (file contents):
Revision 2.20 by greg, Mon Jan 4 19:40:14 2010 UTC vs.
Revision 2.35 by greg, Thu Aug 22 04:27:53 2024 UTC

# Line 12 | Line 12 | static const char      RCSid[] = "$Id$";
12  
13   #include <stdio.h>
14   #include <string.h>
15 + #include <math.h>
16   #include "color.h"
17  
18   #define CEPS    1e-4                    /* color epsilon */
19  
20 < #define CEQ(v1,v2)      ((v1) <= (v2)+CEPS && (v2) <= (v1)+CEPS)
20 > #define CEQ(v1,v2)      (((v1) <= (v2)+CEPS) & ((v2) <= (v1)+CEPS))
21  
22 < #define XYEQ(c1,c2)     (CEQ((c1)[CIEX],(c2)[CIEX]) && CEQ((c1)[CIEY],(c2)[CIEY]))
22 > #define XYEQ(c1,c2)     (CEQ((c1)[CIEX],(c2)[CIEX]) & CEQ((c1)[CIEY],(c2)[CIEY]))
23  
24  
25   RGBPRIMS  stdprims = STDPRIMS;  /* standard primary chromaticities */
26 + RGBPRIMS  xyzprims = {1,0, 0,1, 0,0, 1.f/3.f,1.f/3.f};
27  
28 < COLOR  cblack = BLKCOLOR;               /* global black color */
29 < COLOR  cwhite = WHTCOLOR;               /* global white color */
28 > const COLOR  cblack = BLKCOLOR;         /* global black color */
29 > const COLOR  cwhite = WHTCOLOR;         /* global white color */
30 > const SCOLOR scblack = {0};             /* global black spectrum */
31  
32   float  xyneu[2] = {1./3., 1./3.};       /* neutral xy chromaticities */
33  
34   /*
35 < *      The following table contains the CIE tristimulus integrals
36 < *  for X, Y, and Z.  The table is cumulative, so that
37 < *  each color coordinate integrates to 1.
35 > *      The tables below encode the CIE 1931 2° standard observer
36 > * functions for X, Y, and Z.  These tables are cumulative, as are
37 > * ones that follow.
38   */
39  
40 < #define  STARTWL        380             /* starting wavelength (nanometers) */
41 < #define  INCWL          10              /* wavelength increment */
39 < #define  NINC           40              /* # of values */
40 > #define CIE_X_WLMIN     362
41 > #define CIE_X_WLMAX     774
42  
43 < static BYTE  chroma[3][NINC] = {
44 <        {                                                       /* X */
45 <                0,   0,   0,   2,   6,   13,  22,  30,  36,  41,
46 <                42,  43,  43,  44,  46,  52,  60,  71,  87,  106,
47 <                128, 153, 178, 200, 219, 233, 243, 249, 252, 254,
48 <                255, 255, 255, 255, 255, 255, 255, 255, 255, 255
49 <        }, {                                                    /* Y */
50 <                0,   0,   0,   0,   0,   1,   2,   4,   7,   11,
51 <                17,  24,  34,  48,  64,  84,  105, 127, 148, 169,
52 <                188, 205, 220, 232, 240, 246, 250, 253, 254, 255,
53 <                255, 255, 255, 255, 255, 255, 255, 255, 255, 255
54 <        }, {                                                    /* Z */
55 <                0,   0,   2,   10,  32,  66,  118, 153, 191, 220,
56 <                237, 246, 251, 253, 254, 255, 255, 255, 255, 255,
57 <                255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
58 <                255, 255, 255, 255, 255, 255, 255, 255, 255, 255
59 <        }
43 > static const unsigned short     cie_x_cumul[CIE_X_WLMAX-CIE_X_WLMIN+1] = {
44 > 0,1,1,1,1,1,1,2,2,2,3,3,3,4,5,5,6,7,8,9,10,11,12,14,16,18,20,23,26,29,
45 > 33,37,41,47,53,60,68,77,86,97,108,121,135,151,170,190,214,241,271,304,
46 > 342,385,432,486,545,612,686,768,860,961,1073,1195,1326,1467,1618,
47 > 1776,1943,2117,2298,2485,2677,2875,3076,3281,3489,3700,3912,4125,4340,4555,
48 > 4769,4983,5197,5409,5620,5830,6038,6244,6448,6651,6851,7049,7245,7437,
49 > 7627,7813,7995,8173,8347,8517,8682,8842,8996,9143,9284,9418,9545,9665,
50 > 9778,9884,9984,10077,10164,10245,10321,10390,10454,10513,10566,10615,
51 > 10659,10698,10734,10766,10794,10819,10842,10861,10879,10893,10906,10917,
52 > 10926,10933,10939,10944,10948,10951,10953,10955,10957,10958,10960,10961,
53 > 10964,10967,10971,10977,10984,10994,11006,11020,11038,11060,11085,11114,
54 > 11148,11187,11231,11280,11335,11396,11464,11537,11618,11705,11799,11901,
55 > 12010,12126,12249,12380,12518,12664,12818,12980,13150,13328,13515,13709,
56 > 13913,14124,14345,14574,14813,15060,15317,15582,15858,16142,16437,16741,
57 > 17055,17379,17713,18057,18412,18776,19151,19536,19931,20337,20753,21180,
58 > 21616,22063,22520,22988,23465,23953,24450,24957,25474,26000,26535,27080,
59 > 27633,28195,28765,29343,29929,30522,31122,31729,32342,32961,33585,34215,
60 > 34849,35487,36129,36775,37423,38073,38724,39375,40027,40679,41329,41978,
61 > 42625,43270,43911,44548,45181,45808,46429,47044,47652,48253,48845,49430,
62 > 50005,50571,51128,51674,52209,52733,53245,53745,54232,54706,55167,55614,
63 > 56048,56468,56876,57269,57651,58019,58376,58720,59052,59373,59681,59979,
64 > 60265,60539,60803,61056,61298,61529,61750,61962,62163,62355,62538,62712,
65 > 62877,63034,63183,63325,63459,63586,63706,63820,63927,64028,64123,64213,
66 > 64297,64376,64451,64520,64586,64647,64704,64758,64808,64855,64899,64941,
67 > 64980,65016,65051,65083,65114,65143,65169,65194,65218,65240,65260,65278,
68 > 65296,65312,65327,65341,65354,65366,65377,65387,65397,65406,65415,65423,
69 > 65430,65437,65444,65450,65455,65461,65466,65470,65475,65479,65483,65486,
70 > 65489,65493,65495,65498,65501,65503,65505,65507,65509,65511,65513,65514,
71 > 65516,65517,65518,65519,65520,65521,65522,65523,65524,65525,65526,65526,
72 > 65527,65527,65528,65528,65529,65529,65530,65530,65530,65531,65531,65531,
73 > 65532,65532,65532,65532,65532,65533,65533,65533,65533,65533,65533,65533,
74 > 65533,65534,65534,65534,65534,65534,65534,65534,65534,65534,65534,65534,
75 > 65534,65534,65534,65534,65535
76   };
77  
78 + #define CIE_Y_WLMIN     386
79 + #define CIE_Y_WLMAX     760
80 +
81 + static const unsigned short     cie_y_cumul[CIE_Y_WLMAX-CIE_Y_WLMIN+1] = {
82 + 0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,4,4,5,5,6,7,8,8,10,11,12,14,
83 + 15,17,19,22,25,28,31,35,40,45,50,56,63,70,78,86,95,105,115,126,
84 + 138,150,164,178,193,208,225,242,260,280,300,321,343,367,391,
85 + 417,443,472,501,532,564,598,633,670,708,748,790,833,879,926,
86 + 975,1027,1080,1136,1194,1255,1318,1384,1453,1525,1601,1679,1761,
87 + 1846,1935,2027,2123,2223,2327,2435,2548,2665,2787,2915,3048,3187,
88 + 3332,3484,3643,3808,3981,4162,4352,4550,4757,4975,5203,5442,5691,
89 + 5952,6225,6509,6805,7114,7435,7769,8116,8476,8849,9235,9634,10045,
90 + 10469,10904,11351,11808,12275,12752,13239,13734,14239,14752,15273,
91 + 15801,16337,16880,17429,17984,18546,19112,19684,20260,20841,21426,
92 + 22015,22608,23203,23802,24403,25007,25612,26220,26828,27439,28050,
93 + 28662,29275,29888,30501,31114,31727,32340,32951,33561,34170,34777,
94 + 35382,35985,36585,37182,37777,38368,38955,39539,40119,40695,41266,
95 + 41832,42393,42950,43501,44046,44586,45119,45646,46167,46682,47189,
96 + 47690,48183,48670,49149,49621,50085,50542,50991,51432,51866,52293,
97 + 52711,53122,53524,53919,54306,54685,55057,55420,55775,56123,56463,
98 + 56795,57119,57435,57743,58044,58337,58623,58901,59172,59435,59691,
99 + 59939,60180,60414,60640,60859,61070,61274,61471,61661,61844,62019,
100 + 62188,62351,62507,62657,62802,62940,63073,63201,63323,63441,63553,
101 + 63660,63763,63861,63954,64043,64128,64208,64285,64358,64427,64493,
102 + 64555,64614,64670,64723,64773,64820,64865,64907,64947,64984,65019,
103 + 65052,65083,65113,65140,65166,65190,65212,65233,65253,65271,65288,
104 + 65304,65319,65334,65347,65360,65371,65383,65393,65403,65412,65420,
105 + 65428,65435,65442,65449,65454,65460,65465,65470,65474,65478,65482,
106 + 65485,65488,65492,65494,65497,65500,65502,65504,65506,65508,65510,
107 + 65512,65513,65515,65516,65517,65519,65520,65521,65522,65523,65523,
108 + 65524,65525,65526,65526,65527,65527,65528,65528,65529,65529,65530,
109 + 65530,65530,65531,65531,65531,65532,65532,65532,65532,65532,65533,
110 + 65533,65533,65533,65533,65533,65533,65534,65534,65534,65534,65534,
111 + 65534,65534,65534,65534,65534,65534,65534,65534,65534,65534,65534,65535
112 + };
113 +
114 + #define CIE_Z_WLMIN     359
115 + #define CIE_Z_WLMAX     624
116 +
117 + static const unsigned short     cie_z_cumul[CIE_Z_WLMAX-CIE_Z_WLMIN+1] = {
118 + 0,1,1,2,2,3,4,5,6,7,8,9,11,12,14,16,19,22,25,28,32,37,41,47,52,59,66,75,84,
119 + 95,107,121,136,154,173,196,221,250,283,321,362,408,458,512,573,640,717,804,
120 + 903,1015,1142,1285,1446,1627,1830,2058,2313,2598,2917,3272,3668,4108,4597,
121 + 5135,5723,6360,7044,7773,8544,9356,10205,11090,12006,12952,13923,14918,
122 + 15934,16967,18016,19076,20148,21227,22312,23401,24492,25585,26678,27771,
123 + 28861,29950,31037,32121,33202,34281,35355,36424,37487,38542,39588,40624,
124 + 41647,42657,43652,44631,45590,46527,47438,48321,49173,49993,50783,51542,
125 + 52270,52968,53636,54275,54885,55465,56018,56543,57042,57514,57961,58384,
126 + 58784,59162,59519,59856,60175,60477,60762,61032,61287,61529,61757,61974,
127 + 62179,62374,62559,62734,62901,63059,63211,63355,63492,63622,63745,63862,
128 + 63971,64075,64172,64263,64347,64427,64500,64569,64632,64692,64747,64798,
129 + 64846,64891,64933,64973,65010,65045,65078,65109,65139,65166,65192,65216,
130 + 65239,65260,65280,65298,65315,65331,65345,65359,65371,65383,65393,65403,
131 + 65412,65420,65428,65435,65441,65447,65452,65457,65462,65466,65470,65473,
132 + 65476,65479,65482,65485,65487,65489,65491,65493,65495,65497,65498,65500,
133 + 65501,65503,65504,65505,65506,65508,65509,65510,65511,65512,65513,65514,
134 + 65515,65516,65517,65518,65519,65520,65520,65521,65522,65523,65523,65524,
135 + 65525,65525,65526,65527,65527,65528,65528,65529,65529,65530,65530,65531,
136 + 65531,65531,65532,65532,65532,65532,65533,65533,65533,65533,65533,65533,
137 + 65534,65534,65534,65534,65534,65534,65534,65534,65534,65535
138 + };
139 +
140 + #define SCOTOPIC_WLMIN  382
141 + #define SCOTOPIC_WLMAX  684
142 +
143 + static const unsigned short     scotopic_cumul[SCOTOPIC_WLMAX-SCOTOPIC_WLMIN+1] = {
144 + 0, 1, 1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 15, 17, 20, 24, 28, 33, 38, 44,
145 + 52, 60, 69, 80, 93, 107, 123, 142, 163, 186, 213, 242, 275, 312, 353,
146 + 398, 448, 502, 562, 627, 698, 775, 859, 949, 1046, 1150, 1261, 1380,
147 + 1507, 1642, 1785, 1936, 2096, 2265, 2442, 2628, 2823, 3027, 3239, 3461,
148 + 3691, 3930, 4178, 4435, 4700, 4974, 5257, 5548, 5847, 6154, 6469, 6793,
149 + 7123, 7462, 7809, 8162, 8524, 8892, 9268, 9651, 10041, 10438, 10843, 11254,
150 + 11673, 12099, 12532, 12973, 13422, 13878, 14342, 14814, 15293, 15780, 16276,
151 + 16779, 17290, 17809, 18336, 18872, 19415, 19967, 20526, 21093, 21667, 22249,
152 + 22839, 23436, 24039, 24649, 25266, 25890, 26519, 27154, 27795, 28441, 29092,
153 + 29747, 30405, 31068, 31734, 32402, 33074, 33747, 34420, 35095, 35771, 36446,
154 + 37119, 37793, 38464, 39132, 39798, 40460, 41118, 41772, 42421, 43064, 43701,
155 + 44332, 44957, 45575, 46185, 46787, 47381, 47967, 48543, 49110, 49668, 50215,
156 + 50753, 51280, 51797, 52302, 52797, 53281, 53754, 54215, 54665, 55104, 55531,
157 + 55947, 56352, 56744, 57125, 57495, 57853, 58200, 58536, 58860, 59174, 59477,
158 + 59769, 60051, 60322, 60583, 60834, 61075, 61306, 61528, 61741, 61944, 62139,
159 + 62326, 62504, 62674, 62836, 62991, 63138, 63278, 63412, 63538, 63659, 63773,
160 + 63881, 63983, 64080, 64172, 64259, 64340, 64418, 64490, 64559, 64623, 64684,
161 + 64742, 64795, 64846, 64893, 64937, 64978, 65017, 65053, 65087, 65119, 65149,
162 + 65176, 65202, 65226, 65248, 65269, 65289, 65307, 65323, 65339, 65353, 65367,
163 + 65379, 65391, 65402, 65412, 65421, 65430, 65438, 65445, 65452, 65458, 65464,
164 + 65469, 65474, 65479, 65483, 65487, 65491, 65494, 65497, 65500, 65503, 65505,
165 + 65507, 65509, 65511, 65513, 65514, 65516, 65517, 65519, 65520, 65521, 65522,
166 + 65523, 65524, 65525, 65525, 65526, 65527, 65527, 65528, 65528, 65529, 65529,
167 + 65529, 65530, 65530, 65530, 65531, 65531, 65531, 65531, 65532, 65532, 65532,
168 + 65532, 65532, 65533, 65533, 65533, 65533, 65533, 65533, 65533, 65533, 65533,
169 + 65533, 65534, 65534, 65534, 65534, 65534, 65534, 65534, 65534, 65535
170 + };
171 +
172 + #define MELANOPIC_WLMIN 380
173 + #define MELANOPIC_WLMAX 651
174 +
175 + static const unsigned short     melanopic_cumul[MELANOPIC_WLMAX-MELANOPIC_WLMIN+1] = {
176 + 0, 1, 2, 3, 4, 5, 7, 8, 10, 12, 14, 17, 20, 23, 27, 32, 37, 42, 49, 56,
177 + 65, 75, 86, 99, 114, 131, 150, 173, 200, 230, 265, 303, 347, 395, 448,
178 + 508, 574, 650, 734, 828, 931, 1041, 1158, 1283, 1415, 1554, 1703, 1862,
179 + 2031, 2211, 2400, 2600, 2809, 3028, 3257, 3497, 3748, 4012, 4288, 4576,
180 + 4876, 5187, 5509, 5842, 6185, 6540, 6905, 7283, 7673, 8075, 8489, 8915,
181 + 9351, 9799, 10259, 10729, 11211, 11705, 12211, 12729, 13258, 13799,
182 + 14351, 14915, 15491, 16078, 16676, 17286, 17908, 18541, 19184, 19837,
183 + 20498, 21168, 21846, 22532, 23226, 23928, 24637, 25353, 26075, 26802,
184 + 27532, 28267, 29005, 29746, 30488, 31233, 31979, 32726, 33473, 34220,
185 + 34966, 35711, 36455, 37196, 37935, 38671, 39403, 40129, 40851, 41568,
186 + 42279, 42983, 43680, 44369, 45050, 45724, 46388, 47043, 47688, 48322,
187 + 48945, 49557, 50156, 50743, 51317, 51879, 52428, 52964, 53487, 53997,
188 + 54493, 54976, 55445, 55901, 56343, 56771, 57186, 57587, 57976, 58351,
189 + 58712, 59061, 59397, 59720, 60031, 60330, 60616, 60891, 61154, 61405,
190 + 61646, 61875, 62094, 62303, 62501, 62690, 62870, 63040, 63201, 63354,
191 + 63498, 63634, 63763, 63884, 63998, 64105, 64206, 64300, 64389, 64472,
192 + 64549, 64622, 64689, 64753, 64811, 64866, 64917, 64964, 65008, 65049,
193 + 65086, 65121, 65154, 65184, 65211, 65237, 65260, 65282, 65302, 65321,
194 + 65338, 65354, 65368, 65381, 65394, 65405, 65415, 65425, 65434, 65442,
195 + 65449, 65456, 65463, 65468, 65474, 65479, 65483, 65487, 65491, 65494,
196 + 65498, 65501, 65503, 65506, 65508, 65510, 65512, 65514, 65515, 65517,
197 + 65518, 65520, 65521, 65522, 65523, 65524, 65525, 65525, 65526, 65527,
198 + 65527, 65528, 65528, 65529, 65529, 65530, 65530, 65530, 65531, 65531,
199 + 65531, 65531, 65532, 65532, 65532, 65532, 65532, 65533, 65533, 65533,
200 + 65533, 65533, 65533, 65533, 65533, 65533, 65534, 65534, 65534, 65535
201 + };
202 +
203   COLORMAT  xyz2rgbmat = {                /* XYZ to RGB (no white balance) */
204          {(CIE_y_g - CIE_y_b - CIE_x_b*CIE_y_g + CIE_y_b*CIE_x_g)/CIE_C_rD,
205           (CIE_x_b - CIE_x_g - CIE_x_b*CIE_y_g + CIE_x_g*CIE_y_b)/CIE_C_rD,
# Line 91 | Line 234 | COLORMAT  ivkmat = {           /* inverse Sharp primary matrix
234  
235  
236   void
237 + spec_cie(                       /* compute XYZ color from a spectral range */
238 + COLOR  col,             /* returned color */
239 + int  s,                 /* starting and ending wavelengths */
240 + int  e
241 + )
242 + {
243 +        if (s > e) { int i = s; s = e; e = i; }
244 +
245 +        if ((s >= CIE_X_WLMAX) | (e <= CIE_X_WLMIN))
246 +                col[CIEX] = 0;
247 +        else
248 +                col[CIEX] = (cie_x_cumul[e>=CIE_X_WLMAX ? CIE_X_WLMAX-CIE_X_WLMIN : e-CIE_X_WLMIN] -
249 +                        cie_x_cumul[(s>CIE_X_WLMIN)*(s-CIE_X_WLMIN)])*(1./65535.);
250 +
251 +        if ((s >= CIE_Y_WLMAX) | (e <= CIE_Y_WLMIN))
252 +                col[CIEY] = 0;
253 +        else
254 +                col[CIEY] = (cie_y_cumul[e>=CIE_Y_WLMAX ? CIE_Y_WLMAX-CIE_Y_WLMIN : e-CIE_Y_WLMIN] -
255 +                        cie_y_cumul[(s>CIE_Y_WLMIN)*(s-CIE_Y_WLMIN)])*(1./65535.);
256 +
257 +        if ((s >= CIE_Z_WLMAX) | (e <= CIE_Z_WLMIN))
258 +                col[CIEZ] = 0;
259 +        else
260 +                col[CIEZ] = (cie_z_cumul[e>=CIE_Z_WLMAX ? CIE_Z_WLMAX-CIE_Z_WLMIN : e-CIE_Z_WLMIN] -
261 +                        cie_z_cumul[(s>CIE_Z_WLMIN)*(s-CIE_Z_WLMIN)])*(1./65535.);
262 + }
263 +
264 +
265 + void
266   spec_rgb(                       /* compute RGB color from spectral range */
267   COLOR  col,
268   int  s,
# Line 100 | Line 272 | int  e
272          COLOR  ciecolor;
273  
274          spec_cie(ciecolor, s, e);
275 <        cie_rgb(col, ciecolor);
275 >        colortrans(col, xyz2rgbmat, ciecolor);
276   }
277  
278  
279 + static double
280 + spec_dot(                       /* spectrum dot-product with cumulative observer */
281 +        const SCOLOR scol,
282 +        int  ncs,
283 +        const float wlpt[4],
284 +        const unsigned short cumul[],
285 +        int  wlmin,
286 +        int  wlmax
287 + )
288 + {
289 +        const double    wlstp = (wlpt[0] - wlpt[3])/(double)ncs;
290 +        int             wl1 = (int)wlpt[3];
291 +        int             n = 0;
292 +        double          sum = 0;
293 +
294 +        if (wl1 < wlmin) {
295 +                n += (int)((wlmin - wl1)/wlstp);
296 +                wl1 = wlmin;
297 +        } else if (wl1 >= wlmax)
298 +                return(.0);
299 +
300 +        while (n < ncs) {
301 +                int     wl0 = wl1;
302 +                wl1 = (int)(ncs==3 ? wlpt[2-n] : wlpt[3] + (n+1)*wlstp);
303 +                if (wl1 >= wlmax) {
304 +                        sum += (65535 - cumul[wl0-wlmin]) * scol[ncs-1-n];
305 +                        break;
306 +                }
307 +                sum += (cumul[wl1-wlmin] - cumul[wl0-wlmin]) * scol[ncs-1-n++];
308 +        }
309 +        return(sum * (1./65535.));
310 + }
311 +
312 +
313   void
314 < spec_cie(                       /* compute a color from a spectral range */
315 < COLOR  col,             /* returned color */
316 < int  s,                 /* starting and ending wavelengths */
317 < int  e
314 > scolor2cie(                     /* accurate conversion from spectrum to XYZ */
315 >        COLOR col,
316 >        const SCOLOR scol,
317 >        int ncs,
318 >        const float wlpt[4]
319   )
320   {
321 <        register int  i, d, r;
322 <        
323 <        s -= STARTWL;
324 <        if (s < 0)
325 <                s = 0;
321 >        if (ncs == 3) {         /* not a spectrum! */
322 >                rgb_cie(col, scol);
323 >                return;
324 >        }
325 >        col[CIEX] = spec_dot(scol, ncs, wlpt, cie_x_cumul, CIE_X_WLMIN, CIE_X_WLMAX);
326 >        col[CIEY] = spec_dot(scol, ncs, wlpt, cie_y_cumul, CIE_Y_WLMIN, CIE_Y_WLMAX);
327 >        col[CIEZ] = spec_dot(scol, ncs, wlpt, cie_z_cumul, CIE_Z_WLMIN, CIE_Z_WLMAX);
328 > }
329  
330 <        e -= STARTWL;
331 <        if (e <= s) {
332 <                col[CIEX] = col[CIEY] = col[CIEZ] = 0.0;
330 >
331 > void
332 > scolor2rgb(                     /* accurate conversion from spectrum to RGB */
333 >        COLOR col,
334 >        const SCOLOR scol,
335 >        int ncs,
336 >        const float wlpt[4]
337 > )
338 > {
339 >        COLOR   ciecolor;
340 >
341 >        if (ncs == 3) {         /* not really a spectrum, so we punt... */
342 >                copycolor(col, scol);
343                  return;
344          }
345 <        if (e >= INCWL*(NINC - 1))
346 <                e = INCWL*(NINC - 1) - 1;
345 >        scolor2cie(ciecolor, scol, ncs, wlpt);
346 >        cie_rgb(col, ciecolor);
347 > }
348  
128        d = e / INCWL;                  /* interpolate values */
129        r = e % INCWL;
130        for (i = 0; i < 3; i++)
131                col[i] = chroma[i][d]*(INCWL - r) + chroma[i][d + 1]*r;
349  
350 <        d = s / INCWL;
351 <        r = s % INCWL;
352 <        for (i = 0; i < 3; i++)
353 <                col[i] -= chroma[i][d]*(INCWL - r) - chroma[i][d + 1]*r;
350 > void
351 > scolor_out(                     /* prepare (spectral) color for output */
352 >        COLORV *cout,
353 >        RGBPRIMS pr,
354 >        const SCOLOR cres
355 > )
356 > {
357 >        static COLORMAT xyz2myp;
358 >        static RGBPRIMP lastp = NULL;
359  
360 <        col[CIEX] = (col[CIEX] + 0.5) * (1./(256*INCWL));
361 <        col[CIEY] = (col[CIEY] + 0.5) * (1./(256*INCWL));
362 <        col[CIEZ] = (col[CIEZ] + 0.5) * (1./(256*INCWL));
360 >        if (!pr) {                      /* output is spectral */
361 >                copyscolor(cout, cres);
362 >        } else if (pr == stdprims) {    /* output is standard RGB */
363 >                scolor_rgb(cout, cres);
364 >        } else if (pr == xyzprims) {    /* output is XYZ */
365 >                scolor_cie(cout, cres);
366 >                scalecolor(cout, WHTEFFICACY);
367 >        } else if (NCSAMP > 3) {        /* spectral -> custom RGB */
368 >                COLOR   xyz;
369 >                if (lastp != pr)
370 >                        compxyz2rgbWBmat(xyz2myp, lastp=pr);
371 >                scolor_cie(xyz, cres);
372 >                colortrans(cout, xyz2myp, xyz);
373 >                clipgamut(cout, xyz[CIEY], CGAMUT_LOWER, cblack, cwhite);
374 >        } else {                        /* else copy unknown RGB */
375 >                copycolor(cout, cres);
376 >        }
377   }
378  
379  
380 + double
381 + scolor2photopic(                /* compute scotopic integral for spectral color */
382 +        const SCOLOR  scol,
383 +        int ncs,
384 +        const float wlpt[4]
385 + )
386 + {
387 +        if (ncs == 3)
388 +                return bright(scol);
389 +
390 +        return(spec_dot(scol, ncs, wlpt, cie_y_cumul, CIE_Y_WLMIN, CIE_Y_WLMAX));
391 + }
392 +
393 +
394 + double
395 + scolor2scotopic(                /* compute Y channel for spectral color */
396 +        const SCOLOR  scol,
397 +        int ncs,
398 +        const float wlpt[4]
399 + )
400 + {
401 +        return(spec_dot(scol, ncs, wlpt, scotopic_cumul, SCOTOPIC_WLMIN, SCOTOPIC_WLMAX));
402 + }
403 +
404 +
405 + double
406 + scolor2melanopic(               /* compute melanopic integral for spectral color */
407 +        const SCOLOR  scol,
408 +        int ncs,
409 +        const float wlpt[4]
410 + )
411 + {
412 +        return(spec_dot(scol, ncs, wlpt, melanopic_cumul, MELANOPIC_WLMIN, MELANOPIC_WLMAX));
413 + }
414 +
415 +
416 + double
417 + scolor_photopic(                /* compute scotopic integral for spectral color */
418 +        const SCOLOR  scol
419 + )
420 + {
421 +        return(scolor2photopic(scol, NCSAMP, WLPART));
422 + }
423 +
424 +
425 + double
426 + scolor_scotopic(                /* compute Y channel for spectral color */
427 +        const SCOLOR  scol
428 + )
429 + {
430 +        return(scolor2scotopic(scol, NCSAMP, WLPART));
431 + }
432 +
433 +
434 + double
435 + scolor_melanopic(               /* compute melanopic integral for spectral color */
436 +        const SCOLOR  scol
437 + )
438 + {
439 +        return(scolor2melanopic(scol, NCSAMP, WLPART));
440 + }
441 +
442 +
443   void
444 + convertscolorcol(               /* any uniform spectrum to working */
445 +        SCOLOR rcol,
446 +        const COLORV src[],
447 +        int snc,
448 +        double swl0,
449 +        double swl1
450 + )
451 + {
452 +        if (NCSAMP > 3) {               /* spectrum -> spectrum */
453 +                convertscolor(rcol, NCSAMP, WLPART[0], WLPART[3],
454 +                                src, snc, swl0, swl1);
455 +        } else if ((snc <= MAXCSAMP) & (swl0 > swl1)) {
456 +                float   wlpt[4];        /* no intermediate conversion needed */
457 +                wlpt[0] = swl0; wlpt[3] = swl1;
458 +                wlpt[1] = WLPART[1]; wlpt[2] = WLPART[2];
459 +                scolor2rgb(rcol, (COLORV *)src, snc, wlpt);
460 +        } else {
461 +                SCOLOR  dcol;           /* else convert spectrum first */
462 +                int     dnc = snc*(WLPART[0] - WLPART[3])/fabs(swl0 - swl1) + .99;
463 +                if (dnc > MAXCSAMP) dnc = MAXCSAMP;
464 +                convertscolor(dcol, dnc, WLPART[0], WLPART[3], src, snc, swl0, swl1);
465 +                scolor2rgb(rcol, dcol, dnc, WLPART);
466 +        }
467 + }
468 +
469 +
470 + void
471   cie_rgb(                        /* convert CIE color to standard RGB */
472   COLOR   rgb,
473 < COLOR  xyz
473 > const COLOR  xyz
474   )
475   {
476          colortrans(rgb, xyz2rgbmat, xyz);
# Line 157 | Line 483 | clipgamut(                     /* clip to gamut cube */
483   COLOR  col,
484   double  brt,
485   int  gamut,
486 < COLOR  lower,
487 < COLOR  upper
486 > const COLOR  lower,
487 > const COLOR  upper
488   )
489   {
490          int  rflags = 0;
491          double  brtmin, brtmax, v, vv;
492          COLOR  cgry;
493 <        register int  i;
493 >        int  i;
494                                          /* check for no check */
495          if (gamut == 0) return(0);
496                                          /* check brightness limits */
# Line 202 | Line 528 | COLOR  upper
528  
529   void
530   colortrans(                     /* convert c1 by mat and put into c2 */
531 < register COLOR  c2,
532 < register COLORMAT  mat,
533 < register COLOR  c1
531 > COLOR  c2,
532 > const COLORMAT  mat,
533 > const COLOR  c1
534   )
535   {
536          COLOR   cout;
# Line 220 | Line 546 | register COLOR  c1
546   void
547   multcolormat(                   /* multiply m1 by m2 and put into m3 */
548   COLORMAT  m3,                   /* m3 can be either m1 or m2 w/o harm */
549 < COLORMAT  m2,
550 < COLORMAT  m1
549 > const COLORMAT  m2,
550 > const COLORMAT  m1
551   )
552   {
553          COLORMAT  mt;
554 <        register int  i, j;
554 >        int  i, j;
555  
556          for (i = 0; i < 3; i++)
557                  for (j = 0; j < 3; j++)
# Line 242 | Line 568 | RGBPRIMS  pr
568   )
569   {
570          int     i, j;
571 <        
572 <        for (i = 0; i < 4; i++) {
573 <                if ((pr[i][CIEX] <= -.5) | (pr[i][CIEY] <= -.5))
571 >                                /* check white point */
572 >        if ((pr[3][CIEX] <= CEPS) | (pr[3][CIEX] >= 1.-CEPS) |
573 >                        (pr[3][CIEY] <= CEPS) | (pr[3][CIEY] >= 1.-CEPS))
574 >                return(0);
575 >        for (i = 3; i--; )      /* check for XYZ color primaries */
576 >                if (!CEQ(pr[i][CIEX],(i==0)) | !CEQ(pr[i][CIEY],(i==1)))
577 >                        break;
578 >        if (i < 0)
579 >                return(-1);     /* flag as XYZ color space */
580 >                                /* check color primaries */
581 >        for (i = 0; i < 3; i++) {
582 >                if ((pr[i][CIEX] <= -2.) | (pr[i][CIEY] <= -2.))
583                          return(0);
584 <                if ((pr[i][CIEX] >= 1.5) | (pr[i][CIEY] >= 1.5))
584 >                if ((pr[i][CIEX] >= 3.) | (pr[i][CIEY] >= 3.))
585                          return(0);
586 <                if (pr[i][CIEX] + pr[i][CIEY] >= 1.5)
586 >                if (pr[i][CIEX] + pr[i][CIEY] <= -2.)
587                          return(0);
588 +                if (pr[i][CIEX] + pr[i][CIEY] >= 3.)
589 +                        return(0);
590          }
591 <        for (i = 0; i < 4; i++)
591 >        for (i = 0; i < 4; i++) /* make sure space is 3-dimensional */
592                  for (j = i+1; j < 4; j++)
593 <                        if (CEQ(pr[i][CIEX],pr[j][CIEX]) &&
593 >                        if (CEQ(pr[i][CIEX],pr[j][CIEX]) &
594                                          CEQ(pr[i][CIEY],pr[j][CIEY]))
595                                  return(0);
596          return(1);
# Line 264 | Line 601 | RGBPRIMS  pr
601   int
602   compxyz2rgbmat(                 /* compute conversion from CIE to RGB space */
603   COLORMAT  mat,
604 < register RGBPRIMS  pr
604 > RGBPRIMS  pr
605   )
606   {
607          double  C_rD, C_gD, C_bD;
# Line 273 | Line 610 | register RGBPRIMS  pr
610                  cpcolormat(mat, xyz2rgbmat);
611                  return(1);
612          }
613 +        if (pr == xyzprims) {   /* identity */
614 +                memset(mat, 0, sizeof(COLORMAT));
615 +                mat[0][0] = mat[1][1] = mat[2][2] = 1.f;
616 +                return(1);
617 +        }
618          if (CEQ(pr[WHT][CIEX],0.) | CEQ(pr[WHT][CIEY],0.))
619                  return(0);
620          C_rD = (1./pr[WHT][CIEY]) *
# Line 324 | Line 666 | register RGBPRIMS  pr
666   int
667   comprgb2xyzmat(                 /* compute conversion from RGB to CIE space */
668   COLORMAT  mat,
669 < register RGBPRIMS  pr
669 > RGBPRIMS  pr
670   )
671   {
672          double  C_rD, C_gD, C_bD, D;
# Line 333 | Line 675 | register RGBPRIMS  pr
675                  cpcolormat(mat, rgb2xyzmat);
676                  return(1);
677          }
678 +        if (pr == xyzprims) {   /* identity */
679 +                memset(mat, 0, sizeof(COLORMAT));
680 +                mat[0][0] = mat[1][1] = mat[2][2] = 1.f;
681 +                return(1);
682 +        }
683          if (CEQ(pr[WHT][CIEX],0.) | CEQ(pr[WHT][CIEY],0.))
684                  return(0);
685          C_rD = (1./pr[WHT][CIEY]) *
# Line 375 | Line 722 | RGBPRIMS  pr2
722          COLORMAT  pr1toxyz, xyztopr2;
723  
724          if (pr1 == pr2) {
725 <                mat[0][0] = mat[1][1] = mat[2][2] = 1.0;
726 <                mat[0][1] = mat[0][2] = mat[1][0] =
380 <                mat[1][2] = mat[2][0] = mat[2][1] = 0.0;
725 >                memset(mat, 0, sizeof(COLORMAT));
726 >                mat[0][0] = mat[1][1] = mat[2][2] = 1.f;
727                  return(1);
728          }
729          if (!comprgb2xyzmat(pr1toxyz, pr1))
# Line 393 | Line 739 | RGBPRIMS  pr2
739   int
740   compxyzWBmat(                   /* CIE von Kries transform from wht1 to wht2 */
741   COLORMAT  mat,
742 < float  wht1[2],
743 < float  wht2[2]
742 > const float  wht1[2],
743 > const float  wht2[2]
744   )
745   {
746          COLOR   cw1, cw2;
747          if (XYEQ(wht1,wht2)) {
748 <                mat[0][0] = mat[1][1] = mat[2][2] = 1.0;
749 <                mat[0][1] = mat[0][2] = mat[1][0] =
404 <                mat[1][2] = mat[2][0] = mat[2][1] = 0.0;
748 >                memset(mat, 0, sizeof(COLORMAT));
749 >                mat[0][0] = mat[1][1] = mat[2][2] = 1.f;
750                  return(1);
751          }
752          if (CEQ(wht1[CIEX],0.) | CEQ(wht1[CIEY],0.))
# Line 475 | Line 820 | RGBPRIMS  pr2
820          COLORMAT  pr1toxyz, xyztopr2, wbmat;
821  
822          if (pr1 == pr2) {
823 <                mat[0][0] = mat[1][1] = mat[2][2] = 1.0;
824 <                mat[0][1] = mat[0][2] = mat[1][0] =
480 <                mat[1][2] = mat[2][0] = mat[2][1] = 0.0;
823 >                memset(mat, 0, sizeof(COLORMAT));
824 >                mat[0][0] = mat[1][1] = mat[2][2] = 1.f;
825                  return(1);
826          }
827          if (!comprgb2xyzmat(pr1toxyz, pr1))

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines