2006-12-09 13:33:38 -08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
1997-11-24 14:05:25 -08:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
2013-05-21 04:03:28 -07:00
|
|
|
* Copyright (C) 2013 Daniel Sabo
|
1997-11-24 14:05:25 -08:00
|
|
|
*
|
2009-01-17 14:28:01 -08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
1997-11-24 14:05:25 -08:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-17 14:28:01 -08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
1997-11-24 14:05:25 -08:00
|
|
|
* (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
|
2018-07-11 14:47:19 -07:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
1997-11-24 14:05:25 -08:00
|
|
|
*/
|
2000-12-16 13:37:03 -08:00
|
|
|
|
app/appenv.h New file. Includes <math.h>. Move G_PI, RINT(), ROUND() etc
1999-09-01 Tor Lillqvist <tml@iki.fi>
* app/appenv.h
* libgimp/gimpmath.h: New file. Includes <math.h>. Move G_PI,
RINT(), ROUND() etc from app/appenv.h here, so plug-ins can
use them, too. Remove some commented-out old stuff in appenv.h.
* libgimp/gimp.h: Include gimpmath.h.
* libgimp/gimp.c (gimp_main): Win32: Don't install signal
handlers, we can't do anything useful in the handler ourselves
anyway (it would be nice to print out a backtrace, but that seems
pretty hard to do, even if not impossible). Let Windows inform the
user about the crash. If the plug-in was compiled with MSVC, and
the user also has it, she is offered a chance to start the
debugger automatically anyway.
* app/*several*.c: Include gimpmath.h for G_PI etc. Don't include
<math.h>, as gimpmath.h includes it.
* plug-ins/*/*many*.c: Include config.h. Don't include <math.h>.
Remove all the duplicated definitions of G_PI and rint(). Use
RINT() instead of rint().
* app/app_procs.[ch]: app_exit() takes a gboolean.
* app/batch.c
* app/commands.c
* app/interface.c: Call app_exit() with FALSE or TRUE.
* app/main.c (on_error): Call gimp_fatal_error. (main): Don't
install any signal handler on Win32 here, either.
* app/errors.c (gimp_fatal_error, gimp_terminate): Win32: Format
the message and call MessageBox with it. g_on_error_query doesn't
do anything useful on Win32, and printf'ing a message to stdout or
stderr doesn't do anything, either, in a windowing application.
1999-09-01 13:30:56 -07:00
|
|
|
#include "config.h"
|
|
|
|
|
|
1997-11-24 14:05:25 -08:00
|
|
|
#include <string.h>
|
app/appenv.h New file. Includes <math.h>. Move G_PI, RINT(), ROUND() etc
1999-09-01 Tor Lillqvist <tml@iki.fi>
* app/appenv.h
* libgimp/gimpmath.h: New file. Includes <math.h>. Move G_PI,
RINT(), ROUND() etc from app/appenv.h here, so plug-ins can
use them, too. Remove some commented-out old stuff in appenv.h.
* libgimp/gimp.h: Include gimpmath.h.
* libgimp/gimp.c (gimp_main): Win32: Don't install signal
handlers, we can't do anything useful in the handler ourselves
anyway (it would be nice to print out a backtrace, but that seems
pretty hard to do, even if not impossible). Let Windows inform the
user about the crash. If the plug-in was compiled with MSVC, and
the user also has it, she is offered a chance to start the
debugger automatically anyway.
* app/*several*.c: Include gimpmath.h for G_PI etc. Don't include
<math.h>, as gimpmath.h includes it.
* plug-ins/*/*many*.c: Include config.h. Don't include <math.h>.
Remove all the duplicated definitions of G_PI and rint(). Use
RINT() instead of rint().
* app/app_procs.[ch]: app_exit() takes a gboolean.
* app/batch.c
* app/commands.c
* app/interface.c: Call app_exit() with FALSE or TRUE.
* app/main.c (on_error): Call gimp_fatal_error. (main): Don't
install any signal handler on Win32 here, either.
* app/errors.c (gimp_fatal_error, gimp_terminate): Win32: Format
the message and call MessageBox with it. g_on_error_query doesn't
do anything useful on Win32, and printf'ing a message to stdout or
stderr doesn't do anything, either, in a windowing application.
1999-09-01 13:30:56 -07:00
|
|
|
|
2013-10-14 16:58:39 -07:00
|
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
2008-10-09 13:24:04 -07:00
|
|
|
#include <gegl.h>
|
2000-12-16 13:37:03 -08:00
|
|
|
|
2008-12-27 08:04:43 -08:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2009-04-22 12:22:08 -07:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
2008-12-27 08:04:43 -08:00
|
|
|
|
2002-02-14 11:31:16 -08:00
|
|
|
#include "paint-types.h"
|
2000-12-16 13:37:03 -08:00
|
|
|
|
2017-02-05 06:59:29 -08:00
|
|
|
#include "operations/layer-modes/gimp-layer-modes.h"
|
|
|
|
|
|
2013-05-21 09:52:40 -07:00
|
|
|
#include "gegl/gimp-gegl-loops.h"
|
2012-05-26 03:42:52 -07:00
|
|
|
#include "gegl/gimp-gegl-nodes.h"
|
2012-03-22 06:13:17 -07:00
|
|
|
#include "gegl/gimp-gegl-utils.h"
|
2013-05-21 09:52:40 -07:00
|
|
|
#include "gegl/gimpapplicator.h"
|
2012-03-22 06:13:17 -07:00
|
|
|
|
2003-02-14 06:14:29 -08:00
|
|
|
#include "core/gimp.h"
|
2009-04-22 12:22:08 -07:00
|
|
|
#include "core/gimp-utils.h"
|
2012-05-26 03:42:52 -07:00
|
|
|
#include "core/gimpchannel.h"
|
2001-05-08 19:32:03 -07:00
|
|
|
#include "core/gimpimage.h"
|
2016-01-27 10:13:17 -08:00
|
|
|
#include "core/gimpimage-guides.h"
|
|
|
|
|
#include "core/gimpimage-symmetry.h"
|
2003-02-13 03:23:50 -08:00
|
|
|
#include "core/gimpimage-undo.h"
|
2005-08-28 12:17:44 -07:00
|
|
|
#include "core/gimppickable.h"
|
2008-08-13 10:30:08 -07:00
|
|
|
#include "core/gimpprojection.h"
|
2016-01-27 10:13:17 -08:00
|
|
|
#include "core/gimpsymmetry.h"
|
2012-04-10 09:47:44 -07:00
|
|
|
#include "core/gimptempbuf.h"
|
2001-05-08 19:32:03 -07:00
|
|
|
|
2002-02-14 11:31:16 -08:00
|
|
|
#include "gimppaintcore.h"
|
2007-02-03 10:48:00 -08:00
|
|
|
#include "gimppaintcoreundo.h"
|
2013-05-21 04:03:28 -07:00
|
|
|
#include "gimppaintcore-loops.h"
|
2002-06-17 03:34:28 -07:00
|
|
|
#include "gimppaintoptions.h"
|
2001-03-07 17:07:03 -08:00
|
|
|
|
2004-06-05 09:21:41 -07:00
|
|
|
#include "gimpairbrush.h"
|
2000-03-04 16:06:11 -08:00
|
|
|
|
2004-06-05 09:21:41 -07:00
|
|
|
#include "gimp-intl.h"
|
2000-05-29 01:40:29 -07:00
|
|
|
|
2012-04-23 03:51:11 -07:00
|
|
|
|
|
|
|
|
#define STROKE_BUFFER_INIT_SIZE 2000
|
2004-07-19 07:37:40 -07:00
|
|
|
|
2006-09-03 06:16:58 -07:00
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
PROP_0,
|
|
|
|
|
PROP_UNDO_DESC
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2004-05-25 13:41:09 -07:00
|
|
|
/* local function prototypes */
|
2001-01-23 15:56:18 -08:00
|
|
|
|
2004-05-26 05:55:10 -07:00
|
|
|
static void gimp_paint_core_finalize (GObject *object);
|
2006-09-03 06:16:58 -07:00
|
|
|
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);
|
2004-05-26 05:55:10 -07:00
|
|
|
|
|
|
|
|
static gboolean gimp_paint_core_real_start (GimpPaintCore *core,
|
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
|
GimpPaintOptions *paint_options,
|
2009-04-17 13:29:25 -07:00
|
|
|
const GimpCoords *coords,
|
2006-09-26 13:55:40 -07:00
|
|
|
GError **error);
|
2004-05-26 05:55:10 -07:00
|
|
|
static gboolean gimp_paint_core_real_pre_paint (GimpPaintCore *core,
|
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
|
GimpPaintOptions *options,
|
2004-07-19 07:37:40 -07:00
|
|
|
GimpPaintState paint_state,
|
2004-05-26 09:13:53 -07:00
|
|
|
guint32 time);
|
2004-05-26 05:55:10 -07:00
|
|
|
static void gimp_paint_core_real_paint (GimpPaintCore *core,
|
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
|
GimpPaintOptions *options,
|
2016-01-27 10:13:17 -08:00
|
|
|
GimpSymmetry *sym,
|
2004-07-19 07:37:40 -07:00
|
|
|
GimpPaintState paint_state,
|
2004-05-26 09:13:53 -07:00
|
|
|
guint32 time);
|
2004-06-14 05:52:33 -07:00
|
|
|
static void gimp_paint_core_real_post_paint (GimpPaintCore *core,
|
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
|
GimpPaintOptions *options,
|
2004-07-19 07:37:40 -07:00
|
|
|
GimpPaintState paint_state,
|
2004-06-14 05:52:33 -07:00
|
|
|
guint32 time);
|
2004-05-26 05:55:10 -07:00
|
|
|
static void gimp_paint_core_real_interpolate (GimpPaintCore *core,
|
|
|
|
|
GimpDrawable *drawable,
|
2004-05-26 09:13:53 -07:00
|
|
|
GimpPaintOptions *options,
|
|
|
|
|
guint32 time);
|
2012-04-01 12:20:12 -07:00
|
|
|
static GeglBuffer *
|
|
|
|
|
gimp_paint_core_real_get_paint_buffer (GimpPaintCore *core,
|
2004-05-26 05:55:10 -07:00
|
|
|
GimpDrawable *drawable,
|
2009-05-17 13:45:06 -07:00
|
|
|
GimpPaintOptions *options,
|
2017-01-20 15:27:48 -08:00
|
|
|
GimpLayerMode paint_mode,
|
2012-04-01 12:20:12 -07:00
|
|
|
const GimpCoords *coords,
|
|
|
|
|
gint *paint_buffer_x,
|
2016-01-27 10:13:17 -08:00
|
|
|
gint *paint_buffer_y,
|
|
|
|
|
gint *paint_width,
|
|
|
|
|
gint *paint_height);
|
2007-02-03 10:48:00 -08:00
|
|
|
static GimpUndo* gimp_paint_core_real_push_undo (GimpPaintCore *core,
|
|
|
|
|
GimpImage *image,
|
|
|
|
|
const gchar *undo_desc);
|
1997-11-24 14:05:25 -08:00
|
|
|
|
|
|
|
|
|
2006-05-15 02:46:31 -07:00
|
|
|
G_DEFINE_TYPE (GimpPaintCore, gimp_paint_core, GIMP_TYPE_OBJECT)
|
1997-11-24 14:05:25 -08:00
|
|
|
|
2005-12-07 13:11:53 -08:00
|
|
|
#define parent_class gimp_paint_core_parent_class
|
2001-02-27 11:18:01 -08:00
|
|
|
|
2005-12-07 13:11:53 -08:00
|
|
|
static gint global_core_ID = 1;
|
2001-02-26 21:21:12 -08:00
|
|
|
|
|
|
|
|
|
2001-02-27 11:18:01 -08:00
|
|
|
static void
|
2002-02-14 11:31:16 -08:00
|
|
|
gimp_paint_core_class_init (GimpPaintCoreClass *klass)
|
2001-02-26 21:21:12 -08:00
|
|
|
{
|
2004-05-25 13:41:09 -07:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
2001-02-27 11:18:01 -08:00
|
|
|
|
2006-09-03 06:16:58 -07:00
|
|
|
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;
|
2012-04-01 12:20:12 -07:00
|
|
|
klass->get_paint_buffer = gimp_paint_core_real_get_paint_buffer;
|
2006-09-03 06:16:58 -07:00
|
|
|
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));
|
2001-02-26 21:21:12 -08:00
|
|
|
}
|
1997-11-24 14:05:25 -08:00
|
|
|
|
2001-02-27 11:18:01 -08:00
|
|
|
static void
|
2002-02-14 11:31:16 -08:00
|
|
|
gimp_paint_core_init (GimpPaintCore *core)
|
2001-02-27 11:18:01 -08:00
|
|
|
{
|
2012-03-30 07:24:09 -07:00
|
|
|
core->ID = global_core_ID++;
|
2002-02-13 06:50:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2002-02-14 11:31:16 -08:00
|
|
|
gimp_paint_core_finalize (GObject *object)
|
2002-02-13 06:50:37 -08:00
|
|
|
{
|
2004-05-25 13:41:09 -07:00
|
|
|
GimpPaintCore *core = GIMP_PAINT_CORE (object);
|
2002-02-13 06:50:37 -08:00
|
|
|
|
2002-02-14 11:31:16 -08:00
|
|
|
gimp_paint_core_cleanup (core);
|
2002-02-13 06:50:37 -08:00
|
|
|
|
2017-07-15 09:38:01 -07:00
|
|
|
g_clear_pointer (&core->undo_desc, g_free);
|
2006-09-03 06:16:58 -07:00
|
|
|
|
2012-02-07 05:06:12 -08:00
|
|
|
if (core->stroke_buffer)
|
|
|
|
|
{
|
|
|
|
|
g_array_free (core->stroke_buffer, TRUE);
|
|
|
|
|
core->stroke_buffer = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-13 06:50:37 -08:00
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
2001-02-27 11:18:01 -08:00
|
|
|
}
|
1997-11-24 14:05:25 -08:00
|
|
|
|
2006-09-03 06:16:58 -07:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-26 05:55:10 -07:00
|
|
|
static gboolean
|
|
|
|
|
gimp_paint_core_real_start (GimpPaintCore *core,
|
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
|
GimpPaintOptions *paint_options,
|
2009-04-17 13:29:25 -07:00
|
|
|
const GimpCoords *coords,
|
2006-09-26 13:55:40 -07:00
|
|
|
GError **error)
|
2004-05-26 05:55:10 -07:00
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2004-07-19 07:37:40 -07:00
|
|
|
gimp_paint_core_real_pre_paint (GimpPaintCore *core,
|
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
|
GimpPaintOptions *paint_options,
|
|
|
|
|
GimpPaintState paint_state,
|
|
|
|
|
guint32 time)
|
2004-05-26 05:55:10 -07:00
|
|
|
{
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2004-07-19 07:37:40 -07:00
|
|
|
gimp_paint_core_real_paint (GimpPaintCore *core,
|
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
|
GimpPaintOptions *paint_options,
|
2016-01-27 10:13:17 -08:00
|
|
|
GimpSymmetry *sym,
|
2004-07-19 07:37:40 -07:00
|
|
|
GimpPaintState paint_state,
|
|
|
|
|
guint32 time)
|
2004-05-26 05:55:10 -07:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-14 05:52:33 -07:00
|
|
|
static void
|
2004-07-19 07:37:40 -07:00
|
|
|
gimp_paint_core_real_post_paint (GimpPaintCore *core,
|
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
|
GimpPaintOptions *paint_options,
|
|
|
|
|
GimpPaintState paint_state,
|
|
|
|
|
guint32 time)
|
2004-06-14 05:52:33 -07:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2004-05-26 05:55:10 -07:00
|
|
|
static void
|
|
|
|
|
gimp_paint_core_real_interpolate (GimpPaintCore *core,
|
|
|
|
|
GimpDrawable *drawable,
|
2004-05-26 09:13:53 -07:00
|
|
|
GimpPaintOptions *paint_options,
|
|
|
|
|
guint32 time)
|
2004-05-26 05:55:10 -07:00
|
|
|
{
|
2004-05-26 09:13:53 -07:00
|
|
|
gimp_paint_core_paint (core, drawable, paint_options,
|
2004-07-19 07:37:40 -07:00
|
|
|
GIMP_PAINT_STATE_MOTION, time);
|
2004-05-26 05:55:10 -07:00
|
|
|
|
|
|
|
|
core->last_coords = core->cur_coords;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-01 12:20:12 -07:00
|
|
|
static GeglBuffer *
|
|
|
|
|
gimp_paint_core_real_get_paint_buffer (GimpPaintCore *core,
|
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
|
GimpPaintOptions *paint_options,
|
2017-01-20 15:27:48 -08:00
|
|
|
GimpLayerMode paint_mode,
|
2012-04-01 12:20:12 -07:00
|
|
|
const GimpCoords *coords,
|
|
|
|
|
gint *paint_buffer_x,
|
2016-01-27 10:13:17 -08:00
|
|
|
gint *paint_buffer_y,
|
|
|
|
|
gint *paint_width,
|
|
|
|
|
gint *paint_height)
|
2004-05-26 05:55:10 -07:00
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2007-02-03 10:48:00 -08:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-31 09:43:41 -07:00
|
|
|
|
|
|
|
|
/* public functions */
|
|
|
|
|
|
1997-11-24 14:05:25 -08:00
|
|
|
void
|
2004-07-19 07:37:40 -07:00
|
|
|
gimp_paint_core_paint (GimpPaintCore *core,
|
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
|
GimpPaintOptions *paint_options,
|
|
|
|
|
GimpPaintState paint_state,
|
|
|
|
|
guint32 time)
|
1997-11-24 14:05:25 -08:00
|
|
|
{
|
2004-06-14 05:52:33 -07:00
|
|
|
GimpPaintCoreClass *core_class;
|
|
|
|
|
|
2002-02-14 11:31:16 -08:00
|
|
|
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
|
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
2004-05-25 13:41:09 -07:00
|
|
|
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
|
2003-03-03 10:43:11 -08:00
|
|
|
g_return_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options));
|
2002-02-14 11:31:16 -08:00
|
|
|
|
2004-06-14 05:52:33 -07:00
|
|
|
core_class = GIMP_PAINT_CORE_GET_CLASS (core);
|
|
|
|
|
|
|
|
|
|
if (core_class->pre_paint (core, drawable,
|
|
|
|
|
paint_options,
|
|
|
|
|
paint_state, time))
|
2002-02-15 09:44:05 -08:00
|
|
|
{
|
2016-01-27 10:13:17 -08:00
|
|
|
GimpSymmetry *sym;
|
|
|
|
|
GimpImage *image;
|
|
|
|
|
GimpItem *item;
|
|
|
|
|
|
|
|
|
|
item = GIMP_ITEM (drawable);
|
|
|
|
|
image = gimp_item_get_image (item);
|
2011-04-20 12:00:35 -07:00
|
|
|
|
2011-09-11 12:31:59 -07:00
|
|
|
if (paint_state == GIMP_PAINT_STATE_MOTION)
|
|
|
|
|
{
|
|
|
|
|
/* Save coordinates for gimp_paint_core_interpolate() */
|
|
|
|
|
core->last_paint.x = core->cur_coords.x;
|
|
|
|
|
core->last_paint.y = core->cur_coords.y;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-03 12:25:17 -08:00
|
|
|
sym = g_object_ref (gimp_image_get_active_symmetry (image));
|
2016-01-27 10:13:17 -08:00
|
|
|
gimp_symmetry_set_origin (sym, drawable, &core->cur_coords);
|
|
|
|
|
|
2004-06-14 05:52:33 -07:00
|
|
|
core_class->paint (core, drawable,
|
|
|
|
|
paint_options,
|
2016-01-27 10:13:17 -08:00
|
|
|
sym, paint_state, time);
|
2016-02-03 12:25:17 -08:00
|
|
|
|
2018-05-08 07:11:25 -07:00
|
|
|
gimp_symmetry_clear_origin (sym);
|
2016-01-27 10:13:17 -08:00
|
|
|
g_object_unref (sym);
|
2004-06-14 05:52:33 -07:00
|
|
|
|
|
|
|
|
core_class->post_paint (core, drawable,
|
|
|
|
|
paint_options,
|
|
|
|
|
paint_state, time);
|
2004-05-25 13:41:09 -07:00
|
|
|
}
|
1997-11-24 14:05:25 -08:00
|
|
|
}
|
|
|
|
|
|
2000-03-04 16:06:11 -08:00
|
|
|
gboolean
|
2006-09-26 13:55:40 -07:00
|
|
|
gimp_paint_core_start (GimpPaintCore *core,
|
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
|
GimpPaintOptions *paint_options,
|
2009-04-17 13:29:25 -07:00
|
|
|
const GimpCoords *coords,
|
2006-09-26 13:55:40 -07:00
|
|
|
GError **error)
|
1997-11-24 14:05:25 -08:00
|
|
|
{
|
2013-04-14 13:44:21 -07:00
|
|
|
GimpImage *image;
|
|
|
|
|
GimpItem *item;
|
|
|
|
|
GimpChannel *mask;
|
2001-07-07 05:17:23 -07:00
|
|
|
|
2002-02-14 11:31:16 -08:00
|
|
|
g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), FALSE);
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
2004-05-25 13:41:09 -07:00
|
|
|
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE);
|
2003-03-03 10:43:11 -08:00
|
|
|
g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), FALSE);
|
2002-02-14 11:31:16 -08:00
|
|
|
g_return_val_if_fail (coords != NULL, FALSE);
|
2006-09-26 13:55:40 -07:00
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
1997-11-24 14:05:25 -08:00
|
|
|
|
2012-06-11 03:39:42 -07:00
|
|
|
item = GIMP_ITEM (drawable);
|
|
|
|
|
image = gimp_item_get_image (item);
|
2011-01-07 10:45:29 -08:00
|
|
|
|
2011-01-08 13:18:56 -08:00
|
|
|
if (core->stroke_buffer)
|
|
|
|
|
{
|
|
|
|
|
g_array_free (core->stroke_buffer, TRUE);
|
|
|
|
|
core->stroke_buffer = NULL;
|
|
|
|
|
}
|
2011-01-07 10:45:29 -08:00
|
|
|
|
|
|
|
|
core->stroke_buffer = g_array_sized_new (TRUE, TRUE,
|
2011-01-08 13:18:56 -08:00
|
|
|
sizeof (GimpCoords),
|
2011-01-07 10:45:29 -08:00
|
|
|
STROKE_BUFFER_INIT_SIZE);
|
2002-02-25 09:58:50 -08:00
|
|
|
|
2013-07-14 15:41:43 -07:00
|
|
|
/* remember the last stroke's endpoint for later undo */
|
|
|
|
|
core->start_coords = core->last_coords;
|
|
|
|
|
|
2002-02-14 11:31:16 -08:00
|
|
|
core->cur_coords = *coords;
|
1998-06-05 20:49:01 -07:00
|
|
|
|
2004-05-26 05:55:10 -07:00
|
|
|
if (! GIMP_PAINT_CORE_GET_CLASS (core)->start (core, drawable,
|
|
|
|
|
paint_options,
|
2006-09-26 13:55:40 -07:00
|
|
|
coords, error))
|
1999-10-26 11:27:27 -07:00
|
|
|
{
|
2004-05-25 13:41:09 -07:00
|
|
|
return FALSE;
|
2003-07-24 09:35:25 -07:00
|
|
|
}
|
2002-02-13 06:50:37 -08:00
|
|
|
|
2002-02-07 03:33:01 -08:00
|
|
|
/* Allocate the undo structure */
|
2012-03-22 08:29:33 -07:00
|
|
|
if (core->undo_buffer)
|
|
|
|
|
g_object_unref (core->undo_buffer);
|
1997-11-24 14:05:25 -08:00
|
|
|
|
2012-05-20 13:00:27 -07:00
|
|
|
core->undo_buffer = gegl_buffer_dup (gimp_drawable_get_buffer (drawable));
|
1997-11-24 14:05:25 -08:00
|
|
|
|
2005-08-28 12:17:44 -07:00
|
|
|
/* Allocate the saved proj structure */
|
2017-07-15 09:38:01 -07:00
|
|
|
g_clear_object (&core->saved_proj_buffer);
|
2007-03-31 09:43:41 -07:00
|
|
|
|
2005-08-28 12:17:44 -07:00
|
|
|
if (core->use_saved_proj)
|
|
|
|
|
{
|
2013-09-13 14:29:06 -07:00
|
|
|
GeglBuffer *buffer = gimp_pickable_get_buffer (GIMP_PICKABLE (image));
|
2005-08-28 12:17:44 -07:00
|
|
|
|
2012-05-20 13:00:27 -07:00
|
|
|
core->saved_proj_buffer = gegl_buffer_dup (buffer);
|
2005-08-28 12:17:44 -07:00
|
|
|
}
|
|
|
|
|
|
1997-11-24 14:05:25 -08:00
|
|
|
/* Allocate the canvas blocks structure */
|
2012-03-30 07:38:52 -07:00
|
|
|
if (core->canvas_buffer)
|
|
|
|
|
g_object_unref (core->canvas_buffer);
|
2002-02-07 03:33:01 -08:00
|
|
|
|
2012-03-30 07:38:52 -07:00
|
|
|
core->canvas_buffer =
|
2012-05-20 13:00:27 -07:00
|
|
|
gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
|
|
|
|
gimp_item_get_width (item),
|
|
|
|
|
gimp_item_get_height (item)),
|
2012-09-18 15:06:35 -07:00
|
|
|
babl_format ("Y float"));
|
1997-11-24 14:05:25 -08:00
|
|
|
|
|
|
|
|
/* Get the initial undo extents */
|
|
|
|
|
|
2009-05-03 03:19:07 -07:00
|
|
|
core->x1 = core->x2 = core->cur_coords.x;
|
|
|
|
|
core->y1 = core->y2 = core->cur_coords.y;
|
2002-06-12 12:18:34 -07:00
|
|
|
|
|
|
|
|
core->last_paint.x = -1e6;
|
|
|
|
|
core->last_paint.y = -1e6;
|
2003-07-10 05:13:21 -07:00
|
|
|
|
2013-04-14 13:44:21 -07:00
|
|
|
mask = gimp_image_get_mask (image);
|
|
|
|
|
|
|
|
|
|
/* don't apply the mask to itself and don't apply an empty mask */
|
2013-05-21 09:52:40 -07:00
|
|
|
if (GIMP_DRAWABLE (mask) != drawable && ! gimp_channel_is_empty (mask))
|
2013-04-14 13:44:21 -07:00
|
|
|
{
|
|
|
|
|
GeglBuffer *mask_buffer;
|
|
|
|
|
gint offset_x;
|
|
|
|
|
gint offset_y;
|
2012-05-26 03:42:52 -07:00
|
|
|
|
2013-04-14 13:44:21 -07:00
|
|
|
mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
|
|
|
|
|
gimp_item_get_offset (item, &offset_x, &offset_y);
|
2012-05-26 03:42:52 -07:00
|
|
|
|
2013-05-21 09:52:40 -07:00
|
|
|
core->mask_buffer = g_object_ref (mask_buffer);
|
2013-05-21 04:03:28 -07:00
|
|
|
core->mask_x_offset = -offset_x;
|
|
|
|
|
core->mask_y_offset = -offset_y;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
core->mask_buffer = NULL;
|
2013-04-14 13:44:21 -07:00
|
|
|
}
|
|
|
|
|
|
2013-05-21 09:52:40 -07:00
|
|
|
if (paint_options->use_applicator)
|
2013-05-21 04:03:28 -07:00
|
|
|
{
|
2018-12-29 11:12:51 -08:00
|
|
|
core->applicator = gimp_applicator_new (NULL);
|
2013-05-21 09:52:40 -07:00
|
|
|
|
|
|
|
|
if (core->mask_buffer)
|
2013-05-21 04:03:28 -07:00
|
|
|
{
|
2013-05-21 09:52:40 -07:00
|
|
|
gimp_applicator_set_mask_buffer (core->applicator,
|
|
|
|
|
core->mask_buffer);
|
|
|
|
|
gimp_applicator_set_mask_offset (core->applicator,
|
|
|
|
|
core->mask_x_offset,
|
|
|
|
|
core->mask_y_offset);
|
2013-05-21 04:03:28 -07:00
|
|
|
}
|
2013-05-21 09:52:40 -07:00
|
|
|
|
|
|
|
|
gimp_applicator_set_affect (core->applicator,
|
|
|
|
|
gimp_drawable_get_active_mask (drawable));
|
|
|
|
|
gimp_applicator_set_dest_buffer (core->applicator,
|
|
|
|
|
gimp_drawable_get_buffer (drawable));
|
|
|
|
|
}
|
2012-05-26 03:42:52 -07:00
|
|
|
|
2007-11-13 02:59:32 -08:00
|
|
|
/* Freeze the drawable preview so that it isn't constantly updated. */
|
|
|
|
|
gimp_viewable_preview_freeze (GIMP_VIEWABLE (drawable));
|
|
|
|
|
|
1997-11-24 14:05:25 -08:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-15 09:44:05 -08:00
|
|
|
void
|
|
|
|
|
gimp_paint_core_finish (GimpPaintCore *core,
|
2008-10-25 04:59:03 -07:00
|
|
|
GimpDrawable *drawable,
|
|
|
|
|
gboolean push_undo)
|
2002-02-15 09:44:05 -08:00
|
|
|
{
|
2006-09-03 06:16:58 -07:00
|
|
|
GimpImage *image;
|
2002-02-15 09:44:05 -08:00
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
|
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
2004-05-25 13:41:09 -07:00
|
|
|
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
|
2011-01-07 10:45:29 -08:00
|
|
|
|
2017-07-15 09:38:01 -07:00
|
|
|
g_clear_object (&core->applicator);
|
2013-05-21 09:52:40 -07:00
|
|
|
|
2011-01-08 13:18:56 -08:00
|
|
|
if (core->stroke_buffer)
|
|
|
|
|
{
|
|
|
|
|
g_array_free (core->stroke_buffer, TRUE);
|
|
|
|
|
core->stroke_buffer = NULL;
|
|
|
|
|
}
|
2002-02-15 09:44:05 -08:00
|
|
|
|
2017-07-15 09:38:01 -07:00
|
|
|
g_clear_object (&core->mask_buffer);
|
2013-05-21 04:03:28 -07:00
|
|
|
|
2006-03-28 09:08:36 -08:00
|
|
|
image = gimp_item_get_image (GIMP_ITEM (drawable));
|
2002-02-25 09:58:50 -08:00
|
|
|
|
2002-02-15 09:44:05 -08:00
|
|
|
/* Determine if any part of the image has been altered--
|
|
|
|
|
* if nothing has, then just return...
|
|
|
|
|
*/
|
2003-02-14 06:14:29 -08:00
|
|
|
if ((core->x2 == core->x1) || (core->y2 == core->y1))
|
2010-02-19 11:59:25 -08:00
|
|
|
{
|
|
|
|
|
gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2002-02-15 09:44:05 -08:00
|
|
|
|
2008-10-25 04:59:03 -07:00
|
|
|
if (push_undo)
|
|
|
|
|
{
|
2018-12-01 23:40:27 -08:00
|
|
|
GeglBuffer *buffer;
|
|
|
|
|
GeglRectangle rect;
|
2012-03-22 19:04:14 -07:00
|
|
|
|
|
|
|
|
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)),
|
2018-12-01 23:40:27 -08:00
|
|
|
&rect.x, &rect.y, &rect.width, &rect.height);
|
|
|
|
|
|
|
|
|
|
gimp_gegl_rectangle_align_to_tile_grid (&rect, &rect, core->undo_buffer);
|
2012-03-22 06:13:17 -07:00
|
|
|
|
2008-10-25 04:59:03 -07:00
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_PAINT,
|
|
|
|
|
core->undo_desc);
|
|
|
|
|
|
|
|
|
|
GIMP_PAINT_CORE_GET_CLASS (core)->push_undo (core, image, NULL);
|
2002-02-15 09:44:05 -08:00
|
|
|
|
2018-12-01 23:40:27 -08:00
|
|
|
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, rect.width, rect.height),
|
2012-05-20 13:00:27 -07:00
|
|
|
gimp_drawable_get_format (drawable));
|
2012-03-22 06:13:17 -07:00
|
|
|
|
2018-05-24 07:21:21 -07:00
|
|
|
gimp_gegl_buffer_copy (core->undo_buffer,
|
2018-12-01 23:40:27 -08:00
|
|
|
&rect,
|
2018-05-24 07:21:21 -07:00
|
|
|
GEGL_ABYSS_NONE,
|
|
|
|
|
buffer,
|
|
|
|
|
GEGL_RECTANGLE (0, 0, 0, 0));
|
2012-03-22 06:13:17 -07:00
|
|
|
|
2008-10-25 04:59:03 -07:00
|
|
|
gimp_drawable_push_undo (drawable, NULL,
|
2018-12-01 23:40:27 -08:00
|
|
|
buffer, rect.x, rect.y, rect.width, rect.height);
|
2012-03-22 06:13:17 -07:00
|
|
|
|
|
|
|
|
g_object_unref (buffer);
|
2002-02-15 09:44:05 -08:00
|
|
|
|
2008-10-25 04:59:03 -07:00
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
|
}
|
2003-05-26 10:02:06 -07:00
|
|
|
|
2017-07-15 09:38:01 -07:00
|
|
|
g_clear_object (&core->undo_buffer);
|
|
|
|
|
g_clear_object (&core->saved_proj_buffer);
|
2005-08-28 12:17:44 -07:00
|
|
|
|
2007-11-13 02:59:32 -08:00
|
|
|
gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable));
|
2002-02-15 09:44:05 -08:00
|
|
|
}
|
|
|
|
|
|
2003-09-17 05:05:11 -07:00
|
|
|
void
|
|
|
|
|
gimp_paint_core_cancel (GimpPaintCore *core,
|
2006-04-12 05:49:29 -07:00
|
|
|
GimpDrawable *drawable)
|
2003-09-17 05:05:11 -07:00
|
|
|
{
|
2009-06-16 13:09:48 -07:00
|
|
|
gint x, y;
|
|
|
|
|
gint width, height;
|
|
|
|
|
|
2003-09-17 05:05:11 -07:00
|
|
|
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
|
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
2004-05-25 13:41:09 -07:00
|
|
|
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
|
2003-09-17 05:05:11 -07:00
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
2009-06-16 13:09:48 -07:00
|
|
|
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))
|
|
|
|
|
{
|
2018-05-24 07:21:21 -07:00
|
|
|
gimp_gegl_buffer_copy (core->undo_buffer,
|
|
|
|
|
GEGL_RECTANGLE (x, y, width, height),
|
|
|
|
|
GEGL_ABYSS_NONE,
|
|
|
|
|
gimp_drawable_get_buffer (drawable),
|
|
|
|
|
GEGL_RECTANGLE (x, y, width, height));
|
2009-06-16 13:09:48 -07:00
|
|
|
}
|
2003-09-17 05:05:11 -07:00
|
|
|
|
2017-07-15 09:38:01 -07:00
|
|
|
g_clear_object (&core->undo_buffer);
|
|
|
|
|
g_clear_object (&core->saved_proj_buffer);
|
2005-08-28 12:17:44 -07:00
|
|
|
|
2009-06-16 13:09:48 -07:00
|
|
|
gimp_drawable_update (drawable, x, y, width, height);
|
2007-11-13 02:59:32 -08:00
|
|
|
|
|
|
|
|
gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable));
|
2003-09-17 05:05:11 -07:00
|
|
|
}
|
|
|
|
|
|
2002-02-15 09:44:05 -08:00
|
|
|
void
|
|
|
|
|
gimp_paint_core_cleanup (GimpPaintCore *core)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
|
|
|
|
|
|
2017-07-15 09:38:01 -07:00
|
|
|
g_clear_object (&core->undo_buffer);
|
|
|
|
|
g_clear_object (&core->saved_proj_buffer);
|
|
|
|
|
g_clear_object (&core->canvas_buffer);
|
|
|
|
|
g_clear_object (&core->paint_buffer);
|
2002-02-15 09:44:05 -08:00
|
|
|
}
|
|
|
|
|
|
1997-11-24 14:05:25 -08:00
|
|
|
void
|
2002-02-21 08:02:30 -08:00
|
|
|
gimp_paint_core_interpolate (GimpPaintCore *core,
|
2004-05-28 02:34:13 -07:00
|
|
|
GimpDrawable *drawable,
|
2004-05-26 09:13:53 -07:00
|
|
|
GimpPaintOptions *paint_options,
|
2009-05-25 11:49:34 -07:00
|
|
|
const GimpCoords *coords,
|
2004-05-26 09:13:53 -07:00
|
|
|
guint32 time)
|
1997-11-24 14:05:25 -08:00
|
|
|
{
|
2002-02-14 11:31:16 -08:00
|
|
|
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
|
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
2004-05-25 13:41:09 -07:00
|
|
|
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
|
2003-03-03 10:43:11 -08:00
|
|
|
g_return_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options));
|
2009-05-25 11:49:34 -07:00
|
|
|
g_return_if_fail (coords != NULL);
|
|
|
|
|
|
|
|
|
|
core->cur_coords = *coords;
|
2002-02-14 11:31:16 -08:00
|
|
|
|
2004-05-26 05:55:10 -07:00
|
|
|
GIMP_PAINT_CORE_GET_CLASS (core)->interpolate (core, drawable,
|
2004-05-26 09:13:53 -07:00
|
|
|
paint_options, time);
|
1997-11-24 14:05:25 -08:00
|
|
|
}
|
|
|
|
|
|
2009-05-03 03:08:21 -07:00
|
|
|
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
|
2011-03-16 13:06:39 -07:00
|
|
|
gimp_paint_core_get_current_coords (GimpPaintCore *core,
|
|
|
|
|
GimpCoords *coords)
|
2009-05-03 03:08:21 -07:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-22 12:22:08 -07:00
|
|
|
/**
|
|
|
|
|
* gimp_paint_core_round_line:
|
2018-07-15 14:58:55 -07:00
|
|
|
* @core: the #GimpPaintCore
|
|
|
|
|
* @options: the #GimpPaintOptions to use
|
|
|
|
|
* @constrain_15_degrees: the modifier state
|
|
|
|
|
* @constrain_offset_angle: the angle by which to offset the lines, in degrees
|
|
|
|
|
* @constrain_xres: the horizontal resolution
|
|
|
|
|
* @constrain_yres: the vertical resolution
|
2009-04-22 12:22:08 -07:00
|
|
|
*
|
|
|
|
|
* Adjusts core->last_coords and core_cur_coords in preparation to
|
|
|
|
|
* drawing a straight line. If @center_pixels is TRUE the endpoints
|
2018-03-24 13:49:01 -07:00
|
|
|
* get pushed to the center of the pixels. This avoids artifacts
|
2009-04-22 12:22:08 -07:00
|
|
|
* 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,
|
2017-12-22 02:56:11 -08:00
|
|
|
gboolean constrain_15_degrees,
|
2018-07-15 14:58:55 -07:00
|
|
|
gdouble constrain_offset_angle,
|
|
|
|
|
gdouble constrain_xres,
|
|
|
|
|
gdouble constrain_yres)
|
2009-04-22 12:22:08 -07:00
|
|
|
{
|
|
|
|
|
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,
|
2017-12-22 02:56:11 -08:00
|
|
|
GIMP_CONSTRAIN_LINE_15_DEGREES,
|
2018-07-15 14:58:55 -07:00
|
|
|
constrain_offset_angle,
|
|
|
|
|
constrain_xres, constrain_yres);
|
2009-04-22 12:22:08 -07:00
|
|
|
}
|
|
|
|
|
|
1998-06-05 20:49:01 -07:00
|
|
|
|
2002-02-15 09:44:05 -08:00
|
|
|
/* protected functions */
|
1997-11-24 14:05:25 -08:00
|
|
|
|
2012-03-31 09:28:18 -07:00
|
|
|
GeglBuffer *
|
|
|
|
|
gimp_paint_core_get_paint_buffer (GimpPaintCore *core,
|
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
|
GimpPaintOptions *paint_options,
|
2017-01-20 15:27:48 -08:00
|
|
|
GimpLayerMode paint_mode,
|
2012-03-31 09:28:18 -07:00
|
|
|
const GimpCoords *coords,
|
|
|
|
|
gint *paint_buffer_x,
|
2016-01-27 10:13:17 -08:00
|
|
|
gint *paint_buffer_y,
|
|
|
|
|
gint *paint_width,
|
|
|
|
|
gint *paint_height)
|
2012-03-31 09:28:18 -07:00
|
|
|
{
|
2012-04-01 12:20:12 -07:00
|
|
|
GeglBuffer *paint_buffer;
|
|
|
|
|
|
2012-03-31 09:28:18 -07:00
|
|
|
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);
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), NULL);
|
|
|
|
|
g_return_val_if_fail (coords != NULL, NULL);
|
|
|
|
|
g_return_val_if_fail (paint_buffer_x != NULL, NULL);
|
|
|
|
|
g_return_val_if_fail (paint_buffer_y != NULL, NULL);
|
|
|
|
|
|
2012-04-01 12:20:12 -07:00
|
|
|
paint_buffer =
|
|
|
|
|
GIMP_PAINT_CORE_GET_CLASS (core)->get_paint_buffer (core, drawable,
|
|
|
|
|
paint_options,
|
2017-01-20 15:27:48 -08:00
|
|
|
paint_mode,
|
2012-04-01 12:20:12 -07:00
|
|
|
coords,
|
|
|
|
|
paint_buffer_x,
|
2016-01-27 10:13:17 -08:00
|
|
|
paint_buffer_y,
|
|
|
|
|
paint_width,
|
|
|
|
|
paint_height);
|
2012-03-31 09:28:18 -07:00
|
|
|
|
2012-04-01 12:20:12 -07:00
|
|
|
core->paint_buffer_x = *paint_buffer_x;
|
|
|
|
|
core->paint_buffer_y = *paint_buffer_y;
|
2012-03-31 09:28:18 -07:00
|
|
|
|
2012-04-01 12:20:12 -07:00
|
|
|
return paint_buffer;
|
2012-03-31 09:28:18 -07:00
|
|
|
}
|
|
|
|
|
|
2012-03-30 16:36:10 -07:00
|
|
|
GeglBuffer *
|
2012-03-31 06:40:21 -07:00
|
|
|
gimp_paint_core_get_orig_image (GimpPaintCore *core)
|
1997-11-24 14:05:25 -08:00
|
|
|
{
|
2006-09-26 02:59:13 -07:00
|
|
|
g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), NULL);
|
2012-03-30 16:36:10 -07:00
|
|
|
g_return_val_if_fail (core->undo_buffer != NULL, NULL);
|
2006-09-26 02:59:13 -07:00
|
|
|
|
2012-03-31 06:40:21 -07:00
|
|
|
return core->undo_buffer;
|
1997-11-24 14:05:25 -08:00
|
|
|
}
|
|
|
|
|
|
2012-03-30 16:36:10 -07:00
|
|
|
GeglBuffer *
|
2012-03-31 06:40:21 -07:00
|
|
|
gimp_paint_core_get_orig_proj (GimpPaintCore *core)
|
2005-08-28 12:17:44 -07:00
|
|
|
{
|
2006-09-26 02:59:13 -07:00
|
|
|
g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), NULL);
|
2012-03-30 07:24:09 -07:00
|
|
|
g_return_val_if_fail (core->saved_proj_buffer != NULL, NULL);
|
2005-08-28 12:17:44 -07:00
|
|
|
|
2012-03-31 06:40:21 -07:00
|
|
|
return core->saved_proj_buffer;
|
2005-08-28 12:17:44 -07:00
|
|
|
}
|
|
|
|
|
|
1997-11-24 14:05:25 -08:00
|
|
|
void
|
2002-03-19 07:05:38 -08:00
|
|
|
gimp_paint_core_paste (GimpPaintCore *core,
|
2013-05-21 04:03:28 -07:00
|
|
|
const GimpTempBuf *paint_mask,
|
|
|
|
|
gint paint_mask_offset_x,
|
|
|
|
|
gint paint_mask_offset_y,
|
2006-04-12 05:49:29 -07:00
|
|
|
GimpDrawable *drawable,
|
|
|
|
|
gdouble paint_opacity,
|
|
|
|
|
gdouble image_opacity,
|
2017-01-08 14:00:19 -08:00
|
|
|
GimpLayerMode paint_mode,
|
2006-04-12 05:49:29 -07:00
|
|
|
GimpPaintApplicationMode mode)
|
1997-11-24 14:05:25 -08:00
|
|
|
{
|
2019-02-16 06:43:34 -08:00
|
|
|
gint width = gegl_buffer_get_width (core->paint_buffer);
|
|
|
|
|
gint height = gegl_buffer_get_height (core->paint_buffer);
|
|
|
|
|
GimpComponentMask affect = gimp_drawable_get_active_mask (drawable);
|
|
|
|
|
|
|
|
|
|
if (! affect)
|
|
|
|
|
return;
|
2013-05-21 04:03:28 -07:00
|
|
|
|
2013-05-21 09:52:40 -07:00
|
|
|
if (core->applicator)
|
|
|
|
|
{
|
|
|
|
|
/* If the mode is CONSTANT:
|
2019-02-12 03:43:01 -08:00
|
|
|
* combine the canvas buffer and the paint mask to the paint buffer
|
2013-05-21 09:52:40 -07:00
|
|
|
*/
|
|
|
|
|
if (mode == GIMP_PAINT_CONSTANT)
|
|
|
|
|
{
|
|
|
|
|
/* Some tools (ink) paint the mask to paint_core->canvas_buffer
|
|
|
|
|
* directly. Don't need to copy it in this case.
|
|
|
|
|
*/
|
|
|
|
|
if (paint_mask != NULL)
|
|
|
|
|
{
|
2019-02-12 03:43:01 -08:00
|
|
|
GeglBuffer *paint_mask_buffer =
|
|
|
|
|
gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask);
|
2013-05-21 09:52:40 -07:00
|
|
|
|
|
|
|
|
gimp_gegl_combine_mask_weird (paint_mask_buffer,
|
|
|
|
|
GEGL_RECTANGLE (paint_mask_offset_x,
|
|
|
|
|
paint_mask_offset_y,
|
|
|
|
|
width, height),
|
|
|
|
|
core->canvas_buffer,
|
|
|
|
|
GEGL_RECTANGLE (core->paint_buffer_x,
|
|
|
|
|
core->paint_buffer_y,
|
|
|
|
|
width, height),
|
|
|
|
|
paint_opacity,
|
|
|
|
|
GIMP_IS_AIRBRUSH (core));
|
|
|
|
|
|
|
|
|
|
g_object_unref (paint_mask_buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gimp_gegl_apply_mask (core->canvas_buffer,
|
|
|
|
|
GEGL_RECTANGLE (core->paint_buffer_x,
|
|
|
|
|
core->paint_buffer_y,
|
|
|
|
|
width, height),
|
|
|
|
|
core->paint_buffer,
|
|
|
|
|
GEGL_RECTANGLE (0, 0, width, height),
|
|
|
|
|
1.0);
|
|
|
|
|
|
|
|
|
|
gimp_applicator_set_src_buffer (core->applicator,
|
|
|
|
|
core->undo_buffer);
|
|
|
|
|
}
|
|
|
|
|
/* Otherwise:
|
2019-02-12 03:43:01 -08:00
|
|
|
* combine the paint mask to the paint buffer directly
|
2013-05-21 09:52:40 -07:00
|
|
|
*/
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
GeglBuffer *paint_mask_buffer =
|
|
|
|
|
gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask);
|
2013-05-21 04:03:28 -07:00
|
|
|
|
2013-05-21 09:52:40 -07:00
|
|
|
gimp_gegl_apply_mask (paint_mask_buffer,
|
|
|
|
|
GEGL_RECTANGLE (paint_mask_offset_x,
|
|
|
|
|
paint_mask_offset_y,
|
|
|
|
|
width, height),
|
|
|
|
|
core->paint_buffer,
|
|
|
|
|
GEGL_RECTANGLE (0, 0, width, height),
|
|
|
|
|
paint_opacity);
|
2013-05-21 04:03:28 -07:00
|
|
|
|
2013-05-21 09:52:40 -07:00
|
|
|
g_object_unref (paint_mask_buffer);
|
2007-06-26 15:41:06 -07:00
|
|
|
|
2013-05-21 09:52:40 -07:00
|
|
|
gimp_applicator_set_src_buffer (core->applicator,
|
|
|
|
|
gimp_drawable_get_buffer (drawable));
|
2004-05-26 04:37:23 -07:00
|
|
|
}
|
|
|
|
|
|
2013-05-21 09:52:40 -07:00
|
|
|
gimp_applicator_set_apply_buffer (core->applicator,
|
|
|
|
|
core->paint_buffer);
|
|
|
|
|
gimp_applicator_set_apply_offset (core->applicator,
|
2013-05-21 04:03:28 -07:00
|
|
|
core->paint_buffer_x,
|
|
|
|
|
core->paint_buffer_y);
|
2012-03-22 16:12:13 -07:00
|
|
|
|
2016-05-17 16:51:09 -07:00
|
|
|
gimp_applicator_set_opacity (core->applicator, image_opacity);
|
2017-02-01 15:38:25 -08:00
|
|
|
gimp_applicator_set_mode (core->applicator, paint_mode,
|
2017-02-12 14:49:26 -08:00
|
|
|
GIMP_LAYER_COLOR_SPACE_AUTO,
|
|
|
|
|
GIMP_LAYER_COLOR_SPACE_AUTO,
|
2017-02-14 13:51:47 -08:00
|
|
|
gimp_layer_mode_get_paint_composite_mode (paint_mode));
|
2013-05-21 09:52:40 -07:00
|
|
|
|
|
|
|
|
/* apply the paint area to the image */
|
|
|
|
|
gimp_applicator_blit (core->applicator,
|
|
|
|
|
GEGL_RECTANGLE (core->paint_buffer_x,
|
|
|
|
|
core->paint_buffer_y,
|
|
|
|
|
width, height));
|
1997-11-24 14:05:25 -08:00
|
|
|
}
|
2000-12-30 20:07:42 -08:00
|
|
|
else
|
|
|
|
|
{
|
app: refactor gimppaintcore-loops to coalesce iteration
The gimppaintcore-loops functions perform very little actual
computational work (in case of do_layer_blend(), at least for
simple blend modes), which makes the cost of buffer iteration, and
memory bandwidth, nonnegligible factors. Since these functions are
usually called in succession, acessing the same region of the same
buffers, using the same foramts, coalescing them into a single
function, which performs all the necessary processing in a single
step, can improve performance when these functions are the
bottleneck.
Add a gimp_paint_core_loops_process() function, which does just
that: it takes a set of algorithms to run, and a set of parameters,
and performs all of them in one go. The individual functions are
kept for convenience, but are merely wrappers around
gimp_paint_core_loops_process().
Be warned: the implementation uses unholy C++ from outer space, in
order to make this (sort of) managable. See the comments for more
details.
2018-04-14 16:02:21 -07:00
|
|
|
GimpPaintCoreLoopsParams params = {};
|
|
|
|
|
GimpPaintCoreLoopsAlgorithm algorithms = GIMP_PAINT_CORE_LOOPS_ALGORITHM_NONE;
|
1997-11-24 14:05:25 -08:00
|
|
|
|
app: refactor gimppaintcore-loops to coalesce iteration
The gimppaintcore-loops functions perform very little actual
computational work (in case of do_layer_blend(), at least for
simple blend modes), which makes the cost of buffer iteration, and
memory bandwidth, nonnegligible factors. Since these functions are
usually called in succession, acessing the same region of the same
buffers, using the same foramts, coalescing them into a single
function, which performs all the necessary processing in a single
step, can improve performance when these functions are the
bottleneck.
Add a gimp_paint_core_loops_process() function, which does just
that: it takes a set of algorithms to run, and a set of parameters,
and performs all of them in one go. The individual functions are
kept for convenience, but are merely wrappers around
gimp_paint_core_loops_process().
Be warned: the implementation uses unholy C++ from outer space, in
order to make this (sort of) managable. See the comments for more
details.
2018-04-14 16:02:21 -07:00
|
|
|
params.paint_buf = gimp_gegl_buffer_get_temp_buf (core->paint_buffer);
|
|
|
|
|
params.paint_buf_offset_x = core->paint_buffer_x;
|
|
|
|
|
params.paint_buf_offset_y = core->paint_buffer_y;
|
|
|
|
|
|
|
|
|
|
if (! params.paint_buf)
|
2013-05-21 09:52:40 -07:00
|
|
|
return;
|
2013-04-14 13:44:21 -07:00
|
|
|
|
2019-02-16 06:43:34 -08:00
|
|
|
params.dest_buffer = gimp_drawable_get_buffer (drawable);
|
2013-05-21 09:52:40 -07:00
|
|
|
|
|
|
|
|
if (mode == GIMP_PAINT_CONSTANT)
|
|
|
|
|
{
|
app: refactor gimppaintcore-loops to coalesce iteration
The gimppaintcore-loops functions perform very little actual
computational work (in case of do_layer_blend(), at least for
simple blend modes), which makes the cost of buffer iteration, and
memory bandwidth, nonnegligible factors. Since these functions are
usually called in succession, acessing the same region of the same
buffers, using the same foramts, coalescing them into a single
function, which performs all the necessary processing in a single
step, can improve performance when these functions are the
bottleneck.
Add a gimp_paint_core_loops_process() function, which does just
that: it takes a set of algorithms to run, and a set of parameters,
and performs all of them in one go. The individual functions are
kept for convenience, but are merely wrappers around
gimp_paint_core_loops_process().
Be warned: the implementation uses unholy C++ from outer space, in
order to make this (sort of) managable. See the comments for more
details.
2018-04-14 16:02:21 -07:00
|
|
|
params.canvas_buffer = core->canvas_buffer;
|
|
|
|
|
|
2013-05-21 09:52:40 -07:00
|
|
|
/* This step is skipped by the ink tool, which writes
|
|
|
|
|
* directly to canvas_buffer
|
|
|
|
|
*/
|
|
|
|
|
if (paint_mask != NULL)
|
|
|
|
|
{
|
|
|
|
|
/* Mix paint mask and canvas_buffer */
|
app: refactor gimppaintcore-loops to coalesce iteration
The gimppaintcore-loops functions perform very little actual
computational work (in case of do_layer_blend(), at least for
simple blend modes), which makes the cost of buffer iteration, and
memory bandwidth, nonnegligible factors. Since these functions are
usually called in succession, acessing the same region of the same
buffers, using the same foramts, coalescing them into a single
function, which performs all the necessary processing in a single
step, can improve performance when these functions are the
bottleneck.
Add a gimp_paint_core_loops_process() function, which does just
that: it takes a set of algorithms to run, and a set of parameters,
and performs all of them in one go. The individual functions are
kept for convenience, but are merely wrappers around
gimp_paint_core_loops_process().
Be warned: the implementation uses unholy C++ from outer space, in
order to make this (sort of) managable. See the comments for more
details.
2018-04-14 16:02:21 -07:00
|
|
|
params.paint_mask = paint_mask;
|
|
|
|
|
params.paint_mask_offset_x = paint_mask_offset_x;
|
|
|
|
|
params.paint_mask_offset_y = paint_mask_offset_y;
|
|
|
|
|
params.stipple = GIMP_IS_AIRBRUSH (core);
|
|
|
|
|
params.paint_opacity = paint_opacity;
|
|
|
|
|
|
2019-02-12 00:56:34 -08:00
|
|
|
algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_BUFFER;
|
2013-05-21 09:52:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write canvas_buffer to paint_buf */
|
app: refactor gimppaintcore-loops to coalesce iteration
The gimppaintcore-loops functions perform very little actual
computational work (in case of do_layer_blend(), at least for
simple blend modes), which makes the cost of buffer iteration, and
memory bandwidth, nonnegligible factors. Since these functions are
usually called in succession, acessing the same region of the same
buffers, using the same foramts, coalescing them into a single
function, which performs all the necessary processing in a single
step, can improve performance when these functions are the
bottleneck.
Add a gimp_paint_core_loops_process() function, which does just
that: it takes a set of algorithms to run, and a set of parameters,
and performs all of them in one go. The individual functions are
kept for convenience, but are merely wrappers around
gimp_paint_core_loops_process().
Be warned: the implementation uses unholy C++ from outer space, in
order to make this (sort of) managable. See the comments for more
details.
2018-04-14 16:02:21 -07:00
|
|
|
algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_PAINT_BUF_ALPHA;
|
2013-05-21 09:52:40 -07:00
|
|
|
|
|
|
|
|
/* undo buf -> paint_buf -> dest_buffer */
|
app: refactor gimppaintcore-loops to coalesce iteration
The gimppaintcore-loops functions perform very little actual
computational work (in case of do_layer_blend(), at least for
simple blend modes), which makes the cost of buffer iteration, and
memory bandwidth, nonnegligible factors. Since these functions are
usually called in succession, acessing the same region of the same
buffers, using the same foramts, coalescing them into a single
function, which performs all the necessary processing in a single
step, can improve performance when these functions are the
bottleneck.
Add a gimp_paint_core_loops_process() function, which does just
that: it takes a set of algorithms to run, and a set of parameters,
and performs all of them in one go. The individual functions are
kept for convenience, but are merely wrappers around
gimp_paint_core_loops_process().
Be warned: the implementation uses unholy C++ from outer space, in
order to make this (sort of) managable. See the comments for more
details.
2018-04-14 16:02:21 -07:00
|
|
|
params.src_buffer = core->undo_buffer;
|
2013-05-21 09:52:40 -07:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (paint_mask);
|
2013-04-14 13:44:21 -07:00
|
|
|
|
2013-05-21 09:52:40 -07:00
|
|
|
/* Write paint_mask to paint_buf, does not modify canvas_buffer */
|
app: refactor gimppaintcore-loops to coalesce iteration
The gimppaintcore-loops functions perform very little actual
computational work (in case of do_layer_blend(), at least for
simple blend modes), which makes the cost of buffer iteration, and
memory bandwidth, nonnegligible factors. Since these functions are
usually called in succession, acessing the same region of the same
buffers, using the same foramts, coalescing them into a single
function, which performs all the necessary processing in a single
step, can improve performance when these functions are the
bottleneck.
Add a gimp_paint_core_loops_process() function, which does just
that: it takes a set of algorithms to run, and a set of parameters,
and performs all of them in one go. The individual functions are
kept for convenience, but are merely wrappers around
gimp_paint_core_loops_process().
Be warned: the implementation uses unholy C++ from outer space, in
order to make this (sort of) managable. See the comments for more
details.
2018-04-14 16:02:21 -07:00
|
|
|
params.paint_mask = paint_mask;
|
|
|
|
|
params.paint_mask_offset_x = paint_mask_offset_x;
|
|
|
|
|
params.paint_mask_offset_y = paint_mask_offset_y;
|
|
|
|
|
params.paint_opacity = paint_opacity;
|
|
|
|
|
|
2019-02-12 00:56:34 -08:00
|
|
|
algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_PAINT_BUF_ALPHA;
|
2013-05-21 04:03:28 -07:00
|
|
|
|
2013-05-21 09:52:40 -07:00
|
|
|
/* dest_buffer -> paint_buf -> dest_buffer */
|
2019-02-16 06:43:34 -08:00
|
|
|
params.src_buffer = params.dest_buffer;
|
2013-05-21 09:52:40 -07:00
|
|
|
}
|
|
|
|
|
|
app: refactor gimppaintcore-loops to coalesce iteration
The gimppaintcore-loops functions perform very little actual
computational work (in case of do_layer_blend(), at least for
simple blend modes), which makes the cost of buffer iteration, and
memory bandwidth, nonnegligible factors. Since these functions are
usually called in succession, acessing the same region of the same
buffers, using the same foramts, coalescing them into a single
function, which performs all the necessary processing in a single
step, can improve performance when these functions are the
bottleneck.
Add a gimp_paint_core_loops_process() function, which does just
that: it takes a set of algorithms to run, and a set of parameters,
and performs all of them in one go. The individual functions are
kept for convenience, but are merely wrappers around
gimp_paint_core_loops_process().
Be warned: the implementation uses unholy C++ from outer space, in
order to make this (sort of) managable. See the comments for more
details.
2018-04-14 16:02:21 -07:00
|
|
|
params.mask_buffer = core->mask_buffer;
|
|
|
|
|
params.mask_offset_x = core->mask_x_offset;
|
|
|
|
|
params.mask_offset_y = core->mask_y_offset;
|
|
|
|
|
params.image_opacity = image_opacity;
|
|
|
|
|
params.paint_mode = paint_mode;
|
|
|
|
|
|
|
|
|
|
algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_DO_LAYER_BLEND;
|
|
|
|
|
|
2019-02-16 06:43:34 -08:00
|
|
|
if (affect != GIMP_COMPONENT_MASK_ALL)
|
2013-05-21 09:52:40 -07:00
|
|
|
{
|
2019-02-16 06:43:34 -08:00
|
|
|
params.affect = affect;
|
|
|
|
|
|
|
|
|
|
algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_MASK_COMPONENTS;
|
2013-05-21 09:52:40 -07:00
|
|
|
}
|
2019-02-16 06:43:34 -08:00
|
|
|
|
|
|
|
|
gimp_paint_core_loops_process (¶ms, algorithms);
|
2013-05-21 04:03:28 -07:00
|
|
|
}
|
2012-03-22 14:47:56 -07:00
|
|
|
|
1997-11-24 14:05:25 -08:00
|
|
|
/* Update the undo extents */
|
2012-03-31 09:28:18 -07:00
|
|
|
core->x1 = MIN (core->x1, core->paint_buffer_x);
|
|
|
|
|
core->y1 = MIN (core->y1, core->paint_buffer_y);
|
|
|
|
|
core->x2 = MAX (core->x2, core->paint_buffer_x + width);
|
|
|
|
|
core->y2 = MAX (core->y2, core->paint_buffer_y + height);
|
1997-11-24 14:05:25 -08:00
|
|
|
|
2007-11-13 02:59:32 -08:00
|
|
|
/* Update the drawable */
|
|
|
|
|
gimp_drawable_update (drawable,
|
2012-03-31 09:28:18 -07:00
|
|
|
core->paint_buffer_x,
|
|
|
|
|
core->paint_buffer_y,
|
|
|
|
|
width, height);
|
1997-12-07 17:13:10 -08:00
|
|
|
}
|
|
|
|
|
|
2002-02-14 11:31:16 -08:00
|
|
|
/* 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).
|
1997-12-07 17:13:10 -08:00
|
|
|
|
2002-02-14 11:31:16 -08:00
|
|
|
* When not drawing on alpha-enabled images, it just paints using
|
|
|
|
|
* NORMAL mode.
|
|
|
|
|
*/
|
2004-05-25 13:41:09 -07:00
|
|
|
void
|
2002-03-19 07:05:38 -08:00
|
|
|
gimp_paint_core_replace (GimpPaintCore *core,
|
2013-05-21 04:03:28 -07:00
|
|
|
const GimpTempBuf *paint_mask,
|
|
|
|
|
gint paint_mask_offset_x,
|
|
|
|
|
gint paint_mask_offset_y,
|
2004-05-28 02:34:13 -07:00
|
|
|
GimpDrawable *drawable,
|
|
|
|
|
gdouble paint_opacity,
|
|
|
|
|
gdouble image_opacity,
|
|
|
|
|
GimpPaintApplicationMode mode)
|
1997-12-07 17:13:10 -08:00
|
|
|
{
|
2019-02-16 06:43:34 -08:00
|
|
|
gint width, height;
|
|
|
|
|
GimpComponentMask affect;
|
1997-12-07 17:13:10 -08:00
|
|
|
|
2001-01-14 13:11:52 -08:00
|
|
|
if (! gimp_drawable_has_alpha (drawable))
|
1997-12-07 17:13:10 -08:00
|
|
|
{
|
2013-05-21 04:03:28 -07:00
|
|
|
gimp_paint_core_paste (core, paint_mask,
|
|
|
|
|
paint_mask_offset_x,
|
|
|
|
|
paint_mask_offset_y,
|
2012-04-03 14:58:56 -07:00
|
|
|
drawable,
|
2004-05-28 02:34:13 -07:00
|
|
|
paint_opacity,
|
2017-01-08 14:00:19 -08:00
|
|
|
image_opacity,
|
2017-08-12 12:35:47 -07:00
|
|
|
GIMP_LAYER_MODE_NORMAL,
|
2004-05-28 02:34:13 -07:00
|
|
|
mode);
|
1997-12-07 17:13:10 -08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-31 09:28:18 -07:00
|
|
|
width = gegl_buffer_get_width (core->paint_buffer);
|
|
|
|
|
height = gegl_buffer_get_height (core->paint_buffer);
|
|
|
|
|
|
2019-02-16 06:43:34 -08:00
|
|
|
affect = gimp_drawable_get_active_mask (drawable);
|
|
|
|
|
|
|
|
|
|
if (! affect)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-02-12 03:25:28 -08:00
|
|
|
if (core->applicator)
|
2012-04-03 14:58:56 -07:00
|
|
|
{
|
2019-02-12 03:25:28 -08:00
|
|
|
GeglRectangle mask_rect;
|
2019-02-12 04:58:08 -08:00
|
|
|
GeglBuffer *mask_buffer;
|
2019-02-12 03:25:28 -08:00
|
|
|
|
2019-02-12 04:58:08 -08:00
|
|
|
/* If the mode is CONSTANT:
|
|
|
|
|
* combine the paint mask to the canvas buffer, and use it as the mask
|
|
|
|
|
* buffer
|
|
|
|
|
*/
|
|
|
|
|
if (mode == GIMP_PAINT_CONSTANT)
|
|
|
|
|
{
|
2019-02-12 03:25:28 -08:00
|
|
|
/* Some tools (ink) paint the mask to paint_core->canvas_buffer
|
|
|
|
|
* directly. Don't need to copy it in this case.
|
|
|
|
|
*/
|
2019-02-12 04:58:08 -08:00
|
|
|
if (paint_mask != NULL)
|
|
|
|
|
{
|
|
|
|
|
GeglBuffer *paint_mask_buffer =
|
|
|
|
|
gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask);
|
2013-05-21 09:52:40 -07:00
|
|
|
|
2019-02-12 04:58:08 -08:00
|
|
|
gimp_gegl_combine_mask_weird (paint_mask_buffer,
|
|
|
|
|
GEGL_RECTANGLE (paint_mask_offset_x,
|
|
|
|
|
paint_mask_offset_y,
|
|
|
|
|
width, height),
|
|
|
|
|
core->canvas_buffer,
|
|
|
|
|
GEGL_RECTANGLE (core->paint_buffer_x,
|
|
|
|
|
core->paint_buffer_y,
|
|
|
|
|
width, height),
|
|
|
|
|
paint_opacity,
|
|
|
|
|
GIMP_IS_AIRBRUSH (core));
|
2012-04-03 14:58:56 -07:00
|
|
|
|
2019-02-12 04:58:08 -08:00
|
|
|
g_object_unref (paint_mask_buffer);
|
|
|
|
|
}
|
2019-02-12 03:25:28 -08:00
|
|
|
|
2019-02-12 04:58:08 -08:00
|
|
|
mask_buffer = g_object_ref (core->canvas_buffer);
|
|
|
|
|
mask_rect = *GEGL_RECTANGLE (core->paint_buffer_x,
|
|
|
|
|
core->paint_buffer_y,
|
|
|
|
|
width, height);
|
2019-02-12 03:25:28 -08:00
|
|
|
|
2019-02-12 04:58:08 -08:00
|
|
|
gimp_applicator_set_src_buffer (core->applicator,
|
|
|
|
|
core->undo_buffer);
|
2013-05-21 09:52:40 -07:00
|
|
|
}
|
2019-02-12 04:58:08 -08:00
|
|
|
/* Otherwise:
|
|
|
|
|
* use the paint mask as the mask buffer directly
|
|
|
|
|
*/
|
2013-05-21 09:52:40 -07:00
|
|
|
else
|
|
|
|
|
{
|
2019-02-12 04:58:08 -08:00
|
|
|
mask_buffer =
|
2019-02-12 03:25:28 -08:00
|
|
|
gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask);
|
2019-02-12 04:58:08 -08:00
|
|
|
mask_rect = *GEGL_RECTANGLE (paint_mask_offset_x,
|
|
|
|
|
paint_mask_offset_y,
|
|
|
|
|
width, height);
|
2013-05-21 04:03:28 -07:00
|
|
|
|
2019-02-12 04:58:08 -08:00
|
|
|
gimp_applicator_set_src_buffer (core->applicator,
|
|
|
|
|
gimp_drawable_get_buffer (drawable));
|
2019-02-12 03:25:28 -08:00
|
|
|
}
|
2012-04-22 15:32:14 -07:00
|
|
|
|
2019-02-12 04:58:08 -08:00
|
|
|
if (core->mask_buffer)
|
|
|
|
|
{
|
|
|
|
|
GeglBuffer *combined_mask_buffer;
|
|
|
|
|
GeglRectangle combined_mask_rect;
|
|
|
|
|
GeglRectangle aligned_combined_mask_rect;
|
|
|
|
|
|
|
|
|
|
combined_mask_rect = *GEGL_RECTANGLE (core->paint_buffer_x,
|
|
|
|
|
core->paint_buffer_y,
|
|
|
|
|
width, height);
|
|
|
|
|
|
|
|
|
|
gimp_gegl_rectangle_align_to_tile_grid (
|
|
|
|
|
&aligned_combined_mask_rect, &combined_mask_rect,
|
|
|
|
|
gimp_drawable_get_buffer (drawable));
|
|
|
|
|
|
|
|
|
|
combined_mask_buffer = gegl_buffer_new (&aligned_combined_mask_rect,
|
|
|
|
|
babl_format ("Y float"));
|
|
|
|
|
|
|
|
|
|
gegl_buffer_copy (core->mask_buffer,
|
|
|
|
|
GEGL_RECTANGLE (aligned_combined_mask_rect.x -
|
|
|
|
|
core->mask_x_offset,
|
|
|
|
|
aligned_combined_mask_rect.y -
|
|
|
|
|
core->mask_y_offset,
|
|
|
|
|
aligned_combined_mask_rect.width,
|
|
|
|
|
aligned_combined_mask_rect.height),
|
|
|
|
|
GEGL_ABYSS_NONE,
|
|
|
|
|
combined_mask_buffer, &aligned_combined_mask_rect);
|
|
|
|
|
|
|
|
|
|
gimp_gegl_combine_mask (mask_buffer, &mask_rect,
|
|
|
|
|
combined_mask_buffer, &combined_mask_rect,
|
|
|
|
|
1.0);
|
|
|
|
|
|
|
|
|
|
g_object_unref (mask_buffer);
|
|
|
|
|
|
|
|
|
|
mask_buffer = combined_mask_buffer;
|
|
|
|
|
mask_rect = combined_mask_rect;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gimp_applicator_set_mask_buffer (core->applicator, mask_buffer);
|
|
|
|
|
gimp_applicator_set_mask_offset (core->applicator,
|
|
|
|
|
core->paint_buffer_x - mask_rect.x,
|
|
|
|
|
core->paint_buffer_y - mask_rect.y);
|
|
|
|
|
|
|
|
|
|
gimp_applicator_set_apply_buffer (core->applicator,
|
|
|
|
|
core->paint_buffer);
|
|
|
|
|
gimp_applicator_set_apply_offset (core->applicator,
|
|
|
|
|
core->paint_buffer_x,
|
|
|
|
|
core->paint_buffer_y);
|
|
|
|
|
|
|
|
|
|
gimp_applicator_set_opacity (core->applicator, image_opacity);
|
|
|
|
|
gimp_applicator_set_mode (core->applicator, GIMP_LAYER_MODE_REPLACE,
|
|
|
|
|
GIMP_LAYER_COLOR_SPACE_AUTO,
|
|
|
|
|
GIMP_LAYER_COLOR_SPACE_AUTO,
|
|
|
|
|
gimp_layer_mode_get_paint_composite_mode (
|
|
|
|
|
GIMP_LAYER_MODE_REPLACE));
|
|
|
|
|
|
2019-02-12 03:25:28 -08:00
|
|
|
/* apply the paint area to the image */
|
2019-02-12 04:58:08 -08:00
|
|
|
gimp_applicator_blit (core->applicator,
|
|
|
|
|
GEGL_RECTANGLE (core->paint_buffer_x,
|
|
|
|
|
core->paint_buffer_y,
|
|
|
|
|
width, height));
|
|
|
|
|
|
|
|
|
|
gimp_applicator_set_mask_buffer (core->applicator, core->mask_buffer);
|
|
|
|
|
gimp_applicator_set_mask_offset (core->applicator,
|
|
|
|
|
core->mask_x_offset,
|
|
|
|
|
core->mask_y_offset);
|
|
|
|
|
|
|
|
|
|
g_object_unref (mask_buffer);
|
2000-03-04 16:06:11 -08:00
|
|
|
}
|
2000-12-30 20:07:42 -08:00
|
|
|
else
|
2000-03-04 16:06:11 -08:00
|
|
|
{
|
2019-02-12 03:25:28 -08:00
|
|
|
GimpPaintCoreLoopsParams params = {};
|
|
|
|
|
GimpPaintCoreLoopsAlgorithm algorithms = GIMP_PAINT_CORE_LOOPS_ALGORITHM_NONE;
|
2013-05-21 04:03:28 -07:00
|
|
|
|
2019-02-12 03:25:28 -08:00
|
|
|
params.paint_buf = gimp_gegl_buffer_get_temp_buf (core->paint_buffer);
|
|
|
|
|
params.paint_buf_offset_x = core->paint_buffer_x;
|
|
|
|
|
params.paint_buf_offset_y = core->paint_buffer_y;
|
2000-12-30 20:07:42 -08:00
|
|
|
|
2019-02-12 03:25:28 -08:00
|
|
|
if (! params.paint_buf)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-02-16 06:43:34 -08:00
|
|
|
params.dest_buffer = gimp_drawable_get_buffer (drawable);
|
2012-03-23 04:31:21 -07:00
|
|
|
|
2019-02-12 03:25:28 -08:00
|
|
|
if (mode == GIMP_PAINT_CONSTANT)
|
|
|
|
|
{
|
|
|
|
|
params.canvas_buffer = core->canvas_buffer;
|
|
|
|
|
|
|
|
|
|
/* This step is skipped by the ink tool, which writes
|
|
|
|
|
* directly to canvas_buffer
|
|
|
|
|
*/
|
|
|
|
|
if (paint_mask != NULL)
|
|
|
|
|
{
|
|
|
|
|
/* Mix paint mask and canvas_buffer */
|
|
|
|
|
params.paint_mask = paint_mask;
|
|
|
|
|
params.paint_mask_offset_x = paint_mask_offset_x;
|
|
|
|
|
params.paint_mask_offset_y = paint_mask_offset_y;
|
|
|
|
|
params.stipple = GIMP_IS_AIRBRUSH (core);
|
|
|
|
|
params.paint_opacity = paint_opacity;
|
|
|
|
|
|
|
|
|
|
algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_BUFFER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write canvas_buffer to the compositing mask */
|
|
|
|
|
algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK;
|
|
|
|
|
|
|
|
|
|
/* undo buf -> paint_buf -> dest_buffer */
|
|
|
|
|
params.src_buffer = core->undo_buffer;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (paint_mask);
|
|
|
|
|
|
|
|
|
|
/* Write paint_mask to the compositing mask, does not modify
|
|
|
|
|
* canvas_buffer
|
|
|
|
|
*/
|
|
|
|
|
params.paint_mask = paint_mask;
|
|
|
|
|
params.paint_mask_offset_x = paint_mask_offset_x;
|
|
|
|
|
params.paint_mask_offset_y = paint_mask_offset_y;
|
|
|
|
|
params.paint_opacity = paint_opacity;
|
|
|
|
|
|
|
|
|
|
algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
|
|
|
|
|
|
|
|
|
|
/* dest_buffer -> paint_buf -> dest_buffer */
|
2019-02-16 06:43:34 -08:00
|
|
|
params.src_buffer = params.dest_buffer;
|
2019-02-12 03:25:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
params.mask_buffer = core->mask_buffer;
|
|
|
|
|
params.mask_offset_x = core->mask_x_offset;
|
|
|
|
|
params.mask_offset_y = core->mask_y_offset;
|
|
|
|
|
params.image_opacity = image_opacity;
|
|
|
|
|
params.paint_mode = GIMP_LAYER_MODE_REPLACE;
|
|
|
|
|
|
|
|
|
|
algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_DO_LAYER_BLEND;
|
|
|
|
|
|
2019-02-16 06:43:34 -08:00
|
|
|
if (affect != GIMP_COMPONENT_MASK_ALL)
|
2019-02-12 03:25:28 -08:00
|
|
|
{
|
2019-02-16 06:43:34 -08:00
|
|
|
params.affect = affect;
|
|
|
|
|
|
|
|
|
|
algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_MASK_COMPONENTS;
|
2019-02-12 03:25:28 -08:00
|
|
|
}
|
2019-02-16 06:43:34 -08:00
|
|
|
|
|
|
|
|
gimp_paint_core_loops_process (¶ms, algorithms);
|
2019-02-12 03:25:28 -08:00
|
|
|
}
|
2013-05-21 04:03:28 -07:00
|
|
|
|
1997-12-07 17:13:10 -08:00
|
|
|
/* Update the undo extents */
|
2012-03-31 09:28:18 -07:00
|
|
|
core->x1 = MIN (core->x1, core->paint_buffer_x);
|
|
|
|
|
core->y1 = MIN (core->y1, core->paint_buffer_y);
|
|
|
|
|
core->x2 = MAX (core->x2, core->paint_buffer_x + width);
|
|
|
|
|
core->y2 = MAX (core->y2, core->paint_buffer_y + height);
|
1997-12-07 17:13:10 -08:00
|
|
|
|
2007-11-13 02:59:32 -08:00
|
|
|
/* Update the drawable */
|
|
|
|
|
gimp_drawable_update (drawable,
|
2012-03-31 09:28:18 -07:00
|
|
|
core->paint_buffer_x,
|
|
|
|
|
core->paint_buffer_y,
|
|
|
|
|
width, height);
|
1997-11-24 14:05:25 -08:00
|
|
|
}
|
|
|
|
|
|
2011-09-14 10:42:52 -07:00
|
|
|
/**
|
|
|
|
|
* Smooth and store coords in the stroke buffer
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gimp_paint_core_smooth_coords (GimpPaintCore *core,
|
|
|
|
|
GimpPaintOptions *paint_options,
|
|
|
|
|
GimpCoords *coords)
|
|
|
|
|
{
|
|
|
|
|
GimpSmoothingOptions *smoothing_options = paint_options->smoothing_options;
|
|
|
|
|
GArray *history = core->stroke_buffer;
|
|
|
|
|
|
|
|
|
|
if (core->stroke_buffer == NULL)
|
2018-03-24 13:49:01 -07:00
|
|
|
return; /* Paint core has not initialized yet */
|
2011-09-14 10:42:52 -07:00
|
|
|
|
|
|
|
|
if (smoothing_options->use_smoothing &&
|
|
|
|
|
smoothing_options->smoothing_quality > 0)
|
|
|
|
|
{
|
|
|
|
|
gint i;
|
|
|
|
|
guint length;
|
|
|
|
|
gint min_index;
|
|
|
|
|
gdouble gaussian_weight = 0.0;
|
|
|
|
|
gdouble gaussian_weight2 = SQR (smoothing_options->smoothing_factor);
|
|
|
|
|
gdouble velocity_sum = 0.0;
|
|
|
|
|
gdouble scale_sum = 0.0;
|
|
|
|
|
|
|
|
|
|
g_array_append_val (history, *coords);
|
|
|
|
|
|
|
|
|
|
if (history->len < 2)
|
2018-03-24 13:49:01 -07:00
|
|
|
return; /* Just don't bother, nothing to do */
|
2011-09-14 10:42:52 -07:00
|
|
|
|
|
|
|
|
coords->x = coords->y = 0.0;
|
|
|
|
|
|
|
|
|
|
length = MIN (smoothing_options->smoothing_quality, history->len);
|
|
|
|
|
|
|
|
|
|
min_index = history->len - length;
|
|
|
|
|
|
|
|
|
|
if (gaussian_weight2 != 0.0)
|
|
|
|
|
gaussian_weight = 1 / (sqrt (2 * G_PI) * smoothing_options->smoothing_factor);
|
|
|
|
|
|
|
|
|
|
for (i = history->len - 1; i >= min_index; i--)
|
|
|
|
|
{
|
|
|
|
|
gdouble rate = 0.0;
|
|
|
|
|
GimpCoords *next_coords = &g_array_index (history,
|
|
|
|
|
GimpCoords, i);
|
|
|
|
|
|
|
|
|
|
if (gaussian_weight2 != 0.0)
|
|
|
|
|
{
|
|
|
|
|
/* We use gaussian function with velocity as a window function */
|
|
|
|
|
velocity_sum += next_coords->velocity * 100;
|
2012-04-28 02:42:33 -07:00
|
|
|
rate = gaussian_weight * exp (-velocity_sum * velocity_sum /
|
|
|
|
|
(2 * gaussian_weight2));
|
2011-09-14 10:42:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scale_sum += rate;
|
|
|
|
|
coords->x += rate * next_coords->x;
|
|
|
|
|
coords->y += rate * next_coords->y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (scale_sum != 0.0)
|
|
|
|
|
{
|
|
|
|
|
coords->x /= scale_sum;
|
|
|
|
|
coords->y /= scale_sum;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|