gimpink.c 18.1 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

50 51 52 53 54
static void      gimp_ink_finalize       (GObject          *object);

static void      gimp_ink_paint          (GimpPaintCore    *paint_core,
                                          GimpDrawable     *drawable,
                                          GimpPaintOptions *paint_options,
55
                                          const GimpCoords *coords,
56 57 58 59
                                          GimpPaintState    paint_state,
                                          guint32           time);
static TempBuf * gimp_ink_get_paint_area (GimpPaintCore    *paint_core,
                                          GimpDrawable     *drawable,
60 61
                                          GimpPaintOptions *paint_options,
                                          const GimpCoords *coords);
62 63 64
static GimpUndo* gimp_ink_push_undo      (GimpPaintCore    *core,
                                          GimpImage        *image,
                                          const gchar      *undo_desc);
65 66 67 68

static void      gimp_ink_motion         (GimpPaintCore    *paint_core,
                                          GimpDrawable     *drawable,
                                          GimpPaintOptions *paint_options,
69
                                          const GimpCoords *coords,
70 71 72 73 74 75 76 77 78 79 80 81
                                          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      render_blob             (Blob             *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 180
          /*  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);

          ink->start_blob = 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
  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;
252 253
  Blob           *blob_union = NULL;
  Blob           *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 273 274
      if (ink->start_blob)
        g_free (ink->start_blob);

      ink->start_blob = blob_duplicate (ink->last_blob);

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

      blob_union = 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 348
}

static Blob *
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
{
357
  BlobFunc blob_function;
358 359 360 361 362 363 364
  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 441
      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:
442
      blob_function = blob_ellipse;
443 444 445
      break;

    case GIMP_INK_BLOB_TYPE_SQUARE:
446
      blob_function = blob_square;
447 448 449
      break;

    case GIMP_INK_BLOB_TYPE_DIAMOND:
450 451 452 453 454
      blob_function = blob_diamond;
      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
536
render_blob_line (Blob   *blob,
537 538 539 540
                  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
643 644
render_blob (Blob        *blob,
             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
    }
}