1 /*****************************************************************************
2 * Copyright (c) 2014-2020 OpenRCT2 developers
3 *
4 * For a complete list of all authors, please refer to contributors.md
5 * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6 *
7 * OpenRCT2 is licensed under the GNU General Public License version 3.
8 *****************************************************************************/
9
10 #include "Colour.h"
11
12 #include "../core/EnumMap.hpp"
13 #include "../drawing/Drawing.h"
14 #include "../sprites.h"
15
16 #include <algorithm>
17 #include <cmath>
18
19 rct_colour_map ColourMapA[COLOUR_COUNT] = {};
20
21 enum
22 {
23 INDEX_COLOUR_0 = 243,
24 INDEX_COLOUR_1 = 245,
25 INDEX_DARKEST = 245,
26 INDEX_DARKER = 246,
27 INDEX_DARK = 247,
28 INDEX_MID_DARK = 248,
29 INDEX_MID_LIGHT = 249,
30 INDEX_LIGHT = 250,
31 INDEX_LIGHTER = 251,
32 INDEX_LIGHTEST = 252,
33 INDEX_COLOUR_10 = 253,
34 INDEX_COLOUR_11 = 254,
35 };
36
colours_init_maps()37 void colours_init_maps()
38 {
39 // Get colour maps from g1
40 for (int32_t i = 0; i < COLOUR_COUNT; i++)
41 {
42 const rct_g1_element* g1 = gfx_get_g1_element(SPR_PALETTE_2_START + i);
43 if (g1 != nullptr)
44 {
45 ColourMapA[i].colour_0 = g1->offset[INDEX_COLOUR_0];
46 ColourMapA[i].colour_1 = g1->offset[INDEX_COLOUR_1];
47 ColourMapA[i].darkest = g1->offset[INDEX_DARKEST];
48 ColourMapA[i].darker = g1->offset[INDEX_DARKER];
49 ColourMapA[i].dark = g1->offset[INDEX_DARK];
50 ColourMapA[i].mid_dark = g1->offset[INDEX_MID_DARK];
51 ColourMapA[i].mid_light = g1->offset[INDEX_MID_LIGHT];
52 ColourMapA[i].light = g1->offset[INDEX_LIGHT];
53 ColourMapA[i].lighter = g1->offset[INDEX_LIGHTER];
54 ColourMapA[i].lightest = g1->offset[INDEX_LIGHTEST];
55 ColourMapA[i].colour_10 = g1->offset[INDEX_COLOUR_10];
56 ColourMapA[i].colour_11 = g1->offset[INDEX_COLOUR_11];
57 }
58 }
59 }
60
61 namespace Colour
62 {
63 static const EnumMap<colour_t> LookupTable{
64 { "black", COLOUR_BLACK },
65 { "grey", COLOUR_GREY },
66 { "white", COLOUR_WHITE },
67 { "dark_purple", COLOUR_DARK_PURPLE },
68 { "light_purple", COLOUR_LIGHT_PURPLE },
69 { "bright_purple", COLOUR_BRIGHT_PURPLE },
70 { "dark_blue", COLOUR_DARK_BLUE },
71 { "light_blue", COLOUR_LIGHT_BLUE },
72 { "icy_blue", COLOUR_ICY_BLUE },
73 { "teal", COLOUR_TEAL },
74 { "aquamarine", COLOUR_AQUAMARINE },
75 { "saturated_green", COLOUR_SATURATED_GREEN },
76 { "dark_green", COLOUR_DARK_GREEN },
77 { "moss_green", COLOUR_MOSS_GREEN },
78 { "bright_green", COLOUR_BRIGHT_GREEN },
79 { "olive_green", COLOUR_OLIVE_GREEN },
80 { "dark_olive_green", COLOUR_DARK_OLIVE_GREEN },
81 { "bright_yellow", COLOUR_BRIGHT_YELLOW },
82 { "yellow", COLOUR_YELLOW },
83 { "dark_yellow", COLOUR_DARK_YELLOW },
84 { "light_orange", COLOUR_LIGHT_ORANGE },
85 { "dark_orange", COLOUR_DARK_ORANGE },
86 { "light_brown", COLOUR_LIGHT_BROWN },
87 { "saturated_brown", COLOUR_SATURATED_BROWN },
88 { "dark_brown", COLOUR_DARK_BROWN },
89 { "salmon_pink", COLOUR_SALMON_PINK },
90 { "bordeaux_red", COLOUR_BORDEAUX_RED },
91 { "saturated_red", COLOUR_SATURATED_RED },
92 { "bright_red", COLOUR_BRIGHT_RED },
93 { "dark_pink", COLOUR_DARK_PINK },
94 { "bright_pink", COLOUR_BRIGHT_PINK },
95 { "light_pink", COLOUR_LIGHT_PINK },
96 };
97
FromString(std::string_view s,colour_t defaultValue)98 colour_t FromString(std::string_view s, colour_t defaultValue)
99 {
100 auto result = LookupTable.find(s);
101 return (result != LookupTable.end()) ? result->second : defaultValue;
102 }
103
104 } // namespace Colour
105
106 #ifndef NO_TTF
107 static uint8_t BlendColourMap[PALETTE_COUNT][PALETTE_COUNT] = { 0 };
108
findClosestPaletteIndex(uint8_t red,uint8_t green,uint8_t blue)109 static uint8_t findClosestPaletteIndex(uint8_t red, uint8_t green, uint8_t blue)
110 {
111 int16_t closest = -1;
112 int32_t closestDistance = INT32_MAX;
113
114 for (int i = PALETTE_INDEX_0; i < PALETTE_INDEX_230; i++)
115 {
116 const int32_t distance = std::pow(gPalette[i].Red - red, 2) + std::pow(gPalette[i].Green - green, 2)
117 + std::pow(gPalette[i].Blue - blue, 2);
118
119 if (distance < closestDistance)
120 {
121 closest = i;
122 closestDistance = distance;
123 }
124 }
125
126 return closest;
127 }
128
blendColours(const uint8_t paletteIndex1,const uint8_t paletteIndex2)129 uint8_t blendColours(const uint8_t paletteIndex1, const uint8_t paletteIndex2)
130 {
131 const uint8_t cMin = std::min(paletteIndex1, paletteIndex2);
132 const uint8_t cMax = std::max(paletteIndex1, paletteIndex2);
133
134 if (BlendColourMap[cMin][cMax] != 0)
135 {
136 return BlendColourMap[cMin][cMax];
137 }
138
139 uint8_t red = (gPalette[cMin].Red + gPalette[cMax].Red) / 2;
140 uint8_t green = (gPalette[cMin].Green + gPalette[cMax].Green) / 2;
141 uint8_t blue = (gPalette[cMin].Blue + gPalette[cMax].Blue) / 2;
142
143 BlendColourMap[cMin][cMax] = findClosestPaletteIndex(red, green, blue);
144 return BlendColourMap[cMin][cMax];
145 }
146 #endif
147