[clutter-color] Use a different hls->rgb algorithm + use floating point
authorRobert Bragg <robert@linux.intel.com>
Tue, 17 Mar 2009 00:01:56 +0000 (00:01 +0000)
committerRobert Bragg <robert@linux.intel.com>
Tue, 17 Mar 2009 11:37:29 +0000 (11:37 +0000)
Using test-cogl-vertex-buffer as a test case which is CPU bound due to
hls -> rgb conversions this alternative algorithm looked to be ~10%
faster when tested on an X61s Lenovo.

clutter/clutter-color.c
tests/interactive/test-cogl-vertex-buffer.c

index 2bdecbf..f338527 100644 (file)
@@ -132,35 +132,33 @@ clutter_color_darken (const ClutterColor *color,
   clutter_color_shade (color, 0.7, result);
 }
 
-/*
- * clutter_color_to_hlsx:
+/**
+ * clutter_color_to_hls:
  * @color: a #ClutterColor
  * @hue: return location for the hue value or %NULL
  * @luminance: return location for the luminance value or %NULL
  * @saturation: return location for the saturation value or %NULL
  *
- * Converts @color to the HLS format. Returned hue is in degrees (0 .. 360),
- * luminance and saturation from interval <0 .. 1>.
+ * Converts @color to the HLS format.
  *
- * The implementation is in fixed point because we don't particularly
- * care about precision. It can be moved to floating point at any later
- * date.
+ * The @hue value is in the 0 .. 360 range. The @luminance and
+ * @saturation values are in the 0 .. 1 range.
  */
-static void
-clutter_color_to_hlsx (const ClutterColor *color,
-                      CoglFixed          *hue,
-                      CoglFixed          *luminance,
-                      CoglFixed          *saturation)
-{
-  CoglFixed red, green, blue;
-  CoglFixed min, max, delta;
-  CoglFixed h, l, s;
+void
+clutter_color_to_hls (const ClutterColor *color,
+                     float              *hue,
+                     float              *luminance,
+                     float              *saturation)
+{
+  float red, green, blue;
+  float min, max, delta;
+  float h, l, s;
   
   g_return_if_fail (color != NULL);
 
-  red   = COGL_FIXED_FAST_DIV (color->red,   COGL_FIXED_255);
-  green = COGL_FIXED_FAST_DIV (color->green, COGL_FIXED_255);
-  blue  = COGL_FIXED_FAST_DIV (color->blue,  COGL_FIXED_255);
+  red   = color->red / 255.0;
+  green = color->green / 255.0;
+  blue  = color->blue / 255.0;
 
   if (red > green)
     {
@@ -193,25 +191,24 @@ clutter_color_to_hlsx (const ClutterColor *color,
 
   if (max != min)
     {
-      if (l <= COGL_FIXED_0_5)
-       s = COGL_FIXED_DIV ((max - min), (max + min));
+      if (l <= 0.5)
+       s = (max - min) / (max + min);
       else
-       s = COGL_FIXED_DIV ((max - min),
-                            (COGL_FIXED_FROM_INT (2) - max - min));
+       s = (max - min) / (2.0 - max - min);
 
       delta = max - min;
 
       if (red == max)
-       h = COGL_FIXED_DIV ((green - blue), delta);
+       h = (green - blue) / delta;
       else if (green == max)
-       h = COGL_FIXED_FROM_INT (2) + COGL_FIXED_DIV ((blue - red), delta);
+       h = 2.0 + (blue - red) / delta;
       else if (blue == max)
-       h = COGL_FIXED_FROM_INT (4) + COGL_FIXED_DIV ((red - green), delta);
+       h = 4.0 + (red - green) / delta;
 
       h *= 60;
 
       if (h < 0)
-       h += COGL_FIXED_360;
+       h += 360.0;
     }
 
   if (hue)
@@ -224,245 +221,112 @@ clutter_color_to_hlsx (const ClutterColor *color,
     *saturation = s;
 }
 
-/*
- * clutter_color_from_hlsx:
- * @dest: (out): return location for a #ClutterColor
- * @hue: hue value (0 .. 360)
- * @luminance: luminance value (0 .. 1)
- * @saturation: saturation value (0 .. 1)
+/**
+ * clutter_color_from_hls:
+ * @color: (out): return location for a #ClutterColor
+ * @hue: hue value, in the 0 .. 360 range
+ * @luminance: luminance value, in the 0 .. 1 range
+ * @saturation: saturation value, in the 0 .. 1 range
  *
  * Converts a color expressed in HLS (hue, luminance and saturation)
  * values into a #ClutterColor.
  */
 void
-clutter_color_from_hlsx (ClutterColor *color,
-                        CoglFixed     hue,
-                        CoglFixed     luminance,
-                        CoglFixed     saturation)
+clutter_color_from_hls (ClutterColor *color,
+                       float         hue,
+                       float         luminance,
+                       float         saturation)
 {
-  CoglFixed h, l, s;
-  CoglFixed m1, m2;
-  
-  g_return_if_fail (color != NULL);
-
-  l = luminance;
-  s = saturation;
-
-  if (l <= COGL_FIXED_0_5)
-    m2 = COGL_FIXED_MUL (l, (COGL_FIXED_1 + s));
-  else
-    m2 = l + s - COGL_FIXED_MUL (l, s);
+  float tmp1, tmp2;
+  float tmp3[3];
+  float clr[3];
+  int   i;
 
-  m1 = 2 * l - m2;
+  hue /= 360.0;
 
-  if (s == 0)
+  if (luminance == 0)
     {
-      color->red   = (guint8) (COGL_FIXED_TO_FLOAT (l) * 255);
-      color->green = (guint8) (COGL_FIXED_TO_FLOAT (l) * 255);
-      color->blue  = (guint8) (COGL_FIXED_TO_FLOAT (l) * 255);
+      color->red = color->green = color->blue = 0;
+      return;
     }
-  else
-    {
-      h = hue + COGL_FIXED_120;
-
-      while (h > COGL_FIXED_360)
-       h -= COGL_FIXED_360;
-
-      while (h < 0)
-       h += COGL_FIXED_360;
-
-      if (h < COGL_FIXED_60)
-        {
-          CoglFixed tmp;
 
-          tmp = (m1 + COGL_FIXED_MUL_DIV ((m2 - m1), h, COGL_FIXED_60));
-          color->red = (guint8) (COGL_FIXED_TO_FLOAT (tmp) * 255);
-        }
-      else if (h < COGL_FIXED_180)
-       color->red = (guint8) (COGL_FIXED_TO_FLOAT (m2) * 255);
-      else if (h < COGL_FIXED_240)
-        {
-          CoglFixed tmp;
-
-          tmp = (m1 + COGL_FIXED_MUL_DIV ((m2 - m1),
-                                          (COGL_FIXED_240 - h),
-                                          COGL_FIXED_60));
-          color->red = (guint8) (COGL_FIXED_TO_FLOAT (tmp) * 255);
-        }
-      else
-       color->red = (guint8) (COGL_FIXED_TO_FLOAT (m1) * 255);
-
-      h = hue;
-      while (h > COGL_FIXED_360)
-       h -= COGL_FIXED_360;
-      while (h < 0)
-       h += COGL_FIXED_360;
-
-      if (h < COGL_FIXED_60)
-        {
-          CoglFixed tmp;
-
-          tmp = (m1 + COGL_FIXED_MUL_DIV ((m2 - m1), h, COGL_FIXED_60));
-          color->green = (guint8) (COGL_FIXED_TO_FLOAT (tmp) * 255);
-        }
-      else if (h < COGL_FIXED_180)
-        color->green = (guint8) (COGL_FIXED_TO_FLOAT (m2) * 255);
-      else if (h < COGL_FIXED_240)
-        {
-          CoglFixed tmp;
-
-          tmp = (m1 + COGL_FIXED_MUL_DIV ((m2 - m1),
-                                          (COGL_FIXED_240 - h),
-                                          COGL_FIXED_60));
-          color->green = (guint8) (COGL_FIXED_TO_FLOAT (tmp) * 255);
-        }
-      else
-       color->green = (guint8) (COGL_FIXED_TO_FLOAT (m1) * 255);
-
-      h = hue - COGL_FIXED_120;
-
-      while (h > COGL_FIXED_360)
-       h -= COGL_FIXED_360;
+  if (saturation == 0)
+    {
+      color->red = color->green = color->blue = luminance;
+      return;
+    }
 
-      while (h < 0)
-       h += COGL_FIXED_360;
+  if (luminance <= 0.5)
+    tmp2 = luminance * (1.0 + saturation);
+  else
+    tmp2 = luminance + saturation - (luminance * saturation);
 
-      if (h < COGL_FIXED_60)
-        {
-          CoglFixed tmp;
+  tmp1 = 2.0 * luminance - tmp2;
 
-          tmp = (m1 + COGL_FIXED_MUL_DIV ((m2 - m1), h, COGL_FIXED_60));
-          color->blue = (guint8) (COGL_FIXED_TO_FLOAT (tmp) * 255);
-        }
-      else if (h < COGL_FIXED_180)
-       color->blue = (guint8) (COGL_FIXED_TO_FLOAT (m2) * 255);
-      else if (h < COGL_FIXED_240)
-        {
-          CoglFixed tmp;
+  tmp3[0] = hue + 1.0 / 3.0;
+  tmp3[1] = hue;
+  tmp3[2] = hue - 1.0 / 3.0;
 
-          tmp = (m1 + COGL_FIXED_MUL_DIV ((m2 - m1),
-                                          (COGL_FIXED_240 - h),
-                                          COGL_FIXED_60));
-          color->blue = (guint8) (COGL_FIXED_TO_FLOAT (tmp) * 255);
-        }
+  for (i = 0; i < 3; i++)
+    {
+      if (tmp3[i] < 0)
+        tmp3[i] += 1.0;
+      if (tmp3[i] > 1)
+        tmp3[i] -= 1.0;
+
+      if (6.0 * tmp3[i] < 1.0)
+        clr[i] = tmp1 + (tmp2 - tmp1) * tmp3[i] * 6.0;
+      else if (2.0 * tmp3[i] < 1.0)
+        clr[i] = tmp2;
+      else if (3.0 * tmp3[i] < 2.0)
+        clr[i] = (tmp1 + (tmp2 - tmp1) * ((2.0 / 3.0) - tmp3[i]) * 6.0);
       else
-       color->blue = (guint8) (COGL_FIXED_TO_FLOAT (m1) * 255);
+        clr[i] = tmp1;
     }
-}
-
-/**
- * clutter_color_to_hls:
- * @color: a #ClutterColor
- * @hue: return location for the hue value or %NULL
- * @luminance: return location for the luminance value or %NULL
- * @saturation: return location for the saturation value or %NULL
- *
- * Converts @color to the HLS format.
- *
- * The @hue value is in the 0 .. 360 range. The @luminance and
- * @saturation values are in the 0 .. 1 range.
- */
-void
-clutter_color_to_hls (const ClutterColor *color,
-                     gfloat             *hue,
-                     gfloat             *luminance,
-                     gfloat             *saturation)
-{
-  CoglFixed h, l, s;
-  
-  clutter_color_to_hlsx (color, &h, &l, &s);
-  
-  if (hue)
-    *hue = COGL_FIXED_TO_FLOAT (h);
-
-  if (luminance)
-    *luminance = COGL_FIXED_TO_FLOAT (l);
 
-  if (saturation)
-    *saturation = COGL_FIXED_TO_FLOAT (s);
+  color->red = clr[0] * 255.0;
+  color->green = clr[1] * 255.0;
+  color->blue = clr[2] * 255.0;
 }
 
 /**
- * clutter_color_from_hls:
- * @color: (out): return location for a #ClutterColor
- * @hue: hue value, in the 0 .. 360 range
- * @luminance: luminance value, in the 0 .. 1 range
- * @saturation: saturation value, in the 0 .. 1 range
- *
- * Converts a color expressed in HLS (hue, luminance and saturation)
- * values into a #ClutterColor.
- */
-void
-clutter_color_from_hls (ClutterColor *color,
-                       gfloat        hue,
-                       gfloat        luminance,
-                       gfloat        saturation)
-{
-  CoglFixed h, l, s;
-
-  h = COGL_FIXED_FROM_FLOAT (hue);
-  l = COGL_FIXED_FROM_FLOAT (luminance);
-  s = COGL_FIXED_FROM_FLOAT (saturation);
-
-  clutter_color_from_hlsx (color, h, l, s);
-}
-
-/*
- * clutter_color_shadex:
+ * clutter_color_shade:
  * @color: a #ClutterColor
- * @factor: the shade factor to apply, as a fixed point value
+ * @factor: the shade factor to apply
  * @result: (out): return location for the shaded color
- * 
+ *
  * Shades @color by @factor and saves the modified color into @result.
  */
-static void
-clutter_color_shadex (const ClutterColor *color,
-                      CoglFixed           factor,
-                      ClutterColor       *result)
+void
+clutter_color_shade (const ClutterColor *color,
+                     gdouble             factor,
+                     ClutterColor       *result)
 {
-  CoglFixed h, l, s;
+  float h, l, s;
 
   g_return_if_fail (color != NULL);
   g_return_if_fail (result != NULL);
   
-  clutter_color_to_hlsx (color, &h, &l, &s);
+  clutter_color_to_hls (color, &h, &l, &s);
 
-  l = COGL_FIXED_MUL (l, factor);
-  if (l > COGL_FIXED_1)
-    l = COGL_FIXED_1;
+  l *= factor;
+  if (l > 1.0)
+    l = 1.0;
   else if (l < 0)
     l = 0;
 
-  s = COGL_FIXED_MUL (s, factor);
-  if (s > COGL_FIXED_1)
-    s = COGL_FIXED_1;
+  s *= factor;
+  if (s > 1.0)
+    s = 1.0;
   else if (s < 0)
     s = 0;
   
-  clutter_color_from_hlsx (result, h, l, s);
+  clutter_color_from_hls (result, h, l, s);
 
   result->alpha = color->alpha;
 }
 
 /**
- * clutter_color_shade:
- * @color: a #ClutterColor
- * @factor: the shade factor to apply
- * @result: (out): return location for the shaded color
- *
- * Shades @color by @factor and saves the modified color into @result.
- */
-void
-clutter_color_shade (const ClutterColor *color,
-                     gdouble             factor,
-                    ClutterColor       *result)
-{
-  clutter_color_shadex (color,
-                        COGL_FIXED_FROM_FLOAT (factor),
-                        result);
-}
-
-/**
  * clutter_color_to_pixel:
  * @color: a #ClutterColor
  *
index 69f6ff3..f5755d6 100644 (file)
@@ -41,6 +41,8 @@
 #define HSL_OFFSET    0.5 /* the hue that we map an amplitude of 0 too */
 #define HSL_SCALE     0.25
 
+#define USE_CLUTTER_COLOR 1
+
 typedef struct _TestState
 {
   ClutterActor    *dummy;
@@ -52,6 +54,7 @@ typedef struct _TestState
   ClutterTimeline *timeline;
 } TestState;
 
+#ifndef USE_CLUTTER_COLOR
 /* This algorithm is adapted from the book:
  * Fundamentals of Interactive Computer Graphics by Foley and van Dam
  */
@@ -105,6 +108,7 @@ hsl_to_rgb (float h, float s, float l,
    *g = clr[1] * 255.0;
    *b = clr[2] * 255.0;
 }
+#endif
 
 static void
 frame_cb (ClutterTimeline *timeline,
@@ -152,7 +156,11 @@ frame_cb (ClutterTimeline *timeline,
         s = 0.5;
         l = 0.25 + (period_progress_sin + 1.0) / 4.0;
         color = &state->quad_mesh_colors[4 * vert_index];
+#ifdef USE_CLUTTER_COLOR
+        clutter_color_from_hls ((ClutterColor *)color, h * 360.0, l, s);
+#else
         hsl_to_rgb (h, s, l, &color[0], &color[1], &color[2]);
+#endif
       }
 
   cogl_vertex_buffer_add (state->buffer,