gimpink.c 22.6 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
2 3
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
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 8 9 10 11 12 13 14
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * 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
 */
Sven Neumann's avatar
Sven Neumann committed
17

18 19
#include "config.h"

Tor Lillqvist's avatar
Tor Lillqvist committed
20
#include <string.h>
21

22
#include <gdk-pixbuf/gdk-pixbuf.h>
23
#include <gegl.h>
Sven Neumann's avatar
Sven Neumann committed
24

25 26
#include "libgimpmath/gimpmath.h"

27
#include "paint-types.h"
Sven Neumann's avatar
Sven Neumann committed
28

29 30
#include "operations/layer-modes/gimp-layer-modes.h"

31 32
#include "gegl/gimp-gegl-utils.h"

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"
Jehan's avatar
Jehan committed
38
#include "core/gimpsymmetry.h"
39
#include "core/gimptempbuf.h"
40

41
#include "gimpinkoptions.h"
42 43
#include "gimpink.h"
#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 55 56 57 58
static void         gimp_ink_finalize         (GObject          *object);

static void         gimp_ink_paint            (GimpPaintCore    *paint_core,
                                               GimpDrawable     *drawable,
                                               GimpPaintOptions *paint_options,
Jehan's avatar
Jehan committed
59
                                               GimpSymmetry     *sym,
60 61 62 63 64
                                               GimpPaintState    paint_state,
                                               guint32           time);
static GeglBuffer * gimp_ink_get_paint_buffer (GimpPaintCore    *paint_core,
                                               GimpDrawable     *drawable,
                                               GimpPaintOptions *paint_options,
65
                                               GimpLayerMode     paint_mode,
66 67
                                               const GimpCoords *coords,
                                               gint             *paint_buffer_x,
Jehan's avatar
Jehan committed
68 69 70
                                               gint             *paint_buffer_y,
                                               gint             *paint_width,
                                               gint             *paint_height);
71 72 73 74 75 76 77
static GimpUndo   * gimp_ink_push_undo        (GimpPaintCore    *core,
                                               GimpImage        *image,
                                               const gchar      *undo_desc);

static void         gimp_ink_motion           (GimpPaintCore    *paint_core,
                                               GimpDrawable     *drawable,
                                               GimpPaintOptions *paint_options,
Jehan's avatar
Jehan committed
78
                                               GimpSymmetry     *sym,
79 80 81 82 83 84 85 86 87 88
                                               guint32           time);

static GimpBlob   * ink_pen_ellipse           (GimpInkOptions   *options,
                                               gdouble           x_center,
                                               gdouble           y_center,
                                               gdouble           pressure,
                                               gdouble           xtilt,
                                               gdouble           ytilt,
                                               gdouble           velocity);

89 90 91
static void         render_blob               (GeglBuffer       *buffer,
                                               GeglRectangle    *rect,
                                               GimpBlob         *blob);
92

93

94
G_DEFINE_TYPE (GimpInk, gimp_ink, GIMP_TYPE_PAINT_CORE)
Michael Natterer's avatar
Michael Natterer committed
95 96

#define parent_class gimp_ink_parent_class
97

98

99
void
100 101
gimp_ink_register (Gimp                      *gimp,
                   GimpPaintRegisterCallback  callback)
102
{
103 104
  (* callback) (gimp,
                GIMP_TYPE_INK,
105
                GIMP_TYPE_INK_OPTIONS,
106 107 108
                "gimp-ink",
                _("Ink"),
                "gimp-tool-ink");
109 110 111
}

static void
112
gimp_ink_class_init (GimpInkClass *klass)
113
{
114 115
  GObjectClass       *object_class     = G_OBJECT_CLASS (klass);
  GimpPaintCoreClass *paint_core_class = GIMP_PAINT_CORE_CLASS (klass);
116

117
  object_class->finalize             = gimp_ink_finalize;
118

119 120 121
  paint_core_class->paint            = gimp_ink_paint;
  paint_core_class->get_paint_buffer = gimp_ink_get_paint_buffer;
  paint_core_class->push_undo        = gimp_ink_push_undo;
122 123 124
}

static void
125
gimp_ink_init (GimpInk *ink)
126 127 128 129
{
}

static void
130
gimp_ink_finalize (GObject *object)
131
{
132
  GimpInk *ink = GIMP_INK (object);
133

Jehan's avatar
Jehan committed
134
  if (ink->start_blobs)
Michael Natterer's avatar
Michael Natterer committed
135
    {
Jehan's avatar
Jehan committed
136 137
      g_list_free_full (ink->start_blobs, g_free);
      ink->start_blobs = NULL;
Michael Natterer's avatar
Michael Natterer committed
138 139
    }

Jehan's avatar
Jehan committed
140
  if (ink->last_blobs)
141
    {
Jehan's avatar
Jehan committed
142 143
      g_list_free_full (ink->last_blobs, g_free);
      ink->last_blobs = NULL;
144
    }
145

146
  G_OBJECT_CLASS (parent_class)->finalize (object);
147 148
}

149
static void
150 151 152
gimp_ink_paint (GimpPaintCore    *paint_core,
                GimpDrawable     *drawable,
                GimpPaintOptions *paint_options,
Jehan's avatar
Jehan committed
153
                GimpSymmetry     *sym,
154 155
                GimpPaintState    paint_state,
                guint32           time)
156
{
Jehan's avatar
Jehan committed
157 158 159
  GimpInk    *ink = GIMP_INK (paint_core);
  GimpCoords *cur_coords;
  GimpCoords  last_coords;
160 161

  gimp_paint_core_get_last_coords (paint_core, &last_coords);
Jehan's avatar
Jehan committed
162
  cur_coords = gimp_symmetry_get_origin (sym);
163 164

  switch (paint_state)
165
    {
166
    case GIMP_PAINT_STATE_INIT:
167
        {
168 169
          GimpContext *context = GIMP_CONTEXT (paint_options);
          GimpRGB      foreground;
Michael Natterer's avatar
Michael Natterer committed
170

171
          gimp_symmetry_set_stateful (sym, TRUE);
172 173 174
          gimp_context_get_foreground (context, &foreground);
          gimp_palettes_add_color_history (context->gimp,
                                           &foreground);
Michael Natterer's avatar
Michael Natterer committed
175

Jehan's avatar
Jehan committed
176 177
          if (cur_coords->x == last_coords.x &&
              cur_coords->y == last_coords.y)
Michael Natterer's avatar
Michael Natterer committed
178
            {
Jehan's avatar
Jehan committed
179
              if (ink->start_blobs)
180
                {
Jehan's avatar
Jehan committed
181 182
                  g_list_free_full (ink->start_blobs, g_free);
                  ink->start_blobs = NULL;
183 184
                }

Jehan's avatar
Jehan committed
185
              if (ink->last_blobs)
186
                {
Jehan's avatar
Jehan committed
187 188
                  g_list_free_full (ink->last_blobs, g_free);
                  ink->last_blobs = NULL;
189
                }
Michael Natterer's avatar
Michael Natterer committed
190
            }
Jehan's avatar
Jehan committed
191
          else if (ink->last_blobs)
192
            {
Jehan's avatar
Jehan committed
193 194 195
              GimpBlob *last_blob;
              GList    *iter;
              gint      i;
Michael Natterer's avatar
Michael Natterer committed
196

Jehan's avatar
Jehan committed
197 198 199 200 201
              if (ink->start_blobs)
                {
                  g_list_free_full (ink->start_blobs, g_free);
                  ink->start_blobs = NULL;
                }
Michael Natterer's avatar
Michael Natterer committed
202

Jehan's avatar
Jehan committed
203 204 205 206 207 208 209 210 211
              /*  save the start blobs of each stroke for undo otherwise  */
              for (iter = ink->last_blobs, i = 0; iter; iter = g_list_next (iter), i++)
                {
                  last_blob = g_list_nth_data (ink->last_blobs, i);

                  ink->start_blobs = g_list_prepend (ink->start_blobs,
                                                     gimp_blob_duplicate (last_blob));
                }
              ink->start_blobs = g_list_reverse (ink->start_blobs);
212
            }
213
        }
214
      break;
215

216
    case GIMP_PAINT_STATE_MOTION:
Jehan's avatar
Jehan committed
217
      gimp_ink_motion (paint_core, drawable, paint_options, sym, time);
218
      break;
219

220
    case GIMP_PAINT_STATE_FINISH:
221
      gimp_symmetry_set_stateful (sym, FALSE);
222 223
      break;
    }
224
}
jtl's avatar
jtl committed
225

226 227 228 229
static GeglBuffer *
gimp_ink_get_paint_buffer (GimpPaintCore    *paint_core,
                           GimpDrawable     *drawable,
                           GimpPaintOptions *paint_options,
230
                           GimpLayerMode     paint_mode,
231 232
                           const GimpCoords *coords,
                           gint             *paint_buffer_x,
Jehan's avatar
Jehan committed
233 234 235
                           gint             *paint_buffer_y,
                           gint             *paint_width,
                           gint             *paint_height)
236
{
Sven Neumann's avatar
Sven Neumann committed
237
  GimpInk *ink = GIMP_INK (paint_core);
238 239 240 241
  gint     x, y;
  gint     width, height;
  gint     dwidth, dheight;
  gint     x1, y1, x2, y2;
242

Michael Natterer's avatar
Michael Natterer committed
243
  gimp_blob_bounds (ink->cur_blob, &x, &y, &width, &height);
244

245 246
  dwidth  = gimp_item_get_width  (GIMP_ITEM (drawable));
  dheight = gimp_item_get_height (GIMP_ITEM (drawable));
247

248 249 250 251
  x1 = CLAMP (x / SUBSAMPLE - 1,            0, dwidth);
  y1 = CLAMP (y / SUBSAMPLE - 1,            0, dheight);
  x2 = CLAMP ((x + width)  / SUBSAMPLE + 2, 0, dwidth);
  y2 = CLAMP ((y + height) / SUBSAMPLE + 2, 0, dheight);
252

Jehan's avatar
Jehan committed
253 254 255 256 257
  if (paint_width)
    *paint_width = width / SUBSAMPLE + 3;
  if (paint_height)
    *paint_height = height / SUBSAMPLE + 3;

258 259
  /*  configure the canvas buffer  */
  if ((x2 - x1) && (y2 - y1))
260
    {
261
      GimpTempBuf *temp_buf;
Daniel Sabo's avatar
Daniel Sabo committed
262 263
      const Babl  *format;

264 265 266
      format = gimp_layer_mode_get_format (paint_mode,
                                           GIMP_LAYER_COLOR_SPACE_AUTO,
                                           GIMP_LAYER_COLOR_SPACE_AUTO,
267
                                           gimp_drawable_get_format (drawable));
268

269
      temp_buf = gimp_temp_buf_new ((x2 - x1), (y2 - y1),
Daniel Sabo's avatar
Daniel Sabo committed
270
                                    format);
271

272 273
      *paint_buffer_x = x1;
      *paint_buffer_y = y1;
274 275 276 277

      if (paint_core->paint_buffer)
        g_object_unref (paint_core->paint_buffer);

278 279 280
      paint_core->paint_buffer = gimp_temp_buf_create_buffer (temp_buf);

      gimp_temp_buf_unref (temp_buf);
281

282
      return paint_core->paint_buffer;
283
    }
Raph Levien's avatar
Raph Levien committed
284

285
  return NULL;
286
}
287

288 289 290 291 292 293 294 295 296 297 298 299
static GimpUndo *
gimp_ink_push_undo (GimpPaintCore *core,
                    GimpImage     *image,
                    const gchar   *undo_desc)
{
  return gimp_image_undo_push (image, GIMP_TYPE_INK_UNDO,
                               GIMP_UNDO_INK, undo_desc,
                               0,
                               "paint-core", core,
                               NULL);
}

300
static void
301 302 303
gimp_ink_motion (GimpPaintCore    *paint_core,
                 GimpDrawable     *drawable,
                 GimpPaintOptions *paint_options,
Jehan's avatar
Jehan committed
304
                 GimpSymmetry     *sym,
305
                 guint32           time)
306
{
Jehan's avatar
Jehan committed
307 308 309 310 311
  GimpInk        *ink             = GIMP_INK (paint_core);
  GimpInkOptions *options         = GIMP_INK_OPTIONS (paint_options);
  GimpContext    *context         = GIMP_CONTEXT (paint_options);
  GList          *blob_unions     = NULL;
  GList          *blobs_to_render = NULL;
312 313 314
  GeglBuffer     *paint_buffer;
  gint            paint_buffer_x;
  gint            paint_buffer_y;
315
  GimpLayerMode   paint_mode;
316 317
  GimpRGB         foreground;
  GeglColor      *color;
Jehan's avatar
Jehan committed
318 319 320 321
  GimpBlob       *last_blob;
  GimpCoords     *coords;
  gint            n_strokes;
  gint            i;
322

Jehan's avatar
Jehan committed
323
  n_strokes = gimp_symmetry_get_size (sym);
324

Jehan's avatar
Jehan committed
325 326 327 328 329 330
  if (ink->last_blobs &&
      g_list_length (ink->last_blobs) != n_strokes)
    {
      g_list_free_full (ink->last_blobs, g_free);
      ink->last_blobs = NULL;
    }
Michael Natterer's avatar
Michael Natterer committed
331

Jehan's avatar
Jehan committed
332 333 334 335 336 337 338
  if (! ink->last_blobs)
    {
      if (ink->start_blobs)
        {
          g_list_free_full (ink->start_blobs, g_free);
          ink->start_blobs = NULL;
        }
Michael Natterer's avatar
Michael Natterer committed
339

Jehan's avatar
Jehan committed
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
      for (i = 0; i < n_strokes; i++)
        {
          coords = gimp_symmetry_get_coords (sym, i);

          last_blob = ink_pen_ellipse (options,
                                       coords->x,
                                       coords->y,
                                       coords->pressure,
                                       coords->xtilt,
                                       coords->ytilt,
                                       100);

          ink->last_blobs = g_list_prepend (ink->last_blobs,
                                            last_blob);
          ink->start_blobs = g_list_prepend (ink->start_blobs,
                                             gimp_blob_duplicate (last_blob));
          blobs_to_render = g_list_prepend (blobs_to_render, last_blob);
        }
      ink->start_blobs = g_list_reverse (ink->start_blobs);
      ink->last_blobs = g_list_reverse (ink->last_blobs);
      blobs_to_render = g_list_reverse (blobs_to_render);
361 362 363
    }
  else
    {
Jehan's avatar
Jehan committed
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
      for (i = 0; i < n_strokes; i++)
        {
          GimpBlob *blob;
          GimpBlob *blob_union = NULL;

          coords = gimp_symmetry_get_coords (sym, i);
          blob = ink_pen_ellipse (options,
                                  coords->x,
                                  coords->y,
                                  coords->pressure,
                                  coords->xtilt,
                                  coords->ytilt,
                                  coords->velocity * 100);

          last_blob = g_list_nth_data (ink->last_blobs, i);
          blob_union = gimp_blob_convex_union (last_blob, blob);

          g_free (last_blob);
          g_list_nth (ink->last_blobs, i)->data = blob;

          blobs_to_render = g_list_prepend (blobs_to_render, blob_union);
          blob_unions = g_list_prepend (blob_unions, blob_union);
        }
      blobs_to_render = g_list_reverse (blobs_to_render);
    }
Sven Neumann's avatar
Sven Neumann committed
389

390 391 392 393 394
  paint_mode = gimp_context_get_paint_mode (context);

  gimp_context_get_foreground (context, &foreground);
  gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (drawable),
                                     &foreground, &foreground);
395
  color = gimp_gegl_color_new (&foreground, gimp_drawable_get_space (drawable));
396

Jehan's avatar
Jehan committed
397 398 399 400 401 402 403 404
  for (i = 0; i < n_strokes; i++)
    {
      GimpBlob *blob_to_render = g_list_nth_data (blobs_to_render, i);

      coords = gimp_symmetry_get_coords (sym, i);

      ink->cur_blob = blob_to_render;
      paint_buffer = gimp_paint_core_get_paint_buffer (paint_core, drawable,
405 406 407
                                                       paint_options,
                                                       paint_mode,
                                                       coords,
Jehan's avatar
Jehan committed
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
                                                       &paint_buffer_x,
                                                       &paint_buffer_y,
                                                       NULL, NULL);
      ink->cur_blob = NULL;

      if (! paint_buffer)
        continue;

      gegl_buffer_set_color (paint_buffer, NULL, color);

      /*  draw the blob directly to the canvas_buffer  */
      render_blob (paint_core->canvas_buffer,
                   GEGL_RECTANGLE (paint_core->paint_buffer_x,
                                   paint_core->paint_buffer_y,
                                   gegl_buffer_get_width  (paint_core->paint_buffer),
                                   gegl_buffer_get_height (paint_core->paint_buffer)),
                   blob_to_render);

      /*  draw the paint_area using the just rendered canvas_buffer as mask */
      gimp_paint_core_paste (paint_core,
                             NULL,
                             paint_core->paint_buffer_x,
                             paint_core->paint_buffer_y,
                             drawable,
                             GIMP_OPACITY_OPAQUE,
                             gimp_context_get_opacity (context),
434
                             paint_mode,
Jehan's avatar
Jehan committed
435
                             GIMP_PAINT_CONSTANT);
436

437
    }
438

439 440
  g_object_unref (color);

Jehan's avatar
Jehan committed
441
  g_list_free_full (blob_unions, g_free);
442 443
}

Michael Natterer's avatar
Michael Natterer committed
444
static GimpBlob *
445 446
ink_pen_ellipse (GimpInkOptions *options,
                 gdouble         x_center,
447 448 449 450 451
                 gdouble         y_center,
                 gdouble         pressure,
                 gdouble         xtilt,
                 gdouble         ytilt,
                 gdouble         velocity)
452
{
Michael Natterer's avatar
Michael Natterer committed
453 454 455 456 457 458 459 460
  GimpBlobFunc blob_function;
  gdouble      size;
  gdouble      tsin, tcos;
  gdouble      aspect, radmin;
  gdouble      x,y;
  gdouble      tscale;
  gdouble      tscale_c;
  gdouble      tscale_s;
461

462 463
  /* Adjust the size depending on pressure. */

464
  size = options->size * (1.0 + options->size_sensitivity *
465
                          (2.0 * pressure - 1.0));
466

467 468 469 470
  /* Adjust the size further depending on pointer velocity and
   * velocity-sensitivity.  These 'magic constants' are 'feels
   * natural' tigert-approved. --ADM
   */
471 472 473 474 475

  if (velocity < 3.0)
    velocity = 3.0;

#ifdef VERBOSE
476
  g_printerr ("%g (%g) -> ", size, velocity);
477
#endif
478

479 480 481
  size = (options->vel_sensitivity *
          ((4.5 * size) / (1.0 + options->vel_sensitivity * (2.0 * velocity)))
          + (1.0 - options->vel_sensitivity) * size);
482 483

#ifdef VERBOSE
484
  g_printerr ("%g\n", (gfloat) size);
485 486 487 488
#endif

  /* Clamp resulting size to sane limits */

489 490
  if (size > options->size * (1.0 + options->size_sensitivity))
    size = options->size * (1.0 + options->size_sensitivity);
491

492 493
  if (size * SUBSAMPLE < 1.0)
    size = 1.0 / SUBSAMPLE;
494 495

  /* Add brush angle/aspect to tilt vectorially */
496

Raph Levien's avatar
Raph Levien committed
497
  /* I'm not happy with the way the brush widget info is combined with
498 499 500 501
   * tilt info from the brush. My personal feeling is that
   * representing both as affine transforms would make the most
   * sense. -RLL
   */
Raph Levien's avatar
Raph Levien committed
502

503
  tscale   = options->tilt_sensitivity * 10.0;
504 505 506
  tscale_c = tscale * cos (gimp_deg_to_rad (options->tilt_angle));
  tscale_s = tscale * sin (gimp_deg_to_rad (options->tilt_angle));

507
  x = (options->blob_aspect * cos (options->blob_angle) +
508
       xtilt * tscale_c - ytilt * tscale_s);
509
  y = (options->blob_aspect * sin (options->blob_angle) +
510 511
       ytilt * tscale_c + xtilt * tscale_s);

Raph Levien's avatar
Raph Levien committed
512
#ifdef VERBOSE
513 514 515
  g_printerr ("angle %g aspect %g; %g %g; %g %g\n",
              options->blob_angle, options->blob_aspect,
              tscale_c, tscale_s, x, y);
Raph Levien's avatar
Raph Levien committed
516
#endif
517

Sven Neumann's avatar
Sven Neumann committed
518
  aspect = sqrt (SQR (x) + SQR (y));
519 520 521

  if (aspect != 0)
    {
522 523
      tcos = x / aspect;
      tsin = y / aspect;
524 525 526
    }
  else
    {
527 528 529 530 531 532 533 534 535 536
      tsin = sin (options->blob_angle);
      tcos = cos (options->blob_angle);
    }

  aspect = CLAMP (aspect, 1.0, 10.0);

  radmin = MAX (1.0, SUBSAMPLE * size / aspect);

  switch (options->blob_type)
    {
537
    case GIMP_INK_BLOB_TYPE_CIRCLE:
Michael Natterer's avatar
Michael Natterer committed
538
      blob_function = gimp_blob_ellipse;
539 540 541
      break;

    case GIMP_INK_BLOB_TYPE_SQUARE:
Michael Natterer's avatar
Michael Natterer committed
542
      blob_function = gimp_blob_square;
543 544 545
      break;

    case GIMP_INK_BLOB_TYPE_DIAMOND:
Michael Natterer's avatar
Michael Natterer committed
546
      blob_function = gimp_blob_diamond;
547 548 549 550
      break;

    default:
      g_return_val_if_reached (NULL);
551
      break;
552
    }
553

554 555 556 557 558 559
  return (* blob_function) (x_center * SUBSAMPLE,
                            y_center * SUBSAMPLE,
                            radmin * aspect * tcos,
                            radmin * aspect * tsin,
                            -radmin * tsin,
                            radmin * tcos);
560 561
}

562

563 564 565
/*********************************/
/*  Rendering functions          */
/*********************************/
566

567
/* Some of this stuff should probably be combined with the
568 569 570 571 572 573 574 575
 * code it was copied from in paint_core.c; but I wanted
 * to learn this stuff, so I've kept it simple.
 *
 * The following only supports CONSTANT mode. Incremental
 * would, I think, interact strangely with the way we
 * do things. But it wouldn't be hard to implement at all.
 */

Sven Neumann's avatar
Sven Neumann committed
576 577 578 579 580
enum
{
  ROW_START,
  ROW_STOP
};
581 582 583 584

/* The insertion sort here, for SUBSAMPLE = 8, tends to beat out
 * qsort() by 4x with CFLAGS=-O2, 2x with CFLAGS=-g
 */
585 586
static void
insert_sort (gint *data,
587
             gint  n)
588
{
589
  gint i, j, k;
590

591
  for (i = 2; i < 2 * n; i += 2)
592
    {
Sven Neumann's avatar
Sven Neumann committed
593 594 595
      gint tmp1 = data[i];
      gint tmp2 = data[i + 1];

596
      j = 0;
Sven Neumann's avatar
Sven Neumann committed
597

598
      while (data[j] < tmp1)
599
        j += 2;
600

601
      for (k = i; k > j; k -= 2)
602 603 604 605
        {
          data[k]     = data[k - 2];
          data[k + 1] = data[k - 1];
        }
606

607 608
      data[j]     = tmp1;
      data[j + 1] = tmp2;
609 610 611 612
    }
}

static void
613 614
fill_run (gfloat *dest,
          gfloat  alpha,
615
          gint    w)
616
{
617
  if (alpha == 1.0)
618
    {
619 620 621 622 623
      while (w--)
        {
          *dest = 1.0;
          dest++;
        }
624 625 626 627
    }
  else
    {
      while (w--)
628 629 630 631
        {
          *dest = MAX (*dest, alpha);
          dest++;
        }
632 633 634 635
    }
}

static void
Michael Natterer's avatar
Michael Natterer committed
636
render_blob_line (GimpBlob *blob,
637
                  gfloat   *dest,
Michael Natterer's avatar
Michael Natterer committed
638 639 640
                  gint      x,
                  gint      y,
                  gint      width)
641
{
642 643 644
  gint  buf[4 * SUBSAMPLE];
  gint *data    = buf;
  gint  n       = 0;
645 646
  gint  i, j;
  gint  current = 0;  /* number of filled rows at this point
647 648
                       * in the scan line
                       */
649
  gint last_x;
650 651

  /* Sort start and ends for all lines */
652

653
  j = y * SUBSAMPLE - blob->y;
654
  for (i = 0; i < SUBSAMPLE; i++)
655 656
    {
      if (j >= blob->height)
657
        break;
658

659
      if ((j > 0) && (blob->data[j].left <= blob->data[j].right))
660 661 662 663 664 665 666
        {
          data[2 * n]                     = blob->data[j].left;
          data[2 * n + 1]                 = ROW_START;
          data[2 * SUBSAMPLE + 2 * n]     = blob->data[j].right;
          data[2 * SUBSAMPLE + 2 * n + 1] = ROW_STOP;
          n++;
        }
667 668 669 670 671 672
      j++;
    }

  /*   If we have less than SUBSAMPLE rows, compress */
  if (n < SUBSAMPLE)
    {
673
      for (i = 0; i < 2 * n; i++)
674
        data[2 * n + i] = data[2 * SUBSAMPLE + i];
675 676 677 678 679 680 681 682 683 684 685 686
    }

  /*   Now count start and end separately */
  n *= 2;

  insert_sort (data, n);

  /* Discard portions outside of tile */

  while ((n > 0) && (data[0] < SUBSAMPLE*x))
    {
      if (data[1] == ROW_START)
687
        current++;
688
      else
689
        current--;
690 691 692 693 694 695
      data += 2;
      n--;
    }

  while ((n > 0) && (data[2*(n-1)] >= SUBSAMPLE*(x+width)))
    n--;
696

697 698 699
  /* Render the row */

  last_x = 0;
700
  for (i = 0; i < n;)
701
    {
702
      gint cur_x = data[2 * i] / SUBSAMPLE - x;
703
      gint pixel;
704 705 706

      /* Fill in portion leading up to this pixel */
      if (current && cur_x != last_x)
707
        fill_run (dest + last_x, (gfloat) current / SUBSAMPLE, cur_x - last_x);
708 709

      /* Compute the value for this pixel */
710
      pixel = current * SUBSAMPLE;
711 712

      while (i<n)
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
        {
          gint tmp_x = data[2 * i] / SUBSAMPLE;

          if (tmp_x - x != cur_x)
            break;

          if (data[2 * i + 1] == ROW_START)
            {
              current++;
              pixel += ((tmp_x + 1) * SUBSAMPLE) - data[2 * i];
            }
          else
            {
              current--;
              pixel -= ((tmp_x + 1) * SUBSAMPLE) - data[2 * i];
            }

          i++;
        }
732

733
      dest[cur_x] = MAX (dest[cur_x], (gfloat) pixel / (SUBSAMPLE * SUBSAMPLE));
734 735 736 737 738

      last_x = cur_x + 1;
    }

  if (current != 0)
739
    fill_run (dest + last_x, (gfloat) current / SUBSAMPLE, width - last_x);
740 741 742
}

static void
743 744 745
render_blob (GeglBuffer    *buffer,
             GeglRectangle *rect,
             GimpBlob      *blob)
746
{
747 748 749
  GeglBufferIterator *iter;
  GeglRectangle      *roi;

750
  iter = gegl_buffer_iterator_new (buffer, rect, 0, babl_format ("Y float"),
751 752
                                   GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE, 1);
  roi = &iter->items[0].roi;
753

754
  while (gegl_buffer_iterator_next (iter))
755
    {
756
      gfloat *d = iter->items[0].data;
757
      gint    h = roi->height;
Sven Neumann's avatar
Sven Neumann committed
758
      gint    y;
759

760
      for (y = 0; y < h; y++, d += roi->width * 1)
761
        {
762
          render_blob_line (blob, d, roi->x, roi->y + y, roi->width);
763
        }
764 765
    }
}