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 <pango/pango-attributes.h>
38 #include <gobject/gvaluecollector.h>
40 #include "clutter-main.h"
41 #include "clutter-color.h"
42 #include "clutter-private.h"
43 #include "clutter-debug.h"
47 * @src1: a #ClutterColor
48 * @src2: a #ClutterColor
49 * @dest: (out): return location for the result
51 * Adds @src2 to @src1 and saves the resulting color
54 * The alpha channel of @dest is as the maximum value
55 * between the alpha channels of @src1 and @src2.
58 clutter_color_add (const ClutterColor *src1,
59 const ClutterColor *src2,
62 g_return_if_fail (src1 != NULL);
63 g_return_if_fail (src2 != NULL);
64 g_return_if_fail (dest != NULL);
66 dest->red = CLAMP (src1->red + src2->red, 0, 255);
67 dest->green = CLAMP (src1->green + src2->green, 0, 255);
68 dest->blue = CLAMP (src1->blue + src2->blue, 0, 255);
70 dest->alpha = MAX (src1->alpha, src2->alpha);
74 * clutter_color_subtract:
75 * @src1: a #ClutterColor
76 * @src2: a #ClutterColor
77 * @dest: (out): return location for the result
79 * Subtracts @src2 from @src1 and saves the resulting
80 * color inside @dest. This function assumes that the components
81 * of @src1 are greater than the components of @src2; the result is,
82 * otherwise, undefined.
84 * The alpha channel of @dest is set as the minimum value
85 * between the alpha channels of @src1 and @src2.
88 clutter_color_subtract (const ClutterColor *src1,
89 const ClutterColor *src2,
92 g_return_if_fail (src1 != NULL);
93 g_return_if_fail (src2 != NULL);
94 g_return_if_fail (dest != NULL);
96 dest->red = CLAMP (src1->red - src2->red, 0, 255);
97 dest->green = CLAMP (src1->green - src2->green, 0, 255);
98 dest->blue = CLAMP (src1->blue - src2->blue, 0, 255);
100 dest->alpha = MIN (src1->alpha, src2->alpha);
104 * clutter_color_lighten:
105 * @src: a #ClutterColor
106 * @dest: (out): return location for the lighter color
108 * Lightens @src by a fixed amount, and saves the changed
112 clutter_color_lighten (const ClutterColor *src,
115 clutter_color_shadex (src, dest, CLUTTER_FLOAT_TO_FIXED (1.3));
119 * clutter_color_darken:
120 * @src: a #ClutterColor
121 * @dest: (out): return location for the darker color
123 * Darkens @src by a fixed amount, and saves the changed color
127 clutter_color_darken (const ClutterColor *src,
130 clutter_color_shadex (src, dest, CLUTTER_FLOAT_TO_FIXED (0.7));
134 * clutter_color_to_hlsx:
135 * @src: a #ClutterColor
136 * @hue: return location for the hue value or %NULL
137 * @luminance: return location for the luminance value or %NULL
138 * @saturation: return location for the saturation value or %NULL
140 * Converts @src to the HLS format. Returned hue is in degrees (0 .. 360),
141 * luminance and saturation from interval <0 .. 1>.
144 clutter_color_to_hlsx (const ClutterColor *src,
146 ClutterFixed *luminance,
147 ClutterFixed *saturation)
149 ClutterFixed red, green, blue;
150 ClutterFixed min, max, delta;
151 ClutterFixed h, l, s;
153 g_return_if_fail (src != NULL);
155 red = (float)(src->red) / 255;
156 green = (float)(src->green) / 255;
157 blue = (float)(src->blue) / 255;
191 s = CLUTTER_FIXED_DIV ((max - min), (max + min));
193 s = CLUTTER_FIXED_DIV ((max - min),
194 ((float)(2) - max - min));
199 h = CLUTTER_FIXED_DIV ((green - blue), delta);
200 else if (green == max)
203 + CLUTTER_FIXED_DIV ((blue - red), delta);
205 else if (blue == max)
208 + CLUTTER_FIXED_DIV ((red - green), delta);
228 * clutter_color_from_hlsx:
229 * @dest: (out): return location for a #ClutterColor
230 * @hue: hue value (0 .. 360)
231 * @luminance: luminance value (0 .. 1)
232 * @saturation: saturation value (0 .. 1)
234 * Converts a color expressed in HLS (hue, luminance and saturation)
235 * values into a #ClutterColor.
239 clutter_color_from_hlsx (ClutterColor *dest,
241 ClutterFixed luminance,
242 ClutterFixed saturation)
244 ClutterFixed h, l, s;
247 g_return_if_fail (dest != NULL);
253 m2 = CLUTTER_FIXED_MUL (l, (1.0 + s));
255 m2 = l + s - CLUTTER_FIXED_MUL (l, s);
261 dest->red = (guint8) (l * 255);
262 dest->green = (guint8) (l * 255);
263 dest->blue = (guint8) (l * 255);
279 tmp = (m1 + CLUTTER_FIXED_MUL ((m2 - m1), h) / 60);
280 dest->red = (guint8) (tmp * 255);
283 dest->red = (guint8) (m2 * 255);
288 tmp = (m1 + CLUTTER_FIXED_MUL ((m2 - m1), (240.0 - h)))
290 dest->red = (guint8) (tmp * 255);
293 dest->red = (guint8) (m1 * 255);
305 tmp = (m1 + CLUTTER_FIXED_MUL ((m2 - m1), h) / 60);
306 dest->green = (guint8) (tmp * 255);
309 dest->green = (guint8) (m2 * 255);
314 tmp = (m1 + CLUTTER_FIXED_MUL ((m2 - m1) , (240.0 - h)))
316 dest->green = (guint8) (tmp * 255);
319 dest->green = (guint8) (m1 * 255);
333 tmp = (m1 + CLUTTER_FIXED_MUL ((m2 - m1), h) / 60);
334 dest->blue = (guint8) (tmp * 255);
337 dest->blue = (guint8) (m2 * 255);
342 tmp = (m1 + CLUTTER_FIXED_MUL ((m2 - m1), (240.0 - h)))
344 dest->blue = (guint8) (tmp * 255);
347 dest->blue = (guint8) (m1 * 255);
352 * clutter_color_to_hls:
353 * @src: a #ClutterColor
354 * @hue: return location for the hue value or %NULL
355 * @luminance: return location for the luminance value or %NULL
356 * @saturation: return location for the saturation value or %NULL
358 * Converts @src to the HLS format. Returned HLS values are from interval
362 clutter_color_to_hls (const ClutterColor *src,
367 ClutterFixed h, l, s;
369 clutter_color_to_hlsx (src, &h, &l, &s);
372 *hue = (guint8) (h * 255) / 360;
375 *luminance = (guint8) (l * 255);
378 *saturation = (guint8) (s * 255);
382 * clutter_color_from_hls:
383 * @dest: (out): return location for a #ClutterColor
384 * @hue: hue value (0 .. 255)
385 * @luminance: luminance value (0 .. 255)
386 * @saturation: saturation value (0 .. 255)
388 * Converts a color expressed in HLS (hue, luminance and saturation)
389 * values into a #ClutterColor.
393 clutter_color_from_hls (ClutterColor *dest,
398 ClutterFixed h, l, s;
400 h = (float)(hue * 360) / 255;
401 l = (float)(luminance) / 255;
402 s = (float)(saturation) / 255;
404 clutter_color_from_hlsx (dest, h, l, s);
408 * clutter_color_shade:
409 * @src: a #ClutterColor
410 * @dest: (out): return location for the shaded color
411 * @shade: the shade factor to apply
413 * Shades @src by the factor of @shade and saves the modified
417 clutter_color_shade (const ClutterColor *src,
421 clutter_color_shadex (src, dest, CLUTTER_FLOAT_TO_FIXED (shade));
425 * clutter_color_shadex:
426 * @src: a #ClutterColor
427 * @dest: (out): return location for the shaded color
428 * @shade: #ClutterFixed the shade factor to apply
430 * Fixed point version of clutter_color_shade().
432 * Shades @src by the factor of @shade and saves the modified
438 clutter_color_shadex (const ClutterColor *src,
442 ClutterFixed h, l, s;
444 g_return_if_fail (src != NULL);
445 g_return_if_fail (dest != NULL);
447 clutter_color_to_hlsx (src, &h, &l, &s);
449 l = CLUTTER_FIXED_MUL (l, shade);
455 s = CLUTTER_FIXED_MUL (s, shade);
461 clutter_color_from_hlsx (dest, h, l, s);
462 dest->alpha = src->alpha;
466 * clutter_color_to_pixel:
467 * @src: a #ClutterColor
469 * Converts @src into a packed 32 bit integer, containing
470 * all the four 8 bit channels used by #ClutterColor.
472 * Return value: a packed color
475 clutter_color_to_pixel (const ClutterColor *src)
477 g_return_val_if_fail (src != NULL, 0);
479 return (src->alpha | src->blue << 8 | src->green << 16 | src->red << 24);
483 * clutter_color_from_pixel:
484 * @dest: (out): return location for a #ClutterColor
485 * @pixel: a 32 bit packed integer containing a color
487 * Converts @pixel from the packed representation of a four 8 bit channel
488 * color to a #ClutterColor.
491 clutter_color_from_pixel (ClutterColor *dest,
494 g_return_if_fail (dest != NULL);
496 dest->red = pixel >> 24;
497 dest->green = (pixel >> 16) & 0xff;
498 dest->blue = (pixel >> 8) & 0xff;
499 dest->alpha = pixel & 0xff;
503 * clutter_color_parse:
504 * @color: a string specifiying a color (named color or #RRGGBBAA)
505 * @dest: (out): return location for a #ClutterColor
507 * Parses a string definition of a color, filling the
508 * <structfield>red</structfield>, <structfield>green</structfield>,
509 * <structfield>blue</structfield> and <structfield>alpha</structfield>
510 * channels of @dest. If alpha is not specified it will be set full opaque.
511 * The color in @dest is not allocated.
513 * The color may be defined by any of the formats understood by
514 * <function>pango_color_parse</function>; these include literal color
515 * names, like <literal>Red</literal> or <literal>DarkSlateGray</literal>,
516 * or hexadecimal specifications like <literal>#3050b2</literal> or
517 * <literal>#333</literal>.
519 * Return value: %TRUE if parsing succeeded.
524 clutter_color_parse (const gchar *color,
527 PangoColor pango_color;
529 g_return_val_if_fail (color != NULL, FALSE);
530 g_return_val_if_fail (dest != NULL, FALSE);
532 /* parse ourselves to get alpha */
537 if (sscanf (color + 1, "%x", &result))
539 if (strlen (color) == 9)
541 dest->red = (result >> 24) & 0xff;
542 dest->green = (result >> 16) & 0xff;
543 dest->blue = (result >> 8) & 0xff;
544 dest->alpha = result & 0xff;
548 else if (strlen (color) == 7)
550 dest->red = (result >> 16) & 0xff;
551 dest->green = (result >> 8) & 0xff;
552 dest->blue = result & 0xff;
560 /* Fall back to pango for named colors - note pango does not handle alpha */
561 if (pango_color_parse (&pango_color, color))
563 dest->red = pango_color.red;
564 dest->green = pango_color.green;
565 dest->blue = pango_color.blue;
575 * clutter_color_to_string:
576 * @color: a #ClutterColor
578 * Returns a textual specification of @color in the hexadecimal form
579 * <literal>#rrggbbaa</literal>, where <literal>r</literal>,
580 * <literal>g</literal>, <literal>b</literal> and <literal>a</literal> are
581 * hex digits representing the red, green, blue and alpha components
584 * Return value: a newly-allocated text string
589 clutter_color_to_string (const ClutterColor *color)
591 g_return_val_if_fail (color != NULL, NULL);
593 return g_strdup_printf ("#%02x%02x%02x%02x",
601 * clutter_color_equal:
602 * @a: a #ClutterColor
603 * @b: a #ClutterColor
605 * Compares two #ClutterColor<!-- -->s and checks if they are the same.
607 * Return value: %TRUE if the two colors are the same.
612 clutter_color_equal (const ClutterColor *a,
613 const ClutterColor *b)
615 g_return_val_if_fail (a != NULL, FALSE);
616 g_return_val_if_fail (b != NULL, FALSE);
621 return (a->red == b->red &&
622 a->green == b->green &&
623 a->blue == b->blue &&
624 a->alpha == b->alpha);
628 * clutter_color_copy:
629 * @color: a #ClutterColor
631 * Makes a copy of the color structure. The result must be
632 * freed using clutter_color_free().
634 * Return value: an allocated copy of @color.
639 clutter_color_copy (const ClutterColor *color)
641 ClutterColor *result;
643 g_return_val_if_fail (color != NULL, NULL);
645 result = g_slice_new (ClutterColor);
652 * clutter_color_free:
653 * @color: a #ClutterColor
655 * Frees a color structure created with clutter_color_copy().
660 clutter_color_free (ClutterColor *color)
662 if (G_LIKELY (color))
663 g_slice_free (ClutterColor, color);
668 * @red: red component of the color, between 0 and 255
669 * @green: green component of the color, between 0 and 255
670 * @blue: blue component of the color, between 0 and 255
671 * @alpha: alpha component of the color, between 0 and 255
673 * Creates a new #ClutterColor with the given values.
675 * Return value: the newly allocated color. Use clutter_color_free()
681 clutter_color_new (guint8 red,
688 color = g_slice_new (ClutterColor);
691 color->green = green;
693 color->alpha = alpha;
699 clutter_value_transform_color_string (const GValue *src,
702 gchar *string = clutter_color_to_string (src->data[0].v_pointer);
704 g_value_take_string (dest, string);
708 clutter_value_transform_string_color (const GValue *src,
711 ClutterColor color = { 0, };
713 clutter_color_parse (g_value_get_string (src), &color);
715 clutter_value_set_color (dest, &color);
719 clutter_color_get_type (void)
721 static GType _clutter_color_type = 0;
723 if (G_UNLIKELY (_clutter_color_type == 0))
725 _clutter_color_type =
726 g_boxed_type_register_static (I_("ClutterColor"),
727 (GBoxedCopyFunc) clutter_color_copy,
728 (GBoxedFreeFunc) clutter_color_free);
730 g_value_register_transform_func (_clutter_color_type, G_TYPE_STRING,
731 clutter_value_transform_color_string);
732 g_value_register_transform_func (G_TYPE_STRING, _clutter_color_type,
733 clutter_value_transform_string_color);
736 return _clutter_color_type;
740 clutter_value_init_color (GValue *value)
742 value->data[0].v_pointer = NULL;
746 clutter_value_free_color (GValue *value)
748 if (!(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
749 clutter_color_free (value->data[0].v_pointer);
753 clutter_value_copy_color (const GValue *src,
756 dest->data[0].v_pointer = clutter_color_copy (src->data[0].v_pointer);
760 clutter_value_peek_color (const GValue *value)
762 return value->data[0].v_pointer;
766 clutter_value_collect_color (GValue *value,
767 guint n_collect_values,
768 GTypeCValue *collect_values,
771 if (!collect_values[0].v_pointer)
772 value->data[0].v_pointer = NULL;
775 if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
777 value->data[0].v_pointer = collect_values[0].v_pointer;
778 value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
782 value->data[0].v_pointer =
783 clutter_color_copy (collect_values[0].v_pointer);
791 clutter_value_lcopy_color (const GValue *value,
792 guint n_collect_values,
793 GTypeCValue *collect_values,
796 ClutterColor **color_p = collect_values[0].v_pointer;
799 return g_strdup_printf ("value location for `%s' passed as NULL",
800 G_VALUE_TYPE_NAME (value));
802 if (!value->data[0].v_pointer)
806 if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
807 *color_p = value->data[0].v_pointer;
809 *color_p = clutter_color_copy (value->data[0].v_pointer);
816 * clutter_value_set_color:
817 * @value: a #GValue initialized to #CLUTTER_TYPE_COLOR
818 * @color: the color to set
820 * Sets @value to @color.
825 clutter_value_set_color (GValue *value,
826 const ClutterColor *color)
828 g_return_if_fail (CLUTTER_VALUE_HOLDS_COLOR (value));
830 value->data[0].v_pointer = clutter_color_copy (color);
834 * clutter_value_get_color:
835 * @value: a #GValue initialized to #CLUTTER_TYPE_COLOR
837 * Gets the #ClutterColor contained in @value.
839 * Return value: the colors inside the passed #GValue
843 G_CONST_RETURN ClutterColor *
844 clutter_value_get_color (const GValue *value)
846 g_return_val_if_fail (CLUTTER_VALUE_HOLDS_COLOR (value), NULL);
848 return value->data[0].v_pointer;
852 param_color_init (GParamSpec *pspec)
854 ClutterParamSpecColor *cspec = CLUTTER_PARAM_SPEC_COLOR (pspec);
856 cspec->default_value = NULL;
860 param_color_finalize (GParamSpec *pspec)
862 ClutterParamSpecColor *cspec = CLUTTER_PARAM_SPEC_COLOR (pspec);
864 clutter_color_free (cspec->default_value);
868 param_color_set_default (GParamSpec *pspec,
871 value->data[0].v_pointer = CLUTTER_PARAM_SPEC_COLOR (pspec)->default_value;
872 value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
876 param_color_values_cmp (GParamSpec *pspec,
877 const GValue *value1,
878 const GValue *value2)
880 guint32 color1, color2;
882 color1 = clutter_color_to_pixel (value1->data[0].v_pointer);
883 color2 = clutter_color_to_pixel (value2->data[0].v_pointer);
887 else if (color1 == color2)
893 static const GTypeValueTable _clutter_color_value_table = {
894 clutter_value_init_color,
895 clutter_value_free_color,
896 clutter_value_copy_color,
897 clutter_value_peek_color,
899 clutter_value_collect_color,
901 clutter_value_lcopy_color
905 clutter_param_color_get_type (void)
907 static GType pspec_type = 0;
909 if (G_UNLIKELY (pspec_type == 0))
911 const GParamSpecTypeInfo pspec_info = {
912 sizeof (ClutterParamSpecColor),
916 param_color_finalize,
917 param_color_set_default,
919 param_color_values_cmp,
922 pspec_type = g_param_type_register_static (I_("ClutterParamSpecColor"),
930 * clutter_param_spec_color:
931 * @name: name of the property
933 * @blurb: description (can be translatable)
934 * @default_value: default value
935 * @flags: flags for the param spec
937 * Creates a #GParamSpec for properties using #ClutterColor.
939 * Return value: the newly created #GParamSpec
944 clutter_param_spec_color (const gchar *name,
947 const ClutterColor *default_value,
950 ClutterParamSpecColor *cspec;
952 cspec = g_param_spec_internal (CLUTTER_TYPE_PARAM_COLOR,
953 name, nick, blurb, flags);
955 cspec->default_value = clutter_color_copy (default_value);
957 return G_PARAM_SPEC (cspec);