116ed1e1dSAxel Dörfler/*
216ed1e1dSAxel Dörfler * Copyright 2001-2006, Haiku.
316ed1e1dSAxel Dörfler * Distributed under the terms of the MIT License.
416ed1e1dSAxel Dörfler *
516ed1e1dSAxel Dörfler * Authors:
616ed1e1dSAxel Dörfler *		DarkWyrm <bpmagic@columbus.rr.com>
716ed1e1dSAxel Dörfler *		Stefano Ceccherini (burton666@libero.it)
816ed1e1dSAxel Dörfler */
916ed1e1dSAxel Dörfler
1016ed1e1dSAxel Dörfler//! Methods to initialize and get the system color_map.
1116ed1e1dSAxel Dörfler
1216ed1e1dSAxel Dörfler
1316ed1e1dSAxel Dörfler#include "SystemPalette.h"
1416ed1e1dSAxel Dörfler
15359c905cSStephan Aßmus#include <stdio.h>
16758b1d0eSIngo Weinhold#include <string.h>
17359c905cSStephan Aßmus
1837b83b1aSStefano Ceccherini#include <Palette.h>
197475dcdfSStefano Ceccherini
206ec6f3f8SStefano Ceccherini// TODO: BWindowScreen has a method to set the palette.
216ec6f3f8SStefano Ceccherini// maybe we should have a lock to protect this variable.
226ec6f3f8SStefano Ceccherinistatic color_map sColorMap;
236ec6f3f8SStefano Ceccherini
246ec6f3f8SStefano Ceccherini
25509db2a3SStefano Ceccherini// color_distance
26509db2a3SStefano Ceccherini/*!	\brief Returns the "distance" between two RGB colors.
27509db2a3SStefano Ceccherini
28509db2a3SStefano Ceccherini	This functions defines an metric on the RGB color space. The distance
29509db2a3SStefano Ceccherini	between two colors is 0, if and only if the colors are equal.
30509db2a3SStefano Ceccherini
31509db2a3SStefano Ceccherini	\param red1 Red component of the first color.
32509db2a3SStefano Ceccherini	\param green1 Green component of the first color.
33509db2a3SStefano Ceccherini	\param blue1 Blue component of the first color.
34509db2a3SStefano Ceccherini	\param red2 Red component of the second color.
35509db2a3SStefano Ceccherini	\param green2 Green component of the second color.
36509db2a3SStefano Ceccherini	\param blue2 Blue component of the second color.
37509db2a3SStefano Ceccherini	\return The distance between the given colors.
38509db2a3SStefano Ceccherini*/
3916ed1e1dSAxel Dörflerstatic inline uint32
40509db2a3SStefano Ceccherinicolor_distance(uint8 red1, uint8 green1, uint8 blue1,
41509db2a3SStefano Ceccherini			   uint8 red2, uint8 green2, uint8 blue2)
43509db2a3SStefano Ceccherini	int rd = (int)red1 - (int)red2;
44509db2a3SStefano Ceccherini	int gd = (int)green1 - (int)green2;
45509db2a3SStefano Ceccherini	int bd = (int)blue1 - (int)blue2;
46509db2a3SStefano Ceccherini
47509db2a3SStefano Ceccherini	// distance according to psycho-visual tests
486deb7c67SStefano Ceccherini	// algorithm taken from here:
496deb7c67SStefano Ceccherini	// http://www.stud.uni-hannover.de/~michaelt/juggle/Algorithms.pdf
50509db2a3SStefano Ceccherini	int rmean = ((int)red1 + (int)red2) / 2;
51d039af74SStefano Ceccherini	return (((512 + rmean) * rd * rd) >> 8)
52d039af74SStefano Ceccherini			+ 4 * gd * gd
53d039af74SStefano Ceccherini			+ (((767 - rmean) * bd * bd) >> 8);
54509db2a3SStefano Ceccherini}
57359c905cSStephan Aßmusstatic inline uint8
581f1ed1c6SStefano CeccheriniFindClosestColor(const rgb_color &color, const rgb_color *palette)
591f1ed1c6SStefano Ceccherini{
601f1ed1c6SStefano Ceccherini	uint8 closestIndex = 0;
611f1ed1c6SStefano Ceccherini	unsigned closestDistance = UINT_MAX;
621f1ed1c6SStefano Ceccherini	for (int32 i = 0; i < 256; i++) {
631f1ed1c6SStefano Ceccherini		const rgb_color &c = palette[i];
641f1ed1c6SStefano Ceccherini		unsigned distance = color_distance(color.red, color.green, color.blue,
651f1ed1c6SStefano Ceccherini										   c.red, c.green, c.blue);
661f1ed1c6SStefano Ceccherini		if (distance < closestDistance) {
6744bb3017SStefano Ceccherini			closestIndex = (uint8)i;
681f1ed1c6SStefano Ceccherini			closestDistance = distance;
691f1ed1c6SStefano Ceccherini		}
701f1ed1c6SStefano Ceccherini	}
711f1ed1c6SStefano Ceccherini	return closestIndex;
721f1ed1c6SStefano Ceccherini}
731f1ed1c6SStefano Ceccherini
741f1ed1c6SStefano Ceccherini
751f1ed1c6SStefano Ceccherinistatic inline rgb_color
761f1ed1c6SStefano CeccheriniInvertColor(const rgb_color &color)
771f1ed1c6SStefano Ceccherini{
781f1ed1c6SStefano Ceccherini	// For some reason, Inverting (255, 255, 255) on beos
791f1ed1c6SStefano Ceccherini	// results in the same color.
801f1ed1c6SStefano Ceccherini	if (color.red == 255 && color.green == 255
811f1ed1c6SStefano Ceccherini		&& color.blue == 255)
821f1ed1c6SStefano Ceccherini		return color;
831f1ed1c6SStefano Ceccherini
841f1ed1c6SStefano Ceccherini	rgb_color inverted;
851f1ed1c6SStefano Ceccherini	inverted.red = 255 - color.red;
861f1ed1c6SStefano Ceccherini	inverted.green = 255 - color.green;
871f1ed1c6SStefano Ceccherini	inverted.blue = 255 - color.blue;
886ec6f3f8SStefano Ceccherini	inverted.alpha = 255;
891f1ed1c6SStefano Ceccherini
901f1ed1c6SStefano Ceccherini	return inverted;
911f1ed1c6SStefano Ceccherini}
921f1ed1c6SStefano Ceccherini
931f1ed1c6SStefano Ceccherini
947475dcdfSStefano Ceccherinistatic void
957475dcdfSStefano CeccheriniFillColorMap(const rgb_color *palette, color_map *map)
967475dcdfSStefano Ceccherini{
977475dcdfSStefano Ceccherini	memcpy(map->color_list, palette, sizeof(map->color_list));
98509db2a3SStefano Ceccherini
99509db2a3SStefano Ceccherini	// init index map
100509db2a3SStefano Ceccherini	for (int32 color = 0; color < 32768; color++) {
101509db2a3SStefano Ceccherini		// get components
1021f1ed1c6SStefano Ceccherini		rgb_color rgbColor;
1031f1ed1c6SStefano Ceccherini		rgbColor.red = (color & 0x7c00) >> 7;
1041f1ed1c6SStefano Ceccherini		rgbColor.green = (color & 0x3e0) >> 2;
1051f1ed1c6SStefano Ceccherini		rgbColor.blue = (color & 0x1f) << 3;
1061f1ed1c6SStefano Ceccherini
1076ec6f3f8SStefano Ceccherini		map->index_map[color] = FindClosestColor(rgbColor, palette);
108509db2a3SStefano Ceccherini	}
1091f1ed1c6SStefano Ceccherini
1101f1ed1c6SStefano Ceccherini	// init inversion map
1111f1ed1c6SStefano Ceccherini	for (int32 index = 0; index < 256; index++) {
1121f1ed1c6SStefano Ceccherini		rgb_color inverted = InvertColor(map->color_list[index]);
11344bb3017SStefano Ceccherini		map->inversion_map[index] = FindClosestColor(inverted, palette);
1141f1ed1c6SStefano Ceccherini	}
1157475dcdfSStefano Ceccherini}
1167475dcdfSStefano Ceccherini
1177475dcdfSStefano Ceccherini
1186deb7c67SStefano Ceccherini/*!	\brief Initializes the system color_map.
1196deb7c67SStefano Ceccherini*/
1207475dcdfSStefano Ceccherinivoid
1217475dcdfSStefano CeccheriniInitializeColorMap()
1227475dcdfSStefano Ceccherini{
1237475dcdfSStefano Ceccherini	FillColorMap(kSystemPalette, &sColorMap);
1247475dcdfSStefano Ceccherini}
1257475dcdfSStefano Ceccherini
1267475dcdfSStefano Ceccherini
1276deb7c67SStefano Ceccherini/*!	\brief Returns a pointer to the system palette.
1286deb7c67SStefano Ceccherini	\return A pointer to the system palette.
1296deb7c67SStefano Ceccherini*/
1307475dcdfSStefano Ceccheriniconst rgb_color *
1317475dcdfSStefano CeccheriniSystemPalette()
1327475dcdfSStefano Ceccherini{
1337475dcdfSStefano Ceccherini	return sColorMap.color_list;
1347475dcdfSStefano Ceccherini}
1357475dcdfSStefano Ceccherini
1367475dcdfSStefano Ceccherini
1376deb7c67SStefano Ceccherini/*!	\brief Returns a pointer to the system color_map structure.
1386deb7c67SStefano Ceccherini	\return A pointer to the system color_map.
1396deb7c67SStefano Ceccherini*/
1407475dcdfSStefano Ceccheriniconst color_map *
1417475dcdfSStefano CeccheriniSystemColorMap()
1427475dcdfSStefano Ceccherini{
1437475dcdfSStefano Ceccherini	return &sColorMap;
1447475dcdfSStefano Ceccherini}