4 * An OpenGL based 'interactive canvas' library.
6 * Authored By Matthew Allum <mallum@openedhand.com>
8 * Copyright (C) 2006 OpenedHand
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
27 * SECTION:clutter-color
28 * @short_description: Color management and manipulation.
30 * #ClutterColor is a simple type for representing colors.
37 #include "clutter-main.h"
38 #include "clutter-color.h"
39 #include "clutter-private.h"
40 #include "clutter-debug.h"
44 * @src1: a #ClutterColor
45 * @src2: a #ClutterColor
46 * @dest: return location for the result
48 * Adds @src2 to @src1 and saves the resulting color
51 * The alpha channel of @dest is as the maximum value
52 * between the alpha channels of @src1 and @src2.
55 clutter_color_add (const ClutterColor *src1,
56 const ClutterColor *src2,
59 g_return_if_fail (src1 != NULL);
60 g_return_if_fail (src2 != NULL);
61 g_return_if_fail (dest != NULL);
63 dest->red = CLAMP (src1->red + src2->red, 0, 255);
64 dest->green = CLAMP (src1->green + src2->green, 0, 255);
65 dest->blue = CLAMP (src1->blue + src2->blue, 0, 255);
67 dest->alpha = MAX (src1->alpha, src2->alpha);
71 * clutter_color_subtract:
72 * @src1: a #ClutterColor
73 * @src2: a #ClutterColor
74 * @dest: return location for the result
76 * Subtracts @src2 from @src1 and saves the resulting
79 * The alpha channel of @dest is set as the minimum value
80 * between the alpha channels of @src1 and @src2.
83 clutter_color_subtract (const ClutterColor *src1,
84 const ClutterColor *src2,
87 g_return_if_fail (src1 != NULL);
88 g_return_if_fail (src2 != NULL);
89 g_return_if_fail (dest != NULL);
91 dest->red = CLAMP (src2->red - src1->red, 0, 255);
92 dest->green = CLAMP (src2->green - src1->green, 0, 255);
93 dest->blue = CLAMP (src2->blue - src1->blue, 0, 255);
95 dest->alpha = MIN (src1->alpha, src2->alpha);
99 * clutter_color_lighten:
100 * @src: a #ClutterColor
101 * @dest: return location for the lighter color
103 * Lightens @src by a fixed amount, and saves the changed
107 clutter_color_lighten (const ClutterColor *src,
110 /* 0x14ccd is ClutterFixed for 1.3 */
111 clutter_color_shadex (src, dest, 0x14ccd);
115 * clutter_color_darken:
116 * @src: a #ClutterColor
117 * @dest: return location for the darker color
119 * Darkens @src by a fixed amount, and saves the changed color
123 clutter_color_darken (const ClutterColor *src,
126 /* 0xb333 is ClutterFixed for 0.7 */
127 clutter_color_shadex (src, dest, 0xb333);
131 * clutter_color_to_hlsx:
132 * @src: a #ClutterColor
133 * @hue: return location for the hue value or %NULL
134 * @luminance: return location for the luminance value or %NULL
135 * @saturation: return location for the saturation value or %NULL
137 * Converts @src to the HLS format. Returned hue is in degrees (0 .. 360),
138 * luminance and saturation from interval <0 .. 1>.
141 clutter_color_to_hlsx (const ClutterColor *src,
143 ClutterFixed *luminance,
144 ClutterFixed *saturation)
146 ClutterFixed red, green, blue;
147 ClutterFixed min, max, delta;
148 ClutterFixed h, l, s;
150 g_return_if_fail (src != NULL);
152 red = CLUTTER_INT_TO_FIXED (src->red) / 255;
153 green = CLUTTER_INT_TO_FIXED (src->green) / 255;
154 blue = CLUTTER_INT_TO_FIXED (src->blue) / 255;
188 s = CFX_DIV ((max - min), (max + min));
190 s = CFX_DIV ((max - min), (2 - max - min));
194 h = CFX_DIV ((green - blue), delta);
195 else if (green == max)
196 h = CLUTTER_INT_TO_FIXED (2) + CFX_DIV ((blue - red), delta);
197 else if (blue == max)
198 h = CLUTTER_INT_TO_FIXED (4) + CFX_DIV ((red - green), delta);
202 h += CLUTTER_INT_TO_FIXED (360);
216 * clutter_color_from_hlsx:
217 * @dest: return location for a #ClutterColor
218 * @hue: hue value (0 .. 360)
219 * @luminance: luminance value (0 .. 1)
220 * @saturation: saturation value (0 .. 1)
222 * Converts a color expressed in HLS (hue, luminance and saturation)
223 * values into a #ClutterColor.
227 clutter_color_from_hlsx (ClutterColor *dest,
229 ClutterFixed luminance,
230 ClutterFixed saturation)
232 ClutterFixed h, l, s;
235 g_return_if_fail (dest != NULL);
241 m2 = CFX_MUL (l, (CFX_ONE + s));
243 m2 = l + s - CFX_MUL (l,s);
249 dest->red = (guint8) CFX_INT (l * 255);
250 dest->green = (guint8) CFX_INT (l * 255);
251 dest->blue = (guint8) CFX_INT (l * 255);
262 dest->red = (guint8) CFX_INT((m1 + CFX_MUL((m2-m1), h) / 60) * 255);
263 else if (h < CFX_180)
264 dest->red = (guint8) CFX_INT (m2 * 255);
265 else if (h < CFX_240)
266 dest->red = (guint8)CFX_INT((m1+CFX_MUL((m2-m1),(CFX_240-h))/60)*255);
268 dest->red = (guint8) CFX_INT (m1 * 255);
277 dest->green = (guint8)CFX_INT((m1 + CFX_MUL((m2 - m1), h) / 60) * 255);
278 else if (h < CFX_180)
279 dest->green = (guint8) CFX_INT (m2 * 255);
280 else if (h < CFX_240)
282 (guint8) CFX_INT((m1 + CFX_MUL ((m2-m1), (CFX_240-h)) / 60) * 255);
284 dest->green = (guint8) CFX_INT (m1 * 255);
293 dest->blue = (guint8) CFX_INT ((m1 + CFX_MUL ((m2-m1), h) / 60) * 255);
294 else if (h < CFX_180)
295 dest->blue = (guint8) CFX_INT (m2 * 255);
296 else if (h < CFX_240)
297 dest->blue = (guint8)CFX_INT((m1+CFX_MUL((m2-m1),(CFX_240-h))/60)*255);
299 dest->blue = (guint8) CFX_INT(m1 * 255);
304 * clutter_color_to_hls:
305 * @src: a #ClutterColor
306 * @hue: return location for the hue value or %NULL
307 * @luminance: return location for the luminance value or %NULL
308 * @saturation: return location for the saturation value or %NULL
310 * Converts @src to the HLS format. Returned HLS values are from interval
314 clutter_color_to_hls (const ClutterColor *src,
319 ClutterFixed h, l, s;
321 clutter_color_to_hlsx (src, &h, &l, &s);
324 *hue = (guint8) CFX_INT (h * 255) / 360;
327 *luminance = (guint8) CFX_INT (l * 255);
330 *saturation = (guint8) CFX_INT (s * 255);
334 * clutter_color_from_hls:
335 * @dest: return location for a #ClutterColor
336 * @hue: hue value (0 .. 255)
337 * @luminance: luminance value (0 .. 255)
338 * @saturation: saturation value (0 .. 255)
340 * Converts a color expressed in HLS (hue, luminance and saturation)
341 * values into a #ClutterColor.
345 clutter_color_from_hls (ClutterColor *dest,
350 ClutterFixed h, l, s;
352 h = CLUTTER_INT_TO_FIXED (hue * 360) / 255;
353 l = CLUTTER_INT_TO_FIXED (luminance) / 255;
354 s = CLUTTER_INT_TO_FIXED (saturation) / 255;
356 clutter_color_from_hlsx (dest, h, l, s);
360 * clutter_color_shade:
361 * @src: a #ClutterColor
362 * @dest: return location for the shaded color
363 * @shade: the shade factor to apply
365 * Shades @src by the factor of @shade and saves the modified
369 clutter_color_shade (const ClutterColor *src,
373 clutter_color_shadex (src, dest, CLUTTER_FLOAT_TO_FIXED (shade));
377 * clutter_color_shadex:
378 * @src: a #ClutterColor
379 * @dest: return location for the shaded color
380 * @shade: #ClutterFixed the shade factor to apply
382 * Fixed point version of clutter_color_shade().
384 * Shades @src by the factor of @shade and saves the modified
390 clutter_color_shadex (const ClutterColor *src,
394 ClutterFixed h, l, s;
396 g_return_if_fail (src != NULL);
397 g_return_if_fail (dest != NULL);
399 clutter_color_to_hlsx (src, &h, &l, &s);
401 l = CFX_MUL (l, shade);
407 s = CFX_MUL (s, shade);
413 clutter_color_from_hlsx (dest, h, l, s);
417 * clutter_color_to_pixel:
418 * @src: a #ClutterColor
420 * Converts @src into a packed 32 bit integer, containing
421 * all the four 8 bit channels used by #ClutterColor.
423 * Return value: a packed color
426 clutter_color_to_pixel (const ClutterColor *src)
428 g_return_val_if_fail (src != NULL, 0);
430 return (src->alpha | src->blue << 8 | src->green << 16 | src->red << 24);
434 * clutter_color_from_pixel:
435 * @dest: return location for a #ClutterColor
436 * @pixel: a 32 bit packed integer containing a color
438 * Converts @pixel from the packed representation of a four 8 bit channel
439 * color to a #ClutterColor.
442 clutter_color_from_pixel (ClutterColor *dest,
445 g_return_if_fail (dest != NULL);
447 dest->red = pixel >> 24;
448 dest->green = (pixel >> 16) & 0xff;
449 dest->blue = (pixel >> 8) & 0xff;
450 dest->alpha = pixel & 0xff;
454 * clutter_color_parse:
455 * @color: a string specifiying a color (named color or #RRGGBBAA)
456 * @dest: return location for a #ClutterColor
458 * Parses a string definition of a color, filling the
459 * <structfield>red</structfield>, <structfield>green</structfield>,
460 * <structfield>blue</structfield> and <structfield>alpha</structfield>
461 * channels of @dest. If alpha is not specified it will be set full opaque.
462 * The color in @dest is not allocated.
464 * The color may be defined by any of the formats understood by
465 * <function>pango_color_parse</function>; these include literal color
466 * names, like <literal>Red</literal> or <literal>DarkSlateGray</literal>,
467 * or hexadecimal specifications like <literal>#3050b2</literal> or
468 * <literal>#333</literal>.
470 * Return value: %TRUE if parsing succeeded.
475 clutter_color_parse (const gchar *color,
478 PangoColor pango_color;
480 /* parse ourselves to get alpha */
485 if (sscanf (color+1, "%x", &result))
487 if (strlen(color) == 9)
489 dest->red = result >> 24 & 0xff;
490 dest->green = (result >> 16) & 0xff;
491 dest->blue = (result >> 8) & 0xff;
492 dest->alpha = result & 0xff;
495 else if (strlen(color) == 7)
497 dest->red = (result >> 16) & 0xff;
498 dest->green = (result >> 8) & 0xff;
499 dest->blue = result & 0xff;
506 /* Fall back to pango for named colors - note pango does not handle alpha */
507 if (pango_color_parse (&pango_color, color))
509 dest->red = pango_color.red;
510 dest->green = pango_color.green;
511 dest->blue = pango_color.blue;
520 * clutter_color_to_string:
521 * @color: a #ClutterColor
523 * Returns a textual specification of @color in the hexadecimal form
524 * <literal>#rrrrggggbbbbaaaa</literal>, where <literal>r</literal>,
525 * <literal>g</literal>, <literal>b</literal> and <literal>a</literal> are
526 * hex digits representing the red, green, blue and alpha components
529 * Note: the returned string cannot be used to get the color back with
530 * clutter_color_parse().
532 * Return value: a newly-allocated text string
537 clutter_color_to_string (const ClutterColor *color)
539 g_return_val_if_fail (color != NULL, NULL);
541 return g_strdup_printf ("#%04x%04x%04x%04x",
549 * clutter_color_equal:
550 * @a: a #ClutterColor
551 * @b: a #ClutterColor
553 * Compares two #ClutterColor<!-- -->s and checks if they are the same.
555 * Return value: %TRUE if the two colors are the same.
560 clutter_color_equal (const ClutterColor *a,
561 const ClutterColor *b)
563 g_return_val_if_fail (a != NULL, FALSE);
564 g_return_val_if_fail (b != NULL, FALSE);
569 return (a->red == b->red &&
570 a->green == b->green &&
571 a->blue == b->blue &&
572 a->alpha == b->alpha);
576 * clutter_color_copy:
577 * @color: a #ClutterColor
579 * Makes a copy of the color structure. The result must be
580 * freed using clutter_color_free().
582 * Return value: an allocated copy of @color.
587 clutter_color_copy (const ClutterColor *color)
589 ClutterColor *result;
591 g_return_val_if_fail (color != NULL, NULL);
593 result = g_slice_new (ClutterColor);
600 * clutter_color_free:
601 * @color: a #ClutterColor
603 * Frees a color structure created with clutter_color_copy().
608 clutter_color_free (ClutterColor *color)
610 g_return_if_fail (color != NULL);
612 g_slice_free (ClutterColor, color);
616 clutter_color_get_type (void)
618 static GType our_type = 0;
621 our_type = g_boxed_type_register_static ("ClutterColor",
622 (GBoxedCopyFunc) clutter_color_copy,
623 (GBoxedFreeFunc) clutter_color_free);