1 /* GIMP - The GNU 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 3 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, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <string.h>
21 
22 #include <gdk-pixbuf/gdk-pixbuf.h>
23 #include <gegl.h>
24 
25 #include "libgimpmath/gimpmath.h"
26 
27 #include "paint-types.h"
28 
29 #include "operations/layer-modes/gimp-layer-modes.h"
30 
31 #include "gegl/gimp-babl.h"
32 #include "gegl/gimp-gegl-loops.h"
33 
34 #include "core/gimpbrush-header.h"
35 #include "core/gimpbrushgenerated.h"
36 #include "core/gimpdrawable.h"
37 #include "core/gimpdynamics.h"
38 #include "core/gimpdynamicsoutput.h"
39 #include "core/gimperror.h"
40 #include "core/gimpimage.h"
41 #include "core/gimpmarshal.h"
42 #include "core/gimpsymmetry.h"
43 #include "core/gimptempbuf.h"
44 
45 #include "gimpbrushcore.h"
46 #include "gimpbrushcore-loops.h"
47 #include "gimpbrushcore-kernels.h"
48 
49 #include "gimppaintoptions.h"
50 
51 #include "gimp-intl.h"
52 
53 
54 #define EPSILON  0.00001
55 
56 enum
57 {
58   SET_BRUSH,
59   SET_DYNAMICS,
60   LAST_SIGNAL
61 };
62 
63 
64 /*  local function prototypes  */
65 
66 static void      gimp_brush_core_finalize           (GObject          *object);
67 
68 static gboolean  gimp_brush_core_start              (GimpPaintCore    *core,
69                                                      GimpDrawable     *drawable,
70                                                      GimpPaintOptions *paint_options,
71                                                      const GimpCoords *coords,
72                                                      GError          **error);
73 static gboolean  gimp_brush_core_pre_paint          (GimpPaintCore    *core,
74                                                      GimpDrawable     *drawable,
75                                                      GimpPaintOptions *paint_options,
76                                                      GimpPaintState    paint_state,
77                                                      guint32           time);
78 static void      gimp_brush_core_post_paint         (GimpPaintCore    *core,
79                                                      GimpDrawable     *drawable,
80                                                      GimpPaintOptions *paint_options,
81                                                      GimpPaintState    paint_state,
82                                                      guint32           time);
83 static void      gimp_brush_core_interpolate        (GimpPaintCore    *core,
84                                                      GimpDrawable     *drawable,
85                                                      GimpPaintOptions *paint_options,
86                                                      guint32           time);
87 
88 static GeglBuffer * gimp_brush_core_get_paint_buffer(GimpPaintCore    *paint_core,
89                                                      GimpDrawable     *drawable,
90                                                      GimpPaintOptions *paint_options,
91                                                      GimpLayerMode     paint_mode,
92                                                      const GimpCoords *coords,
93                                                      gint             *paint_buffer_x,
94                                                      gint             *paint_buffer_y,
95                                                      gint             *paint_width,
96                                                      gint             *paint_height);
97 
98 static void      gimp_brush_core_real_set_brush     (GimpBrushCore    *core,
99                                                      GimpBrush        *brush);
100 static void      gimp_brush_core_real_set_dynamics  (GimpBrushCore    *core,
101                                                      GimpDynamics     *dynamics);
102 
103 static gdouble   gimp_brush_core_get_angle          (GimpBrushCore     *core);
104 static gboolean  gimp_brush_core_get_reflect        (GimpBrushCore     *core);
105 
106 static const GimpTempBuf *
107                  gimp_brush_core_transform_mask     (GimpBrushCore     *core,
108                                                      GimpBrush         *brush);
109 
110 static void      gimp_brush_core_invalidate_cache   (GimpBrush         *brush,
111                                                      GimpBrushCore     *core);
112 
113 
114 G_DEFINE_TYPE (GimpBrushCore, gimp_brush_core, GIMP_TYPE_PAINT_CORE)
115 
116 #define parent_class gimp_brush_core_parent_class
117 
118 static guint core_signals[LAST_SIGNAL] = { 0, };
119 
120 
121 static void
gimp_brush_core_class_init(GimpBrushCoreClass * klass)122 gimp_brush_core_class_init (GimpBrushCoreClass *klass)
123 {
124   GObjectClass       *object_class     = G_OBJECT_CLASS (klass);
125   GimpPaintCoreClass *paint_core_class = GIMP_PAINT_CORE_CLASS (klass);
126 
127   core_signals[SET_BRUSH] =
128     g_signal_new ("set-brush",
129                   G_TYPE_FROM_CLASS (klass),
130                   G_SIGNAL_RUN_LAST,
131                   G_STRUCT_OFFSET (GimpBrushCoreClass, set_brush),
132                   NULL, NULL,
133                   gimp_marshal_VOID__OBJECT,
134                   G_TYPE_NONE, 1,
135                   GIMP_TYPE_BRUSH);
136 
137   core_signals[SET_DYNAMICS] =
138     g_signal_new ("set-dynamics",
139                   G_TYPE_FROM_CLASS (klass),
140                   G_SIGNAL_RUN_LAST,
141                   G_STRUCT_OFFSET (GimpBrushCoreClass, set_dynamics),
142                   NULL, NULL,
143                   gimp_marshal_VOID__OBJECT,
144                   G_TYPE_NONE, 1,
145                   GIMP_TYPE_DYNAMICS);
146 
147   object_class->finalize                    = gimp_brush_core_finalize;
148 
149   paint_core_class->start                   = gimp_brush_core_start;
150   paint_core_class->pre_paint               = gimp_brush_core_pre_paint;
151   paint_core_class->post_paint              = gimp_brush_core_post_paint;
152   paint_core_class->interpolate             = gimp_brush_core_interpolate;
153   paint_core_class->get_paint_buffer        = gimp_brush_core_get_paint_buffer;
154 
155   klass->handles_changing_brush             = FALSE;
156   klass->handles_transforming_brush         = TRUE;
157   klass->handles_dynamic_transforming_brush = TRUE;
158 
159   klass->set_brush                          = gimp_brush_core_real_set_brush;
160   klass->set_dynamics                       = gimp_brush_core_real_set_dynamics;
161 }
162 
163 static void
gimp_brush_core_init(GimpBrushCore * core)164 gimp_brush_core_init (GimpBrushCore *core)
165 {
166   gint i, j;
167 
168   core->main_brush                   = NULL;
169   core->brush                        = NULL;
170   core->dynamics                     = NULL;
171   core->spacing                      = 1.0;
172   core->scale                        = 1.0;
173   core->angle                        = 0.0;
174   core->reflect                      = FALSE;
175   core->hardness                     = 1.0;
176   core->aspect_ratio                 = 0.0;
177 
178   core->symmetry_angle               = 0.0;
179   core->symmetry_reflect             = FALSE;
180 
181   core->pressure_brush               = NULL;
182 
183   core->last_solid_brush_mask        = NULL;
184   core->solid_cache_invalid          = FALSE;
185 
186   core->transform_brush              = NULL;
187   core->transform_pixmap             = NULL;
188 
189   core->last_subsample_brush_mask    = NULL;
190   core->subsample_cache_invalid      = FALSE;
191 
192   core->rand                         = g_rand_new ();
193 
194   for (i = 0; i < BRUSH_CORE_SOLID_SUBSAMPLE; i++)
195     {
196       for (j = 0; j < BRUSH_CORE_SOLID_SUBSAMPLE; j++)
197         {
198           core->solid_brushes[i][j] = NULL;
199         }
200     }
201 
202   for (i = 0; i < BRUSH_CORE_JITTER_LUTSIZE - 1; ++i)
203     {
204       core->jitter_lut_y[i] = cos (gimp_deg_to_rad (i * 360 /
205                                                     BRUSH_CORE_JITTER_LUTSIZE));
206       core->jitter_lut_x[i] = sin (gimp_deg_to_rad (i * 360 /
207                                                     BRUSH_CORE_JITTER_LUTSIZE));
208     }
209 
210   gimp_assert (BRUSH_CORE_SUBSAMPLE == KERNEL_SUBSAMPLE);
211 
212   for (i = 0; i < KERNEL_SUBSAMPLE + 1; i++)
213     {
214       for (j = 0; j < KERNEL_SUBSAMPLE + 1; j++)
215         {
216           core->subsample_brushes[i][j] = NULL;
217         }
218     }
219 }
220 
221 static void
gimp_brush_core_finalize(GObject * object)222 gimp_brush_core_finalize (GObject *object)
223 {
224   GimpBrushCore *core = GIMP_BRUSH_CORE (object);
225   gint           i, j;
226 
227   g_clear_pointer (&core->pressure_brush, gimp_temp_buf_unref);
228 
229   for (i = 0; i < BRUSH_CORE_SOLID_SUBSAMPLE; i++)
230     for (j = 0; j < BRUSH_CORE_SOLID_SUBSAMPLE; j++)
231       g_clear_pointer (&core->solid_brushes[i][j], gimp_temp_buf_unref);
232 
233   g_clear_pointer (&core->rand, g_rand_free);
234 
235   for (i = 0; i < KERNEL_SUBSAMPLE + 1; i++)
236     for (j = 0; j < KERNEL_SUBSAMPLE + 1; j++)
237       g_clear_pointer (&core->subsample_brushes[i][j], gimp_temp_buf_unref);
238 
239   if (core->main_brush)
240     {
241       g_signal_handlers_disconnect_by_func (core->main_brush,
242                                             gimp_brush_core_invalidate_cache,
243                                             core);
244       gimp_brush_end_use (core->main_brush);
245       g_clear_object (&core->main_brush);
246     }
247 
248   g_clear_object (&core->dynamics);
249 
250   G_OBJECT_CLASS (parent_class)->finalize (object);
251 }
252 
253 static gboolean
gimp_brush_core_pre_paint(GimpPaintCore * paint_core,GimpDrawable * drawable,GimpPaintOptions * paint_options,GimpPaintState paint_state,guint32 time)254 gimp_brush_core_pre_paint (GimpPaintCore    *paint_core,
255                            GimpDrawable     *drawable,
256                            GimpPaintOptions *paint_options,
257                            GimpPaintState    paint_state,
258                            guint32           time)
259 {
260   GimpBrushCore *core = GIMP_BRUSH_CORE (paint_core);
261 
262   if (paint_state == GIMP_PAINT_STATE_MOTION)
263     {
264       GimpCoords last_coords;
265       GimpCoords current_coords;
266       gdouble scale;
267 
268       gimp_paint_core_get_last_coords (paint_core, &last_coords);
269       gimp_paint_core_get_current_coords (paint_core, &current_coords);
270 
271       /* If we current point == last point, check if the brush
272        * wants to be painted in that case. (Direction dependent
273        * pixmap brush pipes don't, as they don't know which
274        * pixmap to select.)
275        */
276       if (last_coords.x == current_coords.x &&
277           last_coords.y == current_coords.y &&
278           ! gimp_brush_want_null_motion (core->main_brush,
279                                          &last_coords,
280                                          &current_coords))
281         {
282           return FALSE;
283         }
284       /*No drawing anything if the scale is too small*/
285       if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_transforming_brush)
286         {
287           GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
288           gdouble    fade_point;
289 
290           if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_dynamic_transforming_brush)
291             {
292               gdouble width;
293               gdouble height;
294 
295               fade_point = gimp_paint_options_get_fade (paint_options, image,
296                                                         paint_core->pixel_dist);
297               width = gimp_brush_get_width  (core->main_brush);
298               height = gimp_brush_get_height (core->main_brush);
299 
300               scale = paint_options->brush_size /
301                       MAX (width, height) *
302                       gimp_dynamics_get_linear_value (core->dynamics,
303                                                       GIMP_DYNAMICS_OUTPUT_SIZE,
304                                                       &current_coords,
305                                                       paint_options,
306                                                       fade_point);
307 
308               if (paint_options->brush_lock_to_view &&
309                   MAX (current_coords.xscale, current_coords.yscale) > 0)
310                 {
311                   scale /= MAX (current_coords.xscale, current_coords.yscale);
312 
313                   /* Cap transform result for brushes or OOM can occur */
314                   if ((scale * MAX (width, height)) > GIMP_BRUSH_MAX_SIZE)
315                     {
316                       scale = GIMP_BRUSH_MAX_SIZE / MAX (width, height);
317                     }
318                 }
319 
320               if (scale < 0.0000001)
321                 return FALSE;
322             }
323         }
324 
325       if (GIMP_BRUSH_CORE_GET_CLASS (paint_core)->handles_changing_brush)
326         {
327           core->brush = gimp_brush_select_brush (core->main_brush,
328                                                  &last_coords,
329                                                  &current_coords);
330         }
331       if ((! GIMP_IS_BRUSH_GENERATED(core->main_brush)) &&
332           (paint_options->brush_hardness != gimp_brush_get_blur_hardness(core->main_brush)))
333         {
334           gimp_brush_flush_blur_caches(core->main_brush);
335         }
336     }
337 
338   return TRUE;
339 }
340 
341 static void
gimp_brush_core_post_paint(GimpPaintCore * paint_core,GimpDrawable * drawable,GimpPaintOptions * paint_options,GimpPaintState paint_state,guint32 time)342 gimp_brush_core_post_paint (GimpPaintCore    *paint_core,
343                             GimpDrawable     *drawable,
344                             GimpPaintOptions *paint_options,
345                             GimpPaintState    paint_state,
346                             guint32           time)
347 {
348   GimpBrushCore *core = GIMP_BRUSH_CORE (paint_core);
349 
350   if (paint_state == GIMP_PAINT_STATE_MOTION)
351     {
352       core->brush = core->main_brush;
353     }
354 }
355 
356 static gboolean
gimp_brush_core_start(GimpPaintCore * paint_core,GimpDrawable * drawable,GimpPaintOptions * paint_options,const GimpCoords * coords,GError ** error)357 gimp_brush_core_start (GimpPaintCore     *paint_core,
358                        GimpDrawable      *drawable,
359                        GimpPaintOptions  *paint_options,
360                        const GimpCoords  *coords,
361                        GError           **error)
362 {
363   GimpBrushCore *core    = GIMP_BRUSH_CORE (paint_core);
364   GimpContext   *context = GIMP_CONTEXT (paint_options);
365 
366   gimp_brush_core_set_brush (core, gimp_context_get_brush (context));
367 
368   gimp_brush_core_set_dynamics (core, gimp_context_get_dynamics (context));
369 
370   if (! core->main_brush)
371     {
372       g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
373                            _("No brushes available for use with this tool."));
374       return FALSE;
375     }
376 
377   if (! core->dynamics)
378     {
379       g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
380                            _("No paint dynamics available for use with this tool."));
381       return FALSE;
382     }
383 
384   if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_transforming_brush)
385     {
386       gimp_brush_core_eval_transform_dynamics (core,
387                                                drawable,
388                                                paint_options,
389                                                coords);
390 
391       gimp_brush_core_eval_transform_symmetry (core, NULL, 0);
392     }
393 
394   core->spacing = paint_options->brush_spacing;
395 
396   core->brush = core->main_brush;
397 
398   core->jitter =
399     gimp_paint_options_get_jitter (paint_options,
400                                    gimp_item_get_image (GIMP_ITEM (drawable)));
401 
402   return TRUE;
403 }
404 
405 /**
406  * gimp_avoid_exact_integer
407  * @x: points to a gdouble
408  *
409  * Adjusts *x such that it is not too close to an integer. This is used
410  * for decision algorithms that would be vulnerable to rounding glitches
411  * if exact integers were input.
412  *
413  * Side effects: Changes the value of *x
414  **/
415 static void
gimp_avoid_exact_integer(gdouble * x)416 gimp_avoid_exact_integer (gdouble *x)
417 {
418   const gdouble integral   = floor (*x);
419   const gdouble fractional = *x - integral;
420 
421   if (fractional < EPSILON)
422     {
423       *x = integral + EPSILON;
424     }
425   else if (fractional > (1 -EPSILON))
426     {
427       *x = integral + (1 - EPSILON);
428     }
429 }
430 
431 static void
gimp_brush_core_interpolate(GimpPaintCore * paint_core,GimpDrawable * drawable,GimpPaintOptions * paint_options,guint32 time)432 gimp_brush_core_interpolate (GimpPaintCore    *paint_core,
433                              GimpDrawable     *drawable,
434                              GimpPaintOptions *paint_options,
435                              guint32           time)
436 {
437   GimpBrushCore      *core  = GIMP_BRUSH_CORE (paint_core);
438   GimpImage          *image = gimp_item_get_image (GIMP_ITEM (drawable));
439   GimpDynamicsOutput *spacing_output;
440   GimpCoords          last_coords;
441   GimpCoords          current_coords;
442   GimpVector2         delta_vec;
443   gdouble             delta_pressure;
444   gdouble             delta_xtilt, delta_ytilt;
445   gdouble             delta_wheel;
446   gdouble             delta_velocity;
447   gdouble             temp_direction;
448   GimpVector2         temp_vec;
449   gint                n, num_points;
450   gdouble             t0, dt, tn;
451   gdouble             st_factor, st_offset;
452   gdouble             initial;
453   gdouble             dist;
454   gdouble             total;
455   gdouble             pixel_dist;
456   gdouble             pixel_initial;
457   gdouble             xd, yd;
458   gdouble             mag;
459   gdouble             dyn_spacing = core->spacing;
460   gdouble             fade_point;
461   gboolean            use_dyn_spacing;
462 
463   g_return_if_fail (GIMP_IS_BRUSH (core->brush));
464 
465   gimp_paint_core_get_last_coords (paint_core, &last_coords);
466   gimp_paint_core_get_current_coords (paint_core, &current_coords);
467 
468   gimp_avoid_exact_integer (&last_coords.x);
469   gimp_avoid_exact_integer (&last_coords.y);
470   gimp_avoid_exact_integer (&current_coords.x);
471   gimp_avoid_exact_integer (&current_coords.y);
472 
473   delta_vec.x    = current_coords.x        - last_coords.x;
474   delta_vec.y    = current_coords.y        - last_coords.y;
475   delta_pressure = current_coords.pressure - last_coords.pressure;
476   delta_xtilt    = current_coords.xtilt    - last_coords.xtilt;
477   delta_ytilt    = current_coords.ytilt    - last_coords.ytilt;
478   delta_wheel    = current_coords.wheel    - last_coords.wheel;
479   delta_velocity = current_coords.velocity - last_coords.velocity;
480   temp_direction = current_coords.direction;
481 
482   /*  return if there has been no motion  */
483   if (! delta_vec.x    &&
484       ! delta_vec.y    &&
485       ! delta_pressure &&
486       ! delta_xtilt    &&
487       ! delta_ytilt    &&
488       ! delta_wheel    &&
489       ! delta_velocity)
490     return;
491 
492   pixel_dist    = gimp_vector2_length (&delta_vec);
493   pixel_initial = paint_core->pixel_dist;
494 
495   /*  Zero sized brushes are unfit for interpolate, so we just let
496    *  paint core fail on its own
497    */
498   if (core->scale == 0.0)
499     {
500       gimp_paint_core_set_last_coords (paint_core, &current_coords);
501 
502       gimp_paint_core_paint (paint_core, drawable, paint_options,
503                              GIMP_PAINT_STATE_MOTION, time);
504 
505       paint_core->pixel_dist = pixel_initial + pixel_dist; /* Don't forget to update pixel distance*/
506 
507       return;
508     }
509 
510   /* Handle dynamic spacing */
511   spacing_output = gimp_dynamics_get_output (core->dynamics,
512                                              GIMP_DYNAMICS_OUTPUT_SPACING);
513 
514   fade_point = gimp_paint_options_get_fade (paint_options, image,
515                                             paint_core->pixel_dist);
516 
517   use_dyn_spacing = gimp_dynamics_output_is_enabled (spacing_output);
518 
519   if (use_dyn_spacing)
520     {
521       dyn_spacing = gimp_dynamics_output_get_linear_value (spacing_output,
522                                                            &current_coords,
523                                                            paint_options,
524                                                            fade_point);
525 
526       /* Dynamic spacing assumes that the value set in core is the min
527        * value and the max is full 200% spacing. This approach differs
528        * from the usual factor from user input approach because making
529        * spacing smaller than the nominal value is unlikely and
530        * spacing has a hard defined max.
531        */
532       dyn_spacing = (core->spacing +
533                      ((2.0 - core->spacing) * (1.0 - dyn_spacing)));
534 
535       /*  Limiting spacing to minimum 1%  */
536       dyn_spacing = MAX (core->spacing, dyn_spacing);
537     }
538 
539   /* calculate the distance traveled in the coordinate space of the brush */
540   temp_vec = gimp_brush_get_x_axis (core->brush);
541   gimp_vector2_mul (&temp_vec, core->scale);
542   gimp_vector2_rotate (&temp_vec, core->angle * G_PI * 2);
543 
544   mag = gimp_vector2_length (&temp_vec);
545   xd  = gimp_vector2_inner_product (&delta_vec, &temp_vec) / (mag * mag);
546 
547   temp_vec = gimp_brush_get_y_axis (core->brush);
548   gimp_vector2_mul (&temp_vec, core->scale);
549   gimp_vector2_rotate (&temp_vec, core->angle * G_PI * 2);
550 
551   mag = gimp_vector2_length (&temp_vec);
552   yd  = gimp_vector2_inner_product (&delta_vec, &temp_vec) / (mag * mag);
553 
554   dist    = 0.5 * sqrt (xd * xd + yd * yd);
555   total   = dist + paint_core->distance;
556   initial = paint_core->distance;
557 
558 
559   if (delta_vec.x * delta_vec.x > delta_vec.y * delta_vec.y)
560     {
561       st_factor = delta_vec.x;
562       st_offset = last_coords.x - 0.5;
563     }
564   else
565     {
566       st_factor = delta_vec.y;
567       st_offset = last_coords.y - 0.5;
568     }
569 
570   if (use_dyn_spacing)
571     {
572       gint s0;
573 
574       num_points = dist / dyn_spacing;
575 
576       s0 = (gint) floor (st_offset + 0.5);
577       t0 = (s0 - st_offset) / st_factor;
578       dt = dyn_spacing / dist;
579 
580       if (num_points == 0)
581         return;
582     }
583   else if (fabs (st_factor) > dist / core->spacing)
584     {
585       /*  The stripe principle leads to brush positions that are spaced
586        *  *closer* than the official brush spacing. Use the official
587        *  spacing instead. This is the common case when the brush spacing
588        *  is large.
589        *  The net effect is then to put a lower bound on the spacing, but
590        *  one that varies with the slope of the line. This is suppose to
591        *  make thin lines (say, with a 1x1 brush) prettier while leaving
592        *  lines with larger brush spacing as they used to look in 1.2.x.
593        */
594 
595       dt = core->spacing / dist;
596       n = (gint) (initial / core->spacing + 1.0 + EPSILON);
597       t0 = (n * core->spacing - initial) / dist;
598       num_points = 1 + (gint) floor ((1 + EPSILON - t0) / dt);
599 
600       /* if we arnt going to paint anything this time and the brush
601        * has only moved on one axis return without updating the brush
602        * position, distance etc. so that we can more accurately space
603        * brush strokes when curves are supplied to us in single pixel
604        * chunks.
605        */
606 
607       if (num_points == 0 && (delta_vec.x == 0 || delta_vec.y == 0))
608         return;
609     }
610   else if (fabs (st_factor) < EPSILON)
611     {
612       /* Hm, we've hardly moved at all. Don't draw anything, but reset the
613        * old coordinates and hope we've gone longer the next time...
614        */
615       current_coords.x = last_coords.x;
616       current_coords.y = last_coords.y;
617 
618       gimp_paint_core_set_current_coords (paint_core, &current_coords);
619 
620       /* ... but go along with the current pressure, tilt and wheel */
621       return;
622     }
623   else
624     {
625       gint direction = st_factor > 0 ? 1 : -1;
626       gint x, y;
627       gint s0, sn;
628 
629       /*  Choose the first and last stripe to paint.
630        *    FIRST PRIORITY is to avoid gaps painting with a 1x1 aliasing
631        *  brush when a horizontalish line segment follows a verticalish
632        *  one or vice versa - no matter what the angle between the two
633        *  lines is. This will also limit the local thinning that a 1x1
634        *  subsampled brush may suffer in the same situation.
635        *    SECOND PRIORITY is to avoid making free-hand drawings
636        *  unpleasantly fat by plotting redundant points.
637        *    These are achieved by the following rules, but it is a little
638        *  tricky to see just why. Do not change this algorithm unless you
639        *  are sure you know what you're doing!
640        */
641 
642       /*  Basic case: round the beginning and ending point to nearest
643        *  stripe center.
644        */
645       s0 = (gint) floor (st_offset + 0.5);
646       sn = (gint) floor (st_offset + st_factor + 0.5);
647 
648       t0 = (s0 - st_offset) / st_factor;
649       tn = (sn - st_offset) / st_factor;
650 
651       x = (gint) floor (last_coords.x + t0 * delta_vec.x);
652       y = (gint) floor (last_coords.y + t0 * delta_vec.y);
653 
654       if (t0 < 0.0 && !( x == (gint) floor (last_coords.x) &&
655                          y == (gint) floor (last_coords.y) ))
656         {
657           /*  Exception A: If the first stripe's brush position is
658            *  EXTRApolated into a different pixel square than the
659            *  ideal starting point, don't plot it.
660            */
661           s0 += direction;
662         }
663       else if (x == (gint) floor (paint_core->last_paint.x) &&
664                y == (gint) floor (paint_core->last_paint.y))
665         {
666           /*  Exception B: If first stripe's brush position is within the
667            *  same pixel square as the last plot of the previous line,
668            *  don't plot it either.
669            */
670           s0 += direction;
671         }
672 
673       x = (gint) floor (last_coords.x + tn * delta_vec.x);
674       y = (gint) floor (last_coords.y + tn * delta_vec.y);
675 
676       if (tn > 1.0 && !( x == (gint) floor (current_coords.x) &&
677                          y == (gint) floor (current_coords.y)))
678         {
679           /*  Exception C: If the last stripe's brush position is
680            *  EXTRApolated into a different pixel square than the
681            *  ideal ending point, don't plot it.
682            */
683           sn -= direction;
684         }
685 
686       t0 = (s0 - st_offset) / st_factor;
687       tn = (sn - st_offset) / st_factor;
688       dt         =     direction * 1.0 / st_factor;
689       num_points = 1 + direction * (sn - s0);
690 
691       if (num_points >= 1)
692         {
693           /*  Hack the reported total distance such that it looks to the
694            *  next line as if the the last pixel plotted were at an integer
695            *  multiple of the brush spacing. This helps prevent artifacts
696            *  for connected lines when the brush spacing is such that some
697            *  slopes will use the stripe regime and other slopes will use
698            *  the nominal brush spacing.
699            */
700 
701           if (tn < 1)
702             total = initial + tn * dist;
703 
704           total = core->spacing * (gint) (total / core->spacing + 0.5);
705           total += (1.0 - tn) * dist;
706         }
707     }
708 
709   for (n = 0; n < num_points; n++)
710     {
711       gdouble t = t0 + n * dt;
712       gdouble p = (gdouble) n / num_points;
713 
714       current_coords.x         = last_coords.x        + t * delta_vec.x;
715       current_coords.y         = last_coords.y        + t * delta_vec.y;
716       current_coords.pressure  = last_coords.pressure + p * delta_pressure;
717       current_coords.xtilt     = last_coords.xtilt    + p * delta_xtilt;
718       current_coords.ytilt     = last_coords.ytilt    + p * delta_ytilt;
719       current_coords.wheel     = last_coords.wheel    + p * delta_wheel;
720       current_coords.velocity  = last_coords.velocity + p * delta_velocity;
721       current_coords.direction = temp_direction;
722       current_coords.xscale    = last_coords.xscale;
723       current_coords.yscale    = last_coords.yscale;
724       current_coords.angle     = last_coords.angle;
725       current_coords.reflect   = last_coords.reflect;
726 
727       if (core->jitter > 0.0)
728         {
729           GimpVector2 x_axis;
730           GimpVector2 y_axis;
731           gdouble     dyn_jitter;
732           gdouble     jitter_dist;
733           gint32      jitter_angle;
734 
735           x_axis = gimp_brush_get_x_axis (core->brush);
736           y_axis = gimp_brush_get_y_axis (core->brush);
737 
738           dyn_jitter = (core->jitter *
739                         gimp_dynamics_get_linear_value (core->dynamics,
740                                                         GIMP_DYNAMICS_OUTPUT_JITTER,
741                                                         &current_coords,
742                                                         paint_options,
743                                                         fade_point));
744 
745           jitter_dist  = g_rand_double_range (core->rand, 0, dyn_jitter);
746           jitter_angle = g_rand_int_range (core->rand,
747                                            0, BRUSH_CORE_JITTER_LUTSIZE);
748 
749           current_coords.x +=
750             (x_axis.x + y_axis.x) *
751             jitter_dist * core->jitter_lut_x[jitter_angle] * core->scale;
752 
753           current_coords.y +=
754             (y_axis.y + x_axis.y) *
755             jitter_dist * core->jitter_lut_y[jitter_angle] * core->scale;
756         }
757 
758       gimp_paint_core_set_current_coords (paint_core, &current_coords);
759 
760       paint_core->distance   = initial       + t * dist;
761       paint_core->pixel_dist = pixel_initial + t * pixel_dist;
762 
763       gimp_paint_core_paint (paint_core, drawable, paint_options,
764                              GIMP_PAINT_STATE_MOTION, time);
765     }
766 
767   current_coords.x        = last_coords.x        + delta_vec.x;
768   current_coords.y        = last_coords.y        + delta_vec.y;
769   current_coords.pressure = last_coords.pressure + delta_pressure;
770   current_coords.xtilt    = last_coords.xtilt    + delta_xtilt;
771   current_coords.ytilt    = last_coords.ytilt    + delta_ytilt;
772   current_coords.wheel    = last_coords.wheel    + delta_wheel;
773   current_coords.velocity = last_coords.velocity + delta_velocity;
774   current_coords.xscale   = last_coords.xscale;
775   current_coords.yscale   = last_coords.yscale;
776   current_coords.angle    = last_coords.angle;
777   current_coords.reflect  = last_coords.reflect;
778 
779   gimp_paint_core_set_current_coords (paint_core, &current_coords);
780   gimp_paint_core_set_last_coords (paint_core, &current_coords);
781 
782   paint_core->distance   = total;
783   paint_core->pixel_dist = pixel_initial + pixel_dist;
784 }
785 
786 static GeglBuffer *
gimp_brush_core_get_paint_buffer(GimpPaintCore * paint_core,GimpDrawable * drawable,GimpPaintOptions * paint_options,GimpLayerMode paint_mode,const GimpCoords * coords,gint * paint_buffer_x,gint * paint_buffer_y,gint * paint_width,gint * paint_height)787 gimp_brush_core_get_paint_buffer (GimpPaintCore    *paint_core,
788                                   GimpDrawable     *drawable,
789                                   GimpPaintOptions *paint_options,
790                                   GimpLayerMode     paint_mode,
791                                   const GimpCoords *coords,
792                                   gint             *paint_buffer_x,
793                                   gint             *paint_buffer_y,
794                                   gint             *paint_width,
795                                   gint             *paint_height)
796 {
797   GimpBrushCore *core = GIMP_BRUSH_CORE (paint_core);
798   gint           x, y;
799   gint           x1, y1, x2, y2;
800   gint           drawable_width, drawable_height;
801   gint           brush_width, brush_height;
802 
803   gimp_brush_transform_size (core->brush,
804                              core->scale, core->aspect_ratio,
805                              gimp_brush_core_get_angle (core),
806                              gimp_brush_core_get_reflect (core),
807                              &brush_width, &brush_height);
808 
809   if (paint_width)
810     *paint_width  = brush_width;
811   if (paint_height)
812     *paint_height = brush_height;
813 
814   /*  adjust the x and y coordinates to the upper left corner of the brush  */
815   x = (gint) floor (coords->x) - (brush_width  / 2);
816   y = (gint) floor (coords->y) - (brush_height / 2);
817 
818   drawable_width  = gimp_item_get_width  (GIMP_ITEM (drawable));
819   drawable_height = gimp_item_get_height (GIMP_ITEM (drawable));
820 
821   x1 = CLAMP (x - 1, 0, drawable_width);
822   y1 = CLAMP (y - 1, 0, drawable_height);
823   x2 = CLAMP (x + brush_width  + 1, 0, drawable_width);
824   y2 = CLAMP (y + brush_height + 1, 0, drawable_height);
825 
826   /*  configure the canvas buffer  */
827   if ((x2 - x1) && (y2 - y1))
828     {
829       GimpTempBuf            *temp_buf;
830       const Babl             *format;
831       GimpLayerCompositeMode  composite_mode;
832 
833       composite_mode = gimp_layer_mode_get_paint_composite_mode (paint_mode);
834 
835       format = gimp_layer_mode_get_format (paint_mode,
836                                            GIMP_LAYER_COLOR_SPACE_AUTO,
837                                            GIMP_LAYER_COLOR_SPACE_AUTO,
838                                            composite_mode,
839                                            gimp_drawable_get_format (drawable));
840 
841       if (paint_core->paint_buffer                                       &&
842           gegl_buffer_get_width  (paint_core->paint_buffer) == (x2 - x1) &&
843           gegl_buffer_get_height (paint_core->paint_buffer) == (y2 - y1) &&
844           gegl_buffer_get_format (paint_core->paint_buffer) == format)
845         {
846           *paint_buffer_x = x1;
847           *paint_buffer_y = y1;
848 
849           return paint_core->paint_buffer;
850         }
851 
852       g_clear_object (&paint_core->paint_buffer);
853 
854       temp_buf = gimp_temp_buf_new ((x2 - x1), (y2 - y1),
855                                     format);
856 
857       *paint_buffer_x = x1;
858       *paint_buffer_y = y1;
859 
860       paint_core->paint_buffer = gimp_temp_buf_create_buffer (temp_buf);
861 
862       gimp_temp_buf_unref (temp_buf);
863 
864       return paint_core->paint_buffer;
865     }
866 
867   return NULL;
868 }
869 
870 static void
gimp_brush_core_real_set_brush(GimpBrushCore * core,GimpBrush * brush)871 gimp_brush_core_real_set_brush (GimpBrushCore *core,
872                                 GimpBrush     *brush)
873 {
874   if (brush == core->main_brush)
875     return;
876 
877   if (core->main_brush)
878     {
879       g_signal_handlers_disconnect_by_func (core->main_brush,
880                                             gimp_brush_core_invalidate_cache,
881                                             core);
882       gimp_brush_end_use (core->main_brush);
883     }
884 
885   g_set_object (&core->main_brush, brush);
886 
887   if (core->main_brush)
888     {
889       gimp_brush_begin_use (core->main_brush);
890       g_signal_connect (core->main_brush, "invalidate-preview",
891                         G_CALLBACK (gimp_brush_core_invalidate_cache),
892                         core);
893     }
894 }
895 
896 static void
gimp_brush_core_real_set_dynamics(GimpBrushCore * core,GimpDynamics * dynamics)897 gimp_brush_core_real_set_dynamics (GimpBrushCore *core,
898                                    GimpDynamics  *dynamics)
899 {
900   g_set_object (&core->dynamics, dynamics);
901 }
902 
903 void
gimp_brush_core_set_brush(GimpBrushCore * core,GimpBrush * brush)904 gimp_brush_core_set_brush (GimpBrushCore *core,
905                            GimpBrush     *brush)
906 {
907   g_return_if_fail (GIMP_IS_BRUSH_CORE (core));
908   g_return_if_fail (brush == NULL || GIMP_IS_BRUSH (brush));
909 
910   if (brush != core->main_brush)
911     g_signal_emit (core, core_signals[SET_BRUSH], 0, brush);
912 }
913 
914 void
gimp_brush_core_set_dynamics(GimpBrushCore * core,GimpDynamics * dynamics)915 gimp_brush_core_set_dynamics (GimpBrushCore *core,
916                               GimpDynamics  *dynamics)
917 {
918   g_return_if_fail (GIMP_IS_BRUSH_CORE (core));
919   g_return_if_fail (dynamics == NULL || GIMP_IS_DYNAMICS (dynamics));
920 
921   if (dynamics != core->dynamics)
922     g_signal_emit (core, core_signals[SET_DYNAMICS], 0, dynamics);
923 }
924 
925 void
gimp_brush_core_paste_canvas(GimpBrushCore * core,GimpDrawable * drawable,const GimpCoords * coords,gdouble brush_opacity,gdouble image_opacity,GimpLayerMode paint_mode,GimpBrushApplicationMode brush_hardness,gdouble dynamic_force,GimpPaintApplicationMode mode)926 gimp_brush_core_paste_canvas (GimpBrushCore            *core,
927                               GimpDrawable             *drawable,
928                               const GimpCoords         *coords,
929                               gdouble                   brush_opacity,
930                               gdouble                   image_opacity,
931                               GimpLayerMode             paint_mode,
932                               GimpBrushApplicationMode  brush_hardness,
933                               gdouble                   dynamic_force,
934                               GimpPaintApplicationMode  mode)
935 {
936   const GimpTempBuf *brush_mask;
937 
938   brush_mask = gimp_brush_core_get_brush_mask (core, coords,
939                                                brush_hardness,
940                                                dynamic_force);
941 
942   if (brush_mask)
943     {
944       GimpPaintCore *paint_core = GIMP_PAINT_CORE (core);
945       gint           x;
946       gint           y;
947       gint           off_x;
948       gint           off_y;
949 
950       x = (gint) floor (coords->x) - (gimp_temp_buf_get_width  (brush_mask) >> 1);
951       y = (gint) floor (coords->y) - (gimp_temp_buf_get_height (brush_mask) >> 1);
952 
953       off_x = (x < 0) ? -x : 0;
954       off_y = (y < 0) ? -y : 0;
955 
956       gimp_paint_core_paste (paint_core, brush_mask,
957                              off_x, off_y,
958                              drawable,
959                              brush_opacity,
960                              image_opacity,
961                              paint_mode,
962                              mode);
963     }
964 }
965 
966 /* Similar to gimp_brush_core_paste_canvas, but replaces the alpha channel
967  * rather than using it to composite (i.e. transparent over opaque
968  * becomes transparent rather than opauqe.
969  */
970 void
gimp_brush_core_replace_canvas(GimpBrushCore * core,GimpDrawable * drawable,const GimpCoords * coords,gdouble brush_opacity,gdouble image_opacity,GimpBrushApplicationMode brush_hardness,gdouble dynamic_force,GimpPaintApplicationMode mode)971 gimp_brush_core_replace_canvas (GimpBrushCore            *core,
972                                 GimpDrawable             *drawable,
973                                 const GimpCoords         *coords,
974                                 gdouble                   brush_opacity,
975                                 gdouble                   image_opacity,
976                                 GimpBrushApplicationMode  brush_hardness,
977                                 gdouble                   dynamic_force,
978                                 GimpPaintApplicationMode  mode)
979 {
980   const GimpTempBuf *brush_mask;
981 
982   brush_mask = gimp_brush_core_get_brush_mask (core, coords,
983                                                brush_hardness,
984                                                dynamic_force);
985 
986   if (brush_mask)
987     {
988       GimpPaintCore *paint_core = GIMP_PAINT_CORE (core);
989       gint           x;
990       gint           y;
991       gint           off_x;
992       gint           off_y;
993 
994       x = (gint) floor (coords->x) - (gimp_temp_buf_get_width  (brush_mask) >> 1);
995       y = (gint) floor (coords->y) - (gimp_temp_buf_get_height (brush_mask) >> 1);
996 
997       off_x = (x < 0) ? -x : 0;
998       off_y = (y < 0) ? -y : 0;
999 
1000       gimp_paint_core_replace (paint_core, brush_mask,
1001                                off_x, off_y,
1002                                drawable,
1003                                brush_opacity,
1004                                image_opacity,
1005                                mode);
1006     }
1007 }
1008 
1009 
1010 static void
gimp_brush_core_invalidate_cache(GimpBrush * brush,GimpBrushCore * core)1011 gimp_brush_core_invalidate_cache (GimpBrush     *brush,
1012                                   GimpBrushCore *core)
1013 {
1014   /* Make sure we don't cache data for a brush that has changed */
1015 
1016   core->subsample_cache_invalid = TRUE;
1017   core->solid_cache_invalid     = TRUE;
1018 
1019   /* Notify of the brush change */
1020 
1021   g_signal_emit (core, core_signals[SET_BRUSH], 0, brush);
1022 }
1023 
1024 
1025 /************************************************************
1026  *             LOCAL FUNCTION DEFINITIONS                   *
1027  ************************************************************/
1028 
1029 static gdouble
gimp_brush_core_get_angle(GimpBrushCore * core)1030 gimp_brush_core_get_angle (GimpBrushCore *core)
1031 {
1032   gdouble angle = core->angle;
1033 
1034   if (core->reflect)
1035     angle -= core->symmetry_angle;
1036   else
1037     angle += core->symmetry_angle;
1038 
1039   angle = fmod (angle, 1.0);
1040 
1041   if (angle < 0.0)
1042     angle += 1.0;
1043 
1044   return angle;
1045 }
1046 
1047 static gboolean
gimp_brush_core_get_reflect(GimpBrushCore * core)1048 gimp_brush_core_get_reflect (GimpBrushCore *core)
1049 {
1050   return core->reflect ^ core->symmetry_reflect;
1051 }
1052 
1053 static const GimpTempBuf *
gimp_brush_core_transform_mask(GimpBrushCore * core,GimpBrush * brush)1054 gimp_brush_core_transform_mask (GimpBrushCore *core,
1055                                 GimpBrush     *brush)
1056 {
1057   const GimpTempBuf *mask;
1058 
1059   if (core->scale <= 0.0)
1060     return NULL;
1061 
1062   mask = gimp_brush_transform_mask (brush,
1063                                     core->scale,
1064                                     core->aspect_ratio,
1065                                     gimp_brush_core_get_angle (core),
1066                                     gimp_brush_core_get_reflect (core),
1067                                     core->hardness);
1068 
1069   if (mask == core->transform_brush)
1070     return mask;
1071 
1072   core->transform_brush         = mask;
1073   core->subsample_cache_invalid = TRUE;
1074   core->solid_cache_invalid     = TRUE;
1075 
1076   return core->transform_brush;
1077 }
1078 
1079 const GimpTempBuf *
gimp_brush_core_get_brush_mask(GimpBrushCore * core,const GimpCoords * coords,GimpBrushApplicationMode brush_hardness,gdouble dynamic_force)1080 gimp_brush_core_get_brush_mask (GimpBrushCore            *core,
1081                                 const GimpCoords         *coords,
1082                                 GimpBrushApplicationMode  brush_hardness,
1083                                 gdouble                   dynamic_force)
1084 {
1085   const GimpTempBuf *mask;
1086 
1087   if (dynamic_force <= 0.0)
1088     return NULL;
1089 
1090   mask = gimp_brush_core_transform_mask (core, core->brush);
1091 
1092   if (! mask)
1093     return NULL;
1094 
1095   switch (brush_hardness)
1096     {
1097     case GIMP_BRUSH_SOFT:
1098       return gimp_brush_core_subsample_mask (core, mask,
1099                                              coords->x,
1100                                              coords->y);
1101       break;
1102 
1103     case GIMP_BRUSH_HARD:
1104       return gimp_brush_core_solidify_mask (core, mask,
1105                                             coords->x,
1106                                             coords->y);
1107       break;
1108 
1109     case GIMP_BRUSH_PRESSURE:
1110       return gimp_brush_core_pressurize_mask (core, mask,
1111                                               coords->x,
1112                                               coords->y,
1113                                               dynamic_force);
1114       break;
1115     }
1116 
1117   g_return_val_if_reached (NULL);
1118 }
1119 
1120 const GimpTempBuf *
gimp_brush_core_get_brush_pixmap(GimpBrushCore * core)1121 gimp_brush_core_get_brush_pixmap (GimpBrushCore *core)
1122 {
1123   const GimpTempBuf *pixmap;
1124 
1125   if (core->scale <= 0.0)
1126     return NULL;
1127 
1128   pixmap = gimp_brush_transform_pixmap (core->brush,
1129                                         core->scale,
1130                                         core->aspect_ratio,
1131                                         gimp_brush_core_get_angle (core),
1132                                         gimp_brush_core_get_reflect (core),
1133                                         core->hardness);
1134 
1135   if (pixmap == core->transform_pixmap)
1136     return pixmap;
1137 
1138   core->transform_pixmap        = pixmap;
1139   core->subsample_cache_invalid = TRUE;
1140 
1141   return core->transform_pixmap;
1142 }
1143 
1144 void
gimp_brush_core_eval_transform_dynamics(GimpBrushCore * core,GimpDrawable * drawable,GimpPaintOptions * paint_options,const GimpCoords * coords)1145 gimp_brush_core_eval_transform_dynamics (GimpBrushCore     *core,
1146                                          GimpDrawable      *drawable,
1147                                          GimpPaintOptions  *paint_options,
1148                                          const GimpCoords  *coords)
1149 {
1150   if (core->main_brush)
1151     {
1152       gdouble max_side;
1153 
1154       max_side = MAX (gimp_brush_get_width  (core->main_brush),
1155                       gimp_brush_get_height (core->main_brush));
1156 
1157       core->scale = paint_options->brush_size / max_side;
1158 
1159       if (paint_options->brush_lock_to_view &&
1160           MAX (coords->xscale, coords->yscale) > 0)
1161         {
1162           core->scale /= MAX (coords->xscale, coords->yscale);
1163 
1164           /* Cap transform result for brushes or OOM can occur */
1165           if ((core->scale * max_side) > GIMP_BRUSH_MAX_SIZE)
1166             {
1167               core->scale = GIMP_BRUSH_MAX_SIZE / max_side;
1168             }
1169         }
1170    }
1171   else
1172     core->scale = -1;
1173 
1174   core->aspect_ratio = paint_options->brush_aspect_ratio;
1175   core->angle        = paint_options->brush_angle;
1176   core->reflect      = FALSE;
1177   core->hardness     = paint_options->brush_hardness;
1178 
1179   if (paint_options->brush_lock_to_view)
1180     {
1181       core->angle   += coords->angle;
1182       core->reflect  = coords->reflect;
1183     }
1184 
1185   if (! GIMP_IS_DYNAMICS (core->dynamics))
1186     return;
1187 
1188   if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_dynamic_transforming_brush)
1189     {
1190       gdouble fade_point = 1.0;
1191 
1192       if (drawable)
1193         {
1194           GimpImage     *image      = gimp_item_get_image (GIMP_ITEM (drawable));
1195           GimpPaintCore *paint_core = GIMP_PAINT_CORE (core);
1196 
1197           fade_point = gimp_paint_options_get_fade (paint_options, image,
1198                                                     paint_core->pixel_dist);
1199         }
1200 
1201       core->scale *= gimp_dynamics_get_linear_value (core->dynamics,
1202                                                      GIMP_DYNAMICS_OUTPUT_SIZE,
1203                                                      coords,
1204                                                      paint_options,
1205                                                      fade_point);
1206 
1207       core->angle += gimp_dynamics_get_angular_value (core->dynamics,
1208                                                       GIMP_DYNAMICS_OUTPUT_ANGLE,
1209                                                       coords,
1210                                                       paint_options,
1211                                                       fade_point);
1212 
1213       core->hardness *= gimp_dynamics_get_linear_value (core->dynamics,
1214                                                         GIMP_DYNAMICS_OUTPUT_HARDNESS,
1215                                                         coords,
1216                                                         paint_options,
1217                                                         fade_point);
1218 
1219       if (gimp_dynamics_is_output_enabled (core->dynamics,
1220                                            GIMP_DYNAMICS_OUTPUT_ASPECT_RATIO))
1221         {
1222           gdouble dyn_aspect;
1223 
1224           dyn_aspect = gimp_dynamics_get_aspect_value (core->dynamics,
1225                                                        GIMP_DYNAMICS_OUTPUT_ASPECT_RATIO,
1226                                                        coords,
1227                                                        paint_options,
1228                                                        fade_point);
1229 
1230           /* Zero aspect ratio is special cased to half of all ar range,
1231            * to force dynamics to have any effect. Forcing to full results
1232            * in disappearing stamp if applied to maximum.
1233            */
1234           if (core->aspect_ratio == 0.0)
1235             core->aspect_ratio = 10.0 * dyn_aspect;
1236           else
1237             core->aspect_ratio *= dyn_aspect;
1238         }
1239     }
1240 }
1241 
1242 void
gimp_brush_core_eval_transform_symmetry(GimpBrushCore * core,GimpSymmetry * symmetry,gint stroke)1243 gimp_brush_core_eval_transform_symmetry (GimpBrushCore *core,
1244                                          GimpSymmetry  *symmetry,
1245                                          gint           stroke)
1246 {
1247   g_return_if_fail (GIMP_IS_BRUSH_CORE (core));
1248   g_return_if_fail (symmetry == NULL || GIMP_IS_SYMMETRY (symmetry));
1249 
1250   core->symmetry_angle   = 0.0;
1251   core->symmetry_reflect = FALSE;
1252 
1253   if (symmetry)
1254     {
1255       gimp_symmetry_get_transform (symmetry,
1256                                    stroke,
1257                                    &core->symmetry_angle,
1258                                    &core->symmetry_reflect);
1259 
1260       core->symmetry_angle /= 360.0;
1261     }
1262 }
1263 
1264 void
gimp_brush_core_color_area_with_pixmap(GimpBrushCore * core,GimpDrawable * drawable,const GimpCoords * coords,GeglBuffer * area,gint area_x,gint area_y,gboolean apply_mask)1265 gimp_brush_core_color_area_with_pixmap (GimpBrushCore    *core,
1266                                         GimpDrawable     *drawable,
1267                                         const GimpCoords *coords,
1268                                         GeglBuffer       *area,
1269                                         gint              area_x,
1270                                         gint              area_y,
1271                                         gboolean          apply_mask)
1272 {
1273   const GimpTempBuf *pixmap;
1274   GeglBuffer        *pixmap_buffer;
1275   const GimpTempBuf *mask;
1276   GeglBuffer        *mask_buffer;
1277   gint               area_width;
1278   gint               area_height;
1279   gint               ul_x;
1280   gint               ul_y;
1281   gint               offset_x;
1282   gint               offset_y;
1283 
1284   g_return_if_fail (GIMP_IS_BRUSH (core->brush));
1285   g_return_if_fail (gimp_brush_get_pixmap (core->brush) != NULL);
1286 
1287   /*  scale the brush  */
1288   pixmap = gimp_brush_core_get_brush_pixmap (core);
1289 
1290   if (! pixmap)
1291     return;
1292 
1293   if (apply_mask)
1294     mask = gimp_brush_core_transform_mask (core, core->brush);
1295   else
1296     mask = NULL;
1297 
1298   /*  Calculate upper left corner of brush as in
1299    *  gimp_paint_core_get_paint_area.  Ugly to have to do this here, too.
1300    */
1301   ul_x = (gint) floor (coords->x) - (gimp_temp_buf_get_width  (pixmap) >> 1);
1302   ul_y = (gint) floor (coords->y) - (gimp_temp_buf_get_height (pixmap) >> 1);
1303 
1304   /*  Not sure why this is necessary, but empirically the code does
1305    *  not work without it for even-sided brushes.  See bug #166622.
1306    */
1307   if (gimp_temp_buf_get_width (pixmap) % 2 == 0)
1308     ul_x += ROUND (coords->x) - floor (coords->x);
1309   if (gimp_temp_buf_get_height (pixmap) % 2 == 0)
1310     ul_y += ROUND (coords->y) - floor (coords->y);
1311 
1312   offset_x = area_x - ul_x;
1313   offset_y = area_y - ul_y;
1314 
1315   area_width  = gegl_buffer_get_width  (area);
1316   area_height = gegl_buffer_get_height (area);
1317 
1318   pixmap_buffer = gimp_temp_buf_create_buffer (pixmap);
1319 
1320   gimp_gegl_buffer_copy (pixmap_buffer,
1321                          GEGL_RECTANGLE (offset_x,   offset_y,
1322                                          area_width, area_height),
1323                          GEGL_ABYSS_NONE,
1324                          area,
1325                          GEGL_RECTANGLE (0,          0,
1326                                          area_width, area_height));
1327 
1328   g_object_unref (pixmap_buffer);
1329 
1330   if (mask)
1331     {
1332       mask_buffer = gimp_temp_buf_create_buffer (mask);
1333 
1334       gimp_gegl_apply_mask (mask_buffer,
1335                             GEGL_RECTANGLE (offset_x,   offset_y,
1336                                             area_width, area_height),
1337                             area,
1338                             GEGL_RECTANGLE (0,          0,
1339                                             area_width, area_height),
1340                             1.0);
1341 
1342       g_object_unref (mask_buffer);
1343     }
1344 }
1345