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*/
49void
50SetRGBColor16(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*/
79static uint8
80FindClosestColor(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*/
114static uint16
115FindClosestColor15(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*/
139static uint16
140FindClosestColor16(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*/
164RGBColor::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*/
177RGBColor::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*/
187RGBColor::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*/
197RGBColor::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*/
207RGBColor::RGBColor(uint8 color)
208{
209	SetColor(color);
210}
211
212
213/*!
214	\brief Copy Contructor
215	\param color color to initialize from
216*/
217RGBColor::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*/
232RGBColor::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*/
242uint8
243RGBColor::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*/
258uint16
259RGBColor::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*/
274uint16
275RGBColor::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*/
290rgb_color
291RGBColor::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*/
304void
305RGBColor::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*/
323void
324RGBColor::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*/
339void
340RGBColor::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*/
356void
357RGBColor::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*/
372void
373RGBColor::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*/
384void
385RGBColor::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*/
401const RGBColor&
402RGBColor::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*/
420const RGBColor&
421RGBColor::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*/
433void
434RGBColor::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*/
445bool
446RGBColor::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*/
459bool
460RGBColor::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
469bool
470RGBColor::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
479bool
480RGBColor::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
489bool
490RGBColor::IsTransparentMagic() const
491{
492	// TODO: validate this for B_CMAP8 for example
493	return *this == B_TRANSPARENT_COLOR;
494}
495