Celestia

Форк
0
/
color.cpp 
297 строк · 17.9 Кб
1
// color.cpp
2
//
3
// Copyright (C) 2001-2008, the Celestia Development Team
4
//
5
// This program is free software; you can redistribute it and/or
6
// modify it under the terms of the GNU General Public License
7
// as published by the Free Software Foundation; either version 2
8
// of the License, or (at your option) any later version.
9

10
#include <map>
11
#include <system_error>
12

13
#include <celcompat/charconv.h>
14
#include "color.h"
15

16
using namespace std::string_view_literals;
17

18
namespace
19
{
20

21
using ColorMap = std::map<std::string_view, Color>;
22

23
const ColorMap* buildX11ColorMap()
24
{
25
    return new ColorMap
26
    {
27
        { "aliceblue"sv,            Color((std::uint8_t)240, (std::uint8_t)248, (std::uint8_t)255) },
28
        { "antiquewhite"sv,         Color((std::uint8_t)250, (std::uint8_t)235, (std::uint8_t)215) },
29
        { "aqua"sv,                 Color((std::uint8_t)0,   (std::uint8_t)255, (std::uint8_t)255) },
30
        { "aquamarine"sv,           Color((std::uint8_t)127, (std::uint8_t)255, (std::uint8_t)212) },
31
        { "azure"sv,                Color((std::uint8_t)240, (std::uint8_t)255, (std::uint8_t)255) },
32
        { "beige"sv,                Color((std::uint8_t)245, (std::uint8_t)245, (std::uint8_t)220) },
33
        { "bisque"sv,               Color((std::uint8_t)255, (std::uint8_t)228, (std::uint8_t)196) },
34
        { "black"sv,                Color((std::uint8_t)0,   (std::uint8_t)0,   (std::uint8_t)0)   },
35
        { "blanchedalmond"sv,       Color((std::uint8_t)255, (std::uint8_t)235, (std::uint8_t)205) },
36
        { "blue"sv,                 Color((std::uint8_t)0,   (std::uint8_t)0,   (std::uint8_t)255) },
37
        { "blueviolet"sv,           Color((std::uint8_t)138, (std::uint8_t)43,  (std::uint8_t)226) },
38
        { "brown"sv,                Color((std::uint8_t)165, (std::uint8_t)42,  (std::uint8_t)42)  },
39
        { "burlywood"sv,            Color((std::uint8_t)222, (std::uint8_t)184, (std::uint8_t)135) },
40
        { "cadetblue"sv,            Color((std::uint8_t)95,  (std::uint8_t)158, (std::uint8_t)160) },
41
        { "chartreuse"sv,           Color((std::uint8_t)127, (std::uint8_t)255, (std::uint8_t)0)   },
42
        { "chocolate"sv,            Color((std::uint8_t)210, (std::uint8_t)105, (std::uint8_t)30)  },
43
        { "coral"sv,                Color((std::uint8_t)255, (std::uint8_t)127, (std::uint8_t)80)  },
44
        { "cornflowerblue"sv,       Color((std::uint8_t)100, (std::uint8_t)149, (std::uint8_t)237) },
45
        { "cornsilk"sv,             Color((std::uint8_t)255, (std::uint8_t)248, (std::uint8_t)220) },
46
        { "crimson"sv,              Color((std::uint8_t)220, (std::uint8_t)20,  (std::uint8_t)60)  },
47
        { "cyan"sv,                 Color((std::uint8_t)0,   (std::uint8_t)255, (std::uint8_t)255) },
48
        { "darkblue"sv,             Color((std::uint8_t)0,   (std::uint8_t)0,   (std::uint8_t)139) },
49
        { "darkcyan"sv,             Color((std::uint8_t)0,   (std::uint8_t)139, (std::uint8_t)139) },
50
        { "darkgoldenrod"sv,        Color((std::uint8_t)184, (std::uint8_t)134, (std::uint8_t)11)  },
51
        { "darkgray"sv,             Color((std::uint8_t)169, (std::uint8_t)169, (std::uint8_t)169) },
52
        { "darkgreen"sv,            Color((std::uint8_t)0,   (std::uint8_t)100, (std::uint8_t)0)   },
53
        { "darkkhaki"sv,            Color((std::uint8_t)189, (std::uint8_t)183, (std::uint8_t)107) },
54
        { "darkmagenta"sv,          Color((std::uint8_t)139, (std::uint8_t)0,   (std::uint8_t)139) },
55
        { "darkolivegreen"sv,       Color((std::uint8_t)85,  (std::uint8_t)107, (std::uint8_t)47)  },
56
        { "darkorange"sv,           Color((std::uint8_t)255, (std::uint8_t)140, (std::uint8_t)0)   },
57
        { "darkorchid"sv,           Color((std::uint8_t)153, (std::uint8_t)50,  (std::uint8_t)204) },
58
        { "darkred"sv,              Color((std::uint8_t)139, (std::uint8_t)0,   (std::uint8_t)0)   },
59
        { "darksalmon"sv,           Color((std::uint8_t)233, (std::uint8_t)150, (std::uint8_t)122) },
60
        { "darkseagreen"sv,         Color((std::uint8_t)143, (std::uint8_t)188, (std::uint8_t)143) },
61
        { "darkslateblue"sv,        Color((std::uint8_t)72,  (std::uint8_t)61,  (std::uint8_t)139) },
62
        { "darkslategray"sv,        Color((std::uint8_t)47,  (std::uint8_t)79,  (std::uint8_t)79)  },
63
        { "darkturquoise"sv,        Color((std::uint8_t)0,   (std::uint8_t)206, (std::uint8_t)209) },
64
        { "darkviolet"sv,           Color((std::uint8_t)148, (std::uint8_t)0,   (std::uint8_t)211) },
65
        { "deeppink"sv,             Color((std::uint8_t)255, (std::uint8_t)20,  (std::uint8_t)147) },
66
        { "deepskyblue"sv,          Color((std::uint8_t)0,   (std::uint8_t)191, (std::uint8_t)255) },
67
        { "dimgray"sv,              Color((std::uint8_t)105, (std::uint8_t)105, (std::uint8_t)105) },
68
        { "dodgerblue"sv,           Color((std::uint8_t)30,  (std::uint8_t)144, (std::uint8_t)255) },
69
        { "firebrick"sv,            Color((std::uint8_t)178, (std::uint8_t)34,  (std::uint8_t)34)  },
70
        { "floralwhite"sv,          Color((std::uint8_t)255, (std::uint8_t)250, (std::uint8_t)240) },
71
        { "forestgreen"sv,          Color((std::uint8_t)34,  (std::uint8_t)139, (std::uint8_t)34)  },
72
        { "fuchsia"sv,              Color((std::uint8_t)255, (std::uint8_t)0,   (std::uint8_t)255) },
73
        { "gainsboro"sv,            Color((std::uint8_t)220, (std::uint8_t)220, (std::uint8_t)220) },
74
        { "ghostwhite"sv,           Color((std::uint8_t)248, (std::uint8_t)248, (std::uint8_t)255) },
75
        { "gold"sv,                 Color((std::uint8_t)255, (std::uint8_t)215, (std::uint8_t)0)   },
76
        { "goldenrod"sv,            Color((std::uint8_t)218, (std::uint8_t)165, (std::uint8_t)32)  },
77
        { "gray"sv,                 Color((std::uint8_t)128, (std::uint8_t)128, (std::uint8_t)128) },
78
        { "green"sv,                Color((std::uint8_t)0,   (std::uint8_t)128, (std::uint8_t)0)   },
79
        { "greenyellow"sv,          Color((std::uint8_t)173, (std::uint8_t)255, (std::uint8_t)47)  },
80
        { "honeydew"sv,             Color((std::uint8_t)240, (std::uint8_t)255, (std::uint8_t)240) },
81
        { "hotpink"sv,              Color((std::uint8_t)255, (std::uint8_t)105, (std::uint8_t)180) },
82
        { "indianred"sv,            Color((std::uint8_t)205, (std::uint8_t)92,  (std::uint8_t)92)  },
83
        { "indigo"sv,               Color((std::uint8_t)75,  (std::uint8_t)0,   (std::uint8_t)130) },
84
        { "ivory"sv,                Color((std::uint8_t)255, (std::uint8_t)255, (std::uint8_t)240) },
85
        { "khaki"sv,                Color((std::uint8_t)240, (std::uint8_t)230, (std::uint8_t)140) },
86
        { "lavender"sv,             Color((std::uint8_t)230, (std::uint8_t)230, (std::uint8_t)250) },
87
        { "lavenderblush"sv,        Color((std::uint8_t)255, (std::uint8_t)240, (std::uint8_t)245) },
88
        { "lawngreen"sv,            Color((std::uint8_t)124, (std::uint8_t)252, (std::uint8_t)0)   },
89
        { "lemonchiffon"sv,         Color((std::uint8_t)255, (std::uint8_t)250, (std::uint8_t)205) },
90
        { "lightblue"sv,            Color((std::uint8_t)173, (std::uint8_t)216, (std::uint8_t)230) },
91
        { "lightcoral"sv,           Color((std::uint8_t)240, (std::uint8_t)128, (std::uint8_t)128) },
92
        { "lightcyan"sv,            Color((std::uint8_t)224, (std::uint8_t)255, (std::uint8_t)255) },
93
        { "lightgoldenrodyellow"sv, Color((std::uint8_t)250, (std::uint8_t)250, (std::uint8_t)210) },
94
        { "lightgreen"sv,           Color((std::uint8_t)144, (std::uint8_t)238, (std::uint8_t)144) },
95
        { "lightgrey"sv,            Color((std::uint8_t)211, (std::uint8_t)211, (std::uint8_t)211) },
96
        { "lightpink"sv,            Color((std::uint8_t)255, (std::uint8_t)182, (std::uint8_t)193) },
97
        { "lightsalmon"sv,          Color((std::uint8_t)255, (std::uint8_t)160, (std::uint8_t)122) },
98
        { "lightseagreen"sv,        Color((std::uint8_t)32,  (std::uint8_t)178, (std::uint8_t)170) },
99
        { "lightskyblue"sv,         Color((std::uint8_t)135, (std::uint8_t)206, (std::uint8_t)250) },
100
        { "lightslategray"sv,       Color((std::uint8_t)119, (std::uint8_t)136, (std::uint8_t)153) },
101
        { "lightsteelblue"sv,       Color((std::uint8_t)176, (std::uint8_t)196, (std::uint8_t)222) },
102
        { "lightyellow"sv,          Color((std::uint8_t)255, (std::uint8_t)255, (std::uint8_t)224) },
103
        { "lime"sv,                 Color((std::uint8_t)0,   (std::uint8_t)255, (std::uint8_t)0)   },
104
        { "limegreen"sv,            Color((std::uint8_t)50,  (std::uint8_t)205, (std::uint8_t)50)  },
105
        { "linen"sv,                Color((std::uint8_t)250, (std::uint8_t)240, (std::uint8_t)230) },
106
        { "magenta"sv,              Color((std::uint8_t)255, (std::uint8_t)0,   (std::uint8_t)255) },
107
        { "maroon"sv,               Color((std::uint8_t)128, (std::uint8_t)0,   (std::uint8_t)0)   },
108
        { "mediumaquamarine"sv,     Color((std::uint8_t)102, (std::uint8_t)205, (std::uint8_t)170) },
109
        { "mediumblue"sv,           Color((std::uint8_t)0,   (std::uint8_t)0,   (std::uint8_t)205) },
110
        { "mediumorchid"sv,         Color((std::uint8_t)186, (std::uint8_t)85,  (std::uint8_t)211) },
111
        { "mediumpurple"sv,         Color((std::uint8_t)147, (std::uint8_t)112, (std::uint8_t)219) },
112
        { "mediumseagreen"sv,       Color((std::uint8_t)60,  (std::uint8_t)179, (std::uint8_t)113) },
113
        { "mediumslateblue"sv,      Color((std::uint8_t)123, (std::uint8_t)104, (std::uint8_t)238) },
114
        { "mediumspringgreen"sv,    Color((std::uint8_t)0,   (std::uint8_t)250, (std::uint8_t)154) },
115
        { "mediumturquoise"sv,      Color((std::uint8_t)72,  (std::uint8_t)209, (std::uint8_t)204) },
116
        { "mediumvioletred"sv,      Color((std::uint8_t)199, (std::uint8_t)21,  (std::uint8_t)133) },
117
        { "midnightblue"sv,         Color((std::uint8_t)25,  (std::uint8_t)25,  (std::uint8_t)112) },
118
        { "mintcream"sv,            Color((std::uint8_t)245, (std::uint8_t)255, (std::uint8_t)250) },
119
        { "mistyrose"sv,            Color((std::uint8_t)255, (std::uint8_t)228, (std::uint8_t)225) },
120
        { "moccasin"sv,             Color((std::uint8_t)255, (std::uint8_t)228, (std::uint8_t)181) },
121
        { "navajowhite"sv,          Color((std::uint8_t)255, (std::uint8_t)222, (std::uint8_t)173) },
122
        { "navy"sv,                 Color((std::uint8_t)0,   (std::uint8_t)0,   (std::uint8_t)128) },
123
        { "oldlace"sv,              Color((std::uint8_t)253, (std::uint8_t)245, (std::uint8_t)230) },
124
        { "olive"sv,                Color((std::uint8_t)128, (std::uint8_t)128, (std::uint8_t)0)   },
125
        { "olivedrab"sv,            Color((std::uint8_t)107, (std::uint8_t)142, (std::uint8_t)35)  },
126
        { "orange"sv,               Color((std::uint8_t)255, (std::uint8_t)165, (std::uint8_t)0)   },
127
        { "orangered"sv,            Color((std::uint8_t)255, (std::uint8_t)69,  (std::uint8_t)0)   },
128
        { "orchid"sv,               Color((std::uint8_t)218, (std::uint8_t)112, (std::uint8_t)214) },
129
        { "palegoldenrod"sv,        Color((std::uint8_t)238, (std::uint8_t)232, (std::uint8_t)170) },
130
        { "palegreen"sv,            Color((std::uint8_t)152, (std::uint8_t)251, (std::uint8_t)152) },
131
        { "paleturquoise"sv,        Color((std::uint8_t)175, (std::uint8_t)238, (std::uint8_t)238) },
132
        { "palevioletred"sv,        Color((std::uint8_t)219, (std::uint8_t)112, (std::uint8_t)147) },
133
        { "papayawhip"sv,           Color((std::uint8_t)255, (std::uint8_t)239, (std::uint8_t)213) },
134
        { "peachpuff"sv,            Color((std::uint8_t)255, (std::uint8_t)218, (std::uint8_t)185) },
135
        { "peru"sv,                 Color((std::uint8_t)205, (std::uint8_t)133, (std::uint8_t)63)  },
136
        { "pink"sv,                 Color((std::uint8_t)255, (std::uint8_t)192, (std::uint8_t)203) },
137
        { "plum"sv,                 Color((std::uint8_t)221, (std::uint8_t)160, (std::uint8_t)221) },
138
        { "powderblue"sv,           Color((std::uint8_t)176, (std::uint8_t)224, (std::uint8_t)230) },
139
        { "purple"sv,               Color((std::uint8_t)128, (std::uint8_t)0,   (std::uint8_t)128) },
140
        { "red"sv,                  Color((std::uint8_t)255, (std::uint8_t)0,   (std::uint8_t)0)   },
141
        { "rosybrown"sv,            Color((std::uint8_t)188, (std::uint8_t)143, (std::uint8_t)143) },
142
        { "royalblue"sv,            Color((std::uint8_t)65,  (std::uint8_t)105, (std::uint8_t)225) },
143
        { "saddlebrown"sv,          Color((std::uint8_t)139, (std::uint8_t)69,  (std::uint8_t)19)  },
144
        { "salmon"sv,               Color((std::uint8_t)250, (std::uint8_t)128, (std::uint8_t)114) },
145
        { "sandybrown"sv,           Color((std::uint8_t)244, (std::uint8_t)164, (std::uint8_t)96)  },
146
        { "seagreen"sv,             Color((std::uint8_t)46,  (std::uint8_t)139, (std::uint8_t)87)  },
147
        { "seashell"sv,             Color((std::uint8_t)255, (std::uint8_t)245, (std::uint8_t)238) },
148
        { "sienna"sv,               Color((std::uint8_t)160, (std::uint8_t)82,  (std::uint8_t)45)  },
149
        { "silver"sv,               Color((std::uint8_t)192, (std::uint8_t)192, (std::uint8_t)192) },
150
        { "skyblue"sv,              Color((std::uint8_t)135, (std::uint8_t)206, (std::uint8_t)235) },
151
        { "slateblue"sv,            Color((std::uint8_t)106, (std::uint8_t)90,  (std::uint8_t)205) },
152
        { "slategray"sv,            Color((std::uint8_t)112, (std::uint8_t)128, (std::uint8_t)144) },
153
        { "snow"sv,                 Color((std::uint8_t)255, (std::uint8_t)250, (std::uint8_t)250) },
154
        { "springgreen"sv,          Color((std::uint8_t)0,   (std::uint8_t)255, (std::uint8_t)127) },
155
        { "steelblue"sv,            Color((std::uint8_t)70,  (std::uint8_t)130, (std::uint8_t)180) },
156
        { "tan"sv,                  Color((std::uint8_t)210, (std::uint8_t)180, (std::uint8_t)140) },
157
        { "teal"sv,                 Color((std::uint8_t)0,   (std::uint8_t)128, (std::uint8_t)128) },
158
        { "thistle"sv,              Color((std::uint8_t)216, (std::uint8_t)191, (std::uint8_t)216) },
159
        { "tomato"sv,               Color((std::uint8_t)255, (std::uint8_t)99,  (std::uint8_t)71)  },
160
        { "turquoise"sv,            Color((std::uint8_t)64,  (std::uint8_t)224, (std::uint8_t)208) },
161
        { "violet"sv,               Color((std::uint8_t)238, (std::uint8_t)130, (std::uint8_t)238) },
162
        { "wheat"sv,                Color((std::uint8_t)245, (std::uint8_t)222, (std::uint8_t)179) },
163
        { "white"sv,                Color((std::uint8_t)255, (std::uint8_t)255, (std::uint8_t)255) },
164
        { "whitesmoke"sv,           Color((std::uint8_t)245, (std::uint8_t)245, (std::uint8_t)245) },
165
        { "yellow"sv,               Color((std::uint8_t)255, (std::uint8_t)255, (std::uint8_t)0)   },
166
        { "yellowgreen"sv,          Color((std::uint8_t)154, (std::uint8_t)205, (std::uint8_t)50)  },
167
    };
168
}
169

170
bool parseHexColor(std::string_view s, Color& c)
171
{
172
    using celestia::compat::from_chars;
173

174
    std::uint32_t value;
175
    switch (s.size())
176
    {
177
    case 3: // rgb
178
        if (auto [ptr, ec] = from_chars(s.data(), s.data() + s.size(), value, 16);
179
            ec == std::errc{} && ptr == s.data() + s.size())
180
        {
181
            c = Color(static_cast<std::uint8_t>((value >> 8) * UINT32_C(0x11)),
182
                    static_cast<std::uint8_t>(((value & UINT32_C(0x0f0)) >> 4) * UINT32_C(0x11)),
183
                    static_cast<std::uint8_t>((value & UINT32_C(0x00f)) * UINT32_C(0x11)));
184
            return true;
185
        }
186
        break;
187

188
    case 6: // rrggbb
189
        if (auto [ptr, ec] = from_chars(s.data(), s.data() + s.size(), value, 16);
190
            ec == std::errc{} && ptr == s.data() + s.size())
191
        {
192
            c = Color(static_cast<std::uint8_t>(value >> 16),
193
                    static_cast<std::uint8_t>((value & UINT32_C(0x00ff00)) >> 8),
194
                    static_cast<std::uint8_t>(value & UINT32_C(0x0000ff)));
195
            return true;
196
        }
197
        break;
198

199
    case 8: // rrggbbaa
200
        if (auto [ptr, ec] = from_chars(s.data(), s.data() + s.size(), value, 16);
201
            ec == std::errc{} && ptr == s.data() + s.size())
202
        {
203
            c = Color(static_cast<std::uint8_t>(value >> 24),
204
                    static_cast<std::uint8_t>((value & UINT32_C(0x00ff0000)) >> 16),
205
                    static_cast<std::uint8_t>((value & UINT32_C(0x0000ff00)) >> 8),
206
                    static_cast<std::uint8_t>(value & UINT32_C(0x000000ff)));
207
            return true;
208
        }
209
        break;
210

211
    default:
212
        break;
213
    }
214
    return false;
215
}
216

217
} // end unnamed namespace
218

219
/*!
220
 * @brief Convert HSV to RGB.
221
 * @param h Hue, [0, 360]
222
 * @param s Saturation, [0, 1]
223
 * @param v Value, [0, 1]
224
 * @return RGBA color
225
 */
226
Color Color::fromHSV(float h, float s, float v)
227
{
228
    if (s == 0.0f)
229
    {
230
        // achromatic (grey)
231
        return { v, v, v };
232
    }
233

234

235
    h /= 60.0f; // sector 0 to 5
236
    float j = std::floor(h);
237

238
    float f = h - j; // fractional part of h
239
    float p = v * (1.0f - s);
240
    float q = v * (1.0f - s * f);
241
    float t = v * (1.0f - s * (1.0f - f));
242

243
    switch(static_cast<int>(j))
244
    {
245
    case 0:
246
        return { v, t, p };
247
    case 1:
248
        return { q, v, p };
249
    case 2:
250
        return { p, v, t };
251
    case 3:
252
        return { p, q, v };
253
    case 4:
254
        return { t, p, v };
255
    default:
256
        return { v, p, q };
257
    }
258
}
259

260
const Color Color::White = Color(1.0f, 1.0f, 1.0f);
261
const Color Color::Black = Color(0.0f, 0.0f, 0.0f);
262

263
/*! Parse a color string and return true if it was a valid color, otherwise
264
 *  false.  Accetable inputs are HTML/X11 style #xxxxxx colors (where x is
265
 *  hexadecimal digit) or one of a list of named colors.
266
 */
267
bool Color::parse(std::string_view s, Color& c)
268
{
269
    using celestia::compat::from_chars;
270

271
    if (s.empty()) { return false; }
272

273
    if (s[0] == '#')
274
    {
275
        return parseHexColor(s.substr(1), c);
276
    }
277
    else
278
    {
279
        static const ColorMap* x11Colors = nullptr;
280

281
        // Initialize the color dictionary if this is the first
282
        // time Color::parse has been called for a non-hex value.
283
        if (x11Colors == nullptr)
284
        {
285
            x11Colors = buildX11ColorMap();
286
        }
287

288
        auto it = x11Colors->find(s);
289
        if (it != x11Colors->end())
290
        {
291
            c = it->second;
292
            return true;
293
        }
294
    }
295

296
    return false;
297
}
298

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.