1 /*
2  * OpenBOR - http://www.chronocrash.com
3  * -----------------------------------------------------------------------
4  * All rights reserved, see LICENSE in OpenBOR root for details.
5  *
6  * Copyright (c) 2004 - 2014 OpenBOR Team
7  */
8 
9 /*
10 	Code to fiddle about with palettes.
11 
12 	This file features code for:
13 	palette search for RGB values
14 	creation of lookup tables
15 
16 	Lookup tables must be formatted so that a single foreground colour
17 	can be used to find an array of background colours:
18 	new = lookup[(fg<<8)+bg]
19 	bg_array = lookup + (fg<<8);
20 
21 
22 	Last update: 27-jan-2003
23 */
24 
25 #include "vga.h"
26 #include "palette.h"
27 
28 
29 #ifndef NULL
30 #define NULL 0L
31 #endif
32 
33 
34 // Basic bamma correction: ((v*(255+(((255-v)*(g-255))/255)))/255)
35 //			= ((v*(65025+((255-v)*(g-255))))/65025)
36 // Basic brightness correction: (b+((v*(255-b))/255))
37 
38 // Gamma correction, range -255 to 255:
39 // (g<=0?((v*(65025+((255-v)*g)))/65025):(255-(((255-v)*(65025+(v*-g)))/65025)))
40 
41 // Brightness correction, same range:
42 // b<0 ? ((v*(255+b))/255) : (b+((v*(255-b))/255))
43 
44 
45 // Set gamma/brightness corrected palette.
46 // Valid values range between -255 and 255, where 0 is normal.
palette_set_corrected(unsigned char * pal,int gr,int gg,int gb,int br,int bg,int bb)47 void palette_set_corrected(unsigned char *pal, int gr, int gg, int gb, int br, int bg, int bb)
48 {
49     unsigned char pal2[768];
50     int i;
51 
52     if(gr < -255)
53     {
54         gr = -255;
55     }
56     else if(gr > 255)
57     {
58         gr = 255;
59     }
60     if(gg < -255)
61     {
62         gg = -255;
63     }
64     else if(gg > 255)
65     {
66         gg = 255;
67     }
68     if(gb < -255)
69     {
70         gb = -255;
71     }
72     else if(gb > 255)
73     {
74         gb = 255;
75     }
76 
77     if(br < -255)
78     {
79         br = -255;
80     }
81     else if(br > 255)
82     {
83         br = 255;
84     }
85     if(bg < -255)
86     {
87         bg = -255;
88     }
89     else if(bg > 255)
90     {
91         bg = 255;
92     }
93     if(bb < -255)
94     {
95         bb = -255;
96     }
97     else if(bb > 255)
98     {
99         bb = 255;
100     }
101 
102     for(i = 0; i < 256; i++)
103     {
104         pal2[i * 3] =   gbcorrect(pal[i * 3],   gr, br);
105         pal2[i * 3 + 1] = gbcorrect(pal[i * 3 + 1], gg, bg);
106         pal2[i * 3 + 2] = gbcorrect(pal[i * 3 + 2], gb, bb);
107     }
108     vga_setpalette(pal2);
109 }
110 
111 
112 
113 
114 
115 // Search the palette for a colour most like the RGB values specified.
palette_find(unsigned char * pal,int r,int g,int b)116 int palette_find(unsigned char *pal, int r, int g, int b)
117 {
118     int i, j;
119     int diff, olddiff, nearindex = 0;
120     int diffred, diffgreen, diffblue;
121 
122     olddiff = 1000000;	// Set olddiff to an impossibly high value
123 
124     for(i = 0, j = 0; j < 256; j++)
125     {
126         if((diffred = r - pal[i]) < 0)
127         {
128             diffred = -diffred;
129         }
130         ++i;
131         if((diffgreen = g - pal[i]) < 0)
132         {
133             diffgreen = -diffgreen;
134         }
135         ++i;
136         if((diffblue = b - pal[i]) < 0)
137         {
138             diffblue = -diffblue;
139         }
140         ++i;
141 
142         diff = diffred + diffgreen + diffblue;
143 
144         if(diff < olddiff)
145         {
146             nearindex = j;
147             olddiff = diff;
148         }
149     }
150 
151     return nearindex;
152 }
153 
154 
155 
156 
157 
158 #define		multiply(a,b)		(a*b/255)
159 #define		screen(a,b)		(((a^255)*(b^255)/255)^255)
160 #define		hardlight(fg,bg)	(fg<128?multiply(fg*2,bg):screen((fg-128)*2,bg))
161 #define		overlay(fg,bg)		(bg<128?multiply(bg*2,fg):screen((bg-128)*2,fg))
162 
163 
164 
165 
166 
167 // Create a lookup table used for shadows (multiply in photoshop)
palette_table_multiply(unsigned char * pal)168 unsigned char *palette_table_multiply(unsigned char *pal)
169 {
170     int fg, bg;
171     int red, green, blue;
172     unsigned char *lut;
173 
174     if(pal == NULL)
175     {
176         return NULL;
177     }
178 
179     lut = (unsigned char *)malloc(256 * 256);
180     if(lut == NULL)
181     {
182         return NULL;
183     }
184 
185     for(fg = 0; fg < 256; fg++)
186     {
187         for(bg = fg; bg < 256; bg++)
188         {
189             red = pal[bg * 3] * pal[fg * 3] / 255;
190             green = pal[bg * 3 + 1] * pal[fg * 3 + 1] / 255;
191             blue = pal[bg * 3 + 2] * pal[fg * 3 + 2] / 255;
192 
193             lut[(fg << 8) + bg] = palette_find(pal, red, green, blue);
194             lut[(bg << 8) + fg] = lut[(fg << 8) + bg];
195         }
196     }
197     return lut;
198 }
199 
200 
201 
202 
203 
204 // Create a lookup table for 'screen'
palette_table_screen(unsigned char * pal)205 unsigned char *palette_table_screen(unsigned char *pal)
206 {
207     int fg, bg;
208     int red, green, blue;
209     unsigned char *lut;
210 
211     if(pal == NULL)
212     {
213         return NULL;
214     }
215 
216     lut = (unsigned char *)malloc(256 * 256);
217     if(lut == NULL)
218     {
219         return NULL;
220     }
221 
222     for(fg = 0; fg < 256; fg++)
223     {
224         for(bg = fg; bg < 256; bg++)
225         {
226             red =   ((pal[fg * 3] * (255 - pal[bg * 3])) / 255) + pal[bg * 3];
227             green = ((pal[fg * 3 + 1] * (255 - pal[bg * 3 + 1])) / 255) + pal[bg * 3 + 1];
228             blue =  ((pal[fg * 3 + 2] * (255 - pal[bg * 3 + 2])) / 255) + pal[bg * 3 + 2];
229 
230             lut[(fg << 8) + bg] = palette_find(pal, red, green, blue);
231             lut[(bg << 8) + fg] = lut[(fg << 8) + bg];
232         }
233     }
234     return lut;
235 }
236 
237 
238 
239 
240 
241 // Create "overlay" lookup table (multiply and screen combined)
palette_table_overlay(unsigned char * pal)242 unsigned char *palette_table_overlay(unsigned char *pal)
243 {
244     int fg, bg;
245     int red, green, blue;
246     unsigned char *lut;
247 
248     if(pal == NULL)
249     {
250         return NULL;
251     }
252 
253     lut = (unsigned char *)malloc(256 * 256);
254     if(lut == NULL)
255     {
256         return NULL;
257     }
258 
259     for(fg = 0; fg < 256; fg++)
260     {
261         for(bg = fg; bg < 256; bg++)
262         {
263             red = overlay(pal[bg * 3], pal[fg * 3]);
264             green = overlay(pal[bg * 3 + 1], pal[fg * 3 + 1]);
265             blue = overlay(pal[bg * 3 + 2], pal[fg * 3 + 2]);
266 
267             lut[(fg << 8) + bg] = palette_find(pal, red, green, blue);
268             lut[(bg << 8) + fg] = lut[(fg << 8) + bg];
269         }
270     }
271     return lut;
272 }
273 
274 
275 // Create "hard light" lookup table (multiply and screen combined)
palette_table_hardlight(unsigned char * pal)276 unsigned char *palette_table_hardlight(unsigned char *pal)
277 {
278     int fg, bg;
279     int red, green, blue;
280     unsigned char *lut;
281 
282     if(pal == NULL)
283     {
284         return NULL;
285     }
286 
287     lut = (unsigned char *)malloc(256 * 256);
288     if(lut == NULL)
289     {
290         return NULL;
291     }
292 
293     for(fg = 0; fg < 256; fg++)
294     {
295         for(bg = fg; bg < 256; bg++)
296         {
297             red = hardlight(pal[bg * 3], pal[fg * 3]);
298             green = hardlight(pal[bg * 3 + 1], pal[fg * 3 + 1]);
299             blue = hardlight(pal[bg * 3 + 2], pal[fg * 3 + 2]);
300 
301             lut[(fg << 8) + bg] = palette_find(pal, red, green, blue);
302             lut[(bg << 8) + fg] = lut[(fg << 8) + bg];
303         }
304     }
305     return lut;
306 }
307 
308 
309 
310 // Create a lookup table for "dodge".
311 // Very nice for a colourful boost of light.
palette_table_dodge(unsigned char * pal)312 unsigned char *palette_table_dodge(unsigned char *pal)
313 {
314     int fg, bg;
315     int c1, c2;
316     int t1, t2;
317     int red, green, blue;
318     unsigned char *lut;
319 
320     if(pal == NULL)
321     {
322         return NULL;
323     }
324 
325     lut = (unsigned char *)malloc(256 * 256);
326     if(lut == NULL)
327     {
328         return NULL;
329     }
330 
331 
332     for(fg = 0, c2 = 0; fg < 256; fg++, c2 += 3)
333     {
334         for(bg = 0, c1 = 0; bg < 256; bg++)
335         {
336             t2 = pal[c2];
337             t1 = pal[c1++];
338             red = (t1 * 256) / (256 - t2);
339             if(red > 255)
340             {
341                 red = 255;
342             }
343 
344             t2 = pal[c2 + 1];
345             t1 = pal[c1++];
346             green = (t1 * 256) / (256 - t2);
347             if(green > 255)
348             {
349                 green = 255;
350             }
351 
352             t2 = pal[c2 + 2];
353             t1 = pal[c1++];
354             blue = (t1 * 256) / (256 - t2);
355             if(blue > 255)
356             {
357                 blue = 255;
358             }
359 
360             lut[(fg << 8) + bg] = palette_find(pal, red, green, blue);
361         }
362     }
363     return lut;
364 }
365 
366 
367 
368 
369 
370 // Create a lookup table for 50% opacity
palette_table_half(unsigned char * pal)371 unsigned char *palette_table_half(unsigned char *pal)
372 {
373     int fg, bg;
374     int red, green, blue;
375     unsigned char *lut;
376     int dither = 0;
377 
378     if(pal == NULL)
379     {
380         return NULL;
381     }
382 
383     lut = (unsigned char *)malloc(256 * 256);
384     if(lut == NULL)
385     {
386         return NULL;
387     }
388 
389     for(fg = 0; fg < 256; fg++)
390     {
391         for(bg = fg; bg < 256; bg++)
392         {
393             red = (pal[bg * 3] + pal[fg * 3] + (++dither & 1)) / 2;
394             green = (pal[bg * 3 + 1] + pal[fg * 3 + 1] + (++dither & 1)) / 2;
395             blue = (pal[bg * 3 + 2] + pal[fg * 3 + 2] + (++dither & 1)) / 2;
396 
397             lut[(fg << 8) + bg] = palette_find(pal, red, green, blue);
398             lut[(bg << 8) + fg] = lut[(fg << 8) + bg];
399         }
400     }
401     return lut;
402 }
403