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: 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: 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: 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 /* 0x14ccd is ClutterFixed for 1.3 */
116 clutter_color_shadex (src, dest, 0x14ccd);
120 * clutter_color_darken:
121 * @src: a #ClutterColor
122 * @dest: return location for the darker color
124 * Darkens @src by a fixed amount, and saves the changed color
128 clutter_color_darken (const ClutterColor *src,
131 /* 0xb333 is ClutterFixed for 0.7 */
132 clutter_color_shadex (src, dest, 0xb333);
136 * clutter_color_to_hlsx:
137 * @src: a #ClutterColor
138 * @hue: return location for the hue value or %NULL
139 * @luminance: return location for the luminance value or %NULL
140 * @saturation: return location for the saturation value or %NULL
142 * Converts @src to the HLS format. Returned hue is in degrees (0 .. 360),
143 * luminance and saturation from interval <0 .. 1>.
146 clutter_color_to_hlsx (const ClutterColor *src,
148 ClutterFixed *luminance,
149 ClutterFixed *saturation)
151 ClutterFixed red, green, blue;
152 ClutterFixed min, max, delta;
153 ClutterFixed h, l, s;
155 g_return_if_fail (src != NULL);
157 red = (float)(src->red) / 255;
158 green = (float)(src->green) / 255;
159 blue = (float)(src->blue) / 255;
193 s = CLUTTER_FIXED_DIV ((max - min), (max + min));
195 s = CLUTTER_FIXED_DIV ((max - min),
196 ((float)(2) - max - min));
201 h = CLUTTER_FIXED_DIV ((green - blue), delta);
202 else if (green == max)
205 + CLUTTER_FIXED_DIV ((blue - red), delta);
207 else if (blue == max)
210 + CLUTTER_FIXED_DIV ((red - green), delta);
230 * clutter_color_from_hlsx:
231 * @dest: return location for a #ClutterColor
232 * @hue: hue value (0 .. 360)
233 * @luminance: luminance value (0 .. 1)
234 * @saturation: saturation value (0 .. 1)
236 * Converts a color expressed in HLS (hue, luminance and saturation)
237 * values into a #ClutterColor.
241 clutter_color_from_hlsx (ClutterColor *dest,
243 ClutterFixed luminance,
244 ClutterFixed saturation)
246 ClutterFixed h, l, s;
249 g_return_if_fail (dest != NULL);
255 m2 = CLUTTER_FIXED_MUL (l, (1.0 + s));
257 m2 = l + s - CLUTTER_FIXED_MUL (l, s);
263 dest->red = (guint8) (l * 255);
264 dest->green = (guint8) (l * 255);
265 dest->blue = (guint8) (l * 255);
281 tmp = (m1 + CLUTTER_FIXED_MUL ((m2 - m1), h) / 60);
282 dest->red = (guint8) (tmp * 255);
285 dest->red = (guint8) (m2 * 255);
290 tmp = (m1 + CLUTTER_FIXED_MUL ((m2 - m1), (240.0 - h)))
292 dest->red = (guint8) (tmp * 255);
295 dest->red = (guint8) (m1 * 255);
307 tmp = (m1 + CLUTTER_FIXED_MUL ((m2 - m1), h) / 60);
308 dest->green = (guint8) (tmp * 255);
311 dest->green = (guint8) (m2 * 255);
316 tmp = (m1 + CLUTTER_FIXED_MUL ((m2 - m1) , (240.0 - h)))
318 dest->green = (guint8) (tmp * 255);
321 dest->green = (guint8) (m1 * 255);
335 tmp = (m1 + CLUTTER_FIXED_MUL ((m2 - m1), h) / 60);
336 dest->blue = (guint8) (tmp * 255);
339 dest->blue = (guint8) (m2 * 255);
344 tmp = (m1 + CLUTTER_FIXED_MUL ((m2 - m1), (240.0 - h)))
346 dest->blue = (guint8) (tmp * 255);
349 dest->blue = (guint8) (m1 * 255);
354 * clutter_color_to_hls:
355 * @src: a #ClutterColor
356 * @hue: return location for the hue value or %NULL
357 * @luminance: return location for the luminance value or %NULL
358 * @saturation: return location for the saturation value or %NULL
360 * Converts @src to the HLS format. Returned HLS values are from interval
364 clutter_color_to_hls (const ClutterColor *src,
369 ClutterFixed h, l, s;
371 clutter_color_to_hlsx (src, &h, &l, &s);
374 *hue = (guint8) (h * 255) / 360;
377 *luminance = (guint8) (l * 255);
380 *saturation = (guint8) (s * 255);
384 * clutter_color_from_hls:
385 * @dest: return location for a #ClutterColor
386 * @hue: hue value (0 .. 255)
387 * @luminance: luminance value (0 .. 255)
388 * @saturation: saturation value (0 .. 255)
390 * Converts a color expressed in HLS (hue, luminance and saturation)
391 * values into a #ClutterColor.
395 clutter_color_from_hls (ClutterColor *dest,
400 ClutterFixed h, l, s;
402 h = (float)(hue * 360) / 255;
403 l = (float)(luminance) / 255;
404 s = (float)(saturation) / 255;
406 clutter_color_from_hlsx (dest, h, l, s);
410 * clutter_color_shade:
411 * @src: a #ClutterColor
412 * @dest: return location for the shaded color
413 * @shade: the shade factor to apply
415 * Shades @src by the factor of @shade and saves the modified
419 clutter_color_shade (const ClutterColor *src,
423 clutter_color_shadex (src, dest, CLUTTER_FLOAT_TO_FIXED (shade));
427 * clutter_color_shadex:
428 * @src: a #ClutterColor
429 * @dest: return location for the shaded color
430 * @shade: #ClutterFixed the shade factor to apply
432 * Fixed point version of clutter_color_shade().
434 * Shades @src by the factor of @shade and saves the modified
440 clutter_color_shadex (const ClutterColor *src,
444 ClutterFixed h, l, s;
446 g_return_if_fail (src != NULL);
447 g_return_if_fail (dest != NULL);
449 clutter_color_to_hlsx (src, &h, &l, &s);
451 l = CLUTTER_FIXED_MUL (l, shade);
457 s = CLUTTER_FIXED_MUL (s, shade);
463 clutter_color_from_hlsx (dest, h, l, s);
464 dest->alpha = src->alpha;
468 * clutter_color_to_pixel:
469 * @src: a #ClutterColor
471 * Converts @src into a packed 32 bit integer, containing
472 * all the four 8 bit channels used by #ClutterColor.
474 * Return value: a packed color
477 clutter_color_to_pixel (const ClutterColor *src)
479 g_return_val_if_fail (src != NULL, 0);
481 return (src->alpha | src->blue << 8 | src->green << 16 | src->red << 24);
485 * clutter_color_from_pixel:
486 * @dest: return location for a #ClutterColor
487 * @pixel: a 32 bit packed integer containing a color
489 * Converts @pixel from the packed representation of a four 8 bit channel
490 * color to a #ClutterColor.
493 clutter_color_from_pixel (ClutterColor *dest,
496 g_return_if_fail (dest != NULL);
498 dest->red = pixel >> 24;
499 dest->green = (pixel >> 16) & 0xff;
500 dest->blue = (pixel >> 8) & 0xff;
501 dest->alpha = pixel & 0xff;
505 * clutter_color_parse:
506 * @color: a string specifiying a color (named color or #RRGGBBAA)
507 * @dest: return location for a #ClutterColor
509 * Parses a string definition of a color, filling the
510 * <structfield>red</structfield>, <structfield>green</structfield>,
511 * <structfield>blue</structfield> and <structfield>alpha</structfield>
512 * channels of @dest. If alpha is not specified it will be set full opaque.
513 * The color in @dest is not allocated.
515 * The color may be defined by any of the formats understood by
516 * <function>pango_color_parse</function>; these include literal color
517 * names, like <literal>Red</literal> or <literal>DarkSlateGray</literal>,
518 * or hexadecimal specifications like <literal>#3050b2</literal> or
519 * <literal>#333</literal>.
521 * Return value: %TRUE if parsing succeeded.
526 clutter_color_parse (const gchar *color,
529 PangoColor pango_color;
531 g_return_val_if_fail (color != NULL, FALSE);
532 g_return_val_if_fail (dest != NULL, FALSE);
534 /* parse ourselves to get alpha */
539 if (sscanf (color + 1, "%x", &result))
541 if (strlen (color) == 9)
543 dest->red = (result >> 24) & 0xff;
544 dest->green = (result >> 16) & 0xff;
545 dest->blue = (result >> 8) & 0xff;
546 dest->alpha = result & 0xff;
550 else if (strlen (color) == 7)
552 dest->red = (result >> 16) & 0xff;
553 dest->green = (result >> 8) & 0xff;
554 dest->blue = result & 0xff;
562 /* Fall back to pango for named colors - note pango does not handle alpha */
563 if (pango_color_parse (&pango_color, color))
565 dest->red = pango_color.red;
566 dest->green = pango_color.green;
567 dest->blue = pango_color.blue;
577 * clutter_color_to_string:
578 * @color: a #ClutterColor
580 * Returns a textual specification of @color in the hexadecimal form
581 * <literal>#rrggbbaa</literal>, where <literal>r</literal>,
582 * <literal>g</literal>, <literal>b</literal> and <literal>a</literal> are
583 * hex digits representing the red, green, blue and alpha components
586 * Return value: a newly-allocated text string
591 clutter_color_to_string (const ClutterColor *color)
593 g_return_val_if_fail (color != NULL, NULL);
595 return g_strdup_printf ("#%02x%02x%02x%02x",
603 * clutter_color_equal:
604 * @a: a #ClutterColor
605 * @b: a #ClutterColor
607 * Compares two #ClutterColor<!-- -->s and checks if they are the same.
609 * Return value: %TRUE if the two colors are the same.
614 clutter_color_equal (const ClutterColor *a,
615 const ClutterColor *b)
617 g_return_val_if_fail (a != NULL, FALSE);
618 g_return_val_if_fail (b != NULL, FALSE);
623 return (a->red == b->red &&
624 a->green == b->green &&
625 a->blue == b->blue &&
626 a->alpha == b->alpha);
630 * clutter_color_copy:
631 * @color: a #ClutterColor
633 * Makes a copy of the color structure. The result must be
634 * freed using clutter_color_free().
636 * Return value: an allocated copy of @color.
641 clutter_color_copy (const ClutterColor *color)
643 ClutterColor *result;
645 g_return_val_if_fail (color != NULL, NULL);
647 result = g_slice_new (ClutterColor);
654 * clutter_color_free:
655 * @color: a #ClutterColor
657 * Frees a color structure created with clutter_color_copy().
662 clutter_color_free (ClutterColor *color)
664 if (G_LIKELY (color))
665 g_slice_free (ClutterColor, color);
670 * @red: red component of the color, between 0 and 255
671 * @green: green component of the color, between 0 and 255
672 * @blue: blue component of the color, between 0 and 255
673 * @alpha: alpha component of the color, between 0 and 255
675 * Creates a new #ClutterColor with the given values.
677 * Return value: the newly allocated color. Use clutter_color_free()
683 clutter_color_new (guint8 red,
690 color = g_slice_new (ClutterColor);
693 color->green = green;
695 color->alpha = alpha;
701 clutter_value_transform_color_string (const GValue *src,
704 gchar *string = clutter_color_to_string (src->data[0].v_pointer);
706 g_value_take_string (dest, string);
710 clutter_value_transform_string_color (const GValue *src,
713 ClutterColor color = { 0, };
715 clutter_color_parse (g_value_get_string (src), &color);
717 clutter_value_set_color (dest, &color);
721 clutter_color_get_type (void)
723 static GType _clutter_color_type = 0;
725 if (G_UNLIKELY (_clutter_color_type == 0))
727 _clutter_color_type =
728 g_boxed_type_register_static (I_("ClutterColor"),
729 (GBoxedCopyFunc) clutter_color_copy,
730 (GBoxedFreeFunc) clutter_color_free);
732 g_value_register_transform_func (_clutter_color_type, G_TYPE_STRING,
733 clutter_value_transform_color_string);
734 g_value_register_transform_func (G_TYPE_STRING, _clutter_color_type,
735 clutter_value_transform_string_color);
738 return _clutter_color_type;
742 clutter_value_init_color (GValue *value)
744 value->data[0].v_pointer = NULL;
748 clutter_value_free_color (GValue *value)
750 if (!(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
751 clutter_color_free (value->data[0].v_pointer);
755 clutter_value_copy_color (const GValue *src,
758 dest->data[0].v_pointer = clutter_color_copy (src->data[0].v_pointer);
762 clutter_value_peek_color (const GValue *value)
764 return value->data[0].v_pointer;
768 clutter_value_collect_color (GValue *value,
769 guint n_collect_values,
770 GTypeCValue *collect_values,
773 if (!collect_values[0].v_pointer)
774 value->data[0].v_pointer = NULL;
777 if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
779 value->data[0].v_pointer = collect_values[0].v_pointer;
780 value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
784 value->data[0].v_pointer =
785 clutter_color_copy (collect_values[0].v_pointer);
793 clutter_value_lcopy_color (const GValue *value,
794 guint n_collect_values,
795 GTypeCValue *collect_values,
798 ClutterColor **color_p = collect_values[0].v_pointer;
801 return g_strdup_printf ("value location for `%s' passed as NULL",
802 G_VALUE_TYPE_NAME (value));
804 if (!value->data[0].v_pointer)
808 if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
809 *color_p = value->data[0].v_pointer;
811 *color_p = clutter_color_copy (value->data[0].v_pointer);
818 * clutter_value_set_color:
819 * @value: a #GValue initialized to #CLUTTER_TYPE_COLOR
820 * @color: the color to set
822 * Sets @value to @color.
827 clutter_value_set_color (GValue *value,
828 const ClutterColor *color)
830 g_return_if_fail (CLUTTER_VALUE_HOLDS_COLOR (value));
832 value->data[0].v_pointer = clutter_color_copy (color);
836 * clutter_value_get_color:
837 * @value: a #GValue initialized to #CLUTTER_TYPE_COLOR
839 * Gets the #ClutterColor contained in @value.
841 * Return value: the colors inside the passed #GValue
845 G_CONST_RETURN ClutterColor *
846 clutter_value_get_color (const GValue *value)
848 g_return_val_if_fail (CLUTTER_VALUE_HOLDS_COLOR (value), NULL);
850 return value->data[0].v_pointer;
854 param_color_init (GParamSpec *pspec)
856 ClutterParamSpecColor *cspec = CLUTTER_PARAM_SPEC_COLOR (pspec);
858 cspec->default_value = NULL;
862 param_color_finalize (GParamSpec *pspec)
864 ClutterParamSpecColor *cspec = CLUTTER_PARAM_SPEC_COLOR (pspec);
866 clutter_color_free (cspec->default_value);
870 param_color_set_default (GParamSpec *pspec,
873 value->data[0].v_pointer = CLUTTER_PARAM_SPEC_COLOR (pspec)->default_value;
874 value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
878 param_color_values_cmp (GParamSpec *pspec,
879 const GValue *value1,
880 const GValue *value2)
882 guint32 color1, color2;
884 color1 = clutter_color_to_pixel (value1->data[0].v_pointer);
885 color2 = clutter_color_to_pixel (value2->data[0].v_pointer);
889 else if (color1 == color2)
895 static const GTypeValueTable _clutter_color_value_table = {
896 clutter_value_init_color,
897 clutter_value_free_color,
898 clutter_value_copy_color,
899 clutter_value_peek_color,
901 clutter_value_collect_color,
903 clutter_value_lcopy_color
907 clutter_param_color_get_type (void)
909 static GType pspec_type = 0;
911 if (G_UNLIKELY (pspec_type == 0))
913 const GParamSpecTypeInfo pspec_info = {
914 sizeof (ClutterParamSpecColor),
918 param_color_finalize,
919 param_color_set_default,
921 param_color_values_cmp,
924 pspec_type = g_param_type_register_static (I_("ClutterParamSpecColor"),
932 * clutter_param_spec_color:
933 * @name: name of the property
935 * @blurb: description (can be translatable)
936 * @default_value: default value
937 * @flags: flags for the param spec
939 * Creates a #GParamSpec for properties using #ClutterColor.
941 * Return value: the newly created #GParamSpec
946 clutter_param_spec_color (const gchar *name,
949 const ClutterColor *default_value,
952 ClutterParamSpecColor *cspec;
954 cspec = g_param_spec_internal (CLUTTER_TYPE_PARAM_COLOR,
955 name, nick, blurb, flags);
957 cspec->default_value = clutter_color_copy (default_value);
959 return G_PARAM_SPEC (cspec);