1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <string.h>
21 
22 #include <gdk-pixbuf/gdk-pixbuf.h>
23 #include <gegl.h>
24 
25 #include "libgimpmath/gimpmath.h"
26 
27 #include "paint-types.h"
28 
29 #include "operations/layer-modes/gimp-layer-modes.h"
30 
31 #include "gegl/gimp-gegl-utils.h"
32 
33 #include "core/gimp-palettes.h"
34 #include "core/gimpdrawable.h"
35 #include "core/gimpimage.h"
36 #include "core/gimpimage-undo.h"
37 #include "core/gimppickable.h"
38 #include "core/gimpsymmetry.h"
39 #include "core/gimptempbuf.h"
40 
41 #include "gimpinkoptions.h"
42 #include "gimpink.h"
43 #include "gimpink-blob.h"
44 #include "gimpinkundo.h"
45 
46 #include "gimp-intl.h"
47 
48 
49 #define SUBSAMPLE 8
50 
51 
52 /*  local function prototypes  */
53 
54 static void         gimp_ink_finalize         (GObject           *object);
55 
56 static void         gimp_ink_paint            (GimpPaintCore     *paint_core,
57                                                GimpDrawable      *drawable,
58                                                GimpPaintOptions  *paint_options,
59                                                GimpSymmetry      *sym,
60                                                GimpPaintState     paint_state,
61                                                guint32            time);
62 static GeglBuffer * gimp_ink_get_paint_buffer (GimpPaintCore     *paint_core,
63                                                GimpDrawable      *drawable,
64                                                GimpPaintOptions  *paint_options,
65                                                GimpLayerMode      paint_mode,
66                                                const GimpCoords  *coords,
67                                                gint              *paint_buffer_x,
68                                                gint              *paint_buffer_y,
69                                                gint              *paint_width,
70                                                gint              *paint_height);
71 static GimpUndo   * gimp_ink_push_undo        (GimpPaintCore     *core,
72                                                GimpImage         *image,
73                                                const gchar       *undo_desc);
74 
75 static void         gimp_ink_motion           (GimpPaintCore     *paint_core,
76                                                GimpDrawable      *drawable,
77                                                GimpPaintOptions  *paint_options,
78                                                GimpSymmetry      *sym,
79                                                guint32            time);
80 
81 static GimpBlob   * ink_pen_ellipse           (GimpInkOptions    *options,
82                                                gdouble            x_center,
83                                                gdouble            y_center,
84                                                gdouble            pressure,
85                                                gdouble            xtilt,
86                                                gdouble            ytilt,
87                                                gdouble            velocity,
88                                                const GimpMatrix3 *transform);
89 
90 static void         render_blob               (GeglBuffer        *buffer,
91                                                GeglRectangle     *rect,
92                                                GimpBlob          *blob);
93 
94 
G_DEFINE_TYPE(GimpInk,gimp_ink,GIMP_TYPE_PAINT_CORE)95 G_DEFINE_TYPE (GimpInk, gimp_ink, GIMP_TYPE_PAINT_CORE)
96 
97 #define parent_class gimp_ink_parent_class
98 
99 
100 void
101 gimp_ink_register (Gimp                      *gimp,
102                    GimpPaintRegisterCallback  callback)
103 {
104   (* callback) (gimp,
105                 GIMP_TYPE_INK,
106                 GIMP_TYPE_INK_OPTIONS,
107                 "gimp-ink",
108                 _("Ink"),
109                 "gimp-tool-ink");
110 }
111 
112 static void
gimp_ink_class_init(GimpInkClass * klass)113 gimp_ink_class_init (GimpInkClass *klass)
114 {
115   GObjectClass       *object_class     = G_OBJECT_CLASS (klass);
116   GimpPaintCoreClass *paint_core_class = GIMP_PAINT_CORE_CLASS (klass);
117 
118   object_class->finalize             = gimp_ink_finalize;
119 
120   paint_core_class->paint            = gimp_ink_paint;
121   paint_core_class->get_paint_buffer = gimp_ink_get_paint_buffer;
122   paint_core_class->push_undo        = gimp_ink_push_undo;
123 }
124 
125 static void
gimp_ink_init(GimpInk * ink)126 gimp_ink_init (GimpInk *ink)
127 {
128 }
129 
130 static void
gimp_ink_finalize(GObject * object)131 gimp_ink_finalize (GObject *object)
132 {
133   GimpInk *ink = GIMP_INK (object);
134 
135   if (ink->start_blobs)
136     {
137       g_list_free_full (ink->start_blobs, g_free);
138       ink->start_blobs = NULL;
139     }
140 
141   if (ink->last_blobs)
142     {
143       g_list_free_full (ink->last_blobs, g_free);
144       ink->last_blobs = NULL;
145     }
146 
147   G_OBJECT_CLASS (parent_class)->finalize (object);
148 }
149 
150 static void
gimp_ink_paint(GimpPaintCore * paint_core,GimpDrawable * drawable,GimpPaintOptions * paint_options,GimpSymmetry * sym,GimpPaintState paint_state,guint32 time)151 gimp_ink_paint (GimpPaintCore    *paint_core,
152                 GimpDrawable     *drawable,
153                 GimpPaintOptions *paint_options,
154                 GimpSymmetry     *sym,
155                 GimpPaintState    paint_state,
156                 guint32           time)
157 {
158   GimpInk    *ink = GIMP_INK (paint_core);
159   GimpCoords *cur_coords;
160   GimpCoords  last_coords;
161 
162   gimp_paint_core_get_last_coords (paint_core, &last_coords);
163   cur_coords = gimp_symmetry_get_origin (sym);
164 
165   switch (paint_state)
166     {
167     case GIMP_PAINT_STATE_INIT:
168         {
169           GimpContext *context = GIMP_CONTEXT (paint_options);
170           GimpRGB      foreground;
171 
172           gimp_symmetry_set_stateful (sym, TRUE);
173           gimp_context_get_foreground (context, &foreground);
174           gimp_palettes_add_color_history (context->gimp,
175                                            &foreground);
176 
177           if (cur_coords->x == last_coords.x &&
178               cur_coords->y == last_coords.y)
179             {
180               if (ink->start_blobs)
181                 {
182                   g_list_free_full (ink->start_blobs, g_free);
183                   ink->start_blobs = NULL;
184                 }
185 
186               if (ink->last_blobs)
187                 {
188                   g_list_free_full (ink->last_blobs, g_free);
189                   ink->last_blobs = NULL;
190                 }
191             }
192           else if (ink->last_blobs)
193             {
194               GimpBlob *last_blob;
195               GList    *iter;
196               gint      i;
197 
198               if (ink->start_blobs)
199                 {
200                   g_list_free_full (ink->start_blobs, g_free);
201                   ink->start_blobs = NULL;
202                 }
203 
204               /*  save the start blobs of each stroke for undo otherwise  */
205               for (iter = ink->last_blobs, i = 0; iter; iter = g_list_next (iter), i++)
206                 {
207                   last_blob = g_list_nth_data (ink->last_blobs, i);
208 
209                   ink->start_blobs = g_list_prepend (ink->start_blobs,
210                                                      gimp_blob_duplicate (last_blob));
211                 }
212               ink->start_blobs = g_list_reverse (ink->start_blobs);
213             }
214         }
215       break;
216 
217     case GIMP_PAINT_STATE_MOTION:
218       gimp_ink_motion (paint_core, drawable, paint_options, sym, time);
219       break;
220 
221     case GIMP_PAINT_STATE_FINISH:
222       gimp_symmetry_set_stateful (sym, FALSE);
223       break;
224     }
225 }
226 
227 static GeglBuffer *
gimp_ink_get_paint_buffer(GimpPaintCore * paint_core,GimpDrawable * drawable,GimpPaintOptions * paint_options,GimpLayerMode paint_mode,const GimpCoords * coords,gint * paint_buffer_x,gint * paint_buffer_y,gint * paint_width,gint * paint_height)228 gimp_ink_get_paint_buffer (GimpPaintCore    *paint_core,
229                            GimpDrawable     *drawable,
230                            GimpPaintOptions *paint_options,
231                            GimpLayerMode     paint_mode,
232                            const GimpCoords *coords,
233                            gint             *paint_buffer_x,
234                            gint             *paint_buffer_y,
235                            gint             *paint_width,
236                            gint             *paint_height)
237 {
238   GimpInk *ink = GIMP_INK (paint_core);
239   gint     x, y;
240   gint     width, height;
241   gint     dwidth, dheight;
242   gint     x1, y1, x2, y2;
243 
244   gimp_blob_bounds (ink->cur_blob, &x, &y, &width, &height);
245 
246   dwidth  = gimp_item_get_width  (GIMP_ITEM (drawable));
247   dheight = gimp_item_get_height (GIMP_ITEM (drawable));
248 
249   x1 = CLAMP (x / SUBSAMPLE - 1,            0, dwidth);
250   y1 = CLAMP (y / SUBSAMPLE - 1,            0, dheight);
251   x2 = CLAMP ((x + width)  / SUBSAMPLE + 2, 0, dwidth);
252   y2 = CLAMP ((y + height) / SUBSAMPLE + 2, 0, dheight);
253 
254   if (paint_width)
255     *paint_width = width / SUBSAMPLE + 3;
256   if (paint_height)
257     *paint_height = height / SUBSAMPLE + 3;
258 
259   /*  configure the canvas buffer  */
260   if ((x2 - x1) && (y2 - y1))
261     {
262       GimpTempBuf            *temp_buf;
263       const Babl             *format;
264       GimpLayerCompositeMode  composite_mode;
265 
266       composite_mode = gimp_layer_mode_get_paint_composite_mode (paint_mode);
267 
268       format = gimp_layer_mode_get_format (paint_mode,
269                                            GIMP_LAYER_COLOR_SPACE_AUTO,
270                                            GIMP_LAYER_COLOR_SPACE_AUTO,
271                                            composite_mode,
272                                            gimp_drawable_get_format (drawable));
273 
274       temp_buf = gimp_temp_buf_new ((x2 - x1), (y2 - y1),
275                                     format);
276 
277       *paint_buffer_x = x1;
278       *paint_buffer_y = y1;
279 
280       if (paint_core->paint_buffer)
281         g_object_unref (paint_core->paint_buffer);
282 
283       paint_core->paint_buffer = gimp_temp_buf_create_buffer (temp_buf);
284 
285       gimp_temp_buf_unref (temp_buf);
286 
287       return paint_core->paint_buffer;
288     }
289 
290   return NULL;
291 }
292 
293 static GimpUndo *
gimp_ink_push_undo(GimpPaintCore * core,GimpImage * image,const gchar * undo_desc)294 gimp_ink_push_undo (GimpPaintCore *core,
295                     GimpImage     *image,
296                     const gchar   *undo_desc)
297 {
298   return gimp_image_undo_push (image, GIMP_TYPE_INK_UNDO,
299                                GIMP_UNDO_INK, undo_desc,
300                                0,
301                                "paint-core", core,
302                                NULL);
303 }
304 
305 static void
gimp_ink_motion(GimpPaintCore * paint_core,GimpDrawable * drawable,GimpPaintOptions * paint_options,GimpSymmetry * sym,guint32 time)306 gimp_ink_motion (GimpPaintCore    *paint_core,
307                  GimpDrawable     *drawable,
308                  GimpPaintOptions *paint_options,
309                  GimpSymmetry     *sym,
310                  guint32           time)
311 {
312   GimpInk        *ink             = GIMP_INK (paint_core);
313   GimpInkOptions *options         = GIMP_INK_OPTIONS (paint_options);
314   GimpContext    *context         = GIMP_CONTEXT (paint_options);
315   GList          *blob_unions     = NULL;
316   GList          *blobs_to_render = NULL;
317   GeglBuffer     *paint_buffer;
318   gint            paint_buffer_x;
319   gint            paint_buffer_y;
320   GimpLayerMode   paint_mode;
321   GimpRGB         foreground;
322   GeglColor      *color;
323   GimpBlob       *last_blob;
324   GimpCoords     *coords;
325   gint            n_strokes;
326   gint            i;
327 
328   n_strokes = gimp_symmetry_get_size (sym);
329 
330   if (ink->last_blobs &&
331       g_list_length (ink->last_blobs) != n_strokes)
332     {
333       g_list_free_full (ink->last_blobs, g_free);
334       ink->last_blobs = NULL;
335     }
336 
337   if (! ink->last_blobs)
338     {
339       if (ink->start_blobs)
340         {
341           g_list_free_full (ink->start_blobs, g_free);
342           ink->start_blobs = NULL;
343         }
344 
345       for (i = 0; i < n_strokes; i++)
346         {
347           GimpMatrix3 transform;
348 
349           coords = gimp_symmetry_get_coords (sym, i);
350 
351           gimp_symmetry_get_matrix (sym, i, &transform);
352 
353           last_blob = ink_pen_ellipse (options,
354                                        coords->x,
355                                        coords->y,
356                                        coords->pressure,
357                                        coords->xtilt,
358                                        coords->ytilt,
359                                        100,
360                                        &transform);
361 
362           ink->last_blobs = g_list_prepend (ink->last_blobs,
363                                             last_blob);
364           ink->start_blobs = g_list_prepend (ink->start_blobs,
365                                              gimp_blob_duplicate (last_blob));
366           blobs_to_render = g_list_prepend (blobs_to_render, last_blob);
367         }
368       ink->start_blobs = g_list_reverse (ink->start_blobs);
369       ink->last_blobs = g_list_reverse (ink->last_blobs);
370       blobs_to_render = g_list_reverse (blobs_to_render);
371     }
372   else
373     {
374       for (i = 0; i < n_strokes; i++)
375         {
376           GimpBlob    *blob;
377           GimpBlob    *blob_union = NULL;
378           GimpMatrix3  transform;
379 
380           coords = gimp_symmetry_get_coords (sym, i);
381 
382           gimp_symmetry_get_matrix (sym, i, &transform);
383 
384           blob = ink_pen_ellipse (options,
385                                   coords->x,
386                                   coords->y,
387                                   coords->pressure,
388                                   coords->xtilt,
389                                   coords->ytilt,
390                                   coords->velocity * 100,
391                                   &transform);
392 
393           last_blob = g_list_nth_data (ink->last_blobs, i);
394           blob_union = gimp_blob_convex_union (last_blob, blob);
395 
396           g_free (last_blob);
397           g_list_nth (ink->last_blobs, i)->data = blob;
398 
399           blobs_to_render = g_list_prepend (blobs_to_render, blob_union);
400           blob_unions = g_list_prepend (blob_unions, blob_union);
401         }
402       blobs_to_render = g_list_reverse (blobs_to_render);
403     }
404 
405   paint_mode = gimp_context_get_paint_mode (context);
406 
407   gimp_context_get_foreground (context, &foreground);
408   gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (drawable),
409                                      &foreground, &foreground);
410   color = gimp_gegl_color_new (&foreground);
411 
412   for (i = 0; i < n_strokes; i++)
413     {
414       GimpBlob *blob_to_render = g_list_nth_data (blobs_to_render, i);
415 
416       coords = gimp_symmetry_get_coords (sym, i);
417 
418       ink->cur_blob = blob_to_render;
419       paint_buffer = gimp_paint_core_get_paint_buffer (paint_core, drawable,
420                                                        paint_options,
421                                                        paint_mode,
422                                                        coords,
423                                                        &paint_buffer_x,
424                                                        &paint_buffer_y,
425                                                        NULL, NULL);
426       ink->cur_blob = NULL;
427 
428       if (! paint_buffer)
429         continue;
430 
431       gegl_buffer_set_color (paint_buffer, NULL, color);
432 
433       /*  draw the blob directly to the canvas_buffer  */
434       render_blob (paint_core->canvas_buffer,
435                    GEGL_RECTANGLE (paint_core->paint_buffer_x,
436                                    paint_core->paint_buffer_y,
437                                    gegl_buffer_get_width  (paint_core->paint_buffer),
438                                    gegl_buffer_get_height (paint_core->paint_buffer)),
439                    blob_to_render);
440 
441       /*  draw the paint_area using the just rendered canvas_buffer as mask */
442       gimp_paint_core_paste (paint_core,
443                              NULL,
444                              paint_core->paint_buffer_x,
445                              paint_core->paint_buffer_y,
446                              drawable,
447                              GIMP_OPACITY_OPAQUE,
448                              gimp_context_get_opacity (context),
449                              paint_mode,
450                              GIMP_PAINT_CONSTANT);
451 
452     }
453 
454   g_object_unref (color);
455 
456   g_list_free_full (blob_unions, g_free);
457 }
458 
459 static GimpBlob *
ink_pen_ellipse(GimpInkOptions * options,gdouble x_center,gdouble y_center,gdouble pressure,gdouble xtilt,gdouble ytilt,gdouble velocity,const GimpMatrix3 * transform)460 ink_pen_ellipse (GimpInkOptions    *options,
461                  gdouble            x_center,
462                  gdouble            y_center,
463                  gdouble            pressure,
464                  gdouble            xtilt,
465                  gdouble            ytilt,
466                  gdouble            velocity,
467                  const GimpMatrix3 *transform)
468 {
469   GimpBlobFunc blob_function;
470   gdouble      size;
471   gdouble      tsin, tcos;
472   gdouble      aspect, radmin;
473   gdouble      x,y;
474   gdouble      tscale;
475   gdouble      tscale_c;
476   gdouble      tscale_s;
477 
478   /* Adjust the size depending on pressure. */
479 
480   size = options->size * (1.0 + options->size_sensitivity *
481                           (2.0 * pressure - 1.0));
482 
483   /* Adjust the size further depending on pointer velocity and
484    * velocity-sensitivity.  These 'magic constants' are 'feels
485    * natural' tigert-approved. --ADM
486    */
487 
488   if (velocity < 3.0)
489     velocity = 3.0;
490 
491 #ifdef VERBOSE
492   g_printerr ("%g (%g) -> ", size, velocity);
493 #endif
494 
495   size = (options->vel_sensitivity *
496           ((4.5 * size) / (1.0 + options->vel_sensitivity * (2.0 * velocity)))
497           + (1.0 - options->vel_sensitivity) * size);
498 
499 #ifdef VERBOSE
500   g_printerr ("%g\n", (gfloat) size);
501 #endif
502 
503   /* Clamp resulting size to sane limits */
504 
505   if (size > options->size * (1.0 + options->size_sensitivity))
506     size = options->size * (1.0 + options->size_sensitivity);
507 
508   if (size * SUBSAMPLE < 1.0)
509     size = 1.0 / SUBSAMPLE;
510 
511   /* Add brush angle/aspect to tilt vectorially */
512 
513   /* I'm not happy with the way the brush widget info is combined with
514    * tilt info from the brush. My personal feeling is that
515    * representing both as affine transforms would make the most
516    * sense. -RLL
517    */
518 
519   tscale   = options->tilt_sensitivity * 10.0;
520   tscale_c = tscale * cos (gimp_deg_to_rad (options->tilt_angle));
521   tscale_s = tscale * sin (gimp_deg_to_rad (options->tilt_angle));
522 
523   x = (options->blob_aspect * cos (options->blob_angle) +
524        xtilt * tscale_c - ytilt * tscale_s);
525   y = (options->blob_aspect * sin (options->blob_angle) +
526        ytilt * tscale_c + xtilt * tscale_s);
527 
528 #ifdef VERBOSE
529   g_printerr ("angle %g aspect %g; %g %g; %g %g\n",
530               options->blob_angle, options->blob_aspect,
531               tscale_c, tscale_s, x, y);
532 #endif
533 
534   aspect = sqrt (SQR (x) + SQR (y));
535 
536   if (aspect != 0)
537     {
538       tcos = x / aspect;
539       tsin = y / aspect;
540     }
541   else
542     {
543       tcos = cos (options->blob_angle);
544       tsin = sin (options->blob_angle);
545     }
546 
547   gimp_matrix3_transform_point (transform,
548                                 tcos,  tsin,
549                                 &tcos, &tsin);
550 
551   aspect = CLAMP (aspect, 1.0, 10.0);
552 
553   radmin = MAX (1.0, SUBSAMPLE * size / aspect);
554 
555   switch (options->blob_type)
556     {
557     case GIMP_INK_BLOB_TYPE_CIRCLE:
558       blob_function = gimp_blob_ellipse;
559       break;
560 
561     case GIMP_INK_BLOB_TYPE_SQUARE:
562       blob_function = gimp_blob_square;
563       break;
564 
565     case GIMP_INK_BLOB_TYPE_DIAMOND:
566       blob_function = gimp_blob_diamond;
567       break;
568 
569     default:
570       g_return_val_if_reached (NULL);
571       break;
572     }
573 
574   return (* blob_function) (x_center * SUBSAMPLE,
575                             y_center * SUBSAMPLE,
576                             radmin * aspect * tcos,
577                             radmin * aspect * tsin,
578                             -radmin * tsin,
579                             radmin * tcos);
580 }
581 
582 
583 /*********************************/
584 /*  Rendering functions          */
585 /*********************************/
586 
587 /* Some of this stuff should probably be combined with the
588  * code it was copied from in paint_core.c; but I wanted
589  * to learn this stuff, so I've kept it simple.
590  *
591  * The following only supports CONSTANT mode. Incremental
592  * would, I think, interact strangely with the way we
593  * do things. But it wouldn't be hard to implement at all.
594  */
595 
596 enum
597 {
598   ROW_START,
599   ROW_STOP
600 };
601 
602 /* The insertion sort here, for SUBSAMPLE = 8, tends to beat out
603  * qsort() by 4x with CFLAGS=-O2, 2x with CFLAGS=-g
604  */
605 static void
insert_sort(gint * data,gint n)606 insert_sort (gint *data,
607              gint  n)
608 {
609   gint i, j, k;
610 
611   for (i = 2; i < 2 * n; i += 2)
612     {
613       gint tmp1 = data[i];
614       gint tmp2 = data[i + 1];
615 
616       j = 0;
617 
618       while (data[j] < tmp1)
619         j += 2;
620 
621       for (k = i; k > j; k -= 2)
622         {
623           data[k]     = data[k - 2];
624           data[k + 1] = data[k - 1];
625         }
626 
627       data[j]     = tmp1;
628       data[j + 1] = tmp2;
629     }
630 }
631 
632 static void
fill_run(gfloat * dest,gfloat alpha,gint w)633 fill_run (gfloat *dest,
634           gfloat  alpha,
635           gint    w)
636 {
637   if (alpha == 1.0)
638     {
639       while (w--)
640         {
641           *dest = 1.0;
642           dest++;
643         }
644     }
645   else
646     {
647       while (w--)
648         {
649           *dest = MAX (*dest, alpha);
650           dest++;
651         }
652     }
653 }
654 
655 static void
render_blob_line(GimpBlob * blob,gfloat * dest,gint x,gint y,gint width)656 render_blob_line (GimpBlob *blob,
657                   gfloat   *dest,
658                   gint      x,
659                   gint      y,
660                   gint      width)
661 {
662   gint  buf[4 * SUBSAMPLE];
663   gint *data    = buf;
664   gint  n       = 0;
665   gint  i, j;
666   gint  current = 0;  /* number of filled rows at this point
667                        * in the scan line
668                        */
669   gint last_x;
670 
671   /* Sort start and ends for all lines */
672 
673   j = y * SUBSAMPLE - blob->y;
674   for (i = 0; i < SUBSAMPLE; i++)
675     {
676       if (j >= blob->height)
677         break;
678 
679       if ((j > 0) && (blob->data[j].left <= blob->data[j].right))
680         {
681           data[2 * n]                     = blob->data[j].left;
682           data[2 * n + 1]                 = ROW_START;
683           data[2 * SUBSAMPLE + 2 * n]     = blob->data[j].right;
684           data[2 * SUBSAMPLE + 2 * n + 1] = ROW_STOP;
685           n++;
686         }
687       j++;
688     }
689 
690   /*   If we have less than SUBSAMPLE rows, compress */
691   if (n < SUBSAMPLE)
692     {
693       for (i = 0; i < 2 * n; i++)
694         data[2 * n + i] = data[2 * SUBSAMPLE + i];
695     }
696 
697   /*   Now count start and end separately */
698   n *= 2;
699 
700   insert_sort (data, n);
701 
702   /* Discard portions outside of tile */
703 
704   while ((n > 0) && (data[0] < SUBSAMPLE*x))
705     {
706       if (data[1] == ROW_START)
707         current++;
708       else
709         current--;
710       data += 2;
711       n--;
712     }
713 
714   while ((n > 0) && (data[2*(n-1)] >= SUBSAMPLE*(x+width)))
715     n--;
716 
717   /* Render the row */
718 
719   last_x = 0;
720   for (i = 0; i < n;)
721     {
722       gint cur_x = data[2 * i] / SUBSAMPLE - x;
723       gint pixel;
724 
725       /* Fill in portion leading up to this pixel */
726       if (current && cur_x != last_x)
727         fill_run (dest + last_x, (gfloat) current / SUBSAMPLE, cur_x - last_x);
728 
729       /* Compute the value for this pixel */
730       pixel = current * SUBSAMPLE;
731 
732       while (i<n)
733         {
734           gint tmp_x = data[2 * i] / SUBSAMPLE;
735 
736           if (tmp_x - x != cur_x)
737             break;
738 
739           if (data[2 * i + 1] == ROW_START)
740             {
741               current++;
742               pixel += ((tmp_x + 1) * SUBSAMPLE) - data[2 * i];
743             }
744           else
745             {
746               current--;
747               pixel -= ((tmp_x + 1) * SUBSAMPLE) - data[2 * i];
748             }
749 
750           i++;
751         }
752 
753       dest[cur_x] = MAX (dest[cur_x], (gfloat) pixel / (SUBSAMPLE * SUBSAMPLE));
754 
755       last_x = cur_x + 1;
756     }
757 
758   if (current != 0)
759     fill_run (dest + last_x, (gfloat) current / SUBSAMPLE, width - last_x);
760 }
761 
762 static void
render_blob(GeglBuffer * buffer,GeglRectangle * rect,GimpBlob * blob)763 render_blob (GeglBuffer    *buffer,
764              GeglRectangle *rect,
765              GimpBlob      *blob)
766 {
767   GeglBufferIterator *iter;
768   GeglRectangle      *roi;
769 
770   iter = gegl_buffer_iterator_new (buffer, rect, 0, babl_format ("Y float"),
771                                    GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE, 1);
772   roi = &iter->items[0].roi;
773 
774   while (gegl_buffer_iterator_next (iter))
775     {
776       gfloat *d = iter->items[0].data;
777       gint    h = roi->height;
778       gint    y;
779 
780       for (y = 0; y < h; y++, d += roi->width * 1)
781         {
782           render_blob_line (blob, d, roi->x, roi->y + y, roi->width);
783         }
784     }
785 }
786