gimpink.c 20.4 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
  GimpInk *ink = GIMP_INK (paint_core);
173 174

  switch (paint_state)
175
    {
176
    case INIT_PAINT:
177 178 179 180 181 182 183 184
      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;
        }
185
      break;
186

187 188
    case MOTION_PAINT:
      gimp_ink_motion (paint_core, drawable, paint_options, time);
189
      break;
190

191 192
    case FINISH_PAINT:
      break;
jtl's avatar
jtl committed
193

194 195 196
    default:
      break;
    }
197
}
jtl's avatar
jtl committed
198

199 200 201 202
static TempBuf *
gimp_ink_get_paint_area (GimpPaintCore    *paint_core,
                         GimpDrawable     *drawable,
                         GimpPaintOptions *paint_options)
203
{
204 205 206 207 208 209
  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
210

211
  bytes = gimp_drawable_bytes_with_alpha (drawable);
212

213
  blob_bounds (ink->blob, &x, &y, &width, &height);
214

215 216
  dwidth  = gimp_item_width  (GIMP_ITEM (drawable));
  dheight = gimp_item_height (GIMP_ITEM (drawable));
217

218 219 220 221
  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);
222

223 224 225 226 227 228 229
  /*  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
230

231
  return paint_core->canvas_buf;
232
}
233

234
static void
235 236 237 238
gimp_ink_motion (GimpPaintCore    *paint_core,
                 GimpDrawable     *drawable,
                 GimpPaintOptions *paint_options,
                 guint32           time)
239
{
240 241 242 243
  GimpInk        *ink     = GIMP_INK (paint_core);
  GimpInkOptions *options = GIMP_INK_OPTIONS (paint_options);
  GimpContext    *context = GIMP_CONTEXT (paint_options);
  GimpImage      *gimage;
244 245
  Blob           *blob_union = NULL;
  Blob           *blob_to_render;
246 247 248
  TempBuf        *area;
  guchar          col[MAX_CHANNELS];
  PixelRegion     blob_maskPR;
249

250
  gimage = gimp_item_get_image (GIMP_ITEM (drawable));
251

252 253 254 255 256 257 258 259 260
  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);
261

262 263
      time_smoother_init (ink, time);
      ink->last_time = time;
264

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

268 269
      ink->lastx = paint_core->cur_coords.x;
      ink->lasty = paint_core->cur_coords.y;
270

271
      blob_to_render = ink->last_blob;
272 273 274
    }
  else
    {
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
      Blob    *blob;
      gdouble  lasttime, thistime;
      gdouble  dist;
      gdouble  velocity;

      lasttime = ink->last_time;

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

      /* 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
       */
      if (thistime == lasttime)
        thistime = lasttime + 1;

      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)
        {
          dist_smoother_init (ink, dist);
          ink->init_velocity = FALSE;
        }
      else
        {
          dist_smoother_add (ink, dist);
          dist = dist_smoother_result (ink);
        }

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

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

      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);

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

328 329
      blob_to_render = blob_union;
    }
330

331
  /* Get the the buffer */
332
  ink->blob = blob_to_render;
333

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

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

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

343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
  /*  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);

361
  render_blob (blob_to_render, &blob_maskPR);
362 363 364 365 366 367 368 369 370 371 372 373 374 375

  /*  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);
376

377 378
  if (blob_union)
    g_free (blob_union);
379 380 381
}

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

399 400
  /* Adjust the size depending on pressure. */

401
  size = options->size * (1.0 + options->size_sensitivity *
402
                          (2.0 * pressure - 1.0));
403

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

  if (velocity < 3.0)
    velocity = 3.0;

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

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

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

  /* Clamp resulting size to sane limits */

426 427
  if (size > options->size * (1.0 + options->size_sensitivity))
    size = options->size * (1.0 + options->size_sensitivity);
428

429 430
  if (size * SUBSAMPLE < 1.0)
    size = 1.0 / SUBSAMPLE;
431 432

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

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

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

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

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

455
  aspect = sqrt (x * x + y * y);
456 457 458

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

    case GIMP_INK_BLOB_TYPE_SQUARE:
479
      blob_function = blob_square;
480 481 482
      break;

    case GIMP_INK_BLOB_TYPE_DIAMOND:
483 484 485 486 487
      blob_function = blob_diamond;
      break;

    default:
      g_return_val_if_reached (NULL);
488
      break;
489
    }
490

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

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

505
  ink->dt_index = 0;
506

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

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

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

  return (result / (gdouble) DIST_SMOOTHER_BUFFER);
525 526 527
}

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

533 534
  if ((++ink->dt_index) == DIST_SMOOTHER_BUFFER)
    ink->dt_index = 0;
535
}
536

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

543
  ink->ts_index = 0;
544

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

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

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

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

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

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


580 581 582
/*********************************/
/*  Rendering functions          */
/*********************************/
583

584
/* Some of this stuff should probably be combined with the
585 586 587 588 589 590 591 592 593 594 595 596 597
 * 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
 */
598 599 600
static void
insert_sort (gint *data,
	     gint  n)
601
{
602 603
  gint i, j, k;
  gint tmp1, tmp2;
604

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

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

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

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

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

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

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

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

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

  /*   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--;
704

705 706 707
  /* Render the row */

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

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

      /* Compute the value for this pixel */
718
      pixel = current * SUBSAMPLE;
719 720 721

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

724 725 726
	  if (tmp_x - x != cur_x)
	    break;

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

738 739 740
	  i++;
	}

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

      last_x = cur_x + 1;
    }

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

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

759 760
  for (pr = pixel_regions_register (1, dest);
       pr != NULL;
761 762 763 764 765 766 767 768 769 770 771 772 773
       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;
	}
    }
}