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