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