]> git.ipfire.org Git - thirdparty/plymouth.git/commitdiff
rework framebuffer code to be more general
authorRay Strode <rstrode@redhat.com>
Fri, 11 May 2007 03:33:59 +0000 (23:33 -0400)
committerRay Strode <rstrode@redhat.com>
Fri, 11 May 2007 03:33:59 +0000 (23:33 -0400)
add new ply-image apis for loading pngs

src/ply-image.c [new file with mode: 0644]
src/ply-image.h [new file with mode: 0644]
src/ply-utils.h [new file with mode: 0644]
src/ply-video-buffer.c
src/ply-video-buffer.h

diff --git a/src/ply-image.c b/src/ply-image.c
new file mode 100644 (file)
index 0000000..693f1d5
--- /dev/null
@@ -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 <krh@redhat.com>
+ *             Ray Strode <rstrode@redhat.com>
+ *             Carl D. Worth (cworth@cworth.org>
+ */
+#include "config.h"
+#include "ply-image.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <png.h>
+
+#include <linux/fb.h>
+
+#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 <math.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+#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 (file)
index 0000000..39ba671
--- /dev/null
@@ -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 <rstrode@redhat.com>
+ */
+#ifndef PLY_IMAGE_H
+#define PLY_IMAGE_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <unistd.h>
+
+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 (file)
index 0000000..e98a4a7
--- /dev/null
@@ -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 <rstrode@redhat.com>
+ */
+#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 */
index 98abdac0e73bed1953c7fd4a064204c3d6eadbf2..f3b7ec11176fd81959215317b33ec3edb8828ad7 100644 (file)
@@ -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.
 #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 <math.h>
@@ -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;
index 1e6265ae7b27f0749d685bc539b559e9c3bc7ecb..8f381fd446776f5058a6cb7aac0b1bccf5f2d7d7 100644 (file)
@@ -26,6 +26,8 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+#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