2 * Copyright (c) 2007-2013, Czirkos Zoltan http://code.google.com/p/gdash/
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include <glib/gi18n.h>
23 #include "settings.hpp"
24 #include "cave/helper/colors.hpp"
25 #include "misc/printf.hpp"
26 #include "misc/logger.hpp"
27 #include "misc/util.hpp"
29 /* These are in the include/ directory. */
30 /* Stores the atari palettes. */
31 #include "ataripal.cpp"
32 /* Stores the DTV palettes. */
35 static const char *c64_color_bdcff_names
[]={
36 "Black", "White", "Red", "Cyan", "Purple", "Green", "Blue", "Yellow",
37 "Orange", "Brown", "LightRed", "Gray1", "Gray2", "LightGreen", "LightBlue", "Gray3",
40 static const char *c64_color_visible_names
[]={
41 N_("Black"), N_("White"), N_("Red"), N_("Cyan"), N_("Purple"), N_("Green"), N_("Blue"), N_("Yellow"),
42 N_("Orange"), N_("Brown"), N_("Light red"), N_("Dark gray"), N_("Gray"), N_("Light green"), N_("Light blue"), N_("Light gray"),
45 static guint32 c64_colors_vice_old
[]={
46 0x000000, 0xFFFFFF, 0x68372b, 0x70a4b2, 0x6f3d86, 0x588d43, 0x352879, 0xb8c76f,
47 0x6f4f25, 0x433900, 0x9a6759, 0x444444, 0x6c6c6c, 0x9ad284, 0x6c5eb5, 0x959595,
50 static guint32 c64_colors_vice_new
[]={
51 0x000000, 0xffffff, 0x894036, 0x7abfc7, 0x8a46ae, 0x68a941, 0x3e31a2, 0xd0dc71,
52 0x905f25, 0x5c4700, 0xbb776d, 0x555555, 0x808080, 0xacea88, 0x7c70da, 0xababab,
55 static guint32 c64_colors_c64_hq
[]={
56 0x0A0A0A, 0xFFF8FF, 0x851F02, 0x65CDA8, 0xA73B9F, 0x4DAB19, 0x1A0C92, 0xEBE353,
57 0xA94B02, 0x441E00, 0xD28074, 0x464646, 0x8B8B8B, 0x8EF68E, 0x4D91D1, 0xBABABA,
60 static guint32 c64_colors_c64s
[]={
61 0x000000, 0xFCFCFC, 0xA80000, 0x54FCFC, 0xA800A8, 0x00A800, 0x0000A8, 0xFCFC00,
62 0xA85400, 0x802C00, 0xFC5454, 0x545454, 0x808080, 0x54FC54, 0x5454FC, 0xA8A8A8,
65 static guint32 c64_colors_ccs64
[]={
66 0x101010, 0xFFFFFF, 0xE04040, 0x60FFFF, 0xE060E0, 0x40E040, 0x4040E0, 0xFFFF40,
67 0xE0A040, 0x9C7448, 0xFFA0A0, 0x545454, 0x888888, 0xA0FFA0, 0xA0A0FF, 0xC0C0C0,
70 static guint32 c64_colors_vice_default
[]={
71 0x000000, 0xFDFEFC, 0xBE1A24, 0x30E6C6, 0xB41AE2, 0x1FD21E, 0x211BAE, 0xDFF60A,
72 0xB84104, 0x6A3304, 0xFE4A57, 0x424540, 0x70746F, 0x59FE59, 0x5F53FE, 0xA4A7A2,
75 static guint32 c64_colors_frodo
[]={
76 0x000000, 0xFFFFFF, 0xCC0000, 0x00FFCC, 0xFF00FF, 0x00CC00, 0x0000CC, 0xFFFF00,
77 0xFF8800, 0x884400, 0xFF8888, 0x444444, 0x888888, 0x88FF88, 0x8888FF, 0xCCCCCC,
80 static guint32 c64_colors_godot
[]={
81 0x000000, 0xFFFFFF, 0x880000, 0xAAFFEE, 0xCC44CC, 0x00CC55, 0x0000AA, 0xEEEE77,
82 0xDD8855, 0x664400, 0xFE7777, 0x333333, 0x777777, 0xAAFF66, 0x0088FF, 0xBBBBBB,
85 static guint32 c64_colors_pc64
[]={
86 0x212121, 0xFFFFFF, 0xB52121, 0x73FFFF, 0xB521B5, 0x21B521, 0x2121B5, 0xFFFF21,
87 0xB57321, 0x944221, 0xFF7373, 0x737373, 0x949494, 0x73FF73, 0x7373FF, 0xB5B5B5,
90 static guint32 c64_colors_rtadash
[]={
91 0x000000, 0xffffff, 0xea3418, 0x58ffff, 0xd82cff, 0x55fb00, 0x4925ff, 0xffff09,
92 0xe66c00, 0x935f00, 0xff7c64, 0x6c6c6c, 0xa1a1a1, 0xafff4d, 0x9778ff, 0xd8d8d8,
96 /* these values are taken from the title screen, drawn by cws. */
97 /* so menus and everything else will look nice! */
98 /* the 16 colors that can be used are the same as on c64. */
99 /* "Black", "White", "Red", "Cyan", "Purple", "Green", "Blue", "Yellow", */
100 /* "Orange", "Brown", "LightRed", "Gray1", "Gray2", "LightGreen", "LightBlue", "Gray3", */
101 /* not in the png: cyan, purple. gray3 is darker in the png. */
102 /* 17th color is the player's leg in the png. i not connected it to any c64 */
103 /* color, but it is used for theme images for example. */
104 static const guint32 gdash_colors
[]={
105 0x000000, 0xffffff, 0xe33939, 0x55aaaa, 0xaa55aa, 0x71aa55, 0x0039ff, 0xffff55,
106 0xe37139, 0xaa7139, 0xe09080, 0x555555, 0x717171, 0xc6e38e, 0xaaaaff, 0x8e8e8e,
112 /* make sure that pointeres and names match! */
113 static guint32
*c64_palette_pointers
[]={
115 c64_colors_vice_old
, c64_colors_vice_default
, c64_colors_c64_hq
, c64_colors_c64s
,
116 c64_colors_ccs64
, c64_colors_frodo
, c64_colors_godot
, c64_colors_pc64
, c64_colors_rtadash
,
119 static const char *c64_palettes_names
[]={
121 "Vice old", "Vice default", "C64HQ", "C64S",
122 "CCS64", "Frodo", "GoDot", "PC64", "RTADash",
126 /* indexes in this array must match GdColorType */
127 static const char *palette_types_names
[]={
136 /// Color of flashing the screen, gate opening to exit.
137 const GdColor gd_flash_color
=GdColor::from_rgb(0xff, 0xff, 0xff);
138 /// Color of selected object in editor.
139 const GdColor gd_select_color
=GdColor::from_rgb(0x80, 0x80, 0xff);
142 /// Get an array of C strings, which stores the color types known.
143 const char **GdColor::get_palette_types_names() {
144 return palette_types_names
;
147 /// Get an array of C strings, which stores the names of C64 palettes known.
148 const char ** GdColor::get_c64_palette_names() {
149 return c64_palettes_names
;
152 /// Get an array of C strings, which stores the names of C64DTV palettes known.
153 const char ** GdColor::get_c64dtv_palette_names() {
154 return c64dtv_palettes_names
;
157 /// Get an array of C strings, which stores the names of Atari palettes known.
158 const char ** GdColor::get_atari_palette_names() {
159 return atari_palettes_names
;
162 /// Constructor to create an RGB color from a 0x00RRGGBB value.
163 /// Used internally, as palettes can easily be stored this way.
164 /// @param rgb The 0x00RRGGBB value.
165 GdColor::GdColor(unsigned int rgbval
) {
166 g_assert(rgbval
< 0x1000000);
168 rgb
.b
= (rgbval
>>0) & 0xff;
169 rgb
.g
= (rgbval
>>8) & 0xff;
170 rgb
.r
= (rgbval
>>16) & 0xff;
173 /// Create a GDash color. These are similar to C64 colors,
174 /// but always use the same palette. Internally, they are
176 /// @param c Color index, 0..16.
177 GdColor
GdColor::from_gdash_index(unsigned c
) {
178 g_assert(c
>=0 && c
<G_N_ELEMENTS(gdash_colors
));
179 return GdColor(gdash_colors
[c
]);
182 /// Create a C64 color.
183 /// @param index C64 color index, 0..15
184 GdColor
GdColor::from_c64(unsigned index
) {
185 g_assert(index
>=0 && index
<=15);
186 return GdColor(TypeC64
, index
);
190 /// Create an Atari color.
191 /// @param index Color index, 0..255
192 GdColor
GdColor::from_atari(unsigned index
) {
193 g_assert(index
>=0 && index
<=255);
194 return GdColor(TypeAtari
, index
);
198 /// Create an Atari color, hue+sat version.
199 /// Makes generating random Atari palettes easier.
200 /// @param hue Hue, 0..15
201 /// @param sat Saturation, 0..15
202 GdColor
GdColor::from_atari_huesat(unsigned hue
, unsigned sat
) {
203 g_assert(hue
>=0 && hue
<=15);
204 g_assert(sat
>=0 && sat
<=15);
205 return GdColor(TypeAtari
, 16*hue
+sat
);
208 /// Create a C64DTV color.
209 /// @param index Color index, 0..255
210 GdColor
GdColor::from_c64dtv(unsigned index
) {
211 g_assert(index
>=0 && index
<=255);
212 return GdColor(TypeC64DTV
, index
);
215 /// Create a C64DTV color, hue+sat version.
216 /// @param hue Hue, 0..15
217 /// @param sat Saturation, 0..15
218 GdColor
GdColor::from_c64dtv_huesat(unsigned hue
, unsigned sat
) {
219 g_assert(hue
>=0 && hue
<=15);
220 g_assert(sat
>=0 && sat
<=15);
221 return GdColor(TypeC64DTV
, 16*hue
+sat
);
224 /// Create a color from a given r, g, b value.
225 /// @param r Red value 0..255.
226 /// @param g Green value 0..255.
227 /// @param b Blue value 0..255.
228 GdColor
GdColor::from_rgb(unsigned r
, unsigned g
, unsigned b
) {
229 return GdColor(r
, g
, b
);
232 /// Make up GdColor from h,s,v values.
233 /// @param h Hue, 0..360
234 /// @param s Saturation, 0..100
235 /// @param v Value, 0..100
236 GdColor
GdColor::from_hsv(unsigned short h
, unsigned char s
, unsigned char v
) {
246 /// Create a color from a BDCFF description.
247 /// @param color The string which contains the BDCFF representation.
248 /// @return The new color object.
249 bool read_from_string(std::string
const& str
, GdColor
&c
) {
250 // check if it is a name of a c64 color
251 for (unsigned i
=0; i
<G_N_ELEMENTS(c64_color_bdcff_names
); i
++)
252 if (gd_str_ascii_caseequal(str
, c64_color_bdcff_names
[i
])) {
253 c
=GdColor::from_c64(i
);
257 std::string
strupper(str
);
258 for (unsigned i
=0; i
<strupper
.size(); ++i
)
259 strupper
[i
]=toupper(strupper
[i
]);
260 const char *cstr
=strupper
.c_str();
263 // check if atari color.
264 if (sscanf(cstr
, "ATARI%02x", &x
)==1) {
265 c
=GdColor::from_atari(x
);
269 // check if c64dtv color.
270 if (sscanf(cstr
, "C64DTV%02x", &x
)==1) {
271 c
=GdColor::from_c64dtv(x
);
275 // rgb color? may or may not have a #
279 if (sscanf(cstr
, "%02x%02x%02x", &r
, &g
, &b
)==3) {
280 c
= GdColor::from_rgb(r
, g
, b
);
284 // could not read in any way
289 /// Create a color object, which is RGB internally.
290 /// Uses the current user preferences for conversion.
291 /// The color object created should not be saved, but
292 /// only used on-screen.
293 /// @param color The color to convert.
294 GdColor
GdColor::to_rgb() const {
295 const guint8
*atari_pal
;
296 const guint8
*c64dtv_pal
;
297 const guint32
*c64_pal
;
305 if (gd_c64_palette
<0 || gd_c64_palette
>=(int)G_N_ELEMENTS(c64_palette_pointers
)-1)
306 gd_c64_palette
=0; /* silently switch to default, if invalid value */
307 c64_pal
=c64_palette_pointers
[gd_c64_palette
];
308 return GdColor(c64_pal
[index
]);
311 if (gd_c64dtv_palette
<0 || gd_c64dtv_palette
>=(int)G_N_ELEMENTS(c64dtv_palettes_pointers
)-1)
313 c64dtv_pal
=c64dtv_palettes_pointers
[gd_c64dtv_palette
];
314 return from_rgb(c64dtv_pal
[index
*3], c64dtv_pal
[index
*3+1], c64dtv_pal
[index
*3+2]);
317 if (gd_atari_palette
<0 || gd_atari_palette
>=(int)G_N_ELEMENTS(atari_palettes_pointers
)-1)
319 atari_pal
=atari_palettes_pointers
[gd_atari_palette
];
320 return from_rgb(atari_pal
[index
*3], atari_pal
[index
*3+1], atari_pal
[index
*3+2]);
324 double h
= hsv
.h
, s
= hsv
.s
/100.0, v
= hsv
.v
/100.0;
325 int i
= (int)(h
/60)%6; /* divided by 60 degrees */
326 double f
= h
/60-(int)(h
/60); /* fractional part */
328 double q
= v
*(1-s
*f
);
329 double t
= v
*(1-s
*(1-f
));
337 case 0: return GdColor::from_rgb(v
, t
, p
);
338 case 1: return GdColor::from_rgb(q
, v
, p
);
339 case 2: return GdColor::from_rgb(p
, v
, t
);
340 case 3: return GdColor::from_rgb(p
, q
, v
);
341 case 4: return GdColor::from_rgb(t
, p
, v
);
342 case 5: return GdColor::from_rgb(v
, p
, q
);
344 /* no way we reach this */
345 g_assert_not_reached();
346 return GdColor::from_rgb(0,0,0);
349 g_assert_not_reached();
353 /// Create a color object, which is HSV internally.
354 GdColor
GdColor::to_hsv() const {
358 double R
= get_r()/255.0, G
= get_g()/255.0, B
= get_b()/255.0;
359 double M
= std::max(std::max(R
, G
), B
);
360 double m
= std::min(std::min(R
, G
), B
);
375 return GdColor::from_hsv(fmod(H
*60.0+360, 360), S
*100.0, V
*100.0);
379 /// Get red component of color.
380 /// Uses the current user palette, if needed.
381 unsigned int GdColor::get_r() const {
385 return to_rgb().rgb
.r
;
388 /// Get green component of color.
389 /// Uses the current user palette, if needed.
390 unsigned int GdColor::get_g() const {
394 return to_rgb().rgb
.g
;
397 /// Get blue component of color.
398 /// Uses the current user palette, if needed.
399 unsigned int GdColor::get_b() const {
403 return to_rgb().rgb
.b
;
407 /// Get red component of color.
408 /// Uses the current user palette, if needed.
409 unsigned int GdColor::get_h() const {
413 return to_hsv().hsv
.h
;
416 /// Get green component of color.
417 /// Uses the current user palette, if needed.
418 unsigned int GdColor::get_s() const {
422 return to_hsv().hsv
.s
;
425 /// Get blue component of color.
426 /// Uses the current user palette, if needed.
427 unsigned int GdColor::get_v() const {
431 return to_hsv().hsv
.v
;
435 /// Get RGB components of color as an unsigned int 0x00RRGGBB
436 unsigned int GdColor::get_uint() const {
437 unsigned r
= get_r();
438 unsigned g
= get_g();
439 unsigned b
= get_b();
441 return (r
<<16)+(g
<<8)+b
;
445 /// Standard operator<< to write BDCFF info of the color to an ostream.
446 std::ostream
& operator<<(std::ostream
& os
, const GdColor
& c
) {
450 case GdColor::TypeC64
:
451 sprintf(text
, "%s", c64_color_bdcff_names
[c
.index
]);
454 case GdColor::TypeAtari
:
455 sprintf(text
, "Atari%02x", c
.index
);
458 case GdColor::TypeC64DTV
:
459 sprintf(text
, "C64DTV%02x", c
.index
);
462 case GdColor::TypeRGB
:
463 case GdColor::TypeHSV
:
464 sprintf(text
, "#%02x%02x%02x", c
.get_r(), c
.get_g(), c
.get_b());
471 /// Return on-screen visible name of color.
472 /// Returns strings which can be translated.
474 std::string
visible_name(const GdColor
& c
) {
478 case GdColor::TypeC64
:
479 return c64_color_visible_names
[c
.index
];
482 case GdColor::TypeAtari
:
483 sprintf(text
, "Atari #%02X", c
.index
);
486 case GdColor::TypeC64DTV
:
487 sprintf(text
, "C64DTV #%02X", c
.index
);
490 case GdColor::TypeRGB
:
491 case GdColor::TypeHSV
:
492 sprintf(text
, "RGB #%02X%02X%02X", c
.get_r(), c
.get_g(), c
.get_b());
495 /* should not happen */
496 return N_("Invalid");
500 /// Check if the color is a C64 color.
501 /// @return True, if C64 color.
502 bool GdColor::is_c64() const {
503 return type
==TypeC64
;
506 /// Return the "traditional" c64 index of color.
507 /// If not found, reports the error, and gives a random color.
508 /// @return The C64 index.
509 int GdColor::get_c64_index() const {
512 gd_message(CPrintf("Non-C64 color: %s") % visible_name(*this));
513 return g_random_int_range(0, 16);
516 /// Compare two color objects for equality.
517 /// @return True, if they are equal. They must be also of the same type, same rgb values are not enough!
518 bool GdColor::operator==(const GdColor
&rhs
) const {
522 /* for rgb, all must match. */
524 return rgb
.r
==rhs
.rgb
.r
&& rgb
.g
==rhs
.rgb
.g
&& rgb
.b
==rhs
.rgb
.b
;
526 return hsv
.h
==rhs
.hsv
.h
&& hsv
.s
==rhs
.hsv
.s
&& hsv
.v
==rhs
.hsv
.v
;
528 /* for others, we check only r which is used as an index. */
529 return index
==rhs
.index
;