gimppaintcore.c 44 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
Elliot Lee's avatar
Elliot Lee committed
2 3
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
4
 * This program is free software: you can redistribute it and/or modify
Elliot Lee's avatar
Elliot Lee committed
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
Elliot Lee's avatar
Elliot Lee committed
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/>.
Elliot Lee's avatar
Elliot Lee committed
16
 */
Sven Neumann's avatar
Sven Neumann committed
17

18 19
#include "config.h"

Elliot Lee's avatar
Elliot Lee committed
20
#include <string.h>
21

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

24
#include "libgimpbase/gimpbase.h"
25
#include "libgimpmath/gimpmath.h"
26

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

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

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

36
#include "core/gimp.h"
37
#include "core/gimp-utils.h"
38 39
#include "core/gimpdrawable.h"
#include "core/gimpimage.h"
40
#include "core/gimpimage-undo.h"
41
#include "core/gimppickable.h"
42
#include "core/gimpprojection.h"
43

44
#include "gimppaintcore.h"
45
#include "gimppaintcoreundo.h"
46
#include "gimppaintoptions.h"
47

48
#include "gimpairbrush.h"
49

50
#include "gimp-intl.h"
51

52
#define STROKE_BUFFER_INIT_SIZE      2000
53

54 55 56 57 58 59 60
enum
{
  PROP_0,
  PROP_UNDO_DESC
};


61
/*  local function prototypes  */
62

63
static void      gimp_paint_core_finalize            (GObject          *object);
64 65 66 67 68 69 70 71
static void      gimp_paint_core_set_property        (GObject          *object,
                                                      guint             property_id,
                                                      const GValue     *value,
                                                      GParamSpec       *pspec);
static void      gimp_paint_core_get_property        (GObject          *object,
                                                      guint             property_id,
                                                      GValue           *value,
                                                      GParamSpec       *pspec);
72 73 74 75

static gboolean  gimp_paint_core_real_start          (GimpPaintCore    *core,
                                                      GimpDrawable     *drawable,
                                                      GimpPaintOptions *paint_options,
76
                                                      const GimpCoords *coords,
77
                                                      GError          **error);
78 79 80
static gboolean  gimp_paint_core_real_pre_paint      (GimpPaintCore    *core,
                                                      GimpDrawable     *drawable,
                                                      GimpPaintOptions *options,
81
                                                      GimpPaintState    paint_state,
82
                                                      guint32           time);
83 84 85
static void      gimp_paint_core_real_paint          (GimpPaintCore    *core,
                                                      GimpDrawable     *drawable,
                                                      GimpPaintOptions *options,
86
                                                      const GimpCoords *coords,
87
                                                      GimpPaintState    paint_state,
88
                                                      guint32           time);
89 90 91
static void      gimp_paint_core_real_post_paint     (GimpPaintCore    *core,
                                                      GimpDrawable     *drawable,
                                                      GimpPaintOptions *options,
92
                                                      GimpPaintState    paint_state,
93
                                                      guint32           time);
94 95
static void      gimp_paint_core_real_interpolate    (GimpPaintCore    *core,
                                                      GimpDrawable     *drawable,
96 97
                                                      GimpPaintOptions *options,
                                                      guint32           time);
98 99
static TempBuf * gimp_paint_core_real_get_paint_area (GimpPaintCore    *core,
                                                      GimpDrawable     *drawable,
100 101
                                                      GimpPaintOptions *options,
                                                      const GimpCoords *coords);
102 103 104
static GimpUndo* gimp_paint_core_real_push_undo      (GimpPaintCore    *core,
                                                      GimpImage        *image,
                                                      const gchar      *undo_desc);
Elliot Lee's avatar
Elliot Lee committed
105

106 107 108 109 110 111 112
static void      paint_mask_to_canvas_tiles          (GimpPaintCore    *core,
                                                      PixelRegion      *paint_maskPR,
                                                      gdouble           paint_opacity);
static void      paint_mask_to_canvas_buf            (GimpPaintCore    *core,
                                                      PixelRegion      *paint_maskPR,
                                                      gdouble           paint_opacity);
static void      canvas_tiles_to_canvas_buf          (GimpPaintCore    *core);
113

Elliot Lee's avatar
Elliot Lee committed
114

115
G_DEFINE_TYPE (GimpPaintCore, gimp_paint_core, GIMP_TYPE_OBJECT)
Elliot Lee's avatar
Elliot Lee committed
116

Michael Natterer's avatar
Michael Natterer committed
117
#define parent_class gimp_paint_core_parent_class
118

Michael Natterer's avatar
Michael Natterer committed
119
static gint global_core_ID = 1;
120 121


122
static void
123
gimp_paint_core_class_init (GimpPaintCoreClass *klass)
124
{
125
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
126

127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
  object_class->finalize     = gimp_paint_core_finalize;
  object_class->set_property = gimp_paint_core_set_property;
  object_class->get_property = gimp_paint_core_get_property;

  klass->start               = gimp_paint_core_real_start;
  klass->pre_paint           = gimp_paint_core_real_pre_paint;
  klass->paint               = gimp_paint_core_real_paint;
  klass->post_paint          = gimp_paint_core_real_post_paint;
  klass->interpolate         = gimp_paint_core_real_interpolate;
  klass->get_paint_area      = gimp_paint_core_real_get_paint_area;
  klass->push_undo           = gimp_paint_core_real_push_undo;

  g_object_class_install_property (object_class, PROP_UNDO_DESC,
                                   g_param_spec_string ("undo-desc", NULL, NULL,
                                                        _("Paint"),
                                                        GIMP_PARAM_READWRITE |
                                                        G_PARAM_CONSTRUCT_ONLY));
144
}
Elliot Lee's avatar
Elliot Lee committed
145

146
static void
147
gimp_paint_core_init (GimpPaintCore *core)
148
{
149
  core->ID               = global_core_ID++;
150

151 152
  core->undo_desc        = NULL;

153 154 155 156 157 158
  core->distance         = 0.0;
  core->pixel_dist       = 0.0;
  core->x1               = 0;
  core->y1               = 0;
  core->x2               = 0;
  core->y2               = 0;
159

160
  core->use_saved_proj   = FALSE;
161

162 163 164
  core->undo_tiles       = NULL;
  core->saved_proj_tiles = NULL;
  core->canvas_tiles     = NULL;
165

166 167 168
  core->orig_buf         = NULL;
  core->orig_proj_buf    = NULL;
  core->canvas_buf       = NULL;
169 170 171
}

static void
172
gimp_paint_core_finalize (GObject *object)
173
{
174
  GimpPaintCore *core = GIMP_PAINT_CORE (object);
175

176
  gimp_paint_core_cleanup (core);
177

178 179 180
  g_free (core->undo_desc);
  core->undo_desc = NULL;

181
  G_OBJECT_CLASS (parent_class)->finalize (object);
182
}
Elliot Lee's avatar
Elliot Lee committed
183

184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
static void
gimp_paint_core_set_property (GObject      *object,
                              guint         property_id,
                              const GValue *value,
                              GParamSpec   *pspec)
{
  GimpPaintCore *core = GIMP_PAINT_CORE (object);

  switch (property_id)
    {
    case PROP_UNDO_DESC:
      g_free (core->undo_desc);
      core->undo_desc = g_value_dup_string (value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static void
gimp_paint_core_get_property (GObject    *object,
                              guint       property_id,
                              GValue     *value,
                              GParamSpec *pspec)
{
  GimpPaintCore *core = GIMP_PAINT_CORE (object);

  switch (property_id)
    {
    case PROP_UNDO_DESC:
      g_value_set_string (value, core->undo_desc);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

225 226 227 228
static gboolean
gimp_paint_core_real_start (GimpPaintCore    *core,
                            GimpDrawable     *drawable,
                            GimpPaintOptions *paint_options,
229
                            const GimpCoords *coords,
230
                            GError          **error)
231 232 233 234 235
{
  return TRUE;
}

static gboolean
236 237 238 239 240
gimp_paint_core_real_pre_paint (GimpPaintCore    *core,
                                GimpDrawable     *drawable,
                                GimpPaintOptions *paint_options,
                                GimpPaintState    paint_state,
                                guint32           time)
241 242 243 244 245
{
  return TRUE;
}

static void
246 247 248
gimp_paint_core_real_paint (GimpPaintCore    *core,
                            GimpDrawable     *drawable,
                            GimpPaintOptions *paint_options,
249
                            const GimpCoords *coords,
250 251
                            GimpPaintState    paint_state,
                            guint32           time)
252 253 254
{
}

255
static void
256 257 258 259 260
gimp_paint_core_real_post_paint (GimpPaintCore    *core,
                                 GimpDrawable     *drawable,
                                 GimpPaintOptions *paint_options,
                                 GimpPaintState    paint_state,
                                 guint32           time)
261 262 263
{
}

264 265 266
static void
gimp_paint_core_real_interpolate (GimpPaintCore    *core,
                                  GimpDrawable     *drawable,
267 268
                                  GimpPaintOptions *paint_options,
                                  guint32           time)
269
{
270
  gimp_paint_core_paint (core, drawable, paint_options,
271
                         GIMP_PAINT_STATE_MOTION, time);
272 273 274 275 276 277 278

  core->last_coords = core->cur_coords;
}

static TempBuf *
gimp_paint_core_real_get_paint_area (GimpPaintCore    *core,
                                     GimpDrawable     *drawable,
279 280
                                     GimpPaintOptions *paint_options,
                                     const GimpCoords *coords)
281 282 283 284
{
  return NULL;
}

285 286 287 288 289 290 291 292 293 294 295 296
static GimpUndo *
gimp_paint_core_real_push_undo (GimpPaintCore *core,
                                GimpImage     *image,
                                const gchar   *undo_desc)
{
  return gimp_image_undo_push (image, GIMP_TYPE_PAINT_CORE_UNDO,
                               GIMP_UNDO_PAINT, undo_desc,
                               0,
                               "paint-core", core,
                               NULL);
}

297 298 299

/*  public functions  */

Elliot Lee's avatar
Elliot Lee committed
300
void
301 302 303 304 305
gimp_paint_core_paint (GimpPaintCore    *core,
                       GimpDrawable     *drawable,
                       GimpPaintOptions *paint_options,
                       GimpPaintState    paint_state,
                       guint32           time)
Elliot Lee's avatar
Elliot Lee committed
306
{
307 308
  GimpPaintCoreClass *core_class;

309 310
  g_return_if_fail (GIMP_IS_PAINT_CORE (core));
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
311
  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
312
  g_return_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options));
313

314 315 316 317 318
  core_class = GIMP_PAINT_CORE_GET_CLASS (core);

  if (core_class->pre_paint (core, drawable,
                             paint_options,
                             paint_state, time))
319
    {
320
      if (paint_state == GIMP_PAINT_STATE_MOTION)
321 322 323 324 325
        {
          /* Save coordinates for gimp_paint_core_interpolate() */
          core->last_paint.x = core->cur_coords.x;
          core->last_paint.y = core->cur_coords.y;
        }
326

327 328
      core_class->paint (core, drawable,
                         paint_options,
329
                         &core->cur_coords,
330 331 332 333 334
                         paint_state, time);

      core_class->post_paint (core, drawable,
                              paint_options,
                              paint_state, time);
335
    }
Elliot Lee's avatar
Elliot Lee committed
336 337
}

338
gboolean
339 340 341
gimp_paint_core_start (GimpPaintCore     *core,
                       GimpDrawable      *drawable,
                       GimpPaintOptions  *paint_options,
342
                       const GimpCoords  *coords,
343
                       GError           **error)
Elliot Lee's avatar
Elliot Lee committed
344
{
345
  GimpItem *item;
Michael Natterer's avatar
Michael Natterer committed
346

347 348
  g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), FALSE);
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
349
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE);
350
  g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), FALSE);
351
  g_return_val_if_fail (coords != NULL, FALSE);
352
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Elliot Lee's avatar
Elliot Lee committed
353

354
  item = GIMP_ITEM (drawable);
355

356 357 358 359 360
  if (core->stroke_buffer)
    {
      g_array_free (core->stroke_buffer, TRUE);
      core->stroke_buffer = NULL;
    }
361 362

  core->stroke_buffer = g_array_sized_new (TRUE, TRUE,
363
                                           sizeof (GimpCoords),
364
                                           STROKE_BUFFER_INIT_SIZE);
365

366
  core->cur_coords = *coords;
367

368 369
  if (! GIMP_PAINT_CORE_GET_CLASS (core)->start (core, drawable,
                                                 paint_options,
370
                                                 coords, error))
371
    {
372
      return FALSE;
373
    }
374

375
  /*  Allocate the undo structure  */
376
  if (core->undo_tiles)
377
    tile_manager_unref (core->undo_tiles);
Elliot Lee's avatar
Elliot Lee committed
378

379 380
  core->undo_tiles = tile_manager_new (gimp_item_get_width  (item),
                                       gimp_item_get_height (item),
381
                                       gimp_drawable_bytes (drawable));
Elliot Lee's avatar
Elliot Lee committed
382

383 384 385 386
  /*  Allocate the saved proj structure  */
  if (core->saved_proj_tiles)
    tile_manager_unref (core->saved_proj_tiles);

387 388
  core->saved_proj_tiles = NULL;

389 390
  if (core->use_saved_proj)
    {
391 392 393
      GimpImage    *image    = gimp_item_get_image (item);
      GimpPickable *pickable = GIMP_PICKABLE (gimp_image_get_projection (image));
      TileManager  *tiles    = gimp_pickable_get_tiles (pickable);
394 395 396 397 398 399

      core->saved_proj_tiles = tile_manager_new (tile_manager_width (tiles),
                                                 tile_manager_height (tiles),
                                                 tile_manager_bpp (tiles));
    }

Elliot Lee's avatar
Elliot Lee committed
400
  /*  Allocate the canvas blocks structure  */
401
  if (core->canvas_tiles)
402
    tile_manager_unref (core->canvas_tiles);
403

404 405
  core->canvas_tiles = tile_manager_new (gimp_item_get_width  (item),
                                         gimp_item_get_height (item),
406
                                         1);
Elliot Lee's avatar
Elliot Lee committed
407 408 409

  /*  Get the initial undo extents  */

Michael Natterer's avatar
Michael Natterer committed
410 411
  core->x1 = core->x2 = core->cur_coords.x;
  core->y1 = core->y2 = core->cur_coords.y;
412 413 414

  core->last_paint.x = -1e6;
  core->last_paint.y = -1e6;
415

416 417 418
  /*  Freeze the drawable preview so that it isn't constantly updated.  */
  gimp_viewable_preview_freeze (GIMP_VIEWABLE (drawable));

Elliot Lee's avatar
Elliot Lee committed
419 420 421
  return TRUE;
}

422 423
void
gimp_paint_core_finish (GimpPaintCore *core,
424 425
                        GimpDrawable  *drawable,
                        gboolean       push_undo)
426
{
427
  GimpImage *image;
428 429 430

  g_return_if_fail (GIMP_IS_PAINT_CORE (core));
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
431
  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
432

433 434 435 436 437
  if (core->stroke_buffer)
    {
      g_array_free (core->stroke_buffer, TRUE);
      core->stroke_buffer = NULL;
    }
438

439
  image = gimp_item_get_image (GIMP_ITEM (drawable));
440

441 442 443
  /*  Determine if any part of the image has been altered--
   *  if nothing has, then just return...
   */
444
  if ((core->x2 == core->x1) || (core->y2 == core->y1))
445 446 447 448
    {
      gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable));
      return;
    }
449

450 451 452 453 454 455
  if (push_undo)
    {
      gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_PAINT,
                                   core->undo_desc);

      GIMP_PAINT_CORE_GET_CLASS (core)->push_undo (core, image, NULL);
456

457 458
      gimp_drawable_push_undo (drawable, NULL,
                               core->x1, core->y1,
459
                               core->x2 - core->x1, core->y2 - core->y1,
460 461
                               core->undo_tiles,
                               TRUE);
462

463 464
      gimp_image_undo_group_end (image);
    }
465 466

  tile_manager_unref (core->undo_tiles);
467 468
  core->undo_tiles = NULL;

469 470 471 472 473 474
  if (core->saved_proj_tiles)
    {
      tile_manager_unref (core->saved_proj_tiles);
      core->saved_proj_tiles = NULL;
    }

475
  gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable));
476 477
}

478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
static void
gimp_paint_core_copy_valid_tiles (TileManager *src_tiles,
                                  TileManager *dest_tiles,
                                  gint         x,
                                  gint         y,
                                  gint         w,
                                  gint         h)
{
  Tile *src_tile;
  gint  i, j;

  for (i = y; i < (y + h); i += (TILE_HEIGHT - (i % TILE_HEIGHT)))
    {
      for (j = x; j < (x + w); j += (TILE_WIDTH - (j % TILE_WIDTH)))
        {
          src_tile = tile_manager_get_tile (src_tiles,
                                            j, i, FALSE, FALSE);

496
          if (tile_is_valid (src_tile))
497 498 499 500 501 502 503 504 505 506 507 508 509 510
            {
              src_tile = tile_manager_get_tile (src_tiles,
                                                j, i, TRUE, FALSE);

              tile_manager_map_tile (dest_tiles, j, i, src_tile);

              tile_release (src_tile, FALSE);
            }
        }
    }
}

void
gimp_paint_core_cancel (GimpPaintCore *core,
511
                        GimpDrawable  *drawable)
512
{
513 514 515
  gint x, y;
  gint width, height;

516 517
  g_return_if_fail (GIMP_IS_PAINT_CORE (core));
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
518
  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
519 520 521 522 523 524 525

  /*  Determine if any part of the image has been altered--
   *  if nothing has, then just return...
   */
  if ((core->x2 == core->x1) || (core->y2 == core->y1))
    return;

526 527 528 529 530 531 532 533 534 535 536 537
  if (gimp_rectangle_intersect (core->x1, core->y1,
                                core->x2 - core->x1,
                                core->y2 - core->y1,
                                0, 0,
                                gimp_item_get_width  (GIMP_ITEM (drawable)),
                                gimp_item_get_height (GIMP_ITEM (drawable)),
                                &x, &y, &width, &height))
    {
      gimp_paint_core_copy_valid_tiles (core->undo_tiles,
                                        gimp_drawable_get_tiles (drawable),
                                        x, y, width, height);
    }
538 539 540 541

  tile_manager_unref (core->undo_tiles);
  core->undo_tiles = NULL;

542 543 544 545 546 547
  if (core->saved_proj_tiles)
    {
      tile_manager_unref (core->saved_proj_tiles);
      core->saved_proj_tiles = NULL;
    }

548
  gimp_drawable_update (drawable, x, y, width, height);
549 550

  gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable));
551 552
}

553 554 555 556 557 558 559
void
gimp_paint_core_cleanup (GimpPaintCore *core)
{
  g_return_if_fail (GIMP_IS_PAINT_CORE (core));

  if (core->undo_tiles)
    {
560
      tile_manager_unref (core->undo_tiles);
561 562 563
      core->undo_tiles = NULL;
    }

564 565 566 567 568 569
  if (core->saved_proj_tiles)
    {
      tile_manager_unref (core->saved_proj_tiles);
      core->saved_proj_tiles = NULL;
    }

570 571
  if (core->canvas_tiles)
    {
572
      tile_manager_unref (core->canvas_tiles);
573 574 575 576 577 578 579 580 581
      core->canvas_tiles = NULL;
    }

  if (core->orig_buf)
    {
      temp_buf_free (core->orig_buf);
      core->orig_buf = NULL;
    }

582 583 584 585 586 587
  if (core->orig_proj_buf)
    {
      temp_buf_free (core->orig_proj_buf);
      core->orig_proj_buf = NULL;
    }

588 589 590 591 592 593 594
  if (core->canvas_buf)
    {
      temp_buf_free (core->canvas_buf);
      core->canvas_buf = NULL;
    }
}

Elliot Lee's avatar
Elliot Lee committed
595
void
596
gimp_paint_core_interpolate (GimpPaintCore    *core,
597
                             GimpDrawable     *drawable,
598
                             GimpPaintOptions *paint_options,
599
                             const GimpCoords *coords,
600
                             guint32           time)
Elliot Lee's avatar
Elliot Lee committed
601
{
602 603
  g_return_if_fail (GIMP_IS_PAINT_CORE (core));
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
604
  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
605
  g_return_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options));
606 607 608
  g_return_if_fail (coords != NULL);

  core->cur_coords = *coords;
609

610
  GIMP_PAINT_CORE_GET_CLASS (core)->interpolate (core, drawable,
611
                                                 paint_options, time);
Elliot Lee's avatar
Elliot Lee committed
612 613
}

614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
void
gimp_paint_core_set_current_coords (GimpPaintCore    *core,
                                    const GimpCoords *coords)
{
  g_return_if_fail (GIMP_IS_PAINT_CORE (core));
  g_return_if_fail (coords != NULL);

  core->cur_coords = *coords;
}

void
gimp_paint_core_get_current_coords (GimpPaintCore *core,
                                    GimpCoords    *coords)
{
  g_return_if_fail (GIMP_IS_PAINT_CORE (core));
  g_return_if_fail (coords != NULL);

  *coords = core->cur_coords;
}

void
gimp_paint_core_set_last_coords (GimpPaintCore    *core,
                                 const GimpCoords *coords)
{
  g_return_if_fail (GIMP_IS_PAINT_CORE (core));
  g_return_if_fail (coords != NULL);

  core->last_coords = *coords;
}

void
gimp_paint_core_get_last_coords (GimpPaintCore *core,
                                 GimpCoords    *coords)
{
  g_return_if_fail (GIMP_IS_PAINT_CORE (core));
  g_return_if_fail (coords != NULL);

  *coords = core->last_coords;
}

654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
/**
 * gimp_paint_core_round_line:
 * @core:                 the #GimpPaintCore
 * @options:              the #GimpPaintOptions to use
 * @constrain_15_degrees: the modifier state
 *
 * Adjusts core->last_coords and core_cur_coords in preparation to
 * drawing a straight line. If @center_pixels is TRUE the endpoints
 * get pushed to the center of the pixels. This avoids artefacts
 * for e.g. the hard mode. The rounding of the slope to 15 degree
 * steps if ctrl is pressed happens, as does rounding the start and
 * end coordinates (which may be fractional in high zoom modes) to
 * the center of pixels.
 **/
void
gimp_paint_core_round_line (GimpPaintCore    *core,
                            GimpPaintOptions *paint_options,
                            gboolean          constrain_15_degrees)
{
  g_return_if_fail (GIMP_IS_PAINT_CORE (core));
  g_return_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options));

  if (gimp_paint_options_get_brush_mode (paint_options) == GIMP_BRUSH_HARD)
    {
      core->last_coords.x = floor (core->last_coords.x) + 0.5;
      core->last_coords.y = floor (core->last_coords.y) + 0.5;
      core->cur_coords.x  = floor (core->cur_coords.x ) + 0.5;
      core->cur_coords.y  = floor (core->cur_coords.y ) + 0.5;
    }

  if (constrain_15_degrees)
    gimp_constrain_line (core->last_coords.x, core->last_coords.y,
                         &core->cur_coords.x, &core->cur_coords.y,
                         GIMP_CONSTRAIN_LINE_15_DEGREES);
}

690

691
/*  protected functions  */
Elliot Lee's avatar
Elliot Lee committed
692 693

TempBuf *
694 695
gimp_paint_core_get_paint_area (GimpPaintCore    *core,
                                GimpDrawable     *drawable,
696 697
                                GimpPaintOptions *paint_options,
                                const GimpCoords *coords)
Elliot Lee's avatar
Elliot Lee committed
698
{
699 700 701
  g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), NULL);
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
702
  g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), NULL);
703
  g_return_val_if_fail (coords != NULL, NULL);
704

705
  return GIMP_PAINT_CORE_GET_CLASS (core)->get_paint_area (core, drawable,
706 707
                                                           paint_options,
                                                           coords);
Elliot Lee's avatar
Elliot Lee committed
708 709 710
}

TempBuf *
711
gimp_paint_core_get_orig_image (GimpPaintCore *core,
712
                                GimpDrawable  *drawable,
713 714 715 716
                                gint           x,
                                gint           y,
                                gint           width,
                                gint           height)
Elliot Lee's avatar
Elliot Lee committed
717
{
Sven Neumann's avatar
Sven Neumann committed
718 719 720 721 722 723 724 725 726 727 728
  PixelRegion   srcPR;
  PixelRegion   destPR;
  Tile         *undo_tile;
  gboolean      release_tile;
  gint          h;
  gint          pixelwidth;
  gint          drawable_width;
  gint          drawable_height;
  const guchar *s;
  guchar       *d;
  gpointer      pr;
Elliot Lee's avatar
Elliot Lee committed
729

730 731 732 733
  g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), NULL);
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
  g_return_val_if_fail (core->undo_tiles != NULL, NULL);

734 735
  core->orig_buf = temp_buf_resize (core->orig_buf,
                                    gimp_drawable_bytes (drawable),
736
                                    x, y, width, height);
737

738 739
  drawable_width  = gimp_item_get_width  (GIMP_ITEM (drawable));
  drawable_height = gimp_item_get_height (GIMP_ITEM (drawable));
740

741 742 743 744 745 746
  gimp_rectangle_intersect (x, y,
                            width, height,
                            0, 0,
                            drawable_width, drawable_height,
                            &x, &y,
                            &width, &height);
Elliot Lee's avatar
Elliot Lee committed
747 748

  /*  configure the pixel regions  */
749
  pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable),
750
                     x, y, width, height,
751 752
                     FALSE);

Michael Natterer's avatar
Michael Natterer committed
753
  pixel_region_init_temp_buf (&destPR, core->orig_buf,
754 755 756
                              x - core->orig_buf->x,
                              y - core->orig_buf->y,
                              width, height);
Elliot Lee's avatar
Elliot Lee committed
757

758 759 760
  for (pr = pixel_regions_register (2, &srcPR, &destPR);
       pr != NULL;
       pr = pixel_regions_process (pr))
Elliot Lee's avatar
Elliot Lee committed
761 762
    {
      /*  If the undo tile corresponding to this location is valid, use it  */
763
      undo_tile = tile_manager_get_tile (core->undo_tiles,
764
                                         srcPR.x, srcPR.y,
765
                                         FALSE, FALSE);
766 767

      if (tile_is_valid (undo_tile))
768 769 770 771
        {
          release_tile = TRUE;

          undo_tile = tile_manager_get_tile (core->undo_tiles,
772
                                             srcPR.x, srcPR.y,
773
                                             TRUE, FALSE);
774
          s = tile_data_pointer (undo_tile, srcPR.x, srcPR.y);
775
        }
Elliot Lee's avatar
Elliot Lee committed
776
      else
777 778 779 780 781
        {
          release_tile = FALSE;

          s = srcPR.data;
        }
Elliot Lee's avatar
Elliot Lee committed
782 783

      d = destPR.data;
784

Elliot Lee's avatar
Elliot Lee committed
785
      pixelwidth = srcPR.w * srcPR.bytes;
786

Elliot Lee's avatar
Elliot Lee committed
787 788
      h = srcPR.h;
      while (h --)
789 790
        {
          memcpy (d, s, pixelwidth);
791

792 793 794 795 796 797
          s += srcPR.rowstride;
          d += destPR.rowstride;
        }

      if (release_tile)
        tile_release (undo_tile, FALSE);
Elliot Lee's avatar
Elliot Lee committed
798 799
    }

800
  return core->orig_buf;
Elliot Lee's avatar
Elliot Lee committed
801 802
}

803 804 805
TempBuf *
gimp_paint_core_get_orig_proj (GimpPaintCore *core,
                               GimpPickable  *pickable,
806 807 808 809
                               gint           x,
                               gint           y,
                               gint           width,
                               gint           height)
810
{
Sven Neumann's avatar
Sven Neumann committed
811 812 813 814 815 816 817 818 819 820 821 822
  TileManager  *src_tiles;
  PixelRegion   srcPR;
  PixelRegion   destPR;
  Tile         *saved_tile;
  gboolean      release_tile;
  gint          h;
  gint          pixelwidth;
  gint          pickable_width;
  gint          pickable_height;
  const guchar *s;
  guchar       *d;
  gpointer      pr;
823

824 825 826
  g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), NULL);
  g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL);
  g_return_val_if_fail (core->saved_proj_tiles != NULL, NULL);
827 828

  core->orig_proj_buf = temp_buf_resize (core->orig_proj_buf,
829
                                         gimp_pickable_get_bytes (pickable),
830
                                         x, y, width, height);
831

832 833
  src_tiles = gimp_pickable_get_tiles (pickable);

834 835 836
  pickable_width  = tile_manager_width  (src_tiles);
  pickable_height = tile_manager_height (src_tiles);

837 838 839 840 841 842
  gimp_rectangle_intersect (x, y,
                            width, height,
                            0, 0,
                            pickable_width, pickable_height,
                            &x, &y,
                            &width, &height);
843 844 845

  /*  configure the pixel regions  */
  pixel_region_init (&srcPR, src_tiles,
846
                     x, y, width, height,
847 848
                     FALSE);

Michael Natterer's avatar
Michael Natterer committed
849
  pixel_region_init_temp_buf (&destPR, core->orig_proj_buf,
850 851 852
                              x - core->orig_proj_buf->x,
                              y - core->orig_proj_buf->y,
                              width, height);
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869

  for (pr = pixel_regions_register (2, &srcPR, &destPR);
       pr != NULL;
       pr = pixel_regions_process (pr))
    {
      /*  If the saved tile corresponding to this location is valid, use it  */
      saved_tile = tile_manager_get_tile (core->saved_proj_tiles,
                                          srcPR.x, srcPR.y,
                                          FALSE, FALSE);

      if (tile_is_valid (saved_tile))
        {
          release_tile = TRUE;

          saved_tile = tile_manager_get_tile (core->saved_proj_tiles,
                                              srcPR.x, srcPR.y,
                                              TRUE, FALSE);
870
          s = tile_data_pointer (saved_tile, srcPR.x, srcPR.y);
871 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 897 898
        }
      else
        {
          release_tile = FALSE;

          s = srcPR.data;
        }

      d = destPR.data;

      pixelwidth = srcPR.w * srcPR.bytes;

      h = srcPR.h;
      while (h --)
        {
          memcpy (d, s, pixelwidth);

          s += srcPR.rowstride;
          d += destPR.rowstride;
        }

      if (release_tile)
        tile_release (saved_tile, FALSE);
    }

  return core->orig_proj_buf;
}

Elliot Lee's avatar
Elliot Lee committed
899
void
900
gimp_paint_core_paste (GimpPaintCore            *core,
901 902 903 904 905 906
                       PixelRegion              *paint_maskPR,
                       GimpDrawable             *drawable,
                       gdouble                   paint_opacity,
                       gdouble                   image_opacity,
                       GimpLayerModeEffects      paint_mode,
                       GimpPaintApplicationMode  mode)
Elliot Lee's avatar
Elliot Lee committed
907 908
{
  TileManager *alt = NULL;
909
  PixelRegion  srcPR;
910

Elliot Lee's avatar
Elliot Lee committed
911
  /*  set undo blocks  */
912 913 914 915 916
  gimp_paint_core_validate_undo_tiles (core, drawable,
                                       core->canvas_buf->x,
                                       core->canvas_buf->y,
                                       core->canvas_buf->width,
                                       core->canvas_buf->height);
Elliot Lee's avatar
Elliot Lee committed
917

918 919
  if (core->use_saved_proj)
    {
920 921 922 923
      GimpImage      *image      = gimp_item_get_image (GIMP_ITEM (drawable));
      GimpProjection *projection = gimp_image_get_projection (image);
      gint            off_x;
      gint            off_y;
924 925
      gint            x, y;
      gint            w, h;
926

927
      gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
928

929 930 931 932 933 934 935 936 937 938 939 940 941
      if (gimp_rectangle_intersect (core->canvas_buf->x + off_x,
                                    core->canvas_buf->y + off_y,
                                    core->canvas_buf->width,
                                    core->canvas_buf->height,
                                    0, 0,
                                    tile_manager_width (core->saved_proj_tiles),
                                    tile_manager_height (core->saved_proj_tiles),
                                    &x, &y, &w, &h))
        {
          gimp_paint_core_validate_saved_proj_tiles (core,
                                                     GIMP_PICKABLE (projection),
                                                     x, y, w, h);
        }
942 943
    }

Elliot Lee's avatar
Elliot Lee committed
944
  /*  If the mode is CONSTANT:
945
   *   combine the canvas buf, the paint mask to the canvas tiles
Elliot Lee's avatar
Elliot Lee committed
946
   */
947
  if (mode == GIMP_PAINT_CONSTANT)
Elliot Lee's avatar
Elliot Lee committed
948
    {
949 950 951 952 953 954 955 956 957 958 959 960 961 962 963
      /* Some tools (ink) paint the mask to paint_core->canvas_tiles
       * directly. Don't need to copy it in this case.
       */
      if (paint_maskPR->tiles != core->canvas_tiles)
        {
          /*  initialize any invalid canvas tiles  */
          gimp_paint_core_validate_canvas_tiles (core,
                                                 core->canvas_buf->x,
                                                 core->canvas_buf->y,
                                                 core->canvas_buf->width,
                                                 core->canvas_buf->height);

          paint_mask_to_canvas_tiles (core, paint_maskPR, paint_opacity);
        }

964 965
      canvas_tiles_to_canvas_buf (core);
      alt = core->undo_tiles;
Elliot Lee's avatar
Elliot Lee committed
966 967
    }
  /*  Otherwise:
968
   *   combine the canvas buf and the paint mask to the canvas buf
Elliot Lee's avatar
Elliot Lee committed
969
   */
970 971
  else
    {
972
      paint_mask_to_canvas_buf (core, paint_maskPR, paint_opacity);
973
    }
Elliot Lee's avatar
Elliot Lee committed
974 975

  /*  intialize canvas buf source pixel regions  */
Michael Natterer's avatar
Michael Natterer committed
976 977 978 979
  pixel_region_init_temp_buf (&srcPR, core->canvas_buf,
                              0, 0,
                              core->canvas_buf->width,
                              core->canvas_buf->height);
Elliot Lee's avatar
Elliot Lee committed
980

981
  /*  apply the paint area to the image  */
982 983 984 985
  gimp_drawable_apply_region (drawable, &srcPR,
                              FALSE, NULL,
                              image_opacity, paint_mode,
                              alt,  /*  specify an alternative src1  */
986
                              NULL,
987 988
                              core->canvas_buf->x,
                              core->canvas_buf->y);
Elliot Lee's avatar
Elliot Lee committed
989 990

  /*  Update the undo extents  */
991 992 993 994
  core->x1 = MIN (core->x1, core->canvas_buf->x);
  core->y1 = MIN (core->y1, core->canvas_buf->y);
  core->x2 = MAX (core->x2, core->canvas_buf->x + core->canvas_buf->width);
  core->y2 = MAX (core->y2, core->canvas_buf->y + core->canvas_buf->height);
Elliot Lee's avatar
Elliot Lee committed
995

996 997 998 999 1000 1001
  /*  Update the drawable  */
  gimp_drawable_update (drawable,
                        core->canvas_buf->x,
                        core->canvas_buf->y,
                        core->canvas_buf->width,
                        core->canvas_buf->height);
1002 1003
}

1004 1005 1006 1007
/* This works similarly to gimp_paint_core_paste. However, instead of
 * combining the canvas to the paint core drawable using one of the
 * combination modes, it uses a "replace" mode (i.e. transparent
 * pixels in the canvas erase the paint core drawable).
1008

1009 1010 1011
 * When not drawing on alpha-enabled images, it just paints using
 * NORMAL mode.
 */
1012
void
1013
gimp_paint_core_replace (GimpPaintCore            *core,
1014 1015 1016 1017 1018
                         PixelRegion              *paint_maskPR,
                         GimpDrawable             *drawable,
                         gdouble                   paint_opacity,
                         gdouble                   image_opacity,
                         GimpPaintApplicationMode  mode)
1019
{
Sven Neumann's avatar
Sven Neumann committed
1020
  PixelRegion  srcPR;
1021

1022
  if (! gimp_drawable_has_alpha (drawable))
1023
    {