From: Søren Sandmann Pedersen <s...@redhat.com>

A new struct argb_t containing a floating point pixel is added to
pixman-private.h and conversion routines are added to pixman-utils.c
to convert normalized integers to and from that struct.

New functions:

  - pixman_expand_to_float()
    Expands a buffer of integer pixels to a buffer of argb_t pixels

  - pixman_contract_from_float()
    Converts a buffer of argb_t pixels to a buffer integer pixels

  - pixman_float_to_unorm()
    Converts a floating point number to an unsigned normalized integer

  - pixman_unorm_to_float()
    Converts an unsigned normalized integer to a floating point number
---
 pixman/pixman-private.h | 23 ++++++++++++
 pixman/pixman-utils.c   | 98 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 121 insertions(+)

diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h
index 4abdc9f..6dc476e 100644
--- a/pixman/pixman-private.h
+++ b/pixman/pixman-private.h
@@ -45,6 +45,16 @@ typedef struct radial_gradient radial_gradient_t;
 typedef struct bits_image bits_image_t;
 typedef struct circle circle_t;
 
+typedef struct argb_t argb_t;
+
+struct argb_t
+{
+    float a;
+    float r;
+    float g;
+    float b;
+};
+
 typedef void (*fetch_scanline_t) (pixman_image_t *image,
                                  int             x,
                                  int             y,
@@ -774,12 +784,22 @@ pixman_expand (uint64_t *           dst,
                const uint32_t *     src,
                pixman_format_code_t format,
                int                  width);
+void
+pixman_expand_to_float (argb_t               *dst,
+                       const uint32_t       *src,
+                       pixman_format_code_t  format,
+                       int                   width);
 
 void
 pixman_contract (uint32_t *      dst,
                  const uint64_t *src,
                  int             width);
 
+void
+pixman_contract_from_float (uint32_t     *dst,
+                           const argb_t *src,
+                           int           width);
+
 pixman_bool_t
 _pixman_lookup_composite_function (pixman_implementation_t     *toplevel,
                                   pixman_op_t                  op,
@@ -951,6 +971,9 @@ unorm_to_unorm (uint32_t val, int from_bits, int to_bits)
     return result;
 }
 
+uint16_t pixman_float_to_unorm (float f, int n_bits);
+float pixman_unorm_to_float (uint16_t u, int n_bits);
+
 /*
  * Various debugging code
  */
diff --git a/pixman/pixman-utils.c b/pixman/pixman-utils.c
index 93c061a..ad91ae9 100644
--- a/pixman/pixman-utils.c
+++ b/pixman/pixman-utils.c
@@ -274,6 +274,104 @@ pixman_expand (uint64_t *           dst,
     }
 }
 
+static force_inline uint16_t
+float_to_unorm (float f, int n_bits)
+{
+    uint32_t u;
+
+    if (f > 1.0)
+       f = 1.0;
+    if (f < 0.0)
+       f = 0.0;
+
+    u = f * (1 << n_bits);
+    u -= (u >> n_bits);
+
+    return u;
+}
+
+
+static force_inline float
+unorm_to_float (uint16_t u, int n_bits)
+{
+    uint32_t m = ((1 << n_bits) - 1);
+
+    return (u & m) * (1.f / (float)m);
+}
+
+/*
+ * This function expands images from ARGB8 format to argb_t.  To preserve
+ * precision, it needs to know the original source format.  For example, if the
+ * source was PIXMAN_x1r5g5b5 and the red component contained bits 12345, then
+ * the 8-bit value is 12345123.  To correctly expand this to floating point, it
+ * should be 12345 / 31.0 and not 12345123 / 255.0.
+ */
+void
+pixman_expand_to_float (argb_t               *dst,
+                       const uint32_t       *src,
+                       pixman_format_code_t  format,
+                       int                   width)
+{
+    /*
+     * Determine the sizes of each component and the masks and shifts
+     * required to extract them from the source pixel.
+     */
+    const int a_size = PIXMAN_FORMAT_A (format),
+              r_size = PIXMAN_FORMAT_R (format),
+              g_size = PIXMAN_FORMAT_G (format),
+              b_size = PIXMAN_FORMAT_B (format);
+    const int a_shift = 32 - a_size,
+              r_shift = 24 - r_size,
+              g_shift = 16 - g_size,
+              b_shift =  8 - b_size;
+    int i;
+
+    /* Start at the end so that we can do the expansion in place
+     * when src == dst
+     */
+    for (i = width - 1; i >= 0; i--)
+    {
+       const uint32_t pixel = src[i];
+
+       dst[i].a = a_size? unorm_to_float (pixel >> a_shift, a_size) : 1.0;
+       dst[i].r = r_size? unorm_to_float (pixel >> r_shift, r_size) : 0.0;
+       dst[i].g = g_size? unorm_to_float (pixel >> g_shift, g_size) : 0.0;
+       dst[i].b = b_size? unorm_to_float (pixel >> b_shift, b_size) : 0.0;
+    }
+}
+
+uint16_t
+pixman_float_to_unorm (float f, int n_bits)
+{
+    return float_to_unorm (f, n_bits);
+}
+
+float
+pixman_unorm_to_float (uint16_t u, int n_bits)
+{
+    return unorm_to_float (u, n_bits);
+}
+
+void
+pixman_contract_from_float (uint32_t     *dst,
+                           const argb_t *src,
+                           int           width)
+{
+    int i;
+
+    for (i = 0; i < width; ++i)
+    {
+       uint8_t a, r, g, b;
+
+       a = float_to_unorm (src[i].a, 8);
+       r = float_to_unorm (src[i].r, 8);
+       g = float_to_unorm (src[i].g, 8);
+       b = float_to_unorm (src[i].b, 8);
+
+       dst[i] = (a << 24) | (r << 16) | (g << 8) | (b << 0);
+    }
+}
+
 /*
  * Contracting is easier than expanding.  We just need to truncate the
  * components.
-- 
1.7.11.4

_______________________________________________
Pixman mailing list
Pixman@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/pixman

Reply via email to