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