home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / convolve.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  19.1 KB  |  679 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <gtk/gtk.h>
  22. #include <gdk/gdkkeysyms.h>
  23.  
  24. #include "apptypes.h"
  25.  
  26. #include "appenv.h"
  27. #include "drawable.h"
  28. #include "convolve.h"
  29. #include "gdisplay.h"
  30. #include "gimpui.h"
  31. #include "paint_funcs.h"
  32. #include "paint_core.h"
  33. #include "paint_options.h"
  34. #include "selection.h"
  35. #include "tools.h"
  36. #include "gimage.h"
  37.  
  38. #include "libgimp/gimpintl.h"
  39.  
  40.  
  41. #define FIELD_COLS    4
  42. #define MIN_BLUR      64         /*  (8/9 original pixel)   */
  43. #define MAX_BLUR      0.25       /*  (1/33 original pixel)  */
  44. #define MIN_SHARPEN   -512
  45. #define MAX_SHARPEN   -64
  46.  
  47. /* defaults */
  48. #define DEFAULT_CONVOLVE_RATE  50.0
  49. #define DEFAULT_CONVOLVE_TYPE  BLUR_CONVOLVE
  50.  
  51.  
  52. /* Different clip relationships between a blur-blob and edges: 
  53.    see convolve_motion */
  54.  
  55. typedef enum
  56. {
  57.   CONVOLVE_NCLIP,       /* Left or top edge     */
  58.   CONVOLVE_NOT_CLIPPED, /* No edges             */
  59.   CONVOLVE_PCLIP        /* Right or bottom edge */
  60. } ConvolveClipType;
  61.  
  62.  
  63. /*  the convolve structures  */
  64.  
  65. typedef struct _ConvolveOptions ConvolveOptions;
  66.  
  67. struct _ConvolveOptions
  68. {
  69.   PaintOptions  paint_options;
  70.  
  71.   ConvolveType  type;
  72.   ConvolveType  type_d;
  73.   GtkWidget    *type_w[2];
  74.  
  75.   gdouble       rate;
  76.   gdouble       rate_d;
  77.   GtkObject    *rate_w;
  78. };
  79.  
  80.  
  81. /*  the convolve tool options  */
  82. static ConvolveOptions * convolve_options = NULL;
  83.  
  84. /*  local variables  */
  85. static gint         matrix [25];
  86. static gint         matrix_size;
  87. static gint         matrix_divisor;
  88.  
  89. static ConvolveType non_gui_type;
  90. static gdouble      non_gui_rate;
  91.  
  92. static gfloat       custom_matrix [25] =
  93. {
  94.   0, 0, 0, 0, 0,
  95.   0, 0, 0, 0, 0,
  96.   0, 0, 1, 0, 0,
  97.   0, 0, 0, 0, 0,
  98.   0, 0, 0, 0, 0,
  99. };
  100.  
  101. static gfloat       blur_matrix [25] =
  102. {
  103.   0, 0, 0, 0, 0,
  104.   0, 1, 1, 1, 0,
  105.   0, 1, MIN_BLUR, 1, 0,
  106.   0, 1, 1, 1, 0,
  107.   0, 0 ,0, 0, 0,
  108. };
  109.  
  110. static gfloat       sharpen_matrix [25] =
  111. {
  112.   0, 0, 0, 0, 0,
  113.   0, 1, 1, 1, 0,
  114.   0, 1, MIN_SHARPEN, 1, 0,
  115.   0, 1, 1, 1, 0,
  116.   0, 0, 0, 0, 0,
  117. };
  118.  
  119.  
  120. /*  forward function declarations  */
  121. static void         calculate_matrix     (ConvolveType, double);
  122. static void         integer_matrix       (float *, int *, int);
  123. static void         copy_matrix          (float *, float *, int);
  124. static int          sum_matrix           (int *, int);
  125.  
  126. static void         convolve_motion      (PaintCore *, GimpDrawable *, 
  127.                       PaintPressureOptions *,
  128.                       ConvolveType, double);
  129.  
  130. /* functions  */
  131.  
  132.  
  133. static void
  134. convolve_options_reset (void)
  135. {
  136.   ConvolveOptions *options = convolve_options;
  137.  
  138.   paint_options_reset ((PaintOptions *) options);
  139.  
  140.   gtk_adjustment_set_value (GTK_ADJUSTMENT (options->rate_w), options->rate_d);
  141.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->type_w[options->type_d]), TRUE);
  142. }
  143.  
  144. static ConvolveOptions *
  145. convolve_options_new (void)
  146. {
  147.   ConvolveOptions *options;
  148.  
  149.   GtkWidget *vbox;
  150.   GtkWidget *hbox;
  151.   GtkWidget *label;
  152.   GtkWidget *scale;
  153.   GtkWidget *frame;
  154.  
  155.   /*  the new convolve tool options structure  */
  156.   options = g_new (ConvolveOptions, 1);
  157.   paint_options_init ((PaintOptions *) options,
  158.               CONVOLVE,
  159.               convolve_options_reset);
  160.   options->type = options->type_d = DEFAULT_CONVOLVE_TYPE;
  161.   options->rate = options->rate_d = DEFAULT_CONVOLVE_RATE;
  162.  
  163.   /*  the main vbox  */
  164.   vbox = ((ToolOptions *) options)->main_vbox;
  165.  
  166.   /*  the rate scale  */
  167.   hbox = gtk_hbox_new (FALSE, 4);
  168.   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  169.  
  170.   label = gtk_label_new (_("Rate:"));
  171.   gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
  172.   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  173.   gtk_widget_show (label);
  174.  
  175.   options->rate_w =
  176.     gtk_adjustment_new (options->rate_d, 0.0, 100.0, 1.0, 1.0, 0.0);
  177.   scale = gtk_hscale_new (GTK_ADJUSTMENT (options->rate_w));
  178.   gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
  179.   gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
  180.   gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
  181.   gtk_signal_connect (GTK_OBJECT (options->rate_w), "value_changed",
  182.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  183.               &options->rate);
  184.   gtk_widget_show (scale);
  185.   gtk_widget_show (hbox);
  186.  
  187.   frame = gimp_radio_group_new2 (TRUE, _("Convolve Type"),
  188.                  gimp_radio_button_update,
  189.                  &options->type, (gpointer) options->type,
  190.  
  191.                  _("Blur"), (gpointer) BLUR_CONVOLVE,
  192.                  &options->type_w[0],
  193.                  _("Sharpen"), (gpointer) SHARPEN_CONVOLVE,
  194.                  &options->type_w[1],
  195.  
  196.                  NULL);
  197.  
  198.   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  199.   gtk_widget_show (frame);
  200.  
  201.   return options;
  202. }
  203.  
  204. void *
  205. convolve_paint_func (PaintCore    *paint_core,
  206.              GimpDrawable *drawable,
  207.              int           state)
  208. {
  209.   switch (state)
  210.     {
  211.     case MOTION_PAINT:
  212.       convolve_motion (paint_core, drawable, 
  213.                convolve_options->paint_options.pressure_options,
  214.                convolve_options->type, convolve_options->rate);
  215.       break;
  216.     }
  217.  
  218.   return NULL;
  219. }
  220.  
  221. static void
  222. convolve_modifier_key_func (Tool        *tool,
  223.                 GdkEventKey *kevent,
  224.                 gpointer     gdisp_ptr)
  225. {
  226.   switch (kevent->keyval)
  227.     {
  228.     case GDK_Alt_L: 
  229.     case GDK_Alt_R:
  230.       break;
  231.     case GDK_Shift_L: 
  232.     case GDK_Shift_R:
  233.       if (kevent->state & GDK_CONTROL_MASK)    /* reset tool toggle */
  234.     {
  235.       switch (convolve_options->type)
  236.         {
  237.         case BLUR_CONVOLVE:
  238.           gtk_toggle_button_set_active
  239.         (GTK_TOGGLE_BUTTON (convolve_options->type_w[SHARPEN_CONVOLVE]),
  240.          TRUE);
  241.           break;
  242.         case SHARPEN_CONVOLVE:
  243.           gtk_toggle_button_set_active
  244.         (GTK_TOGGLE_BUTTON (convolve_options->type_w[BLUR_CONVOLVE]),
  245.          TRUE);
  246.           break;
  247.         default:
  248.           break;
  249.         }
  250.     }
  251.       break;
  252.     case GDK_Control_L: 
  253.     case GDK_Control_R:
  254.       if ( !(kevent->state & GDK_SHIFT_MASK) ) /* shift enables line draw mode */
  255.     {
  256.       switch (convolve_options->type)
  257.         {
  258.         case BLUR_CONVOLVE:
  259.           gtk_toggle_button_set_active
  260.         (GTK_TOGGLE_BUTTON (convolve_options->type_w[SHARPEN_CONVOLVE]),
  261.          TRUE);
  262.           break;
  263.         case SHARPEN_CONVOLVE:
  264.           gtk_toggle_button_set_active
  265.         (GTK_TOGGLE_BUTTON (convolve_options->type_w[BLUR_CONVOLVE]),
  266.          TRUE);
  267.           break;
  268.         default:
  269.           break;
  270.         }
  271.     }
  272.       break;
  273.     }
  274.  
  275.   tool->toggled = (convolve_options->type == SHARPEN_CONVOLVE);
  276. }
  277.  
  278. static void
  279. convolve_cursor_update_func (Tool           *tool,
  280.                  GdkEventMotion *mevent,
  281.                  gpointer        gdisp_ptr)
  282. {
  283.   tool->toggled = (convolve_options->type == SHARPEN_CONVOLVE);
  284.  
  285.   paint_core_cursor_update (tool, mevent, gdisp_ptr);
  286. }
  287.  
  288. Tool *
  289. tools_new_convolve (void)
  290. {
  291.   Tool * tool;
  292.   PaintCore * private;
  293.  
  294.   /*  The tool options  */
  295.   if (! convolve_options)
  296.     {
  297.       convolve_options = convolve_options_new ();
  298.       tools_register (CONVOLVE, (ToolOptions *) convolve_options);
  299.  
  300.       /*  press all default buttons  */
  301.       convolve_options_reset ();
  302.     }
  303.  
  304.   tool = paint_core_new (CONVOLVE);
  305.   tool->modifier_key_func  = convolve_modifier_key_func;
  306.   tool->cursor_update_func = convolve_cursor_update_func;
  307.  
  308.   private = (PaintCore *) tool->private;
  309.   private->paint_func = convolve_paint_func;
  310.  
  311.   return tool;
  312. }
  313.  
  314. void
  315. tools_free_convolve (Tool *tool)
  316. {
  317.   paint_core_free (tool);
  318. }
  319.  
  320. static void
  321. convolve_motion (PaintCore            *paint_core,
  322.          GimpDrawable         *drawable,
  323.          PaintPressureOptions *pressure_options,
  324.          ConvolveType          type,
  325.          double                rate)
  326. {
  327.   TempBuf         *area;
  328.   guchar          *temp_data;
  329.   PixelRegion      srcPR; 
  330.   PixelRegion      destPR;
  331.   gdouble          scale;
  332.   ConvolveClipType area_hclip = CONVOLVE_NOT_CLIPPED;
  333.   ConvolveClipType area_vclip = CONVOLVE_NOT_CLIPPED;
  334.   gint             marginx = 0;
  335.   gint             marginy = 0;
  336.  
  337.   if (!drawable_gimage (drawable))
  338.     return;
  339.  
  340.   /*  If the image type is indexed, don't convolve  */
  341.   if ((drawable_type (drawable) == INDEXED_GIMAGE) ||
  342.       (drawable_type (drawable) == INDEXEDA_GIMAGE))
  343.     return;
  344.  
  345.   /* If the brush is smaller than the convolution matrix, don't convolve */
  346.  
  347.   if((paint_core->brush->mask->width < matrix_size) || (paint_core->brush->mask->height < matrix_size))
  348.     return;
  349.  
  350.   if (pressure_options->size)
  351.     scale = paint_core->curpressure;
  352.   else
  353.     scale = 1.0;
  354.  
  355.   /*  Get image region around current brush (mask bbox + 1 pixel)  */
  356.   if (! (area = paint_core_get_paint_area (paint_core, drawable, scale)))
  357.     return;
  358.  
  359.   /*  configure the source pixel region  */
  360.   pixel_region_init (&srcPR, drawable_data (drawable),
  361.              area->x, area->y, area->width, area->height, FALSE);
  362.  
  363.   /* Configure the destination pixel region - a paint_core TempBuf */
  364.  
  365.   destPR.bytes     = area->bytes;
  366.   destPR.tiles     = NULL;
  367.   destPR.x         = 0; 
  368.   destPR.y         = 0;
  369.   destPR.w         = area->width;
  370.   destPR.h         = area->height;
  371.   destPR.rowstride = area->width * destPR.bytes;
  372.   destPR.data      = temp_buf_data (area);
  373.  
  374.   if (pressure_options->rate)
  375.     rate = rate * 2.0 * paint_core->curpressure;
  376.  
  377.   calculate_matrix (type, rate); 
  378.     
  379.   /*  Image region near edges? If so, paint area will be clipped   */
  380.   /*  with respect to brush mask + 1 pixel border (# 19285)        */
  381.  
  382.   if((marginx = (gint)paint_core->curx - paint_core->brush->mask->width/2 - 1)  != area->x)
  383.     area_hclip = CONVOLVE_NCLIP;
  384.   else
  385.     if((marginx = area->width - paint_core->brush->mask->width - 2) != 0)
  386.       area_hclip = CONVOLVE_PCLIP;
  387.  
  388.   if((marginy = (gint)paint_core->cury - paint_core->brush->mask->height/2 - 1) != area->y)
  389.     area_vclip = CONVOLVE_NCLIP;
  390.   else 
  391.     if((marginy = area->height - paint_core->brush->mask->height - 2) != 0)
  392.       area_vclip = CONVOLVE_PCLIP;
  393.  
  394.   /* Has the TempBuf been clipped by a canvas edge or two ?        */
  395.   if((area_hclip == CONVOLVE_NOT_CLIPPED)  && (area_vclip == CONVOLVE_NOT_CLIPPED))
  396.     {
  397.       /* No clipping...                                              */
  398.       /* Standard case: copy src to temp. convolve temp to dest.     */
  399.       /* Brush defines pipe size and no edge adjustments are needed. */
  400.  
  401.       /*  If the source has no alpha, then add alpha pixels          */
  402.       /*  Because paint_core.c is alpha-only code. See below.        */
  403.  
  404.       PixelRegion  tempPR;
  405.  
  406.       tempPR.x     = 0; 
  407.       tempPR.y     = 0;
  408.       tempPR.w     = area->width;
  409.       tempPR.h     = area->height;
  410.       tempPR.tiles = NULL;
  411.  
  412.       if (!drawable_has_alpha (drawable))
  413.     {
  414.       /* note: this particular approach needlessly convolves the totally-
  415.          opaque alpha channel. A faster approach would be to keep
  416.          tempPR the same number of bytes as srcPR, and extend the
  417.          paint_core_replace_canvas API to handle non-alpha images. */
  418.  
  419.       tempPR.bytes     = srcPR.bytes + 1;
  420.       tempPR.rowstride = tempPR.bytes * tempPR.w;
  421.       temp_data        = g_malloc (tempPR.h * tempPR.rowstride);
  422.       tempPR.data      = temp_data;
  423.       add_alpha_region (&srcPR, &tempPR);
  424.     }
  425.       else
  426.     {
  427.       tempPR.bytes     = srcPR.bytes;
  428.       tempPR.rowstride = tempPR.bytes * tempPR.w;
  429.       temp_data        = g_malloc (tempPR.h * tempPR.rowstride);
  430.       tempPR.data      = temp_data;
  431.       copy_region (&srcPR, &tempPR);
  432.     }
  433.  
  434.       /*  Convolve the region  */
  435.  
  436.       tempPR.x    = 0;
  437.       tempPR.y    = 0;
  438.       tempPR.w    = area->width;
  439.       tempPR.h    = area->height;
  440.       tempPR.data = temp_data;
  441.       convolve_region (&tempPR, &destPR, matrix, matrix_size,
  442.                matrix_divisor, NORMAL_CONVOL);
  443.  
  444.       /*  Free the allocated temp space  */
  445.       g_free (temp_data);
  446.     }
  447.   else
  448.     {
  449.       /* TempBuf clipping has occured on at least one edge...                   */
  450.       /* Edge case: expand area under brush margin px on near edge(s), convolve */
  451.       /* expanded buffers. copy src -> ovrsz1 convolve ovrsz1 -> ovrsz2         */
  452.       /* copy-with-crop ovrsz2 -> dest                                          */
  453.  
  454.       PixelRegion   ovrsz1PR;
  455.       PixelRegion   ovrsz2PR;
  456.       guchar        *ovrsz1_data = NULL;
  457.       guchar        *ovrsz2_data = NULL;
  458.       guchar        *fillcolor   = gimp_drawable_get_color_at (drawable,
  459.                      CLAMP ((gint) paint_core->curx, 0, gimp_drawable_width (drawable) - 1),
  460.                      CLAMP ((gint) paint_core->cury, 0, gimp_drawable_height (drawable) - 1));
  461.  
  462.       marginx *= (marginx < 0) ? -1 : 0;
  463.       marginy *= (marginy < 0) ? -1 : 0;
  464.  
  465.       ovrsz2PR.x         = 0;
  466.       ovrsz2PR.y         = 0;
  467.       ovrsz2PR.w         = area->width  + marginx;
  468.       ovrsz2PR.h         = area->height + marginy;
  469.       ovrsz2PR.bytes     = (drawable_has_alpha (drawable))? srcPR.bytes : srcPR.bytes + 1; 
  470.       ovrsz2PR.offx      = 0;
  471.       ovrsz2PR.offy      = 0;
  472.       ovrsz2PR.rowstride = ovrsz2PR.bytes * ovrsz2PR.w;
  473.       ovrsz2PR.tiles     = NULL;
  474.       ovrsz2_data        = g_malloc (ovrsz2PR.h * ovrsz2PR.rowstride);
  475.       ovrsz2PR.data      = ovrsz2_data;
  476.  
  477.       ovrsz1PR.x         = 0;
  478.       ovrsz1PR.y         = 0;
  479.       ovrsz1PR.w         = area->width  + marginx;
  480.       ovrsz1PR.h         = area->height + marginy;
  481.       ovrsz1PR.bytes     = (drawable_has_alpha (drawable))? srcPR.bytes : srcPR.bytes + 1; 
  482.       ovrsz1PR.offx      = 0;
  483.       ovrsz1PR.offy      = 0;
  484.       ovrsz1PR.rowstride = ovrsz2PR.bytes * ovrsz2PR.w;
  485.       ovrsz1PR.tiles     = NULL;
  486.       ovrsz1_data        = g_malloc (ovrsz1PR.h * ovrsz1PR.rowstride);
  487.       ovrsz1PR.data      = ovrsz1_data;
  488.       color_region (&ovrsz1PR, (const guchar *)fillcolor); 
  489.  
  490.       ovrsz1PR.x         = (area_hclip == CONVOLVE_NCLIP)? marginx : 0; 
  491.       ovrsz1PR.y         = (area_vclip == CONVOLVE_NCLIP)? marginy : 0;
  492.       ovrsz1PR.w         = area->width;
  493.       ovrsz1PR.h         = area->height;
  494.       ovrsz1PR.data      = ovrsz1_data + (ovrsz1PR.rowstride * ovrsz1PR.y) + (ovrsz1PR.bytes * ovrsz1PR.x);
  495.  
  496.       if (!(drawable_has_alpha (drawable)))
  497.     add_alpha_region (&srcPR, &ovrsz1PR);
  498.       else
  499.     copy_region (&srcPR, &ovrsz1PR);
  500.  
  501.       /*  Convolve the region  */
  502.  
  503.       ovrsz1PR.x    = 0;
  504.       ovrsz1PR.y    = 0;
  505.       ovrsz1PR.w    = area->width  + marginx;
  506.       ovrsz1PR.h    = area->height + marginy;
  507.       ovrsz1PR.data = ovrsz1_data;
  508.       convolve_region (&ovrsz1PR, &ovrsz2PR, matrix, matrix_size,
  509.                matrix_divisor, NORMAL_CONVOL);
  510.  
  511.       /* Crop and copy to destination */
  512.  
  513.       ovrsz2PR.x    = (area_hclip == CONVOLVE_NCLIP)? marginx : 0; 
  514.       ovrsz2PR.y    = (area_vclip == CONVOLVE_NCLIP)? marginy : 0; 
  515.       ovrsz2PR.w    = area->width;
  516.       ovrsz2PR.h    = area->height;
  517.       ovrsz2PR.data = ovrsz2_data + (ovrsz2PR.rowstride * ovrsz2PR.y) + (ovrsz2PR.bytes * ovrsz2PR.x);
  518.       copy_region (&ovrsz2PR, &destPR);
  519.       g_free(ovrsz1_data);
  520.       g_free(ovrsz2_data);
  521.       g_free(fillcolor);
  522.     }
  523.  
  524.   /*  paste the newly painted canvas to the gimage which is being worked on  */
  525.   paint_core_replace_canvas (paint_core, drawable, OPAQUE_OPACITY,
  526.                  (int) (gimp_context_get_opacity (NULL) * 255),
  527.                  pressure_options->pressure ? PRESSURE : SOFT,
  528.                  scale, INCREMENTAL);
  529. }
  530.  
  531. static void
  532. calculate_matrix (ConvolveType type,
  533.           double       rate)
  534. {
  535.   float percent;
  536.  
  537.   /*  find percent of tool pressure  */
  538.   percent = MIN (rate / 100.0, 1.0);
  539.  
  540.   /*  get the appropriate convolution matrix and size and divisor  */
  541.   switch (type)
  542.     {
  543.     case BLUR_CONVOLVE:
  544.       matrix_size = 5;
  545.       blur_matrix [12] = MIN_BLUR + percent * (MAX_BLUR - MIN_BLUR);
  546.       copy_matrix (blur_matrix, custom_matrix, matrix_size);
  547.       break;
  548.  
  549.     case SHARPEN_CONVOLVE:
  550.       matrix_size = 5;
  551.       sharpen_matrix [12] = MIN_SHARPEN + percent * (MAX_SHARPEN - MIN_SHARPEN);
  552.       copy_matrix (sharpen_matrix, custom_matrix, matrix_size);
  553.       break;
  554.  
  555.     case CUSTOM_CONVOLVE:
  556.       matrix_size = 5;
  557.       break;
  558.     }
  559.  
  560.   integer_matrix (custom_matrix, matrix, matrix_size);
  561.   matrix_divisor = sum_matrix (matrix, matrix_size);
  562.  
  563.   if (!matrix_divisor)
  564.     matrix_divisor = 1;
  565. }
  566.  
  567. static void
  568. integer_matrix (float *source,
  569.         int   *dest,
  570.         int    size)
  571. {
  572.   int i;
  573.  
  574. #define PRECISION  10000
  575.  
  576.   for (i = 0; i < size*size; i++)
  577.     *dest++ = (int) (*source ++ * PRECISION);
  578. }
  579.  
  580. static void
  581. copy_matrix (float *src,
  582.          float *dest,
  583.          int    size)
  584. {
  585.   int i;
  586.  
  587.   for (i = 0; i < size*size; i++)
  588.     *dest++ = *src++;
  589. }
  590.  
  591. static int
  592. sum_matrix (int *matrix,
  593.         int  size)
  594. {
  595.   int sum = 0;
  596.  
  597.   size *= size;
  598.  
  599.   while (size --)
  600.     sum += *matrix++;
  601.  
  602.   return sum;
  603. }
  604.  
  605.  
  606. static void *
  607. convolve_non_gui_paint_func (PaintCore *paint_core,
  608.                  GimpDrawable *drawable,
  609.                  int        state)
  610. {
  611.   convolve_motion (paint_core, drawable, &non_gui_pressure_options,
  612.            non_gui_type, non_gui_rate);
  613.  
  614.   return NULL;
  615. }
  616.  
  617. gboolean
  618. convolve_non_gui_default (GimpDrawable *drawable,
  619.               int           num_strokes,
  620.               double       *stroke_array)
  621. {
  622.   double rate = DEFAULT_CONVOLVE_RATE;
  623.   ConvolveType type = DEFAULT_CONVOLVE_TYPE;
  624.   ConvolveOptions *options = convolve_options;
  625.  
  626.   if (options)
  627.     {
  628.       rate = options->rate;
  629.       type = options->type;
  630.     }
  631.  
  632.   return convolve_non_gui (drawable, rate, type, num_strokes, stroke_array);
  633. }
  634.  
  635. gboolean
  636. convolve_non_gui (GimpDrawable *drawable,
  637.               double        rate,
  638.           ConvolveType  type,
  639.           int           num_strokes,
  640.           double       *stroke_array)
  641. {
  642.   int i;
  643.  
  644.   if (paint_core_init (&non_gui_paint_core, drawable,
  645.                stroke_array[0], stroke_array[1]))
  646.     {
  647.       /* Set the paint core's paint func */
  648.       non_gui_paint_core.paint_func = convolve_non_gui_paint_func;
  649.       
  650.       non_gui_type = type;
  651.       non_gui_rate = rate;
  652.  
  653.       non_gui_paint_core.startx = non_gui_paint_core.lastx = stroke_array[0];
  654.       non_gui_paint_core.starty = non_gui_paint_core.lasty = stroke_array[1];
  655.  
  656.       convolve_non_gui_paint_func (&non_gui_paint_core, drawable, 0);
  657.  
  658.       for (i = 1; i < num_strokes; i++)
  659.     {
  660.       non_gui_paint_core.curx = stroke_array[i * 2 + 0];
  661.       non_gui_paint_core.cury = stroke_array[i * 2 + 1];
  662.  
  663.       paint_core_interpolate (&non_gui_paint_core, drawable);
  664.  
  665.       non_gui_paint_core.lastx = non_gui_paint_core.curx;
  666.       non_gui_paint_core.lasty = non_gui_paint_core.cury;
  667.     }
  668.  
  669.       /* Finish the painting */
  670.       paint_core_finish (&non_gui_paint_core, drawable, -1);
  671.  
  672.       /* Cleanup */
  673.       paint_core_cleanup ();
  674.       return TRUE;
  675.     }
  676.   else
  677.     return FALSE;
  678. }
  679.