gimp r25038 - in trunk: . app/display



Author: neo
Date: Wed Mar  5 20:44:19 2008
New Revision: 25038
URL: http://svn.gnome.org/viewvc/gimp?rev=25038&view=rev

Log:
2008-03-05  Sven Neumann  <sven gimp org>

	* app/display/gimpdisplayshell-preview.c: applied a modified and
	further optimized version of the patch from Tom Lechner as
	attached to bug #167926.  This makes the transform preview take
	the layer opacity into account. Needs some more work...



Modified:
   trunk/ChangeLog
   trunk/app/display/gimpdisplayshell-preview.c

Modified: trunk/app/display/gimpdisplayshell-preview.c
==============================================================================
--- trunk/app/display/gimpdisplayshell-preview.c	(original)
+++ trunk/app/display/gimpdisplayshell-preview.c	Wed Mar  5 20:44:19 2008
@@ -25,9 +25,10 @@
 #include "display-types.h"
 #include "tools/tools-types.h"
 
-#include "core/gimpimage.h"
-#include "core/gimpdrawable.h"
 #include "core/gimpchannel.h"
+#include "core/gimpdrawable.h"
+#include "core/gimplayer.h"
+#include "core/gimpimage.h"
 
 #include "base/tile-manager.h"
 
@@ -42,6 +43,10 @@
 #include "gimpdisplayshell-transform.h"
 
 
+#define INT_MULT(a,b,t)  ((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8))
+#define INT_BLEND(a,b,alpha,tmp)  (INT_MULT((a) - (b), alpha, tmp) + (b))
+
+
 #define MAX_SUB_COLS 6     /* number of columns and  */
 #define MAX_SUB_ROWS 6     /* rows to use in perspective preview subdivision */
 
@@ -55,29 +60,39 @@
                                                       gint         *x,
                                                       gint         *y,
                                                       gfloat       *u,
-                                                      gfloat       *v);
+                                                      gfloat       *v,
+                                                      guchar        opacity);
 static void    gimp_display_shell_draw_tri           (GimpDrawable *texture,
                                                       GdkDrawable  *dest,
+                                                      GdkPixbuf    *area,
+                                                      gint          area_offx,
+                                                      gint          area_offy,
                                                       GimpChannel  *mask,
                                                       gint          mask_offx,
                                                       gint          mask_offy,
                                                       gint         *x,
                                                       gint         *y,
                                                       gfloat       *u,
-                                                      gfloat       *v);
+                                                      gfloat       *v,
+                                                      guchar        opacity);
 static void    gimp_display_shell_draw_tri_row       (GimpDrawable *texture,
                                                       GdkDrawable  *dest,
-                                                      GdkPixbuf    *row,
+                                                      GdkPixbuf    *area,
+                                                      gint          area_offx,
+                                                      gint          area_offy,
                                                       gint          x1,
                                                       gfloat        u1,
                                                       gfloat        v1,
                                                       gint          x2,
                                                       gfloat        u2,
                                                       gfloat        v2,
-                                                      gint          y);
+                                                      gint          y,
+                                                      guchar        opacity);
 static void    gimp_display_shell_draw_tri_row_mask  (GimpDrawable *texture,
                                                       GdkDrawable  *dest,
-                                                      GdkPixbuf    *row,
+                                                      GdkPixbuf    *area,
+                                                      gint          area_offx,
+                                                      gint          area_offy,
                                                       GimpChannel  *mask,
                                                       gint          mask_offx,
                                                       gint          mask_offy,
@@ -87,7 +102,8 @@
                                                       gint          x2,
                                                       gfloat        u2,
                                                       gfloat        v2,
-                                                      gint          y);
+                                                      gint          y,
+                                                      guchar        opacity);
 static void    gimp_display_shell_trace_tri_edge     (gint         *dest,
                                                       gint          x1,
                                                       gint          y1,
@@ -96,187 +112,222 @@
 
 /*  public functions  */
 
+/**
+ * gimp_display_shell_preview_transform:
+ * @shell: the #GimpDisplayShell
+ *
+ * If the active tool as reported by tool_manager_get_active() is a
+ * #GimpTransformTool and the tool has a valid drawable, and the tool
+ * has use_grid true (which, incidentally, is not the same thing as
+ * the preview type), and the area of the transformed preview is
+ * convex, then proceed with drawing the preview.
+ *
+ * The preview area is divided into 1 or more quadrilaterals, and
+ * drawn with gimp_display_shell_draw_quad(), which in turn breaks it
+ * down into 2 triangles, and draws row by row. If the tool is the
+ * Perspective tool, then more small quadrilaterals are used to
+ * compensate for the little rectangles not being the same size. In
+ * other words, all the transform tools are affine transformations
+ * except perspective, so approximate it with a few subdivisions.
+ **/
 void
 gimp_display_shell_preview_transform (GimpDisplayShell *shell)
 {
+  GimpTool          *tool;
+  GimpTransformTool *tr_tool;
+  gdouble            z1, z2, z3, z4;
+
+  GimpChannel *mask;
+  gint         mask_x1, mask_y1;
+  gint         mask_x2, mask_y2;
+  gint         mask_offx, mask_offy;
+
+  gint         columns, rows;
+  gint         j, k, sub;
+
+   /* x and y get filled with the screen coordinates of each corner of
+    * each quadrilateral subdivision of the transformed area. u and v
+    * are the corresponding points in the mask
+    */
+  gfloat       du, dv, dx, dy;
+  gint         x[MAX_SUB_COLS * MAX_SUB_ROWS][4],
+               y[MAX_SUB_COLS * MAX_SUB_ROWS][4];
+  gfloat       u[MAX_SUB_COLS * MAX_SUB_ROWS][4],
+               v[MAX_SUB_COLS * MAX_SUB_ROWS][4];
+  guchar       opacity = 255;
+
   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
 
-  if (gimp_display_shell_get_show_transform (shell))
-    {
-      GimpTool          *tool;
-      GimpTransformTool *tr_tool;
-      gdouble            z1, z2, z3, z4;
+  if (! gimp_display_shell_get_show_transform (shell) || ! shell->canvas)
+    return;
 
-      tool = tool_manager_get_active (shell->display->image->gimp);
+  tool = tool_manager_get_active (shell->display->image->gimp);
 
-      if (! GIMP_IS_TRANSFORM_TOOL (tool) ||
-          ! GIMP_IS_DRAWABLE (tool->drawable))
-        return;
+  if (! GIMP_IS_TRANSFORM_TOOL (tool) ||
+      ! GIMP_IS_DRAWABLE (tool->drawable))
+    return;
 
-      tr_tool = GIMP_TRANSFORM_TOOL (tool);
+  tr_tool = GIMP_TRANSFORM_TOOL (tool);
 
-      if (! tr_tool->use_grid)
-        return;
+  if (! tr_tool->use_grid)
+    return;
 
-      z1 = ((tr_tool->tx2 - tr_tool->tx1) * (tr_tool->ty4 - tr_tool->ty1) -
-            (tr_tool->tx4 - tr_tool->tx1) * (tr_tool->ty2 - tr_tool->ty1));
-      z2 = ((tr_tool->tx4 - tr_tool->tx1) * (tr_tool->ty3 - tr_tool->ty1) -
-            (tr_tool->tx3 - tr_tool->tx1) * (tr_tool->ty4 - tr_tool->ty1));
-      z3 = ((tr_tool->tx4 - tr_tool->tx2) * (tr_tool->ty3 - tr_tool->ty2) -
-            (tr_tool->tx3 - tr_tool->tx2) * (tr_tool->ty4 - tr_tool->ty2));
-      z4 = ((tr_tool->tx3 - tr_tool->tx2) * (tr_tool->ty1 - tr_tool->ty2) -
-            (tr_tool->tx1 - tr_tool->tx2) * (tr_tool->ty3 - tr_tool->ty2));
+  z1 = ((tr_tool->tx2 - tr_tool->tx1) * (tr_tool->ty4 - tr_tool->ty1) -
+        (tr_tool->tx4 - tr_tool->tx1) * (tr_tool->ty2 - tr_tool->ty1));
+  z2 = ((tr_tool->tx4 - tr_tool->tx1) * (tr_tool->ty3 - tr_tool->ty1) -
+        (tr_tool->tx3 - tr_tool->tx1) * (tr_tool->ty4 - tr_tool->ty1));
+  z3 = ((tr_tool->tx4 - tr_tool->tx2) * (tr_tool->ty3 - tr_tool->ty2) -
+        (tr_tool->tx3 - tr_tool->tx2) * (tr_tool->ty4 - tr_tool->ty2));
+  z4 = ((tr_tool->tx3 - tr_tool->tx2) * (tr_tool->ty1 - tr_tool->ty2) -
+        (tr_tool->tx1 - tr_tool->tx2) * (tr_tool->ty3 - tr_tool->ty2));
 
-      /* only draw convex polygons */
+  /* only draw convex polygons */
 
-      if ((z1 * z2 > 0) && (z3 * z4 > 0))
-        {
-          GimpChannel *mask;
-          gint         mask_x1, mask_y1;
-          gint         mask_x2, mask_y2;
-          gint         mask_offx, mask_offy;
-
-          gint         columns, rows;
-          gint         j, k, sub;
-
-          gfloat       du, dv, dx, dy;
-          gint         x[MAX_SUB_COLS * MAX_SUB_ROWS][4],
-                       y[MAX_SUB_COLS * MAX_SUB_ROWS][4];
-          gfloat       u[MAX_SUB_COLS * MAX_SUB_ROWS][4],
-                       v[MAX_SUB_COLS * MAX_SUB_ROWS][4];
-
-          mask = NULL;
-          mask_offx = mask_offy = 0;
-
-          if (gimp_drawable_mask_bounds (tool->drawable,
-                                         &mask_x1, &mask_y1,
-                                         &mask_x2, &mask_y2))
-            {
-              mask = gimp_image_get_mask (shell->display->image);
+  if (! ((z1 * z2 > 0) && (z3 * z4 > 0))) return;
 
-              gimp_item_offsets (GIMP_ITEM (tool->drawable),
-                                 &mask_offx, &mask_offy);
-            }
+  if (GIMP_IS_LAYER (tool->drawable))
+    opacity = gimp_layer_get_opacity (GIMP_LAYER (tool->drawable)) * 255.999;
 
-          if (GIMP_IS_PERSPECTIVE_TOOL (tr_tool))
-            {
-              /* approximate perspective transform by subdivision
-               *
-               * increase number of columns/rows to increase precision
-               */
-              columns = MAX_SUB_COLS;
-              rows    = MAX_SUB_ROWS;
-            }
-          else
-            {
-              /*  for affine transforms subdivision has no effect
-               */
-              columns = 1;
-              rows    = 1;
-            }
+  mask = NULL;
+  mask_offx = mask_offy = 0;
 
-          dx = (tr_tool->x2 - tr_tool->x1) / ((gfloat) columns);
-          dy = (tr_tool->y2 - tr_tool->y1) / ((gfloat) rows);
+  if (gimp_drawable_mask_bounds (tool->drawable,
+                                 &mask_x1, &mask_y1,
+                                 &mask_x2, &mask_y2))
+    {
+      mask = gimp_image_get_mask (shell->display->image);
 
-          du = (mask_x2 - mask_x1) / ((gfloat) columns);
-          dv = (mask_y2 - mask_y1) / ((gfloat) rows);
+      gimp_item_offsets (GIMP_ITEM (tool->drawable),
+                         &mask_offx, &mask_offy);
+    }
 
-#define CALC_VERTEX(col, row, sub, index) \
-          { \
-            gdouble tx1, ty1; \
-            gdouble tx2, ty2; \
-\
-            u[sub][index] = tr_tool->x1 + (dx * (col + (index & 1))); \
-            v[sub][index] = tr_tool->y1 + (dy * (row + (index >> 1))); \
-\
-            gimp_matrix3_transform_point (&tr_tool->transform, \
-                                          u[sub][index], v[sub][index], \
-                                          &tx1, &ty1); \
-\
-            gimp_display_shell_transform_xy_f (shell, \
-                                               tx1, ty1, \
-                                               &tx2, &ty2, \
-                                               FALSE); \
-            x[sub][index] = (gint) tx2; \
-            y[sub][index] = (gint) ty2; \
-\
-            u[sub][index] = mask_x1 + (du * (col + (index & 1))); \
-            v[sub][index] = mask_y1 + (dv * (row + (index >> 1))); \
-          }
+  if (GIMP_IS_PERSPECTIVE_TOOL (tr_tool))
+    {
+      /* approximate perspective transform by subdivision
+       *
+       * increase number of columns/rows to increase precision
+       */
+      columns = MAX_SUB_COLS;
+      rows    = MAX_SUB_ROWS;
+    }
+  else
+    {
+      /*  for affine transforms subdivision has no effect
+       */
+      columns = 1;
+      rows    = 1;
+    }
+
+  dx = (tr_tool->x2 - tr_tool->x1) / ((gfloat) columns);
+  dy = (tr_tool->y2 - tr_tool->y1) / ((gfloat) rows);
+
+  du = (mask_x2 - mask_x1) / ((gfloat) columns);
+  dv = (mask_y2 - mask_y1) / ((gfloat) rows);
+
+#define CALC_VERTEX(col, row, sub, index)                       \
+  {                                                             \
+    gdouble tx1, ty1;                                           \
+    gdouble tx2, ty2;                                           \
+                                                                \
+    u[sub][index] = tr_tool->x1 + (dx * (col + (index & 1)));   \
+    v[sub][index] = tr_tool->y1 + (dy * (row + (index >> 1)));  \
+                                                                \
+    gimp_matrix3_transform_point (&tr_tool->transform,          \
+                                  u[sub][index], v[sub][index], \
+                                  &tx1, &ty1);                  \
+                                                                \
+    gimp_display_shell_transform_xy_f (shell,                   \
+                                       tx1, ty1,                \
+                                       &tx2, &ty2,              \
+                                       FALSE);                  \
+    x[sub][index] = (gint) tx2;                                 \
+    y[sub][index] = (gint) ty2;                                 \
+                                                                \
+    u[sub][index] = mask_x1 + (du * (col + (index & 1)));       \
+    v[sub][index] = mask_y1 + (dv * (row + (index >> 1)));      \
+  }
 
 #define COPY_VERTEX(subdest, idest, subsrc, isrc) \
-          x[subdest][idest] = x[subsrc][isrc]; \
-          y[subdest][idest] = y[subsrc][isrc]; \
-          u[subdest][idest] = u[subsrc][isrc]; \
-          v[subdest][idest] = v[subsrc][isrc];
-
-          /*
-           * upper left corner subdivision: calculate all vertices
-           */
+  x[subdest][idest] = x[subsrc][isrc];            \
+  y[subdest][idest] = y[subsrc][isrc];            \
+  u[subdest][idest] = u[subsrc][isrc];            \
+  v[subdest][idest] = v[subsrc][isrc];
 
-          for (j = 0; j < 4; j++)
-            {
-              CALC_VERTEX (0, 0, 0, j);
-            }
+  /*
+   * upper left corner subdivision: calculate all vertices
+   */
 
-          /*
-           * top row subdivisions: calculate only right side vertices
-           */
+  for (j = 0; j < 4; j++)
+    {
+      CALC_VERTEX (0, 0, 0, j);
+    }
 
-          for (j = 1; j < columns; j++)
-            {
-              COPY_VERTEX (j, 0, j - 1, 1);
-              CALC_VERTEX (j, 0, j, 1);
-              COPY_VERTEX (j, 2, j - 1, 3);
-              CALC_VERTEX (j, 0, j, 3);
-            }
+  /*
+   * top row subdivisions: calculate only right side vertices
+   */
 
-          /*
-           * left column subdivisions: calculate only bottom side vertices
-           */
+  for (j = 1; j < columns; j++)
+    {
+      COPY_VERTEX (j, 0, j - 1, 1);
+      CALC_VERTEX (j, 0, j, 1);
+      COPY_VERTEX (j, 2, j - 1, 3);
+      CALC_VERTEX (j, 0, j, 3);
+    }
 
-          for (j = 1, sub = columns; j < rows; j++, sub += columns)
-            {
-              COPY_VERTEX (sub, 0, sub - columns, 2);
-              COPY_VERTEX (sub, 1, sub - columns, 3);
-              CALC_VERTEX (0, j, sub, 2);
-              CALC_VERTEX (0, j, sub, 3);
-            }
+  /*
+   * left column subdivisions: calculate only bottom side vertices
+   */
 
-          /*
-           * the rest: calculate only the bottom-right vertex
-           */
+  for (j = 1, sub = columns; j < rows; j++, sub += columns)
+    {
+      COPY_VERTEX (sub, 0, sub - columns, 2);
+      COPY_VERTEX (sub, 1, sub - columns, 3);
+      CALC_VERTEX (0, j, sub, 2);
+      CALC_VERTEX (0, j, sub, 3);
+    }
 
-          for (j = 1, sub = columns; j < rows; j++)
-            {
-              sub++;
+  /*
+   * the rest: calculate only the bottom-right vertex
+   */
 
-              for (k = 1; k < columns; k++, sub++)
-                {
-                  COPY_VERTEX (sub, 0, sub - 1, 1);
-                  COPY_VERTEX (sub, 1, sub - columns, 3);
-                  COPY_VERTEX (sub, 2, sub - 1, 3);
-                  CALC_VERTEX (k, j, sub, 3);
-                }
-            }
+  for (j = 1, sub = columns; j < rows; j++)
+    {
+      sub++;
+
+      for (k = 1; k < columns; k++, sub++)
+        {
+          COPY_VERTEX (sub, 0, sub - 1, 1);
+          COPY_VERTEX (sub, 1, sub - columns, 3);
+          COPY_VERTEX (sub, 2, sub - 1, 3);
+          CALC_VERTEX (k, j, sub, 3);
+        }
+    }
 
 #undef CALC_VERTEX
 #undef COPY_VERTEX
 
-          k = columns * rows;
-          for (j = 0; j < k; j++)
-            gimp_display_shell_draw_quad (tool->drawable,
-                            GDK_DRAWABLE (GTK_WIDGET (shell->canvas)->window),
-                            mask, mask_offx, mask_offy,
-                            x[j], y[j], u[j], v[j]);
-
-        }
-    }
+  k = columns * rows;
+  for (j = 0; j < k; j++)
+    gimp_display_shell_draw_quad (tool->drawable,
+                    GDK_DRAWABLE (GTK_WIDGET (shell->canvas)->window),
+                    mask, mask_offx, mask_offy,
+                    x[j], y[j], u[j], v[j],
+                    opacity);
 }
 
 
 /*  private functions  */
 
+/**
+ * gimp_display_shell_draw_quad:
+ * @texture:   the #GimpDrawable to be previewed
+ * @dest:      the #GdkDrawable for that @texture lives on
+ * @mask:      a #GimpChannel
+ * @opacity:   the opacity of the preview
+ *
+ * Take a quadrilateral, divide it into two triangles, and draw those
+ * with gimp_display_shell_draw_tri().
+ **/
 static void
 gimp_display_shell_draw_quad (GimpDrawable *texture,
                               GdkDrawable  *dest,
@@ -286,62 +337,118 @@
                               gint         *x,
                               gint         *y,
                               gfloat       *u,
-                              gfloat       *v)
+                              gfloat       *v,
+                              guchar        opacity)
 {
-  gint   x2[3], y2[3];
-  gfloat u2[3], v2[3];
+  gint       x2[3], y2[3];
+  gfloat     u2[3], v2[3];
+  gint       minx, maxx, miny, maxy; /* screen bounds of the quad        */
+  gint       dwidth, dheight;        /* dimensions of dest               */
+  GdkPixbuf *area;                   /* quad sized area with dest pixels */
+  gint       c;
+
+  g_return_if_fail(GDK_IS_DRAWABLE (dest));
 
   x2[0] = x[3];  y2[0] = y[3];  u2[0] = u[3];  v2[0] = v[3];
   x2[1] = x[2];  y2[1] = y[2];  u2[1] = u[2];  v2[1] = v[2];
   x2[2] = x[1];  y2[2] = y[1];  u2[2] = u[1];  v2[2] = v[1];
 
-  gimp_display_shell_draw_tri (texture, dest, mask, mask_offx, mask_offy,
-                               x, y, u, v);
-  gimp_display_shell_draw_tri (texture, dest, mask, mask_offx, mask_offy,
-                               x2, y2, u2, v2);
+   /* Allocate a box around the quad to compute preview data into
+    * and fill it with the original window contents.
+    */
+
+  gdk_drawable_get_size (dest, &dwidth, &dheight);
+
+  /* find bounds of quad in order to only grab as much of dest as needed */
+
+  minx = maxx = x[0];
+  miny = maxy = y[0];
+  for (c = 1; c < 4; c++)
+    {
+      if (x[c] < minx) minx = x[c];
+      else if (x[c] > maxx) maxx = x[c];
+
+      if (y[c] < miny) miny = y[c];
+      else if (y[c] > maxy) maxy = y[c];
+    }
+  if (minx < 0) minx = 0;
+  if (miny < 0) miny = 0;
+  if (maxx > dwidth - 1)  maxx=dwidth  - 1;
+  if (maxy > dheight - 1) maxy=dheight - 1;
+
+  area = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                        mask ? TRUE : gimp_drawable_has_alpha (texture),
+                        8, maxx - minx + 1, maxy - miny + 1);
+  g_return_if_fail (area != NULL);
+
+
+  /* get original data from dest in order to potentially take
+   * into account opacity
+   */
+
+  if (opacity != 255)
+    gdk_pixbuf_get_from_drawable (area, dest, NULL, minx, miny,
+                                  0, 0, maxx - minx + 1, maxy - miny + 1);
+
+  gimp_display_shell_draw_tri (texture, dest, area, minx, miny,
+                               mask, mask_offx, mask_offy,
+                               x, y, u, v, opacity);
+  gimp_display_shell_draw_tri (texture, dest, area, minx, miny,
+                               mask, mask_offx, mask_offy,
+                               x2, y2, u2, v2, opacity);
+
+  g_object_unref (area);
 }
 
+/**
+ * gimp_display_shell_draw_tri:
+ * @texture:   the thing being transformed
+ * @dest:      the #GdkDrawable for that @texture lives on
+ * @area:      has prefetched pixel data of dest
+ * @area_offx: x coordinate of area in dest
+ * @area_offy: y coordinate of area in dest
+ * @x:         Array of the three x coords of triangle
+ * @y:         Array of the three y coords of triangle
+ *
+ * This draws a triangle onto dest by breaking it down into pixel rows, and
+ * then calling gimp_display_shell_draw_tri_row() and
+ * gimp_display_shell_draw_tri_row_mask() to do the actual pixel changing.
+ **/
 static void
 gimp_display_shell_draw_tri (GimpDrawable *texture,
                              GdkDrawable  *dest,
+                             GdkPixbuf    *area,
+                             gint          area_offx,
+                             gint          area_offy,
                              GimpChannel  *mask,
                              gint          mask_offx,
                              gint          mask_offy,
                              gint         *x,
                              gint         *y,
                              gfloat       *u, /* texture coords */
-                             gfloat       *v) /* 0.0 ... tex width, height */
+                             gfloat       *v, /* 0.0 ... tex width, height */
+                             guchar        opacity)
 {
-  GdkPixbuf   *row;
   gint         dwidth, dheight;    /* clip boundary */
   gint         j, k;
   gint         ry;
   gint        *l_edge, *r_edge;    /* arrays holding x-coords of edge pixels */
-  gint        *left,   *right;
-  gfloat       dul, dvl, dur, dvr; /* left and right texture coord deltas */
-  gfloat       u_l, v_l, u_r, v_r; /* left and right texture coord pairs */
+  gint        *left,   *right;     /* temp pointers into l_edge and r_edge  */
+  gfloat       dul, dvl, dur, dvr; /* left and right texture coord deltas  */
+  gfloat       u_l, v_l, u_r, v_r; /* left and right texture coord pairs  */
 
-  if (! GIMP_IS_DRAWABLE (texture) ||
-      ! GDK_IS_DRAWABLE (dest))
-    return;
+  g_return_if_fail (GIMP_IS_DRAWABLE (texture));
+  g_return_if_fail (GDK_IS_DRAWABLE (dest));
+  g_return_if_fail (GDK_IS_PIXBUF (area));
 
   g_return_if_fail (x != NULL && y != NULL && u != NULL && v != NULL);
 
-  gdk_drawable_get_size (dest, &dwidth, &dheight);
-
-  if (dwidth > 0 && dheight > 0)
-    row = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
-                          mask ? TRUE : gimp_drawable_has_alpha (texture),
-                          8, dwidth, 1);
-  else
-    return;
-
-  g_return_if_fail (row != NULL);
-
   left = right = NULL;
   dul = dvl = dur = dvr = 0;
   u_l = v_l = u_r = v_r = 0;
 
+  gdk_drawable_get_size (dest, &dwidth, &dheight);
+
   /* sort vertices in order of y-coordinate */
 
   for (j = 0; j < 3; j++)
@@ -383,28 +490,36 @@
       u_r   = u[0];
       v_r   = v[0];
 
-      for (ry = y[0]; ry < y[1]; ry++)
-        {
-          if (ry >= 0 && ry < dheight)
-            {
-              if (mask)
-                gimp_display_shell_draw_tri_row_mask
-                                                (texture, dest, row,
+      if (mask)
+        for (ry = y[0]; ry < y[1]; ry++)
+          {
+            if (ry >= 0 && ry < dheight)
+              gimp_display_shell_draw_tri_row_mask
+                                                (texture, dest,
+                                                 area, area_offx, area_offy,
                                                  mask, mask_offx, mask_offy,
                                                  *left, u_l, v_l,
                                                  *right, u_r, v_r,
-                                                 ry);
-              else
-                gimp_display_shell_draw_tri_row (texture, dest, row,
-                                                 *left, u_l, v_l,
-                                                 *right, u_r, v_r,
-                                                 ry);
-            }
-
-          left++;       right++;
-          u_l += dul;   v_l += dvl;
-          u_r += dur;   v_r += dvr;
-        }
+                                                 ry,
+                                                 opacity);
+            left ++;      right ++;
+            u_l += dul;   v_l += dvl;
+            u_r += dur;   v_r += dvr;
+          }
+      else
+        for (ry = y[0]; ry < y[1]; ry++)
+          {
+            if (ry >= 0 && ry < dheight)
+              gimp_display_shell_draw_tri_row (texture, dest,
+                                               area, area_offx, area_offy,
+                                               *left, u_l, v_l,
+                                               *right, u_r, v_r,
+                                               ry,
+                                               opacity);
+            left ++;      right ++;
+            u_l += dul;   v_l += dvl;
+            u_r += dur;   v_r += dvr;
+          }
     }
 
   if (y[1] != y[2])
@@ -417,51 +532,69 @@
       u_r   = u[1];
       v_r   = v[1];
 
-      for (ry = y[1]; ry < y[2]; ry++)
-        {
-          if (ry >= 0 && ry < dheight)
-            {
-              if (mask)
-                gimp_display_shell_draw_tri_row_mask
-                                                (texture, dest, row,
-                                                 mask, mask_offx, mask_offy,
-                                                 *left,  u_l, v_l,
-                                                 *right, u_r, v_r,
-                                                 ry);
-              else
-                gimp_display_shell_draw_tri_row (texture, dest, row,
-                                                 *left,  u_l, v_l,
-                                                 *right, u_r, v_r,
-                                                 ry);
-            }
-
-          left++;       right++;
-          u_l += dul;   v_l += dvl;
-          u_r += dur;   v_r += dvr;
-        }
+      if (mask)
+        for (ry = y[1]; ry < y[2]; ry++)
+          {
+            if (ry >= 0 && ry < dheight)
+              gimp_display_shell_draw_tri_row_mask
+                                              (texture, dest,
+                                               area, area_offx, area_offy,
+                                               mask, mask_offx, mask_offy,
+                                               *left,  u_l, v_l,
+                                               *right, u_r, v_r,
+                                               ry,
+                                               opacity);
+            left ++;      right ++;
+            u_l += dul;   v_l += dvl;
+            u_r += dur;   v_r += dvr;
+          }
+      else
+        for (ry = y[1]; ry < y[2]; ry++)
+          {
+            if (ry >= 0 && ry < dheight)
+              gimp_display_shell_draw_tri_row (texture, dest,
+                                               area, area_offx, area_offy,
+                                               *left,  u_l, v_l,
+                                               *right, u_r, v_r,
+                                               ry,
+                                               opacity);
+            left ++;      right ++;
+            u_l += dul;   v_l += dvl;
+            u_r += dur;   v_r += dvr;
+          }
     }
 
   g_free (l_edge);
   g_free (r_edge);
-
-  g_object_unref (row);
 }
 
+/**
+ * gimp_display_shell_draw_tri_row:
+ * @texture: the thing being transformed
+ * @dest:    the #GdkDrawable for that @texture lives on
+ * @area:    has prefetched pixel data of dest
+ *
+ * Called from gimp_display_shell_draw_tri(), this draws a single row of a
+ * triangle onto dest when there is not a mask. The run (x1,y) to (x2,y) in
+ * dest corresponds to the run (u1,v1) to (u2,v2) in texture.
+ **/
 static void
 gimp_display_shell_draw_tri_row (GimpDrawable *texture,
                                  GdkDrawable  *dest,
-                                 GdkPixbuf    *row,
+                                 GdkPixbuf    *area,
+                                 gint          area_offx,
+                                 gint          area_offy,
                                  gint          x1,
                                  gfloat        u1,
                                  gfloat        v1,
                                  gint          x2,
                                  gfloat        u2,
                                  gfloat        v2,
-                                 gint          y)
+                                 gint          y,
+                                 guchar        opacity)
 {
-  TileManager  *tiles;
-  guchar       *pptr;
-  guchar        bytes;
+  TileManager  *tiles;     /* used to get the source texture colors   */
+  guchar       *pptr;      /* points into the pixels of a row of area */
   gfloat        u, v;
   gfloat        du, dv;
   gint          dx;
@@ -474,16 +607,13 @@
 
   g_return_if_fail (GIMP_IS_DRAWABLE (texture));
   g_return_if_fail (GDK_IS_DRAWABLE (dest));
-  g_return_if_fail (GDK_IS_PIXBUF (row));
-  g_return_if_fail (gdk_pixbuf_get_bits_per_sample (row) == 8);
-  g_return_if_fail (gdk_pixbuf_get_colorspace (row) == GDK_COLORSPACE_RGB);
-  g_return_if_fail (gdk_pixbuf_get_has_alpha (row) ==
+  g_return_if_fail (GDK_IS_PIXBUF (area));
+  g_return_if_fail (gdk_pixbuf_get_bits_per_sample (area) == 8);
+  g_return_if_fail (gdk_pixbuf_get_colorspace (area) == GDK_COLORSPACE_RGB);
+  g_return_if_fail (gdk_pixbuf_get_has_alpha (area) ==
                     gimp_drawable_has_alpha (texture));
 
-  bytes = gdk_pixbuf_get_n_channels (row);
-  pptr  = gdk_pixbuf_get_pixels (row);
-  tiles = gimp_drawable_get_tiles (texture);
-
+  /* make sure the pixel run goes in the positive direction */
   if (x1 > x2)
     {
       gint   tmp;
@@ -500,123 +630,274 @@
   dv = (v2 - v1) / (x2 - x1);
 
   /* don't calculate unseen pixels */
-  if (x1 < 0)
+  if (x1 < area_offx)
     {
-      u += du * (0 - x1);
-      v += dv * (0 - x1);
-      x1 = 0;
+      u += du * (area_offx - x1);
+      v += dv * (area_offx - x1);
+      x1 = area_offx;
     }
-  else if (x1 > gdk_pixbuf_get_width (row))
+  else if (x1 > area_offx + gdk_pixbuf_get_width (area) - 1)
     {
       return;
     }
 
-  if (x2 < 0)
+  if (x2 < area_offx)
     {
       return;
     }
-  else if (x2 > gdk_pixbuf_get_width (row))
+  else if (x2 > area_offx + gdk_pixbuf_get_width (area) - 1)
     {
-      x2 = gdk_pixbuf_get_width (row);
+      x2 = area_offx + gdk_pixbuf_get_width (area) - 1;
     }
 
   dx = x2 - x1;
+  if (! dx) return;
 
-  if (! dx)
-    return;
+  pptr = (gdk_pixbuf_get_pixels (area)
+          + (y - area_offy) * gdk_pixbuf_get_rowstride (area)
+          + (x1 - area_offx) * gdk_pixbuf_get_n_channels (area));
+
+  tiles = gimp_drawable_get_tiles (texture);
 
   switch (gimp_drawable_type (texture))
     {
     case GIMP_INDEXED_IMAGE:
       cmap = gimp_drawable_get_colormap (texture);
 
-      while (dx--)
-        {
-          read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+      if (opacity == 255)
+        while (dx--)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
 
-          offset = pixel[0] + pixel[0] + pixel[0];
+            offset = pixel[0] + pixel[0] + pixel[0];
 
-          *pptr++ = cmap[offset];
-          *pptr++ = cmap[offset + 1];
-          *pptr++ = cmap[offset + 2];
+            pptr[0] = cmap[offset + 0];
+            pptr[1] = cmap[offset + 1];
+            pptr[2] = cmap[offset + 2];
 
-          u += du;
-          v += dv;
-        }
+            pptr += 3;
+
+            u += du;
+            v += dv;
+          }
+      else
+        while (dx--)
+          {
+            register gulong tmp;
+
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            offset = pixel[0] + pixel[0] + pixel[0];
+
+            pptr[0] = INT_BLEND (pptr[0], cmap[offset + 0], opacity, tmp);
+            pptr[1] = INT_BLEND (pptr[1], cmap[offset + 1], opacity, tmp);
+            pptr[2] = INT_BLEND (pptr[2], cmap[offset + 2], opacity, tmp);
+
+            pptr += 3;
+
+            u += du;
+            v += dv;
+          }
       break;
 
     case GIMP_INDEXEDA_IMAGE:
       cmap = gimp_drawable_get_colormap (texture);
 
-      while (dx--)
-        {
-          read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+      if (opacity == 255)
+        while (dx--)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            offset = pixel[0] + pixel[0] + pixel[0];
+
+            pptr[0] = cmap[offset + 0];
+            pptr[1] = cmap[offset + 1];
+            pptr[2] = cmap[offset + 2];
+            pptr[3] = pixel[1];
 
-          offset = pixel[0] + pixel[0] + pixel[0];
+            pptr += 4;
 
-          *pptr++ = cmap[offset];
-          *pptr++ = cmap[offset + 1];
-          *pptr++ = cmap[offset + 2];
-          *pptr++ = pixel[1];
+            u += du;
+            v += dv;
+          }
+      else
+        while (dx--)
+          {
+            register gulong tmp;
 
-          u += du;
-          v += dv;
-        }
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            offset = pixel[0] + pixel[0] + pixel[0];
+
+            pptr[0] = INT_BLEND (pptr[0], cmap[offset + 0], opacity, tmp);
+            pptr[1] = INT_BLEND (pptr[1], cmap[offset + 1], opacity, tmp);
+            pptr[2] = INT_BLEND (pptr[2], cmap[offset + 2], opacity, tmp);
+            pptr[3] = pixel[1];
+
+            pptr += 4;
+
+            u += du;
+            v += dv;
+          }
       break;
 
     case GIMP_GRAY_IMAGE:
-      while (dx--)
-        {
-          read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+      if (opacity == 255)
+        while (dx--)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            pptr[0] = pixel[0];
+            pptr[1] = pixel[0];
+            pptr[2] = pixel[0];
 
-          *pptr++ = pixel[0];
-          *pptr++ = pixel[0];
-          *pptr++ = pixel[0];
+            pptr += 3;
 
-          u += du;
-          v += dv;
-        }
+            u += du;
+            v += dv;
+          }
+      else
+        while (dx--)
+          {
+            register gulong tmp;
+
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            pptr[0] = INT_BLEND (pptr[0], pixel[0], opacity, tmp);
+            pptr[1] = INT_BLEND (pptr[1], pixel[0], opacity, tmp);
+            pptr[2] = INT_BLEND (pptr[2], pixel[0], opacity, tmp);
+
+            pptr += 3;
+
+            u += du;
+            v += dv;
+          }
       break;
 
     case GIMP_GRAYA_IMAGE:
-      while (dx--)
-        {
-          read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+      if (opacity == 255)
+        while (dx--)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            pptr[0] = pixel[0];
+            pptr[1] = pixel[0];
+            pptr[2] = pixel[0];
+            pptr[3] = pixel[1];
 
-          *pptr++ = pixel[0];
-          *pptr++ = pixel[0];
-          *pptr++ = pixel[0];
-          *pptr++ = pixel[1];
+            pptr += 4;
 
-          u += du;
-          v += dv;
-        }
+            u += du;
+            v += dv;
+          }
+      else
+        while (dx--)
+          {
+            register gulong tmp;
+
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            pptr[0] = INT_BLEND (pptr[0], pixel[0], opacity, tmp);
+            pptr[1] = INT_BLEND (pptr[1], pixel[0], opacity, tmp);
+            pptr[2] = INT_BLEND (pptr[2], pixel[0], opacity, tmp);
+            pptr[3] = pixel[1];
+
+            pptr += 4;
+
+            u += du;
+            v += dv;
+          }
       break;
 
     case GIMP_RGB_IMAGE:
+      if (opacity == 255)
+        while (dx--)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            pptr[0] = pixel[0];
+            pptr[1] = pixel[1];
+            pptr[2] = pixel[2];
+
+            pptr += 3;
+
+            u += du;
+            v += dv;
+          }
+      else
+        while (dx--)
+          {
+            register gulong tmp;
+
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            pptr[0] = INT_BLEND (pptr[0], pixel[0], opacity, tmp);
+            pptr[1] = INT_BLEND (pptr[1], pixel[1], opacity, tmp);
+            pptr[2] = INT_BLEND (pptr[2], pixel[2], opacity, tmp);
+
+            pptr += 3;
+
+            u += du;
+            v += dv;
+          }
+      break;
+
     case GIMP_RGBA_IMAGE:
-      while (dx--)
-        {
-          read_pixel_data_1 (tiles, (gint) u, (gint) v, pptr);
+      if (opacity == 255)
+        while (dx--)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            pptr[0] = pixel[0];
+            pptr[1] = pixel[1];
+            pptr[2] = pixel[2];
+            pptr[3] = pixel[3];
 
-          pptr += bytes;
-          u += du;
-          v += dv;
-        }
+            pptr += 4;
+
+            u += du;
+            v += dv;
+          }
+      else
+        while (dx--)
+          {
+            register gulong tmp;
+
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            pptr[0] = INT_BLEND (pptr[0], pixel[0], opacity, tmp);
+            pptr[1] = INT_BLEND (pptr[1], pixel[1], opacity, tmp);
+            pptr[2] = INT_BLEND (pptr[2], pixel[2], opacity, tmp);
+            pptr[3] = pixel[3];
+
+            pptr += 4;
+
+            u += du;
+            v += dv;
+          }
       break;
 
     default:
       return;
     }
 
-  gdk_draw_pixbuf (dest, NULL, row, 0, 0, x1, y, x2 - x1, 1,
+  gdk_draw_pixbuf (dest, NULL, area, x1 - area_offx, y - area_offy,
+                   x1, y, x2 - x1, 1,
                    GDK_RGB_DITHER_NONE, 0, 0);
 }
 
+/**
+ * gimp_display_shell_draw_tri_row_mask:
+ *
+ * Called from gimp_display_shell_draw_tri(), this draws a single row of a
+ * triangle onto dest, when there is a mask.
+ **/
 static void
 gimp_display_shell_draw_tri_row_mask (GimpDrawable *texture,
                                       GdkDrawable  *dest,
-                                      GdkPixbuf    *row,
+                                      GdkPixbuf    *area,
+                                      gint          area_offx,
+                                      gint          area_offy,
                                       GimpChannel  *mask,
                                       gint          mask_offx,
                                       gint          mask_offy,
@@ -626,11 +907,12 @@
                                       gint          x2,
                                       gfloat        u2,
                                       gfloat        v2,
-                                      gint          y)
+                                      gint          y,
+                                      guchar        opacity)
 {
-  TileManager  *tiles, *masktiles;
-  guchar       *pptr;
-  guchar        bytes, alpha;
+
+  TileManager  *tiles, *masktiles; /* used to get the source texture colors */
+  guchar       *pptr;              /* points into the pixels of area        */
   gfloat        u, v;
   gfloat        mu, mv;
   gfloat        du, dv;
@@ -645,16 +927,11 @@
   g_return_if_fail (GIMP_IS_DRAWABLE (texture));
   g_return_if_fail (GIMP_IS_CHANNEL (mask));
   g_return_if_fail (GDK_IS_DRAWABLE (dest));
-  g_return_if_fail (GDK_IS_PIXBUF (row));
-  g_return_if_fail (gdk_pixbuf_get_bits_per_sample (row) == 8);
-  g_return_if_fail (gdk_pixbuf_get_colorspace (row) == GDK_COLORSPACE_RGB);
-
-  bytes     = gdk_pixbuf_get_n_channels (row);
-  alpha     = bytes - 1;
-  pptr      = gdk_pixbuf_get_pixels (row);
-  tiles     = gimp_drawable_get_tiles (texture);
-  masktiles = gimp_drawable_get_tiles (GIMP_DRAWABLE (mask));
+  g_return_if_fail (GDK_IS_PIXBUF (area));
+  g_return_if_fail (gdk_pixbuf_get_bits_per_sample (area) == 8);
+  g_return_if_fail (gdk_pixbuf_get_colorspace (area) == GDK_COLORSPACE_RGB);
 
+  /* make sure the pixel run goes in the positive direction */
   if (x1 > x2)
     {
       gint   tmp;
@@ -671,154 +948,315 @@
   dv = (v2 - v1) / (x2 - x1);
 
   /* don't calculate unseen pixels */
-  if (x1 < 0)
+  if (x1 < area_offx)
     {
-      u += du * (0 - x1);
-      v += dv * (0 - x1);
-      x1 = 0;
+      u += du * (area_offx - x1);
+      v += dv * (area_offx - x1);
+      x1 = area_offx;
     }
-  else if (x1 > gdk_pixbuf_get_width (row))
+  else if (x1 > area_offx + gdk_pixbuf_get_width (area) - 1)
     {
       return;
     }
 
-  if (x2 < 0)
+  if (x2 < area_offx)
     {
       return;
     }
-  else if (x2 > gdk_pixbuf_get_width (row))
+  else if (x2 > area_offx + gdk_pixbuf_get_width (area) - 1)
     {
-      x2 = gdk_pixbuf_get_width (row);
+      x2 = area_offx + gdk_pixbuf_get_width (area) - 1;
     }
 
   dx = x2 - x1;
-
   if (! dx)
     return;
 
   mu = u + mask_offx;
   mv = v + mask_offy;
 
+  pptr = (gdk_pixbuf_get_pixels (area)
+          + (y - area_offy) * gdk_pixbuf_get_rowstride (area)
+          + (x1 - area_offx) * gdk_pixbuf_get_n_channels (area));
+
+  tiles     = gimp_drawable_get_tiles (texture);
+  masktiles = gimp_drawable_get_tiles (GIMP_DRAWABLE (mask));
+
   switch (gimp_drawable_type (texture))
     {
     case GIMP_INDEXED_IMAGE:
       cmap = gimp_drawable_get_colormap (texture);
 
-      while (dx--)
-        {
-          read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
-          read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, pptr + alpha);
-
-          offset = pixel[0] + pixel[0] + pixel[0];
-
-          *pptr++ = cmap[offset];
-          *pptr++ = cmap[offset + 1];
-          *pptr++ = cmap[offset + 2];
-
-          pptr ++;
-          u += du;
-          v += dv;
-          mu += du;
-          mv += dv;
-        }
+      if (opacity == 255)
+        while (dx--)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, pptr + 3);
+
+            offset = pixel[0] + pixel[0] + pixel[0];
+
+            pptr[0] = cmap[offset + 0];
+            pptr[1] = cmap[offset + 1];
+            pptr[2] = cmap[offset + 2];
+
+            pptr += 4;
+
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
+      else
+        while (dx--)
+          {
+            register gulong tmp;
+
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, pptr + 3);
+
+            offset = pixel[0] + pixel[0] + pixel[0];
+
+            pptr[0] = INT_BLEND (pptr[0], cmap[offset + 0], opacity, tmp);
+            pptr[1] = INT_BLEND (pptr[1], cmap[offset + 1], opacity, tmp);
+            pptr[2] = INT_BLEND (pptr[2], cmap[offset + 2], opacity, tmp);
+
+            pptr += 4;
+
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
       break;
 
     case GIMP_INDEXEDA_IMAGE:
       cmap = gimp_drawable_get_colormap (texture);
 
-      while (dx--)
-        {
-          read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
-          read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, &maskval);
-
-          offset = pixel[0] + pixel[0] + pixel[0];
-
-          *pptr++ = cmap[offset];
-          *pptr++ = cmap[offset + 1];
-          *pptr++ = cmap[offset + 2];
-          *pptr++ = ((gint) maskval * pixel[1]) >> 8;
-
-          u += du;
-          v += dv;
-          mu += du;
-          mv += dv;
-        }
+      if (opacity == 255)
+        while (dx--)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, &maskval);
+
+            offset = pixel[0] + pixel[0] + pixel[0];
+
+            pptr[0] = cmap[offset + 0];
+            pptr[1] = cmap[offset + 1];
+            pptr[2] = cmap[offset + 2];
+            pptr[3] = ((gint) maskval * pixel[1]) >> 8;
+
+            pptr += 4;
+
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
+      else
+        while (dx--)
+          {
+            register gulong tmp;
+
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, &maskval);
+
+            offset = pixel[0] + pixel[0] + pixel[0];
+
+            pptr[0] = INT_BLEND (pptr[0], cmap[offset + 0], opacity, tmp);
+            pptr[1] = INT_BLEND (pptr[1], cmap[offset + 1], opacity, tmp);
+            pptr[2] = INT_BLEND (pptr[2], cmap[offset + 2], opacity, tmp);
+            pptr[3] = INT_MULT (maskval, pixel[1], tmp);
+
+            pptr += 4;
+
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
       break;
 
     case GIMP_GRAY_IMAGE:
-      while (dx--)
-        {
-          read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
-          read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, pptr + alpha);
-
-          *pptr++ = pixel[0];
-          *pptr++ = pixel[0];
-          *pptr++ = pixel[0];
-
-          pptr ++;
-          u += du;
-          v += dv;
-          mu += du;
-          mv += dv;
-        }
+      if (opacity == 255)
+        while (dx--)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, pptr + 3);
+
+            pptr[0] = pixel[0];
+            pptr[1] = pixel[0];
+            pptr[2] = pixel[0];
+
+            pptr += 4;
+
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
+      else
+        while (dx--)
+          {
+            register gulong tmp;
+
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, pptr + 3);
+
+            pptr[0] = INT_BLEND (pptr[0], pixel[0], opacity, tmp);
+            pptr[1] = INT_BLEND (pptr[1], pixel[0], opacity, tmp);
+            pptr[2] = INT_BLEND (pptr[2], pixel[0], opacity, tmp);
+
+            pptr += 4;
+
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
       break;
 
     case GIMP_GRAYA_IMAGE:
-      while (dx--)
-        {
-          read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
-          read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, &maskval);
-
-          *pptr++ = pixel[0];
-          *pptr++ = pixel[0];
-          *pptr++ = pixel[0];
-          *pptr++ = ((gint) maskval * pixel[1]) >> 8;
-
-          u += du;
-          v += dv;
-          mu += du;
-          mv += dv;
-        }
+      if (opacity == 255)
+        while (dx--)
+          {
+            register gulong tmp;
+
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, &maskval);
+
+            pptr[0] = pixel[0];
+            pptr[1] = pixel[0];
+            pptr[2] = pixel[0];
+            pptr[3] = INT_MULT (maskval, pixel[1], tmp);
+
+            pptr += 4;
+
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
+      else
+        while (dx--)
+          {
+            register gulong tmp;
+
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, &maskval);
+
+            pptr[0] = INT_BLEND (pptr[0], pixel[0], opacity, tmp);
+            pptr[1] = INT_BLEND (pptr[1], pixel[0], opacity, tmp);
+            pptr[2] = INT_BLEND (pptr[2], pixel[0], opacity, tmp);
+            pptr[3] = INT_MULT (maskval, pixel[1], tmp);
+
+            pptr += 4;
+
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
       break;
 
     case GIMP_RGB_IMAGE:
-      while (dx--)
-        {
-          read_pixel_data_1 (tiles, (gint) u, (gint) v, pptr);
-          read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, pptr + alpha);
-
-          pptr += bytes;
-          u += du;
-          v += dv;
-          mu += du;
-          mv += dv;
-        }
+      if (opacity == 255)
+        while (dx--)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, pptr + 3);
+
+            pptr[0] = pixel[0];
+            pptr[1] = pixel[1];
+            pptr[2] = pixel[2];
+
+            pptr += 4;
+
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
+      else
+        while (dx--)
+          {
+            register gulong tmp;
+
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, pptr + 3);
+
+            pptr[0] = INT_BLEND (pptr[0], pixel[0], opacity, tmp);
+            pptr[1] = INT_BLEND (pptr[1], pixel[1], opacity, tmp);
+            pptr[2] = INT_BLEND (pptr[2], pixel[2], opacity, tmp);
+
+            pptr += 4;
+
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
       break;
 
     case GIMP_RGBA_IMAGE:
-      while (dx--)
-        {
-          read_pixel_data_1 (tiles, (gint) u, (gint) v, pptr);
-          read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, &maskval);
-
-          pptr[alpha] = ((gint) maskval * pptr[alpha]) >> 8;
-
-          pptr += bytes;
-          u += du;
-          v += dv;
-          mu += du;
-          mv += dv;
-        }
+      if (opacity == 255)
+        while (dx--)
+          {
+            register gulong tmp;
+
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, &maskval);
+
+            pptr[0] = pixel[0];
+            pptr[1] = pixel[1];
+            pptr[2] = pixel[2];
+            pptr[3] = INT_MULT (maskval, pixel[3], tmp);
+
+            pptr += 4;
+
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
+      else
+        while (dx--)
+          {
+            register gulong tmp;
+
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, &maskval);
+
+            pptr[0] = INT_BLEND (pptr[0], pixel[0], opacity, tmp);
+            pptr[1] = INT_BLEND (pptr[1], pixel[1], opacity, tmp);
+            pptr[2] = INT_BLEND (pptr[2], pixel[2], opacity, tmp);
+            pptr[3] = INT_MULT (maskval, pixel[3], tmp);
+
+            pptr += 4;
+
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
       break;
 
     default:
       return;
     }
 
-  gdk_draw_pixbuf (dest, NULL, row, 0, 0, x1, y, x2 - x1, 1,
+  gdk_draw_pixbuf (dest, NULL, area, x1 - area_offx, y - area_offy,
+                   x1, y, x2 - x1, 1,
                    GDK_RGB_DITHER_NONE, 0, 0);
 }
 
+/**
+ * gimp_display_shell_trace_tri_edge:
+ * @dest: x coordinates are placed in this array
+ *
+ * Find the x coordinates for a line that runs from (x1,y1) to (x2,y2),
+ * corresponding to the y coordinates y1 to y2-1. So
+ * dest must be large enough to hold y2-y1 values.
+ **/
 static void
 gimp_display_shell_trace_tri_edge (gint *dest,
                                    gint  x1,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]