xref: /haiku/src/servers/app/RGBColor.cpp (revision b55a57da7173b9af0432bd3e148d03f06161d036)
1 /*
2  * Copyright 2001-2006, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		DarkWyrm <bpmagic@columbus.rr.com>
7  */
8 
9 
10 #include "RGBColor.h"
11 #include "SystemPalette.h"
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 
16 
17 /*!
18 	\brief An approximation of 31/255, which is needed for converting from 32-bit
19 		colors to 16-bit and 15-bit.
20 */
21 #define RATIO_8_TO_5_BIT .121568627451
22 
23 /*!
24 	\brief An approximation of 63/255, which is needed for converting from 32-bit
25 		colors to 16-bit.
26 */
27 #define RATIO_8_TO_6_BIT .247058823529
28 
29 /*!
30 	\brief An approximation of 255/31, which is needed for converting from 16-bit
31 		and 15-bit colors to 32-bit.
32 */
33 #define RATIO_5_TO_8_BIT 8.22580645161
34 
35 /*!
36 	\brief An approximation of 255/63, which is needed for converting from 16-bit
37 		colors to 32-bit.
38 */
39 #define RATIO_6_TO_8_BIT 4.04761904762
40 
41 #if 0
42 /*!
43 	\brief Function for easy conversion of 16-bit colors to 32-bit
44 	\param col Pointer to an rgb_color.
45 	\param color RGB16 color
46 
47 	This function will do nothing if passed a NULL 32-bit color.
48 */
49 void
50 SetRGBColor16(rgb_color *col,uint16 color)
51 {
52 	if(!col)
53 		return;
54 
55 	uint16 r16,g16,b16;
56 
57 	// alpha's the easy part
58 	col->alpha=0;
59 
60 	r16= (color >> 11) & 31;
61 	g16= (color >> 5) & 63;
62 	b16= color & 31;
63 
64 	col->red=uint8(r16 * RATIO_5_TO_8_BIT);
65 	col->green=uint8(g16 * RATIO_6_TO_8_BIT);
66 	col->blue=uint8(b16 * RATIO_5_TO_8_BIT);
67 }
68 #endif
69 
70 /*!
71 	\brief Finds the index of the closest matching color in a rgb_color palette array
72 	\param palette Array of 256 rgb_color objects
73 	\param color Color to match
74 	\return Index of the closest matching color
75 
76 	Note that passing a NULL palette will always return 0 and passing an array of less
77 	than 256 rgb_colors will cause a crash.
78 */
79 static uint8
80 FindClosestColor(const rgb_color *palette, rgb_color color)
81 {
82 	if (!palette)
83 		return 0;
84 
85 	uint16 cindex = 0, cdelta = 765, delta = 765;
86 
87 	for (uint16 i = 0; i < 256; i++) {
88 		const rgb_color *c = &(palette[i]);
89 		delta = abs(c->red-color.red) + abs(c->green-color.green)
90 			+ abs(c->blue-color.blue);
91 
92 		if (delta == 0) {
93 			cindex = i;
94 			break;
95 		}
96 
97 		if (delta < cdelta) {
98 			cindex = i;
99 			cdelta = delta;
100 		}
101 	}
102 
103 	return (uint8)cindex;
104 }
105 
106 
107 /*!
108 	\brief Constructs a RGBA15 color which best matches a given 32-bit color
109 	\param color Color to match
110 	\return The closest matching color's value
111 
112 	Format is ARGB, 1:5:5:5
113 */
114 static uint16
115 FindClosestColor15(rgb_color color)
116 {
117 	uint16 r16 = uint16(color.red * RATIO_8_TO_5_BIT);
118 	uint16 g16 = uint16(color.green * RATIO_8_TO_5_BIT);
119 	uint16 b16 = uint16(color.blue * RATIO_8_TO_5_BIT);
120 
121 	// start with alpha value
122 	uint16 color16 = color.alpha > 127 ? 0x8000 : 0;
123 
124 	color16 |= r16 << 10;
125 	color16 |= g16 << 5;
126 	color16 |= b16;
127 
128 	return color16;
129 }
130 
131 
132 /*!
133 	\brief Constructs a RGB16 color which best matches a given 32-bit color
134 	\param color Color to match
135 	\return The closest matching color's value
136 
137 	Format is RGB, 5:6:5
138 */
139 static uint16
140 FindClosestColor16(rgb_color color)
141 {
142 	uint16 r16 = uint16(color.red * RATIO_8_TO_5_BIT);
143 	uint16 g16 = uint16(color.green * RATIO_8_TO_6_BIT);
144 	uint16 b16 = uint16(color.blue * RATIO_8_TO_5_BIT);
145 
146 	uint16 color16 = r16 << 11;
147 	color16 |= g16 << 5;
148 	color16 |= b16;
149 
150 	return color16;
151 }
152 
153 
154 //	#pragma mark -
155 
156 
157 /*!
158 	\brief Create an RGBColor from specified values
159 	\param red red
160 	\param green green
161 	\param blue blue
162 	\param alpha alpha, defaults to 255
163 */
164 RGBColor::RGBColor(uint8 r, uint8 g, uint8 b, uint8 a)
165 {
166 	SetColor(r,g,b,a);
167 }
168 
169 
170 /*!
171 	\brief Create an RGBColor from specified values
172 	\param red red
173 	\param green green
174 	\param blue blue
175 	\param alpha alpha, defaults to 255
176 */
177 RGBColor::RGBColor(int r, int g, int b, int a)
178 {
179 	SetColor(r, g, b, a);
180 }
181 
182 
183 /*!
184 	\brief Create an RGBColor from an rgb_color
185 	\param color color to initialize from
186 */
187 RGBColor::RGBColor(const rgb_color &color)
188 {
189 	SetColor(color);
190 }
191 
192 #if 0
193 /*!
194 	\brief Create an RGBColor from a 16-bit RGBA color
195 	\param color color to initialize from
196 */
197 RGBColor::RGBColor(uint16 color)
198 {
199 	SetColor(color);
200 }
201 #endif
202 
203 /*!
204 	\brief Create an RGBColor from an index color
205 	\param color color to initialize from
206 */
207 RGBColor::RGBColor(uint8 color)
208 {
209 	SetColor(color);
210 }
211 
212 
213 /*!
214 	\brief Copy Contructor
215 	\param color color to initialize from
216 */
217 RGBColor::RGBColor(const RGBColor &color)
218 {
219 	fColor32 = color.fColor32;
220 	fColor16 = color.fColor16;
221 	fColor8 = color.fColor8;
222 	fUpdate8 = color.fUpdate8;
223 	fUpdate16 = color.fUpdate16;
224 }
225 
226 
227 /*!
228 	\brief Create an RGBColor with the values(0,0,0,0)
229 */
230 RGBColor::RGBColor()
231 {
232 	SetColor(0, 0, 0, 0);
233 }
234 
235 
236 /*!
237 	\brief Returns the color as the closest 8-bit color in the palette
238 	\return The palette index for the current color
239 */
240 uint8
241 RGBColor::GetColor8() const
242 {
243 	if (fUpdate8) {
244 		fColor8 = FindClosestColor(SystemPalette(), fColor32);
245 		fUpdate8 = false;
246 	}
247 
248 	return fColor8;
249 }
250 
251 
252 /*!
253 	\brief Returns the color as the closest 15-bit color
254 	\return 15-bit value of the current color plus 1-bit alpha
255 */
256 uint16
257 RGBColor::GetColor15() const
258 {
259 	if (fUpdate15) {
260 		fColor15 = FindClosestColor15(fColor32);
261 		fUpdate15 = false;
262 	}
263 
264 	return fColor15;
265 }
266 
267 
268 /*!
269 	\brief Returns the color as the closest 16-bit color
270 	\return 16-bit value of the current color
271 */
272 uint16
273 RGBColor::GetColor16() const
274 {
275 	if (fUpdate16) {
276 		fColor16 = FindClosestColor16(fColor32);
277 		fUpdate16 = false;
278 	}
279 
280 	return fColor16;
281 }
282 
283 
284 /*!
285 	\brief Returns the color as a 32-bit color
286 	\return current color, including alpha
287 */
288 rgb_color
289 RGBColor::GetColor32() const
290 {
291 	return fColor32;
292 }
293 
294 
295 /*!
296 	\brief Set the object to specified values
297 	\param red red
298 	\param green green
299 	\param blue blue
300 	\param alpha alpha, defaults to 255
301 */
302 void
303 RGBColor::SetColor(uint8 r, uint8 g, uint8 b, uint8 a)
304 {
305 	fColor32.red = r;
306 	fColor32.green = g;
307 	fColor32.blue = b;
308 	fColor32.alpha = a;
309 
310 	fUpdate8 = fUpdate16 = true;
311 }
312 
313 
314 /*!
315 	\brief Set the object to specified values
316 	\param red red
317 	\param green green
318 	\param blue blue
319 	\param alpha alpha, defaults to 255
320 */
321 void
322 RGBColor::SetColor(int r, int g, int b, int a)
323 {
324 	fColor32.red = (uint8)r;
325 	fColor32.green = (uint8)g;
326 	fColor32.blue = (uint8)b;
327 	fColor32.alpha = (uint8)a;
328 
329 	fUpdate8 = fUpdate16 = true;
330 }
331 
332 #if 0
333 /*!
334 	\brief Set the object to specified value
335 	\param col16 color to copy
336 */
337 void
338 RGBColor::SetColor(uint16 col16)
339 {
340 	fColor16 = col16;
341 	SetRGBColor(&fColor32,col16);
342 
343 	fUpdate8 = true;
344 	fUpdate16 = false;
345 }
346 #endif
347 
348 
349 /*!
350 	\brief Set the object to specified index in the palette
351 	\param col8 color to copy
352 */
353 void
354 RGBColor::SetColor(uint8 col8)
355 {
356 	fColor8 = col8;
357 	fColor32 = SystemPalette()[col8];
358 
359 	fUpdate8 = false;
360 	fUpdate16 = true;
361 }
362 
363 
364 /*!
365 	\brief Set the object to specified color
366 	\param color color to copy
367 */
368 void
369 RGBColor::SetColor(const rgb_color &color)
370 {
371 	fColor32 = color;
372 	fUpdate8 = fUpdate16 = true;
373 }
374 
375 
376 /*!
377 	\brief Set the object to specified color
378 	\param color color to copy
379 */
380 void
381 RGBColor::SetColor(const RGBColor &color)
382 {
383 	fColor32 = color.fColor32;
384 	fColor16 = color.fColor16;
385 	fColor8 = color.fColor8;
386 	fUpdate8 = color.fUpdate8;
387 	fUpdate16 = color.fUpdate16;
388 }
389 
390 
391 /*!
392 	\brief Set the object to specified color
393 	\param color color to copy
394 */
395 const RGBColor&
396 RGBColor::operator=(const RGBColor &color)
397 {
398 	fColor32 = color.fColor32;
399 	fColor16 = color.fColor16;
400 	fColor8 = color.fColor8;
401 	fUpdate8 = color.fUpdate8;
402 	fUpdate16 = color.fUpdate16;
403 
404 	return *this;
405 }
406 
407 
408 /*!
409 	\brief Set the object to specified color
410 	\param color color to copy
411 */
412 const RGBColor&
413 RGBColor::operator=(const rgb_color &color)
414 {
415 	fColor32 = color;
416 	fUpdate8 = fUpdate16 = true;
417 
418 	return *this;
419 }
420 
421 
422 /*!
423 	\brief Prints the 32-bit values of the color to standard out
424 */
425 void
426 RGBColor::PrintToStream(void) const
427 {
428 	printf("RGBColor(%u,%u,%u,%u)\n",
429 		fColor32.red, fColor32.green, fColor32.blue, fColor32.alpha);
430 }
431 
432 
433 /*!
434 	\brief Overloaded comaparison
435 	\return true if all color elements are exactly equal
436 */
437 bool
438 RGBColor::operator==(const rgb_color &color) const
439 {
440 	return fColor32.red == color.red
441 		&& fColor32.green == color.green
442 		&& fColor32.blue == color.blue
443 		&& fColor32.alpha == color.alpha;
444 }
445 
446 
447 /*!
448 	\brief Overloaded comaparison
449 	\return true if all color elements are exactly equal
450 */
451 bool
452 RGBColor::operator==(const RGBColor &color) const
453 {
454 	return fColor32.red == color.fColor32.red
455 		&& fColor32.green == color.fColor32.green
456 		&& fColor32.blue == color.fColor32.blue
457 		&& fColor32.alpha == color.fColor32.alpha;
458 }
459 
460 
461 bool
462 RGBColor::operator!=(const rgb_color &color) const
463 {
464 	return fColor32.red != color.red
465 		|| fColor32.green != color.green
466 		|| fColor32.blue != color.blue
467 		|| fColor32.alpha != color.alpha;
468 }
469 
470 
471 bool
472 RGBColor::operator!=(const RGBColor &color) const
473 {
474 	return fColor32.red != color.fColor32.red
475 		|| fColor32.green != color.fColor32.green
476 		|| fColor32.blue != color.fColor32.blue
477 		|| fColor32.alpha != color.fColor32.alpha;
478 }
479 
480 
481 bool
482 RGBColor::IsTransparentMagic() const
483 {
484 	// TODO: validate this for B_CMAP8 for example
485 	return *this == B_TRANSPARENT_COLOR;
486 }
487