gimpink.c 18.2 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
2 3
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7 8 9 10 11 12 13 14
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 */
Sven Neumann's avatar
Sven Neumann committed
17

18 19
#include "config.h"

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

22
#include <gegl.h>
Sven Neumann's avatar
Sven Neumann committed
23

24 25
#include "libgimpmath/gimpmath.h"

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

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

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

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

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

42
#include "gimp-intl.h"
43

44

45
#define SUBSAMPLE 8
46

47

48
/*  local function prototypes  */
49

Michael Natterer's avatar
Michael Natterer committed
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
static void       gimp_ink_finalize       (GObject          *object);

static void       gimp_ink_paint          (GimpPaintCore    *paint_core,
                                           GimpDrawable     *drawable,
                                           GimpPaintOptions *paint_options,
                                           const GimpCoords *coords,
                                           GimpPaintState    paint_state,
                                           guint32           time);
static TempBuf  * gimp_ink_get_paint_area (GimpPaintCore    *paint_core,
                                           GimpDrawable     *drawable,
                                           GimpPaintOptions *paint_options,
                                           const GimpCoords *coords);
static GimpUndo * gimp_ink_push_undo      (GimpPaintCore    *core,
                                           GimpImage        *image,
                                           const gchar      *undo_desc);

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

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

static void      render_blob              (GimpBlob         *blob,
                                           PixelRegion      *dest);
82

83

84
G_DEFINE_TYPE (GimpInk, gimp_ink, GIMP_TYPE_PAINT_CORE)
Michael Natterer's avatar
Michael Natterer committed
85 86

#define parent_class gimp_ink_parent_class
87

88

89
void
90 91
gimp_ink_register (Gimp                      *gimp,
                   GimpPaintRegisterCallback  callback)
92
{
93 94
  (* callback) (gimp,
                GIMP_TYPE_INK,
95
                GIMP_TYPE_INK_OPTIONS,
96 97 98
                "gimp-ink",
                _("Ink"),
                "gimp-tool-ink");
99 100 101
}

static void
102
gimp_ink_class_init (GimpInkClass *klass)
103
{
104 105
  GObjectClass       *object_class     = G_OBJECT_CLASS (klass);
  GimpPaintCoreClass *paint_core_class = GIMP_PAINT_CORE_CLASS (klass);
106

Michael Natterer's avatar
Michael Natterer committed
107
  object_class->finalize           = gimp_ink_finalize;
108

109 110
  paint_core_class->paint          = gimp_ink_paint;
  paint_core_class->get_paint_area = gimp_ink_get_paint_area;
Michael Natterer's avatar
Michael Natterer committed
111
  paint_core_class->push_undo      = gimp_ink_push_undo;
112 113 114
}

static void
115
gimp_ink_init (GimpInk *ink)
116 117 118 119
{
}

static void
120
gimp_ink_finalize (GObject *object)
121
{
122
  GimpInk *ink = GIMP_INK (object);
123

Michael Natterer's avatar
Michael Natterer committed
124 125 126 127 128 129
  if (ink->start_blob)
    {
      g_free (ink->start_blob);
      ink->start_blob = NULL;
    }

130
  if (ink->last_blob)
131
    {
132 133
      g_free (ink->last_blob);
      ink->last_blob = NULL;
134
    }
135

136
  G_OBJECT_CLASS (parent_class)->finalize (object);
137 138
}

139
static void
140 141 142
gimp_ink_paint (GimpPaintCore    *paint_core,
                GimpDrawable     *drawable,
                GimpPaintOptions *paint_options,
143
                const GimpCoords *coords,
144 145
                GimpPaintState    paint_state,
                guint32           time)
146
{
147
  GimpInk *ink = GIMP_INK (paint_core);
148 149

  switch (paint_state)
150
    {
151 152
      GimpCoords last_coords;

153
    case GIMP_PAINT_STATE_INIT:
154 155 156 157
      gimp_paint_core_get_last_coords (paint_core, &last_coords);

      if (coords->x == last_coords.x &&
          coords->y == last_coords.y)
158
        {
Michael Natterer's avatar
Michael Natterer committed
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
          /*  start with new blobs if we're not interpolating  */

          if (ink->start_blob)
            {
              g_free (ink->start_blob);
              ink->start_blob = NULL;
            }

          if (ink->last_blob)
            {
              g_free (ink->last_blob);
              ink->last_blob = NULL;
            }
        }
      else if (ink->last_blob)
        {
          /*  save the start blob of the line for undo otherwise  */

          if (ink->start_blob)
            g_free (ink->start_blob);

Michael Natterer's avatar
Michael Natterer committed
180
          ink->start_blob = gimp_blob_duplicate (ink->last_blob);
181
        }
182
      break;
183

184
    case GIMP_PAINT_STATE_MOTION:
185
      gimp_ink_motion (paint_core, drawable, paint_options, coords, time);
186
      break;
187

188
    case GIMP_PAINT_STATE_FINISH:
189 190
      break;
    }
191
}
jtl's avatar
jtl committed
192

193 194 195
static TempBuf *
gimp_ink_get_paint_area (GimpPaintCore    *paint_core,
                         GimpDrawable     *drawable,
196 197
                         GimpPaintOptions *paint_options,
                         const GimpCoords *coords)
198
{
Sven Neumann's avatar
Sven Neumann committed
199
  GimpInk *ink = GIMP_INK (paint_core);
200 201 202 203 204
  gint     x, y;
  gint     width, height;
  gint     dwidth, dheight;
  gint     x1, y1, x2, y2;
  gint     bytes;
jtl's avatar
jtl committed
205

206
  bytes = gimp_drawable_bytes_with_alpha (drawable);
207

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

210 211
  dwidth  = gimp_item_get_width  (GIMP_ITEM (drawable));
  dheight = gimp_item_get_height (GIMP_ITEM (drawable));
212

213 214 215 216
  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);
217

218 219 220 221 222 223 224
  /*  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
225

226
  return paint_core->canvas_buf;
227
}
228

229 230 231 232 233 234 235 236 237 238 239 240
static GimpUndo *
gimp_ink_push_undo (GimpPaintCore *core,
                    GimpImage     *image,
                    const gchar   *undo_desc)
{
  return gimp_image_undo_push (image, GIMP_TYPE_INK_UNDO,
                               GIMP_UNDO_INK, undo_desc,
                               0,
                               "paint-core", core,
                               NULL);
}

241
static void
242 243 244
gimp_ink_motion (GimpPaintCore    *paint_core,
                 GimpDrawable     *drawable,
                 GimpPaintOptions *paint_options,
245
                 const GimpCoords *coords,
246
                 guint32           time)
247
{
248 249 250
  GimpInk        *ink     = GIMP_INK (paint_core);
  GimpInkOptions *options = GIMP_INK_OPTIONS (paint_options);
  GimpContext    *context = GIMP_CONTEXT (paint_options);
251
  GimpImage      *image;
Michael Natterer's avatar
Michael Natterer committed
252 253
  GimpBlob       *blob_union = NULL;
  GimpBlob       *blob_to_render;
254 255 256
  TempBuf        *area;
  guchar          col[MAX_CHANNELS];
  PixelRegion     blob_maskPR;
257

258
  image = gimp_item_get_image (GIMP_ITEM (drawable));
259

260 261 262
  if (! ink->last_blob)
    {
      ink->last_blob = ink_pen_ellipse (options,
263 264 265 266 267
                                        coords->x,
                                        coords->y,
                                        coords->pressure,
                                        coords->xtilt,
                                        coords->ytilt,
268
                                        100);
269

Michael Natterer's avatar
Michael Natterer committed
270 271 272
      if (ink->start_blob)
        g_free (ink->start_blob);

Michael Natterer's avatar
Michael Natterer committed
273
      ink->start_blob = gimp_blob_duplicate (ink->last_blob);
Michael Natterer's avatar
Michael Natterer committed
274

275
      blob_to_render = ink->last_blob;
276 277 278
    }
  else
    {
Michael Natterer's avatar
Michael Natterer committed
279 280 281 282 283 284 285
      GimpBlob *blob = ink_pen_ellipse (options,
                                        coords->x,
                                        coords->y,
                                        coords->pressure,
                                        coords->xtilt,
                                        coords->ytilt,
                                        coords->velocity * 100);
286

Michael Natterer's avatar
Michael Natterer committed
287
      blob_union = gimp_blob_convex_union (ink->last_blob, blob);
Sven Neumann's avatar
Sven Neumann committed
288

289 290
      g_free (ink->last_blob);
      ink->last_blob = blob;
291

292 293
      blob_to_render = blob_union;
    }
294

295
  /* Get the buffer */
Michael Natterer's avatar
Michael Natterer committed
296
  ink->cur_blob = blob_to_render;
297 298
  area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options,
                                         coords);
Michael Natterer's avatar
Michael Natterer committed
299 300
  ink->cur_blob = NULL;

301 302
  if (! area)
    return;
jtl's avatar
jtl committed
303

304 305
  gimp_image_get_foreground (image, context, gimp_drawable_type (drawable),
                             col);
306

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

310
  /*  color the pixels  */
311
  color_pixels (temp_buf_get_data (paint_core->canvas_buf), col,
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
                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);

328
  render_blob (blob_to_render, &blob_maskPR);
329 330 331 332 333 334 335 336 337 338 339 340 341 342

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

344 345
  if (blob_union)
    g_free (blob_union);
346 347
}

Michael Natterer's avatar
Michael Natterer committed
348
static GimpBlob *
349 350
ink_pen_ellipse (GimpInkOptions *options,
                 gdouble         x_center,
351 352 353 354 355
                 gdouble         y_center,
                 gdouble         pressure,
                 gdouble         xtilt,
                 gdouble         ytilt,
                 gdouble         velocity)
356
{
Michael Natterer's avatar
Michael Natterer committed
357 358 359 360 361 362 363 364
  GimpBlobFunc blob_function;
  gdouble      size;
  gdouble      tsin, tcos;
  gdouble      aspect, radmin;
  gdouble      x,y;
  gdouble      tscale;
  gdouble      tscale_c;
  gdouble      tscale_s;
365

366 367
  /* Adjust the size depending on pressure. */

368
  size = options->size * (1.0 + options->size_sensitivity *
369
                          (2.0 * pressure - 1.0));
370

371 372 373 374
  /* Adjust the size further depending on pointer velocity and
   * velocity-sensitivity.  These 'magic constants' are 'feels
   * natural' tigert-approved. --ADM
   */
375 376 377 378 379

  if (velocity < 3.0)
    velocity = 3.0;

#ifdef VERBOSE
380
  g_printerr ("%g (%g) -> ", size, velocity);
381
#endif
382

383 384 385
  size = (options->vel_sensitivity *
          ((4.5 * size) / (1.0 + options->vel_sensitivity * (2.0 * velocity)))
          + (1.0 - options->vel_sensitivity) * size);
386 387

#ifdef VERBOSE
388
  g_printerr ("%g\n", (gfloat) size);
389 390 391 392
#endif

  /* Clamp resulting size to sane limits */

393 394
  if (size > options->size * (1.0 + options->size_sensitivity))
    size = options->size * (1.0 + options->size_sensitivity);
395

396 397
  if (size * SUBSAMPLE < 1.0)
    size = 1.0 / SUBSAMPLE;
398 399

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

Raph Levien's avatar
Raph Levien committed
401
  /* I'm not happy with the way the brush widget info is combined with
402 403 404 405
   * 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
406

407
  tscale   = options->tilt_sensitivity * 10.0;
408 409 410
  tscale_c = tscale * cos (gimp_deg_to_rad (options->tilt_angle));
  tscale_s = tscale * sin (gimp_deg_to_rad (options->tilt_angle));

411
  x = (options->blob_aspect * cos (options->blob_angle) +
412
       xtilt * tscale_c - ytilt * tscale_s);
413
  y = (options->blob_aspect * sin (options->blob_angle) +
414 415
       ytilt * tscale_c + xtilt * tscale_s);

Raph Levien's avatar
Raph Levien committed
416
#ifdef VERBOSE
417 418 419
  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
420
#endif
421

Sven Neumann's avatar
Sven Neumann committed
422
  aspect = sqrt (SQR (x) + SQR (y));
423 424 425

  if (aspect != 0)
    {
426 427
      tcos = x / aspect;
      tsin = y / aspect;
428 429 430
    }
  else
    {
431 432 433 434 435 436 437 438 439 440
      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)
    {
441
    case GIMP_INK_BLOB_TYPE_CIRCLE:
Michael Natterer's avatar
Michael Natterer committed
442
      blob_function = gimp_blob_ellipse;
443 444 445
      break;

    case GIMP_INK_BLOB_TYPE_SQUARE:
Michael Natterer's avatar
Michael Natterer committed
446
      blob_function = gimp_blob_square;
447 448 449
      break;

    case GIMP_INK_BLOB_TYPE_DIAMOND:
Michael Natterer's avatar
Michael Natterer committed
450
      blob_function = gimp_blob_diamond;
451 452 453 454
      break;

    default:
      g_return_val_if_reached (NULL);
455
      break;
456
    }
457

458 459 460 461 462 463
  return (* blob_function) (x_center * SUBSAMPLE,
                            y_center * SUBSAMPLE,
                            radmin * aspect * tcos,
                            radmin * aspect * tsin,
                            -radmin * tsin,
                            radmin * tcos);
464 465
}

466

467 468 469
/*********************************/
/*  Rendering functions          */
/*********************************/
470

471
/* Some of this stuff should probably be combined with the
472 473 474 475 476 477 478 479
 * code it was copied from in paint_core.c; but I wanted
 * to learn this stuff, so I've kept it simple.
 *
 * The following only supports CONSTANT mode. Incremental
 * would, I think, interact strangely with the way we
 * do things. But it wouldn't be hard to implement at all.
 */

Sven Neumann's avatar
Sven Neumann committed
480 481 482 483 484
enum
{
  ROW_START,
  ROW_STOP
};
485 486 487 488

/* The insertion sort here, for SUBSAMPLE = 8, tends to beat out
 * qsort() by 4x with CFLAGS=-O2, 2x with CFLAGS=-g
 */
489 490
static void
insert_sort (gint *data,
491
             gint  n)
492
{
493
  gint i, j, k;
494

495
  for (i = 2; i < 2 * n; i += 2)
496
    {
Sven Neumann's avatar
Sven Neumann committed
497 498 499
      gint tmp1 = data[i];
      gint tmp2 = data[i + 1];

500
      j = 0;
Sven Neumann's avatar
Sven Neumann committed
501

502
      while (data[j] < tmp1)
503
        j += 2;
504

505
      for (k = i; k > j; k -= 2)
506 507 508 509
        {
          data[k]     = data[k - 2];
          data[k + 1] = data[k - 1];
        }
510

511 512
      data[j]     = tmp1;
      data[j + 1] = tmp2;
513 514 515 516 517
    }
}

static void
fill_run (guchar *dest,
518 519
          guchar  alpha,
          gint    w)
520 521 522 523 524 525 526 527
{
  if (alpha == 255)
    {
      memset (dest, 255, w);
    }
  else
    {
      while (w--)
528 529 530 531
        {
          *dest = MAX (*dest, alpha);
          dest++;
        }
532 533 534 535
    }
}

static void
Michael Natterer's avatar
Michael Natterer committed
536 537 538 539 540
render_blob_line (GimpBlob *blob,
                  guchar   *dest,
                  gint      x,
                  gint      y,
                  gint      width)
541
{
542 543 544
  gint  buf[4 * SUBSAMPLE];
  gint *data    = buf;
  gint  n       = 0;
545 546
  gint  i, j;
  gint  current = 0;  /* number of filled rows at this point
547 548
                       * in the scan line
                       */
549
  gint last_x;
550 551

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

553
  j = y * SUBSAMPLE - blob->y;
554
  for (i = 0; i < SUBSAMPLE; i++)
555 556
    {
      if (j >= blob->height)
557
        break;
558

559
      if ((j > 0) && (blob->data[j].left <= blob->data[j].right))
560 561 562 563 564 565 566
        {
          data[2 * n]                     = blob->data[j].left;
          data[2 * n + 1]                 = ROW_START;
          data[2 * SUBSAMPLE + 2 * n]     = blob->data[j].right;
          data[2 * SUBSAMPLE + 2 * n + 1] = ROW_STOP;
          n++;
        }
567 568 569 570 571 572
      j++;
    }

  /*   If we have less than SUBSAMPLE rows, compress */
  if (n < SUBSAMPLE)
    {
573
      for (i = 0; i < 2 * n; i++)
574
        data[2 * n + i] = data[2 * SUBSAMPLE + i];
575 576 577 578 579 580 581 582 583 584 585 586
    }

  /*   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)
587
        current++;
588
      else
589
        current--;
590 591 592 593 594 595
      data += 2;
      n--;
    }

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

597 598 599
  /* Render the row */

  last_x = 0;
600
  for (i = 0; i < n;)
601
    {
602
      gint cur_x = data[2 * i] / SUBSAMPLE - x;
603
      gint pixel;
604 605 606

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

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

      while (i<n)
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
        {
          gint tmp_x = data[2 * i] / SUBSAMPLE;

          if (tmp_x - x != cur_x)
            break;

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

          i++;
        }
632

633
      dest[cur_x] = MAX (dest[cur_x], (pixel * 255) / (SUBSAMPLE * SUBSAMPLE));
634 635 636 637 638

      last_x = cur_x + 1;
    }

  if (current != 0)
639
    fill_run (dest + last_x, (255 * current)/ SUBSAMPLE, width - last_x);
640 641 642
}

static void
Michael Natterer's avatar
Michael Natterer committed
643
render_blob (GimpBlob    *blob,
644
             PixelRegion *dest)
645
{
646
  gpointer  pr;
647

648 649
  for (pr = pixel_regions_register (1, dest);
       pr != NULL;
650 651
       pr = pixel_regions_process (pr))
    {
Sven Neumann's avatar
Sven Neumann committed
652 653 654
      guchar *d = dest->data;
      gint    h = dest->h;
      gint    y;
655

Sven Neumann's avatar
Sven Neumann committed
656
      for (y = 0; y < h; y++, d += dest->rowstride)
657
        {
Sven Neumann's avatar
Sven Neumann committed
658
          render_blob_line (blob, d, dest->x, dest->y + y, dest->w);
659
        }
660 661
    }
}