gimp r25033 - in branches/weskaggs: . app/display app/tools



Author: weskaggs
Date: Tue Mar  4 19:17:18 2008
New Revision: 25033
URL: http://svn.gnome.org/viewvc/gimp?rev=25033&view=rev

Log:
Bill Skaggs  <weskaggs primate ucdavis edu>

	* app/tools/gimptransformtool.[ch]
	* app/tools/gimptransformoptions.[ch]
	* app/display/gimpdisplayshell-preview.c: apply patch
	from Tom Lechner (comment #35 in bug #167926) to allow
	tranlucency in transform tool previews, for testing.


Modified:
   branches/weskaggs/ChangeLog
   branches/weskaggs/app/display/gimpdisplayshell-preview.c
   branches/weskaggs/app/tools/gimptransformoptions.c
   branches/weskaggs/app/tools/gimptransformoptions.h
   branches/weskaggs/app/tools/gimptransformtool.c
   branches/weskaggs/app/tools/gimptransformtool.h

Modified: branches/weskaggs/app/display/gimpdisplayshell-preview.c
==============================================================================
--- branches/weskaggs/app/display/gimpdisplayshell-preview.c	(original)
+++ branches/weskaggs/app/display/gimpdisplayshell-preview.c	Tue Mar  4 19:17:18 2008
@@ -28,10 +28,12 @@
 #include "core/gimpimage.h"
 #include "core/gimpdrawable.h"
 #include "core/gimpchannel.h"
+#include "core/gimptoolinfo.h"
 
 #include "base/tile-manager.h"
 
 #include "tools/gimpperspectivetool.h"
+#include "tools/gimptransformoptions.h"
 #include "tools/gimptransformtool.h"
 #include "tools/tool_manager.h"
 
@@ -55,29 +57,39 @@
                                                       gint         *x,
                                                       gint         *y,
                                                       gfloat       *u,
-                                                      gfloat       *v);
+                                                      gfloat       *v,
+                                                      gint         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,
+                                                      gint         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,
+                                                      gint          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 +99,8 @@
                                                       gint          x2,
                                                       gfloat        u2,
                                                       gfloat        v2,
-                                                      gint          y);
+                                                      gint          y,
+                                                      gint          opacity);
 static void    gimp_display_shell_trace_tri_edge     (gint         *dest,
                                                       gint          x1,
                                                       gint          y1,
@@ -96,187 +109,224 @@
 
 /*  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)
 {
-  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;
-
-      tool = tool_manager_get_active (shell->display->image->gimp);
-
-      if (! GIMP_IS_TRANSFORM_TOOL (tool) ||
-          ! GIMP_IS_DRAWABLE (tool->drawable))
-        return;
+  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];
+  gint         preview_opacity;
 
-      tr_tool = GIMP_TRANSFORM_TOOL (tool);
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
 
-      if (! tr_tool->use_grid)
-        return;
+  if (! gimp_display_shell_get_show_transform (shell) || ! shell->canvas)
+    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));
+  tool = tool_manager_get_active (shell->display->image->gimp);
 
-      /* only draw convex polygons */
+  if (! GIMP_IS_TRANSFORM_TOOL (tool) ||
+      ! GIMP_IS_DRAWABLE (tool->drawable))
+    return;
 
-      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);
+  tr_tool = GIMP_TRANSFORM_TOOL (tool);
 
-              gimp_item_offsets (GIMP_ITEM (tool->drawable),
-                                 &mask_offx, &mask_offy);
-            }
+  if (! tr_tool->use_grid)
+    return;
 
-          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;
-            }
+  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 */
+
+  if (! ((z1 * z2 > 0) && (z3 * z4 > 0))) return;
+
+  preview_opacity = 
+      GIMP_TRANSFORM_OPTIONS (tool->tool_info->tool_options)
+        ->preview_opacity * 255 / 100;
+  
+  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);
+
+      gimp_item_offsets (GIMP_ITEM (tool->drawable),
+                         &mask_offx, &mask_offy);
+    }
+
+  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);
+  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);
+  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; \
+  { \
+    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))); \
+    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_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; \
+    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))); \
-          }
+    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],
+                    preview_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 +336,118 @@
                               gint         *x,
                               gint         *y,
                               gfloat       *u,
-                              gfloat       *v)
+                              gfloat       *v,
+                              gint         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 */
+                             gint         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 +489,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 +531,70 @@
       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,
+                                 gint          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 */
+  guchar        bytes;     /* the number of channels of area          */
   gfloat        u, v;
   gfloat        du, dv;
   gint          dx;
@@ -474,16 +607,17 @@
 
   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);
+  bytes = gdk_pixbuf_get_n_channels (area);
+  pptr  = gdk_pixbuf_get_pixels (area);
   tiles = gimp_drawable_get_tiles (texture);
 
+  /* make sure the pixel run goes in the positive direction */
   if (x1 > x2)
     {
       gint   tmp;
@@ -500,123 +634,244 @@
   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;
+  /* set pptr to the proper position in area */
+  pptr += (y - area_offy) * gdk_pixbuf_get_rowstride(area) 
+          + (x1 - area_offx)*bytes;
 
   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];
+
+            *pptr++ = cmap[offset];
+            *pptr++ = cmap[offset + 1];
+            *pptr++ = cmap[offset + 2];
 
-          offset = pixel[0] + pixel[0] + pixel[0];
-
-          *pptr++ = cmap[offset];
-          *pptr++ = cmap[offset + 1];
-          *pptr++ = cmap[offset + 2];
+            u += du;
+            v += dv;
+          }
+      else 
+        while (dx --)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            offset = pixel[0] + pixel[0] + pixel[0];
+
+            pptr[0] = (pptr[0] * (255-opacity) + cmap[offset  ] * opacity)>>8;
+            pptr[1] = (pptr[1] * (255-opacity) + cmap[offset+1] * opacity)>>8;
+            pptr[2] = (pptr[2] * (255-opacity) + cmap[offset+2] * opacity)>>8;
+            pptr += bytes;
 
-          u += du;
-          v += dv;
-        }
+            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);
-
-          offset = pixel[0] + pixel[0] + pixel[0];
+      if (opacity == 255)
+        while (dx --)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            offset = pixel[0] + pixel[0] + pixel[0];
+
+            *pptr++ = cmap[offset];
+            *pptr++ = cmap[offset + 1];
+            *pptr++ = cmap[offset + 2];
+            *pptr++ = pixel[1];
 
-          *pptr++ = cmap[offset];
-          *pptr++ = cmap[offset + 1];
-          *pptr++ = cmap[offset + 2];
-          *pptr++ = pixel[1];
+            u += du;
+            v += dv;
+          }
+      else 
+        while (dx --)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            offset = pixel[0] + pixel[0] + pixel[0];
+
+            pptr[0] = (pptr[0] * (255-opacity) + cmap[offset  ] * opacity)>>8;
+            pptr[1] = (pptr[1] * (255-opacity) + cmap[offset+1] * opacity)>>8;
+            pptr[2] = (pptr[2] * (255-opacity) + cmap[offset+2] * opacity)>>8;
+            pptr[3] = pixel[1];
+            pptr += bytes;
 
-          u += du;
-          v += dv;
-        }
+            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++ = pixel[0];
+            *pptr++ = pixel[0];
+            *pptr++ = pixel[0];
 
-          *pptr++ = pixel[0];
-          *pptr++ = pixel[0];
-          *pptr++ = pixel[0];
+            u += du;
+            v += dv;
+          }
+      else 
+        while (dx --)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            pptr[0] = (pptr[0] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr[1] = (pptr[1] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr[2] = (pptr[2] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr += bytes;
 
-          u += du;
-          v += dv;
-        }
+            u += du;
+            v += dv;
+          }
       break;
 
     case GIMP_GRAYA_IMAGE:
-      while (dx--)
-        {
-          read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
-
-          *pptr++ = pixel[0];
-          *pptr++ = pixel[0];
-          *pptr++ = pixel[0];
-          *pptr++ = pixel[1];
-
-          u += du;
-          v += dv;
-        }
+      if (opacity == 255)
+        while (dx --)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            *pptr++ = pixel[0];
+            *pptr++ = pixel[0];
+            *pptr++ = pixel[0];
+            *pptr++ = pixel[1];
+              
+            u += du;
+            v += dv;
+          }
+      else 
+        while (dx --)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            pptr[0] = (pptr[0] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr[1] = (pptr[1] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr[2] = (pptr[2] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr[3] = pixel[1];
+            pptr += bytes;
+              
+            u += du;
+            v += dv;
+          }
       break;
 
     case GIMP_RGB_IMAGE:
-    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 += bytes;
+            u += du;
+            v += dv;
+          }
+      else 
+        while (dx --)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            pptr[0] = (pptr[0] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr[1] = (pptr[1] * (255-opacity) + pixel[1] * opacity) >> 8;
+            pptr[2] = (pptr[2] * (255-opacity) + pixel[2] * opacity) >> 8;
+          
+            pptr += bytes;
+            u += du;
+            v += dv;
+          }
+      break;
 
-          pptr += bytes;
-          u += du;
-          v += dv;
-        }
+    case GIMP_RGBA_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] = pixel[3];
+          
+            pptr += bytes;
+            u += du;
+            v += dv;
+          }
+      else 
+        while (dx --)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+            pptr[0] = (pptr[0] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr[1] = (pptr[1] * (255-opacity) + pixel[1] * opacity) >> 8;
+            pptr[2] = (pptr[2] * (255-opacity) + pixel[2] * opacity) >> 8;
+            pptr[3] = pixel[3];
+          
+            pptr += bytes;
+            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 +881,13 @@
                                       gint          x2,
                                       gfloat        u2,
                                       gfloat        v2,
-                                      gint          y)
+                                      gint          y,
+                                      gint          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        */
+  guchar        bytes, alpha;      /* channels in row, channel of alpha     */
   gfloat        u, v;
   gfloat        mu, mv;
   gfloat        du, dv;
@@ -645,16 +902,18 @@
   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);
+  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);
 
-  bytes     = gdk_pixbuf_get_n_channels (row);
+  bytes     = gdk_pixbuf_get_n_channels (area);
   alpha     = bytes - 1;
-  pptr      = gdk_pixbuf_get_pixels (row);
+  pptr      = gdk_pixbuf_get_pixels (area);
   tiles     = gimp_drawable_get_tiles (texture);
   masktiles = gimp_drawable_get_tiles (GIMP_DRAWABLE (mask));
 
+
+  /* make sure the pixel run goes in the positive direction */ 
   if (x1 > x2)
     {
       gint   tmp;
@@ -671,154 +930,285 @@
   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)
+  if (! dx) 
     return;
 
   mu = u + mask_offx;
   mv = v + mask_offy;
 
+  /* set pptr to the proper position in area */
+  pptr += (y - area_offy) * gdk_pixbuf_get_rowstride(area) 
+          + (x1 - area_offx) * bytes;
+  
   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 + 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;
+          }
+      else 
+        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[0] = (pptr[0] * (255-opacity) + cmap[offset] * opacity) >> 8;
+            pptr[1] = (pptr[1] * (255-opacity) + cmap[offset+1] * opacity)>>8;
+            pptr[2] = (pptr[2] * (255-opacity) + cmap[offset+2] * opacity)>>8;
+            pptr += 3;
+
+            pptr ++;
+            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++ = cmap[offset];
+            *pptr++ = cmap[offset + 1];
+            *pptr++ = cmap[offset + 2];
+
+            *pptr++ = ((gint) maskval * pixel[1]) >> 8;
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
+      else 
+        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] = (pptr[0] * (255-opacity) + cmap[offset]   * opacity)>>8;
+            pptr[1] = (pptr[1] * (255-opacity) + cmap[offset+1] * opacity)>>8;
+            pptr[2] = (pptr[2] * (255-opacity) + cmap[offset+2] * opacity)>>8;
+            pptr += 3;
+  
+            *pptr++ = ((gint) maskval * pixel[1]) >> 8;
+            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 + alpha);
+  
+            *pptr++ = pixel[0];
+            *pptr++ = pixel[0];
+            *pptr++ = pixel[0];
+            pptr ++;
+  
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
+      else 
+        while (dx --)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, pptr + alpha);
+  
+            pptr[0] = (pptr[0] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr[1] = (pptr[1] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr[2] = (pptr[2] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr += bytes;
+  
+            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 --)
+          {
+            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;
+          }
+      else 
+        while (dx --)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, &maskval);
+  
+            pptr[0] = (pptr[0] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr[1] = (pptr[1] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr[2] = (pptr[2] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr[3] = ((gint) maskval * pixel[1]) >> 8;
+            pptr += bytes;
+  
+            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, &maskval);
+  
+            pptr[0] = pixel[0];
+            pptr[1] = pixel[1];
+            pptr[2] = pixel[2];
+            pptr[alpha] = maskval;
+  
+            pptr += bytes;
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
+      else 
+        while (dx --)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, &maskval);
+  
+            pptr[0] = (pptr[0] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr[1] = (pptr[1] * (255-opacity) + pixel[1] * opacity) >> 8;
+            pptr[2] = (pptr[2] * (255-opacity) + pixel[2] * opacity) >> 8;
+            pptr[alpha] = maskval;
+  
+            pptr += bytes;
+            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 --)
+          {
+            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[alpha] = ((gint) maskval * pixel[alpha]) >> 8;
+              
+            pptr += bytes;
+            u += du;
+            v += dv;
+            mu += du;
+            mv += dv;
+          }
+      else 
+        while (dx --)
+          {
+            read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+            read_pixel_data_1 (masktiles, (gint) mu, (gint) mv, &maskval);
+  
+            pptr[0] = (pptr[0] * (255-opacity) + pixel[0] * opacity) >> 8;
+            pptr[1] = (pptr[1] * (255-opacity) + pixel[1] * opacity) >> 8;
+            pptr[2] = (pptr[2] * (255-opacity) + pixel[2] * opacity) >> 8;
+            pptr[alpha] = ((gint) maskval * pixel[alpha]) >> 8;
+              
+            pptr += bytes;
+            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,

Modified: branches/weskaggs/app/tools/gimptransformoptions.c
==============================================================================
--- branches/weskaggs/app/tools/gimptransformoptions.c	(original)
+++ branches/weskaggs/app/tools/gimptransformoptions.c	Tue Mar  4 19:17:18 2008
@@ -50,7 +50,8 @@
   PROP_PREVIEW_TYPE,
   PROP_GRID_TYPE,
   PROP_GRID_SIZE,
-  PROP_CONSTRAIN
+  PROP_CONSTRAIN,
+  PROP_PREVIEW_OPACITY
 };
 
 
@@ -69,6 +70,10 @@
                                                      GParamSpec           *pspec,
                                                      GtkWidget            *density_box);
 
+static void   gimp_transform_options_preview_opacity_notify (GimpTransformOptions *options,
+                                                     GParamSpec           *pspec,
+                                                     GtkWidget            *density_box);
+
 
 G_DEFINE_TYPE (GimpTransformOptions, gimp_transform_options,
                GIMP_TYPE_TOOL_OPTIONS)
@@ -125,6 +130,10 @@
                                     "constrain", NULL,
                                     FALSE,
                                     GIMP_PARAM_STATIC_STRINGS);
+  GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_PREVIEW_OPACITY,
+                                "preview-opacity", NULL,
+                                0, 100, 100,
+                                GIMP_PARAM_STATIC_STRINGS);
 }
 
 static void
@@ -167,6 +176,9 @@
     case PROP_CONSTRAIN:
       options->constrain = g_value_get_boolean (value);
       break;
+    case PROP_PREVIEW_OPACITY:
+      options->preview_opacity = g_value_get_int (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -207,6 +219,9 @@
     case PROP_CONSTRAIN:
       g_value_set_boolean (value, options->constrain);
       break;
+    case PROP_PREVIEW_OPACITY:
+      g_value_set_int (value, options->preview_opacity);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -228,6 +243,12 @@
   GIMP_TOOL_OPTIONS_CLASS (parent_class)->reset (tool_options);
 }
 
+/** 
+ * gimp_transform_options_gui:
+ * @tool_options: a #GimpToolOptions
+ *
+ * Build the Transform Tool Options dialog.
+ **/
 GtkWidget *
 gimp_transform_options_gui (GimpToolOptions *tool_options)
 {
@@ -311,7 +332,17 @@
   gtk_box_pack_start (GTK_BOX (button), table, FALSE, FALSE, 0);
   gtk_widget_show (table);
 
-  gtk_widget_set_sensitive (button,
+  gtk_widget_set_sensitive (combo,
+                            options->preview_type ==
+                            GIMP_TRANSFORM_PREVIEW_TYPE_GRID ||
+                            options->preview_type ==
+                            GIMP_TRANSFORM_PREVIEW_TYPE_IMAGE_GRID);
+  
+  g_signal_connect (config, "notify::preview-type",
+                    G_CALLBACK (gimp_transform_options_preview_notify),
+                    combo);
+  
+  gtk_widget_set_sensitive (table,
                             options->preview_type ==
                             GIMP_TRANSFORM_PREVIEW_TYPE_GRID ||
                             options->preview_type ==
@@ -319,7 +350,7 @@
 
   g_signal_connect (config, "notify::preview-type",
                     G_CALLBACK (gimp_transform_options_preview_notify),
-                    button);
+                    table);
 
   gimp_prop_scale_entry_new (config, "grid-size",
                              GTK_TABLE (table), 0, 0,
@@ -327,6 +358,29 @@
                              1.0, 8.0, 0,
                              FALSE, 0.0, 0.0);
 
+  /*  the preview opacity scale  */
+  table = gtk_table_new (1, 3, FALSE);
+  gtk_table_set_col_spacing (GTK_TABLE (table), 1, 2);
+  gtk_box_pack_start (GTK_BOX (button), table, FALSE, FALSE, 0);
+  gtk_widget_show (table);
+
+  gtk_widget_set_sensitive (table,
+                            options->preview_type ==
+                            GIMP_TRANSFORM_PREVIEW_TYPE_IMAGE ||
+                            options->preview_type ==
+                            GIMP_TRANSFORM_PREVIEW_TYPE_IMAGE_GRID);
+
+  g_signal_connect (config, "notify::preview-type",
+                    G_CALLBACK (gimp_transform_options_preview_opacity_notify),
+                    table);
+
+  gimp_prop_scale_entry_new (config, "preview-opacity",
+                             GTK_TABLE (table), 0, 0,
+                             _("Opacity:"),
+                             1.0, 8.0, 0,
+                             FALSE, 0.0, 0.0);
+
+
   if (tool_options->tool_info->tool_type == GIMP_TYPE_ROTATE_TOOL)
     {
       constrain = (_("15 degrees  (%s)"));
@@ -365,3 +419,16 @@
                             options->preview_type ==
                             GIMP_TRANSFORM_PREVIEW_TYPE_IMAGE_GRID);
 }
+
+static void
+gimp_transform_options_preview_opacity_notify (GimpTransformOptions *options,
+                                               GParamSpec           *pspec,
+                                               GtkWidget            *density_box)
+{
+  gtk_widget_set_sensitive (density_box,
+                            options->preview_type ==
+                            GIMP_TRANSFORM_PREVIEW_TYPE_IMAGE ||
+                            options->preview_type ==
+                            GIMP_TRANSFORM_PREVIEW_TYPE_IMAGE_GRID);
+}
+

Modified: branches/weskaggs/app/tools/gimptransformoptions.h
==============================================================================
--- branches/weskaggs/app/tools/gimptransformoptions.h	(original)
+++ branches/weskaggs/app/tools/gimptransformoptions.h	Tue Mar  4 19:17:18 2008
@@ -47,6 +47,7 @@
   GimpTransformGridType     grid_type;
   gint                      grid_size;
   gboolean                  constrain;
+  gint                      preview_opacity;
 };
 
 

Modified: branches/weskaggs/app/tools/gimptransformtool.c
==============================================================================
--- branches/weskaggs/app/tools/gimptransformtool.c	(original)
+++ branches/weskaggs/app/tools/gimptransformtool.c	Tue Mar  4 19:17:18 2008
@@ -280,6 +280,10 @@
       g_signal_connect_object (options, "notify::grid-size",
                                G_CALLBACK (gimp_transform_tool_notify_preview),
                                tr_tool, 0);
+      g_signal_connect_object (tool->tool_info->tool_options,
+                               "notify::preview-opacity",
+                               G_CALLBACK (gimp_transform_tool_notify_preview),
+                               tr_tool, 0);
     }
 
   g_signal_connect_object (options, "notify::constrain",
@@ -1360,7 +1364,7 @@
   static gint       last_h = 0;
 
   GimpDisplayShell *shell;
-  gdouble           dx [4], dy [4];
+  gdouble           dx[4], dy[4];
   gint              area_x, area_y, area_w, area_h;
   gint              i;
 
@@ -1388,20 +1392,20 @@
                                      dx + 3, dy + 3, FALSE);
 
   /* find bounding box around preview */
-  area_x = area_w = (gint) dx [0];
-  area_y = area_h = (gint) dy [0];
+  area_x = area_w = (gint) dx[0];
+  area_y = area_h = (gint) dy[0];
 
   for (i = 1; i < 4; i++)
     {
-      if (dx [i] < area_x)
-        area_x = (gint) dx [i];
-      else if (dx [i] > area_w)
-        area_w = (gint) dx [i];
-
-      if (dy [i] < area_y)
-        area_y = (gint) dy [i];
-      else if (dy [i] > area_h)
-        area_h = (gint) dy [i];
+      if (dx[i] < area_x)
+        area_x = (gint) dx[i];
+      else if (dx[i] > area_w)
+        area_w = (gint) dx[i];
+
+      if (dy[i] < area_y)
+        area_y = (gint) dy[i];
+      else if (dy[i] > area_h)
+        area_h = (gint) dy[i];
     }
 
   area_w -= area_x;

Modified: branches/weskaggs/app/tools/gimptransformtool.h
==============================================================================
--- branches/weskaggs/app/tools/gimptransformtool.h	(original)
+++ branches/weskaggs/app/tools/gimptransformtool.h	Tue Mar  4 19:17:18 2008
@@ -62,7 +62,7 @@
   gdouble         cx, cy;          /*  center point (for rotation)       */
   gdouble         aspect;          /*  original aspect ratio             */
 
-  gdouble         tx1, ty1;        /*  transformed coords                */
+  gdouble         tx1, ty1;        /*  transformed handle coords         */
   gdouble         tx2, ty2;
   gdouble         tx3, ty3;
   gdouble         tx4, ty4;



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