gimp r27987 - in trunk: . app/actions app/core app/paint app/tools



Author: neo
Date: Thu Feb  5 21:47:57 2009
New Revision: 27987
URL: http://svn.gnome.org/viewvc/gimp?rev=27987&view=rev

Log:
2009-02-05  Sven Neumann  <sven gimp org>

	Bug 520078 â Rotate brushes

	Applied patch from Alexia Death:

	* app/core/gimpbrush.[ch]
	* app/core/gimpbrushgenerated.c
	* app/core/gimpbrush-transform.[ch]: affine transformations for
	brushes. So far only scaling and rotation is supported. The
	transformation is done using nearest-neighbour. This is a
	regression and we need to add back interpolation before the next
	release.

	* app/paint/gimpsmudge.c
	* app/paint/gimppaintoptions.[ch]
	* app/paint/gimpbrushcore.[ch]: allow to control the brush
	rotation angle.

	* app/tools/gimppaintoptions-gui.c
	* app/tools/gimpbrushtool.c: added UI for controlling the
	brush rotation angle.

	* app/actions/tools-actions.c
	* app/actions/tools-commands.[ch]: add actions for controlling 
the
	brush rotation angle.



Modified:
   trunk/ChangeLog
   trunk/app/actions/tools-actions.c
   trunk/app/actions/tools-commands.c
   trunk/app/actions/tools-commands.h
   trunk/app/core/gimpbrush-transform.c
   trunk/app/core/gimpbrush-transform.h
   trunk/app/core/gimpbrush.c
   trunk/app/core/gimpbrush.h
   trunk/app/core/gimpbrushgenerated.c
   trunk/app/paint/gimpbrushcore.c
   trunk/app/paint/gimpbrushcore.h
   trunk/app/paint/gimppaintoptions.c
   trunk/app/paint/gimppaintoptions.h
   trunk/app/paint/gimpsmudge.c
   trunk/app/tools/gimpbrushtool.c
   trunk/app/tools/gimppaintoptions-gui.c

Modified: trunk/app/actions/tools-actions.c
==============================================================================
--- trunk/app/actions/tools-actions.c	(original)
+++ trunk/app/actions/tools-actions.c	Thu Feb  5 21:47:57 2009
@@ -181,6 +181,42 @@
     NULL },
 };
 
+static const GimpEnumActionEntry tools_paint_brush_angle_actions[] =
+{
+  { "tools-paint-brush-angle-set", GIMP_STOCK_TOOL_PAINTBRUSH,
+    "Set Brush Angle", NULL, NULL,
+    GIMP_ACTION_SELECT_SET, TRUE,
+    NULL },
+  { "tools-paint-brush-angle-set-to-default", GIMP_STOCK_TOOL_PAINTBRUSH,
+    "Set Brush Angle To Default Value", NULL, NULL,
+    GIMP_ACTION_SELECT_SET_TO_DEFAULT, FALSE,
+    NULL },
+  { "tools-paint-brush-angle-minimum", GIMP_STOCK_TOOL_PAINTBRUSH,
+    "Minimize Brush Angle", NULL, NULL,
+    GIMP_ACTION_SELECT_FIRST, FALSE,
+    NULL },
+  { "tools-paint-brush-angle-maximum", GIMP_STOCK_TOOL_PAINTBRUSH,
+    "Maximize Brush Angle", NULL, NULL,
+    GIMP_ACTION_SELECT_LAST, FALSE,
+    NULL },
+  { "tools-paint-brush-angle-decrease", GIMP_STOCK_TOOL_PAINTBRUSH,
+    "Decrease Brush Angle", NULL, NULL,
+    GIMP_ACTION_SELECT_PREVIOUS, FALSE,
+    NULL },
+  { "tools-paint-brush-angle-increase", GIMP_STOCK_TOOL_PAINTBRUSH,
+    "Increase Brush Angle", NULL, NULL,
+    GIMP_ACTION_SELECT_NEXT, FALSE,
+    NULL },
+  { "tools-paint-brush-angle-decrease-skip", GIMP_STOCK_TOOL_PAINTBRUSH,
+    "Decrease Brush Angle More", NULL, NULL,
+    GIMP_ACTION_SELECT_SKIP_PREVIOUS, FALSE,
+    NULL },
+  { "tools-paint-brush-angle-increase-skip", GIMP_STOCK_TOOL_PAINTBRUSH,
+    "Increase Brush Angle More", NULL, NULL,
+    GIMP_ACTION_SELECT_SKIP_NEXT, FALSE,
+    NULL },
+};
+
 static const GimpEnumActionEntry tools_ink_blob_size_actions[] =
 {
   { "tools-ink-blob-size-set", GIMP_STOCK_TOOL_INK,
@@ -590,6 +626,11 @@
                                       G_CALLBACK (tools_paint_brush_scale_cmd_callback));
 
   gimp_action_group_add_enum_actions (group, NULL,
+                                      tools_paint_brush_angle_actions,
+                                      G_N_ELEMENTS (tools_paint_brush_angle_actions),
+                                      G_CALLBACK (tools_paint_brush_angle_cmd_callback));
+
+  gimp_action_group_add_enum_actions (group, NULL,
                                       tools_ink_blob_size_actions,
                                       G_N_ELEMENTS (tools_ink_blob_size_actions),
                                       G_CALLBACK (tools_ink_blob_size_cmd_callback));

Modified: trunk/app/actions/tools-commands.c
==============================================================================
--- trunk/app/actions/tools-commands.c	(original)
+++ trunk/app/actions/tools-commands.c	Thu Feb  5 21:47:57 2009
@@ -295,6 +295,26 @@
 }
 
 void
+tools_paint_brush_angle_cmd_callback (GtkAction *action,
+                                      gint       value,
+                                      gpointer   data)
+{
+  GimpContext  *context;
+  GimpToolInfo *tool_info;
+  return_if_no_context (context, data);
+
+  tool_info = gimp_context_get_tool (context);
+
+  if (tool_info && GIMP_IS_PAINT_OPTIONS (tool_info->tool_options))
+    {
+      action_select_property ((GimpActionSelectType) value,
+                              G_OBJECT (tool_info->tool_options),
+                              "brush-angle",
+                              0.01, 0.1, 1.0, FALSE);
+    }
+}
+
+void
 tools_ink_blob_size_cmd_callback (GtkAction *action,
                                   gint       value,
                                   gpointer   data)

Modified: trunk/app/actions/tools-commands.h
==============================================================================
--- trunk/app/actions/tools-commands.h	(original)
+++ trunk/app/actions/tools-commands.h	Thu Feb  5 21:47:57 2009
@@ -45,6 +45,10 @@
                                                      gint         value,
                                                      gpointer     data);
 
+void   tools_paint_brush_angle_cmd_callback         (GtkAction   *action,
+                                                     gint         value,
+                                                     gpointer     data);
+
 void   tools_ink_blob_size_cmd_callback             (GtkAction   *action,
                                                      gint         value,
                                                      gpointer     data);

Modified: trunk/app/core/gimpbrush-transform.c
==============================================================================
--- trunk/app/core/gimpbrush-transform.c	(original)
+++ trunk/app/core/gimpbrush-transform.c	Thu Feb  5 21:47:57 2009
@@ -1,7 +1,7 @@
 /* GIMP - The GNU Image Manipulation Program
  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  *
- * gimpbrush-scale.c
+ * gimpbrush-transform.c
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -23,26 +23,26 @@
 
 #include "core-types.h"
 
+#include "libgimpmath/gimpmath.h"
+
 #include "gimpbrush.h"
 #include "gimpbrush-transform.h"
 
-#include "base/pixel-region.h"
 #include "base/temp-buf.h"
 
-#include "paint-funcs/scale-region.h"
-
 
 /*  local function prototypes  */
 
-static TempBuf * gimp_brush_scale_buf_up      (TempBuf *brush_buf,
-                                               gint     dest_width,
-                                               gint     dest_height);
-static TempBuf * gimp_brush_scale_mask_down   (TempBuf *brush_mask,
-                                               gint     dest_width,
-                                               gint     dest_height);
-static TempBuf * gimp_brush_scale_pixmap_down (TempBuf *pixmap,
-                                               gint     dest_width,
-                                               gint     dest_height);
+static void  gimp_brush_transform_matrix       (GimpBrush         *brush,
+                                                gdouble            scale,
+                                                gdouble            angle,
+                                                GimpMatrix3       *matrix);
+static void  gimp_brush_transform_bounding_box (GimpBrush         *brush,
+                                                const GimpMatrix3 *matrix,
+                                                gint              *x,
+                                                gint              *y,
+                                                gint              *width,
+                                                gint              *height);
 
 
 /*  public functions  */
@@ -50,421 +50,187 @@
 void
 gimp_brush_real_transform_size (GimpBrush *brush,
                                 gdouble    scale,
+                                gdouble    angle,
                                 gint      *width,
                                 gint      *height)
 {
-  *width  = (gint) (brush->mask->width  * scale + 0.5);
-  *height = (gint) (brush->mask->height * scale + 0.5);
-}
-
-TempBuf *
-gimp_brush_real_transform_mask (GimpBrush *brush,
-                                gdouble    scale)
-{
-  gint dest_width;
-  gint dest_height;
+  GimpMatrix3 matrix;
+  gint        x, y;
 
-  gimp_brush_transform_size (brush, scale, &dest_width, &dest_height);
-
-  if (dest_width <= 0 || dest_height <= 0)
-    return NULL;
-
-  if (scale <= 1.0)
-    {
-      /*  Downscaling with brush_transform_mask is much faster than with
-       *  gimp_brush_scale_buf.
-       */
-      return gimp_brush_scale_mask_down (brush->mask,
-                                         dest_width, dest_height);
-    }
-
-  return gimp_brush_scale_buf_up (brush->mask, dest_width, dest_height);
+  gimp_brush_transform_matrix (brush, scale, angle, &matrix);
+  gimp_brush_transform_bounding_box (brush, &matrix, &x, &y, width, height);
 }
 
 TempBuf *
-gimp_brush_real_transform_pixmap (GimpBrush *brush,
-                                  gdouble    scale)
-{
-  gint dest_width;
-  gint dest_height;
-
-  gimp_brush_transform_size (brush, scale, &dest_width, &dest_height);
-
-  if (dest_width <= 0 || dest_height <= 0)
-    return NULL;
-
-  if (scale <= 1.0)
-    {
-      /*  Downscaling with brush_scale_pixmap is much faster than with
-       *  gimp_brush_scale_buf.
-       */
-      return gimp_brush_scale_pixmap_down (brush->pixmap,
-                                           dest_width, dest_height);
-    }
-
-  return gimp_brush_scale_buf_up (brush->pixmap, dest_width, dest_height);
-}
-
-
-/*  private functions  */
-
-static TempBuf *
-gimp_brush_scale_buf_up (TempBuf *brush_buf,
-                         gint     dest_width,
-                         gint     dest_height)
+gimp_brush_real_transform_mask (GimpBrush *brush,
+                                gdouble    scale,
+                                gdouble    angle)
 {
-  PixelRegion  source_region;
-  PixelRegion  dest_region;
-  TempBuf     *dest_brush_buf;
+  TempBuf      *result;
+  guchar       *dest;
+  const guchar *src;
+  GimpMatrix3   matrix;
+  gint          src_width;
+  gint          src_height;
+  gint          dest_width;
+  gint          dest_height;
+  gint          x, y;
 
-  pixel_region_init_temp_buf (&source_region, brush_buf,
-                              0, 0, brush_buf->width, brush_buf->height);
+  gimp_brush_transform_matrix (brush, scale, angle, &matrix);
 
-  dest_brush_buf = temp_buf_new (dest_width, dest_height, brush_buf->bytes,
-                                 0, 0, NULL);
+  if (gimp_matrix3_is_identity (&matrix))
+    return temp_buf_copy (brush->mask, NULL);
 
-  pixel_region_init_temp_buf (&dest_region, dest_brush_buf,
-                              0, 0, dest_width, dest_height);
+  src_width  = brush->mask->width;
+  src_height = brush->mask->height;
 
-  scale_region (&source_region, &dest_region,
-                GIMP_INTERPOLATION_LINEAR, NULL, NULL);
+  gimp_brush_transform_bounding_box (brush, &matrix,
+                                     &x, &y, &dest_width, &dest_height);
+  gimp_matrix3_translate (&matrix, -x, -y);
+  gimp_matrix3_invert (&matrix);
 
-  return dest_brush_buf;
-}
+  result = temp_buf_new (dest_width, dest_height, 1, 0, 0, NULL);
 
-static TempBuf *
-gimp_brush_scale_mask_down (TempBuf *brush_mask,
-                            gint     dest_width,
-                            gint     dest_height)
-{
-  TempBuf *scale_brush;
-  gint     src_width;
-  gint     src_height;
-  gint     value;
-  gint     area;
-  gint     i, j;
-  gint     x, x0, y, y0;
-  gint     dx, dx0, dy, dy0;
-  gint     fx, fx0, fy, fy0;
-  guchar  *src, *dest;
-
-  g_return_val_if_fail (brush_mask != NULL &&
-                        dest_width != 0 && dest_height != 0, NULL);
-
-  src_width  = brush_mask->width;
-  src_height = brush_mask->height;
-
-  scale_brush = temp_buf_new (dest_width, dest_height, 1, 0, 0, NULL);
-  g_return_val_if_fail (scale_brush != NULL, NULL);
-
-  /*  get the data  */
-  dest = temp_buf_get_data (scale_brush);
-  src  = temp_buf_get_data (brush_mask);
-
-  fx = fx0 = (src_width << 8) / dest_width;
-  fy = fy0 = (src_height << 8) / dest_height;
-
-  area = (fx0 * fy0) >> 8;
-
-  x = x0 = 0;
-  y = y0 = 0;
-  dx = dx0 = 0;
-  dy = dy0 = 0;
+  dest = temp_buf_get_data (result);
+  src  = temp_buf_get_data (brush->mask);
 
-  for (i = 0; i < dest_height; i++)
+  for (y = 0; y < dest_height; y++)
     {
-      for (j = 0; j < dest_width; j++)
+      for (x = 0; x < dest_width; x++)
         {
-          value  = 0;
+          gdouble dx, dy;
+          gint    ix, iy;
 
-          fy = fy0;
-          y  = y0;
-          dy = dy0;
+          gimp_matrix3_transform_point (&matrix, x, y, &dx, &dy);
 
-          if (dy)
-            {
-              fx = fx0;
-              x  = x0;
-              dx = dx0;
-
-              if (dx)
-                {
-                  value += (dx * dy * src[x + src_width * y]) >> 8;
-                  x++;
-                  fx -= dx;
-                  dx = 0;
-                }
-              while (fx >= 256)
-                {
-                  value += dy * src[x + src_width * y];
-                  x++;
-                  fx -= 256;
-                }
-              if (fx)
-                {
-                  value += fx * dy * src[x + src_width * y] >> 8;
-                  dx = 256 - fx;
-                }
-
-              y++;
-              fy -= dy;
-              dy = 0;
-            }
+          ix = ROUND (dx);
+          iy = ROUND (dy);
 
-          while (fy >= 256)
+          if (ix > 0 && ix < src_width &&
+              iy > 0 && iy < src_height)
             {
-              fx = fx0;
-              x  = x0;
-              dx = dx0;
-
-              if (dx)
-                {
-                  value += dx * src[x + src_width * y];
-                  x++;
-                  fx -= dx;
-                  dx = 0;
-                }
-              while (fx >= 256)
-                {
-                  value += 256 * src[x + src_width * y];
-                  x++;
-                  fx -= 256;
-                }
-              if (fx)
-                {
-                  value += fx * src[x + src_width * y];
-                  dx = 256 - fx;
-                }
-
-              y++;
-              fy -= 256;
+              *dest = src[iy * src_width + ix];
             }
-
-          if (fy)
+          else
             {
-              fx = fx0;
-              x  = x0;
-              dx = dx0;
-
-              if (dx)
-                {
-                  value += (dx * fy * src[x + src_width * y]) >> 8;
-                  x++;
-                  fx -= dx;
-                  dx = 0;
-                }
-              while (fx >= 256)
-                {
-                  value += fy * src[x + src_width * y];
-                  x++;
-                  fx -= 256;
-                }
-              if (fx)
-                {
-                  value += (fx * fy * src[x + src_width * y]) >> 8;
-                  dx = 256 - fx;
-                }
-
-              dy = 256 - fy;
+              *dest = 0;
             }
 
-          value /= area;
-          *dest++ = MIN (value, 255);
-
-          x0  = x;
-          dx0 = dx;
+          dest++;
         }
-
-      x0  = 0;
-      dx0 = 0;
-      y0  = y;
-      dy0 = dy;
     }
 
-  return scale_brush;
+  return result;
 }
 
-
-#define ADD_RGB(dest, factor, src) \
-  dest[0] += factor * src[0]; \
-  dest[1] += factor * src[1]; \
-  dest[2] += factor * src[2];
-
-static TempBuf *
-gimp_brush_scale_pixmap_down (TempBuf *pixmap,
-                              gint     dest_width,
-                              gint     dest_height)
+TempBuf *
+gimp_brush_real_transform_pixmap (GimpBrush *brush,
+                                  gdouble    scale,
+                                  gdouble    angle)
 {
-  TempBuf *scale_brush;
-  gint     src_width;
-  gint     src_height;
-  gint     value[3];
-  gint     factor;
-  gint     area;
-  gint     i, j;
-  gint     x, x0, y, y0;
-  gint     dx, dx0, dy, dy0;
-  gint     fx, fx0, fy, fy0;
-  guchar  *src, *src_ptr, *dest;
-
-  g_return_val_if_fail (pixmap != NULL && pixmap->bytes == 3 &&
-                        dest_width != 0 && dest_height != 0, NULL);
-
-  src_width  = pixmap->width;
-  src_height = pixmap->height;
-
-  scale_brush = temp_buf_new (dest_width, dest_height, 3, 0, 0, NULL);
-  g_return_val_if_fail (scale_brush != NULL, NULL);
-
-  /*  get the data  */
-  dest = temp_buf_get_data (scale_brush);
-  src  = temp_buf_get_data (pixmap);
-
-  fx = fx0 = (src_width << 8) / dest_width;
-  fy = fy0 = (src_height << 8) / dest_height;
-  area = (fx0 * fy0) >> 8;
-
-  x = x0 = 0;
-  y = y0 = 0;
-  dx = dx0 = 0;
-  dy = dy0 = 0;
+  TempBuf      *result;
+  guchar       *dest;
+  const guchar *src;
+  GimpMatrix3   matrix;
+  gint          src_width;
+  gint          src_height;
+  gint          dest_width;
+  gint          dest_height;
+  gint          x, y;
+
+  gimp_brush_transform_matrix (brush, scale, angle, &matrix);
+
+  if (gimp_matrix3_is_identity (&matrix))
+    return temp_buf_copy (brush->pixmap, NULL);
+
+  src_width  = brush->pixmap->width;
+  src_height = brush->pixmap->height;
+
+  gimp_brush_transform_bounding_box (brush, &matrix,
+                                     &x, &y, &dest_width, &dest_height);
+  gimp_matrix3_translate (&matrix, -x, -y);
+  gimp_matrix3_invert (&matrix);
+
+  result = temp_buf_new (dest_width, dest_height, 3, 0, 0, NULL);
+
+  dest = temp_buf_get_data (result);
+  src  = temp_buf_get_data (brush->pixmap);
 
-  for (i = 0; i < dest_height; i++)
+  for (y = 0; y < dest_height; y++)
     {
-      for (j=0; j<dest_width; j++)
+      for (x = 0; x < dest_width; x++)
         {
-          value[0] = 0;
-          value[1] = 0;
-          value[2] = 0;
-
-          fy = fy0;
-          y  = y0;
-          dy = dy0;
+          gdouble dx, dy;
+          gint    ix, iy;
 
-          if (dy)
-            {
-              fx = fx0;
-              x  = x0;
-              dx = dx0;
-
-              if (dx)
-                {
-                  factor = (dx * dy) >> 8;
-                  src_ptr = src + 3 * (x + y * src_width);
-                  ADD_RGB (value, factor, src_ptr);
-                  x++;
-                  fx -= dx;
-                  dx = 0;
-                }
-              while (fx >= 256)
-                {
-                  factor = dy;
-                  src_ptr = src + 3 * (x + y * src_width);
-                  ADD_RGB (value, factor, src_ptr);
-                  x++;
-                  fx -= 256;
-                }
-              if (fx)
-                {
-                  factor = (fx * dy) >> 8;
-                  src_ptr = src + 3 * (x + y * src_width);
-                  ADD_RGB (value, factor, src_ptr);
-                  dx = 256 - fx;
-                }
-
-              y++;
-              fy -= dy;
-              dy = 0;
-            }
+          gimp_matrix3_transform_point (&matrix, x, y, &dx, &dy);
 
-          while (fy >= 256)
+          ix = ROUND (dx);
+          iy = ROUND (dy);
+
+          if (ix > 0 && ix < src_width &&
+              iy > 0 && iy < src_height)
             {
-              fx = fx0;
-              x  = x0;
-              dx = dx0;
-
-              if (dx)
-                {
-                  factor = dx;
-                  src_ptr = src + 3 * (x + y * src_width);
-                  ADD_RGB (value, factor, src_ptr);
-                  x++;
-                  fx -= dx;
-                  dx = 0;
-                }
-              while (fx >= 256)
-                {
-                  factor = 256;
-                  src_ptr = src + 3 * (x + y * src_width);
-                  ADD_RGB (value, factor, src_ptr);
-                  x++;
-                  fx -= 256;
-                }
-              if (fx)
-                {
-                  factor = fx;
-                  src_ptr = src + 3 * (x + y * src_width);
-                  ADD_RGB (value, factor, src_ptr);
-                  dx = 256 - fx;
-                }
+              const guchar *s = src + 3 * (iy * src_width + ix);
 
-              y++;
-              fy -= 256;
+              dest[0] = s[0];
+              dest[1] = s[1];
+              dest[2] = s[2];
             }
-
-          if (fy)
+          else
             {
-              fx = fx0;
-              x  = x0;
-              dx = dx0;
-
-              if (dx)
-                {
-                  factor = (dx * fy) >> 8;
-                  src_ptr = src + 3 * (x + y * src_width);
-                  ADD_RGB (value, factor, src_ptr);
-                  x++;
-                  fx -= dx;
-                  dx = 0;
-                }
-              while (fx >= 256)
-                {
-                  factor = fy;
-                  src_ptr = src + 3 * (x + y * src_width);
-                  ADD_RGB (value, factor, src_ptr);
-                  x++;
-                  fx -= 256;
-                }
-              if (fx)
-                {
-                  factor = (fx * fy) >> 8;
-                  src_ptr = src + 3 * (x + y * src_width);
-                  ADD_RGB (value, factor, src_ptr);
-                  dx = 256 - fx;
-                }
-
-              dy = 256 - fy;
+              dest[0] = 0;
+              dest[1] = 0;
+              dest[2] = 0;
             }
 
-          value[0] /= area;
-          value[1] /= area;
-          value[2] /= area;
-
-          *dest++ = MIN (value[0], 255);
-          *dest++ = MIN (value[1], 255);
-          *dest++ = MIN (value[2], 255);
-
-          x0  = x;
-          dx0 = dx;
+          dest += 3;
         }
-
-      x0  = 0;
-      dx0 = 0;
-      y0  = y;
-      dy0 = dy;
     }
 
-  return scale_brush;
+  return result;
 }
 
-#undef ADD_RGB
+
+/*  private functions  */
+
+static void
+gimp_brush_transform_matrix (GimpBrush   *brush,
+                             gdouble      scale,
+                             gdouble      angle,
+                             GimpMatrix3 *matrix)
+{
+  const gdouble center_x = brush->mask->width  / 2;
+  const gdouble center_y = brush->mask->height / 2;
+
+  gimp_matrix3_identity (matrix);
+  gimp_matrix3_translate (matrix, - center_x, - center_x);
+  gimp_matrix3_rotate (matrix, 2 * G_PI * angle);
+  gimp_matrix3_translate (matrix, center_x, center_y);
+  gimp_matrix3_scale (matrix, scale, scale);
+}
+
+static void
+gimp_brush_transform_bounding_box (GimpBrush         *brush,
+                                   const GimpMatrix3 *matrix,
+                                   gint              *x,
+                                   gint              *y,
+                                   gint              *width,
+                                   gint              *height)
+{
+  const gdouble  w = brush->mask->width;
+  const gdouble  h = brush->mask->height;
+  gdouble        x1, x2, x3, x4;
+  gdouble        y1, y2, y3, y4;
+
+  gimp_matrix3_transform_point (matrix, 0, 0, &x1, &y1);
+  gimp_matrix3_transform_point (matrix, w, 0, &x2, &y2);
+  gimp_matrix3_transform_point (matrix, 0, h, &x3, &y3);
+  gimp_matrix3_transform_point (matrix, w, h, &x4, &y4);
+
+  *x = floor (MIN (MIN (x1, x2), MIN (x3, x4)));
+  *y = floor (MIN (MIN (y1, y2), MIN (y3, y4)));
+
+  *width  = (gint) (ceil  (MAX (MAX (x1, x2), MAX (x3, x4))) - *x);
+  *height = (gint) (ceil  (MAX (MAX (y1, y2), MAX (y3, y4))) - *y);
+}

Modified: trunk/app/core/gimpbrush-transform.h
==============================================================================
--- trunk/app/core/gimpbrush-transform.h	(original)
+++ trunk/app/core/gimpbrush-transform.h	Thu Feb  5 21:47:57 2009
@@ -25,12 +25,15 @@
 
 void      gimp_brush_real_transform_size   (GimpBrush *brush,
                                             gdouble    scale,
+                                            gdouble    angle,
                                             gint      *scaled_width,
                                             gint      *scaled_height);
 TempBuf * gimp_brush_real_transform_mask   (GimpBrush *brush,
-                                            gdouble    scale);
+                                            gdouble    scale,
+                                            gdouble    angle);
 TempBuf * gimp_brush_real_transform_pixmap (GimpBrush *brush,
-                                            gdouble    scale);
+                                            gdouble    scale,
+                                            gdouble    angle);
 
 
 #endif  /*  __GIMP_BRUSH_SCALE_H__  */

Modified: trunk/app/core/gimpbrush.c
==============================================================================
--- trunk/app/core/gimpbrush.c	(original)
+++ trunk/app/core/gimpbrush.c	Thu Feb  5 21:47:57 2009
@@ -276,13 +276,13 @@
 
       if (scale != 1.0)
         {
-          mask_buf = gimp_brush_transform_mask (brush, scale);
+          mask_buf = gimp_brush_transform_mask (brush, scale, 0.0);
 
           if (! mask_buf)
             mask_buf = temp_buf_new (1, 1, 1, 0, 0, transp);
 
           if (pixmap_buf)
-            pixmap_buf = gimp_brush_transform_pixmap (brush, scale);
+            pixmap_buf = gimp_brush_transform_pixmap (brush, scale, 0.0);
 
           mask_width  = mask_buf->width;
           mask_height = mask_buf->height;
@@ -458,6 +458,7 @@
 void
 gimp_brush_transform_size (GimpBrush     *brush,
                            gdouble        scale,
+                           gdouble        angle,
                            gint          *width,
                            gint          *height)
 {
@@ -466,7 +467,7 @@
   g_return_if_fail (width != NULL);
   g_return_if_fail (height != NULL);
 
-  if (scale == 1.0)
+  if ((scale == 1.0) && ((angle == 0.0) || (angle == 0.5) || (angle == 1.0)))
     {
       *width  = brush->mask->width;
       *height = brush->mask->height;
@@ -474,34 +475,36 @@
       return;
     }
 
-  GIMP_BRUSH_GET_CLASS (brush)->transform_size (brush, scale, width, height);
+  GIMP_BRUSH_GET_CLASS (brush)->transform_size (brush, scale, angle, width, height);
 }
 
 TempBuf *
 gimp_brush_transform_mask (GimpBrush *brush,
-                           gdouble    scale)
+                           gdouble    scale,
+                           gdouble    angle)
 {
   g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL);
   g_return_val_if_fail (scale > 0.0, NULL);
 
-  if (scale == 1.0)
+  if ((scale == 1.0) && (angle == 0.0))
     return temp_buf_copy (brush->mask, NULL);
 
-  return GIMP_BRUSH_GET_CLASS (brush)->transform_mask (brush, scale);
+  return GIMP_BRUSH_GET_CLASS (brush)->transform_mask (brush, scale, angle);
 }
 
 TempBuf *
 gimp_brush_transform_pixmap (GimpBrush *brush,
-                             gdouble    scale)
+                             gdouble    scale,
+                             gdouble    angle)
 {
   g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL);
   g_return_val_if_fail (brush->pixmap != NULL, NULL);
   g_return_val_if_fail (scale > 0.0, NULL);
 
-  if (scale == 1.0)
+  if ((scale == 1.0) && (angle == 0.0))
     return temp_buf_copy (brush->pixmap, NULL);
 
-  return GIMP_BRUSH_GET_CLASS (brush)->transform_pixmap (brush, scale);
+  return GIMP_BRUSH_GET_CLASS (brush)->transform_pixmap (brush, scale, angle);
 }
 
 TempBuf *

Modified: trunk/app/core/gimpbrush.h
==============================================================================
--- trunk/app/core/gimpbrush.h	(original)
+++ trunk/app/core/gimpbrush.h	Thu Feb  5 21:47:57 2009
@@ -58,12 +58,15 @@
                                     GimpCoords *cur_coords);
   void        (* transform_size)   (GimpBrush  *brush,
                                     gdouble     scale,
+                                    gdouble     angle,
                                     gint       *width,
                                     gint       *height);
   TempBuf   * (* transform_mask)   (GimpBrush  *brush,
-                                    gdouble     scale);
+                                    gdouble     scale,
+                                    gdouble     angle);
   TempBuf   * (* transform_pixmap) (GimpBrush  *brush,
-                                    gdouble     scale);
+                                    gdouble     scale,
+                                    gdouble     angle);
 
   /*  signals  */
   void        (* spacing_changed)  (GimpBrush  *brush);
@@ -85,12 +88,15 @@
 /* Gets width and height of a transformed mask of the brush, for provided parameters. */
 void        gimp_brush_transform_size   (GimpBrush        *brush,
                                          gdouble           scale,
+                                         gdouble           angle,
                                          gint             *width,
                                          gint             *height);
 TempBuf   * gimp_brush_transform_mask   (GimpBrush        *brush,
-                                         gdouble           scale);
+                                         gdouble           scale,
+                                         gdouble           angle);
 TempBuf   * gimp_brush_transform_pixmap (GimpBrush        *brush,
-                                         gdouble           scale);
+                                         gdouble           scale,
+                                         gdouble           angle);
 
 TempBuf   * gimp_brush_get_mask         (const GimpBrush  *brush);
 TempBuf   * gimp_brush_get_pixmap       (const GimpBrush  *brush);

Modified: trunk/app/core/gimpbrushgenerated.c
==============================================================================
--- trunk/app/core/gimpbrushgenerated.c	(original)
+++ trunk/app/core/gimpbrushgenerated.c	Thu Feb  5 21:47:57 2009
@@ -65,10 +65,12 @@
 
 static void          gimp_brush_generated_transform_size(GimpBrush    *gbrush,
                                                          gdouble       scale,
+                                                         gdouble       angle,
                                                          gint         *width,
                                                          gint         *height);
 static TempBuf     * gimp_brush_generated_transform_mask(GimpBrush    *gbrush,
-                                                         gdouble       scale);
+                                                         gdouble       scale,
+                                                         gdouble       angle);
 
 static TempBuf     * gimp_brush_generated_calc          (GimpBrushGenerated      *brush,
                                                          GimpBrushGeneratedShape  shape,
@@ -279,6 +281,7 @@
 static void
 gimp_brush_generated_transform_size (GimpBrush *gbrush,
                                      gdouble    scale,
+                                     gdouble    angle,
                                      gint      *width,
                                      gint      *height)
 {
@@ -292,7 +295,7 @@
                                       brush->spikes,
                                       brush->hardness,
                                       brush->aspect_ratio,
-                                      brush->angle,
+                                      (brush->angle + 360 * angle),
                                       &half_width, &half_height,
                                       NULL, NULL, NULL, NULL);
 
@@ -302,7 +305,8 @@
 
 static TempBuf *
 gimp_brush_generated_transform_mask (GimpBrush *gbrush,
-                                     gdouble    scale)
+                                     gdouble    scale,
+                                     gdouble    angle)
 {
   GimpBrushGenerated *brush  = GIMP_BRUSH_GENERATED (gbrush);
 
@@ -312,7 +316,7 @@
                                     brush->spikes,
                                     brush->hardness,
                                     brush->aspect_ratio,
-                                    brush->angle,
+                                    (brush->angle + 360 * angle),
                                     NULL, NULL);
 }
 

Modified: trunk/app/paint/gimpbrushcore.c
==============================================================================
--- trunk/app/paint/gimpbrushcore.c	(original)
+++ trunk/app/paint/gimpbrushcore.c	Thu Feb  5 21:47:57 2009
@@ -154,9 +154,9 @@
   paint_core_class->interpolate    = gimp_brush_core_interpolate;
   paint_core_class->get_paint_area = gimp_brush_core_get_paint_area;
 
-  klass->handles_changing_brush    = FALSE;
-  klass->handles_scaling_brush     = TRUE;
-  klass->set_brush                 = gimp_brush_core_real_set_brush;
+  klass->handles_changing_brush     = FALSE;
+  klass->handles_transforming_brush = TRUE;
+  klass->set_brush                  = gimp_brush_core_real_set_brush;
 }
 
 static void
@@ -168,6 +168,7 @@
   core->brush                        = NULL;
   core->spacing                      = 1.0;
   core->scale                        = 1.0;
+  core->angle                        = 1.0;
 
   core->pressure_brush               = NULL;
 
@@ -363,10 +364,14 @@
       return FALSE;
     }
 
-  core->scale = gimp_paint_options_get_dynamic_size (paint_options,
-                                                     coords,
-                                                     GIMP_BRUSH_CORE_GET_CLASS (core)->handles_scaling_brush);
-
+  if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_transforming_brush)
+    {
+      core->scale = gimp_paint_options_get_dynamic_size (paint_options,
+                                                         coords,
+                                                         TRUE);
+      core->angle = gimp_paint_options_get_dynamic_angle (paint_options,
+                                                          coords);
+    }
   core->spacing = (gdouble) gimp_brush_get_spacing (core->main_brush) / 100.0;
 
   core->brush = core->main_brush;
@@ -696,14 +701,19 @@
   gint           drawable_width, drawable_height;
   gint           brush_width, brush_height;
 
-  if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_scaling_brush)
-    core->scale = gimp_paint_options_get_dynamic_size (paint_options,
-                                                       &paint_core->cur_coords,
-                                                       TRUE);
+  if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_transforming_brush)
+    {
+      core->scale = gimp_paint_options_get_dynamic_size (paint_options,
+                                                         &paint_core->cur_coords,
+                                                         TRUE);
+
+      core->angle = gimp_paint_options_get_dynamic_angle (paint_options,
+                                                          &paint_core->cur_coords);
+    }
 
   core->scale = gimp_brush_core_clamp_brush_scale (core, core->scale);
 
-  gimp_brush_transform_size (core->brush, core->scale, &brush_width, &brush_height);
+  gimp_brush_transform_size (core->brush, core->scale, core->angle, &brush_width, &brush_height);
 
   /*  adjust the x and y coordinates to the upper left corner of the brush  */
   x = (gint) floor (paint_core->cur_coords.x) - (brush_width  / 2);
@@ -783,18 +793,20 @@
 {
   TempBuf *mask  = NULL;
   gdouble  scale;
+  gdouble  angle;
 
   g_return_if_fail (GIMP_IS_BRUSH_CORE (core));
   g_return_if_fail (core->main_brush != NULL);
   g_return_if_fail (core->brush_bound_segs == NULL);
 
   scale = paint_options->brush_scale;
+  angle = paint_options->brush_angle;
 
   if (scale > 0.0)
     {
       scale = gimp_brush_core_clamp_brush_scale (core, scale);
 
-      mask = gimp_brush_transform_mask (core->main_brush, scale);
+      mask = gimp_brush_transform_mask (core->main_brush, scale, angle);
     }
 
   if (mask)
@@ -1296,17 +1308,18 @@
   if (core->scale <= 0.0)
     return NULL; /* Should never happen now, with scale clamping. */
 
-  if (core->scale == 1.0)
+  if ((core->scale == 1.0) && (core->angle == 0.0))
     return brush->mask;
 
-  gimp_brush_transform_size (brush, core->scale, &width, &height);
+  gimp_brush_transform_size (brush, core->scale, core->angle, &width, &height);
 
-  if (! core->cache_invalid                      &&
+    if (! core->cache_invalid                      &&
       core->transform_brush                      &&
       brush->mask == core->last_transform_brush  &&
       width       == core->last_transform_width  &&
       height      == core->last_transform_height &&
-      core->scale == core->last_scale)
+      core->scale == core->last_scale            &&
+      core->angle == core->last_angle)
     {
       return core->transform_brush;
     }
@@ -1315,11 +1328,13 @@
   core->last_transform_width  = width;
   core->last_transform_height = height;
   core->last_scale        = core->scale;
+  core->last_angle        = core->angle;
+
 
   if (core->transform_brush)
     temp_buf_free (core->transform_brush);
 
-  core->transform_brush = gimp_brush_transform_mask (brush, core->scale);
+  core->transform_brush = gimp_brush_transform_mask (brush, core->scale, core->angle);
 
   core->cache_invalid       = TRUE;
   core->solid_cache_invalid = TRUE;
@@ -1337,16 +1352,18 @@
   if (core->scale <= 0.0)
     return NULL;
 
-  if (core->scale == 1.0)
+  if ((core->scale == 1.0) && (core->angle == 0.0))
     return brush->pixmap;
 
-  gimp_brush_transform_size (brush, core->scale, &width, &height);
+  gimp_brush_transform_size (brush, core->scale, core->angle, &width, &height);
+
 
   if (! core->cache_invalid                              &&
       core->transform_pixmap                             &&
       brush->pixmap == core->last_transform_pixmap       &&
       width         == core->last_transform_pixmap_width &&
-      height        == core->last_transform_pixmap_height)
+      height        == core->last_transform_pixmap_height&&
+      core->angle   == core->last_angle)
     {
       return core->transform_pixmap;
     }
@@ -1354,11 +1371,13 @@
   core->last_transform_pixmap        = brush->pixmap;
   core->last_transform_pixmap_width  = width;
   core->last_transform_pixmap_height = height;
+  core->last_angle = core->angle;
 
   if (core->transform_pixmap)
     temp_buf_free (core->transform_pixmap);
 
-  core->transform_pixmap = gimp_brush_transform_pixmap (brush, core->scale);
+
+  core->transform_pixmap = gimp_brush_transform_pixmap (brush, core->scale, core->angle);
 
   core->cache_invalid = TRUE;
 

Modified: trunk/app/paint/gimpbrushcore.h
==============================================================================
--- trunk/app/paint/gimpbrushcore.h	(original)
+++ trunk/app/paint/gimpbrushcore.h	Thu Feb  5 21:47:57 2009
@@ -45,6 +45,7 @@
   GimpBrush     *brush;
   gdouble        spacing;
   gdouble        scale;
+  gdouble        angle;
 
   /*  brush buffers  */
   TempBuf       *pressure_brush;
@@ -58,6 +59,7 @@
   gint           last_transform_width;
   gint           last_transform_height;
   gdouble        last_scale;
+  gdouble        last_angle;
 
   TempBuf       *transform_pixmap;
   TempBuf       *last_transform_pixmap;
@@ -90,7 +92,8 @@
   gboolean            handles_changing_brush;
 
   /*  Set for tools that don't mind if the brush scales while painting  */
-  gboolean            handles_scaling_brush;
+
+  gboolean            handles_transforming_brush;
 
   void (* set_brush) (GimpBrushCore *core,
                       GimpBrush     *brush);

Modified: trunk/app/paint/gimppaintoptions.c
==============================================================================
--- trunk/app/paint/gimppaintoptions.c	(original)
+++ trunk/app/paint/gimppaintoptions.c	Thu Feb  5 21:47:57 2009
@@ -34,6 +34,8 @@
 
 
 #define DEFAULT_BRUSH_SCALE           1.0
+#define DEFAULT_BRUSH_ANGLE           0.0
+
 #define DEFAULT_APPLICATION_MODE      GIMP_PAINT_CONSTANT
 #define DEFAULT_HARD                  FALSE
 
@@ -45,6 +47,7 @@
 #define DEFAULT_PRESSURE_SIZE         FALSE
 #define DEFAULT_PRESSURE_INVERSE_SIZE FALSE
 #define DEFAULT_PRESSURE_COLOR        FALSE
+#define DEFAULT_PRESSURE_ANGLE        FALSE
 #define DEFAULT_PRESSURE_PRESCALE     1.0
 
 #define DEFAULT_VELOCITY_OPACITY      FALSE
@@ -53,6 +56,7 @@
 #define DEFAULT_VELOCITY_SIZE         FALSE
 #define DEFAULT_VELOCITY_INVERSE_SIZE FALSE
 #define DEFAULT_VELOCITY_COLOR        FALSE
+#define DEFAULT_VELOCITY_ANGLE        FALSE
 #define DEFAULT_VELOCITY_PRESCALE     1.0
 
 #define DEFAULT_RANDOM_OPACITY        FALSE
@@ -61,6 +65,7 @@
 #define DEFAULT_RANDOM_SIZE           FALSE
 #define DEFAULT_RANDOM_INVERSE_SIZE   FALSE
 #define DEFAULT_RANDOM_COLOR          FALSE
+#define DEFAULT_RANDOM_ANGLE          FALSE
 #define DEFAULT_RANDOM_PRESCALE       1.0
 
 #define DEFAULT_USE_FADE              FALSE
@@ -82,7 +87,10 @@
   PROP_0,
 
   PROP_PAINT_INFO,
+
   PROP_BRUSH_SCALE,
+  PROP_BRUSH_ANGLE,
+
   PROP_APPLICATION_MODE,
   PROP_HARD,
 
@@ -94,6 +102,7 @@
   PROP_PRESSURE_SIZE,
   PROP_PRESSURE_INVERSE_SIZE,
   PROP_PRESSURE_COLOR,
+  PROP_PRESSURE_ANGLE,
   PROP_PRESSURE_PRESCALE,
 
   PROP_VELOCITY_OPACITY,
@@ -102,6 +111,7 @@
   PROP_VELOCITY_SIZE,
   PROP_VELOCITY_INVERSE_SIZE,
   PROP_VELOCITY_COLOR,
+  PROP_VELOCITY_ANGLE,
   PROP_VELOCITY_PRESCALE,
 
   PROP_RANDOM_OPACITY,
@@ -110,6 +120,7 @@
   PROP_RANDOM_SIZE,
   PROP_RANDOM_INVERSE_SIZE,
   PROP_RANDOM_COLOR,
+  PROP_RANDOM_ANGLE,
   PROP_RANDOM_PRESCALE,
 
   PROP_USE_FADE,
@@ -180,6 +191,11 @@
                                    "brush-scale", NULL,
                                    0.01, 10.0, DEFAULT_BRUSH_SCALE,
                                    GIMP_PARAM_STATIC_STRINGS);
+  GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_BRUSH_ANGLE,
+                                   "brush-angle", NULL,
+                                   -180.0, 180.0, DEFAULT_BRUSH_ANGLE,
+                                   GIMP_PARAM_STATIC_STRINGS);
+
   GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_APPLICATION_MODE,
                                  "application-mode", NULL,
                                  GIMP_TYPE_PAINT_APPLICATION_MODE,
@@ -215,6 +231,10 @@
                                     "pressure-color", NULL,
                                     DEFAULT_PRESSURE_COLOR,
                                     GIMP_PARAM_STATIC_STRINGS);
+  GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_PRESSURE_ANGLE,
+                                    "pressure-angle", NULL,
+                                    DEFAULT_PRESSURE_COLOR,
+                                    GIMP_PARAM_STATIC_STRINGS);
   GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_PRESSURE_INVERSE_SIZE,
                                     "pressure-inverse-size", NULL,
                                     DEFAULT_PRESSURE_INVERSE_SIZE,
@@ -244,6 +264,10 @@
                                     "velocity-color", NULL,
                                     DEFAULT_VELOCITY_COLOR,
                                     GIMP_PARAM_STATIC_STRINGS);
+  GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_VELOCITY_ANGLE,
+                                    "velocity-angle", NULL,
+                                    DEFAULT_VELOCITY_COLOR,
+                                    GIMP_PARAM_STATIC_STRINGS);
   GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_VELOCITY_INVERSE_SIZE,
                                     "velocity-inverse-size", NULL,
                                     DEFAULT_VELOCITY_INVERSE_SIZE,
@@ -273,6 +297,10 @@
                                     "random-color", NULL,
                                     DEFAULT_RANDOM_COLOR,
                                     GIMP_PARAM_STATIC_STRINGS);
+  GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_RANDOM_ANGLE,
+                                    "random-angle", NULL,
+                                    DEFAULT_RANDOM_COLOR,
+                                    GIMP_PARAM_STATIC_STRINGS);
   GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_RANDOM_INVERSE_SIZE,
                                     "random-inverse-size", NULL,
                                     DEFAULT_RANDOM_INVERSE_SIZE,
@@ -418,6 +446,10 @@
       options->brush_scale = g_value_get_double (value);
       break;
 
+    case PROP_BRUSH_ANGLE:
+      options->brush_angle = g_value_get_double (value) / 360.0;
+      break;
+
     case PROP_APPLICATION_MODE:
       options->application_mode = g_value_get_enum (value);
       break;
@@ -454,6 +486,10 @@
       pressure_options->color = g_value_get_boolean (value);
       break;
 
+    case PROP_PRESSURE_ANGLE:
+      pressure_options->angle = g_value_get_boolean (value);
+      break;
+
     case PROP_PRESSURE_PRESCALE:
       pressure_options->prescale = g_value_get_double (value);
       break;
@@ -482,6 +518,10 @@
       velocity_options->color = g_value_get_boolean (value);
       break;
 
+    case PROP_VELOCITY_ANGLE:
+      velocity_options->angle = g_value_get_boolean (value);
+      break;
+
     case PROP_VELOCITY_PRESCALE:
       velocity_options->prescale = g_value_get_double (value);
       break;
@@ -510,6 +550,10 @@
       random_options->color = g_value_get_boolean (value);
       break;
 
+    case PROP_RANDOM_ANGLE:
+      random_options->angle = g_value_get_boolean (value);
+      break;
+
     case PROP_RANDOM_PRESCALE:
       random_options->prescale = g_value_get_double (value);
       break;
@@ -608,6 +652,10 @@
       g_value_set_double (value, options->brush_scale);
       break;
 
+    case PROP_BRUSH_ANGLE:
+      g_value_set_double (value, options->brush_angle * 360.0);
+      break;
+
     case PROP_APPLICATION_MODE:
       g_value_set_enum (value, options->application_mode);
       break;
@@ -644,6 +692,10 @@
       g_value_set_boolean (value, pressure_options->color);
       break;
 
+    case PROP_PRESSURE_ANGLE:
+      g_value_set_boolean (value, pressure_options->angle);
+      break;
+
     case PROP_PRESSURE_PRESCALE:
       g_value_set_double (value, pressure_options->prescale);
       break;
@@ -672,6 +724,10 @@
       g_value_set_boolean (value, velocity_options->color);
       break;
 
+    case PROP_VELOCITY_ANGLE:
+      g_value_set_boolean (value, velocity_options->angle);
+      break;
+
     case PROP_VELOCITY_PRESCALE:
       g_value_set_double (value, velocity_options->prescale);
       break;
@@ -700,6 +756,10 @@
       g_value_set_boolean (value, random_options->color);
       break;
 
+    case PROP_RANDOM_ANGLE:
+      g_value_set_boolean (value, random_options->angle);
+      break;
+
     case PROP_RANDOM_PRESCALE:
       g_value_set_double (value, random_options->prescale);
       break;
@@ -1244,3 +1304,40 @@
 
   return hardness;
 }
+
+gdouble
+gimp_paint_options_get_dynamic_angle (GimpPaintOptions *paint_options,
+                                      const GimpCoords *coords)
+{
+  gdouble angle = 1.0;
+
+  g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), 1.0);
+  g_return_val_if_fail (coords != NULL, 1.0);
+
+  if (paint_options->pressure_options->angle ||
+      paint_options->velocity_options->angle ||
+      paint_options->random_options->angle)
+    {
+      gdouble pressure = -1.0;
+      gdouble velocity = -1.0;
+      gdouble random   = -1.0;
+
+      if (paint_options->pressure_options->angle)
+        pressure = GIMP_PAINT_PRESSURE_SCALE * coords->pressure;
+
+      if (paint_options->velocity_options->angle)
+        velocity = GIMP_PAINT_VELOCITY_SCALE * (1 - coords->velocity);
+
+      if (paint_options->random_options->angle)
+        random = g_random_double_range (0.0, 1.0);
+
+      angle = gimp_paint_options_get_dynamics_mix (pressure,
+                                                  paint_options->pressure_options->prescale,
+                                                  velocity,
+                                                  paint_options->velocity_options->prescale,
+                                                  random,
+                                                  paint_options->random_options->prescale);
+    }
+
+  return angle + paint_options->brush_angle;
+}

Modified: trunk/app/paint/gimppaintoptions.h
==============================================================================
--- trunk/app/paint/gimppaintoptions.h	(original)
+++ trunk/app/paint/gimppaintoptions.h	Thu Feb  5 21:47:57 2009
@@ -42,6 +42,7 @@
   gboolean  size;
   gboolean  inverse_size;
   gboolean  color;
+  gboolean  angle;
   gdouble   prescale;
 };
 
@@ -87,6 +88,7 @@
   GimpPaintInfo            *paint_info;
 
   gdouble                   brush_scale;
+  gdouble                   brush_angle;
 
   GimpPaintApplicationMode  application_mode;
   GimpPaintApplicationMode  application_mode_save;
@@ -150,6 +152,9 @@
 gdouble gimp_paint_options_get_dynamic_color   (GimpPaintOptions *paint_options,
                                                 const GimpCoords *coords);
 
+gdouble gimp_paint_options_get_dynamic_angle   (GimpPaintOptions *paint_options,
+                                                const GimpCoords *coords);
+
 gdouble gimp_paint_options_get_dynamic_hardness(GimpPaintOptions *paint_options,
                                                 const GimpCoords *coords);
 

Modified: trunk/app/paint/gimpsmudge.c
==============================================================================
--- trunk/app/paint/gimpsmudge.c	(original)
+++ trunk/app/paint/gimpsmudge.c	Thu Feb  5 21:47:57 2009
@@ -89,7 +89,7 @@
 
   paint_core_class->paint = gimp_smudge_paint;
 
-  brush_core_class->handles_scaling_brush = FALSE;
+  brush_core_class->handles_transforming_brush = FALSE;
 }
 
 static void
@@ -329,7 +329,7 @@
   gint           height;
 
   gimp_brush_transform_size (brush_core->brush, brush_core->scale,
-                             &width, &height);
+                             brush_core->angle, &width, &height);
 
   /* Note: these are the brush mask size plus a border of 1 pixel */
   *x = (gint) paint_core->cur_coords.x - width  / 2 - 1;

Modified: trunk/app/tools/gimpbrushtool.c
==============================================================================
--- trunk/app/tools/gimpbrushtool.c	(original)
+++ trunk/app/tools/gimpbrushtool.c	Thu Feb  5 21:47:57 2009
@@ -62,21 +62,21 @@
 
 static void   gimp_brush_tool_draw           (GimpDrawTool        *draw_tool);
 
-static void   gimp_brush_tool_brush_changed  (GimpContext         *context,
-                                              GimpBrush           *brush,
-                                              GimpBrushTool       *brush_tool);
-static void   gimp_brush_tool_brush_scaled   (GimpPaintOptions    *options,
-                                              GParamSpec          *pspec,
-                                              GimpBrushTool       *brush_tool);
-static void   gimp_brush_tool_set_brush      (GimpBrushCore       *brush_core,
-                                              GimpBrush           *brush,
-                                              GimpBrushTool       *brush_tool);
-static void   gimp_brush_tool_set_brush_after(GimpBrushCore       *brush_core,
-                                              GimpBrush           *brush,
-                                              GimpBrushTool       *brush_tool);
-static void   gimp_brush_tool_notify_brush   (GimpDisplayConfig   *config,
-                                              GParamSpec          *pspec,
-                                              GimpBrushTool       *brush_tool);
+static void   gimp_brush_tool_brush_changed     (GimpContext         *context,
+                                                 GimpBrush           *brush,
+                                                 GimpBrushTool       *brush_tool);
+static void   gimp_brush_tool_brush_transformed (GimpPaintOptions    *options,
+                                                 GParamSpec          *pspec,
+                                                 GimpBrushTool       *brush_tool);
+static void   gimp_brush_tool_set_brush         (GimpBrushCore       *brush_core,
+                                                 GimpBrush           *brush,
+                                                 GimpBrushTool       *brush_tool);
+static void   gimp_brush_tool_set_brush_after   (GimpBrushCore       *brush_core,
+                                                 GimpBrush           *brush,
+                                                 GimpBrushTool       *brush_tool);
+static void   gimp_brush_tool_notify_brush      (GimpDisplayConfig   *config,
+                                                 GParamSpec          *pspec,
+                                                 GimpBrushTool       *brush_tool);
 
 
 G_DEFINE_TYPE (GimpBrushTool, gimp_brush_tool, GIMP_TYPE_PAINT_TOOL)
@@ -155,7 +155,11 @@
                            G_CALLBACK (gimp_brush_tool_brush_changed),
                            brush_tool, 0);
   g_signal_connect_object (gimp_tool_get_options (tool), "notify::brush-scale",
-                           G_CALLBACK (gimp_brush_tool_brush_scaled),
+                           G_CALLBACK (gimp_brush_tool_brush_transformed),
+                           brush_tool, 0);
+
+  g_signal_connect_object (gimp_tool_get_options (tool), "notify::brush-angle",
+                           G_CALLBACK (gimp_brush_tool_brush_transformed),
                            brush_tool, 0);
 
   g_signal_connect (paint_tool->core, "set-brush",
@@ -345,9 +349,9 @@
 }
 
 static void
-gimp_brush_tool_brush_scaled (GimpPaintOptions *options,
-                              GParamSpec       *pspec,
-                              GimpBrushTool    *brush_tool)
+gimp_brush_tool_brush_transformed  (GimpPaintOptions *options,
+                                    GParamSpec       *pspec,
+                                    GimpBrushTool    *brush_tool)
 {
   GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (brush_tool);
   GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_tool->core);

Modified: trunk/app/tools/gimppaintoptions-gui.c
==============================================================================
--- trunk/app/tools/gimppaintoptions-gui.c	(original)
+++ trunk/app/tools/gimppaintoptions-gui.c	Thu Feb  5 21:47:57 2009
@@ -52,6 +52,7 @@
 static gboolean    tool_has_rate_dynamics     (GType       tool_type);
 static gboolean    tool_has_size_dynamics     (GType       tool_type);
 static gboolean    tool_has_color_dynamics    (GType       tool_type);
+static gboolean    tool_has_angle_dynamics    (GType       tool_type);
 
 static void        pressure_options_gui (GimpPaintOptions *paint_options,
                                          GType             tool_type,
@@ -128,7 +129,8 @@
   /*  the brush  */
   if (g_type_is_a (tool_type, GIMP_TYPE_BRUSH_TOOL))
     {
-      GtkObject *adj;
+      GtkObject *adj_scale;
+      GtkObject *adj_angle;
 
       button = gimp_prop_brush_box_new (NULL, GIMP_CONTEXT (tool_options), 2,
                                         "brush-view-type", "brush-view-size");
@@ -136,12 +138,20 @@
                                  _("Brush:"), 0.0, 0.5,
                                  button, 2, FALSE);
 
-      adj = gimp_prop_scale_entry_new (config, "brush-scale",
-                                       GTK_TABLE (table), 0, table_row++,
-                                       _("Scale:"),
-                                       0.01, 0.1, 2,
-                                       FALSE, 0.0, 0.0);
-      gimp_scale_entry_set_logarithmic (adj, TRUE);
+      adj_scale = gimp_prop_scale_entry_new (config, "brush-scale",
+                                             GTK_TABLE (table), 0, table_row++,
+                                             _("Scale:"),
+                                             0.01, 0.1, 2,
+                                             FALSE, 0.0, 0.0);
+      gimp_scale_entry_set_logarithmic (adj_scale, TRUE);
+
+      adj_angle = gimp_prop_scale_entry_new (config, "brush-angle",
+                                             GTK_TABLE (table), 0, table_row++,
+                                             _("Angle:"),
+                                             1.0, 5.0, 2,
+                                             FALSE, 0.0, 0.0);
+      gimp_scale_entry_set_logarithmic (adj_angle, FALSE);
+
     }
 
   if (tool_has_opacity_dynamics (tool_type))
@@ -168,6 +178,12 @@
       n_dynamics++;
     }
 
+  if (tool_has_angle_dynamics (tool_type))
+    {
+      dynamics_labels[n_dynamics] = gtk_label_new (_("Angle"));
+      n_dynamics++;
+    }
+
   if (tool_has_color_dynamics (tool_type))
     {
       dynamics_labels[n_dynamics] = gtk_label_new (_("Color"));
@@ -340,6 +356,12 @@
 }
 
 static gboolean
+tool_has_angle_dynamics (GType tool_type)
+{
+  return (g_type_is_a (tool_type, GIMP_TYPE_PAINTBRUSH_TOOL));
+}
+
+static gboolean
 tool_has_color_dynamics (GType tool_type)
 {
   return (g_type_is_a (tool_type, GIMP_TYPE_PAINTBRUSH_TOOL));
@@ -439,6 +461,16 @@
       column++;
     }
 
+  if (tool_has_angle_dynamics (tool_type))
+    {
+      button = dynamics_check_button_new (config, "pressure-angle",
+                                          table, column, row);
+      g_signal_connect (button, "size-allocate",
+                        G_CALLBACK (dynamics_check_button_size_allocate),
+                        labels[column - 1]);
+      column++;
+    }
+
   if (tool_has_color_dynamics (tool_type))
     {
       button = dynamics_check_button_new (config, "pressure-color",
@@ -489,6 +521,12 @@
                                  table, column++, row);
     }
 
+  if (tool_has_angle_dynamics (tool_type))
+    {
+      dynamics_check_button_new (config, "velocity-angle",
+                                 table, column++, row);
+    }
+
   if (tool_has_color_dynamics (tool_type))
     {
       dynamics_check_button_new (config, "velocity-color",
@@ -535,6 +573,12 @@
                                  table, column++, row);
     }
 
+  if (tool_has_angle_dynamics (tool_type))
+    {
+      dynamics_check_button_new (config, "random-angle",
+                                 table, column++, row);
+    }
+
   if (tool_has_color_dynamics (tool_type))
     {
       dynamics_check_button_new (config, "random-color",



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