xref: /haiku/src/build/libbe/interface/SystemPalette.cpp (revision b617a7b410c05275effb95f4b2f5608359d9b7b9)
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  *		Stefano Ceccherini (burton666@libero.it)
8  */
9 
10 //! Methods to initialize and get the system color_map.
11 
12 
13 #include <GraphicsDefs.h>
14 #include <InterfaceDefs.h>
15 
16 #include <Palette.h>
17 
18 // TODO: BWindowScreen has a method to set the palette.
19 // maybe we should have a lock to protect this variable.
20 static color_map sColorMap;
21 
22 
23 // color_distance
24 /*!	\brief Returns the "distance" between two RGB colors.
25 
26 	This functions defines an metric on the RGB color space. The distance
27 	between two colors is 0, if and only if the colors are equal.
28 
29 	\param red1 Red component of the first color.
30 	\param green1 Green component of the first color.
31 	\param blue1 Blue component of the first color.
32 	\param red2 Red component of the second color.
33 	\param green2 Green component of the second color.
34 	\param blue2 Blue component of the second color.
35 	\return The distance between the given colors.
36 */
37 static inline uint32
38 color_distance(uint8 red1, uint8 green1, uint8 blue1,
39 			   uint8 red2, uint8 green2, uint8 blue2)
40 {
41 	int rd = (int)red1 - (int)red2;
42 	int gd = (int)green1 - (int)green2;
43 	int bd = (int)blue1 - (int)blue2;
44 
45 	// distance according to psycho-visual tests
46 	// algorithm taken from here:
47 	// http://www.stud.uni-hannover.de/~michaelt/juggle/Algorithms.pdf
48 	int rmean = ((int)red1 + (int)red2) / 2;
49 	return (((512 + rmean) * rd * rd) >> 8)
50 			+ 4 * gd * gd
51 			+ (((767 - rmean) * bd * bd) >> 8);
52 }
53 
54 
55 static inline uint8
56 FindClosestColor(const rgb_color &color, const rgb_color *palette)
57 {
58 	uint8 closestIndex = 0;
59 	unsigned closestDistance = UINT_MAX;
60 	for (int32 i = 0; i < 256; i++) {
61 		const rgb_color &c = palette[i];
62 		unsigned distance = color_distance(color.red, color.green, color.blue,
63 										   c.red, c.green, c.blue);
64 		if (distance < closestDistance) {
65 			closestIndex = (uint8)i;
66 			closestDistance = distance;
67 		}
68 	}
69 	return closestIndex;
70 }
71 
72 
73 static inline rgb_color
74 InvertColor(const rgb_color &color)
75 {
76 	// For some reason, Inverting (255, 255, 255) on beos
77 	// results in the same color.
78 	if (color.red == 255 && color.green == 255
79 		&& color.blue == 255)
80 		return color;
81 
82 	rgb_color inverted;
83 	inverted.red = 255 - color.red;
84 	inverted.green = 255 - color.green;
85 	inverted.blue = 255 - color.blue;
86 	inverted.alpha = 255;
87 
88 	return inverted;
89 }
90 
91 
92 static void
93 FillColorMap(const rgb_color *palette, color_map *map)
94 {
95 	memcpy(map->color_list, palette, sizeof(map->color_list));
96 
97 	// init index map
98 	for (int32 color = 0; color < 32768; color++) {
99 		// get components
100 		rgb_color rgbColor;
101 		rgbColor.red = (color & 0x7c00) >> 7;
102 		rgbColor.green = (color & 0x3e0) >> 2;
103 		rgbColor.blue = (color & 0x1f) << 3;
104 
105 		map->index_map[color] = FindClosestColor(rgbColor, palette);
106 	}
107 
108 	// init inversion map
109 	for (int32 index = 0; index < 256; index++) {
110 		rgb_color inverted = InvertColor(map->color_list[index]);
111 		map->inversion_map[index] = FindClosestColor(inverted, palette);
112 	}
113 }
114 
115 
116 const color_map *
117 system_colors()
118 {
119 	static bool sInitialized = false;
120 	if (!sInitialized) {
121 		FillColorMap(kSystemPalette, &sColorMap);
122 		sInitialized = true;
123 	}
124 
125 	return &sColorMap;
126 }
127