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