1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimp-gegl-loops.c
5  * Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include <string.h>
24 
25 #include <cairo.h>
26 #include <gdk-pixbuf/gdk-pixbuf.h>
27 #include <gegl.h>
28 #include <gegl-buffer-backend.h>
29 
30 extern "C"
31 {
32 
33 #include "libgimpbase/gimpbase.h"
34 #include "libgimpcolor/gimpcolor.h"
35 #include "libgimpmath/gimpmath.h"
36 
37 #include "gimp-gegl-types.h"
38 
39 #include "gimp-babl.h"
40 #include "gimp-gegl-loops.h"
41 #include "gimp-gegl-loops-sse2.h"
42 
43 #include "core/gimp-atomic.h"
44 #include "core/gimp-utils.h"
45 #include "core/gimpprogress.h"
46 
47 
48 #define PIXELS_PER_THREAD \
49   (/* each thread costs as much as */ 64.0 * 64.0 /* pixels */)
50 
51 #define SHIFTED_AREA(dest, src)                                                \
52   const GeglRectangle dest##_area_ = {                                         \
53     src##_area->x + (dest##_rect->x - src##_rect->x),                          \
54     src##_area->y + (dest##_rect->y - src##_rect->y),                          \
55     src##_area->width, src##_area->height                                      \
56   };                                                                           \
57   const GeglRectangle * const dest##_area = &dest##_area_
58 
59 
60 void
gimp_gegl_buffer_copy(GeglBuffer * src_buffer,const GeglRectangle * src_rect,GeglAbyssPolicy abyss_policy,GeglBuffer * dest_buffer,const GeglRectangle * dest_rect)61 gimp_gegl_buffer_copy (GeglBuffer          *src_buffer,
62                        const GeglRectangle *src_rect,
63                        GeglAbyssPolicy      abyss_policy,
64                        GeglBuffer          *dest_buffer,
65                        const GeglRectangle *dest_rect)
66 {
67   GeglRectangle real_dest_rect;
68 
69   g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
70   g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
71 
72   if (! src_rect)
73     src_rect = gegl_buffer_get_extent (src_buffer);
74 
75   if (! dest_rect)
76     dest_rect = src_rect;
77 
78   real_dest_rect        = *dest_rect;
79   real_dest_rect.width  = src_rect->width;
80   real_dest_rect.height = src_rect->height;
81 
82   dest_rect = &real_dest_rect;
83 
84   if (gegl_buffer_get_format (src_buffer) ==
85       gegl_buffer_get_format (dest_buffer))
86     {
87       gboolean      skip_abyss = FALSE;
88       GeglRectangle src_abyss;
89       GeglRectangle dest_abyss;
90 
91       if (abyss_policy == GEGL_ABYSS_NONE)
92         {
93           src_abyss  = *gegl_buffer_get_abyss (src_buffer);
94           dest_abyss = *gegl_buffer_get_abyss (dest_buffer);
95 
96           skip_abyss = ! (gegl_rectangle_contains (&src_abyss,  src_rect) &&
97                           gegl_rectangle_contains (&dest_abyss, dest_rect));
98         }
99 
100       if (skip_abyss)
101         {
102           if (src_buffer < dest_buffer)
103             {
104               gegl_tile_handler_lock (GEGL_TILE_HANDLER (src_buffer));
105               gegl_tile_handler_lock (GEGL_TILE_HANDLER (dest_buffer));
106             }
107           else
108             {
109               gegl_tile_handler_lock (GEGL_TILE_HANDLER (dest_buffer));
110               gegl_tile_handler_lock (GEGL_TILE_HANDLER (src_buffer));
111             }
112 
113           gegl_buffer_set_abyss (src_buffer,  src_rect);
114           gegl_buffer_set_abyss (dest_buffer, dest_rect);
115         }
116 
117       gegl_buffer_copy (src_buffer, src_rect, abyss_policy,
118                         dest_buffer, dest_rect);
119 
120       if (skip_abyss)
121         {
122           gegl_buffer_set_abyss (src_buffer,  &src_abyss);
123           gegl_buffer_set_abyss (dest_buffer, &dest_abyss);
124 
125           gegl_tile_handler_unlock (GEGL_TILE_HANDLER (src_buffer));
126           gegl_tile_handler_unlock (GEGL_TILE_HANDLER (dest_buffer));
127         }
128     }
129   else
130     {
131       gegl_parallel_distribute_area (
132         src_rect, PIXELS_PER_THREAD,
133         [=] (const GeglRectangle *src_area)
134         {
135           SHIFTED_AREA (dest, src);
136 
137           gegl_buffer_copy (src_buffer, src_area, abyss_policy,
138                             dest_buffer, dest_area);
139         });
140     }
141 }
142 
143 void
gimp_gegl_clear(GeglBuffer * buffer,const GeglRectangle * rect)144 gimp_gegl_clear (GeglBuffer          *buffer,
145                  const GeglRectangle *rect)
146 {
147   const Babl *format;
148   gint        bpp;
149   gint        n_components;
150   gint        bpc;
151   gint        alpha_offset;
152 
153   g_return_if_fail (GEGL_IS_BUFFER (buffer));
154 
155   if (! rect)
156     rect = gegl_buffer_get_extent (buffer);
157 
158   format = gegl_buffer_get_format (buffer);
159 
160   if (! babl_format_has_alpha (format))
161     return;
162 
163   bpp          = babl_format_get_bytes_per_pixel (format);
164   n_components = babl_format_get_n_components (format);
165   bpc          = bpp / n_components;
166   alpha_offset = (n_components - 1) * bpc;
167 
168   gegl_parallel_distribute_area (
169     rect, PIXELS_PER_THREAD,
170     [=] (const GeglRectangle *area)
171     {
172       GeglBufferIterator *iter;
173 
174       iter = gegl_buffer_iterator_new (buffer, area, 0, format,
175                                        GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE,
176                                        1);
177 
178       while (gegl_buffer_iterator_next (iter))
179         {
180           guint8 *data = (guint8 *) iter->items[0].data;
181           gint    i;
182 
183           data += alpha_offset;
184 
185           for (i = 0; i < iter->length; i++)
186             {
187               memset (data, 0, bpc);
188 
189               data += bpp;
190             }
191         }
192     });
193 }
194 
195 void
gimp_gegl_convolve(GeglBuffer * src_buffer,const GeglRectangle * src_rect,GeglBuffer * dest_buffer,const GeglRectangle * dest_rect,const gfloat * kernel,gint kernel_size,gdouble divisor,GimpConvolutionType mode,gboolean alpha_weighting)196 gimp_gegl_convolve (GeglBuffer          *src_buffer,
197                     const GeglRectangle *src_rect,
198                     GeglBuffer          *dest_buffer,
199                     const GeglRectangle *dest_rect,
200                     const gfloat        *kernel,
201                     gint                 kernel_size,
202                     gdouble              divisor,
203                     GimpConvolutionType  mode,
204                     gboolean             alpha_weighting)
205 {
206   gfloat     *src;
207   gint        src_rowstride;
208 
209   const Babl *src_format;
210   const Babl *dest_format;
211   gint        src_components;
212   gint        dest_components;
213   gfloat      offset;
214 
215   if (! src_rect)
216     src_rect = gegl_buffer_get_extent (src_buffer);
217 
218   if (! dest_rect)
219     dest_rect = gegl_buffer_get_extent (dest_buffer);
220 
221   src_format = gegl_buffer_get_format (src_buffer);
222 
223   if (babl_format_is_palette (src_format))
224     src_format = gimp_babl_format (GIMP_RGB,
225                                    GIMP_PRECISION_FLOAT_LINEAR,
226                                    babl_format_has_alpha (src_format));
227   else
228     src_format = gimp_babl_format (gimp_babl_format_get_base_type (src_format),
229                                    GIMP_PRECISION_FLOAT_LINEAR,
230                                    babl_format_has_alpha (src_format));
231 
232   dest_format = gegl_buffer_get_format (dest_buffer);
233 
234   if (babl_format_is_palette (dest_format))
235     dest_format = gimp_babl_format (GIMP_RGB,
236                                     GIMP_PRECISION_FLOAT_LINEAR,
237                                     babl_format_has_alpha (dest_format));
238   else
239     dest_format = gimp_babl_format (gimp_babl_format_get_base_type (dest_format),
240                                     GIMP_PRECISION_FLOAT_LINEAR,
241                                     babl_format_has_alpha (dest_format));
242 
243   src_components  = babl_format_get_n_components (src_format);
244   dest_components = babl_format_get_n_components (dest_format);
245 
246   /* Get source pixel data */
247   src_rowstride = src_components * src_rect->width;
248   src = g_new (gfloat, src_rowstride * src_rect->height);
249   gegl_buffer_get (src_buffer, src_rect, 1.0, src_format, src,
250                    GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
251 
252   /*  If the mode is NEGATIVE_CONVOL, the offset should be 0.5  */
253   if (mode == GIMP_NEGATIVE_CONVOL)
254     {
255       offset = 0.5;
256       mode = GIMP_NORMAL_CONVOL;
257     }
258   else
259     {
260       offset = 0.0;
261     }
262 
263   gegl_parallel_distribute_area (
264     dest_rect, PIXELS_PER_THREAD,
265     [=] (const GeglRectangle *dest_area)
266     {
267       const gint          components  = src_components;
268       const gint          a_component = components - 1;
269       const gint          margin      = kernel_size / 2;
270       GeglBufferIterator *dest_iter;
271 
272       /* Set up dest iterator */
273       dest_iter = gegl_buffer_iterator_new (dest_buffer, dest_area, 0, dest_format,
274                                             GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 1);
275 
276       while (gegl_buffer_iterator_next (dest_iter))
277         {
278           /*  Convolve the src image using the convolution kernel, writing
279            *  to dest Convolve is not tile-enabled--use accordingly
280            */
281           gfloat     *dest    = (gfloat *) dest_iter->items[0].data;
282           const gint  x1      = 0;
283           const gint  y1      = 0;
284           const gint  x2      = src_rect->width  - 1;
285           const gint  y2      = src_rect->height - 1;
286           const gint  dest_x1 = dest_iter->items[0].roi.x;
287           const gint  dest_y1 = dest_iter->items[0].roi.y;
288           const gint  dest_x2 = dest_iter->items[0].roi.x + dest_iter->items[0].roi.width;
289           const gint  dest_y2 = dest_iter->items[0].roi.y + dest_iter->items[0].roi.height;
290           gint        x, y;
291 
292           for (y = dest_y1; y < dest_y2; y++)
293             {
294               gfloat *d = dest;
295 
296               if (alpha_weighting)
297                 {
298                   for (x = dest_x1; x < dest_x2; x++)
299                     {
300                       const gfloat *m                = kernel;
301                       gdouble       total[4]         = { 0.0, 0.0, 0.0, 0.0 };
302                       gdouble       weighted_divisor = 0.0;
303                       gint          i, j, b;
304 
305                       for (j = y - margin; j <= y + margin; j++)
306                         {
307                           for (i = x - margin; i <= x + margin; i++, m++)
308                             {
309                               gint          xx = CLAMP (i, x1, x2);
310                               gint          yy = CLAMP (j, y1, y2);
311                               const gfloat *s  = src + yy * src_rowstride + xx * components;
312                               const gfloat  a  = s[a_component];
313 
314                               if (a)
315                                 {
316                                   gdouble mult_alpha = *m * a;
317 
318                                   weighted_divisor += mult_alpha;
319 
320                                   for (b = 0; b < a_component; b++)
321                                     total[b] += mult_alpha * s[b];
322 
323                                   total[a_component] += mult_alpha;
324                                 }
325                             }
326                         }
327 
328                       if (weighted_divisor == 0.0)
329                         weighted_divisor = divisor;
330 
331                       for (b = 0; b < a_component; b++)
332                         total[b] /= weighted_divisor;
333 
334                       total[a_component] /= divisor;
335 
336                       for (b = 0; b < components; b++)
337                         {
338                           total[b] += offset;
339 
340                           if (mode != GIMP_NORMAL_CONVOL && total[b] < 0.0)
341                             total[b] = - total[b];
342 
343                           *d++ = CLAMP (total[b], 0.0, 1.0);
344                         }
345                     }
346                 }
347               else
348                 {
349                   for (x = dest_x1; x < dest_x2; x++)
350                     {
351                       const gfloat *m        = kernel;
352                       gdouble       total[4] = { 0.0, 0.0, 0.0, 0.0 };
353                       gint          i, j, b;
354 
355                       for (j = y - margin; j <= y + margin; j++)
356                         {
357                           for (i = x - margin; i <= x + margin; i++, m++)
358                             {
359                               gint          xx = CLAMP (i, x1, x2);
360                               gint          yy = CLAMP (j, y1, y2);
361                               const gfloat *s  = src + yy * src_rowstride + xx * components;
362 
363                               for (b = 0; b < components; b++)
364                                 total[b] += *m * s[b];
365                             }
366                         }
367 
368                       for (b = 0; b < components; b++)
369                         {
370                           total[b] = total[b] / divisor + offset;
371 
372                           if (mode != GIMP_NORMAL_CONVOL && total[b] < 0.0)
373                             total[b] = - total[b];
374 
375                           *d++ = CLAMP (total[b], 0.0, 1.0);
376                         }
377                     }
378                 }
379 
380               dest += dest_iter->items[0].roi.width * dest_components;
381             }
382         }
383     });
384 
385   g_free (src);
386 }
387 
388 static inline gfloat
odd_powf(gfloat x,gfloat y)389 odd_powf (gfloat x,
390           gfloat y)
391 {
392   if (x >= 0.0f)
393     return  powf ( x, y);
394   else
395     return -powf (-x, y);
396 }
397 
398 void
gimp_gegl_dodgeburn(GeglBuffer * src_buffer,const GeglRectangle * src_rect,GeglBuffer * dest_buffer,const GeglRectangle * dest_rect,gdouble exposure,GimpDodgeBurnType type,GimpTransferMode mode)399 gimp_gegl_dodgeburn (GeglBuffer          *src_buffer,
400                      const GeglRectangle *src_rect,
401                      GeglBuffer          *dest_buffer,
402                      const GeglRectangle *dest_rect,
403                      gdouble              exposure,
404                      GimpDodgeBurnType    type,
405                      GimpTransferMode     mode)
406 {
407   if (type == GIMP_DODGE_BURN_TYPE_BURN)
408     exposure = -exposure;
409 
410   if (! src_rect)
411     src_rect = gegl_buffer_get_extent (src_buffer);
412 
413   if (! dest_rect)
414     dest_rect = gegl_buffer_get_extent (dest_buffer);
415 
416   gegl_parallel_distribute_area (
417     src_rect, PIXELS_PER_THREAD,
418     [=] (const GeglRectangle *src_area)
419     {
420       GeglBufferIterator *iter;
421 
422       SHIFTED_AREA (dest, src);
423 
424       iter = gegl_buffer_iterator_new (src_buffer, src_area, 0,
425                                        babl_format ("R'G'B'A float"),
426                                        GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2);
427 
428       gegl_buffer_iterator_add (iter, dest_buffer, dest_area, 0,
429                                 babl_format ("R'G'B'A float"),
430                                 GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);
431 
432       switch (mode)
433         {
434           gfloat factor;
435 
436         case GIMP_TRANSFER_HIGHLIGHTS:
437           factor = 1.0 + exposure * (0.333333);
438 
439           while (gegl_buffer_iterator_next (iter))
440             {
441               gfloat *src   = (gfloat *) iter->items[0].data;
442               gfloat *dest  = (gfloat *) iter->items[1].data;
443               gint    count = iter->length;
444 
445               while (count--)
446                 {
447                   *dest++ = *src++ * factor;
448                   *dest++ = *src++ * factor;
449                   *dest++ = *src++ * factor;
450 
451                   *dest++ = *src++;
452                 }
453             }
454           break;
455 
456         case GIMP_TRANSFER_MIDTONES:
457           if (exposure < 0)
458             factor = 1.0 - exposure * (0.333333);
459           else
460             factor = 1.0 / (1.0 + exposure);
461 
462           while (gegl_buffer_iterator_next (iter))
463             {
464               gfloat *src   = (gfloat *) iter->items[0].data;
465               gfloat *dest  = (gfloat *) iter->items[1].data;
466               gint    count = iter->length;
467 
468               while (count--)
469                 {
470                   *dest++ = odd_powf (*src++, factor);
471                   *dest++ = odd_powf (*src++, factor);
472                   *dest++ = odd_powf (*src++, factor);
473 
474                   *dest++ = *src++;
475                 }
476             }
477           break;
478 
479         case GIMP_TRANSFER_SHADOWS:
480           if (exposure >= 0)
481             factor = 0.333333 * exposure;
482           else
483             factor = -0.333333 * exposure;
484 
485           while (gegl_buffer_iterator_next (iter))
486             {
487               gfloat *src   = (gfloat *) iter->items[0].data;
488               gfloat *dest  = (gfloat *) iter->items[1].data;
489               gint    count = iter->length;
490 
491               while (count--)
492                 {
493                   if (exposure >= 0)
494                     {
495                       gfloat s;
496 
497                       s = *src++; *dest++ = factor + s - factor * s;
498                       s = *src++; *dest++ = factor + s - factor * s;
499                       s = *src++; *dest++ = factor + s - factor * s;
500                     }
501                   else
502                     {
503                       gfloat s;
504 
505                       s = *src++;
506                       if (s < factor)
507                         *dest++ = 0;
508                       else /* factor <= value <=1 */
509                         *dest++ = (s - factor) / (1.0 - factor);
510 
511                       s = *src++;
512                       if (s < factor)
513                         *dest++ = 0;
514                       else /* factor <= value <=1 */
515                         *dest++ = (s - factor) / (1.0 - factor);
516 
517                       s = *src++;
518                       if (s < factor)
519                         *dest++ = 0;
520                       else /* factor <= value <=1 */
521                         *dest++ = (s - factor) / (1.0 - factor);
522                     }
523 
524                   *dest++ = *src++;
525                }
526             }
527           break;
528         }
529     });
530 }
531 
532 /* helper function of gimp_gegl_smudge_with_paint_process()
533    src and dest can be the same address
534  */
535 static inline void
gimp_gegl_smudge_with_paint_blend(const gfloat * src1,gfloat src1_rate,const gfloat * src2,gfloat src2_rate,gfloat * dest,gboolean no_erasing_src2)536 gimp_gegl_smudge_with_paint_blend (const gfloat *src1,
537                                    gfloat        src1_rate,
538                                    const gfloat *src2,
539                                    gfloat        src2_rate,
540                                    gfloat       *dest,
541                                    gboolean      no_erasing_src2)
542 {
543   gfloat orginal_src2_alpha;
544   gfloat src1_alpha;
545   gfloat src2_alpha;
546   gfloat result_alpha;
547   gint   b;
548 
549   orginal_src2_alpha = src2[3];
550   src1_alpha         = src1_rate * src1[3];
551   src2_alpha         = src2_rate * orginal_src2_alpha;
552   result_alpha       = src1_alpha + src2_alpha;
553 
554   if (result_alpha == 0)
555     {
556       memset (dest, 0, sizeof (gfloat) * 4);
557       return;
558     }
559 
560   for (b = 0; b < 3; b++)
561     dest[b] = (src1[b] * src1_alpha + src2[b] * src2_alpha) / result_alpha;
562 
563   if (no_erasing_src2)
564     {
565       result_alpha = MAX (result_alpha, orginal_src2_alpha);
566     }
567 
568   dest[3] = result_alpha;
569 }
570 
571 /* helper function of gimp_gegl_smudge_with_paint() */
572 static void
gimp_gegl_smudge_with_paint_process(gfloat * accum,const gfloat * canvas,gfloat * paint,gint count,const gfloat * brush_color,gfloat brush_a,gboolean no_erasing,gfloat flow,gfloat rate)573 gimp_gegl_smudge_with_paint_process (gfloat       *accum,
574                                      const gfloat *canvas,
575                                      gfloat       *paint,
576                                      gint          count,
577                                      const gfloat *brush_color,
578                                      gfloat        brush_a,
579                                      gboolean      no_erasing,
580                                      gfloat        flow,
581                                      gfloat        rate)
582 {
583   while (count--)
584     {
585       /* blend accum_buffer and canvas_buffer to accum_buffer */
586       gimp_gegl_smudge_with_paint_blend (accum, rate, canvas, 1 - rate,
587                                          accum, no_erasing);
588 
589       /* blend accum_buffer and brush color/pixmap to paint_buffer */
590       if (brush_a == 0) /* pure smudge */
591         {
592           memcpy (paint, accum, sizeof (gfloat) * 4);
593         }
594       else
595         {
596           const gfloat *src1 = brush_color ? brush_color : paint;
597 
598           gimp_gegl_smudge_with_paint_blend (src1, flow, accum, 1 - flow,
599                                              paint, no_erasing);
600         }
601 
602       accum  += 4;
603       canvas += 4;
604       paint  += 4;
605     }
606 }
607 
608 /*  smudge painting calculation. Currently only smudge tool uses this function
609  *  Accum = rate*Accum + (1-rate)*Canvas
610  *  if brush_color!=NULL
611  *    Paint = flow*brushColor + (1-flow)*Accum
612  *  else
613  *    Paint = flow*Paint + (1-flow)*Accum
614  */
615 void
gimp_gegl_smudge_with_paint(GeglBuffer * accum_buffer,const GeglRectangle * accum_rect,GeglBuffer * canvas_buffer,const GeglRectangle * canvas_rect,const GimpRGB * brush_color,GeglBuffer * paint_buffer,gboolean no_erasing,gdouble flow,gdouble rate)616 gimp_gegl_smudge_with_paint (GeglBuffer          *accum_buffer,
617                              const GeglRectangle *accum_rect,
618                              GeglBuffer          *canvas_buffer,
619                              const GeglRectangle *canvas_rect,
620                              const GimpRGB       *brush_color,
621                              GeglBuffer          *paint_buffer,
622                              gboolean             no_erasing,
623                              gdouble              flow,
624                              gdouble              rate)
625 {
626   gfloat         brush_color_float[4];
627   gfloat         brush_a = flow;
628   GeglAccessMode paint_buffer_access_mode = (brush_color ?
629                                              GEGL_ACCESS_WRITE :
630                                              GEGL_ACCESS_READWRITE);
631 #if COMPILE_SSE2_INTRINISICS
632   gboolean       sse2 = (gimp_cpu_accel_get_support () &
633                          GIMP_CPU_ACCEL_X86_SSE2);
634 #endif
635 
636   if (! accum_rect)
637     accum_rect = gegl_buffer_get_extent (accum_buffer);
638 
639   if (! canvas_rect)
640     canvas_rect = gegl_buffer_get_extent (canvas_buffer);
641 
642   /* convert brush color from double to float */
643   if (brush_color)
644     {
645       const gdouble *brush_color_ptr = &brush_color->r;
646       gint           b;
647 
648       for (b = 0; b < 4; b++)
649         brush_color_float[b] = brush_color_ptr[b];
650 
651       brush_a *= brush_color_ptr[3];
652     }
653 
654   gegl_parallel_distribute_area (
655     accum_rect, PIXELS_PER_THREAD,
656     [=] (const GeglRectangle *accum_area)
657     {
658       GeglBufferIterator *iter;
659 
660       SHIFTED_AREA (canvas, accum);
661 
662       iter = gegl_buffer_iterator_new (accum_buffer, accum_area, 0,
663                                        babl_format ("RGBA float"),
664                                        GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE, 3);
665 
666       gegl_buffer_iterator_add (iter, canvas_buffer, canvas_area, 0,
667                                 babl_format ("RGBA float"),
668                                 GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
669 
670       gegl_buffer_iterator_add (iter, paint_buffer,
671                                 GEGL_RECTANGLE (accum_area->x - accum_rect->x,
672                                                 accum_area->y - accum_rect->y,
673                                                 0, 0),
674                                 0,
675                                 babl_format ("RGBA float"),
676                                 paint_buffer_access_mode, GEGL_ABYSS_NONE);
677 
678       while (gegl_buffer_iterator_next (iter))
679         {
680           gfloat       *accum  = (gfloat *)       iter->items[0].data;
681           const gfloat *canvas = (const gfloat *) iter->items[1].data;
682           gfloat       *paint  = (gfloat *)       iter->items[2].data;
683           gint          count  = iter->length;
684 
685 #if COMPILE_SSE2_INTRINISICS
686           if (sse2 && ((guintptr) accum                                     |
687                        (guintptr) canvas                                    |
688                        (guintptr) (brush_color ? brush_color_float : paint) |
689                        (guintptr) paint) % 16 == 0)
690             {
691               gimp_gegl_smudge_with_paint_process_sse2 (accum, canvas, paint, count,
692                                                         brush_color ? brush_color_float :
693                                                                       NULL,
694                                                         brush_a,
695                                                         no_erasing, flow, rate);
696             }
697           else
698 #endif
699             {
700               gimp_gegl_smudge_with_paint_process (accum, canvas, paint, count,
701                                                    brush_color ? brush_color_float :
702                                                                  NULL,
703                                                    brush_a,
704                                                    no_erasing, flow, rate);
705             }
706         }
707     });
708 }
709 
710 void
gimp_gegl_apply_mask(GeglBuffer * mask_buffer,const GeglRectangle * mask_rect,GeglBuffer * dest_buffer,const GeglRectangle * dest_rect,gdouble opacity)711 gimp_gegl_apply_mask (GeglBuffer          *mask_buffer,
712                       const GeglRectangle *mask_rect,
713                       GeglBuffer          *dest_buffer,
714                       const GeglRectangle *dest_rect,
715                       gdouble              opacity)
716 {
717   if (! mask_rect)
718     mask_rect = gegl_buffer_get_extent (mask_buffer);
719 
720   if (! dest_rect)
721     dest_rect = gegl_buffer_get_extent (dest_buffer);
722 
723   gegl_parallel_distribute_area (
724     mask_rect, PIXELS_PER_THREAD,
725     [=] (const GeglRectangle *mask_area)
726     {
727       GeglBufferIterator *iter;
728 
729       SHIFTED_AREA (dest, mask);
730 
731       iter = gegl_buffer_iterator_new (mask_buffer, mask_area, 0,
732                                        babl_format ("Y float"),
733                                        GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2);
734 
735       gegl_buffer_iterator_add (iter, dest_buffer, dest_area, 0,
736                                 babl_format ("RGBA float"),
737                                 GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE);
738 
739       while (gegl_buffer_iterator_next (iter))
740         {
741           const gfloat *mask  = (const gfloat *) iter->items[0].data;
742           gfloat       *dest  = (gfloat *)       iter->items[1].data;
743           gint          count = iter->length;
744 
745           while (count--)
746             {
747               dest[3] *= *mask * opacity;
748 
749               mask += 1;
750               dest += 4;
751             }
752         }
753     });
754 }
755 
756 void
gimp_gegl_combine_mask(GeglBuffer * mask_buffer,const GeglRectangle * mask_rect,GeglBuffer * dest_buffer,const GeglRectangle * dest_rect,gdouble opacity)757 gimp_gegl_combine_mask (GeglBuffer          *mask_buffer,
758                         const GeglRectangle *mask_rect,
759                         GeglBuffer          *dest_buffer,
760                         const GeglRectangle *dest_rect,
761                         gdouble              opacity)
762 {
763   if (! mask_rect)
764     mask_rect = gegl_buffer_get_extent (mask_buffer);
765 
766   if (! dest_rect)
767     dest_rect = gegl_buffer_get_extent (dest_buffer);
768 
769   gegl_parallel_distribute_area (
770     mask_rect, PIXELS_PER_THREAD,
771     [=] (const GeglRectangle *mask_area)
772     {
773       GeglBufferIterator *iter;
774 
775       SHIFTED_AREA (dest, mask);
776 
777       iter = gegl_buffer_iterator_new (mask_buffer, mask_area, 0,
778                                        babl_format ("Y float"),
779                                        GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2);
780 
781       gegl_buffer_iterator_add (iter, dest_buffer, dest_area, 0,
782                                 babl_format ("Y float"),
783                                 GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE);
784 
785       while (gegl_buffer_iterator_next (iter))
786         {
787           const gfloat *mask  = (const gfloat *) iter->items[0].data;
788           gfloat       *dest  = (gfloat *)       iter->items[1].data;
789           gint          count = iter->length;
790 
791           while (count--)
792             {
793               *dest *= *mask * opacity;
794 
795               mask += 1;
796               dest += 1;
797             }
798         }
799     });
800 }
801 
802 void
gimp_gegl_combine_mask_weird(GeglBuffer * mask_buffer,const GeglRectangle * mask_rect,GeglBuffer * dest_buffer,const GeglRectangle * dest_rect,gdouble opacity,gboolean stipple)803 gimp_gegl_combine_mask_weird (GeglBuffer          *mask_buffer,
804                               const GeglRectangle *mask_rect,
805                               GeglBuffer          *dest_buffer,
806                               const GeglRectangle *dest_rect,
807                               gdouble              opacity,
808                               gboolean             stipple)
809 {
810   if (! mask_rect)
811     mask_rect = gegl_buffer_get_extent (mask_buffer);
812 
813   if (! dest_rect)
814     dest_rect = gegl_buffer_get_extent (dest_buffer);
815 
816   gegl_parallel_distribute_area (
817     mask_rect, PIXELS_PER_THREAD,
818     [=] (const GeglRectangle *mask_area)
819     {
820       GeglBufferIterator *iter;
821 
822       SHIFTED_AREA (dest, mask);
823 
824       iter = gegl_buffer_iterator_new (mask_buffer, mask_area, 0,
825                                        babl_format ("Y float"),
826                                        GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2);
827 
828       gegl_buffer_iterator_add (iter, dest_buffer, dest_area, 0,
829                                 babl_format ("Y float"),
830                                 GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE);
831 
832       while (gegl_buffer_iterator_next (iter))
833         {
834           const gfloat *mask  = (const gfloat *) iter->items[0].data;
835           gfloat       *dest  = (gfloat *)       iter->items[1].data;
836           gint          count = iter->length;
837 
838           if (stipple)
839             {
840               while (count--)
841                 {
842                   dest[0] += (1.0 - dest[0]) * *mask * opacity;
843 
844                   mask += 1;
845                   dest += 1;
846                 }
847             }
848           else
849             {
850               while (count--)
851                 {
852                   if (opacity > dest[0])
853                     dest[0] += (opacity - dest[0]) * *mask * opacity;
854 
855                   mask += 1;
856                   dest += 1;
857                 }
858             }
859         }
860     });
861 }
862 
863 void
gimp_gegl_index_to_mask(GeglBuffer * indexed_buffer,const GeglRectangle * indexed_rect,const Babl * indexed_format,GeglBuffer * mask_buffer,const GeglRectangle * mask_rect,gint index)864 gimp_gegl_index_to_mask (GeglBuffer          *indexed_buffer,
865                          const GeglRectangle *indexed_rect,
866                          const Babl          *indexed_format,
867                          GeglBuffer          *mask_buffer,
868                          const GeglRectangle *mask_rect,
869                          gint                 index)
870 {
871   if (! indexed_rect)
872     indexed_rect = gegl_buffer_get_extent (indexed_buffer);
873 
874   if (! mask_rect)
875     mask_rect = gegl_buffer_get_extent (mask_buffer);
876 
877   gegl_parallel_distribute_area (
878     indexed_rect, PIXELS_PER_THREAD,
879     [=] (const GeglRectangle *indexed_area)
880     {
881       GeglBufferIterator *iter;
882 
883       SHIFTED_AREA (mask, indexed);
884 
885       iter = gegl_buffer_iterator_new (indexed_buffer, indexed_area, 0,
886                                        indexed_format,
887                                        GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 2);
888 
889       gegl_buffer_iterator_add (iter, mask_buffer, mask_area, 0,
890                                 babl_format ("Y float"),
891                                 GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);
892 
893       while (gegl_buffer_iterator_next (iter))
894         {
895           const guchar *indexed = (const guchar *) iter->items[0].data;
896           gfloat       *mask    = (gfloat *)       iter->items[1].data;
897           gint          count   = iter->length;
898 
899           while (count--)
900             {
901               if (*indexed == index)
902                 *mask = 1.0;
903               else
904                 *mask = 0.0;
905 
906               indexed++;
907               mask++;
908             }
909         }
910     });
911 }
912 
913 static void
gimp_gegl_convert_color_profile_progress(GimpProgress * progress,gdouble value)914 gimp_gegl_convert_color_profile_progress (GimpProgress *progress,
915                                           gdouble       value)
916 {
917   if (gegl_is_main_thread ())
918     gimp_progress_set_value (progress, value);
919 }
920 
921 void
gimp_gegl_convert_color_profile(GeglBuffer * src_buffer,const GeglRectangle * src_rect,GimpColorProfile * src_profile,GeglBuffer * dest_buffer,const GeglRectangle * dest_rect,GimpColorProfile * dest_profile,GimpColorRenderingIntent intent,gboolean bpc,GimpProgress * progress)922 gimp_gegl_convert_color_profile (GeglBuffer               *src_buffer,
923                                  const GeglRectangle      *src_rect,
924                                  GimpColorProfile         *src_profile,
925                                  GeglBuffer               *dest_buffer,
926                                  const GeglRectangle      *dest_rect,
927                                  GimpColorProfile         *dest_profile,
928                                  GimpColorRenderingIntent  intent,
929                                  gboolean                  bpc,
930                                  GimpProgress             *progress)
931 {
932   GimpColorTransform *transform;
933   guint               flags = 0;
934   const Babl         *src_format;
935   const Babl         *dest_format;
936 
937   src_format  = gegl_buffer_get_format (src_buffer);
938   dest_format = gegl_buffer_get_format (dest_buffer);
939 
940   if (bpc)
941     flags |= GIMP_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION;
942 
943   flags |= GIMP_COLOR_TRANSFORM_FLAGS_NOOPTIMIZE;
944 
945   transform = gimp_color_transform_new (src_profile,  src_format,
946                                         dest_profile, dest_format,
947                                         intent,
948                                         (GimpColorTransformFlags) flags);
949 
950   if (! src_rect)
951     src_rect = gegl_buffer_get_extent (src_buffer);
952 
953   if (! dest_rect)
954     dest_rect = gegl_buffer_get_extent (dest_buffer);
955 
956   if (transform)
957     {
958       if (progress)
959         {
960           g_signal_connect_swapped (
961             transform, "progress",
962             G_CALLBACK (gimp_gegl_convert_color_profile_progress),
963             progress);
964         }
965 
966       GIMP_TIMER_START ();
967 
968       gegl_parallel_distribute_area (
969         src_rect, PIXELS_PER_THREAD,
970         [=] (const GeglRectangle *src_area)
971         {
972           SHIFTED_AREA (dest, src);
973 
974           gimp_color_transform_process_buffer (transform,
975                                                src_buffer,  src_area,
976                                                dest_buffer, dest_area);
977         });
978 
979       GIMP_TIMER_END ("converting buffer");
980 
981       g_object_unref (transform);
982     }
983   else
984     {
985       gimp_gegl_buffer_copy (src_buffer,  src_rect, GEGL_ABYSS_NONE,
986                              dest_buffer, dest_rect);
987 
988       if (progress)
989         gimp_progress_set_value (progress, 1.0);
990     }
991 }
992 
993 void
gimp_gegl_average_color(GeglBuffer * buffer,const GeglRectangle * rect,gboolean clip_to_buffer,GeglAbyssPolicy abyss_policy,const Babl * format,gpointer color)994 gimp_gegl_average_color (GeglBuffer          *buffer,
995                          const GeglRectangle *rect,
996                          gboolean             clip_to_buffer,
997                          GeglAbyssPolicy      abyss_policy,
998                          const Babl          *format,
999                          gpointer             color)
1000 {
1001   typedef struct
1002   {
1003     gfloat color[4];
1004     gint   n;
1005   } Sum;
1006 
1007   const Babl        *average_format = babl_format ("RaGaBaA float");
1008   GeglRectangle      roi;
1009   GSList * volatile  sums           = NULL;
1010   GSList            *list;
1011   Sum                average        = {};
1012   gint               c;
1013 
1014   g_return_if_fail (GEGL_IS_BUFFER (buffer));
1015   g_return_if_fail (color != NULL);
1016 
1017   if (! rect)
1018     rect = gegl_buffer_get_extent (buffer);
1019 
1020   if (! format)
1021     format = gegl_buffer_get_format (buffer);
1022 
1023   if (clip_to_buffer)
1024     gegl_rectangle_intersect (&roi, rect, gegl_buffer_get_extent (buffer));
1025   else
1026     roi = *rect;
1027 
1028   gegl_parallel_distribute_area (
1029     &roi, PIXELS_PER_THREAD,
1030     [&] (const GeglRectangle *area)
1031     {
1032       Sum                *sum;
1033       GeglBufferIterator *iter;
1034       gfloat              color[4] = {};
1035       gint                n        = 0;
1036 
1037       iter = gegl_buffer_iterator_new (buffer, area, 0, average_format,
1038                                        GEGL_BUFFER_READ, abyss_policy, 1);
1039 
1040       while (gegl_buffer_iterator_next (iter))
1041         {
1042           const gfloat *p = (const gfloat *) iter->items[0].data;
1043           gint          i;
1044 
1045           for (i = 0; i < iter->length; i++)
1046             {
1047               gint c;
1048 
1049               for (c = 0; c < 4; c++)
1050                 color[c] += p[c];
1051 
1052               p += 4;
1053             }
1054 
1055           n += iter->length;
1056         }
1057 
1058       sum = g_slice_new (Sum);
1059 
1060       memcpy (sum->color, color, sizeof (color));
1061       sum->n = n;
1062 
1063       gimp_atomic_slist_push_head (&sums, sum);
1064     });
1065 
1066   for (list = sums; list; list = g_slist_next (list))
1067     {
1068       Sum *sum = (Sum *) list->data;
1069 
1070       for (c = 0; c < 4; c++)
1071         average.color[c] += sum->color[c];
1072 
1073       average.n += sum->n;
1074 
1075       g_slice_free (Sum, sum);
1076     }
1077 
1078   g_slist_free (sums);
1079 
1080   if (average.n > 0)
1081     {
1082       for (c = 0; c < 4; c++)
1083         average.color[c] /= average.n;
1084     }
1085 
1086   babl_process (babl_fish (average_format, format), average.color, color, 1);
1087 }
1088 
1089 } /* extern "C" */
1090