1 /*	csel.c
2 	Copyright (C) 2006-2020 Dmitry Groshev
3 
4 	This file is part of mtPaint.
5 
6 	mtPaint is free software; you can redistribute it and/or modify
7 	it under the terms of the GNU General Public License as published by
8 	the Free Software Foundation; either version 3 of the License, or
9 	(at your option) any later version.
10 
11 	mtPaint is distributed in the hope that it will be useful,
12 	but WITHOUT ANY WARRANTY; without even the implied warranty of
13 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 	GNU General Public License for more details.
15 
16 	You should have received a copy of the GNU General Public License
17 	along with mtPaint in the file COPYING.
18 */
19 
20 #include "global.h"
21 
22 #include "mygtk.h"
23 #include "memory.h"
24 #include "otherwindow.h"
25 #include "channels.h"
26 #include "csel.h"
27 #include "thread.h"
28 
29 /* Use sRGB gamma if defined, ITU-R 709 gamma otherwise */
30 /* From my point of view, ITU-R 709 is a better model of a real CRT */
31 // #define SRGB
32 
33 /* Use distorted L*X*N* model; the distortion possibly makes it better for *
34  * smaller colour differences, but at extrema, error becomes unacceptable  */
35 // #define DISTORT_LXN
36 
37 #define CIENUM 8192
38 #define EXPNUM 1024
39 #define EXPLOW (-0.1875)
40 
41 csel_info *csel_data;
42 int csel_preview = 0x00FF00, csel_preview_a = 128, csel_overlay;
43 
44 double gamma256[256], gamma64[64];
45 double midgamma256[256];
46 
47 #ifndef NATIVE_DOUBLES
48 float Fgamma256[256];
49 #endif
50 
51 static float CIE[CIENUM + 2];
52 static float EXP[EXPNUM];
53 
54 /* This nightmarish code does conversion from CIE XYZ into my own perceptually
55  * uniform colour space L*X*N*. To produce it, I combined McAdam's colour space
56  * and CIE lightness function, like it was done for L*u*v* space - the result
57  * is a bitch to evaluate and impossible to reverse, but works much better
58  * than both L*a*b and L*u*v for colour comparison - WJ */
59 static double wXN[2];
xyz2XN(double * XN,double x,double y,double z)60 static void xyz2XN(double *XN, double x, double y, double z)
61 {
62 	double xyz = x + y + z;
63 	double k, xk, yk, sxk;
64 
65 	/* Black is a darker white ;) */
66 	if (xyz == 0.0)
67 	{
68 		XN[0] = wXN[0]; XN[1] = wXN[1];
69 		return;
70 	}
71 	k = 10.0 / (x * 2.4 + y * 34.0 + xyz);
72 	xk = x * k; yk = y * k;
73 	sxk = sqrt(xk);
74 	XN[0] = (xk * xk * (3751.0 - xk * xk * 10.0) -
75 		yk * yk * (520.0 - yk * 13295.0) +
76 		xk * yk * (32327.0 - xk * 25491.0 - yk * 41672.0 + xk * xk * 10.0) -
77 		sxk * 5227.0 + sqrt(sxk) * 2952.0) / 900.0;
78 #ifndef DISTORT_LXN
79 	/* Do transform properly */
80 	k = 10.0 / (y * 4.2 - x + xyz);
81 #else
82 	/* This equation is incorrect, but I felt that in reality it's better -
83 	 * it compresses the colour plane so that green and blue are farther
84 	 * from red than from each other, which conforms to human perception.
85 	 * Yet for pure colours, distortion tends to become too high. - WJ */
86 	k = 10.0 / (y * 5.2 - x + xyz);
87 #endif
88 	xk = x * k; yk = y * k;
89 	XN[1] = (yk * (404.0 - yk * (185.0 - yk * 52.0)) +
90 		xk * (69.0 - yk * (yk * (69.0 - yk * 30.0) + xk * 3.0))) / 900.0;
91 }
92 
CIElum(double x)93 static inline double CIElum(double x)
94 {
95 	int n;
96 
97 	x *= CIENUM;
98 	n = x;
99 	return (CIE[n] + (CIE[n + 1] - CIE[n]) * (x - n));
100 }
101 
exp10(double x)102 static inline double exp10(double x)
103 {
104 	int n;
105 
106 	x = (x - EXPLOW) * (EXPNUM + EXPNUM);
107 	n = x;
108 	return (EXP[n] + (EXP[n + 1] - EXP[n]) * (x - n));
109 }
110 
111 /* MinGW has cube root function, glibc hasn't */
112 #ifndef WIN32
113 #define cbrt(X) pow((X), 1.0 / 3.0)
114 #endif
115 
116 #define XX1 (16.0 / 116.0)
117 #define XX2 ((116.0 * 116.0) / (24.0 * 24.0 * 3.0))
118 #define XX3 ((24.0 * 24.0 * 24.0) / (116.0 * 116.0 * 116.0))
CIEpow(double x)119 static inline double CIEpow(double x)
120 {
121 	return ((x > XX3) ? cbrt(x) : x * XX2 + XX1);
122 }
123 
124 static double rxyz[3], gxyz[3], bxyz[3], wy;
rgb2LXN(double * tmp,double r,double g,double b)125 void rgb2LXN(double *tmp, double r, double g, double b)
126 {
127 	double x = r * rxyz[0] + g * gxyz[0] + b * bxyz[0];
128 	double y = r * rxyz[1] + g * gxyz[1] + b * bxyz[1];
129 	double z = r * rxyz[2] + g * gxyz[2] + b * bxyz[2];
130 	double L = CIElum(y);
131 //	double L = CIEpow(y) * 116.0 - 16.0;
132 	double XN[2];
133 	xyz2XN(XN, x, y, z);
134 	/* Luminance's range must be near to chrominance's _diameter_ */
135 #ifndef DISTORT_LXN
136 	/* As recommended in literature (but sqrt(3) may be better) */
137 	tmp[0] = L * 2.0;
138 #else
139 	/* As felt good in practice */
140 	tmp[0] = L * M_SQRT2;
141 #endif
142 	tmp[1] = (XN[0] - wXN[0]) * L * 13.0;
143 	tmp[2] = (XN[1] - wXN[1]) * L * 13.0;
144 }
145 
146 /* Get subjective brightness measure, by using Ware-Cowan formula */
rgb2B(double r,double g,double b)147 double rgb2B(double r, double g, double b)
148 {
149 	double x = r * rxyz[0] + g * gxyz[0] + b * bxyz[0];
150 	double y = r * rxyz[1] + g * gxyz[1] + b * bxyz[1];
151 	double z = r * rxyz[2] + g * gxyz[2] + b * bxyz[2];
152 	z += x + y;
153 	if (z <= 0.0) return (y);
154 	z = 1.0 / z;
155 	x *= z;
156 	z *= y; /* It's not Z now, but y */
157 	z = 0.256 + (-0.184 + (-2.527 + 4.656 * x * x + 4.657 * z * z * z) * x) * z;
158 	y *= exp10(z) * wy;
159 	return (y > 1.0 ? 1.0 : y);
160 }
161 
162 #if 0 /* Disable while not in use */
163 void rgb2Lab(double *tmp, double r, double g, double b)
164 {
165 	double x = r * rxyz[0] + g * gxyz[0] + b * bxyz[0];
166 	double y = r * rxyz[1] + g * gxyz[1] + b * bxyz[1];
167 	double z = r * rxyz[2] + g * gxyz[2] + b * bxyz[2];
168 	double L = CIElum(y);
169 	tmp[0] = L;
170 	tmp[1] = (CIElum(x * (WHITE_Y / WHITE_X)) - L) * (500.0 / 116.0);
171 	tmp[2] = (L - CIElum(z * (WHITE_Y / (1.0 - WHITE_X - WHITE_Y))) * (200.0 / 116.0);
172 }
173 #endif
174 
175 /* ITU-R 709 */
176 
177 #define RED_X 0.640
178 #define RED_Y 0.330
179 #define GREEN_X 0.300
180 #define GREEN_Y 0.600
181 #define BLUE_X 0.150
182 #define BLUE_Y 0.060
183 
184 #if 1 /* 6500K whitepoint (D65) */
185 #define WHITE_X 0.3127
186 #define WHITE_Y 0.3290
187 /* Some, like lcms, use y=0.3291, but that isn't how ITU-R BT.709-5 defines D65,
188  * but instead how SMPTE 240M does - WJ */
189 #else /* 9300K whitepoint */
190 #define WHITE_X 0.2848
191 #define WHITE_Y 0.2932
192 #endif
193 
det(double x1,double y1,double x2,double y2,double x3,double y3)194 static inline double det(double x1, double y1, double x2, double y2, double x3, double y3)
195 {
196 	return ((y1 - y2) * x3 + (y2 - y3) * x1 + (y3 - y1) * x2);
197 }
make_rgb_xyz(void)198 static void make_rgb_xyz(void)
199 {
200 	double rgbdet = det(RED_X, RED_Y, GREEN_X, GREEN_Y, BLUE_X, BLUE_Y) * WHITE_Y;
201 	double wr = det(WHITE_X, WHITE_Y, GREEN_X, GREEN_Y, BLUE_X, BLUE_Y) / rgbdet;
202 	double wg = det(RED_X, RED_Y, WHITE_X, WHITE_Y, BLUE_X, BLUE_Y) / rgbdet;
203 	double wb = det(RED_X, RED_Y, GREEN_X, GREEN_Y, WHITE_X, WHITE_Y) / rgbdet;
204 	rxyz[0] = RED_X * wr;
205 	rxyz[1] = RED_Y * wr;
206 	rxyz[2] = (1.0 - RED_X - RED_Y) * wr;
207 	gxyz[0] = GREEN_X * wg;
208 	gxyz[1] = GREEN_Y * wg;
209 	gxyz[2] = (1.0 - GREEN_X - GREEN_Y) * wg;
210 	bxyz[0] = BLUE_X * wb;
211 	bxyz[1] = BLUE_Y * wb;
212 	bxyz[2] = (1.0 - BLUE_X - BLUE_Y) * wb;
213 	xyz2XN(wXN, WHITE_X / WHITE_Y, 1.0, (1 - WHITE_X - WHITE_Y) / WHITE_Y);
214 	/* Normalize brightness of white */
215 	wy = 1.0 / exp10(0.256 + (-0.184 + (-2.527 + 4.656 * WHITE_X * WHITE_X +
216 		4.657 * WHITE_Y * WHITE_Y * WHITE_Y) * WHITE_X) * WHITE_Y);
217 }
218 
219 #ifdef SRGB
220 
221 #define GAMMA_POW 2.4
222 #define GAMMA_OFS 0.055
223 #if 1 /* Standard */
224 #define GAMMA_SPLIT 0.04045
225 #define GAMMA_DIV 12.92
226 #else /* C1 continuous */
227 #define GAMMA_SPLIT 0.03928
228 #define GAMMA_DIV 12.92321
229 #endif
230 #define KGAMMA 800
231 #define KGAMMA64K 12900
232 
233 #else /* ITU-R 709 */
234 
235 #define GAMMA_POW (1.0 / 0.45)
236 #define GAMMA_OFS 0.099
237 #define GAMMA_SPLIT 0.081
238 #define GAMMA_DIV 4.5
239 #define KGAMMA 300
240 #define KGAMMA64K 4550
241 
242 #endif
243 
make_gamma(double * Gamma,int cnt)244 static void make_gamma(double *Gamma, int cnt)
245 {
246 	int i, k;
247 	double mult = 1.0 / (double)(cnt - 1);
248 
249 	k = (int)(GAMMA_SPLIT * (cnt - 1)) + 1;
250 
251 	for (i = k; i < cnt; i++)
252 	{
253 		Gamma[i] = pow(((double)i * mult + GAMMA_OFS) /
254 			(1.0 + GAMMA_OFS), GAMMA_POW);
255 	}
256 	mult /= GAMMA_DIV;
257 	for (i = 0; i < k; i++)
258 	{
259 		Gamma[i] = (double)i * mult;
260 	}
261 }
262 
263 int kgamma256 = KGAMMA * 4;
264 unsigned char ungamma256[KGAMMA * 4 + 1];
265 
make_ungamma(double * Gamma,double * Midgamma,unsigned char * Ungamma,int kgamma,int cnt)266 static void make_ungamma(double *Gamma, double *Midgamma,
267 	unsigned char *Ungamma,	int kgamma, int cnt)
268 {
269 	int i, j, k = 0;
270 
271 	Midgamma[0] = 0.0;
272 	for (i = 1; i < cnt; i++)
273 	{
274 		Midgamma[i] = (Gamma[i - 1] + Gamma[i]) / 2.0;
275 		j = Midgamma[i] * kgamma;
276 		for (; k < j; k++) Ungamma[k] = i - 1;
277 	}
278 	for (; k <= kgamma; k++) Ungamma[k] = cnt - 1;
279 }
280 
281 /* 16-bit gamma correction */
282 
283 static double gamma64K[255 * 4 + 2];
284 static double gammaslope64K[255 * 4 + 1];
285 static unsigned short ungamma64K[KGAMMA64K + 1];
286 
287 #if 0 /* Disable while not in use */
288 double gamma65536(int idx)
289 {
290 	int n;
291 
292 	idx *= 4;
293 	n = idx / 257;
294 	return ((idx % 257) * (1.0 / 257.0) * (gamma64K[n + 1] - gamma64K[n]) +
295 		gamma64K[n]);
296 }
297 
298 int ungamma65536(double v)
299 {
300 	int n = ungamma64K[(int)(v * KGAMMA64K)];
301 
302 	n -= v < gamma64K[n];
303 	return ((int)((n + (v - gamma64K[n]) * gammaslope64K[n]) * 64.25 + 0.5));
304 }
305 #endif
306 
gamma65281(int idx)307 double gamma65281(int idx)
308 {
309 	int n;
310 
311 	n = idx >> 6;
312 	return ((idx & 0x3F) * (1.0 / 64.0) * (gamma64K[n + 1] - gamma64K[n]) +
313 		gamma64K[n]);
314 }
315 
ungamma65281(double v)316 int ungamma65281(double v)
317 {
318 	int n = ungamma64K[(int)(v * KGAMMA64K)];
319 
320 	n -= v < gamma64K[n];
321 	return ((int)((n + (v - gamma64K[n]) * gammaslope64K[n]) * 64.0 + 0.5));
322 }
323 
make_ungamma64K()324 static void make_ungamma64K()
325 {
326 	int i, j, k = 0;
327 
328 	for (i = 1; i < 255 * 4 + 1; i++)
329 	{
330 		gammaslope64K[i - 1] = 1.0 / (gamma64K[i] - gamma64K[i - 1]);
331 		j = gamma64K[i] * KGAMMA64K;
332 		for (; k < j; k++) ungamma64K[k] = i - 1;
333 	}
334 	gammaslope64K[255 * 4] = 0.0;
335 	for (; k <= KGAMMA64K; k++) ungamma64K[k] = 255 * 4;
336 }
337 
make_CIE(void)338 static void make_CIE(void)
339 {
340 	int i;
341 
342 	for (i = 0; i < CIENUM; i++)
343 	{
344 		CIE[i] = CIEpow(i * (1.0 / CIENUM)) * 116.0 - 16.0;
345 	}
346 	CIE[CIENUM] = CIE[CIENUM + 1] = 100.0;
347 }
348 
make_EXP(void)349 static void make_EXP(void)
350 {
351 	int i;
352 
353 	for (i = 0; i < EXPNUM; i++)
354 	{
355 		EXP[i] = exp(M_LN10 * (i * (0.5 / EXPNUM) + EXPLOW));
356 	}
357 }
358 
init_cols(void)359 void init_cols(void)
360 {
361 	make_gamma(gamma64K, 255 * 4 + 1);
362 	gamma64K[255 * 4 + 1] = 1.0;
363 	make_gamma(gamma256, 256);
364 	make_gamma(gamma64, 64);
365 	make_ungamma64K();
366 	make_ungamma(gamma256, midgamma256, ungamma256, kgamma256, 256);
367 	make_CIE();
368 	make_EXP();
369 	make_rgb_xyz();
370 #ifndef NATIVE_DOUBLES
371 	/* Fill reduced-precision gamma table */
372 	{
373 		int i;
374 		for (i = 0; i < 256; i++) Fgamma256[i] = gamma256[i];
375 	}
376 #endif
377 }
378 
379 /* Get L*X*N* triple */
get_lxn(double * lxn,int col)380 void get_lxn(double *lxn, int col)
381 {
382 	rgb2LXN(lxn, gamma256[INT_2_R(col)], gamma256[INT_2_G(col)],
383 		gamma256[INT_2_B(col)]);
384 }
385 
386 /* Get hue vector (0..1529) */
get_vect(int col)387 static double get_vect(int col)
388 {
389 	static int ixx[5] = {0, 1, 2, 0, 1};
390 	int rgb[3] = {INT_2_R(col), INT_2_G(col), INT_2_B(col)};
391 	int c1, c2, minc, midc, maxc;
392 
393 	if (!((rgb[0] ^ rgb[1]) | (rgb[0] ^ rgb[2]))) return (0.0);
394 
395 	c2 = rgb[2] < rgb[0] ? (rgb[1] < rgb[2] ? 2 : 0) : (rgb[0] < rgb[1] ? 1 : 2);
396 	minc = rgb[ixx[c2 + 2]];
397 	midc = rgb[ixx[c2 + 1]];
398 	c1 = midc > rgb[c2];
399 	midc -= c1 ? rgb[c2] : minc;
400 	maxc = rgb[ixx[c2 + c1]] - minc;
401 	return ((c2 + c2 + c1) * 255 + midc * 255 / (double)maxc);
402 }
403 
404 #if defined(U_THREADS) && defined(HAVE__SFA)
405 /* Hope this and __sync_fetch_and_add() always come as a package */
406 #define SETBIT(A,B) __sync_fetch_and_or(&(A), (B))
407 #else
408 #define SETBIT(A,B) (A) |= (B)
409 #endif
410 
411 
412 /* Answer which pixels are masked through selectivity */
csel_scan(int start,int step,int cnt,unsigned char * mask,unsigned char * img,csel_info * info)413 int csel_scan(int start, int step, int cnt, unsigned char *mask,
414 	unsigned char *img, csel_info *info)
415 {
416 	unsigned char res = 0;
417 	double d, dist = 0.0, lxn[3];
418 	int i, j, k, l, jj, st3 = step * 3;
419 #ifndef HAVE__SFA
420 	DEF_MUTEX(csel_lock); // To prevent concurrent writes to *info
421 
422 
423 	LOCK_MUTEX(csel_lock);
424 #endif
425 	cnt = start + step * (cnt - 1) + 1;
426 	if (!mask)
427 	{
428 		mask = &res - start;
429 		cnt = start + 1;
430 	}
431 	if (mem_img_bpp == 1)	/* Indexed image */
432 	{
433 		for (i = start; i < cnt; i += step)
434 		{
435 			j = img[i];
436 			k = PNG_2_INT(mem_pal[j]);
437 			if (info->pcache[j] != k)
438 			{
439 				if (info->mode == 0) /* Sphere mode */
440 				{
441 					get_lxn(lxn, k);
442 					dist = (lxn[0] - info->clxn[0]) *
443 						(lxn[0] - info->clxn[0]) +
444 						(lxn[1] - info->clxn[1]) *
445 						(lxn[1] - info->clxn[1]) +
446 						(lxn[2] - info->clxn[2]) *
447 						(lxn[2] - info->clxn[2]);
448 				}
449 				else if (info->mode == 1) /* Angle mode */
450 				{
451 					dist = fabs(get_vect(k) - info->cvec);
452 					if (dist > 765.0) dist = 1530.0 - dist;
453 				}
454 				else if (info->mode == 2) /* Cube mode */
455 				{
456 					l = abs(INT_2_R(info->center) - INT_2_R(k));
457 					jj = abs(INT_2_G(info->center) - INT_2_G(k));
458 					if (l < jj) l = jj;
459 					jj = abs(INT_2_B(info->center) - INT_2_B(k));
460 					dist = l > jj ? l : jj;
461 				}
462 				if (dist <= info->range2)
463 					SETBIT(info->pmap[j >> 5], 1U << (j & 31));
464 				info->pcache[j] = k;
465 			}
466 			if (((info->pmap[j >> 5] >> (j & 31)) ^ info->invert) & 1)
467 				mask[i] |= 255;
468 		}
469 	}
470 	else if (info->mode == 0)	/* RGB image, sphere mode */
471 	{
472 		img += start * 3;
473 		for (i = start; i < cnt; i += step , img += st3)
474 		{
475 			unsigned l;
476 			k = MEM_2_INT(img, 0) - info->cbase;
477 			if (k & 0xFFC0C0C0) /* Coarse map */
478 			{
479 				j = ((img[0] & 0xFC) << 6) + (img[1] & 0xFC) +
480 					(img[2] >> 6);
481 				k = (img[2] >> 1) & 0x1E;
482 			}
483 			else /* Fine map */
484 			{
485 				j = ((k & 0x3F0000) >> 8) + ((k & 0x3F00) >> 6) +
486 					((k & 0x3F) >> 4) + CMAPSIZE;
487 				k = (k + k) & 0x1E;
488 			}
489 			l = (info->colormap[j] >> k) & 3;
490 			if (!l) /* Not mapped */
491 			{
492 				if (j < CMAPSIZE) rgb2LXN(lxn, gamma64[img[0] >> 2],
493 					gamma64[img[1] >> 2], gamma64[img[2] >> 2]);
494 				else rgb2LXN(lxn, gamma256[img[0]], gamma256[img[1]],
495 					gamma256[img[2]]);
496 				dist = (lxn[0] - info->clxn[0]) *
497 					(lxn[0] - info->clxn[0]) +
498 					(lxn[1] - info->clxn[1]) *
499 					(lxn[1] - info->clxn[1]) +
500 					(lxn[2] - info->clxn[2]) *
501 					(lxn[2] - info->clxn[2]);
502 				l = dist <= info->range2 ? 3 : 2;
503 				SETBIT(info->colormap[j], l << k);
504 			}
505 			if ((l ^ info->invert) & 1) mask[i] |= 255;
506 		}
507 	}
508 	else if (info->mode == 1)	/* RGB image, angle mode */
509 	{
510 		static int ixx[5] = {0, 1, 2, 0, 1};
511 
512 		img += start * 3;
513 		for (i = start; i < cnt; i += step , img += st3)
514 		{
515 			unsigned l;
516 			k = img[2] < img[0] ? (img[1] < img[2] ? 2 : 0) :
517 				(img[0] < img[1] ? 1 : 2);
518 			j = (img[ixx[k]] << 8) + img[ixx[k + 1]] -
519 				img[ixx[k + 2]] * 257;
520 			l = (info->colormap[j >> 3] >> ((j & 7) << 2)) & 0xF;
521 			if (!l) /* Not mapped */
522 			{
523 				/* Map 3 sectors at once */
524 				d = get_vect(j << 8) - info->cvec;
525 				for (jj = 1; jj < 8; jj += jj)
526 				{
527 					dist = fabs(d);
528 					d += 510.0;
529 					if (dist > 765.0) dist = 1530.0 - dist;
530 					if (dist <= info->range2) l += jj;
531 				}
532 				SETBIT(info->colormap[j >> 3], (l + 8) << ((j & 7) << 2));
533 			}
534 			if (((l >> k) ^ info->invert) & 1) mask[i] |= 255;
535 		}
536 	}
537 	else if (info->mode == 2)	/* RGB image, cube mode */
538 	{
539 		j = INT_2_R(info->center);
540 		k = INT_2_G(info->center);
541 		l = INT_2_B(info->center);
542 		jj = info->invert & 1;
543 		img += start * 3;
544 		for (i = start; i < cnt; i += step , img += st3)
545 		{
546 			if (((abs(j - img[0]) <= info->irange) &&
547 				(abs(k - img[1]) <= info->irange) &&
548 				(abs(l - img[2]) <= info->irange)) ^ jj)
549 				mask[i] |= 255;
550 		}
551 	}
552 #ifndef HAVE__SFA
553 	UNLOCK_MUTEX(csel_lock);
554 #endif
555 	return (res);
556 }
557 
558 /* Evaluate range */
csel_eval(int mode,int center,int limit)559 double csel_eval(int mode, int center, int limit)
560 {
561 	double cw[3], lw[3], cwv, lwv, r2;
562 	int i, j, k, ir;
563 
564 	switch (mode)
565 	{
566 	case 0: /* L*X*N* spherical */
567 		get_lxn(cw, center);
568 		get_lxn(lw, limit);
569 		r2 = (lw[0] - cw[0]) * (lw[0] - cw[0]) +
570 			(lw[1] - cw[1]) * (lw[1] - cw[1]) +
571 			(lw[2] - cw[2]) * (lw[2] - cw[2]);
572 		return (sqrt(r2));
573 	case 1: /* RGB angular */
574 		cwv = get_vect(center);
575 		lwv = get_vect(limit);
576 		r2 = fabs(lwv - cwv);
577 		if (r2 > 765.0) r2 = 1530.0 - r2;
578 		return (r2);
579 	case 2: /* RGB cubic */
580 		i = abs(INT_2_R(center) - INT_2_R(limit));
581 		j = abs(INT_2_G(center) - INT_2_G(limit));
582 		k = abs(INT_2_B(center) - INT_2_B(limit));
583 		ir = i > j ? i : j;
584 		if (ir < k) ir = k;
585 		return ((double)ir);
586 	}
587 	return (0.0);
588 }
589 
590 /* Clear bitmaps and setup extra vars */
csel_reset(csel_info * info)591 void csel_reset(csel_info *info)
592 {
593 	int i, j, k, l;
594 
595 	memset(info->colormap, 0, sizeof(info->colormap));
596 	memset(info->pmap, 0, sizeof(info->pmap));
597 	memset(info->pcache, 255, sizeof(info->pcache));
598 	switch (info->mode)
599 	{
600 	case 0: /* L*X*N* sphere */
601 		get_lxn(info->clxn, info->center);
602 		info->range2 = info->range * info->range;
603 		/* Find fine-precision base */
604 		l = info->center & 0xFCFCFC;
605 		i = INT_2_R(l);
606 		j = INT_2_G(l);
607 		k = INT_2_B(l);
608 		i = i > 32 ? i - 32 : 0;
609 		j = j > 32 ? j - 32 : 0;
610 		k = k > 32 ? k - 32 : 0;
611 		info->cbase = RGB_2_INT(i, j, k);
612 		break;
613 	case 1: /* RGB angular */
614 		info->cvec = get_vect(info->center);
615 		info->range2 = info->range;
616 		break;
617 	case 2: /* RGB cubic */
618 		info->irange = info->range2 = (int)(info->range);
619 		break;
620 	}
621 	if (info->center_a < info->limit_a)
622 	{
623 		info->amin = info->center_a;
624 		info->amax = info->limit_a;
625 	}
626 	else
627 	{
628 		info->amax = info->center_a;
629 		info->amin = info->limit_a;
630 	}
631 }
632 
633 /* Set center at A, limit at B */
csel_init()634 void csel_init()
635 {
636 	csel_info *info;
637 
638 	info = ALIGN(calloc(1, sizeof(csel_info) + sizeof(double)));
639 	if (!info)
640 	{
641 		memory_errors(1);
642 		return;
643 	}
644 	info->center = PNG_2_INT(mem_col_A24);
645 	info->limit = PNG_2_INT(mem_col_B24);
646 	info->center_a = channel_col_A[CHN_ALPHA];
647 	info->limit_a = channel_col_B[CHN_ALPHA];
648 	info->range = csel_eval(0, info->center, info->limit);
649 	csel_reset(info);
650 	csel_data = info;
651 }
652