gimpink.c 29.8 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"

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

24
#include <gtk/gtk.h>
Sven Neumann's avatar
Sven Neumann committed
25

26
#include "libgimpwidgets/gimpwidgets.h"
27

28
#include "tools-types.h"
Sven Neumann's avatar
Sven Neumann committed
29

Michael Natterer's avatar
Michael Natterer committed
30 31 32 33 34
#include "base/pixel-region.h"
#include "base/temp-buf.h"
#include "base/tile.h"
#include "base/tile-manager.h"

35 36
#include "paint-funcs/paint-funcs.h"

Michael Natterer's avatar
Michael Natterer committed
37
#include "core/gimp.h"
38
#include "core/gimpchannel.h"
39
#include "core/gimpimage.h"
40
#include "core/gimpimage-undo-push.h"
41
#include "core/gimptoolinfo.h"
42

43 44
#include "paint/gimppaintoptions.h"

45 46
#include "widgets/gimphelp-ids.h"

47 48
#include "display/gimpdisplay.h"

49
#include "gimpinkoptions.h"
50 51
#include "gimpinktool.h"
#include "gimpinktool-blob.h"
52
#include "gimptoolcontrol.h"
53

54
#include "gimp-intl.h"
55

56

57
#define SUBSAMPLE 8
58

59

60
/*  local function prototypes  */
61

62 63 64
static void        gimp_ink_tool_class_init      (GimpInkToolClass *klass);
static void        gimp_ink_tool_init            (GimpInkTool      *tool);

65
static void        gimp_ink_tool_finalize        (GObject          *object);
66

67
static void        gimp_ink_tool_control         (GimpTool         *tool,
68
                                                  GimpToolAction    action,
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
                                                  GimpDisplay      *gdisp);
static void        gimp_ink_tool_button_press    (GimpTool         *tool,
                                                  GimpCoords       *coords,
                                                  guint32           time,
                                                  GdkModifierType   state,
                                                  GimpDisplay      *gdisp);
static void        gimp_ink_tool_button_release  (GimpTool         *tool,
                                                  GimpCoords       *coords,
                                                  guint32           time,
                                                  GdkModifierType   state,
                                                  GimpDisplay      *gdisp);
static void        gimp_ink_tool_motion          (GimpTool         *tool,
                                                  GimpCoords       *coords,
                                                  guint32           time,
                                                  GdkModifierType   state,
                                                  GimpDisplay      *gdisp);
static void        gimp_ink_tool_cursor_update   (GimpTool         *tool,
                                                  GimpCoords       *coords,
                                                  GdkModifierType   state,
                                                  GimpDisplay      *gdisp);

90
static Blob *      ink_pen_ellipse      (GimpInkOptions  *options,
91
                                         gdouble          x_center,
92 93 94 95 96
                                         gdouble          y_center,
                                         gdouble          pressure,
                                         gdouble          xtilt,
                                         gdouble          ytilt,
                                         gdouble          velocity);
97 98 99 100 101 102 103 104 105 106 107 108

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

109 110 111
static void        ink_init             (GimpInkTool     *ink_tool,
					 GimpDrawable    *drawable,
					 gdouble          x,
112
					 gdouble          y);
113
static void        ink_finish           (GimpInkTool     *ink_tool,
114
					 GimpDrawable    *drawable);
115 116
static void        ink_cleanup          (void);

Michael Natterer's avatar
Michael Natterer committed
117
/*  Rendering functions  */
118 119
static void        ink_set_paint_area   (GimpInkTool     *ink_tool,
					 GimpDrawable    *drawable,
120
					 Blob            *blob);
121
static void        ink_paste            (GimpInkTool     *ink_tool,
122 123 124 125 126 127 128 129
					 GimpDrawable    *drawable,
					 Blob            *blob);

static void        ink_to_canvas_tiles  (GimpInkTool     *ink_tool,
					 Blob            *blob,
					 guchar          *color);

static void        ink_set_undo_tiles   (GimpDrawable    *drawable,
130
					 gint             x,
131
					 gint             y,
132
					 gint             w,
133
					 gint             h);
134
static void        ink_set_canvas_tiles (gint             x,
135
					 gint             y,
136
					 gint             w,
137
					 gint             h);
138 139


140 141 142 143 144 145 146 147 148 149 150 151 152
/* local variables */

/*  undo blocks variables  */
static TileManager *undo_tiles = NULL;

/* Tiles used to render the stroke at 1 byte/pp */
static TileManager *canvas_tiles = NULL;

/* Flat buffer that is used to used to render the dirty region
 * for composition onto the destination drawable
 */
static TempBuf *canvas_buf = NULL;

153
static GimpToolClass *parent_class = NULL;
154

155

156
/*  public functions  */
157

158
void
Nate Summers's avatar
Nate Summers committed
159
gimp_ink_tool_register (GimpToolRegisterCallback  callback,
160
                        gpointer                  data)
161
{
Nate Summers's avatar
Nate Summers committed
162
  (* callback) (GIMP_TYPE_INK_TOOL,
163 164
                GIMP_TYPE_INK_OPTIONS,
                gimp_ink_options_gui,
165 166 167
                GIMP_CONTEXT_FOREGROUND_MASK |
                GIMP_CONTEXT_BACKGROUND_MASK |
                GIMP_CONTEXT_OPACITY_MASK    |
168
                GIMP_CONTEXT_PAINT_MODE_MASK,
169
                "gimp-ink-tool",
170
                _("Ink"),
171
                _("Draw in ink"),
172
                N_("In_k"), "K",
173
                NULL, GIMP_HELP_TOOL_INK,
Nate Summers's avatar
Nate Summers committed
174
                GIMP_STOCK_TOOL_INK,
175
                data);
176 177
}

178
GType
179 180
gimp_ink_tool_get_type (void)
{
181
  static GType tool_type = 0;
182 183 184

  if (! tool_type)
    {
185
      static const GTypeInfo tool_info =
186
      {
187 188 189 190 191 192
        sizeof (GimpInkToolClass),
	(GBaseInitFunc) NULL,
	(GBaseFinalizeFunc) NULL,
	(GClassInitFunc) gimp_ink_tool_class_init,
	NULL,           /* class_finalize */
	NULL,           /* class_data     */
193
	sizeof (GimpInkTool),
194 195
	0,              /* n_preallocs    */
	(GInstanceInitFunc) gimp_ink_tool_init,
196 197
      };

198
      tool_type = g_type_register_static (GIMP_TYPE_TOOL,
199
					  "GimpInkTool",
200
                                          &tool_info, 0);
201 202 203 204 205
    }

  return tool_type;
}

206 207 208

/*  private functions  */

209 210 211
static void
gimp_ink_tool_class_init (GimpInkToolClass *klass)
{
212
  GObjectClass   *object_class;
213 214
  GimpToolClass  *tool_class;

215 216
  object_class = G_OBJECT_CLASS (klass);
  tool_class   = GIMP_TOOL_CLASS (klass);
217

218
  parent_class = g_type_class_peek_parent (klass);
219

220
  object_class->finalize     = gimp_ink_tool_finalize;
221

222 223 224 225 226
  tool_class->control        = gimp_ink_tool_control;
  tool_class->button_press   = gimp_ink_tool_button_press;
  tool_class->button_release = gimp_ink_tool_button_release;
  tool_class->motion         = gimp_ink_tool_motion;
  tool_class->cursor_update  = gimp_ink_tool_cursor_update;
227 228 229 230 231 232 233 234
}

static void
gimp_ink_tool_init (GimpInkTool *ink_tool)
{
  GimpTool *tool;

  tool = GIMP_TOOL (ink_tool);
235

236 237
  gimp_tool_control_set_motion_mode (tool->control, GIMP_MOTION_MODE_EXACT);
  gimp_tool_control_set_tool_cursor (tool->control, GIMP_INK_TOOL_CURSOR);
238 239 240
}

static void
241
gimp_ink_tool_finalize (GObject *object)
242 243 244 245 246 247
{
  GimpInkTool *ink_tool;

  ink_tool = GIMP_INK_TOOL (object);

  if (ink_tool->last_blob)
248 249 250 251
    {
      g_free (ink_tool->last_blob);
      ink_tool->last_blob = NULL;
    }
252 253 254

  ink_cleanup ();

255
  G_OBJECT_CLASS (parent_class)->finalize (object);
256 257
}

258
static void
259 260 261
gimp_ink_tool_control (GimpTool       *tool,
                       GimpToolAction  action,
                       GimpDisplay    *gdisp)
262
{
263
  GimpInkTool *ink_tool;
264

265
  ink_tool = GIMP_INK_TOOL (tool);
266

267 268 269 270
  switch (action)
    {
    case PAUSE:
      break;
271

272 273
    case RESUME:
      break;
274

275 276 277
    case HALT:
      ink_cleanup ();
      break;
278

279 280 281
    default:
      break;
    }
282 283

  GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
284 285
}

286 287 288 289 290 291
static void
gimp_ink_tool_button_press (GimpTool        *tool,
                            GimpCoords      *coords,
                            guint32          time,
                            GdkModifierType  state,
                            GimpDisplay     *gdisp)
292
{
293 294 295
  GimpInkTool    *ink_tool;
  GimpInkOptions *options;
  GimpDrawable   *drawable;
296
  GimpCoords      curr_coords;
297
  gint            off_x, off_y;
298
  Blob           *b;
299

300
  ink_tool = GIMP_INK_TOOL (tool);
301
  options  = GIMP_INK_OPTIONS (tool->tool_info->tool_options);
302

303
  drawable = gimp_image_active_drawable (gdisp->gimage);
jtl's avatar
jtl committed
304

305 306
  curr_coords = *coords;

307
  gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y);
308

309 310
  curr_coords.x -= off_x;
  curr_coords.y -= off_y;
311 312

  ink_init (ink_tool, drawable, curr_coords.x, curr_coords.y);
jtl's avatar
jtl committed
313

314
  gimp_tool_control_activate (tool->control);
315
  tool->gdisp = gdisp;
316

317
  /*  pause the current selection  */
318
  gimp_image_selection_control (gdisp->gimage, GIMP_SELECTION_PAUSE);
319

320
  b = ink_pen_ellipse (options,
321 322 323 324 325
                       curr_coords.x,
                       curr_coords.y,
		       curr_coords.pressure,
                       curr_coords.xtilt,
                       curr_coords.ytilt,
326
		       10.0);
jtl's avatar
jtl committed
327

328 329
  ink_paste (ink_tool, drawable, b);
  ink_tool->last_blob = b;
330

331 332
  time_smoother_init (ink_tool, time);
  ink_tool->last_time = time;
333

334 335
  dist_smoother_init (ink_tool, 0.0);
  ink_tool->init_velocity = TRUE;
336 337 338

  ink_tool->lastx = curr_coords.x;
  ink_tool->lasty = curr_coords.y;
jtl's avatar
jtl committed
339

340 341
  gimp_display_flush_now (gdisp);
}
jtl's avatar
jtl committed
342

343 344 345 346 347 348 349 350 351
static void
gimp_ink_tool_button_release (GimpTool        *tool,
                              GimpCoords      *coords,
                              guint32          time,
                              GdkModifierType  state,
                              GimpDisplay     *gdisp)
{
  GimpInkTool *ink_tool;
  GimpImage   *gimage;
jtl's avatar
jtl committed
352

353
  ink_tool = GIMP_INK_TOOL (tool);
354

355
  gimage = gdisp->gimage;
356

357
  /*  resume the current selection  */
358
  gimp_image_selection_control (gdisp->gimage, GIMP_SELECTION_RESUME);
359

360
  /*  Set tool state to inactive -- no longer painting */
361
  gimp_tool_control_halt (tool->control);
362

363 364 365
  /*  free the last blob  */
  g_free (ink_tool->last_blob);
  ink_tool->last_blob = NULL;
Raph Levien's avatar
Raph Levien committed
366

367
  ink_finish (ink_tool, gimp_image_active_drawable (gdisp->gimage));
368
  gimp_image_flush (gdisp->gimage);
369
}
370

371 372 373 374 375 376 377
static void
gimp_ink_tool_motion (GimpTool        *tool,
                      GimpCoords      *coords,
                      guint32          time,
                      GdkModifierType  state,
                      GimpDisplay     *gdisp)
{
378 379 380
  GimpInkTool    *ink_tool;
  GimpInkOptions *options;
  GimpDrawable   *drawable;
381
  GimpCoords      curr_coords;
382
  gint            off_x, off_y;
383 384 385 386 387
  Blob           *b;
  Blob           *blob_union;
  gdouble         velocity;
  gdouble         dist;
  gdouble         lasttime, thistime;
388

389
  ink_tool = GIMP_INK_TOOL (tool);
390
  options  = GIMP_INK_OPTIONS (tool->tool_info->tool_options);
391

392
  drawable = gimp_image_active_drawable (gdisp->gimage);
393

394 395
  curr_coords = *coords;

396
  gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y);
397

398 399
  curr_coords.x -= off_x;
  curr_coords.y -= off_y;
400

401
  lasttime = ink_tool->last_time;
402

403 404
  time_smoother_add (ink_tool, time);
  thistime = ink_tool->last_time = time_smoother_result (ink_tool);
405

406 407 408 409 410 411
  /* 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 */
412

413 414
  if (thistime == lasttime)
    thistime = lasttime + 1;
415

416 417 418
  if (ink_tool->init_velocity)
    {
      dist_smoother_init (ink_tool,
419 420 421 422
			  dist = sqrt ((ink_tool->lastx - curr_coords.x) *
                                       (ink_tool->lastx - curr_coords.x) +
				       (ink_tool->lasty - curr_coords.y) *
                                       (ink_tool->lasty - curr_coords.y)));
423 424 425 426 427
      ink_tool->init_velocity = FALSE;
    }
  else
    {
      dist_smoother_add (ink_tool,
428 429 430 431
			 sqrt ((ink_tool->lastx - curr_coords.x) *
                               (ink_tool->lastx - curr_coords.x) +
			       (ink_tool->lasty - curr_coords.y) *
                               (ink_tool->lasty - curr_coords.y)));
432

433 434
      dist = dist_smoother_result (ink_tool);
    }
435

436 437
  ink_tool->lastx = curr_coords.x;
  ink_tool->lasty = curr_coords.y;
438

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

441
  b = ink_pen_ellipse (options,
442 443 444 445 446
                       curr_coords.x,
                       curr_coords.y,
                       curr_coords.pressure,
                       curr_coords.xtilt,
		       curr_coords.ytilt,
447
                       velocity);
448

449 450 451
  blob_union = blob_convex_union (ink_tool->last_blob, b);
  g_free (ink_tool->last_blob);
  ink_tool->last_blob = b;
452

453
  ink_paste (ink_tool, drawable, blob_union);
454
  g_free (blob_union);
455

456 457
  gimp_display_flush_now (gdisp);
}
jtl's avatar
jtl committed
458

459 460 461 462 463 464
static void
gimp_ink_tool_cursor_update (GimpTool        *tool,
                             GimpCoords      *coords,
                             GdkModifierType  state,
                             GimpDisplay     *gdisp)
{
465
  GdkCursorType ctype = GDK_TOP_LEFT_ARROW;
466

467
  if (gimp_display_coords_in_active_drawable (gdisp, coords))
468
    {
469 470
      GimpChannel *selection = gimp_image_get_mask (gdisp->gimage);

471 472 473
      /*  One more test--is there a selected region?
       *  if so, is cursor inside?
       */
474
      if (gimp_channel_is_empty (selection))
475
        ctype = GIMP_MOUSE_CURSOR;
476
      else if (gimp_channel_value (selection, coords->x, coords->y))
477
        ctype = GIMP_MOUSE_CURSOR;
478
    }
479

480
  gimp_tool_control_set_cursor (tool->control, ctype);
481 482

  GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, gdisp);
483 484
}

485

486
static Blob *
487 488 489 490 491 492 493
ink_pen_ellipse (GimpInkOptions *options,
                 gdouble         x_center,
		 gdouble         y_center,
		 gdouble         pressure,
		 gdouble         xtilt,
		 gdouble         ytilt,
		 gdouble         velocity)
494
{
495 496 497 498 499 500 501 502
  BlobFunc function = blob_ellipse;
  gdouble  size;
  gdouble  tsin, tcos;
  gdouble  aspect, radmin;
  gdouble  x,y;
  gdouble  tscale;
  gdouble  tscale_c;
  gdouble  tscale_s;
503

504 505
  /* Adjust the size depending on pressure. */

506
  size = options->size * (1.0 + options->size_sensitivity *
507
                          (2.0 * pressure - 1.0) );
508 509 510 511 512 513 514 515 516

  /* Adjust the size further depending on pointer velocity
     and velocity-sensitivity.  These 'magic constants' are
     'feels natural' tigert-approved. --ADM */

  if (velocity < 3.0)
    velocity = 3.0;

#ifdef VERBOSE
517
  g_printerr ("%g (%g) -> ", size, velocity);
518
#endif
519

520 521 522
  size = (options->vel_sensitivity *
          ((4.5 * size) / (1.0 + options->vel_sensitivity * (2.0 * velocity)))
          + (1.0 - options->vel_sensitivity) * size);
523 524

#ifdef VERBOSE
525
  g_printerr ("%g\n", (gfloat) size);
526 527 528 529
#endif

  /* Clamp resulting size to sane limits */

530 531
  if (size > options->size * (1.0 + options->size_sensitivity))
    size = options->size * (1.0 + options->size_sensitivity);
532

533 534
  if (size * SUBSAMPLE < 1.0)
    size = 1.0 / SUBSAMPLE;
535 536

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

Raph Levien's avatar
Raph Levien committed
538 539 540 541
  /* I'm not happy with the way the brush widget info is combined with
     tilt info from the brush. My personal feeling is that representing
     both as affine transforms would make the most sense. -RLL */

542 543 544 545
  tscale = options->tilt_sensitivity * 10.0;
  tscale_c = tscale * cos (gimp_deg_to_rad (options->tilt_angle));
  tscale_s = tscale * sin (gimp_deg_to_rad (options->tilt_angle));

546
  x = (options->blob_aspect * cos (options->blob_angle) +
547
       xtilt * tscale_c - ytilt * tscale_s);
548
  y = (options->blob_aspect * sin (options->blob_angle) +
549 550
       ytilt * tscale_c + xtilt * tscale_s);

Raph Levien's avatar
Raph Levien committed
551
#ifdef VERBOSE
552 553 554
  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
555
#endif
556 557

  aspect = sqrt (x*x + y*y);
558 559 560

  if (aspect != 0)
    {
561 562
      tcos = x / aspect;
      tsin = y / aspect;
563 564 565
    }
  else
    {
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
      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:
      function = blob_ellipse;
      break;

    case GIMP_INK_BLOB_TYPE_SQUARE:
      function = blob_square;
      break;

    case GIMP_INK_BLOB_TYPE_DIAMOND:
      function = blob_diamond;
      break;
587
    }
588

589 590 591
  return (* function) (x_center * SUBSAMPLE,
                       y_center * SUBSAMPLE,
                       radmin * aspect * tcos,
592
                       radmin * aspect * tsin,
593 594
                       -radmin * tsin,
                       radmin * tcos);
595 596 597
}

static void
598 599
dist_smoother_init (GimpInkTool *ink_tool,
		    gdouble      initval)
600
{
601
  gint i;
602

603
  ink_tool->dt_index = 0;
604

605
  for (i = 0; i < DIST_SMOOTHER_BUFFER; i++)
606
    {
607 608 609
      ink_tool->dt_buffer[i] = initval;
    }
}
610

611 612 613 614 615
static gdouble
dist_smoother_result (GimpInkTool *ink_tool)
{
  gint    i;
  gdouble result = 0.0;
616

617 618 619
  for (i = 0; i < DIST_SMOOTHER_BUFFER; i++)
    {
      result += ink_tool->dt_buffer[i];
620
    }
621 622

  return (result / (gdouble) DIST_SMOOTHER_BUFFER);
623 624 625
}

static void
626 627
dist_smoother_add (GimpInkTool *ink_tool,
		   gdouble      value)
628
{
629
  ink_tool->dt_buffer[ink_tool->dt_index] = value;
Michael Natterer's avatar
Michael Natterer committed
630

631 632 633
  if ((++ink_tool->dt_index) == DIST_SMOOTHER_BUFFER)
    ink_tool->dt_index = 0;
}
634 635


636 637 638 639 640
static void
time_smoother_init (GimpInkTool *ink_tool,
		    guint32      initval)
{
  gint i;
641

642
  ink_tool->ts_index = 0;
643

644
  for (i = 0; i < TIME_SMOOTHER_BUFFER; i++)
645
    {
646
      ink_tool->ts_buffer[i] = initval;
647
    }
648 649 650 651 652 653 654 655 656
}

static gdouble
time_smoother_result (GimpInkTool *ink_tool)
{
  gint    i;
  guint64 result = 0;

  for (i = 0; i < TIME_SMOOTHER_BUFFER; i++)
657
    {
658
      result += ink_tool->ts_buffer[i];
659
    }
660

661 662 663 664 665 666
#ifdef _MSC_VER
  return (gdouble) (gint64) (result / TIME_SMOOTHER_BUFFER);
#else
  return (result / TIME_SMOOTHER_BUFFER);
#endif
}
667 668

static void
669 670
time_smoother_add (GimpInkTool *ink_tool,
		   guint32      value)
671 672 673 674 675 676 677
{
  ink_tool->ts_buffer[ink_tool->ts_index] = value;

  if ((++ink_tool->ts_index) == TIME_SMOOTHER_BUFFER)
    ink_tool->ts_index = 0;
}

678
static void
679
ink_init (GimpInkTool  *ink_tool,
680
	  GimpDrawable *drawable,
681 682
	  gdouble       x,
	  gdouble       y)
683
{
684 685
  GimpItem *item = GIMP_ITEM (drawable);

686
  /*  Allocate the undo structure  */
687
  if (undo_tiles)
688
    tile_manager_unref (undo_tiles);
689

690 691
  undo_tiles = tile_manager_new (gimp_item_width  (item),
				 gimp_item_height (item),
692
				 gimp_drawable_bytes (drawable));
693 694

  /*  Allocate the canvas blocks structure  */
695 696 697
  if (canvas_tiles)
    tile_manager_unref (canvas_tiles);

698 699
  canvas_tiles = tile_manager_new (gimp_item_width  (item),
				   gimp_item_height (item), 1);
700 701 702 703 704 705 706

  /*  Get the initial undo extents  */
  ink_tool->x1 = ink_tool->x2 = x;
  ink_tool->y1 = ink_tool->y2 = y;
}

static void
707 708
ink_finish (GimpInkTool  *ink_tool,
	    GimpDrawable *drawable)
709
{
710 711
  GimpImage *gimage;

712
  gimp_drawable_push_undo (drawable, _("Ink"),
713 714 715
                           ink_tool->x1, ink_tool->y1,
                           ink_tool->x2, ink_tool->y2,
                           undo_tiles, TRUE);
716 717

  tile_manager_unref (undo_tiles);
718 719
  undo_tiles = NULL;

720 721 722
  gimage = gimp_item_get_image (GIMP_ITEM (drawable));

  /*  invalidate the previews -- have to do it here, because
723 724
   *  it is not done during the actual painting.
   */
725
  gimp_viewable_invalidate_preview (GIMP_VIEWABLE (drawable));
726
  gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage));
727 728 729 730 731 732 733 734
}

static void
ink_cleanup (void)
{
  /*  If the undo tiles exist, nuke them  */
  if (undo_tiles)
    {
735
      tile_manager_unref (undo_tiles);
736 737 738 739 740 741
      undo_tiles = NULL;
    }

  /*  If the canvas blocks exist, nuke them  */
  if (canvas_tiles)
    {
742
      tile_manager_unref (canvas_tiles);
743 744 745 746 747
      canvas_tiles = NULL;
    }

  /*  Free the temporary buffer if it exist  */
  if (canvas_buf)
748 749 750 751
    {
      temp_buf_free (canvas_buf);
      canvas_buf = NULL;
    }
752 753 754 755 756 757
}

/*********************************
 *  Rendering functions          *
 *********************************/

758
/* Some of this stuff should probably be combined with the
759 760 761 762 763 764 765 766 767
 * 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.
 */

static void
768 769
ink_set_paint_area (GimpInkTool  *ink_tool,
		    GimpDrawable *drawable,
770 771
		    Blob         *blob)
{
772 773 774 775
  GimpItem *item = GIMP_ITEM (drawable);
  gint      x, y, width, height;
  gint      x1, y1, x2, y2;
  gint      bytes;
776

777 778
  blob_bounds (blob, &x, &y, &width, &height);

779
  bytes = gimp_drawable_bytes_with_alpha (drawable);
780

781 782 783 784
  x1 = CLAMP (x / SUBSAMPLE - 1,            0, gimp_item_width  (item));
  y1 = CLAMP (y / SUBSAMPLE - 1,            0, gimp_item_height (item));
  x2 = CLAMP ((x + width)  / SUBSAMPLE + 2, 0, gimp_item_width  (item));
  y2 = CLAMP ((y + height) / SUBSAMPLE + 2, 0, gimp_item_height (item));
785 786 787 788 789 790 791 792 793 794 795 796

  /*  configure the canvas buffer  */
  if ((x2 - x1) && (y2 - y1))
    canvas_buf = temp_buf_resize (canvas_buf, bytes, x1, y1,
				  (x2 - x1), (y2 - y1));
}

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
 */
797 798 799
static void
insert_sort (gint *data,
	     gint  n)
800
{
801 802
  gint i, j, k;
  gint tmp1, tmp2;
803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825

  for (i=2; i<2*n; i+=2)
    {
      tmp1 = data[i];
      tmp2 = data[i+1];
      j = 0;
      while (data[j] < tmp1)
	j += 2;

      for (k=i; k>j; k-=2)
	{
	  data[k] = data[k-2];
	  data[k+1] = data[k-1];
	}

      data[j] = tmp1;
      data[j+1] = tmp2;
    }
}

static void
fill_run (guchar *dest,
	  guchar  alpha,
826
	  gint    w)
827 828 829 830 831 832 833 834 835
{
  if (alpha == 255)
    {
      memset (dest, 255, w);
    }
  else
    {
      while (w--)
	{
836
	  *dest = MAX(*dest, alpha);
837 838 839 840 841 842
	  dest++;
	}
    }
}

static void
843 844 845 846 847
render_blob_line (Blob   *blob,
		  guchar *dest,
		  gint    x,
		  gint    y,
		  gint    width)
848
{
849 850 851
  gint  buf[4 * SUBSAMPLE];
  gint *data    = buf;
  gint  n       = 0;
852 853 854 855 856
  gint  i, j;
  gint  current = 0;  /* number of filled rows at this point
		       * in the scan line
		       */
  gint last_x;
857 858

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

860
  j = y * SUBSAMPLE - blob->y;
861
  for (i = 0; i < SUBSAMPLE; i++)
862 863 864
    {
      if (j >= blob->height)
	break;
865

866 867
      if ((j > 0) && (blob->data[j].left <= blob->data[j].right))
	{
868 869 870 871
	  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;
872 873 874 875 876 877 878 879
	  n++;
	}
      j++;
    }

  /*   If we have less than SUBSAMPLE rows, compress */
  if (n < SUBSAMPLE)
    {
880 881
      for (i = 0; i < 2 * n; i++)
	data[2 * n + i] = data[2 * SUBSAMPLE + i];
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
    }

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

904 905 906
  /* Render the row */

  last_x = 0;
907
  for (i = 0; i < n;)
908
    {
909
      gint cur_x = data[2 * i] / SUBSAMPLE - x;
910
      gint pixel;
911 912 913

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

      /* Compute the value for this pixel */
917
      pixel = current * SUBSAMPLE;
918 919 920

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

923 924 925
	  if (tmp_x - x != cur_x)
	    break;

926
	  if (data[2 * i + 1] == ROW_START)
927 928
	    {
	      current++;
929
	      pixel += ((tmp_x + 1) * SUBSAMPLE) - data[2 * i];
930 931 932 933
	    }
	  else
	    {
	      current--;
934
	      pixel -= ((tmp_x + 1) * SUBSAMPLE) - data[2 * i];
935
	    }
936

937 938 939
	  i++;
	}

940
      dest[cur_x] = MAX (dest[cur_x], (pixel * 255) / (SUBSAMPLE * SUBSAMPLE));