1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpoperationflood.c
5  * Copyright (C) 2016 Ell
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 
22 /* Implementation of the Flood algorithm.
23  * See https://wiki.gimp.org/wiki/Algorithms:Flood for details.
24  */
25 
26 
27 #include "config.h"
28 
29 #include <string.h> /* For `memcpy()`. */
30 
31 #include <cairo.h>
32 #include <gegl.h>
33 #include <gdk-pixbuf/gdk-pixbuf.h>
34 
35 #include "libgimpbase/gimpbase.h"
36 
37 #include "operations-types.h"
38 
39 #include "gimpoperationflood.h"
40 
41 
42 /* Maximal gap, in pixels, between consecutive dirty ranges, below (and
43  * including) which they are coalesced, at the beginning of the distribution
44  * step.
45  */
46 #define GIMP_OPERATION_FLOOD_COALESCE_MAX_GAP 32
47 
48 
49 typedef struct _GimpOperationFloodSegment    GimpOperationFloodSegment;
50 typedef struct _GimpOperationFloodDirtyRange GimpOperationFloodDirtyRange;
51 typedef struct _GimpOperationFloodContext    GimpOperationFloodContext;
52 
53 
54 /* A segment. */
55 struct _GimpOperationFloodSegment
56 {
57   /* A boolean flag indicating whether the image- and ROI-virtual coordinate
58    * systems should be transposed when processing this segment.  TRUE iff the
59    * segment is vertical.
60    */
61   guint  transpose      : 1;
62 
63   /* The y-coordinate of the segment, in the ROI-virtual coordinate system. */
64   guint  y              : 8 * sizeof (guint) - 3;
65   /* The difference between the y-coordinates of the source segment and this
66    * segment, in the ROI-virtual coordinate system.  Either -1 or +1 for
67    * ordinary segments, and 0 for seed segments, as a special case.
68    *
69    * Note the use of `signed` as the type specifier.  The C standard doesn't
70    * specify the signedness of bit-fields whose type specifier is `int`, or a
71    * typedef-name defined as `int`, such as `gint`.
72    */
73   signed source_y_delta : 2;
74 
75   /* The x-coordinates of the first and last pixels of the segment, in the ROI-
76    * virtual coordinate system.  Note that this is a closed range:
77    * [x[0], x[1]].
78    */
79   gint   x[2];
80 };
81 /* Make sure the maximal image dimension fits in
82  * `GimpOperationFloodSegment::y`.
83  */
84 G_STATIC_ASSERT (GIMP_MAX_IMAGE_SIZE <= (1 << (8 * sizeof (guint) - 3)));
85 
86 /* A dirty range of the current segment. */
87 struct _GimpOperationFloodDirtyRange
88 {
89   /* A boolean flag indicating whether the range was extended, or its existing
90    * pixels were modified, during the horizontal propagation step.
91    */
92   gboolean modified;
93 
94   /* The x-coordinates of the first and last pixels of the range, in the ROI-
95    * virtual coordinate system.  Note that this is a closed range:
96    * [x[0], x[1]].
97    */
98   gint     x[2];
99 };
100 
101 /* Common parameters for the various parts of the algorithm. */
102 struct _GimpOperationFloodContext
103 {
104   /* Input image. */
105   GeglBuffer                *input;
106   /* Input image format. */
107   const Babl                *input_format;
108   /* Output image. */
109   GeglBuffer                *output;
110   /* Output image format. */
111   const Babl                *output_format;
112 
113   /* Region of interset. */
114   GeglRectangle  roi;
115 
116   /* Current segment. */
117   GimpOperationFloodSegment  segment;
118 
119   /* The following arrays hold the ground- and water-level of the current- and
120    * source-segments.  The vertical- and horizontal-propagation steps don't
121    * generally access the input and output GEGL buffers directly, but rather
122    * read from, and write to, these arrays, for efficiency.  These arrays are
123    * read-from, and written-to, the corresponding GEGL buffers before and after
124    * these steps.
125    */
126 
127   /* Ground level of the current segment, indexed by x-coordinate in the ROI-
128    * virtual coordinate system.  Only valid inside the range
129    * `[segment.x[0], segment.x[1]]`.
130    */
131   gfloat                    *ground;
132   /* Water level of the current segment, indexed by x-coordinate in the ROI-
133    * virtual coordinate system.  Initially only valid inside the range
134    * `[segment.x[0], segment.x[1]]`, but may be written-to outside this range
135    * during horizontal propagation, if the dirty ranges are extended past the
136    * bounds of the segment.
137    */
138   gfloat                    *water;
139   /* Water level of the source segment, indexed by x-coordinate in the ROI-
140    * virtual coordinate system.  Only valid inside the range
141    * `[segment.x[0], segment.x[1]]`.
142    */
143   gfloat                    *source_water;
144 
145   /* A common buffer for the water level of the current- and source-segments.
146    * `water` and `source_water` are pointers into this buffer.  This buffer is
147    * used as an optimization, in order to read the water level of both segments
148    * from the output GEGL buffer in a single call, and is otherwise not used
149    * directly (`water` and `source_water` are used to access the water level
150    * instead.)
151    */
152   gfloat                    *water_buffer;
153 };
154 
155 
156 static void          gimp_operation_flood_prepare                      (GeglOperation                     *operation);
157 static GeglRectangle gimp_operation_flood_get_required_for_output      (GeglOperation                     *self,
158                                                                         const gchar                       *input_pad,
159                                                                         const GeglRectangle               *roi);
160 static GeglRectangle gimp_operation_flood_get_cached_region            (GeglOperation                     *self,
161                                                                         const GeglRectangle               *roi);
162 
163 static void          gimp_operation_flood_process_push                 (GQueue                            *queue,
164                                                                         gboolean                           transpose,
165                                                                         gint                               y,
166                                                                         gint                               source_y_delta,
167                                                                         gint                               x0,
168                                                                         gint                               x1);
169 static void          gimp_operation_flood_process_seed                 (GQueue                            *queue,
170                                                                         const GeglRectangle               *roi);
171 static void          gimp_operation_flood_process_transform_rect       (const GimpOperationFloodContext    *ctx,
172                                                                         GeglRectangle                      *dest,
173                                                                         const GeglRectangle                *src);
174 static void          gimp_operation_flood_process_fetch                (GimpOperationFloodContext          *ctx);
175 static gint          gimp_operation_flood_process_propagate_vertical   (GimpOperationFloodContext          *ctx,
176                                                                         GimpOperationFloodDirtyRange       *dirty_ranges);
177 static void          gimp_operation_flood_process_propagate_horizontal (GimpOperationFloodContext          *ctx,
178                                                                         gint                                dir,
179                                                                         GimpOperationFloodDirtyRange       *dirty_ranges,
180                                                                         gint                                range_count);
181 static gint         gimp_operation_flood_process_coalesce              (const GimpOperationFloodContext    *ctx,
182                                                                         GimpOperationFloodDirtyRange       *dirty_ranges,
183                                                                         gint                                range_count,
184                                                                         gint                                gap);
185 static void          gimp_operation_flood_process_commit               (const GimpOperationFloodContext    *ctx,
186                                                                         const GimpOperationFloodDirtyRange *dirty_ranges,
187                                                                         gint                                range_count);
188 static void          gimp_operation_flood_process_distribute           (const GimpOperationFloodContext    *ctx,
189                                                                         GQueue                             *queue,
190                                                                         const GimpOperationFloodDirtyRange *dirty_ranges,
191                                                                         gint                                range_count);
192 static gboolean      gimp_operation_flood_process                      (GeglOperation                      *operation,
193                                                                         GeglBuffer                         *input,
194                                                                         GeglBuffer                         *output,
195                                                                         const GeglRectangle                *roi,
196                                                                         gint                                level);
197 
198 
199 G_DEFINE_TYPE (GimpOperationFlood, gimp_operation_flood,
200                GEGL_TYPE_OPERATION_FILTER)
201 
202 #define parent_class gimp_operation_flood_parent_class
203 
204 
205 /* GEGL graph for the test case. */
206 static const gchar* reference_xml = "<?xml version='1.0' encoding='UTF-8'?>"
207 "<gegl>"
208 "<node operation='gimp:flood'> </node>"
209 "<node operation='gegl:load'>"
210 "  <params>"
211 "    <param name='path'>flood-input.png</param>"
212 "  </params>"
213 "</node>"
214 "</gegl>";
215 
216 
217 static void
gimp_operation_flood_class_init(GimpOperationFloodClass * klass)218 gimp_operation_flood_class_init (GimpOperationFloodClass *klass)
219 {
220   GeglOperationClass       *operation_class = GEGL_OPERATION_CLASS (klass);
221   GeglOperationFilterClass *filter_class    = GEGL_OPERATION_FILTER_CLASS (klass);
222 
223   /* The input and output buffers must be different, since we generally need to
224    * be able to access the input-image values after having written to the
225    * output buffer.
226    */
227   operation_class->want_in_place = FALSE;
228   /* We don't want `GeglOperationFilter` to split the image across multiple
229    * threads, since this operation depends on, and affects, the image as a
230    * whole.
231    */
232   operation_class->threaded      = FALSE;
233   /* Note that both of these options are the default; we set them here for
234    * explicitness.
235    */
236 
237   gegl_operation_class_set_keys (operation_class,
238                                  "name",        "gimp:flood",
239                                  "categories",  "gimp",
240                                  "description", "GIMP Flood operation",
241                                  "reference", "https://wiki.gimp.org/wiki/Algorithms:Flood",
242                                  "reference-image", "flood-output.png",
243                                  "reference-composition", reference_xml,
244                                  NULL);
245 
246   operation_class->prepare                 = gimp_operation_flood_prepare;
247   operation_class->get_required_for_output = gimp_operation_flood_get_required_for_output;
248   operation_class->get_cached_region       = gimp_operation_flood_get_cached_region;
249 
250   filter_class->process                    = gimp_operation_flood_process;
251 }
252 
253 static void
gimp_operation_flood_init(GimpOperationFlood * self)254 gimp_operation_flood_init (GimpOperationFlood *self)
255 {
256 }
257 
258 static void
gimp_operation_flood_prepare(GeglOperation * operation)259 gimp_operation_flood_prepare (GeglOperation *operation)
260 {
261   const Babl *space = gegl_operation_get_source_space (operation, "input");
262   gegl_operation_set_format (operation, "input",  babl_format_with_space ("Y float", space));
263   gegl_operation_set_format (operation, "output", babl_format_with_space ("Y float", space));
264 }
265 
266 static GeglRectangle
gimp_operation_flood_get_required_for_output(GeglOperation * self,const gchar * input_pad,const GeglRectangle * roi)267 gimp_operation_flood_get_required_for_output (GeglOperation       *self,
268                                               const gchar         *input_pad,
269                                               const GeglRectangle *roi)
270 {
271   return *gegl_operation_source_get_bounding_box (self, "input");
272 }
273 
274 static GeglRectangle
gimp_operation_flood_get_cached_region(GeglOperation * self,const GeglRectangle * roi)275 gimp_operation_flood_get_cached_region (GeglOperation       *self,
276                                         const GeglRectangle *roi)
277 {
278   return *gegl_operation_source_get_bounding_box (self, "input");
279 }
280 
281 
282 /* Pushes a single segment into the queue. */
283 static void
gimp_operation_flood_process_push(GQueue * queue,gboolean transpose,gint y,gint source_y_delta,gint x0,gint x1)284 gimp_operation_flood_process_push (GQueue   *queue,
285                                    gboolean  transpose,
286                                    gint      y,
287                                    gint      source_y_delta,
288                                    gint      x0,
289                                    gint      x1)
290 {
291   GimpOperationFloodSegment *segment;
292 
293   segment                 = g_slice_new (GimpOperationFloodSegment);
294 
295   segment->transpose      = transpose;
296   segment->y              = y;
297   segment->source_y_delta = source_y_delta;
298   segment->x[0]           = x0;
299   segment->x[1]           = x1;
300 
301   g_queue_push_tail (queue, segment);
302 }
303 
304 /* Pushes the seed segments into the queue.  Recall that the seed segments are
305  * indicated by having their `source_y_delta` field equal 0.
306  *
307  * `roi` is given in the image-physical coordinate system.
308  */
309 static void
gimp_operation_flood_process_seed(GQueue * queue,const GeglRectangle * roi)310 gimp_operation_flood_process_seed (GQueue              *queue,
311                                    const GeglRectangle *roi)
312 {
313   if (roi->width == 0 || roi->height == 0)
314     return;
315 
316   /* Top edge. */
317   gimp_operation_flood_process_push (queue,
318                                      /* transpose      = */ FALSE,
319                                      /* y              = */ 0,
320                                      /* source_y_delta = */ 0,
321                                      /* x0             = */ 0,
322                                      /* x1             = */ roi->width - 1);
323 
324   if (roi->height == 1)
325     return;
326 
327   /* Bottom edge. */
328   gimp_operation_flood_process_push (queue,
329                                      /* transpose      = */ FALSE,
330                                      /* y              = */ roi->height - 1,
331                                      /* source_y_delta = */ 0,
332                                      /* x0             = */ 0,
333                                      /* x1             = */ roi->width - 1);
334 
335   if (roi->height == 2)
336     return;
337 
338   /* Left edge. */
339   gimp_operation_flood_process_push (queue,
340                                      /* transpose      = */ TRUE,
341                                      /* y              = */ 0,
342                                      /* source_y_delta = */ 0,
343                                      /* x0             = */ 1,
344                                      /* x1             = */ roi->height - 2);
345 
346   if (roi->width == 1)
347     return;
348 
349   /* Right edge. */
350   gimp_operation_flood_process_push (queue,
351                                      /* transpose      = */ TRUE,
352                                      /* y              = */ roi->width - 1,
353                                      /* source_y_delta = */ 0,
354                                      /* x0             = */ 1,
355                                      /* x1             = */ roi->height - 2);
356 }
357 
358 /* Transforms a `GeglRectangle` between the image-physical and image-virtual
359  * coordinate systems, in either direction, based on the attributes of the
360  * current segment (namely, its `transpose` flag.)
361  *
362  * Takes the input rectangle through `src`, and stores the result in `dest`.
363  * Both parameters may refer to the same object.
364  */
365 static void
gimp_operation_flood_process_transform_rect(const GimpOperationFloodContext * ctx,GeglRectangle * dest,const GeglRectangle * src)366 gimp_operation_flood_process_transform_rect (const GimpOperationFloodContext *ctx,
367                                              GeglRectangle                   *dest,
368                                              const GeglRectangle             *src)
369 {
370   if (! ctx->segment.transpose)
371     *dest = *src;
372   else
373     {
374       gint temp;
375 
376       temp         = src->x;
377       dest->x      = src->y;
378       dest->y      = temp;
379 
380       temp         = src->width;
381       dest->width  = src->height;
382       dest->height = temp;
383     }
384 }
385 
386 /* Reads the ground- and water-level for the current- and source-segments from
387  * the GEGL buffers into the corresponding arrays.  Sets up the `water` and
388  * `source_water` pointers of `ctx` to point to the right location in
389  * `water_buffer`.
390  */
391 static void
gimp_operation_flood_process_fetch(GimpOperationFloodContext * ctx)392 gimp_operation_flood_process_fetch (GimpOperationFloodContext *ctx)
393 {
394   /* Image-virtual and image-physical rectangles, respectively. */
395   GeglRectangle iv_rect, ip_rect;
396 
397   /* Set the horizontal extent of the rectangle to span the entire segment. */
398   iv_rect.x     = ctx->roi.x + ctx->segment.x[0];
399   iv_rect.width = ctx->segment.x[1] - ctx->segment.x[0] + 1;
400 
401   /* For reading the water level, we treat ordinary (non-seed) and seed
402    * segments differently.
403    */
404   if (ctx->segment.source_y_delta != 0)
405     {
406       /* Ordinary segment. */
407 
408       /* We set the vertical extent of the rectangle to span both the current-
409        * and the source-segments, and set the `water` and `source_water`
410        * pointers to point to two consecutive rows of the `water_buffer` array
411        * (the y-coordinate of the rectangle, and which row is above which,
412        * depends on whether the source segment is above, or below, the current
413        * one.)
414        */
415       if (ctx->segment.source_y_delta < 0)
416         {
417           iv_rect.y         = ctx->roi.y + ctx->segment.y - 1;
418           ctx->water        = ctx->water_buffer + ctx->roi.width;
419           ctx->source_water = ctx->water_buffer;
420         }
421       else
422         {
423           iv_rect.y         = ctx->roi.y + ctx->segment.y;
424           ctx->water        = ctx->water_buffer;
425           ctx->source_water = ctx->water_buffer + ctx->roi.width;
426         }
427       iv_rect.height        = 2;
428 
429       /* Transform `iv_rect` to the image-physical coordinate system, and store
430        * the result in `ip_rect`.
431        */
432       gimp_operation_flood_process_transform_rect (ctx, &ip_rect, &iv_rect);
433 
434       /* Read the water level from the output GEGL buffer into `water_buffer`.
435        *
436        * Notice the stride:  If the current segment is horizontal, then we're
437        * reading a pair of rows directly into the correct locations inside
438        * `water_buffer` (i.e., `water` and `source_water`).  On the other hand,
439        * if the current segment is vertical, then we're reading a pair of
440        * *columns*; we set the stride to 2-pixels so that the current- and
441        * source-water levels are interleaved in `water_buffer`, and reorder
442        * them below.
443        */
444       gegl_buffer_get (ctx->output, &ip_rect, 1.0, ctx->output_format,
445                        ctx->water_buffer + ctx->segment.x[0],
446                        sizeof (gfloat) *
447                        (ctx->segment.transpose ? 2 : ctx->roi.width),
448                        GEGL_ABYSS_NONE);
449 
450       /* As mentioned above, if the current segment is vertical, then the
451        * water levels of the current- and source-segments are interleaved in
452        * `water_buffer`.  We deinterleave the water levels into `water` and
453        * `source_water`, using the yet-to-be-written-to `ground` array as a
454        * temporary buffer, as necessary.
455        */
456       if (ctx->segment.transpose)
457         {
458           const gfloat *src;
459           gfloat       *dest1, *dest2, *temp;
460           gint          size, temp_size;
461           gint          i;
462 
463           src       = ctx->water_buffer + ctx->segment.x[0];
464 
465           dest1     = ctx->water_buffer + ctx->segment.x[0];
466           dest2     = ctx->water_buffer + ctx->roi.width + ctx->segment.x[0];
467           temp      = ctx->ground;
468 
469           size      = ctx->segment.x[1] - ctx->segment.x[0] + 1;
470           temp_size = MAX (0, 2 * size - ctx->roi.width);
471 
472           for (i = 0; i < temp_size; i++)
473             {
474               dest1[i] = src[2 * i];
475               temp[i]  = src[2 * i + 1];
476             }
477           for (; i < size; i++)
478             {
479               dest1[i] = src[2 * i];
480               dest2[i] = src[2 * i + 1];
481             }
482 
483           memcpy (dest2, temp, sizeof (gfloat) * temp_size);
484         }
485     }
486   else
487     {
488       /* Seed segment. */
489 
490       gint x;
491 
492       /* Set the `water` and `source_water` pointers to point to consecutive
493        * rows of the `water_buffer` array.
494        */
495       ctx->water        = ctx->water_buffer;
496       ctx->source_water = ctx->water_buffer + ctx->roi.width;
497 
498       /* Set the vertical extent of the rectangle to span a the current
499        * segment's row.
500        */
501       iv_rect.y      = ctx->roi.y + ctx->segment.y;
502       iv_rect.height = 1;
503 
504       /* Transform `iv_rect` to the image-physical coordinate system, and store
505        * the result in `ip_rect`.
506        */
507       gimp_operation_flood_process_transform_rect (ctx, &ip_rect, &iv_rect);
508 
509       /* Read the water level of the current segment from the output GEGL
510        * buffer into `water`.
511        */
512       gegl_buffer_get (ctx->output, &ip_rect, 1.0, ctx->output_format,
513                        ctx->water + ctx->segment.x[0],
514                        GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
515 
516       /* Initialize `source_water` to 0, as this is a seed segment. */
517       for (x = ctx->segment.x[0]; x <= ctx->segment.x[1]; x++)
518         ctx->source_water[x] = 0.0;
519     }
520 
521   /* Set the vertical extent of the rectangle to span a the current segment's
522    * row.
523    */
524   iv_rect.y      = ctx->roi.y + ctx->segment.y;
525   iv_rect.height = 1;
526 
527   /* Transform `iv_rect` to the image-physical coordinate system, and store the
528    * result in `ip_rect`.
529    */
530   gimp_operation_flood_process_transform_rect (ctx, &ip_rect, &iv_rect);
531 
532   /* Read the ground level of the current segment from the input GEGL buffer
533    * into `ground`.
534    */
535   gegl_buffer_get (ctx->input, &ip_rect, 1.0, ctx->input_format,
536                    ctx->ground + ctx->segment.x[0],
537                    GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
538 }
539 
540 /* Performs the vertical propagation step of the algorithm.  Writes the dirty
541  * ranges to the `dirty_ranges` parameter, and returns the number of dirty
542  * ranges as the function's result.
543  */
544 static gint
gimp_operation_flood_process_propagate_vertical(GimpOperationFloodContext * ctx,GimpOperationFloodDirtyRange * dirty_ranges)545 gimp_operation_flood_process_propagate_vertical (GimpOperationFloodContext    *ctx,
546                                                  GimpOperationFloodDirtyRange *dirty_ranges)
547 {
548   GimpOperationFloodDirtyRange *range = dirty_ranges;
549   gint                          x;
550 
551   for (x = ctx->segment.x[0]; x <= ctx->segment.x[1]; x++)
552     {
553       /* Scan the segment until we find a pixel whose water level needs to be
554        * updated.
555        */
556       if (ctx->source_water[x] < ctx->water[x] &&
557           ctx->ground[x]       < ctx->water[x])
558         {
559           /* Compute and update the water level. */
560           gfloat level = MAX (ctx->source_water[x], ctx->ground[x]);
561 
562           ctx->water[x] = level;
563 
564           /* Start a new dirty range at the current pixel. */
565           range->x[0]     = x;
566           range->modified = FALSE;
567 
568           for (x++; x <= ctx->segment.x[1]; x++)
569             {
570               /* Keep scanning the segment while the water level of consecutive
571                * pixels needs to be updated.
572                */
573               if (ctx->source_water[x] < ctx->water[x] &&
574                   ctx->ground[x]       < ctx->water[x])
575                 {
576                   /* Compute and update the water level. */
577                   gfloat other_level = MAX (ctx->source_water[x],
578                                             ctx->ground[x]);
579 
580                   ctx->water[x] = other_level;
581 
582                   /* If the water level of the current pixel, `other_level`,
583                    * equals the water level of the current dirty range,
584                    * `level`, we keep scanning, making the current pixel part
585                    * of the current range.  On the other hand, if the current
586                    * pixel's water level is different than the that of the
587                    * current range, we finalize the range, and start a new one
588                    * at the current pixel.
589                    */
590                   if (other_level != level)
591                     {
592                       range->x[1]     = x - 1;
593                       range++;
594 
595                       range->x[0]     = x;
596                       range->modified = FALSE;
597                       level           = other_level;
598                     }
599                 }
600               else
601                 break;
602             }
603 
604           /* Finalize the current dirty range. */
605           range->x[1] = x - 1;
606           range++;
607 
608           /* Make sure we don't over-increment `x` on the continuation of the
609            * loop.
610            */
611           if (x > ctx->segment.x[1])
612             break;
613         }
614     }
615 
616   /* Return the number of dirty ranges. */
617   return range - dirty_ranges;
618 }
619 
620 /* Performs a single pass of the horizontal propagation step of the algorithm.
621  * `dir` controls the direction of the pass: either +1 for a left-to-right
622  * pass, or -1 for a right-to-left pass.  The dirty ranges are passed through
623  * the `dirty_ranges` array (and their number in `range_count`), and are
624  * modified in-place.
625  */
626 static void
gimp_operation_flood_process_propagate_horizontal(GimpOperationFloodContext * ctx,gint dir,GimpOperationFloodDirtyRange * dirty_ranges,gint range_count)627 gimp_operation_flood_process_propagate_horizontal (GimpOperationFloodContext    *ctx,
628                                                    gint                          dir,
629                                                    GimpOperationFloodDirtyRange *dirty_ranges,
630                                                    gint                          range_count)
631 {
632   /* The index of the terminal (i.e., "`dir`-most") component of the `x[]`
633    * array of `GimpOperationFloodSegment` and `GimpOperationFloodDirtyRange`,
634    * based on the scan direction.  Equals 1 (i.e., the right component) when
635    * `dir` is +1 (i.e., left-to-right), and equals 0 (i.e., the left component)
636    * when `dir` is -1 (i.e., right-to-left).
637    */
638   gint          x_component;
639   /* One-past the final x-coordinate of the ROI, in the ROI-virtual coordinate
640    * system, based on the scan direction.  That is, the x-coordinate of the
641    * pixel to the right of the rightmost pixel, for a left-to-right scan, and
642    * of the pixel to the left of the leftmost pixel, for a right-to-left scan.
643    */
644   gint          roi_lim;
645   /* One-past the final x-coordinate of the segment, in the ROI-virtual
646    * coordinate system, based on the scan direction, in a similar fashion to
647    * `roi_lim`.
648    */
649   gint          segment_lim;
650   /* The indices of the first, and one-past-the-last dirty ranges, based on the
651    * direction of the scan.  Recall that when scanning right-to-left, we
652    * iterate over the ranges in reverse.
653    */
654   gint          first_range, last_range;
655   /* Index of the current dirty range. */
656   gint          range_index;
657   /* Image-virtual and image-physical rectangles, respectively. */
658   GeglRectangle iv_rect, ip_rect;
659 
660   /* Initialize the above variables based on the scan direction. */
661   if (dir > 0)
662     {
663       /* Left-to-right. */
664       x_component = 1;
665       roi_lim     = ctx->roi.width;
666       first_range = 0;
667       last_range  = range_count;
668     }
669   else
670     {
671       /* Right-to-left. */
672       x_component = 0;
673       roi_lim     = -1;
674       first_range = range_count - 1;
675       last_range  = -1;
676     }
677   segment_lim     = ctx->segment.x[x_component] + dir;
678 
679   /* We loop over the dirty ranges, in the direction of the scan.  For each
680    * range, we iterate over the pixels, in the scan direction, starting at the
681    * outer edge of the range, and update the water level, considering only the
682    * water level of the previous and current pixels, until we arrive at a pixel
683    * whose water level remains the same, at which point we move to the next
684    * range, as described in the algorithm overview.
685    */
686   for (range_index  = first_range;
687        range_index != last_range;
688        range_index += dir)
689     {
690       /* Current dirty range. */
691       GimpOperationFloodDirtyRange *range;
692       /* Current pixel, in the ROI-virtual coordinate system. */
693       gint                          x;
694       /* We use `level` to compute the water level of the current pixel.  At
695        * the beginning of each iteration, it holds the water level of the
696        * previous pixel.
697        */
698       gfloat                        level;
699       /* The `inside` flag indicates whether `x` is inside the current segment.
700        * Recall that we may iterate past the bounds of the current segment, in
701        * which case we need to read the ground- and water-levels from the GEGL
702        * buffers directly, instead of the corresponding arrays.
703        */
704       gboolean                      inside;
705       /* Loop limit. */
706       gint                          lim;
707 
708       range  = &dirty_ranges[range_index];
709       /* Last x-coordinate of the range, in the direction of the scan. */
710       x      = range->x[x_component];
711       /* We start iterating on the pixel after `x`; initialize `level` to the
712        * water level of the previous pixel.
713        */
714       level  = ctx->water[x];
715       /* The ranges produced by the vertical propagation step are all within
716        * the bounds of the segment; the horizontal propagation step may only
717        * extend them in the direction of the scan.  Therefore, on both passes
718        * of the horizontal propagation step, the last pixel of each range, in
719        * the direction of the scan, is initially inside the segment.
720        */
721       inside = TRUE;
722       /* If this isn't the last range, break the loop at the beginning of the
723        * next range.  Otherwise, break the loop at the edge of the ROI.
724        */
725       if (range_index + dir != last_range)
726         lim  = (range + dir)->x[1 - x_component];
727       else
728         lim  = roi_lim;
729 
730       /* Loop over the pixels between the edge of the current range, and the
731        * beginning of the next range (or the edge of the ROI).
732        */
733       for (x += dir; x != lim; x += dir)
734         {
735           gfloat ground_level, water_level;
736 
737           /* Recall that `segment_lim` is one-past the last pixel of the
738            * segment.  If we hit it, we've gone outside the segment bounds.
739            */
740           if (x == segment_lim)
741             {
742               inside         = FALSE;
743               /* Initialize the rectangle to sample pixels directly from the
744                * GEGL buffers.
745                */
746               iv_rect.y      = ctx->roi.y + ctx->segment.y;
747               iv_rect.width  = 1;
748               iv_rect.height = 1;
749             }
750 
751           /* If we're inside the segment, read the ground- and water-levels
752            * from the corresponding arrays; otherwise, read them from the GEGL
753            * buffers directly.  Note that, on each pass, we may only write to
754            * pixels outside the segment *in direction of the scan* (in which
755            * case, the new values are written to the `water` array, but not
756            * directly to the output GEGL buffer), hence, when reading from the
757            * GEGL buffers, there's no danger of reading stale values, that were
758            * changed on the previous pass.
759            */
760           if (inside)
761             {
762               ground_level = ctx->ground[x];
763               water_level  = ctx->water[x];
764             }
765           else
766             {
767               iv_rect.x = ctx->roi.x + x;
768 
769               /* Transform `iv_rect` to the image-physical coordinate system,
770                * and store the result in `ip_rect`.
771                */
772               gimp_operation_flood_process_transform_rect (ctx,
773                                                            &ip_rect, &iv_rect);
774 
775               /* Read the current pixel's ground level. */
776               gegl_buffer_get (ctx->input, &ip_rect, 1.0, ctx->input_format,
777                                &ground_level,
778                                GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
779               /* Read the current pixel's water level. */
780               gegl_buffer_get (ctx->output, &ip_rect, 1.0, ctx->output_format,
781                                &water_level,
782                                GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
783             }
784 
785           /* The new water level is the maximum of the current ground level,
786            * and the minimum of the current and previous water levels.  Recall
787            * that `level` holds the previous water level, and that the current
788            * water level is never less than the ground level.
789            */
790           if (level < ground_level)
791             level             = ground_level;
792           if (level < water_level)
793             {
794               /* The water level changed.  Update the current pixel, and set
795                * the `modified` flag of the current range, since it will be
796                * extended to include the current pixel.
797                */
798               ctx->water[x]   = level;
799               range->modified = TRUE;
800             }
801           else
802             /* The water level stayed the same.  Break the loop. */
803             break;
804         }
805 
806       /* Extend the current dirty range to include the last modified pixel, if
807        * any.
808        */
809       range->x[x_component] = x - dir;
810 
811       /* If we stopped the loop before hitting the edge of the next range, or
812        * if we're at the last range, continue to the next range (or quit).
813        */
814       if (x != lim || range_index + dir == last_range)
815         continue;
816 
817       /* If we hit the edge of the next range, we keep propagating the changes
818        * *inside* the next range, until we hit its other edge, or until the
819        * water level stays the same.
820        */
821       range += dir;
822       lim    = range->x[x_component] + dir;
823 
824       for (; x != lim; x += dir)
825         {
826           /* Note that we're necessarily inside the segment right now, since
827            * the only range that could have been extended past the edge of the
828            * segment by the previous pass, is the first range of the current
829            * pass, while the range we're currently inside is at least the
830            * second.
831            */
832           if (level < ctx->ground[x])
833             level             = ctx->ground[x];
834           if (level < ctx->water[x])
835             {
836               ctx->water[x]   = level;
837               /* Set the `modified` flag of the range, since the water level of
838                * its existing pixels changed.
839                */
840               range->modified = TRUE;
841             }
842           else
843             break;
844         }
845     }
846 }
847 
848 /* Coalesces consecutive dirty ranges that are separated by a gap less-than or
849  * equal-to `max_gap`, in-place, and returns the new number of ranges.
850  */
851 static gint
gimp_operation_flood_process_coalesce(const GimpOperationFloodContext * ctx,GimpOperationFloodDirtyRange * dirty_ranges,gint range_count,gint max_gap)852 gimp_operation_flood_process_coalesce (const GimpOperationFloodContext *ctx,
853                                        GimpOperationFloodDirtyRange    *dirty_ranges,
854                                        gint                             range_count,
855                                        gint                             max_gap)
856 {
857   /* First and last ranges to coalesce, respectively. */
858   const GimpOperationFloodDirtyRange *first_range, *last_range;
859   /* Destination range. */
860   GimpOperationFloodDirtyRange       *range = dirty_ranges;
861 
862   for (first_range  = dirty_ranges;
863        first_range != dirty_ranges + range_count;
864        first_range++)
865     {
866       /* The `modified` flag of the coalesced range -- the logical-OR of the
867        * `modified` flags of the individual ranges.
868        */
869       gboolean modified = first_range->modified;
870 
871       /* Find all consecutive ranges with a small-enough gap. */
872       for (last_range      = first_range;
873            last_range + 1 != dirty_ranges + range_count;
874            last_range++)
875         {
876           if ((last_range + 1)->x[0] - last_range->x[1] > max_gap)
877             break;
878 
879           modified |= (last_range + 1)->modified;
880         }
881 
882       /* Write the coalesced range, or copy the current range, to the
883        * destination range.
884        */
885       if (first_range != last_range || first_range != range)
886         {
887           range->x[0]     = first_range->x[0];
888           range->x[1]     = last_range->x[1];
889           range->modified = modified;
890         }
891 
892       first_range = last_range;
893       range++;
894     }
895 
896   /* Return the new range count. */
897   return range - dirty_ranges;
898 }
899 
900 /* Writes the updated water level of the dirty ranges back to the output GEGL
901  * buffer.
902  */
903 static void
gimp_operation_flood_process_commit(const GimpOperationFloodContext * ctx,const GimpOperationFloodDirtyRange * dirty_ranges,gint range_count)904 gimp_operation_flood_process_commit (const GimpOperationFloodContext    *ctx,
905                                      const GimpOperationFloodDirtyRange *dirty_ranges,
906                                      gint                                range_count)
907 {
908   const GimpOperationFloodDirtyRange *range;
909   /* Image-virtual and image-physical rectangles, respectively. */
910   GeglRectangle                       iv_rect, ip_rect;
911 
912   /* Set the vertical extent of the rectangle to span a the current segment's
913    * row.
914    */
915   iv_rect.y      = ctx->roi.y + ctx->segment.y;
916   iv_rect.height = 1;
917 
918   for (range = dirty_ranges; range != dirty_ranges + range_count; range++)
919     {
920       /* Set the horizontal extent of the rectangle to span the dirty range. */
921       iv_rect.x     = ctx->roi.x + range->x[0];
922       iv_rect.width = range->x[1] - range->x[0] + 1;
923 
924       /* Transform `iv_rect` to the image-physical coordinate system, and store
925        * the result in `ip_rect`.
926        */
927       gimp_operation_flood_process_transform_rect (ctx, &ip_rect, &iv_rect);
928 
929       /* Write the updated water level to the output GEGL buffer. */
930       gegl_buffer_set (ctx->output, &ip_rect, 0, ctx->output_format,
931                        ctx->water + range->x[0],
932                        GEGL_AUTO_ROWSTRIDE);
933     }
934 }
935 
936 /* Pushes the new segments, corresponding to the dirty ranges of the current
937  * segment, into the queue.
938  */
939 static void
gimp_operation_flood_process_distribute(const GimpOperationFloodContext * ctx,GQueue * queue,const GimpOperationFloodDirtyRange * dirty_ranges,gint range_count)940 gimp_operation_flood_process_distribute (const GimpOperationFloodContext    *ctx,
941                                          GQueue                             *queue,
942                                          const GimpOperationFloodDirtyRange *dirty_ranges,
943                                          gint                                range_count)
944 {
945   const GimpOperationFloodDirtyRange *range;
946   static const gint                   y_deltas[] = {-1, +1};
947   gint                                i;
948 
949   /* For each neighboring row... */
950   for (i = 0; i < G_N_ELEMENTS (y_deltas); i++)
951     {
952       /* The difference between the negihboring row's y-coordinate and the
953        * current row's y-corindate, in the ROI-virtual coordinate system.
954        */
955       gint y_delta = y_deltas[i];
956       /* The negihboring row's y-coordinate in the ROI-virtual coordinate
957        * system.
958        */
959       gint y = ctx->segment.y + y_delta;
960 
961       /* If the neighboring row is outside the ROI, skip it. */
962       if (y < 0 || y >= ctx->roi.height)
963         continue;
964 
965       /* For each dirty range... */
966       for (range = dirty_ranges; range != dirty_ranges + range_count; range++)
967         {
968           /* If the range was modified during horizontal propagation, or if the
969            * neighboring row is not the source segment's row... (note that the
970            * latter is always true for seed segments.)
971            */
972           if (range->modified || y_delta != ctx->segment.source_y_delta)
973             {
974               /* Push a new segment into the queue, spanning the same pixels as
975                * the dirty range on the neighboring row, using the current row
976                * as its source segment.
977                */
978               gimp_operation_flood_process_push (queue,
979                                                  ctx->segment.transpose,
980                                                  y,
981                                                  -y_delta,
982                                                  range->x[0],
983                                                  range->x[1]);
984             }
985         }
986     }
987 }
988 
989 /* Main algorithm. */
990 static gboolean
gimp_operation_flood_process(GeglOperation * operation,GeglBuffer * input,GeglBuffer * output,const GeglRectangle * roi,gint level)991 gimp_operation_flood_process (GeglOperation       *operation,
992                               GeglBuffer          *input,
993                               GeglBuffer          *output,
994                               const GeglRectangle *roi,
995                               gint                 level)
996 {
997   const Babl                   *input_format  = gegl_operation_get_format (operation, "input");
998   const Babl                   *output_format = gegl_operation_get_format (operation, "output");
999   GeglColor                    *color;
1000   gint                          max_size;
1001   GimpOperationFloodContext     ctx;
1002   GimpOperationFloodDirtyRange *dirty_ranges;
1003   GQueue                       *queue;
1004 
1005   /* Make sure the input- and output-buffers are different. */
1006   g_return_val_if_fail (input != output, FALSE);
1007 
1008   /* Make sure the ROI is small enough for the `GimpOperationFloodSegment::y`
1009    * field.
1010    */
1011   g_return_val_if_fail (roi->width  <= GIMP_MAX_IMAGE_SIZE &&
1012                         roi->height <= GIMP_MAX_IMAGE_SIZE, FALSE);
1013 
1014   ctx.input         = input;
1015   ctx.input_format  = input_format;
1016   ctx.output        = output;
1017   ctx.output_format = output_format;
1018 
1019   /* All buffers need to have enough capacity to process a full row, or a full
1020    * column, since, when processing vertical segments, we treat the image as
1021    * transposed.
1022    */
1023   max_size          = MAX (roi->width, roi->height);
1024   ctx.ground        = g_new (gfloat, max_size);
1025   /* The `water_buffer` array needs to be able to hold two rows (or columns). */
1026   ctx.water_buffer  = g_new (gfloat, 2 * max_size);
1027   dirty_ranges      = g_new (GimpOperationFloodDirtyRange, max_size);
1028 
1029   /* Initialize the water level to 1 everywhere. */
1030   color = gegl_color_new ("#fff");
1031   gegl_buffer_set_color (output, roi, color);
1032   g_object_unref (color);
1033 
1034   /* Create the queue and push the seed segments. */
1035   queue  = g_queue_new ();
1036   gimp_operation_flood_process_seed (queue, roi);
1037 
1038   /* While there are segments to process in the queue... */
1039   while (! g_queue_is_empty (queue))
1040     {
1041       GimpOperationFloodSegment *segment;
1042       gint                       range_count;
1043 
1044       /* Pop a segment off the top of the queue, copy it to `ctx.segment`, and
1045        * free its memory.
1046        */
1047       segment     = (GimpOperationFloodSegment *) g_queue_pop_head (queue);
1048       ctx.segment = *segment;
1049       g_slice_free (GimpOperationFloodSegment, segment);
1050 
1051       /* Transform the ROI from the image-physical coordinate system to the
1052        * image-virtual coordinate system, and store the result in `ctx.roi`.
1053        */
1054       gimp_operation_flood_process_transform_rect (&ctx, &ctx.roi, roi);
1055 
1056       /* Read the ground- and water-levels of the current- and source-segments
1057        * from the corresponding GEGL buffers to the corresponding arrays.
1058        */
1059       gimp_operation_flood_process_fetch (&ctx);
1060 
1061       /* Perform the vertical propagation step. */
1062       range_count = gimp_operation_flood_process_propagate_vertical (&ctx,
1063                                                                      dirty_ranges);
1064       /* If no dirty ranges were produced during vertical propagation, then the
1065        * water level of the current segment didn't change, and we can short-
1066        * circuit early.
1067        */
1068       if (range_count == 0)
1069         continue;
1070 
1071       /* Perform both passes of the horizontal propagation step. */
1072       gimp_operation_flood_process_propagate_horizontal (&ctx,
1073                                                          /* Left-to-right */ +1,
1074                                                          dirty_ranges,
1075                                                          range_count);
1076       gimp_operation_flood_process_propagate_horizontal (&ctx,
1077                                                          /* Right-to-left */ -1,
1078                                                          dirty_ranges,
1079                                                          range_count);
1080 
1081       /* Coalesce consecutive dirty ranges separated by a gap less-than or
1082        * equal-to `GIMP_OPERATION_FLOOD_COALESCE_MAX_GAP`.
1083        */
1084       range_count = gimp_operation_flood_process_coalesce (&ctx,
1085                                                            dirty_ranges,
1086                                                            range_count,
1087                                                            GIMP_OPERATION_FLOOD_COALESCE_MAX_GAP);
1088 
1089       /* Write the updated water level back to the output GEGL buffer. */
1090       gimp_operation_flood_process_commit (&ctx, dirty_ranges, range_count);
1091 
1092       /* Push the new segments into the queue. */
1093       gimp_operation_flood_process_distribute (&ctx, queue,
1094                                                dirty_ranges, range_count);
1095     }
1096 
1097   g_queue_free (queue);
1098 
1099   g_free (dirty_ranges);
1100   g_free (ctx.water_buffer);
1101   g_free (ctx.ground);
1102 
1103   return TRUE;
1104 }
1105