From: Ray Strode Date: Fri, 11 May 2007 03:33:59 +0000 (-0400) Subject: rework framebuffer code to be more general X-Git-Tag: 0.1.0~315 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b6a50319e8375370fd16e6b863e78beda9d3be3a;p=thirdparty%2Fplymouth.git rework framebuffer code to be more general add new ply-image apis for loading pngs --- diff --git a/src/ply-image.c b/src/ply-image.c new file mode 100644 index 00000000..693f1d5a --- /dev/null +++ b/src/ply-image.c @@ -0,0 +1,370 @@ +/* vim: ts=4 sw=2 expandtab autoindent cindent + * ply-image.c - png file loader + * + * Copyright (C) 2006, 2007 Red Hat, Inc. + * Copyright (C) 2003 University of Southern California + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Some implementation taken from the cairo library. + * + * Written by: Kristian Høgsberg + * Ray Strode + * Carl D. Worth (cworth@cworth.org> + */ +#include "config.h" +#include "ply-image.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "ply-utils.h" + +typedef union +{ + uint32_t *as_pixels; + png_byte *as_png_bytes; + char *address; +} PlyImageLayout; + +struct _PlyImage +{ + char *filename; + FILE *fp; + + PlyImageLayout layout; + size_t size; + + long width; + long height; +}; + +static bool ply_image_open_file (PlyImage *image); +static void ply_image_close_file (PlyImage *image); + +static bool +ply_image_open_file (PlyImage *image) +{ + assert (image != NULL); + + image->fp = fopen (image->filename, "r"); + + if (image->fp == NULL) + return false; + return true; +} + +static void +ply_image_close_file (PlyImage *image) +{ + assert (image != NULL); + + if (image->fp == NULL) + return; + fclose (image->fp); + image->fp = NULL; +} + +PlyImage * +ply_image_new (const char *filename) +{ + PlyImage *image; + + assert (filename != NULL); + + image = calloc (1, sizeof (PlyImage)); + + image->filename = strdup (filename); + image->fp = NULL; + image->layout.address = NULL; + image->size = -1; + image->width = -1; + image->height = -1; + + return image; +} + +void +ply_image_free (PlyImage *image) +{ + assert (image != NULL); + assert (image->filename != NULL); + + if (image->layout.address != NULL) + { + free (image->layout.address); + image->layout.address = NULL; + } + + free (image->filename); + free (image); +} + +static void +transform_to_argb32 (png_struct *png, + png_row_info *row_info, + png_byte *data) +{ + unsigned int i; + + for (i = 0; i < row_info->rowbytes; i += 4) + { + uint8_t red, green, blue, alpha; + uint32_t pixel_value; + + red = data[i + 0]; + green = data[i + 1]; + blue = data[i + 2]; + alpha = data[i + 3]; + + red = (uint8_t) CLAMP (((red / 255.0) * (alpha / 255.0)) * 255.0, 0, 255.0); + green = (uint8_t) CLAMP (((green / 255.0) * (alpha / 255.0)) * 255.0, + 0, 255.0); + blue = (uint8_t) CLAMP (((blue / 255.0) * (alpha / 255.0)) * 255.0, 0, 255.0); + + pixel_value = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0); + memcpy (data + i, &pixel_value, sizeof (uint32_t)); + } +} + +bool +ply_image_load (PlyImage *image) +{ + png_struct *png; + png_info *info; + png_uint_32 width, height, bytes_per_row, row; + int bits_per_pixel, color_type, interlace_method; + png_byte **rows; + + assert (image != NULL); + + if (!ply_image_open_file (image)) + return false; + + png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + assert (png != NULL); + + info = png_create_info_struct (png); + assert (info != NULL); + + png_init_io (png, image->fp); + + if (setjmp (png_jmpbuf (png)) != 0) + { + ply_image_close_file (image); + return false; + } + + png_read_info (png, info); + png_get_IHDR (png, info, + &width, &height, &bits_per_pixel, + &color_type, &interlace_method, NULL, NULL); + bytes_per_row = 4 * width; + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb (png); + + if ((color_type == PNG_COLOR_TYPE_GRAY) && (bits_per_pixel < 8)) + png_set_gray_1_2_4_to_8 (png); + + if (png_get_valid (png, info, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha (png); + + if (bits_per_pixel == 16) + png_set_strip_16 (png); + + if (bits_per_pixel < 8) + png_set_packing (png); + + if ((color_type == PNG_COLOR_TYPE_GRAY) + || (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_set_gray_to_rgb (png); + + if (interlace_method != PNG_INTERLACE_NONE) + png_set_interlace_handling (png); + + png_set_filler (png, 0xff, PNG_FILLER_AFTER); + + png_set_read_user_transform_fn (png, transform_to_argb32); + + png_read_update_info (png, info); + + rows = malloc (height * sizeof (png_byte *)); + image->layout.address = malloc (height * bytes_per_row); + + for (row = 0; row < height; row++) + rows[row] = &image->layout.as_png_bytes[row * bytes_per_row]; + + png_read_image (png, rows); + + free (rows); + png_read_end (png, info); + ply_image_close_file (image); + + image->width = width; + image->height = height; + + return true; +} + +uint32_t * +ply_image_get_data (PlyImage *image) +{ + assert (image != NULL); + + return image->layout.as_pixels; +} + +ssize_t +ply_image_get_size (PlyImage *image) +{ + assert (image != NULL); + + return image->size; +} + +long +ply_image_get_width (PlyImage *image) +{ + assert (image != NULL); + + return image->width; +} + +long +ply_image_get_height (PlyImage *image) +{ + assert (image != NULL); + + return image->height; +} + +#ifdef PLY_IMAGE_ENABLE_TEST + +#include "ply-video-buffer.h" + +#include +#include +#include + +#ifndef FRAMES_PER_SECOND +#define FRAMES_PER_SECOND 30 +#endif + +static double +get_current_time (void) +{ + const double microseconds_per_second = 1000000.0; + double timestamp; + struct timeval now = { 0L, /* zero-filled */ }; + + gettimeofday (&now, NULL); + timestamp = ((microseconds_per_second * now.tv_sec) + now.tv_usec) / + microseconds_per_second; + + return timestamp; +} + +static void +animate_at_time (PlyVideoBuffer *buffer, + PlyImage *image, + double time) +{ + PlyVideoBufferArea area; + uint32_t *data; + long width, height; + double opacity = 0.0; + + data = ply_image_get_data (image); + width = ply_image_get_width (image); + height = ply_image_get_height (image); + + ply_video_buffer_get_size (buffer, &area); + area.x = (area.width / 2) - (width / 2); + area.y = (area.height / 2) - (height / 2); + area.width = width; + area.height = height; + + opacity = .5 * sin (time * (2 * M_PI)) + .5; + ply_video_buffer_pause_updates (buffer); + ply_video_buffer_fill_with_color (buffer, &area, + 60.0/256.0, 110.0/256.0, 180.0/256.0, 1.0); + ply_video_buffer_fill_with_argb32_data_at_opacity (buffer, &area, + 0, 0, width, height, + data, 0.3); + ply_video_buffer_unpause_updates (buffer); +} + +int +main (int argc, + char **argv) +{ + PlyImage *image; + PlyVideoBuffer *buffer; + int exit_code; + double start_time; + + exit_code = 0; + + image = ply_image_new ("booting.png"); + + if (!ply_image_load (image)) + { + exit_code = errno; + perror ("could not load image"); + return exit_code; + } + + buffer = ply_video_buffer_new (NULL); + + if (!ply_video_buffer_open (buffer)) + { + exit_code = errno; + perror ("could not open framebuffer"); + return exit_code; + } + + start_time = get_current_time (); + ply_video_buffer_fill_with_color (buffer, NULL, + 60.0/256.0, 110.0/256.0, 180.0/256.0, 1.0); + while ("we want to see ad-hoc animations") + { + animate_at_time (buffer, image, get_current_time () - start_time); + usleep ((long) (1000000 / FRAMES_PER_SECOND)); + } + ply_video_buffer_close (buffer); + ply_video_buffer_free (buffer); + + ply_image_free (image); + + return exit_code; +} + +#endif /* PLY_IMAGE_ENABLE_TEST */ diff --git a/src/ply-image.h b/src/ply-image.h new file mode 100644 index 00000000..39ba671d --- /dev/null +++ b/src/ply-image.h @@ -0,0 +1,43 @@ +/* vim: ts=4 sw=2 expandtab autoindent cindent + * ply-video-buffer.h - framebuffer abstraction + * + * Copyright (C) 2007 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written By: Ray Strode + */ +#ifndef PLY_IMAGE_H +#define PLY_IMAGE_H + +#include +#include +#include + +typedef struct _PlyImage PlyImage; + +#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +PlyImage *ply_image_new (const char *filename); +void ply_image_free (PlyImage *image); +bool ply_image_load (PlyImage *image); +uint32_t *ply_image_get_data (PlyImage *image); +ssize_t ply_image_get_size (PlyImage *image); +long ply_image_get_width (PlyImage *image); +long ply_image_get_height (PlyImage *image); + +#endif + +#endif /* PLY_IMAGE_H */ diff --git a/src/ply-utils.h b/src/ply-utils.h new file mode 100644 index 00000000..e98a4a7b --- /dev/null +++ b/src/ply-utils.h @@ -0,0 +1,38 @@ +/* vim: ts=4 sw=2 expandtab autoindent cindent cino={1s + * ply-utils.h - random useful functions and macros + * + * Copyright (C) 2007 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written By: Ray Strode + */ +#ifndef PLY_UTILS_H +#define PLY_UTILS_H + +#ifndef MIN +#define MIN(a,b) ((a) <= (b)? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a,b) ((a) >= (b)? (a) : (b)) +#endif + +#ifndef CLAMP +#define CLAMP(a,b,c) (MIN (MAX ((a), (b)), (c))) +#endif + +#endif /* PLY_UTILS_H */ diff --git a/src/ply-video-buffer.c b/src/ply-video-buffer.c index 98abdac0..f3b7ec11 100644 --- a/src/ply-video-buffer.c +++ b/src/ply-video-buffer.c @@ -1,4 +1,4 @@ -/* vim: ts=4 sw=2 expandtab autoindent cindent +/* vim: ts=4 sw=2 expandtab autoindent cindent cino={1s,(0 * ply-video-buffer.c - framebuffer abstraction * * Copyright (C) 2006, 2007 Red Hat, Inc. @@ -45,26 +45,25 @@ #define PLY_VIDEO_BUFFER_DEFAULT_FB_DEVICE_NAME "/dev/fb" #endif -#define MIN(a,b) (a <= b? a : b) -#define MAX(a,b) (a >= b? a : b) -#define CLAMP(a,b,c) (((a) > (c)) ? (c) : (((a) < (b)) ? (b) : (a))) - -typedef union -{ - uint16_t *for_16bpp; - uint32_t *for_32bpp; - char *address; -} PlyVideoBufferPixelLayout; - struct _PlyVideoBuffer { - char *device_name; - int device_fd; + char *device_name; + int device_fd; + + char *map_address; + size_t size; + + uint32_t *shadow_buffer; - PlyVideoBufferPixelLayout layout; - size_t layout_size; + uint32_t red_bit_position; + uint32_t green_bit_position; + uint32_t blue_bit_position; + uint32_t alpha_bit_position; - PlyVideoBufferPixelLayout shadow_layout; + uint32_t bits_for_red; + uint32_t bits_for_green; + uint32_t bits_for_blue; + uint32_t bits_for_alpha; unsigned int bits_per_pixel; unsigned int bytes_per_pixel; @@ -77,13 +76,11 @@ struct _PlyVideoBuffer static bool ply_video_buffer_open_device (PlyVideoBuffer *buffer); static void ply_video_buffer_close_device (PlyVideoBuffer *buffer); static bool ply_video_buffer_query_device (PlyVideoBuffer *buffer); -static bool ply_video_buffer_map_to_layout (PlyVideoBuffer *buffer); -static uint32_t ply_video_buffer_convert_color_to_pixel_value ( +static bool ply_video_buffer_map_to_device (PlyVideoBuffer *buffer); +static uint_least32_t ply_video_buffer_pixel_value_to_device_pixel_value ( PlyVideoBuffer *buffer, - uint8_t red, - uint8_t green, - uint8_t blue, - uint8_t alpha); + uint32_t pixel_value); + static uint32_t ply_video_buffer_get_value_at_pixel (PlyVideoBuffer *buffer, int x, int y); @@ -92,9 +89,9 @@ static void ply_video_buffer_set_value_at_pixel (PlyVideoBuffer *buffer, int y, uint32_t pixel_value); static void ply_video_buffer_blend_value_at_pixel (PlyVideoBuffer *buffer, - int x, - int y, - uint32_t pixel_value); + int x, + int y, + uint32_t pixel_value); static void ply_video_buffer_set_area_to_pixel_value ( PlyVideoBuffer *buffer, @@ -107,6 +104,12 @@ static void ply_video_buffer_blend_area_with_pixel_value ( static void ply_video_buffer_add_area_to_flush_area (PlyVideoBuffer *buffer, PlyVideoBufferArea *area); +static bool ply_video_buffer_copy_to_device (PlyVideoBuffer *buffer, + unsigned long x, + unsigned long y, + unsigned long width, + unsigned long height); + static bool ply_video_buffer_flush (PlyVideoBuffer *buffer); static bool @@ -130,10 +133,10 @@ ply_video_buffer_close_device (PlyVideoBuffer *buffer) { assert (buffer != NULL); - if (buffer->layout.address != MAP_FAILED) + if (buffer->map_address != MAP_FAILED) { - munmap (buffer->layout.address, buffer->layout_size); - buffer->layout.address = MAP_FAILED; + munmap (buffer->map_address, buffer->size); + buffer->map_address = MAP_FAILED; } if (buffer->device_fd >= 0) @@ -164,70 +167,65 @@ ply_video_buffer_query_device (PlyVideoBuffer *buffer) buffer->area.width = variable_screen_info.xres; buffer->area.height = variable_screen_info.yres; + buffer->red_bit_position = variable_screen_info.red.offset; + buffer->bits_for_red = variable_screen_info.red.length; + + buffer->green_bit_position = variable_screen_info.green.offset; + buffer->bits_for_green = variable_screen_info.green.length; + + buffer->blue_bit_position = variable_screen_info.blue.offset; + buffer->bits_for_blue = variable_screen_info.blue.length; + + buffer->alpha_bit_position = variable_screen_info.transp.offset; + buffer->bits_for_alpha = variable_screen_info.transp.length; + if (ioctl(buffer->device_fd, FBIOGET_FSCREENINFO, &fixed_screen_info) < 0) { return false; } bytes_per_row = fixed_screen_info.line_length; - buffer->layout_size = buffer->area.height * bytes_per_row; + buffer->size = buffer->area.height * bytes_per_row; buffer->bytes_per_pixel = bytes_per_row / buffer->area.width; return true; } static bool -ply_video_buffer_map_to_layout (PlyVideoBuffer *buffer) +ply_video_buffer_map_to_device (PlyVideoBuffer *buffer) { assert (buffer != NULL); assert (buffer->device_fd >= 0); - assert (buffer->layout_size > 0); + assert (buffer->size > 0); - buffer->layout.address = mmap (NULL, buffer->layout_size, PROT_WRITE, - MAP_SHARED, buffer->device_fd, 0); + buffer->map_address = mmap (NULL, buffer->size, PROT_WRITE, + MAP_SHARED, buffer->device_fd, 0); - return buffer->layout.address != MAP_FAILED; + return buffer->map_address != MAP_FAILED; } -static uint32_t -ply_video_buffer_convert_color_to_pixel_value (PlyVideoBuffer *buffer, - uint8_t red, - uint8_t green, - uint8_t blue, - uint8_t alpha) +static uint_least32_t +ply_video_buffer_pixel_value_to_device_pixel_value (PlyVideoBuffer *buffer, + uint32_t pixel_value) { - uint32_t pixel_value; + uint8_t r, g, b, a; - assert (buffer != NULL); + a = pixel_value >> 24; + a >>= (8 - buffer->bits_for_alpha); - switch (buffer->bytes_per_pixel) - { - case 2: + r = (pixel_value >> 16) & 0xff; + r >>= (8 - buffer->bits_for_red); - red >>= 3; - green >>= 2; - blue >>= 3; + g = (pixel_value >> 8) & 0xff; + g >>= (8 - buffer->bits_for_green); - pixel_value = (red << 11) | (green << 5) | blue; - break; + b = pixel_value & 0xff; + b >>= (8 - buffer->bits_for_blue); - case 3: - pixel_value = (red << 16) | (green << 8) | blue; - break; - - case 4: - pixel_value = (alpha << 24) | (red << 16) | (green << 8) | blue; - break; - - default: - pixel_value = 0; - assert ((buffer->bytes_per_pixel == 2) - || (buffer->bytes_per_pixel == 3) - || (buffer->bytes_per_pixel == 4)); - break; - } - - return pixel_value; + return ((a << buffer->alpha_bit_position) + | (r << buffer->red_bit_position) + | (g << buffer->green_bit_position) + | (b << buffer->blue_bit_position)); } static uint32_t @@ -235,39 +233,11 @@ ply_video_buffer_get_value_at_pixel (PlyVideoBuffer *buffer, int x, int y) { - unsigned long bytes_per_row; - unsigned long offset; uint32_t pixel_value; assert (buffer != NULL); - switch (buffer->bytes_per_pixel) - { - case 2: - pixel_value = - buffer->shadow_layout.for_16bpp[y * buffer->area.width + x]; - break; - - case 3: - bytes_per_row = buffer->bytes_per_pixel * buffer->area.width; - offset = (y * bytes_per_row) + (x * buffer->bytes_per_pixel); - - memcpy (&pixel_value, buffer->shadow_layout.address + offset, - buffer->bytes_per_pixel); - pixel_value = ntohl (pixel_value); - break; - - case 4: - pixel_value = - buffer->shadow_layout.for_16bpp[y * buffer->area.width + x]; - break; - - default: - assert ((buffer->bytes_per_pixel == 2) - || (buffer->bytes_per_pixel == 3) - || (buffer->bytes_per_pixel == 4)); - break; - } + pixel_value = buffer->shadow_buffer[y * buffer->area.width + x]; return pixel_value; } @@ -278,38 +248,37 @@ ply_video_buffer_set_value_at_pixel (PlyVideoBuffer *buffer, int y, uint32_t pixel_value) { - unsigned long bytes_per_row; - unsigned long offset; - assert (buffer != NULL); - switch (buffer->bytes_per_pixel) - { - case 2: - buffer->shadow_layout.for_16bpp[y * buffer->area.width + x] = - (uint16_t) pixel_value; - break; - - case 3: - bytes_per_row = buffer->bytes_per_pixel * buffer->area.width; - offset = (y * bytes_per_row) + (x * buffer->bytes_per_pixel); - - /* FIXME: endianess issues here I think - */ - memcpy (buffer->shadow_layout.address + offset, &pixel_value, - buffer->bytes_per_pixel); - break; - - case 4: - buffer->shadow_layout.for_32bpp[y * buffer->area.width + x] = pixel_value; - break; - - default: - assert ((buffer->bytes_per_pixel == 2) - || (buffer->bytes_per_pixel == 3) - || (buffer->bytes_per_pixel == 4)); - break; - } + /* FIXME: endianess issues here I think + */ + memcpy (&buffer->shadow_buffer[y * buffer->area.width + x], + &pixel_value, sizeof (uint32_t)); +} + +static uint32_t +blend_two_pixel_values (uint32_t pixel_value_1, + uint32_t pixel_value_2) +{ + double alpha, red, green, blue; + double alpha_2, red_2, green_2, blue_2; + + alpha = (double) (pixel_value_1 >> 24) / 255.0; + red = (double) ((pixel_value_1 >> 16) & 0xff) / 255.0; + green = (double) ((pixel_value_1 >> 8) & 0xff) / 255.0; + blue = (double) (pixel_value_1 & 0xff) / 255.0; + + alpha_2 = (double) (pixel_value_2 >> 24) / 255.0; + red_2 = (double) ((pixel_value_2 >> 26) & 0xff) / 255.0; + green_2 = (double) ((pixel_value_2 >> 8) & 0xff) / 255.0; + blue_2 = (double) (pixel_value_2 & 0xff) / 255.0; + + red = red + red_2 * (1.0 - alpha); + green = green + green_2 * (1.0 - alpha); + blue = blue + blue_2 * (1.0 - alpha); + alpha = alpha + alpha_2 * (1.0 - alpha); + + return PLY_VIDEO_BUFFER_COLOR_TO_PIXEL_VALUE (red, green, blue, alpha); } static void @@ -318,37 +287,10 @@ ply_video_buffer_blend_value_at_pixel (PlyVideoBuffer *buffer, int y, uint32_t pixel_value) { - uint32_t old_pixel_value; - double old_red, old_green, old_blue, old_alpha; - double new_red, new_green, new_blue, new_alpha; - uint32_t new_pixel_value; + uint32_t old_pixel_value, new_pixel_value; old_pixel_value = ply_video_buffer_get_value_at_pixel (buffer, x, y); - - old_alpha = (old_pixel_value >> 24) / 255.0; - old_red = ((old_pixel_value >> 16) & 0xff) / 255.0; - old_green = ((old_pixel_value >> 8) & 0xff) / 255.0; - old_blue = (old_pixel_value & 0xff) / 255.0; - - new_alpha = ((pixel_value >> 24) & 0xff) / 255.0; - new_red = ((pixel_value >> 16) & 0xff) / 255.0; - new_green = ((pixel_value >> 8) & 0xff) / 255.0; - new_blue = (pixel_value & 0xff) / 255.0; - - new_red = new_red + old_red * (1.0 - new_alpha); - new_green = new_green + old_green * (1.0 - new_alpha); - new_blue = new_blue + old_blue * (1.0 - new_alpha); - new_alpha = new_alpha + (1.0 - old_alpha); - - new_red = CLAMP (new_red * 255.0, 0, 255.0); - new_green = CLAMP (new_green * 255.0, 0, 255.0); - new_blue = CLAMP (new_blue * 255.0, 0, 255.0); - new_alpha = CLAMP (new_alpha * 255.0, 0, 255.0); - - new_pixel_value = (((uint8_t) new_alpha) << 24) - | (((uint8_t) new_red) << 16) - | (((uint8_t) new_green) << 8) - | ((uint8_t) new_blue); + new_pixel_value = blend_two_pixel_values (pixel_value, old_pixel_value); ply_video_buffer_set_value_at_pixel (buffer, x, y, new_pixel_value); } @@ -408,6 +350,50 @@ ply_video_buffer_add_area_to_flush_area (PlyVideoBuffer *buffer, buffer->area_to_flush.height = MAX (buffer->area_to_flush.height, area->height); } +static bool +ply_video_buffer_copy_to_device (PlyVideoBuffer *buffer, + unsigned long x, + unsigned long y, + unsigned long width, + unsigned long height) +{ + unsigned long row, column; + unsigned long start_offset; + unsigned long size; + + unsigned long bytes_per_row; + + bytes_per_row = buffer->area.width * buffer->bytes_per_pixel; + start_offset = y * bytes_per_row + x * buffer->bytes_per_pixel; + size = width * height * buffer->bytes_per_pixel; + + for (row = y; row < y + height; row++) + { + for (column = x; column < x + width; column++) + { + uint32_t pixel_value; + uint_least32_t device_pixel_value; + unsigned long offset; + + pixel_value = buffer->shadow_buffer[width * row + column]; + + device_pixel_value = + ply_video_buffer_pixel_value_to_device_pixel_value (buffer, + pixel_value); + + offset = row * bytes_per_row + column * buffer->bytes_per_pixel; + + memcpy (buffer->map_address + offset, &device_pixel_value, + buffer->bits_per_pixel); + } + } + + if (msync (buffer->map_address + start_offset, size, MS_SYNC) < 0) + return false; + + return true; +} + static bool ply_video_buffer_flush (PlyVideoBuffer *buffer) { @@ -421,15 +407,15 @@ ply_video_buffer_flush (PlyVideoBuffer *buffer) if (buffer->is_paused) return true; - bytes_per_row = buffer->bytes_per_pixel * buffer->area_to_flush.width; - start_offset = (buffer->area_to_flush.y * bytes_per_row) - + (buffer->area_to_flush.x * buffer->bytes_per_pixel); - size = buffer->area_to_flush.width * buffer->area_to_flush.height - * buffer->bytes_per_pixel; + start_offset = (buffer->area_to_flush.y * 4 * buffer->area_to_flush.width) + + (buffer->area_to_flush.x * 4); + size = buffer->area_to_flush.width * buffer->area_to_flush.height; - memcpy (buffer->layout.address + start_offset, - buffer->shadow_layout.address + start_offset, size); - if (msync (buffer->layout.address + start_offset, size, MS_SYNC) < 0) + if (!ply_video_buffer_copy_to_device (buffer, + buffer->area_to_flush.x, + buffer->area_to_flush.y, + buffer->area_to_flush.width, + buffer->area_to_flush.height)) return false; buffer->area_to_flush.x = 0; @@ -453,8 +439,8 @@ ply_video_buffer_new (const char *device_name) buffer->device_name = strdup (PLY_VIDEO_BUFFER_DEFAULT_FB_DEVICE_NAME); - buffer->layout.address = MAP_FAILED; - buffer->shadow_layout.address = NULL; + buffer->map_address = MAP_FAILED; + buffer->shadow_buffer = NULL; buffer->is_paused = false; @@ -470,7 +456,7 @@ ply_video_buffer_free (PlyVideoBuffer *buffer) ply_video_buffer_close (buffer); free (buffer->device_name); - free (buffer->shadow_layout.address); + free (buffer->shadow_buffer); free (buffer); } @@ -493,15 +479,16 @@ ply_video_buffer_open (PlyVideoBuffer *buffer) goto out; } - if (!ply_video_buffer_map_to_layout (buffer)) + if (!ply_video_buffer_map_to_device (buffer)) { goto out; } - buffer->shadow_layout.address = - realloc (buffer->shadow_layout.address, - buffer->layout_size); - memset (buffer->shadow_layout.address, 0, buffer->layout_size); + buffer->shadow_buffer = + realloc (buffer->shadow_buffer, + 4 * buffer->area.width * buffer->area.height); + memset (buffer->shadow_buffer, 0, + 4 * buffer->area.width * buffer->area.height); ply_video_buffer_fill_with_color (buffer, NULL, 0.0, 0.0, 0.0, 1.0); is_open = true; @@ -541,7 +528,7 @@ bool ply_video_buffer_device_is_open (PlyVideoBuffer *buffer) { assert (buffer != NULL); - return buffer->device_fd >= 0 && buffer->layout.address != MAP_FAILED; + return buffer->device_fd >= 0 && buffer->map_address != MAP_FAILED; } char * @@ -616,12 +603,7 @@ ply_video_buffer_fill_with_color (PlyVideoBuffer *buffer, green *= alpha; blue *= alpha; - pixel_value = - ply_video_buffer_convert_color_to_pixel_value (buffer, - CLAMP (red * 255.0, 0, 255), - CLAMP (green * 255.0, 0, 255), - CLAMP (blue * 255.0, 0, 255), - CLAMP (alpha * 255.0, 0, 255)); + pixel_value = PLY_VIDEO_BUFFER_COLOR_TO_PIXEL_VALUE (red, green, blue, alpha); if (abs (alpha - 1.0) <= DBL_MIN) ply_video_buffer_set_area_to_pixel_value (buffer, area, pixel_value); @@ -634,15 +616,18 @@ ply_video_buffer_fill_with_color (PlyVideoBuffer *buffer, } bool -ply_video_buffer_fill_with_argb32_data (PlyVideoBuffer *buffer, - PlyVideoBufferArea *area, - unsigned long x, - unsigned long y, - unsigned long width, - unsigned long height, - uint32_t *data) +ply_video_buffer_fill_with_argb32_data_at_opacity (PlyVideoBuffer *buffer, + PlyVideoBufferArea *area, + unsigned long x, + unsigned long y, + unsigned long width, + unsigned long height, + uint32_t *data, + double opacity) { long row, column; + bool is_translucent; + uint32_t alpha_pixel_value; assert (buffer != NULL); assert (ply_video_buffer_device_is_open (buffer)); @@ -650,23 +635,34 @@ ply_video_buffer_fill_with_argb32_data (PlyVideoBuffer *buffer, if (area == NULL) area = &buffer->area; + if (abs (opacity - 1.0) > DBL_MIN) + { + uint8_t alpha; + alpha_pixel_value = 0x00000000; + alpha = (uint8_t) CLAMP (opacity * 255.0, 0.0, 255.0); + alpha_pixel_value |= alpha << 24; + is_translucent = true; + } + else + is_translucent = false; + for (row = y; row < y + height; row++) { for (column = x; column < x + width; column++) { - uint8_t alpha; + uint32_t pixel_value; - alpha = data[width * row + column] >> 24; - if (alpha == 0xff) - ply_video_buffer_set_value_at_pixel (buffer, + pixel_value = data[width * row + column]; + + if (is_translucent) + { + pixel_value = + blend_two_pixel_values (alpha_pixel_value, pixel_value); + } + ply_video_buffer_blend_value_at_pixel (buffer, area->x + (column - x), area->y + (row - y), - data[width * row + column]); - else - ply_video_buffer_blend_value_at_pixel (buffer, - area->x + (column - x), - area->y + (row - y), - data[width * row + column]); + pixel_value); } } @@ -675,6 +671,20 @@ ply_video_buffer_fill_with_argb32_data (PlyVideoBuffer *buffer, return ply_video_buffer_flush (buffer); } +bool +ply_video_buffer_fill_with_argb32_data (PlyVideoBuffer *buffer, + PlyVideoBufferArea *area, + unsigned long x, + unsigned long y, + unsigned long width, + unsigned long height, + uint32_t *data) +{ + return ply_video_buffer_fill_with_argb32_data_at_opacity (buffer, area, + x, y, width, + height, data, 1.0); +} + #ifdef PLY_VIDEO_BUFFER_ENABLE_TEST #include @@ -706,11 +716,11 @@ animate_at_time (PlyVideoBuffer *buffer, for (y = 0; y < 768; y++) { - int blue_offset; + int blue_bit_position; uint8_t red, green, blue, alpha; - blue_offset = (int) 64 * sin (time) + (255 - 64); - blue = rand () % blue_offset; + blue_bit_position = (int) 64 * sin (time) + (255 - 64); + blue = rand () % blue_bit_position; for (x = 0; x < 1024; x++) { alpha = 0xff; diff --git a/src/ply-video-buffer.h b/src/ply-video-buffer.h index 1e6265ae..8f381fd4 100644 --- a/src/ply-video-buffer.h +++ b/src/ply-video-buffer.h @@ -26,6 +26,8 @@ #include #include +#include "ply-utils.h" + typedef struct _PlyVideoBuffer PlyVideoBuffer; typedef struct _PlyVideoBufferArea PlyVideoBufferArea; @@ -37,6 +39,12 @@ struct _PlyVideoBufferArea unsigned long height; }; +#define PLY_VIDEO_BUFFER_COLOR_TO_PIXEL_VALUE(r,g,b,a) \ + (((uint8_t) (CLAMP (a * 255.0, 0.0, 255.0)) << 24) \ + | ((uint8_t) (CLAMP (r * 255.0, 0.0, 255.0)) << 16) \ + | ((uint8_t) (CLAMP (g * 255.0, 0.0, 255.0)) << 8) \ + | ((uint8_t) (CLAMP (b * 255.0, 0.0, 255.0)))) + #ifndef PLY_HIDE_FUNCTION_DECLARATIONS PlyVideoBuffer *ply_video_buffer_new (const char *device_name); void ply_video_buffer_free (PlyVideoBuffer *buffer); @@ -64,7 +72,14 @@ bool ply_video_buffer_fill_with_argb32_data (PlyVideoBuffer *buffer, unsigned long width, unsigned long height, uint32_t *data); - +bool ply_video_buffer_fill_with_argb32_data_at_opacity (PlyVideoBuffer *buffer, + PlyVideoBufferArea *area, + unsigned long x, + unsigned long y, + unsigned long width, + unsigned long height, + uint32_t *data, + double opacity); #endif