gimpink.c 20.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (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
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
Sven Neumann's avatar
Sven Neumann committed
18

19 20
#include "config.h"

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

23
#include <glib-object.h>
Sven Neumann's avatar
Sven Neumann committed
24

25
#include "paint-types.h"
Sven Neumann's avatar
Sven Neumann committed
26

Michael Natterer's avatar
Michael Natterer committed
27 28 29 30 31
#include "base/pixel-region.h"
#include "base/temp-buf.h"
#include "base/tile.h"
#include "base/tile-manager.h"

32 33
#include "paint-funcs/paint-funcs.h"

34
#include "core/gimpdrawable.h"
35
#include "core/gimpimage.h"
36

37
#include "gimpinkoptions.h"
38 39
#include "gimpink.h"
#include "gimpink-blob.h"
40

41
#include "gimp-intl.h"
42

43

44
#define SUBSAMPLE 8
45

46

47
/*  local function prototypes  */
48

49 50 51 52 53 54 55 56
static void      gimp_ink_class_init     (GimpInkClass       *klass);
static void      gimp_ink_init           (GimpInk            *ink);

static void      gimp_ink_finalize       (GObject            *object);

static void      gimp_ink_paint          (GimpPaintCore      *paint_core,
                                          GimpDrawable       *drawable,
                                          GimpPaintOptions   *paint_options,
57 58
                                          GimpPaintCoreState  paint_state,
                                          guint32             time);
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
static TempBuf * gimp_ink_get_paint_area (GimpPaintCore      *paint_core,
                                          GimpDrawable       *drawable,
                                          GimpPaintOptions   *paint_options);

static void      gimp_ink_motion         (GimpPaintCore      *paint_core,
                                          GimpDrawable       *drawable,
                                          GimpPaintOptions   *paint_options,
                                          guint32             time);

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

static void      time_smoother_add       (GimpInk            *ink,
                                          guint32             value);
static gdouble   time_smoother_result    (GimpInk            *ink);
static void      time_smoother_init      (GimpInk            *ink,
                                          guint32             initval);
static void      dist_smoother_add       (GimpInk            *ink,
                                          gdouble             value);
static gdouble   dist_smoother_result    (GimpInk            *ink);
static void      dist_smoother_init      (GimpInk            *ink,
                                          gdouble             initval);

static void      render_blob             (Blob               *blob,
                                          PixelRegion        *dest);
89

90

91
static GimpPaintCoreClass *parent_class = NULL;
92

93

94
void
95 96
gimp_ink_register (Gimp                      *gimp,
                   GimpPaintRegisterCallback  callback)
97
{
98 99
  (* callback) (gimp,
                GIMP_TYPE_INK,
100
                GIMP_TYPE_INK_OPTIONS,
101
                _("Ink"));
102 103
}

104
GType
105
gimp_ink_get_type (void)
106
{
107
  static GType type = 0;
108

109
  if (! type)
110
    {
111
      static const GTypeInfo info =
112
      {
113 114 115 116 117 118 119 120 121
        sizeof (GimpInkClass),
        (GBaseInitFunc) NULL,
        (GBaseFinalizeFunc) NULL,
        (GClassInitFunc) gimp_ink_class_init,
        NULL,           /* class_finalize */
        NULL,           /* class_data     */
        sizeof (GimpInk),
        0,              /* n_preallocs    */
        (GInstanceInitFunc) gimp_ink_init,
122 123
      };

124 125 126
      type = g_type_register_static (GIMP_TYPE_PAINT_CORE,
                                     "GimpInk",
                                     &info, 0);
127 128
    }

129
  return type;
130 131 132
}

static void
133
gimp_ink_class_init (GimpInkClass *klass)
134
{
135 136
  GObjectClass       *object_class     = G_OBJECT_CLASS (klass);
  GimpPaintCoreClass *paint_core_class = GIMP_PAINT_CORE_CLASS (klass);
137

138
  parent_class = g_type_class_peek_parent (klass);
139

140
  object_class->finalize  = gimp_ink_finalize;
141

142 143
  paint_core_class->paint          = gimp_ink_paint;
  paint_core_class->get_paint_area = gimp_ink_get_paint_area;
144 145 146
}

static void
147
gimp_ink_init (GimpInk *ink)
148 149 150 151
{
}

static void
152
gimp_ink_finalize (GObject *object)
153
{
154
  GimpInk *ink = GIMP_INK (object);
155

156
  if (ink->last_blob)
157
    {
158 159
      g_free (ink->last_blob);
      ink->last_blob = NULL;
160
    }
161

162
  G_OBJECT_CLASS (parent_class)->finalize (object);
163 164
}

165
static void
166 167 168
gimp_ink_paint (GimpPaintCore      *paint_core,
                GimpDrawable       *drawable,
                GimpPaintOptions   *paint_options,
169 170
                GimpPaintCoreState  paint_state,
                guint32             time)
171
{
172 173 174 175
  GimpInk        *ink     = GIMP_INK (paint_core);
  GimpInkOptions *options = GIMP_INK_OPTIONS (paint_options);

  switch (paint_state)
176
    {
177
    case PRETRACE_PAINT:
178
      break;
179

180
    case POSTTRACE_PAINT:
181
      break;
182

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
    case INIT_PAINT:
      {
        if (ink->last_blob                                        &&
            paint_core->cur_coords.x == paint_core->last_coords.x &&
            paint_core->cur_coords.y == paint_core->last_coords.y)
          {
            /*  start with a new blob if we're not interpolating  */
            g_free (ink->last_blob);
            ink->last_blob = NULL;
          }

        if (! ink->last_blob)
          ink->last_blob = ink_pen_ellipse (options,
                                            paint_core->cur_coords.x,
                                            paint_core->cur_coords.y,
                                            paint_core->cur_coords.pressure,
                                            paint_core->cur_coords.xtilt,
                                            paint_core->cur_coords.ytilt,
                                            10.0);

        time_smoother_init (ink, time);
        ink->last_time = time;

        dist_smoother_init (ink, 0.0);
        ink->init_velocity = TRUE;

        ink->lastx = paint_core->cur_coords.x;
        ink->lasty = paint_core->cur_coords.y;
      }
212
      break;
213

214 215
    case MOTION_PAINT:
      gimp_ink_motion (paint_core, drawable, paint_options, time);
216
      break;
217

218 219
    case FINISH_PAINT:
      break;
jtl's avatar
jtl committed
220

221 222 223
    default:
      break;
    }
224
}
jtl's avatar
jtl committed
225

226 227 228 229
static TempBuf *
gimp_ink_get_paint_area (GimpPaintCore    *paint_core,
                         GimpDrawable     *drawable,
                         GimpPaintOptions *paint_options)
230
{
231 232 233 234 235 236
  GimpInk  *ink  = GIMP_INK (paint_core);
  gint      x, y;
  gint      width, height;
  gint      dwidth, dheight;
  gint      x1, y1, x2, y2;
  gint      bytes;
jtl's avatar
jtl committed
237

238
  bytes = gimp_drawable_bytes_with_alpha (drawable);
239

240
  blob_bounds (ink->blob, &x, &y, &width, &height);
241

242 243
  dwidth  = gimp_item_width  (GIMP_ITEM (drawable));
  dheight = gimp_item_height (GIMP_ITEM (drawable));
244

245 246 247 248
  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);
249

250 251 252 253 254 255 256
  /*  configure the canvas buffer  */
  if ((x2 - x1) && (y2 - y1))
    paint_core->canvas_buf = temp_buf_resize (paint_core->canvas_buf, bytes,
                                              x1, y1,
                                              (x2 - x1), (y2 - y1));
  else
    return NULL;
Raph Levien's avatar
Raph Levien committed
257

258
  return paint_core->canvas_buf;
259
}
260

261
static void
262 263 264 265
gimp_ink_motion (GimpPaintCore    *paint_core,
                 GimpDrawable     *drawable,
                 GimpPaintOptions *paint_options,
                 guint32           time)
266
{
267 268 269 270 271
  GimpInk        *ink     = GIMP_INK (paint_core);
  GimpInkOptions *options = GIMP_INK_OPTIONS (paint_options);
  GimpContext    *context = GIMP_CONTEXT (paint_options);
  GimpImage      *gimage;
  Blob           *blob;
272 273 274 275
  Blob           *blob_union;
  gdouble         velocity;
  gdouble         dist;
  gdouble         lasttime, thistime;
276 277 278
  TempBuf        *area;
  guchar          col[MAX_CHANNELS];
  PixelRegion     blob_maskPR;
279

280
  gimage = gimp_item_get_image (GIMP_ITEM (drawable));
281

282
  lasttime = ink->last_time;
283

284 285
  time_smoother_add (ink, time);
  thistime = ink->last_time = time_smoother_result (ink);
286

287 288 289 290 291 292
  /* The time resolution on X-based GDK motion events is
     bloody awful, hence the use of the smoothing function.
     Sadly this also means that there is always the chance of
     having an indeterminite velocity since this event and
     the previous several may still appear to issue at the same
     instant. -ADM */
293

294 295
  if (thistime == lasttime)
    thistime = lasttime + 1;
296

297 298 299 300 301 302
  dist = sqrt ((ink->lastx - paint_core->cur_coords.x) *
               (ink->lastx - paint_core->cur_coords.x) +
               (ink->lasty - paint_core->cur_coords.y) *
               (ink->lasty - paint_core->cur_coords.y));

  if (ink->init_velocity)
303
    {
304 305
      dist_smoother_init (ink, dist);
      ink->init_velocity = FALSE;
306 307 308
    }
  else
    {
309 310
      dist_smoother_add (ink, dist);
      dist = dist_smoother_result (ink);
311
    }
312

313 314
  ink->lastx = paint_core->cur_coords.x;
  ink->lasty = paint_core->cur_coords.y;
315

316
  velocity = 10.0 * sqrt ((dist) / (gdouble) (thistime - lasttime));
317

318 319 320 321 322 323 324
  blob = ink_pen_ellipse (options,
                          paint_core->cur_coords.x,
                          paint_core->cur_coords.y,
                          paint_core->cur_coords.pressure,
                          paint_core->cur_coords.xtilt,
                          paint_core->cur_coords.ytilt,
                          velocity);
325

326 327 328
  blob_union = blob_convex_union (ink->last_blob, blob);
  g_free (ink->last_blob);
  ink->last_blob = blob;
329

330 331
  /* Get the the buffer */
  ink->blob = blob_union;
332

333 334 335
  area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options);
  if (! area)
    return;
jtl's avatar
jtl committed
336

337
  gimp_image_get_foreground (gimage, drawable, context, col);
338

339 340
  /*  set the alpha channel  */
  col[paint_core->canvas_buf->bytes - 1] = OPAQUE_OPACITY;
341

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
  /*  color the pixels  */
  color_pixels (temp_buf_data (paint_core->canvas_buf), col,
                area->width * area->height, area->bytes);

  gimp_paint_core_validate_canvas_tiles (paint_core,
                                         paint_core->canvas_buf->x,
                                         paint_core->canvas_buf->y,
                                         paint_core->canvas_buf->width,
                                         paint_core->canvas_buf->height);

  /*  draw the blob directly to the canvas_tiles  */
  pixel_region_init (&blob_maskPR, paint_core->canvas_tiles,
                     paint_core->canvas_buf->x,
                     paint_core->canvas_buf->y,
                     paint_core->canvas_buf->width,
                     paint_core->canvas_buf->height,
                     TRUE);

  render_blob (blob_union, &blob_maskPR);

  /*  draw the canvas_buf using the just rendered canvas_tiles as mask */
  pixel_region_init (&blob_maskPR, paint_core->canvas_tiles,
                     paint_core->canvas_buf->x,
                     paint_core->canvas_buf->y,
                     paint_core->canvas_buf->width,
                     paint_core->canvas_buf->height,
                     FALSE);

  gimp_paint_core_paste (paint_core, &blob_maskPR, drawable,
                         GIMP_OPACITY_OPAQUE,
                         gimp_context_get_opacity (context),
                         gimp_context_get_paint_mode (context),
                         GIMP_PAINT_CONSTANT);
375

376
  g_free (blob_union);
377 378 379
}

static Blob *
380 381 382 383 384 385 386
ink_pen_ellipse (GimpInkOptions *options,
                 gdouble         x_center,
		 gdouble         y_center,
		 gdouble         pressure,
		 gdouble         xtilt,
		 gdouble         ytilt,
		 gdouble         velocity)
387
{
388
  BlobFunc blob_function;
389 390 391 392 393 394 395
  gdouble  size;
  gdouble  tsin, tcos;
  gdouble  aspect, radmin;
  gdouble  x,y;
  gdouble  tscale;
  gdouble  tscale_c;
  gdouble  tscale_s;
396

397 398
  /* Adjust the size depending on pressure. */

399
  size = options->size * (1.0 + options->size_sensitivity *
400
                          (2.0 * pressure - 1.0));
401

402 403 404 405
  /* Adjust the size further depending on pointer velocity and
   * velocity-sensitivity.  These 'magic constants' are 'feels
   * natural' tigert-approved. --ADM
   */
406 407 408 409 410

  if (velocity < 3.0)
    velocity = 3.0;

#ifdef VERBOSE
411
  g_printerr ("%g (%g) -> ", size, velocity);
412
#endif
413

414 415 416
  size = (options->vel_sensitivity *
          ((4.5 * size) / (1.0 + options->vel_sensitivity * (2.0 * velocity)))
          + (1.0 - options->vel_sensitivity) * size);
417 418

#ifdef VERBOSE
419
  g_printerr ("%g\n", (gfloat) size);
420 421 422 423
#endif

  /* Clamp resulting size to sane limits */

424 425
  if (size > options->size * (1.0 + options->size_sensitivity))
    size = options->size * (1.0 + options->size_sensitivity);
426

427 428
  if (size * SUBSAMPLE < 1.0)
    size = 1.0 / SUBSAMPLE;
429 430

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

Raph Levien's avatar
Raph Levien committed
432
  /* I'm not happy with the way the brush widget info is combined with
433 434 435 436
   * 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
437

438
  tscale   = options->tilt_sensitivity * 10.0;
439 440 441
  tscale_c = tscale * cos (gimp_deg_to_rad (options->tilt_angle));
  tscale_s = tscale * sin (gimp_deg_to_rad (options->tilt_angle));

442
  x = (options->blob_aspect * cos (options->blob_angle) +
443
       xtilt * tscale_c - ytilt * tscale_s);
444
  y = (options->blob_aspect * sin (options->blob_angle) +
445 446
       ytilt * tscale_c + xtilt * tscale_s);

Raph Levien's avatar
Raph Levien committed
447
#ifdef VERBOSE
448 449 450
  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
451
#endif
452

453
  aspect = sqrt (x * x + y * y);
454 455 456

  if (aspect != 0)
    {
457 458
      tcos = x / aspect;
      tsin = y / aspect;
459 460 461
    }
  else
    {
462 463 464 465 466 467 468 469 470 471 472
      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)
    {
    case GIMP_INK_BLOB_TYPE_ELLIPSE:
473
      blob_function = blob_ellipse;
474 475 476
      break;

    case GIMP_INK_BLOB_TYPE_SQUARE:
477
      blob_function = blob_square;
478 479 480
      break;

    case GIMP_INK_BLOB_TYPE_DIAMOND:
481 482 483 484 485
      blob_function = blob_diamond;
      break;

    default:
      g_return_val_if_reached (NULL);
486
      break;
487
    }
488

489 490 491 492 493 494
  return (* blob_function) (x_center * SUBSAMPLE,
                            y_center * SUBSAMPLE,
                            radmin * aspect * tcos,
                            radmin * aspect * tsin,
                            -radmin * tsin,
                            radmin * tcos);
495 496 497
}

static void
498 499
dist_smoother_init (GimpInk *ink,
                    gdouble  initval)
500
{
501
  gint i;
502

503
  ink->dt_index = 0;
504

505
  for (i = 0; i < DIST_SMOOTHER_BUFFER; i++)
506
    {
507
      ink->dt_buffer[i] = initval;
508 509
    }
}
510

511
static gdouble
512
dist_smoother_result (GimpInk *ink)
513 514 515
{
  gint    i;
  gdouble result = 0.0;
516

517 518
  for (i = 0; i < DIST_SMOOTHER_BUFFER; i++)
    {
519
      result += ink->dt_buffer[i];
520
    }
521 522

  return (result / (gdouble) DIST_SMOOTHER_BUFFER);
523 524 525
}

static void
526 527
dist_smoother_add (GimpInk *ink,
                   gdouble  value)
528
{
529
  ink->dt_buffer[ink->dt_index] = value;
Michael Natterer's avatar
Michael Natterer committed
530

531 532
  if ((++ink->dt_index) == DIST_SMOOTHER_BUFFER)
    ink->dt_index = 0;
533
}
534

535
static void
536 537
time_smoother_init (GimpInk *ink,
                    guint32  initval)
538 539
{
  gint i;
540

541
  ink->ts_index = 0;
542

543
  for (i = 0; i < TIME_SMOOTHER_BUFFER; i++)
544
    {
545
      ink->ts_buffer[i] = initval;
546
    }
547 548 549
}

static gdouble
550
time_smoother_result (GimpInk *ink)
551 552 553 554 555
{
  gint    i;
  guint64 result = 0;

  for (i = 0; i < TIME_SMOOTHER_BUFFER; i++)
556
    {
557
      result += ink->ts_buffer[i];
558
    }
559

560 561 562 563 564 565
#ifdef _MSC_VER
  return (gdouble) (gint64) (result / TIME_SMOOTHER_BUFFER);
#else
  return (result / TIME_SMOOTHER_BUFFER);
#endif
}
566 567

static void
568 569
time_smoother_add (GimpInk *ink,
                   guint32  value)
570
{
571
  ink->ts_buffer[ink->ts_index] = value;
572

573 574
  if ((++ink->ts_index) == TIME_SMOOTHER_BUFFER)
    ink->ts_index = 0;
575 576 577
}


578 579 580
/*********************************/
/*  Rendering functions          */
/*********************************/
581

582
/* Some of this stuff should probably be combined with the
583 584 585 586 587 588 589 590 591 592 593 594 595
 * 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.
 */

enum { ROW_START, ROW_STOP };

/* The insertion sort here, for SUBSAMPLE = 8, tends to beat out
 * qsort() by 4x with CFLAGS=-O2, 2x with CFLAGS=-g
 */
596 597 598
static void
insert_sort (gint *data,
	     gint  n)
599
{
600 601
  gint i, j, k;
  gint tmp1, tmp2;
602

603
  for (i = 2; i < 2 * n; i += 2)
604 605
    {
      tmp1 = data[i];
606
      tmp2 = data[i + 1];
607 608 609 610
      j = 0;
      while (data[j] < tmp1)
	j += 2;

611
      for (k = i; k > j; k -= 2)
612
	{
613 614
	  data[k]     = data[k - 2];
	  data[k + 1] = data[k - 1];
615 616
	}

617 618
      data[j]     = tmp1;
      data[j + 1] = tmp2;
619 620 621 622 623 624
    }
}

static void
fill_run (guchar *dest,
	  guchar  alpha,
625
	  gint    w)
626 627 628 629 630 631 632 633
{
  if (alpha == 255)
    {
      memset (dest, 255, w);
    }
  else
    {
      while (w--)
634 635 636 637
        {
          *dest = MAX (*dest, alpha);
          dest++;
        }
638 639 640 641
    }
}

static void
642 643 644 645 646
render_blob_line (Blob   *blob,
		  guchar *dest,
		  gint    x,
		  gint    y,
		  gint    width)
647
{
648 649 650
  gint  buf[4 * SUBSAMPLE];
  gint *data    = buf;
  gint  n       = 0;
651 652 653 654 655
  gint  i, j;
  gint  current = 0;  /* number of filled rows at this point
		       * in the scan line
		       */
  gint last_x;
656 657

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

659
  j = y * SUBSAMPLE - blob->y;
660
  for (i = 0; i < SUBSAMPLE; i++)
661 662 663
    {
      if (j >= blob->height)
	break;
664

665 666
      if ((j > 0) && (blob->data[j].left <= blob->data[j].right))
	{
667 668 669 670
	  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;
671 672 673 674 675 676 677 678
	  n++;
	}
      j++;
    }

  /*   If we have less than SUBSAMPLE rows, compress */
  if (n < SUBSAMPLE)
    {
679 680
      for (i = 0; i < 2 * n; i++)
	data[2 * n + i] = data[2 * SUBSAMPLE + i];
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
    }

  /*   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)
	current++;
      else
	current--;
      data += 2;
      n--;
    }

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

703 704 705
  /* Render the row */

  last_x = 0;
706
  for (i = 0; i < n;)
707
    {
708
      gint cur_x = data[2 * i] / SUBSAMPLE - x;
709
      gint pixel;
710 711 712

      /* Fill in portion leading up to this pixel */
      if (current && cur_x != last_x)
713
	fill_run (dest + last_x, (255 * current) / SUBSAMPLE, cur_x - last_x);
714 715

      /* Compute the value for this pixel */
716
      pixel = current * SUBSAMPLE;
717 718 719

      while (i<n)
	{
720 721
	  gint tmp_x = data[2 * i] / SUBSAMPLE;

722 723 724
	  if (tmp_x - x != cur_x)
	    break;

725
	  if (data[2 * i + 1] == ROW_START)
726 727
	    {
	      current++;
728
	      pixel += ((tmp_x + 1) * SUBSAMPLE) - data[2 * i];
729 730 731 732
	    }
	  else
	    {
	      current--;
733
	      pixel -= ((tmp_x + 1) * SUBSAMPLE) - data[2 * i];
734
	    }
735

736 737 738
	  i++;
	}

739
      dest[cur_x] = MAX (dest[cur_x], (pixel * 255) / (SUBSAMPLE * SUBSAMPLE));
740 741 742 743 744

      last_x = cur_x + 1;
    }

  if (current != 0)
745
    fill_run (dest + last_x, (255 * current)/ SUBSAMPLE, width - last_x);
746 747 748
}

static void
749 750
render_blob (Blob        *blob,
             PixelRegion *dest)
751
{
752 753 754 755
  gint      i;
  gint      h;
  guchar   *s;
  gpointer  pr;
756

757 758
  for (pr = pixel_regions_register (1, dest);
       pr != NULL;
759 760 761 762 763 764 765 766 767 768 769 770 771
       pr = pixel_regions_process (pr))
    {
      h = dest->h;
      s = dest->data;

      for (i=0; i<h; i++)
	{
	  render_blob_line (blob, s,
			    dest->x, dest->y + i, dest->w);
	  s += dest->rowstride;
	}
    }
}