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