convolve.c 18 KB

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