xref: /haiku/src/servers/app/RGBColor.cpp (revision aa8219391fcf054df81e4c281e2785f041f47aad)
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
FindClosestColor(const rgb_color * palette,rgb_color color)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
FindClosestColor15(rgb_color color)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
FindClosestColor16(rgb_color color)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 */
RGBColor(uint8 r,uint8 g,uint8 b,uint8 a)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 */
RGBColor(int r,int g,int b,int a)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 */
RGBColor(const rgb_color & color)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 */
RGBColor(uint8 color)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 */
RGBColor(const RGBColor & color)217 RGBColor::RGBColor(const RGBColor &color)
218 {
219 	fColor32 = color.fColor32;
220 	fColor16 = color.fColor16;
221 	fColor15 = color.fColor15;
222 	fColor8 = color.fColor8;
223 	fUpdate8 = color.fUpdate8;
224 	fUpdate15 = color.fUpdate15;
225 	fUpdate16 = color.fUpdate16;
226 }
227 
228 
229 /*!
230 	\brief Create an RGBColor with the values(0,0,0,0)
231 */
RGBColor()232 RGBColor::RGBColor()
233 {
234 	SetColor(0, 0, 0, 0);
235 }
236 
237 
238 /*!
239 	\brief Returns the color as the closest 8-bit color in the palette
240 	\return The palette index for the current color
241 */
242 uint8
GetColor8() const243 RGBColor::GetColor8() const
244 {
245 	if (fUpdate8) {
246 		fColor8 = FindClosestColor(SystemPalette(), fColor32);
247 		fUpdate8 = false;
248 	}
249 
250 	return fColor8;
251 }
252 
253 
254 /*!
255 	\brief Returns the color as the closest 15-bit color
256 	\return 15-bit value of the current color plus 1-bit alpha
257 */
258 uint16
GetColor15() const259 RGBColor::GetColor15() const
260 {
261 	if (fUpdate15) {
262 		fColor15 = FindClosestColor15(fColor32);
263 		fUpdate15 = false;
264 	}
265 
266 	return fColor15;
267 }
268 
269 
270 /*!
271 	\brief Returns the color as the closest 16-bit color
272 	\return 16-bit value of the current color
273 */
274 uint16
GetColor16() const275 RGBColor::GetColor16() const
276 {
277 	if (fUpdate16) {
278 		fColor16 = FindClosestColor16(fColor32);
279 		fUpdate16 = false;
280 	}
281 
282 	return fColor16;
283 }
284 
285 
286 /*!
287 	\brief Returns the color as a 32-bit color
288 	\return current color, including alpha
289 */
290 rgb_color
GetColor32() const291 RGBColor::GetColor32() const
292 {
293 	return fColor32;
294 }
295 
296 
297 /*!
298 	\brief Set the object to specified values
299 	\param red red
300 	\param green green
301 	\param blue blue
302 	\param alpha alpha, defaults to 255
303 */
304 void
SetColor(uint8 r,uint8 g,uint8 b,uint8 a)305 RGBColor::SetColor(uint8 r, uint8 g, uint8 b, uint8 a)
306 {
307 	fColor32.red = r;
308 	fColor32.green = g;
309 	fColor32.blue = b;
310 	fColor32.alpha = a;
311 
312 	fUpdate8 = fUpdate15 = fUpdate16 = true;
313 }
314 
315 
316 /*!
317 	\brief Set the object to specified values
318 	\param red red
319 	\param green green
320 	\param blue blue
321 	\param alpha alpha, defaults to 255
322 */
323 void
SetColor(int r,int g,int b,int a)324 RGBColor::SetColor(int r, int g, int b, int a)
325 {
326 	fColor32.red = (uint8)r;
327 	fColor32.green = (uint8)g;
328 	fColor32.blue = (uint8)b;
329 	fColor32.alpha = (uint8)a;
330 
331 	fUpdate8 = fUpdate15 = fUpdate16 = true;
332 }
333 
334 #if 0
335 /*!
336 	\brief Set the object to specified value
337 	\param col16 color to copy
338 */
339 void
340 RGBColor::SetColor(uint16 col16)
341 {
342 	fColor16 = col16;
343 	SetRGBColor(&fColor32, col16);
344 
345 	fUpdate8 = true;
346 	fUpdate15 = true;
347 	fUpdate16 = false;
348 }
349 #endif
350 
351 
352 /*!
353 	\brief Set the object to specified index in the palette
354 	\param col8 color to copy
355 */
356 void
SetColor(uint8 col8)357 RGBColor::SetColor(uint8 col8)
358 {
359 	fColor8 = col8;
360 	fColor32 = SystemPalette()[col8];
361 
362 	fUpdate8 = false;
363 	fUpdate15 = true;
364 	fUpdate16 = true;
365 }
366 
367 
368 /*!
369 	\brief Set the object to specified color
370 	\param color color to copy
371 */
372 void
SetColor(const rgb_color & color)373 RGBColor::SetColor(const rgb_color &color)
374 {
375 	fColor32 = color;
376 	fUpdate8 = fUpdate15 = fUpdate16 = true;
377 }
378 
379 
380 /*!
381 	\brief Set the object to specified color
382 	\param color color to copy
383 */
384 void
SetColor(const RGBColor & color)385 RGBColor::SetColor(const RGBColor &color)
386 {
387 	fColor32 = color.fColor32;
388 	fColor16 = color.fColor16;
389 	fColor15 = color.fColor15;
390 	fColor8 = color.fColor8;
391 	fUpdate8 = color.fUpdate8;
392 	fUpdate15 = color.fUpdate15;
393 	fUpdate16 = color.fUpdate16;
394 }
395 
396 
397 /*!
398 	\brief Set the object to specified color
399 	\param color color to copy
400 */
401 const RGBColor&
operator =(const RGBColor & color)402 RGBColor::operator=(const RGBColor &color)
403 {
404 	fColor32 = color.fColor32;
405 	fColor16 = color.fColor16;
406 	fColor15 = color.fColor15;
407 	fColor8 = color.fColor8;
408 	fUpdate8 = color.fUpdate8;
409 	fUpdate15 = color.fUpdate15;
410 	fUpdate16 = color.fUpdate16;
411 
412 	return *this;
413 }
414 
415 
416 /*!
417 	\brief Set the object to specified color
418 	\param color color to copy
419 */
420 const RGBColor&
operator =(const rgb_color & color)421 RGBColor::operator=(const rgb_color &color)
422 {
423 	fColor32 = color;
424 	fUpdate8 = fUpdate15 = fUpdate16 = true;
425 
426 	return *this;
427 }
428 
429 
430 /*!
431 	\brief Prints the 32-bit values of the color to standard out
432 */
433 void
PrintToStream(void) const434 RGBColor::PrintToStream(void) const
435 {
436 	printf("RGBColor(%u,%u,%u,%u)\n",
437 		fColor32.red, fColor32.green, fColor32.blue, fColor32.alpha);
438 }
439 
440 
441 /*!
442 	\brief Overloaded comaparison
443 	\return true if all color elements are exactly equal
444 */
445 bool
operator ==(const rgb_color & color) const446 RGBColor::operator==(const rgb_color &color) const
447 {
448 	return fColor32.red == color.red
449 		&& fColor32.green == color.green
450 		&& fColor32.blue == color.blue
451 		&& fColor32.alpha == color.alpha;
452 }
453 
454 
455 /*!
456 	\brief Overloaded comaparison
457 	\return true if all color elements are exactly equal
458 */
459 bool
operator ==(const RGBColor & color) const460 RGBColor::operator==(const RGBColor &color) const
461 {
462 	return fColor32.red == color.fColor32.red
463 		&& fColor32.green == color.fColor32.green
464 		&& fColor32.blue == color.fColor32.blue
465 		&& fColor32.alpha == color.fColor32.alpha;
466 }
467 
468 
469 bool
operator !=(const rgb_color & color) const470 RGBColor::operator!=(const rgb_color &color) const
471 {
472 	return fColor32.red != color.red
473 		|| fColor32.green != color.green
474 		|| fColor32.blue != color.blue
475 		|| fColor32.alpha != color.alpha;
476 }
477 
478 
479 bool
operator !=(const RGBColor & color) const480 RGBColor::operator!=(const RGBColor &color) const
481 {
482 	return fColor32.red != color.fColor32.red
483 		|| fColor32.green != color.fColor32.green
484 		|| fColor32.blue != color.fColor32.blue
485 		|| fColor32.alpha != color.fColor32.alpha;
486 }
487 
488 
489 bool
IsTransparentMagic() const490 RGBColor::IsTransparentMagic() const
491 {
492 	// TODO: validate this for B_CMAP8 for example
493 	return *this == B_TRANSPARENT_COLOR;
494 }
495