1 /*
2 * OpenBOR - http://www.LavaLit.com
3 * -----------------------------------------------------------------------
4 * All rights reserved, see LICENSE in OpenBOR root for details.
5 *
6 * Copyright (c) 2004 - 2011 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 #define gammacorrect(v,g) (g<=0?((v*(65025+((255-v)*g)))/65025):(255-(((255-v)*(65025+(v*-g)))/65025)))
46 #define brightnesscorrect(v,b) (b<0?((v*(255+b))/255):(b+((v*(255-b))/255)))
47 #define gbcorrect(vx,gx,bx) (gammacorrect(brightnesscorrect(vx,bx),gx))
48
49
50 // Set gamma/brightness corrected palette.
51 // 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)52 void palette_set_corrected(unsigned char *pal, int gr, int gg, int gb, int br, int bg, int bb){
53 unsigned char pal2[768];
54 int i;
55
56 if(gr<-255) gr = -255;
57 else if(gr>255) gr = 255;
58 if(gg<-255) gg = -255;
59 else if(gg>255) gg = 255;
60 if(gb<-255) gb = -255;
61 else if(gb>255) gb = 255;
62
63 if(br<-255) br = -255;
64 else if(br>255) br = 255;
65 if(bg<-255) bg = -255;
66 else if(bg>255) bg = 255;
67 if(bb<-255) bb = -255;
68 else if(bb>255) bb = 255;
69
70 for(i=0; i<256; i++){
71 pal2[i*3] = gbcorrect(pal[i*3], gr, br);
72 pal2[i*3+1] = gbcorrect(pal[i*3+1], gg, bg);
73 pal2[i*3+2] = gbcorrect(pal[i*3+2], gb, bb);
74 }
75 vga_setpalette(pal2);
76 }
77
78
79
80
81
82 // Search the palette for a colour most like the RGB values specified.
palette_find(unsigned char * pal,int r,int g,int b)83 int palette_find(unsigned char *pal, int r, int g, int b){
84 int i,j;
85 int diff, olddiff, nearindex = 0;
86 int diffred, diffgreen, diffblue;
87
88 olddiff = 1000000; // Set olddiff to an impossibly high value
89
90 for(i=0,j=0; j<256; j++){
91 if((diffred = r-pal[i])<0) diffred = -diffred;
92 ++i;
93 if((diffgreen = g-pal[i])<0) diffgreen = -diffgreen;
94 ++i;
95 if((diffblue = b-pal[i])<0) diffblue = -diffblue;
96 ++i;
97
98 diff = diffred+diffgreen+diffblue;
99
100 if(diff<olddiff){
101 nearindex = j;
102 olddiff = diff;
103 }
104 }
105
106 return nearindex;
107 }
108
109
110
111
112
113 #define multiply(a,b) (a*b/255)
114 #define screen(a,b) (((a^255)*(b^255)/255)^255)
115 #define hardlight(fg,bg) (fg<128?multiply(fg*2,bg):screen((fg-128)*2,bg))
116 #define overlay(fg,bg) (bg<128?multiply(bg*2,fg):screen((bg-128)*2,fg))
117
118
119
120
121
122 // Create a lookup table used for shadows (multiply in photoshop)
palette_table_multiply(unsigned char * pal)123 unsigned char * palette_table_multiply(unsigned char *pal){
124 int fg, bg;
125 int red, green, blue;
126 unsigned char * lut;
127
128 if(pal==NULL) return NULL;
129
130 lut = (unsigned char*)malloc(256*256);
131 if(lut==NULL) return NULL;
132
133 for(fg=0; fg<256; fg++){
134 for(bg=fg; bg<256; bg++){
135 red = pal[bg*3] * pal[fg*3] / 255;
136 green = pal[bg*3+1] * pal[fg*3+1] / 255;
137 blue = pal[bg*3+2] * pal[fg*3+2] / 255;
138
139 lut[(fg<<8)+bg] = palette_find(pal, red, green, blue);
140 lut[(bg<<8)+fg] = lut[(fg<<8)+bg];
141 }
142 }
143 return lut;
144 }
145
146
147
148
149
150 // Create a lookup table for 'screen'
palette_table_screen(unsigned char * pal)151 unsigned char * palette_table_screen(unsigned char *pal){
152 int fg, bg;
153 int red, green, blue;
154 unsigned char * lut;
155
156 if(pal==NULL) return NULL;
157
158 lut = (unsigned char*)malloc(256*256);
159 if(lut==NULL) return NULL;
160
161 for(fg=0; fg<256; fg++){
162 for(bg=fg; bg<256; bg++){
163 red = ((pal[fg*3] * (255 - pal[bg*3])) / 255) + pal[bg*3];
164 green = ((pal[fg*3+1] * (255 - pal[bg*3+1])) / 255) + pal[bg*3+1];
165 blue = ((pal[fg*3+2] * (255 - pal[bg*3+2])) / 255) + pal[bg*3+2];
166
167 lut[(fg<<8)+bg] = palette_find(pal, red, green, blue);
168 lut[(bg<<8)+fg] = lut[(fg<<8)+bg];
169 }
170 }
171 return lut;
172 }
173
174
175
176
177
178 // Create "overlay" lookup table (multiply and screen combined)
palette_table_overlay(unsigned char * pal)179 unsigned char * palette_table_overlay(unsigned char *pal){
180 int fg, bg;
181 int red, green, blue;
182 unsigned char * lut;
183
184 if(pal==NULL) return NULL;
185
186 lut = (unsigned char*)malloc(256*256);
187 if(lut==NULL) return NULL;
188
189 for(fg=0; fg<256; fg++){
190 for(bg=fg; bg<256; bg++){
191 red = overlay(pal[bg*3], pal[fg*3]);
192 green = overlay(pal[bg*3+1], pal[fg*3+1]);
193 blue = overlay(pal[bg*3+2], pal[fg*3+2]);
194
195 lut[(fg<<8)+bg] = palette_find(pal, red, green, blue);
196 lut[(bg<<8)+fg] = lut[(fg<<8)+bg];
197 }
198 }
199 return lut;
200 }
201
202
203 // Create "hard light" lookup table (multiply and screen combined)
palette_table_hardlight(unsigned char * pal)204 unsigned char * palette_table_hardlight(unsigned char *pal){
205 int fg, bg;
206 int red, green, blue;
207 unsigned char * lut;
208
209 if(pal==NULL) return NULL;
210
211 lut = (unsigned char*)malloc(256*256);
212 if(lut==NULL) return NULL;
213
214 for(fg=0; fg<256; fg++){
215 for(bg=fg; bg<256; bg++){
216 red = hardlight(pal[bg*3], pal[fg*3]);
217 green = hardlight(pal[bg*3+1], pal[fg*3+1]);
218 blue = hardlight(pal[bg*3+2], pal[fg*3+2]);
219
220 lut[(fg<<8)+bg] = palette_find(pal, red, green, blue);
221 lut[(bg<<8)+fg] = lut[(fg<<8)+bg];
222 }
223 }
224 return lut;
225 }
226
227
228
229 // Create a lookup table for "dodge".
230 // Very nice for a colourful boost of light.
palette_table_dodge(unsigned char * pal)231 unsigned char * palette_table_dodge(unsigned char *pal){
232 int fg, bg;
233 int c1, c2;
234 int t1, t2;
235 int red, green, blue;
236 unsigned char * lut;
237
238 if(pal==NULL) return NULL;
239
240 lut = (unsigned char*)malloc(256*256);
241 if(lut==NULL) return NULL;
242
243
244 for(fg=0, c2=0; fg<256; fg++, c2+=3){
245 for(bg=0, c1=0; bg<256; bg++){
246 t2 = pal[c2];
247 t1 = pal[c1++];
248 red = (t1 * 256) / (256 - t2);
249 if(red>255) red = 255;
250
251 t2 = pal[c2+1];
252 t1 = pal[c1++];
253 green = (t1 * 256) / (256 - t2);
254 if(green>255) green = 255;
255
256 t2 = pal[c2+2];
257 t1 = pal[c1++];
258 blue = (t1 * 256) / (256 - t2);
259 if(blue>255) blue = 255;
260
261 lut[(fg<<8)+bg] = palette_find(pal, red, green, blue);
262 }
263 }
264 return lut;
265 }
266
267
268
269
270
271 // Create a lookup table for 50% opacity
palette_table_half(unsigned char * pal)272 unsigned char * palette_table_half(unsigned char *pal){
273 int fg, bg;
274 int red, green, blue;
275 unsigned char * lut;
276 int dither = 0;
277
278 if(pal==NULL) return NULL;
279
280 lut = (unsigned char*)malloc(256*256);
281 if(lut==NULL) return NULL;
282
283 for(fg=0; fg<256; fg++){
284 for(bg=fg; bg<256; bg++){
285 red = (pal[bg*3] + pal[fg*3] + (++dither&1)) / 2;
286 green = (pal[bg*3+1] + pal[fg*3+1] + (++dither&1)) / 2;
287 blue = (pal[bg*3+2] + pal[fg*3+2] + (++dither&1)) / 2;
288
289 lut[(fg<<8)+bg] = palette_find(pal, red, green, blue);
290 lut[(bg<<8)+fg] = lut[(fg<<8)+bg];
291 }
292 }
293 return lut;
294 }
295