gimpink.c 29.5 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 39 40
#include "core/gimpdrawable.h"
#include "core/gimpimage.h"
#include "core/gimpimage-mask.h"
41
#include "core/gimpimage-undo-push.h"
42
#include "core/gimptoolinfo.h"
43

44 45
#include "paint/gimppaintoptions.h"

46 47
#include "display/gimpdisplay.h"

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

53
#include "gimp-intl.h"
54

55

56
#define SUBSAMPLE 8
57

58

59
/*  local function prototypes  */
60

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

64
static void        gimp_ink_tool_finalize        (GObject          *object);
65

66
static void        gimp_ink_tool_control         (GimpTool         *tool,
67
                                                  GimpToolAction    action,
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
                                                  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);

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

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

static void        ink_init             (GimpInkTool     *ink_tool, 
					 GimpDrawable    *drawable, 
					 gdouble          x, 
					 gdouble          y);
static void        ink_finish           (GimpInkTool     *ink_tool, 
					 GimpDrawable    *drawable);
114 115
static void        ink_cleanup          (void);

Michael Natterer's avatar
Michael Natterer committed
116
/*  Rendering functions  */
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
static void        ink_set_paint_area   (GimpInkTool     *ink_tool, 
					 GimpDrawable    *drawable, 
					 Blob            *blob);
static void        ink_paste            (GimpInkTool     *ink_tool, 
					 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,
					 gint             x, 
					 gint             y,
					 gint             w, 
					 gint             h);
static void        ink_set_canvas_tiles (gint             x, 
					 gint             y,
					 gint             w, 
					 gint             h);
137 138


139 140 141 142 143 144 145 146 147 148 149 150 151
/* 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;

152
static GimpToolClass *parent_class = NULL;
153

154

155
/*  public functions  */
156

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

175
GType
176 177
gimp_ink_tool_get_type (void)
{
178
  static GType tool_type = 0;
179 180 181

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

195 196 197
      tool_type = g_type_register_static (GIMP_TYPE_TOOL,
					  "GimpInkTool", 
                                          &tool_info, 0);
198 199 200 201 202
    }

  return tool_type;
}

203 204 205

/*  private functions  */

206 207 208
static void
gimp_ink_tool_class_init (GimpInkToolClass *klass)
{
209
  GObjectClass   *object_class;
210 211
  GimpToolClass  *tool_class;

212 213
  object_class = G_OBJECT_CLASS (klass);
  tool_class   = GIMP_TOOL_CLASS (klass);
214

215
  parent_class = g_type_class_peek_parent (klass);
216

217
  object_class->finalize     = gimp_ink_tool_finalize;
218

219 220 221 222 223
  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;
224 225 226 227 228 229 230 231
}

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

  tool = GIMP_TOOL (ink_tool);
232

233 234
  gimp_tool_control_set_motion_mode (tool->control, GIMP_MOTION_MODE_EXACT);
  gimp_tool_control_set_tool_cursor (tool->control, GIMP_INK_TOOL_CURSOR);
235 236 237
}

static void
238
gimp_ink_tool_finalize (GObject *object)
239 240 241 242 243 244
{
  GimpInkTool *ink_tool;

  ink_tool = GIMP_INK_TOOL (object);

  if (ink_tool->last_blob)
245 246 247 248
    {
      g_free (ink_tool->last_blob);
      ink_tool->last_blob = NULL;
    }
249 250 251

  ink_cleanup ();

252
  G_OBJECT_CLASS (parent_class)->finalize (object);
253 254
}

255
static void
256 257 258
gimp_ink_tool_control (GimpTool       *tool,
                       GimpToolAction  action,
                       GimpDisplay    *gdisp)
259
{
260
  GimpInkTool *ink_tool;
261

262
  ink_tool = GIMP_INK_TOOL (tool);
263

264 265 266 267
  switch (action)
    {
    case PAUSE:
      break;
268

269 270
    case RESUME:
      break;
271

272 273 274
    case HALT:
      ink_cleanup ();
      break;
275

276 277 278
    default:
      break;
    }
279 280

  GIMP_TOOL_CLASS (parent_class)->control (tool, action, gdisp);
281 282
}

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

297
  ink_tool = GIMP_INK_TOOL (tool);
298
  options  = GIMP_INK_OPTIONS (tool->tool_info->tool_options);
299

300
  drawable = gimp_image_active_drawable (gdisp->gimage);
jtl's avatar
jtl committed
301

302 303
  curr_coords = *coords;

304
  gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y);
305

306 307
  curr_coords.x -= off_x;
  curr_coords.y -= off_y;
308 309

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

311
  gimp_tool_control_activate (tool->control);
312
  tool->gdisp = gdisp; 
313

314
  /*  pause the current selection  */
315
  gimp_image_selection_control (gdisp->gimage, GIMP_SELECTION_PAUSE);
316

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

325 326
  ink_paste (ink_tool, drawable, b);
  ink_tool->last_blob = b;
327

328 329
  time_smoother_init (ink_tool, time);
  ink_tool->last_time = time;
330

331 332
  dist_smoother_init (ink_tool, 0.0);
  ink_tool->init_velocity = TRUE;
333 334 335

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

337 338
  gimp_display_flush_now (gdisp);
}
jtl's avatar
jtl committed
339

340 341 342 343 344 345 346 347 348
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
349

350
  ink_tool = GIMP_INK_TOOL (tool);
351

352
  gimage = gdisp->gimage;
353

354
  /*  resume the current selection  */
355
  gimp_image_selection_control (gdisp->gimage, GIMP_SELECTION_RESUME);
356

357
  /*  Set tool state to inactive -- no longer painting */
358
  gimp_tool_control_halt (tool->control);
359

360 361 362
  /*  free the last blob  */
  g_free (ink_tool->last_blob);
  ink_tool->last_blob = NULL;
Raph Levien's avatar
Raph Levien committed
363

364
  ink_finish (ink_tool, gimp_image_active_drawable (gdisp->gimage));
365
  gimp_image_flush (gdisp->gimage);
366
}
367

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

386
  ink_tool = GIMP_INK_TOOL (tool);
387
  options  = GIMP_INK_OPTIONS (tool->tool_info->tool_options);
388

389
  drawable = gimp_image_active_drawable (gdisp->gimage);
390

391 392
  curr_coords = *coords;

393
  gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y);
394

395 396
  curr_coords.x -= off_x;
  curr_coords.y -= off_y;
397

398
  lasttime = ink_tool->last_time;
399

400 401
  time_smoother_add (ink_tool, time);
  thistime = ink_tool->last_time = time_smoother_result (ink_tool);
402

403 404 405 406 407 408
  /* 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 */
409

410 411
  if (thistime == lasttime)
    thistime = lasttime + 1;
412

413 414 415
  if (ink_tool->init_velocity)
    {
      dist_smoother_init (ink_tool,
416 417 418 419
			  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)));
420 421 422 423 424
      ink_tool->init_velocity = FALSE;
    }
  else
    {
      dist_smoother_add (ink_tool,
425 426 427 428
			 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)));
429

430 431
      dist = dist_smoother_result (ink_tool);
    }
432

433 434
  ink_tool->lastx = curr_coords.x;
  ink_tool->lasty = curr_coords.y;
435

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

438
  b = ink_pen_ellipse (options,
439 440 441 442 443
                       curr_coords.x,
                       curr_coords.y,
                       curr_coords.pressure,
                       curr_coords.xtilt,
		       curr_coords.ytilt,
444
                       velocity);
445

446 447 448
  blob_union = blob_convex_union (ink_tool->last_blob, b);
  g_free (ink_tool->last_blob);
  ink_tool->last_blob = b;
449

450 451
  ink_paste (ink_tool, drawable, blob_union);  
  g_free (blob_union);
452

453 454
  gimp_display_flush_now (gdisp);
}
jtl's avatar
jtl committed
455

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

464
  if (gimp_display_coords_in_active_drawable (gdisp, coords))
465
    {
466 467 468 469 470 471 472
      /*  One more test--is there a selected region?
       *  if so, is cursor inside?
       */
      if (gimp_image_mask_is_empty (gdisp->gimage))
        ctype = GIMP_MOUSE_CURSOR;
      else if (gimp_image_mask_value (gdisp->gimage, coords->x, coords->y))
        ctype = GIMP_MOUSE_CURSOR;
473
    }
474

475
  gimp_tool_control_set_cursor (tool->control, ctype);
476 477

  GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, gdisp);
478 479
}

480

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

499 500
  /* Adjust the size depending on pressure. */

501
  size = options->size * (1.0 + options->size_sensitivity *
502
                          (2.0 * pressure - 1.0) );
503 504 505 506 507 508 509 510 511

  /* 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
512
  g_print ("%f (%f) -> ", (float)size, (float)velocity);
513 514
#endif  

515 516 517
  size = (options->vel_sensitivity *
          ((4.5 * size) / (1.0 + options->vel_sensitivity * (2.0 * velocity)))
          + (1.0 - options->vel_sensitivity) * size);
518 519

#ifdef VERBOSE
520
  g_print ("%f\n", (float)size);
521 522 523 524
#endif

  /* Clamp resulting size to sane limits */

525 526
  if (size > options->size * (1.0 + options->size_sensitivity))
    size = options->size * (1.0 + options->size_sensitivity);
527

528 529
  if (size * SUBSAMPLE < 1.0)
    size = 1.0 / SUBSAMPLE;
530 531

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

Raph Levien's avatar
Raph Levien committed
533 534 535 536
  /* 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 */

537 538 539 540
  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));

541
  x = (options->blob_aspect * cos (options->blob_angle) +
542
       xtilt * tscale_c - ytilt * tscale_s);
543
  y = (options->blob_aspect * sin (options->blob_angle) +
544 545
       ytilt * tscale_c + xtilt * tscale_s);

Raph Levien's avatar
Raph Levien committed
546 547
#ifdef VERBOSE
  g_print ("angle %g aspect %g; %g %g; %g %g\n",
548
	   options->blob_angle, options->blob_aspect, tscale_c, tscale_s, x, y);
Raph Levien's avatar
Raph Levien committed
549
#endif
550 551

  aspect = sqrt (x*x + y*y);
552 553 554

  if (aspect != 0)
    {
555 556
      tcos = x / aspect;
      tsin = y / aspect;
557 558 559
    }
  else
    {
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
      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;
581
    }
582

583 584 585 586 587 588
  return (* function) (x_center * SUBSAMPLE,
                       y_center * SUBSAMPLE,
                       radmin * aspect * tcos,
                       radmin * aspect * tsin,  
                       -radmin * tsin,
                       radmin * tcos);
589 590 591
}

static void
592 593
dist_smoother_init (GimpInkTool *ink_tool,
		    gdouble      initval)
594
{
595
  gint i;
596

597
  ink_tool->dt_index = 0;
598

599
  for (i = 0; i < DIST_SMOOTHER_BUFFER; i++)
600
    {
601 602 603
      ink_tool->dt_buffer[i] = initval;
    }
}
604

605 606 607 608 609
static gdouble
dist_smoother_result (GimpInkTool *ink_tool)
{
  gint    i;
  gdouble result = 0.0;
610

611 612 613
  for (i = 0; i < DIST_SMOOTHER_BUFFER; i++)
    {
      result += ink_tool->dt_buffer[i];
614
    }
615 616

  return (result / (gdouble) DIST_SMOOTHER_BUFFER);
617 618 619
}

static void
620 621
dist_smoother_add (GimpInkTool *ink_tool,
		   gdouble      value)
622
{
623
  ink_tool->dt_buffer[ink_tool->dt_index] = value;
Michael Natterer's avatar
Michael Natterer committed
624

625 626 627
  if ((++ink_tool->dt_index) == DIST_SMOOTHER_BUFFER)
    ink_tool->dt_index = 0;
}
628 629


630 631 632 633 634
static void
time_smoother_init (GimpInkTool *ink_tool,
		    guint32      initval)
{
  gint i;
635

636
  ink_tool->ts_index = 0;
637

638
  for (i = 0; i < TIME_SMOOTHER_BUFFER; i++)
639
    {
640
      ink_tool->ts_buffer[i] = initval;
641
    }
642 643 644 645 646 647 648 649 650
}

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

  for (i = 0; i < TIME_SMOOTHER_BUFFER; i++)
651
    {
652
      result += ink_tool->ts_buffer[i];
653
    }
654

655 656 657 658 659 660
#ifdef _MSC_VER
  return (gdouble) (gint64) (result / TIME_SMOOTHER_BUFFER);
#else
  return (result / TIME_SMOOTHER_BUFFER);
#endif
}
661 662

static void
663 664
time_smoother_add (GimpInkTool *ink_tool,
		   guint32      value)
665 666 667 668 669 670 671
{
  ink_tool->ts_buffer[ink_tool->ts_index] = value;

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

672
static void
673
ink_init (GimpInkTool  *ink_tool,
674 675 676
	  GimpDrawable *drawable, 
	  gdouble       x,
	  gdouble       y)
677
{
678 679
  GimpItem *item = GIMP_ITEM (drawable);

680
  /*  Allocate the undo structure  */
681
  if (undo_tiles)
682
    tile_manager_unref (undo_tiles);
683

684 685
  undo_tiles = tile_manager_new (gimp_item_width  (item),
				 gimp_item_height (item),
686
				 gimp_drawable_bytes (drawable));
687 688

  /*  Allocate the canvas blocks structure  */
689 690 691
  if (canvas_tiles)
    tile_manager_unref (canvas_tiles);

692 693
  canvas_tiles = tile_manager_new (gimp_item_width  (item),
				   gimp_item_height (item), 1);
694 695 696 697 698 699 700

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

static void
701 702
ink_finish (GimpInkTool  *ink_tool,
	    GimpDrawable *drawable)
703
{
704
  gimp_drawable_push_undo (drawable, _("Ink"),
705 706 707
                           ink_tool->x1, ink_tool->y1,
                           ink_tool->x2, ink_tool->y2,
                           undo_tiles, TRUE);
708 709

  tile_manager_unref (undo_tiles);
710 711 712 713 714
  undo_tiles = NULL;

  /*  invalidate the drawable--have to do it here, because
   *  it is not done during the actual painting.
   */
715
  gimp_viewable_invalidate_preview (GIMP_VIEWABLE (drawable));
716 717 718 719 720 721 722 723
}

static void
ink_cleanup (void)
{
  /*  If the undo tiles exist, nuke them  */
  if (undo_tiles)
    {
724
      tile_manager_unref (undo_tiles);
725 726 727 728 729 730
      undo_tiles = NULL;
    }

  /*  If the canvas blocks exist, nuke them  */
  if (canvas_tiles)
    {
731
      tile_manager_unref (canvas_tiles);
732 733 734 735 736
      canvas_tiles = NULL;
    }

  /*  Free the temporary buffer if it exist  */
  if (canvas_buf)
737 738 739 740
    {
      temp_buf_free (canvas_buf);
      canvas_buf = NULL;
    }
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
}

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

/* Some of this stuff should probably be combined with the 
 * 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
757
ink_set_paint_area (GimpInkTool  *ink_tool, 
758 759 760
		    GimpDrawable *drawable, 
		    Blob         *blob)
{
761 762 763 764
  GimpItem *item = GIMP_ITEM (drawable);
  gint      x, y, width, height;
  gint      x1, y1, x2, y2;
  gint      bytes;
765

766 767
  blob_bounds (blob, &x, &y, &width, &height);

768 769
  bytes = gimp_drawable_has_alpha (drawable) ?
    gimp_drawable_bytes (drawable) : gimp_drawable_bytes (drawable) + 1;
770

771 772 773 774
  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));
775 776 777 778 779 780 781 782 783 784 785 786

  /*  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
 */
787 788 789
static void
insert_sort (gint *data,
	     gint  n)
790
{
791 792
  gint i, j, k;
  gint tmp1, tmp2;
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815

  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,
816
	  gint    w)
817 818 819 820 821 822 823 824 825
{
  if (alpha == 255)
    {
      memset (dest, 255, w);
    }
  else
    {
      while (w--)
	{
826
	  *dest = MAX(*dest, alpha);
827 828 829 830 831 832
	  dest++;
	}
    }
}

static void
833 834 835 836 837
render_blob_line (Blob   *blob,
		  guchar *dest,
		  gint    x,
		  gint    y,
		  gint    width)
838
{
839 840 841
  gint  buf[4 * SUBSAMPLE];
  gint *data    = buf;
  gint  n       = 0;
842 843 844 845 846
  gint  i, j;
  gint  current = 0;  /* number of filled rows at this point
		       * in the scan line
		       */
  gint last_x;
847 848 849 850

  /* Sort start and ends for all lines */
  
  j = y * SUBSAMPLE - blob->y;
851
  for (i = 0; i < SUBSAMPLE; i++)
852 853 854
    {
      if (j >= blob->height)
	break;
855

856 857
      if ((j > 0) && (blob->data[j].left <= blob->data[j].right))
	{
858 859 860 861
	  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;
862 863 864 865 866 867 868 869
	  n++;
	}
      j++;
    }

  /*   If we have less than SUBSAMPLE rows, compress */
  if (n < SUBSAMPLE)
    {
870 871
      for (i = 0; i < 2 * n; i++)
	data[2 * n + i] = data[2 * SUBSAMPLE + i];
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896
    }

  /*   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--;
  
  /* Render the row */

  last_x = 0;
897
  for (i = 0; i < n;)
898
    {
899
      gint cur_x = data[2 * i] / SUBSAMPLE - x;
900
      gint pixel;
901 902 903

      /* Fill in portion leading up to this pixel */
      if (current && cur_x != last_x)
904
	fill_run (dest + last_x, (255 * current) / SUBSAMPLE, cur_x - last_x);
905 906 907 908 909 910

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

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

913 914 915
	  if (tmp_x - x != cur_x)
	    break;

916
	  if (data[2 * i + 1] == ROW_START)
917 918
	    {
	      current++;
919
	      pixel += ((tmp_x + 1) * SUBSAMPLE) - data[2 * i];
920 921 922 923
	    }
	  else
	    {
	      current--;
924
	      pixel -= ((tmp_x + 1) * SUBSAMPLE) - data[2 * i];
925 926 927 928 929
	    }
	  
	  i++;
	}

930
      dest[cur_x] = MAX (dest[cur_x], (pixel * 255) / (SUBSAMPLE * SUBSAMPLE));
931 932 933 934 935

      last_x = cur_x + 1;
    }

  if (current != 0)
936
    fill_run (dest + last_x, (255 * current)/ SUBSAMPLE, width - last_x);
937 938 939
}

static void
940 941
render_blob (PixelRegion *dest,
	     Blob        *blob)
942
{
943 944 945 946
  gint      i;
  gint      h;
  guchar   *s;
  gpointer  pr;
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964

  for (pr = pixel_regions_register (1, dest); 
       pr != NULL; 
       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;
	}
    }
}

static void
965
ink_paste (GimpInkTool  *ink_tool, 
966 967 968
	   GimpDrawable *drawable,
	   Blob         *blob)
{
969
  GimpImage   *gimage;
Michael Natterer's avatar
Michael Natterer committed
970
  GimpContext *context;
971 972
  PixelRegion  srcPR;
  gint         offx, offy;
973
  guchar       col[MAX_CHANNELS];
974

975
  if (! (gimage = gimp_item_get_image (GIMP_ITEM (drawable))))
976
    return;
977

978
  context = GIMP_CONTEXT (GIMP_TOOL (ink_tool)->tool_info->tool_options);
Michael Natterer's avatar
Michael Natterer committed
979

980 981
  /* Get the the buffer */
  ink_set_paint_area (ink_tool, drawable, blob);
982 983 984 985
 
  /* check to make sure there is actually a canvas to draw on */
  if (!canvas_buf)
    return;
986

987
  gimp_image_get_foreground (gimage, drawable, col);
988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015

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

  /*  color the pixels  */
  color_pixels (temp_buf_data (canvas_buf), col,
		canvas_buf->width * canvas_buf->height, canvas_buf->bytes);

  /*  set undo blocks  */
  ink_set_undo_tiles (drawable,
		      canvas_buf->x, canvas_buf->y,
		      canvas_buf->width, canvas_buf->height);

  /*  initialize any invalid canvas tiles  */
  ink_set_canvas_tiles (canvas_buf->x, canvas_buf->y,
			canvas_buf->width, canvas_buf->height);

  ink_to_canvas_tiles (ink_tool, blob, col);

  /*  initialize canvas buf source pixel regions  */
  srcPR.bytes = canvas_buf->bytes;
  srcPR.x = 0; srcPR.y = 0;
  srcPR.w = canvas_buf->width;
  srcPR.h = canvas_buf->height;
  srcPR.rowstride = canvas_buf->width * canvas_buf