]> git.ipfire.org Git - thirdparty/plymouth.git/commitdiff
Add alpha blending to video buffer
authorRay Strode <rstrode@redhat.com>
Thu, 10 May 2007 16:26:34 +0000 (12:26 -0400)
committerRay Strode <rstrode@redhat.com>
Thu, 10 May 2007 16:26:34 +0000 (12:26 -0400)
src/ply-video-buffer.c

index 50294cb113cedd722e11ee783cfe825b4e2f69bc..e15f2523c1f45cf0f0d9773508ac72917db8c160 100644 (file)
@@ -36,6 +36,7 @@
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <values.h>
 #include <unistd.h>
 
 #include <linux/fb.h>
@@ -81,12 +82,28 @@ static uint32_t ply_video_buffer_convert_color_to_pixel_value (
     uint8_t         green,
     uint8_t         blue, 
     uint8_t         alpha);
-static void ply_video_buffer_set_pixel_to_value (PlyVideoBuffer *buffer,
+static uint32_t ply_video_buffer_get_value_at_pixel (PlyVideoBuffer *buffer,
+                                                     int             x,
+                                                     int             y);
+static void ply_video_buffer_set_value_at_pixel (PlyVideoBuffer *buffer,
                                                  int             x,
                                                  int             y,
                                                  uint32_t        pixel_value);
-
-static void ply_video_buffer_add_area_to_flush_area (PlyVideoBuffer     *buffer, 
+static void ply_video_buffer_blend_value_at_pixel (PlyVideoBuffer *buffer,
+    int             x,
+    int             y,
+    uint32_t        pixel_value);
+
+static void ply_video_buffer_set_area_to_pixel_value (
+    PlyVideoBuffer     *buffer,
+    PlyVideoBufferArea *area,
+    uint32_t            pixel_value);
+static void ply_video_buffer_blend_area_with_pixel_value (
+    PlyVideoBuffer     *buffer,
+    PlyVideoBufferArea *area,
+    uint32_t            pixel_value);
+
+static void ply_video_buffer_add_area_to_flush_area (PlyVideoBuffer     *buffer,
                                                      PlyVideoBufferArea *area);
 static bool ply_video_buffer_flush (PlyVideoBuffer *buffer);
 
@@ -200,6 +217,51 @@ ply_video_buffer_convert_color_to_pixel_value (PlyVideoBuffer *buffer,
         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;
+}
+
+static uint32_t
+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);
+
+        /* FIXME: I think we're going to need to byteswap pixel_value on
+         * ppc
+         */
+        memcpy (&pixel_value, buffer->shadow_layout.address + offset,
+                buffer->bytes_per_pixel);
+        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) 
@@ -211,7 +273,7 @@ ply_video_buffer_convert_color_to_pixel_value (PlyVideoBuffer *buffer,
 }
 
 static void
-ply_video_buffer_set_pixel_to_value (PlyVideoBuffer *buffer,
+ply_video_buffer_set_value_at_pixel (PlyVideoBuffer *buffer,
                                      int             x,
                                      int             y,
                                      uint32_t        pixel_value)
@@ -232,8 +294,7 @@ ply_video_buffer_set_pixel_to_value (PlyVideoBuffer *buffer,
         bytes_per_row = buffer->bytes_per_pixel * buffer->area.width;
         offset = (y * bytes_per_row) + (x * buffer->bytes_per_pixel);
 
-        /* FIXME: I think we're going to need to byteswap pixel_value on
-         * ppc
+        /* FIXME: see fixme in _get_value_at_pixel
          */
         memcpy (buffer->shadow_layout.address + offset, &pixel_value,
                 buffer->bytes_per_pixel);
@@ -251,6 +312,80 @@ ply_video_buffer_set_pixel_to_value (PlyVideoBuffer *buffer,
     }
 }
 
+static void 
+ply_video_buffer_blend_value_at_pixel (PlyVideoBuffer *buffer,
+                                       int             x,
+                                       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;
+
+  old_pixel_value = ply_video_buffer_get_value_at_pixel (buffer, x, y);
+
+  old_alpha = old_pixel_value / 255.0;
+  old_red = old_pixel_value / 255.0;
+  old_green = old_pixel_value / 255.0;
+  old_blue = old_pixel_value / 255.0;
+
+  new_alpha = (pixel_value >> 24) / 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 * new_alpha + old_red * old_alpha * (1.0 - new_alpha);
+  new_green = new_green * new_alpha + old_green * old_alpha * (1.0 - new_alpha);
+  new_blue = new_blue * new_alpha + old_blue * old_alpha * (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);
+
+  pixel_value = (((uint8_t) new_alpha) << 24)
+                 | (((uint8_t) new_red) << 16)
+                 | (((uint8_t) new_green) << 8)
+                 | ((uint8_t) new_blue);
+
+  ply_video_buffer_set_value_at_pixel (buffer, x, y, pixel_value);
+}
+
+static void
+ply_video_buffer_set_area_to_pixel_value (PlyVideoBuffer     *buffer,
+                                          PlyVideoBufferArea *area,
+                                          uint32_t            pixel_value)
+{
+  long row, column;
+
+  for (row = 0; row < area->height; row++)
+    {
+      for (column = 0; column < area->width; column++)
+        {
+          ply_video_buffer_set_value_at_pixel (buffer, column, row,
+                                               pixel_value);
+        }
+    }
+}
+
+static void
+ply_video_buffer_blend_area_with_pixel_value (PlyVideoBuffer     *buffer,
+                                              PlyVideoBufferArea *area,
+                                              uint32_t            pixel_value)
+{
+  long row, column;
+
+  for (row = 0; row < area->height; row++)
+    {
+      for (column = 0; column < area->width; column++)
+        {
+          ply_video_buffer_blend_value_at_pixel (buffer, column, row, 
+                                                 pixel_value);
+        }
+    }
+}
+
 static void
 ply_video_buffer_add_area_to_flush_area (PlyVideoBuffer     *buffer, 
                                          PlyVideoBufferArea *area)
@@ -357,6 +492,7 @@ ply_video_buffer_open (PlyVideoBuffer *buffer)
     realloc (buffer->shadow_layout.address,
              buffer->layout_size);
   memset (buffer->shadow_layout.address, 0, buffer->layout_size);
+  ply_video_buffer_fill_with_color (buffer, NULL, 0.0, 0.0, 0.0, 1.0);
 
   is_open = true;
 
@@ -442,7 +578,6 @@ ply_video_buffer_fill_with_color (PlyVideoBuffer      *buffer,
                                   double               alpha)
 {
   uint32_t pixel_value;
-  long row, column;
 
   assert (buffer != NULL);
   assert (ply_video_buffer_device_is_open (buffer));
@@ -456,14 +591,11 @@ ply_video_buffer_fill_with_color (PlyVideoBuffer      *buffer,
                                                    CLAMP (green * 255.0, 0, 255), 
                                                    CLAMP (blue * 255.0, 0, 255),
                                                    CLAMP (alpha * 255.0, 0, 255));
-  for (row = 0; row < area->height; row++)
-    {
-      for (column = 0; column < area->width; column++)
-        {
-          ply_video_buffer_set_pixel_to_value (buffer, column, row,
-                                               pixel_value);
-        }
-    }
+
+  if (abs (alpha - 1.0) <= DBL_MIN) 
+    ply_video_buffer_set_area_to_pixel_value (buffer, area, pixel_value);
+  else
+    ply_video_buffer_blend_area_with_pixel_value (buffer, area, pixel_value);
 
   ply_video_buffer_add_area_to_flush_area (buffer, area);
 
@@ -504,8 +636,12 @@ ply_video_buffer_fill_with_argb32_data (PlyVideoBuffer     *buffer,
           pixel_value = 
             ply_video_buffer_convert_color_to_pixel_value (buffer, red, green,
                                                            blue, alpha);
-          ply_video_buffer_set_pixel_to_value (buffer, column, row,
-                                               pixel_value);
+          if (alpha == 0xff)
+            ply_video_buffer_set_value_at_pixel (buffer, column, row,
+                                                 pixel_value);
+          else
+            ply_video_buffer_blend_value_at_pixel (buffer, column, row,
+                                                   pixel_value);
         }
     }