diff options
author | Søren Sandmann Pedersen <ssp@redhat.com> | 2012-08-18 13:02:31 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <ssp@redhat.com> | 2012-09-30 18:22:58 -0400 |
commit | 15dc00f1739424efdee495e7152419fec3f3c053 (patch) | |
tree | 4e3a89e65c0677c3d6127038657ff8ace059a028 | |
parent | 489251ca25df86cab553f7ca81c3c2d0f2f4a8af (diff) |
pixman-utils.c, pixman-private.h: Add floating point conversion routines
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
-rw-r--r-- | pixman/pixman-private.h | 23 | ||||
-rw-r--r-- | pixman/pixman-utils.c | 107 |
2 files changed, 130 insertions, 0 deletions
diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h index c82316ff..379943ec 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, @@ -792,12 +802,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); + /* Region Helpers */ pixman_bool_t pixman_region32_copy_from_region16 (pixman_region32_t *dst, @@ -957,6 +977,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 e4a97300..4f9db296 100644 --- a/pixman/pixman-utils.c +++ b/pixman/pixman-utils.c @@ -162,6 +162,113 @@ 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 a8r8g8b8 to argb_t. To preserve + * precision, it needs to know from which source format the a8r8g8b8 pixels + * originally came. + * + * 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) +{ + int a_size, r_size, g_size, b_size; + int a_shift, r_shift, g_shift, b_shift; + int i; + + if (!PIXMAN_FORMAT_VIS (format)) + format = PIXMAN_a8r8g8b8; + + /* + * Determine the sizes of each component and the masks and shifts + * required to extract them from the source pixel. + */ + a_size = PIXMAN_FORMAT_A (format); + r_size = PIXMAN_FORMAT_R (format); + g_size = PIXMAN_FORMAT_G (format); + b_size = PIXMAN_FORMAT_B (format); + + a_shift = 32 - a_size; + r_shift = 24 - r_size; + g_shift = 16 - g_size; + b_shift = 8 - b_size; + + /* 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. |