2006-06-22 Matthew Allum <mallum@openedhand.com>
[profile/ivi/clutter.git] / clutter / clutter-color.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006 OpenedHand
9  *
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.
14  *
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.
19  *
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.
24  */
25
26 /**
27  * SECTION:clutter-color
28  * @short_description: Color management and manipulation.
29  *
30  * #ClutterColor is a simple type for representing colors.
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include "clutter-color.h"
38
39 /**
40  * clutter_color_add:
41  * @src1: a #ClutterColor
42  * @src2: a #ClutterColor
43  * @dest: return location for the result
44  *
45  * Adds @src2 to @src1 and saves the resulting color
46  * inside @dest.
47  *
48  * The alpha channel of @dest is as the maximum value
49  * between the alpha channels of @src1 and @src2.
50  */
51 void
52 clutter_color_add (const ClutterColor *src1,
53                    const ClutterColor *src2,
54                    ClutterColor       *dest)
55 {
56   g_return_if_fail (src1 != NULL);
57   g_return_if_fail (src2 != NULL);
58   g_return_if_fail (dest != NULL);
59
60   dest->red   = CLAMP (src1->red   + src2->red,   0, 255);
61   dest->green = CLAMP (src1->green + src2->green, 0, 255);
62   dest->blue  = CLAMP (src1->blue  + src2->blue,  0, 255);
63
64   dest->alpha = MAX (src1->alpha, src2->alpha);
65 }
66
67 /**
68  * clutter_color_subtract:
69  * @src1: a #ClutterColor
70  * @src2: a #ClutterColor
71  * @dest: return location for the result
72  *
73  * Subtracts @src2 from @src1 and saves the resulting
74  * color inside @dest.
75  *
76  * The alpha channel of @dest is set as the minimum value
77  * between the alpha channels of @src1 and @src2.
78  */
79 void
80 clutter_color_subtract (const ClutterColor *src1,
81                         const ClutterColor *src2,
82                         ClutterColor       *dest)
83 {
84   g_return_if_fail (src1 != NULL);
85   g_return_if_fail (src2 != NULL);
86   g_return_if_fail (dest != NULL);
87
88   dest->red   = CLAMP (src2->red   - src1->red,   0, 255);
89   dest->green = CLAMP (src2->green - src1->green, 0, 255);
90   dest->blue  = CLAMP (src2->blue  - src1->blue,  0, 255);
91
92   dest->alpha = MIN (src1->alpha, src2->alpha);
93 }
94
95 /**
96  * clutter_color_lighten:
97  * @src: a #ClutterColor
98  * @dest: return location for the lighter color
99  *
100  * Lightens @src by a fixed amount, and saves the changed
101  * color in @dest.
102  */
103 void
104 clutter_color_lighten (const ClutterColor *src,
105                        ClutterColor       *dest)
106 {
107   clutter_color_shade (src, dest, 1.3);
108 }
109
110 /**
111  * clutter_color_darken:
112  * @src: a #ClutterColor
113  * @dest: return location for the darker color
114  *
115  * Darkens @src by a fixed amount, and saves the changed color
116  * in @dest.
117  */
118 void
119 clutter_color_darken (const ClutterColor *src,
120                       ClutterColor       *dest)
121 {
122   clutter_color_shade (src, dest, 0.7);
123 }
124
125 /**
126  * clutter_color_to_hls:
127  * @src: a #ClutterColor
128  * @hue: return location for the hue value or %NULL
129  * @luminance: return location for the luminance value or %NULL
130  * @saturation: return location for the saturation value or %NULL
131  *
132  * Converts @src to the HLS format.
133  */
134 void
135 clutter_color_to_hls (const ClutterColor *src,
136                       guint8             *hue,
137                       guint8             *luminance,
138                       guint8             *saturation)
139 {
140   gdouble red, green, blue;
141   gdouble min, max, delta;
142   gdouble h, l, s;
143   
144   g_return_if_fail (src != NULL);
145
146   red = src->red / 255.0;
147   green = src->green / 255.0;
148   blue = src->blue / 255.0;
149
150   if (red > green)
151     {
152       if (red > blue)
153         max = red;
154       else
155         max = blue;
156
157       if (green < blue)
158         min = green;
159       else
160         min = blue;
161     }
162   else
163     {
164       if (green > blue)
165         max = green;
166       else
167         max = blue;
168
169       if (red < blue)
170         min = red;
171       else
172         min = blue;
173     }
174
175   l = (max + min) / 2;
176   s = 0;
177   h = 0;
178
179   if (max != min)
180     {
181       if (l <= 0.5)
182         s = (max - min) / (max + min);
183       else
184         s = (max - min) / (2 - max - min);
185
186       delta = max - min;
187       if (red == max)
188         h = (green - blue) / delta;
189       else if (green == max)
190         h = 2 + (blue - red) / delta;
191       else if (blue == max)
192         h = 4 + (red - green) / delta;
193
194       h *= 60;
195       if (h < 0.0)
196         h += 360;
197     }
198
199   if (hue)
200     *hue = (guint8) (h * 255);
201
202   if (luminance)
203     *luminance = (guint8) (l * 255);
204
205   if (saturation)
206     *saturation = (guint8) (s * 255);
207 }
208
209 /**
210  * clutter_color_from_hls:
211  * @dest: return location for a #ClutterColor
212  * @hue: hue value (0 .. 255)
213  * @luminance: luminance value (0 .. 255)
214  * @saturation: saturation value (0 .. 255)
215  *
216  * Converts a color expressed in HLS (hue, luminance and saturation)
217  * values into a #ClutterColor.
218  */
219 void
220 clutter_color_from_hls (ClutterColor *dest,
221                         guint8        hue,
222                         guint8        luminance,
223                         guint8        saturation)
224 {
225   gdouble h, l, s;
226   gdouble m1, m2;
227   
228   g_return_if_fail (dest != NULL);
229
230   l = (gdouble) luminance / 255.0;
231   s = (gdouble) saturation / 255.0;
232
233   if (l <= 0.5)
234     m2 = l * (1 - s);
235   else
236     m2 = l + s - l * s;
237
238   m1 = 2 * l - m2;
239
240   if (s == 0)
241     {
242       dest->red = (guint8) l * 255;
243       dest->green = (guint8) l * 255;
244       dest->blue = (guint8) l * 255;
245     }
246   else
247     {
248       h = ((gdouble) hue / 255.0) + 120;
249       while (h > 360)
250         h -= 360;
251       while (h < 0)
252         h += 360;
253
254       if (h < 60)
255         dest->red = (guint8) (m1 + (m2 - m1) * h / 60) * 255;
256       else if (h < 180)
257         dest->red = (guint8) m2 * 255;
258       else if (h < 240)
259         dest->red = (guint8) (m1 + (m2 - m1) * (240 - h) / 60) * 255;
260       else
261         dest->red = (guint8) m1 * 255;
262
263       h = (gdouble) hue / 255.0;
264       while (h > 360)
265         h -= 360;
266       while (h < 0)
267         h += 360;
268
269       if (h < 60)
270         dest->green = (guint8) (m1 + (m2 - m1) * h / 60) * 255;
271       else if (h < 180)
272         dest->green = (guint8) m2 * 255;
273       else if (h < 240)
274         dest->green = (guint8) (m1 + (m2 - m1) * (240 - h) / 60) * 255;
275       else
276         dest->green = (guint8) m1 * 255;
277
278       h = ((gdouble) hue / 255.0) - 120;
279       while (h > 360)
280         h -= 360;
281       while (h < 0)
282         h += 360;
283
284       if (h < 60)
285         dest->blue = (guint8) (m1 + (m2 - m1) * h / 60) * 255;
286       else if (h < 180)
287         dest->blue = (guint8) m2 * 255;
288       else if (h < 240)
289         dest->blue = (guint8) (m1 + (m2 - m1) * (240 - h) / 60) * 255;
290       else
291         dest->blue = (guint8) m1 * 255;
292     }
293 }
294
295 /**
296  * clutter_color_shade:
297  * @src: a #ClutterColor
298  * @dest: return location for the shaded color
299  * @shade: the shade factor to apply
300  * 
301  * Shades @src by the factor of @shade and saves the modified
302  * color into @dest.
303  */
304 void
305 clutter_color_shade (const ClutterColor *src,
306                      ClutterColor       *dest,
307                      gdouble             shade)
308 {
309   guint8 h, l, s;
310   gdouble h1, l1, s1;
311
312   g_return_if_fail (src != NULL);
313   g_return_if_fail (dest != NULL);
314   
315   clutter_color_to_hls (src, &h, &l, &s);
316
317   h1 = (gdouble) h / 255.0;
318   l1 = (gdouble) l / 255.0;
319   s1 = (gdouble) s / 255.0;
320   
321   l1 *= shade;
322   if (l1 > 1.0)
323     l1 = 1.0;
324   else if (l1 < 0.0)
325     l1 = 0.0;
326   
327   s1 *= shade;
328   if (s1 > 1.0)
329     s1 = 1.0;
330   else if (s1 < 0.0)
331     s1 = 0.0;
332
333   h = (guint8) h1 * 255;
334   l = (guint8) l1 * 255;
335   s = (guint8) s1 * 255;
336
337   clutter_color_from_hls (dest, h, l, s);
338 }
339
340 /**
341  * clutter_color_to_pixel:
342  * @src: a #ClutterColor
343  *
344  * Converts @src into a packed 32 bit integer, containing
345  * all the four 8 bit channels used by #ClutterColor.
346  *
347  * Return value: a packed color
348  */
349 guint32
350 clutter_color_to_pixel (const ClutterColor *src)
351 {
352   g_return_val_if_fail (src != NULL, 0);
353   
354   return (src->alpha | src->blue << 8 | src->green << 16  | src->red << 24);
355 }
356
357 /**
358  * clutter_color_from_pixel:
359  * @dest: return location for a #ClutterColor
360  * @pixel: a 32 bit packed integer containing a color
361  *
362  * Converts @pixel from the packed representation of a four 8 bit channel
363  * color to a #ClutterColor.
364  */
365 void
366 clutter_color_from_pixel (ClutterColor *dest,
367                           guint32       pixel)
368 {
369   g_return_if_fail (dest != NULL);
370
371   dest->red = pixel >> 24;
372   dest->green = (pixel >> 16) & 0xff;
373   dest->blue = (pixel >> 8) & 0xff;
374   dest->alpha = pixel % 0xff;
375 }
376
377 static ClutterColor *
378 clutter_color_copy (ClutterColor *color)
379 {
380   ClutterColor *result = g_new0 (ClutterColor, 1);
381
382   *result = *color;
383
384   return result;
385 }
386
387 GType
388 clutter_color_get_type (void)
389 {
390   static GType our_type = 0;
391   
392   if (!our_type)
393     our_type = g_boxed_type_register_static ("ClutterColor",
394                                              (GBoxedCopyFunc) clutter_color_copy,
395                                              (GBoxedFreeFunc) g_free);
396   return our_type;
397 }