1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "ags/lib/allegro/color.h"
24 #include "ags/lib/allegro/system.h"
25 #include "ags/lib/allegro/aintern.h"
26 #include "ags/shared/core/types.h"
27 #include "ags/shared/util/stream.h"
28 #include "ags/globals.h"
29 #include "common/textconsole.h"
30 #include "common/system.h"
31 #include "graphics/palette.h"
32 
33 namespace AGS3 {
34 
35 #define VGA_COLOR_TRANS(x) ((x) * 255 / 63)
36 
readFromFile(AGS::Shared::Stream * file)37 void color::readFromFile(AGS::Shared::Stream *file) {
38 	r = file->ReadByte();
39 	g = file->ReadByte();
40 	b = file->ReadByte();
41 	filler = file->ReadByte();
42 }
43 
writeToFile(AGS::Shared::Stream * file) const44 void color::writeToFile(AGS::Shared::Stream *file) const {
45 	file->WriteByte(r);
46 	file->WriteByte(g);
47 	file->WriteByte(b);
48 	file->WriteByte(filler);
49 }
50 
convertPalette(const PALETTE src,byte dest[PALETTE_SIZE])51 static void convertPalette(const PALETTE src, byte dest[PALETTE_SIZE]) {
52 	const color *cSrc = (const color *)src;
53 	for (int i = 0; i < PALETTE_COUNT; ++i, cSrc++, dest += 3) {
54 		dest[0] = VGA_COLOR_TRANS(cSrc->r);
55 		dest[1] = VGA_COLOR_TRANS(cSrc->g);
56 		dest[2] = VGA_COLOR_TRANS(cSrc->b);
57 	}
58 }
59 
applyPalette()60 static void applyPalette() {
61 	if (g_system->getScreenFormat().bytesPerPixel == 1) {
62 		byte pal[PALETTE_SIZE];
63 		convertPalette(_G(current_palette), pal);
64 		g_system->getPaletteManager()->setPalette(pal, 0, PALETTE_COUNT);
65 	}
66 }
67 
set_palette(const PALETTE p)68 void set_palette(const PALETTE p) {
69 	for (int idx = 0; idx < PAL_SIZE; ++idx)
70 		_G(current_palette)[idx] = p[idx];
71 
72 	applyPalette();
73 }
74 
set_palette_range(const PALETTE p,int from,int to,int retracesync)75 void set_palette_range(const PALETTE p, int from, int to, int retracesync) {
76 	for (int i = from; i <= to; ++i) {
77 		_G(current_palette)[i] = p[i];
78 	}
79 
80 	applyPalette();
81 }
82 
makecol15(int r,int g,int b)83 int makecol15(int r, int g, int b) {
84 	return (((r >> 3) << _G(_rgb_r_shift_15)) |
85 	        ((g >> 3) << _G(_rgb_g_shift_15)) |
86 	        ((b >> 3) << _G(_rgb_b_shift_15)));
87 }
88 
makecol16(int r,int g,int b)89 int makecol16(int r, int g, int b) {
90 	return (((r >> 3) << _G(_rgb_r_shift_16)) |
91 	        ((g >> 2) << _G(_rgb_g_shift_16)) |
92 	        ((b >> 3) << _G(_rgb_b_shift_16)));
93 }
94 
makecol24(int r,int g,int b)95 int makecol24(int r, int g, int b) {
96 	return ((r << _G(_rgb_r_shift_24)) |
97 	        (g << _G(_rgb_g_shift_24)) |
98 	        (b << _G(_rgb_b_shift_24)));
99 }
100 
makecol32(int r,int g,int b)101 int makecol32(int r, int g, int b) {
102 	return ((r << _G(_rgb_r_shift_32)) |
103 	        (g << _G(_rgb_g_shift_32)) |
104 	        (b << _G(_rgb_b_shift_32)));
105 }
106 
makeacol32(int r,int g,int b,int a)107 int makeacol32(int r, int g, int b, int a) {
108 	return ((r << _G(_rgb_r_shift_32)) |
109 	        (g << _G(_rgb_g_shift_32)) |
110 	        (b << _G(_rgb_b_shift_32)) |
111 	        (a << _G(_rgb_a_shift_32)));
112 }
113 
getr8(int c)114 int getr8(int c) {
115 	return (int)_G(current_palette)[c].r;
116 }
117 
getg8(int c)118 int getg8(int c) {
119 	return (int)_G(current_palette)[c].g;
120 }
121 
getb8(int c)122 int getb8(int c) {
123 	return (int)_G(current_palette)[c].b;
124 }
125 
getr15(int c)126 int getr15(int c) {
127 	return _rgb_scale_5[(c >> _G(_rgb_r_shift_15)) & 0x1F];
128 }
129 
getg15(int c)130 int getg15(int c) {
131 	return _rgb_scale_5[(c >> _G(_rgb_g_shift_15)) & 0x1F];
132 }
133 
getb15(int c)134 int getb15(int c) {
135 	return _rgb_scale_5[(c >> _G(_rgb_b_shift_15)) & 0x1F];
136 }
137 
getr16(int c)138 int getr16(int c) {
139 	return _rgb_scale_5[(c >> _G(_rgb_r_shift_16)) & 0x1F];
140 }
141 
getg16(int c)142 int getg16(int c) {
143 	return _rgb_scale_6[(c >> _G(_rgb_g_shift_16)) & 0x3F];
144 }
145 
getb16(int c)146 int getb16(int c) {
147 	return _rgb_scale_5[(c >> _G(_rgb_b_shift_16)) & 0x1F];
148 }
149 
getr24(int c)150 int getr24(int c) {
151 	return ((c >> _G(_rgb_r_shift_24)) & 0xFF);
152 }
153 
getg24(int c)154 int getg24(int c) {
155 	return ((c >> _G(_rgb_g_shift_24)) & 0xFF);
156 }
157 
getb24(int c)158 int getb24(int c) {
159 	return ((c >> _G(_rgb_b_shift_24)) & 0xFF);
160 }
161 
getr32(int c)162 int getr32(int c) {
163 	return ((c >> _G(_rgb_r_shift_32)) & 0xFF);
164 }
165 
getg32(int c)166 int getg32(int c) {
167 	return ((c >> _G(_rgb_g_shift_32)) & 0xFF);
168 }
169 
getb32(int c)170 int getb32(int c) {
171 	return ((c >> _G(_rgb_b_shift_32)) & 0xFF);
172 }
173 
geta32(int c)174 int geta32(int c) {
175 	return ((c >> _G(_rgb_a_shift_32)) & 0xFF);
176 }
177 
makecol(byte r,byte g,byte b)178 int makecol(byte r, byte g, byte b) {
179 	return (b) | (g << 8) | (r << 16);
180 }
181 
makecol8(byte r,byte g,byte b)182 int makecol8(byte r, byte g, byte b) {
183 	return (b) | (g << 8) | (r << 16);
184 }
185 
get_color(int idx,RGB * p)186 void get_color(int idx, RGB *p) {
187 	*p = _G(current_palette)[idx];
188 }
189 
get_palette_range(PALETTE p,int from,int to)190 void get_palette_range(PALETTE p, int from, int to) {
191 	Common::copy(&_G(current_palette)[from], &_G(current_palette)[to + 1], &p[from]);
192 }
193 
get_palette(PALETTE p)194 void get_palette(PALETTE p) {
195 	get_palette_range(p, 0, PAL_SIZE - 1);
196 }
197 
fade_interpolate(AL_CONST PALETTE source,AL_CONST PALETTE dest,PALETTE output,int pos,int from,int to)198 void fade_interpolate(AL_CONST PALETTE source, AL_CONST PALETTE dest, PALETTE output, int pos, int from, int to) {
199 	assert(pos >= 0 && pos <= 64);
200 	assert(from >= 0 && from < PAL_SIZE);
201 	assert(to >= 0 && to < PAL_SIZE);
202 
203 	for (int c = from; c <= to; c++) {
204 		output[c].r = ((int)source[c].r * (63 - pos) + (int)dest[c].r * pos) / 64;
205 		output[c].g = ((int)source[c].g * (63 - pos) + (int)dest[c].g * pos) / 64;
206 		output[c].b = ((int)source[c].b * (63 - pos) + (int)dest[c].b * pos) / 64;
207 	}
208 }
209 
select_palette(AL_CONST PALETTE p)210 void select_palette(AL_CONST PALETTE p) {
211 	int c;
212 
213 	for (c = 0; c < PAL_SIZE; c++) {
214 		_G(prev_current_palette)[c] = _G(current_palette)[c];
215 		_G(current_palette)[c] = p[c];
216 	}
217 
218 	applyPalette();
219 }
220 
unselect_palette(void)221 void unselect_palette(void) {
222 	int c;
223 
224 	for (c = 0; c < PAL_SIZE; c++)
225 		_G(current_palette)[c] = _G(prev_current_palette)[c];
226 
227 	applyPalette();
228 }
229 
set_blender_mode(BlenderMode m,int r,int g,int b,int a)230 void set_blender_mode(BlenderMode m, int r, int g, int b, int a) {
231 	_G(_blender_mode) = m;
232 	_G(trans_blend_alpha) = a;
233 	_G(trans_blend_red) = r;
234 	_G(trans_blend_green) = g;
235 	_G(trans_blend_blue) = b;
236 }
237 
set_alpha_blender(void)238 void set_alpha_blender(void) {
239 	set_blender_mode(kSourceAlphaBlender, 0, 0, 0, 0);
240 }
241 
set_trans_blender(int r,int g,int b,int a)242 void set_trans_blender(int r, int g, int b, int a) {
243 	set_blender_mode(kRgbToRgbBlender, r, g, b, a);
244 }
245 
246 /* makecol_depth:
247  *  Converts R, G, and B values (ranging 0-255) to whatever pixel format
248  *  is required by the specified color depth.
249  */
makecol_depth(int color_depth,int r,int g,int b)250 int makecol_depth(int color_depth, int r, int g, int b) {
251 	switch (color_depth) {
252 
253 	case 8:
254 		return makecol8(r, g, b);
255 
256 	case 15:
257 		return makecol15(r, g, b);
258 
259 	case 16:
260 		return makecol16(r, g, b);
261 
262 	case 24:
263 		return makecol24(r, g, b);
264 
265 	case 32:
266 		return makecol32(r, g, b);
267 	}
268 
269 	return 0;
270 }
271 
272 
273 
274 /* makeacol_depth:
275  *  Converts R, G, B, and A values (ranging 0-255) to whatever pixel format
276  *  is required by the specified color depth.
277  */
makeacol_depth(int color_depth,int r,int g,int b,int a)278 int makeacol_depth(int color_depth, int r, int g, int b, int a) {
279 	switch (color_depth) {
280 
281 	case 8:
282 		return makecol8(r, g, b);
283 
284 	case 15:
285 		return makecol15(r, g, b);
286 
287 	case 16:
288 		return makecol16(r, g, b);
289 
290 	case 24:
291 		return makecol24(r, g, b);
292 
293 	case 32:
294 		return makeacol32(r, g, b, a);
295 	}
296 
297 	return 0;
298 }
299 
300 /* getr_depth:
301  *  Extracts the red component (ranging 0-255) from a pixel in the format
302  *  being used by the specified color depth.
303  */
getr_depth(int color_depth,int c)304 int getr_depth(int color_depth, int c) {
305 	switch (color_depth) {
306 
307 	case 8:
308 		return getr8(c);
309 
310 	case 15:
311 		return getr15(c);
312 
313 	case 16:
314 		return getr16(c);
315 
316 	case 24:
317 		return getr24(c);
318 
319 	case 32:
320 		return getr32(c);
321 	}
322 
323 	return 0;
324 }
325 
326 
327 
328 /* getg_depth:
329  *  Extracts the green component (ranging 0-255) from a pixel in the format
330  *  being used by the specified color depth.
331  */
getg_depth(int color_depth,int c)332 int getg_depth(int color_depth, int c) {
333 	switch (color_depth) {
334 
335 	case 8:
336 		return getg8(c);
337 
338 	case 15:
339 		return getg15(c);
340 
341 	case 16:
342 		return getg16(c);
343 
344 	case 24:
345 		return getg24(c);
346 
347 	case 32:
348 		return getg32(c);
349 	}
350 
351 	return 0;
352 }
353 
354 
355 
356 /* getb_depth:
357  *  Extracts the blue component (ranging 0-255) from a pixel in the format
358  *  being used by the specified color depth.
359  */
getb_depth(int color_depth,int c)360 int getb_depth(int color_depth, int c) {
361 	switch (color_depth) {
362 
363 	case 8:
364 		return getb8(c);
365 
366 	case 15:
367 		return getb15(c);
368 
369 	case 16:
370 		return getb16(c);
371 
372 	case 24:
373 		return getb24(c);
374 
375 	case 32:
376 		return getb32(c);
377 	}
378 
379 	return 0;
380 }
381 
382 
383 
384 /* geta_depth:
385  *  Extracts the alpha component (ranging 0-255) from a pixel in the format
386  *  being used by the specified color depth.
387  */
geta_depth(int color_depth,int c)388 int geta_depth(int color_depth, int c) {
389 	if (color_depth == 32)
390 		return geta32(c);
391 
392 	return 0;
393 }
394 
395 
396 
397 /* getr:
398  *  Extracts the red component (ranging 0-255) from a pixel in the format
399  *  being used by the current video mode.
400  */
getr(int c)401 int getr(int c) {
402 	return getr_depth(_G(_color_depth), c);
403 }
404 
405 
406 
407 /* getg:
408  *  Extracts the green component (ranging 0-255) from a pixel in the format
409  *  being used by the current video mode.
410  */
getg(int c)411 int getg(int c) {
412 	return getg_depth(_G(_color_depth), c);
413 }
414 
415 
416 
417 /* getb:
418  *  Extracts the blue component (ranging 0-255) from a pixel in the format
419  *  being used by the current video mode.
420  */
getb(int c)421 int getb(int c) {
422 	return getb_depth(_G(_color_depth), c);
423 }
424 
425 
426 
427 /* geta:
428  *  Extracts the alpha component (ranging 0-255) from a pixel in the format
429  *  being used by the current video mode.
430  */
geta(int c)431 int geta(int c) {
432 	return geta_depth(_G(_color_depth), c);
433 }
434 
435 
436 
437 /* 1.5k lookup table for color matching */
438 static unsigned int col_diff[3 * 128];
439 
440 
441 
442 /* bestfit_init:
443  *  Color matching is done with weighted squares, which are much faster
444  *  if we pregenerate a little lookup table...
445  */
bestfit_init(void)446 static void bestfit_init(void) {
447 	int i;
448 
449 	for (i = 1; i < 64; i++) {
450 		int k = i * i;
451 		col_diff[0 + i] = col_diff[0 + 128 - i] = k * (59 * 59);
452 		col_diff[128 + i] = col_diff[128 + 128 - i] = k * (30 * 30);
453 		col_diff[256 + i] = col_diff[256 + 128 - i] = k * (11 * 11);
454 	}
455 }
456 
457 
458 
459 /* bestfit_color:
460  *  Searches a palette for the color closest to the requested R, G, B value.
461  */
bestfit_color(AL_CONST PALETTE pal,int r,int g,int b)462 int bestfit_color(AL_CONST PALETTE pal, int r, int g, int b) {
463 	int i, coldiff, lowest, bestfit;
464 
465 	assert(r >= 0 && r <= 63);
466 	assert(g >= 0 && g <= 63);
467 	assert(b >= 0 && b <= 63);
468 
469 	if (col_diff[1] == 0)
470 		bestfit_init();
471 
472 	bestfit = 0;
473 	lowest = INT_MAX;
474 
475 	/* only the transparent (pink) color can be mapped to index 0 */
476 	if ((r == 63) && (g == 0) && (b == 63))
477 		i = 0;
478 	else
479 		i = 1;
480 
481 	while (i < PAL_SIZE) {
482 		AL_CONST RGB *rgb = &pal[i];
483 		coldiff = (col_diff + 0)[(rgb->g - g) & 0x7F];
484 		if (coldiff < lowest) {
485 			coldiff += (col_diff + 128)[(rgb->r - r) & 0x7F];
486 			if (coldiff < lowest) {
487 				coldiff += (col_diff + 256)[(rgb->b - b) & 0x7F];
488 				if (coldiff < lowest) {
489 					bestfit = rgb - pal;    /* faster than `bestfit = i;' */
490 					if (coldiff == 0)
491 						return bestfit;
492 					lowest = coldiff;
493 				}
494 			}
495 		}
496 		i++;
497 	}
498 
499 	return bestfit;
500 }
501 
502 
503 
504 /* makecol8:
505  *  Converts R, G, and B values (ranging 0-255) to an 8 bit paletted color.
506  *  If the global _G(rgb_map) table is initialised, it uses that, otherwise
507  *  it searches through the current palette to find the best match.
508  */
makecol8(int r,int g,int b)509 int makecol8(int r, int g, int b) {
510 	if (_G(rgb_map))
511 		return _G(rgb_map)->data[r >> 3][g >> 3][b >> 3];
512 	else
513 		return bestfit_color(_G(current_palette), r >> 2, g >> 2, b >> 2);
514 }
515 
516 
517 
518 /* hsv_to_rgb:
519  *  Converts from HSV colorspace to RGB values.
520  */
hsv_to_rgb(float h,float s,float v,int * r,int * g,int * b)521 void hsv_to_rgb(float h, float s, float v, int *r, int *g, int *b) {
522 	float f, x, y, z;
523 	int i;
524 
525 	assert(s >= 0 && s <= 1);
526 	assert(v >= 0 && v <= 1);
527 
528 	v *= 255.0f;
529 
530 	if (s == 0.0f) { /* ok since we don't divide by s, and faster */
531 		*r = *g = *b = v + 0.5f;
532 	} else {
533 		h = fmod(h, 360.0f) / 60.0f;
534 		if (h < 0.0f)
535 			h += 6.0f;
536 
537 		i = (int)h;
538 		f = h - i;
539 		x = v * s;
540 		y = x * f;
541 		v += 0.5f; /* round to the nearest integer below */
542 		z = v - x;
543 
544 		switch (i) {
545 
546 		case 6:
547 		case 0:
548 			*r = v;
549 			*g = z + y;
550 			*b = z;
551 			break;
552 
553 		case 1:
554 			*r = v - y;
555 			*g = v;
556 			*b = z;
557 			break;
558 
559 		case 2:
560 			*r = z;
561 			*g = v;
562 			*b = z + y;
563 			break;
564 
565 		case 3:
566 			*r = z;
567 			*g = v - y;
568 			*b = v;
569 			break;
570 
571 		case 4:
572 			*r = z + y;
573 			*g = z;
574 			*b = v;
575 			break;
576 
577 		case 5:
578 			*r = v;
579 			*g = z;
580 			*b = v - y;
581 			break;
582 		}
583 	}
584 }
585 
586 
587 
588 /* rgb_to_hsv:
589  *  Converts an RGB value into the HSV colorspace.
590  */
rgb_to_hsv(int r,int g,int b,float * h,float * s,float * v)591 void rgb_to_hsv(int r, int g, int b, float *h, float *s, float *v) {
592 	int delta;
593 
594 	assert(r >= 0 && r <= 255);
595 	assert(g >= 0 && g <= 255);
596 	assert(b >= 0 && b <= 255);
597 
598 	if (r > g) {
599 		if (b > r) {
600 			/* b>r>g */
601 			delta = b - g;
602 			*h = 240.0f + ((r - g) * 60) / (float)delta;
603 			*s = (float)delta / (float)b;
604 			*v = (float)b * (1.0f / 255.0f);
605 		} else {
606 			/* r>g and r>b */
607 			delta = r - MIN(g, b);
608 			*h = ((g - b) * 60) / (float)delta;
609 			if (*h < 0.0f)
610 				*h += 360.0f;
611 			*s = (float)delta / (float)r;
612 			*v = (float)r * (1.0f / 255.0f);
613 		}
614 	} else {
615 		if (b > g) {
616 			/* b>g>=r */
617 			delta = b - r;
618 			*h = 240.0f + ((r - g) * 60) / (float)delta;
619 			*s = (float)delta / (float)b;
620 			*v = (float)b * (1.0f / 255.0f);
621 		} else {
622 			/* g>=b and g>=r */
623 			delta = g - MIN(r, b);
624 			if (delta == 0) {
625 				*h = 0.0f;
626 				if (g == 0)
627 					*s = *v = 0.0f;
628 				else {
629 					*s = (float)delta / (float)g;
630 					*v = (float)g * (1.0f / 255.0f);
631 				}
632 			} else {
633 				*h = 120.0f + ((b - r) * 60) / (float)delta;
634 				*s = (float)delta / (float)g;
635 				*v = (float)g * (1.0f / 255.0f);
636 			}
637 		}
638 	}
639 }
640 
641 
642 
643 /* create_rgb_table:
644  *  Fills an RGB_MAP lookup table with conversion data for the specified
645  *  palette. This is the faster version by Jan Hubicka.
646  *
647  *  Uses alg. similar to floodfill - it adds one seed per every color in
648  *  palette to its best position. Then areas around seed are filled by
649  *  same color because it is best approximation for them, and then areas
650  *  about them etc...
651  *
652  *  It does just about 80000 tests for distances and this is about 100
653  *  times better than normal 256*32000 tests so the calculation time
654  *  is now less than one second at all computers I tested.
655  */
create_rgb_table(RGB_MAP * table,AL_CONST PALETTE pal,void (* callback)(int pos))656 void create_rgb_table(RGB_MAP *table, AL_CONST PALETTE pal, void (*callback)(int pos)) {
657 #define UNUSED 65535
658 #define LAST 65532
659 
660 	/* macro add adds to single linked list */
661 #define add(i)    (next[(i)] == UNUSED ? (next[(i)] = LAST, \
662                    (first != LAST ? (next[last] = (i)) : (first = (i))), \
663                    (last = (i))) : 0)
664 
665 	/* same but w/o checking for first element */
666 #define add1(i)   (next[(i)] == UNUSED ? (next[(i)] = LAST, \
667                    next[last] = (i), \
668                    (last = (i))) : 0)
669 
670 	/* calculates distance between two colors */
671 #define dist(a1, a2, a3, b1, b2, b3) \
672 	(col_diff[ ((a2) - (b2)) & 0x7F] + \
673 	 (col_diff + 128)[((a1) - (b1)) & 0x7F] + \
674 	 (col_diff + 256)[((a3) - (b3)) & 0x7F])
675 
676 	/* converts r,g,b to position in array and back */
677 #define pos(r, g, b) \
678 	(((r) / 2) * 32 * 32 + ((g) / 2) * 32 + ((b) / 2))
679 
680 #define depos(pal, r, g, b) \
681 	((b) = ((pal) & 31) * 2, \
682 	 (g) = (((pal) >> 5) & 31) * 2, \
683 	 (r) = (((pal) >> 10) & 31) * 2)
684 
685 	/* is current color better than pal1? */
686 #define better(r1, g1, b1, pal1) \
687 	(((int)dist((r1), (g1), (b1), \
688 	            (pal1).r, (pal1).g, (pal1).b)) > (int)dist2)
689 
690 	/* checking of position */
691 #define dopos(rp, gp, bp, ts) \
692 	if ((rp > -1 || r > 0) && (rp < 1 || r < 61) && \
693 	        (gp > -1 || g > 0) && (gp < 1 || g < 61) && \
694 	        (bp > -1 || b > 0) && (bp < 1 || b < 61)) { \
695 		i = first + rp * 32 * 32 + gp * 32 + bp; \
696 		if (!data[i]) { \
697 			data[i] = val; \
698 			add1(i); \
699 		} \
700 		else if ((ts) && (data[i] != val)) { \
701 			dist2 = (rp ? (col_diff+128)[(r+2*rp-pal[val].r) & 0x7F] : r2) + \
702 			        (gp ? (col_diff    )[(g+2*gp-pal[val].g) & 0x7F] : g2) + \
703 			        (bp ? (col_diff+256)[(b+2*bp-pal[val].b) & 0x7F] : b2); \
704 			if (better((r+2*rp), (g+2*gp), (b+2*bp), pal[data[i]])) { \
705 				data[i] = val; \
706 				add1(i); \
707 			} \
708 		} \
709 	}
710 
711 	int i, curr, r, g, b, val, dist2;
712 	unsigned int r2, g2, b2;
713 	unsigned short next[32 * 32 * 32];
714 	unsigned char *data;
715 	int first = LAST;
716 	int last = LAST;
717 	int count = 0;
718 	int cbcount = 0;
719 
720 #define AVERAGE_COUNT   18000
721 
722 	if (col_diff[1] == 0)
723 		bestfit_init();
724 
725 	memset(next, 255, sizeof(next));
726 	memset(table->data, 0, sizeof(char) * 32 * 32 * 32);
727 
728 	data = (unsigned char *)table->data;
729 
730 	/* add starting seeds for floodfill */
731 	for (i = 1; i < PAL_SIZE; i++) {
732 		curr = pos(pal[i].r, pal[i].g, pal[i].b);
733 		if (next[curr] == UNUSED) {
734 			data[curr] = i;
735 			add(curr);
736 		}
737 	}
738 
739 	/* main floodfill: two versions of loop for faster growing in blue axis */
740 	while (first != LAST) {
741 		depos(first, r, g, b);
742 
743 		/* calculate distance of current color */
744 		val = data[first];
745 		r2 = (col_diff + 128)[((pal[val].r) - (r)) & 0x7F];
746 		g2 = (col_diff)[((pal[val].g) - (g)) & 0x7F];
747 		b2 = (col_diff + 256)[((pal[val].b) - (b)) & 0x7F];
748 
749 		/* try to grow to all directions */
750 		dopos(0, 0, 1, 1);
751 		dopos(0, 0, -1, 1);
752 		dopos(1, 0, 0, 1);
753 		dopos(-1, 0, 0, 1);
754 		dopos(0, 1, 0, 1);
755 		dopos(0, -1, 0, 1);
756 
757 		/* faster growing of blue direction */
758 		if ((b > 0) && (data[first - 1] == val)) {
759 			b -= 2;
760 			first--;
761 			b2 = (col_diff + 256)[((pal[val].b) - (b)) & 0x7F];
762 
763 			dopos(-1, 0, 0, 0);
764 			dopos(1, 0, 0, 0);
765 			dopos(0, -1, 0, 0);
766 			dopos(0, 1, 0, 0);
767 
768 			first++;
769 		}
770 
771 		/* get next from list */
772 		i = first;
773 		first = next[first];
774 		next[i] = UNUSED;
775 
776 		/* second version of loop */
777 		if (first != LAST) {
778 			depos(first, r, g, b);
779 
780 			val = data[first];
781 			r2 = (col_diff + 128)[((pal[val].r) - (r)) & 0x7F];
782 			g2 = (col_diff)[((pal[val].g) - (g)) & 0x7F];
783 			b2 = (col_diff + 256)[((pal[val].b) - (b)) & 0x7F];
784 
785 			dopos(0, 0, 1, 1);
786 			dopos(0, 0, -1, 1);
787 			dopos(1, 0, 0, 1);
788 			dopos(-1, 0, 0, 1);
789 			dopos(0, 1, 0, 1);
790 			dopos(0, -1, 0, 1);
791 
792 			if ((b < 61) && (data[first + 1] == val)) {
793 				b += 2;
794 				first++;
795 				b2 = (col_diff + 256)[((pal[val].b) - (b)) & 0x7f];
796 
797 				dopos(-1, 0, 0, 0);
798 				dopos(1, 0, 0, 0);
799 				dopos(0, -1, 0, 0);
800 				dopos(0, 1, 0, 0);
801 
802 				first--;
803 			}
804 
805 			i = first;
806 			first = next[first];
807 			next[i] = UNUSED;
808 		}
809 
810 		count++;
811 		if (count == (cbcount + 1) * AVERAGE_COUNT / 256) {
812 			if (cbcount < 256) {
813 				if (callback)
814 					callback(cbcount);
815 				cbcount++;
816 			}
817 		}
818 	}
819 
820 	/* only the transparent (pink) color can be mapped to index 0 */
821 	if ((pal[0].r == 63) && (pal[0].g == 0) && (pal[0].b == 63))
822 		table->data[31][0][31] = 0;
823 
824 	if (callback)
825 		while (cbcount < 256)
826 			callback(cbcount++);
827 }
828 
829 
830 
831 /* create_light_table:
832  *  Constructs a lighting color table for the specified palette. At light
833  *  intensity 255 the table will produce the palette colors directly, and
834  *  at level 0 it will produce the specified R, G, B value for all colors
835  *  (this is specified in 0-63 VGA format). If the callback function is
836  *  not NULL, it will be called 256 times during the calculation, allowing
837  *  you to display a progress indicator.
838  */
create_light_table(COLOR_MAP * table,AL_CONST PALETTE pal,int r,int g,int b,void (* callback)(int pos))839 void create_light_table(COLOR_MAP *table, AL_CONST PALETTE pal, int r, int g, int b, void (*callback)(int pos)) {
840 	int r1, g1, b1, r2, g2, b2, x, y;
841 	unsigned int t1, t2;
842 
843 	assert(table);
844 	assert(r >= 0 && r <= 63);
845 	assert(g >= 0 && g <= 63);
846 	assert(b >= 0 && b <= 63);
847 
848 	if (_G(rgb_map)) {
849 		for (x = 0; x < PAL_SIZE - 1; x++) {
850 			t1 = x * 0x010101;
851 			t2 = 0xFFFFFF - t1;
852 
853 			r1 = (1 << 24) + r * t2;
854 			g1 = (1 << 24) + g * t2;
855 			b1 = (1 << 24) + b * t2;
856 
857 			for (y = 0; y < PAL_SIZE; y++) {
858 				r2 = (r1 + pal[y].r * t1) >> 25;
859 				g2 = (g1 + pal[y].g * t1) >> 25;
860 				b2 = (b1 + pal[y].b * t1) >> 25;
861 
862 				table->data[x][y] = _G(rgb_map)->data[r2][g2][b2];
863 			}
864 		}
865 		if (callback)
866 			(*callback)(x);
867 	} else {
868 		for (x = 0; x < PAL_SIZE - 1; x++) {
869 			t1 = x * 0x010101;
870 			t2 = 0xFFFFFF - t1;
871 
872 			r1 = (1 << 23) + r * t2;
873 			g1 = (1 << 23) + g * t2;
874 			b1 = (1 << 23) + b * t2;
875 
876 			for (y = 0; y < PAL_SIZE; y++) {
877 				r2 = (r1 + pal[y].r * t1) >> 24;
878 				g2 = (g1 + pal[y].g * t1) >> 24;
879 				b2 = (b1 + pal[y].b * t1) >> 24;
880 
881 				table->data[x][y] = bestfit_color(pal, r2, g2, b2);
882 			}
883 		}
884 
885 		if (callback)
886 			(*callback)(x);
887 	}
888 
889 	for (y = 0; y < PAL_SIZE; y++)
890 		table->data[255][y] = y;
891 }
892 
893 
894 
895 /* create_trans_table:
896  *  Constructs a translucency color table for the specified palette. The
897  *  r, g, and b parameters specifiy the solidity of each color component,
898  *  ranging from 0 (totally transparent) to 255 (totally solid). Source
899  *  color #0 is a special case, and is set to leave the destination
900  *  unchanged, so that masked sprites will draw correctly. If the callback
901  *  function is not NULL, it will be called 256 times during the calculation,
902  *  allowing you to display a progress indicator.
903  */
create_trans_table(COLOR_MAP * table,AL_CONST PALETTE pal,int r,int g,int b,void (* callback)(int pos))904 void create_trans_table(COLOR_MAP *table, AL_CONST PALETTE pal, int r, int g, int b, void (*callback)(int pos)) {
905 	int tmp[768], *q;
906 	int x, y, i, j, k;
907 	unsigned char *p;
908 	int tr, tg, tb;
909 	int add;
910 
911 	assert(table);
912 	assert(r >= 0 && r <= 255);
913 	assert(g >= 0 && g <= 255);
914 	assert(b >= 0 && b <= 255);
915 
916 	/* This is a bit ugly, but accounts for the solidity parameters
917 	   being in the range 0-255 rather than 0-256. Given that the
918 	   precision of r,g,b components is only 6 bits it shouldn't do any
919 	   harm. */
920 	if (r > 128)
921 		r++;
922 	if (g > 128)
923 		g++;
924 	if (b > 128)
925 		b++;
926 
927 	if (_G(rgb_map))
928 		add = 255;
929 	else
930 		add = 127;
931 
932 	for (x = 0; x < 256; x++) {
933 		tmp[x * 3] = pal[x].r * (256 - r) + add;
934 		tmp[x * 3 + 1] = pal[x].g * (256 - g) + add;
935 		tmp[x * 3 + 2] = pal[x].b * (256 - b) + add;
936 	}
937 
938 	for (x = 1; x < PAL_SIZE; x++) {
939 		i = pal[x].r * r;
940 		j = pal[x].g * g;
941 		k = pal[x].b * b;
942 
943 		p = table->data[x];
944 		q = tmp;
945 
946 		if (_G(rgb_map)) {
947 			for (y = 0; y < PAL_SIZE; y++) {
948 				tr = (i + * (q++)) >> 9;
949 				tg = (j + * (q++)) >> 9;
950 				tb = (k + * (q++)) >> 9;
951 				p[y] = _G(rgb_map)->data[tr][tg][tb];
952 			}
953 		} else {
954 			for (y = 0; y < PAL_SIZE; y++) {
955 				tr = (i + * (q++)) >> 8;
956 				tg = (j + * (q++)) >> 8;
957 				tb = (k + * (q++)) >> 8;
958 				p[y] = bestfit_color(pal, tr, tg, tb);
959 			}
960 		}
961 
962 		if (callback)
963 			(*callback)(x - 1);
964 	}
965 
966 	for (y = 0; y < PAL_SIZE; y++) {
967 		table->data[0][y] = y;
968 		table->data[y][y] = y;
969 	}
970 
971 	if (callback)
972 		(*callback)(255);
973 }
974 
975 } // namespace AGS3
976