1997-11-25 06:05:25 +08:00
|
|
|
/* The GIMP -- an image manipulation program
|
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
1998-04-13 13:44:11 +08:00
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
1997-11-25 06:05:25 +08:00
|
|
|
*/
|
2000-12-17 05: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-02 04:30:56 +08:00
|
|
|
#include "config.h"
|
|
|
|
|
2003-08-14 16:46:05 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
#include <stdlib.h>
|
|
|
|
#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-02 04:30:56 +08:00
|
|
|
|
2003-02-08 01:12:21 +08:00
|
|
|
#include <glib-object.h>
|
2000-12-17 05:37:03 +08:00
|
|
|
|
2001-01-24 02:49:44 +08:00
|
|
|
#include "libgimpcolor/gimpcolor.h"
|
2001-01-24 07:56:18 +08:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
2001-05-21 21:58:46 +08:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2001-01-24 02:49:44 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
#include "paint-types.h"
|
2000-12-17 05:37:03 +08:00
|
|
|
|
2001-05-15 19:25:25 +08:00
|
|
|
#include "base/brush-scale.h"
|
|
|
|
#include "base/pixel-region.h"
|
|
|
|
#include "base/temp-buf.h"
|
|
|
|
#include "base/tile-manager.h"
|
|
|
|
#include "base/tile.h"
|
|
|
|
|
2001-04-07 23:58:26 +08:00
|
|
|
#include "paint-funcs/paint-funcs.h"
|
|
|
|
|
2003-02-14 22:14:29 +08:00
|
|
|
#include "core/gimp.h"
|
2002-06-17 18:34:28 +08:00
|
|
|
#include "core/gimpbrush.h"
|
2003-02-14 22:14:29 +08:00
|
|
|
#include "core/gimpcontainer.h"
|
2001-05-09 10:32:03 +08:00
|
|
|
#include "core/gimpdrawable.h"
|
|
|
|
#include "core/gimpgradient.h"
|
|
|
|
#include "core/gimpimage.h"
|
2003-02-13 19:23:50 +08:00
|
|
|
#include "core/gimpimage-undo.h"
|
Port to glib/gtk+ 2.0 episode I (every segfault has it's beginning)
2001-07-24 Michael Natterer <mitch@gimp.org>
Port to glib/gtk+ 2.0 episode I (every segfault has it's beginning)
* configure.in: require glib/gtk+ >= 1.3.7, commented out the
gtkxmhtml stuff.
From now on, you will need glib, pango, atk and gtk+ HEAD from CVS
to hack or use GIMP HEAD.
Beware, it crashes randomly :)
* app/core/Makefile.am
* app/core/gimpmarshal.list: new file plus rules to generate
gimpmarshal.[ch] from it.
* app/core/*
* app/tools/*
* app/widgets/*
* libgimpwidgets/*: started to use the glib object system. All
core/ objects are still gtk objects however. All signals are
created using g_signal_new(). There are many gtk+ artefacts left.
Finally, we will _not_ use the gtk_signal_foo() wrappers and
friends any more.
* app/colormaps.c
* app/devices.[ch]
* app/disp_callbacks.c
* app/errorconsole.c
* app/file-save.[ch]
* app/interface.c
* app/module_db.c
* app/nav_window.c
* app/ops_buttons.c
* app/scroll.c
* app/user_install.c
* app/gui/about-dialog.c
* app/gui/brush-editor.c
* app/gui/brushes-commands.c
* app/gui/color-notebook.c
* app/gui/colormap-dialog.c
* app/gui/dialogs-commands.c
* app/gui/dialogs-constructors.c
* app/gui/file-commands.c
* app/gui/file-dialog-utils.c
* app/gui/file-new-dialog.c
* app/gui/file-open-dialog.[ch]
* app/gui/file-save-dialog.c
* app/gui/gradient-editor.c
* app/gui/gradients-commands.c
* app/gui/image-commands.c
* app/gui/info-dialog.[ch]
* app/gui/layer-select.c
* app/gui/layers-commands.c
* app/gui/menus.c
* app/gui/offset-dialog.c
* app/gui/palette-editor.c
* app/gui/palettes-commands.c
* app/gui/patterns-commands.c
* app/gui/preferences-dialog.c
* app/gui/resize-dialog.[ch]
* app/gui/splash.c
* app/gui/tips-dialog.c
* app/gui/tool-options-dialog.c
* app/gui/toolbox.c
* app/gui/tools-commands.c
* libgimp/gimpbrushmenu.c
* libgimp/gimpmenu.c
* libgimp/gimppatternmenu.c
* libgimp/gimpui.c
* libgimpbase/gimpenv.c: tons and tons of changes like "const
gchar*", switch from GdkDeviceInfo to GdkDevice (very incomplete
and currently disables), lots of s/gtk_signal/g_signal/,
removal/replacement of deprecated stuff,
s/GtkSignalFunc/GCallback/ and lots of small changes and fixes
while I was on it, zillions of warnings left...
* modules/Makefile.am: disabled the water color selector
temporarily (XInput issues).
* plug-ins/Makefile.am
* plug-ins/common/.cvsignore
* plug-ins/common/Makefile.am
* plug-ins/common/plugin-defs.pl: simply excluded all plug-ins
which did not build (including Script-Fu). They are trivial to
fix.
2001-07-25 05:27:11 +08:00
|
|
|
#include "core/gimpmarshal.h"
|
2003-02-14 22:14:29 +08:00
|
|
|
#include "core/gimppaintinfo.h"
|
2001-05-09 10:32:03 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
#include "gimppaintcore.h"
|
|
|
|
#include "gimppaintcore-kernels.h"
|
2003-02-14 22:14:29 +08:00
|
|
|
#include "gimppaintcore-undo.h"
|
2002-06-17 18:34:28 +08:00
|
|
|
#include "gimppaintoptions.h"
|
2001-03-08 09:07:03 +08:00
|
|
|
|
2003-03-26 00:38:19 +08:00
|
|
|
#include "gimp-intl.h"
|
2000-03-05 08:06:11 +08:00
|
|
|
|
2000-05-29 16:40:29 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
#define EPSILON 0.00001
|
2001-01-24 07:56:18 +08:00
|
|
|
|
1999-05-15 08:02:47 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
/* local function prototypes */
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
static void gimp_paint_core_class_init (GimpPaintCoreClass *klass);
|
|
|
|
static void gimp_paint_core_init (GimpPaintCore *core);
|
2001-02-28 03:18:01 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
static void gimp_paint_core_finalize (GObject *object);
|
2001-11-20 22:20:17 +08:00
|
|
|
|
2002-02-21 19:01:12 +08:00
|
|
|
static void gimp_paint_core_calc_brush_size (GimpPaintCore *core,
|
|
|
|
MaskBuf *mask,
|
2002-02-15 03:31:16 +08:00
|
|
|
gdouble scale,
|
|
|
|
gint *width,
|
|
|
|
gint *height);
|
2003-10-07 05:22:09 +08:00
|
|
|
static inline void rotate_pointers (gulong **p,
|
|
|
|
guint32 n);
|
2002-02-15 03:31:16 +08:00
|
|
|
static MaskBuf * gimp_paint_core_subsample_mask (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
MaskBuf *mask,
|
|
|
|
gdouble x,
|
|
|
|
gdouble y);
|
2002-02-15 03:31:16 +08:00
|
|
|
static MaskBuf * gimp_paint_core_pressurize_mask (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
MaskBuf *brush_mask,
|
|
|
|
gdouble x,
|
|
|
|
gdouble y,
|
|
|
|
gdouble pressure);
|
2002-02-15 03:31:16 +08:00
|
|
|
static MaskBuf * gimp_paint_core_solidify_mask (GimpPaintCore *core,
|
2003-07-14 22:50:41 +08:00
|
|
|
MaskBuf *brush_mask,
|
|
|
|
gdouble x,
|
|
|
|
gdouble y);
|
2002-02-15 03:31:16 +08:00
|
|
|
static MaskBuf * gimp_paint_core_scale_mask (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
MaskBuf *brush_mask,
|
|
|
|
gdouble scale);
|
2002-02-15 03:31:16 +08:00
|
|
|
static MaskBuf * gimp_paint_core_scale_pixmap (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
MaskBuf *brush_mask,
|
|
|
|
gdouble scale);
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
static MaskBuf * gimp_paint_core_get_brush_mask (GimpPaintCore *core,
|
2002-03-19 23:05:38 +08:00
|
|
|
GimpBrushApplicationMode brush_hardness,
|
2002-02-13 22:50:37 +08:00
|
|
|
gdouble scale);
|
2002-02-15 03:31:16 +08:00
|
|
|
static void gimp_paint_core_paste (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
MaskBuf *brush_mask,
|
|
|
|
GimpDrawable *drawable,
|
2002-03-04 01:38:12 +08:00
|
|
|
gdouble brush_opacity,
|
|
|
|
gdouble image_opacity,
|
2002-02-13 22:50:37 +08:00
|
|
|
GimpLayerModeEffects paint_mode,
|
2002-03-19 23:05:38 +08:00
|
|
|
GimpPaintApplicationMode mode);
|
2002-02-15 03:31:16 +08:00
|
|
|
static void gimp_paint_core_replace (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
MaskBuf *brush_mask,
|
|
|
|
GimpDrawable *drawable,
|
2002-03-04 01:38:12 +08:00
|
|
|
gdouble brush_opacity,
|
|
|
|
gdouble image_opacity,
|
2002-03-19 23:05:38 +08:00
|
|
|
GimpPaintApplicationMode mode);
|
2002-02-13 22:50:37 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
static void brush_to_canvas_tiles (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
MaskBuf *brush_mask,
|
2002-03-04 01:38:12 +08:00
|
|
|
gdouble brush_opacity);
|
2002-02-15 03:31:16 +08:00
|
|
|
static void brush_to_canvas_buf (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
MaskBuf *brush_mask,
|
2002-03-04 01:38:12 +08:00
|
|
|
gdouble brush_opacity);
|
2002-02-15 03:31:16 +08:00
|
|
|
static void canvas_tiles_to_canvas_buf (GimpPaintCore *core);
|
2002-02-13 22:50:37 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
static void set_undo_tiles (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
GimpDrawable *drawable,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gint h);
|
2002-02-15 03:31:16 +08:00
|
|
|
static void set_canvas_tiles (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gint h);
|
2002-02-15 03:31:16 +08:00
|
|
|
static void gimp_paint_core_invalidate_cache (GimpBrush *brush,
|
|
|
|
GimpPaintCore *core);
|
2000-06-06 06:08:45 +08:00
|
|
|
|
|
|
|
|
|
|
|
/* brush pipe utility functions */
|
2002-02-15 03:31:16 +08:00
|
|
|
static void paint_line_pixmap_mask (GimpImage *dest,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
TempBuf *pixmap_mask,
|
|
|
|
TempBuf *brush_mask,
|
|
|
|
guchar *d,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint bytes,
|
|
|
|
gint width,
|
2002-03-19 23:05:38 +08:00
|
|
|
GimpBrushApplicationMode mode);
|
2002-02-15 03:31:16 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
static GimpObjectClass *parent_class = NULL;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2003-02-14 22:14:29 +08:00
|
|
|
static gint global_core_ID = 1;
|
2001-02-28 03:18:01 +08:00
|
|
|
|
2001-02-27 13:21:12 +08:00
|
|
|
|
2001-08-14 22:53:55 +08:00
|
|
|
GType
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_get_type (void)
|
2001-02-27 13:21:12 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
static GType core_type = 0;
|
2001-02-27 13:21:12 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
if (! core_type)
|
2001-02-27 13:21:12 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
static const GTypeInfo core_info =
|
2001-02-27 13:21:12 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
sizeof (GimpPaintCoreClass),
|
2001-08-14 22:53:55 +08:00
|
|
|
(GBaseInitFunc) NULL,
|
|
|
|
(GBaseFinalizeFunc) NULL,
|
2002-02-15 03:31:16 +08:00
|
|
|
(GClassInitFunc) gimp_paint_core_class_init,
|
2001-08-14 22:53:55 +08:00
|
|
|
NULL, /* class_finalize */
|
|
|
|
NULL, /* class_data */
|
2002-02-15 03:31:16 +08:00
|
|
|
sizeof (GimpPaintCore),
|
2001-08-14 22:53:55 +08:00
|
|
|
0, /* n_preallocs */
|
2002-02-15 03:31:16 +08:00
|
|
|
(GInstanceInitFunc) gimp_paint_core_init,
|
2001-02-27 13:21:12 +08:00
|
|
|
};
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
core_type = g_type_register_static (GIMP_TYPE_OBJECT,
|
2003-07-14 22:50:41 +08:00
|
|
|
"GimpPaintCore",
|
2002-02-15 03:31:16 +08:00
|
|
|
&core_info, 0);
|
2001-02-27 13:21:12 +08:00
|
|
|
}
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
return core_type;
|
2001-02-27 13:21:12 +08:00
|
|
|
}
|
|
|
|
|
2001-02-28 03:18:01 +08:00
|
|
|
static void
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_class_init (GimpPaintCoreClass *klass)
|
2001-02-27 13:21:12 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
GObjectClass *object_class;
|
2001-02-28 03:18:01 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
object_class = G_OBJECT_CLASS (klass);
|
2001-02-28 03:18:01 +08:00
|
|
|
|
Port to glib/gtk+ 2.0 episode I (every segfault has it's beginning)
2001-07-24 Michael Natterer <mitch@gimp.org>
Port to glib/gtk+ 2.0 episode I (every segfault has it's beginning)
* configure.in: require glib/gtk+ >= 1.3.7, commented out the
gtkxmhtml stuff.
From now on, you will need glib, pango, atk and gtk+ HEAD from CVS
to hack or use GIMP HEAD.
Beware, it crashes randomly :)
* app/core/Makefile.am
* app/core/gimpmarshal.list: new file plus rules to generate
gimpmarshal.[ch] from it.
* app/core/*
* app/tools/*
* app/widgets/*
* libgimpwidgets/*: started to use the glib object system. All
core/ objects are still gtk objects however. All signals are
created using g_signal_new(). There are many gtk+ artefacts left.
Finally, we will _not_ use the gtk_signal_foo() wrappers and
friends any more.
* app/colormaps.c
* app/devices.[ch]
* app/disp_callbacks.c
* app/errorconsole.c
* app/file-save.[ch]
* app/interface.c
* app/module_db.c
* app/nav_window.c
* app/ops_buttons.c
* app/scroll.c
* app/user_install.c
* app/gui/about-dialog.c
* app/gui/brush-editor.c
* app/gui/brushes-commands.c
* app/gui/color-notebook.c
* app/gui/colormap-dialog.c
* app/gui/dialogs-commands.c
* app/gui/dialogs-constructors.c
* app/gui/file-commands.c
* app/gui/file-dialog-utils.c
* app/gui/file-new-dialog.c
* app/gui/file-open-dialog.[ch]
* app/gui/file-save-dialog.c
* app/gui/gradient-editor.c
* app/gui/gradients-commands.c
* app/gui/image-commands.c
* app/gui/info-dialog.[ch]
* app/gui/layer-select.c
* app/gui/layers-commands.c
* app/gui/menus.c
* app/gui/offset-dialog.c
* app/gui/palette-editor.c
* app/gui/palettes-commands.c
* app/gui/patterns-commands.c
* app/gui/preferences-dialog.c
* app/gui/resize-dialog.[ch]
* app/gui/splash.c
* app/gui/tips-dialog.c
* app/gui/tool-options-dialog.c
* app/gui/toolbox.c
* app/gui/tools-commands.c
* libgimp/gimpbrushmenu.c
* libgimp/gimpmenu.c
* libgimp/gimppatternmenu.c
* libgimp/gimpui.c
* libgimpbase/gimpenv.c: tons and tons of changes like "const
gchar*", switch from GdkDeviceInfo to GdkDevice (very incomplete
and currently disables), lots of s/gtk_signal/g_signal/,
removal/replacement of deprecated stuff,
s/GtkSignalFunc/GCallback/ and lots of small changes and fixes
while I was on it, zillions of warnings left...
* modules/Makefile.am: disabled the water color selector
temporarily (XInput issues).
* plug-ins/Makefile.am
* plug-ins/common/.cvsignore
* plug-ins/common/Makefile.am
* plug-ins/common/plugin-defs.pl: simply excluded all plug-ins
which did not build (including Script-Fu). They are trivial to
fix.
2001-07-25 05:27:11 +08:00
|
|
|
parent_class = g_type_class_peek_parent (klass);
|
2001-02-28 03:18:01 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
object_class->finalize = gimp_paint_core_finalize;
|
2001-02-28 03:18:01 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
klass->paint = NULL;
|
2001-02-27 13:21:12 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2001-02-28 03:18:01 +08:00
|
|
|
static void
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_init (GimpPaintCore *core)
|
2001-02-28 03:18:01 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
gint i, j;
|
2002-02-05 19:35:03 +08:00
|
|
|
|
2002-02-16 01:44:05 +08:00
|
|
|
core->ID = global_core_ID++;
|
2002-02-05 19:35:03 +08:00
|
|
|
|
2002-02-16 01:44:05 +08:00
|
|
|
core->distance = 0.0;
|
|
|
|
core->spacing = 0.0;
|
|
|
|
core->x1 = 0;
|
|
|
|
core->y1 = 0;
|
|
|
|
core->x2 = 0;
|
|
|
|
core->y2 = 0;
|
2002-02-05 19:35:03 +08:00
|
|
|
|
2002-02-16 01:44:05 +08:00
|
|
|
core->brush = NULL;
|
2002-02-13 22:50:37 +08:00
|
|
|
|
2002-02-16 01:44:05 +08:00
|
|
|
core->flags = 0;
|
2002-02-21 19:01:12 +08:00
|
|
|
core->use_pressure = FALSE;
|
2002-02-13 22:50:37 +08:00
|
|
|
|
2002-02-16 01:44:05 +08:00
|
|
|
core->undo_tiles = NULL;
|
|
|
|
core->canvas_tiles = NULL;
|
2002-02-13 22:50:37 +08:00
|
|
|
|
2002-02-16 01:44:05 +08:00
|
|
|
core->orig_buf = NULL;
|
|
|
|
core->canvas_buf = NULL;
|
2002-02-13 22:50:37 +08:00
|
|
|
|
2002-02-16 01:44:05 +08:00
|
|
|
core->pressure_brush = NULL;
|
|
|
|
|
2003-07-14 22:50:41 +08:00
|
|
|
for (i = 0; i < PAINT_CORE_SOLID_SUBSAMPLE; i++)
|
|
|
|
for (j = 0; j < PAINT_CORE_SOLID_SUBSAMPLE; j++)
|
|
|
|
core->solid_brushes[i][j] = NULL;
|
|
|
|
|
2002-02-16 01:44:05 +08:00
|
|
|
core->last_solid_brush = NULL;
|
2003-07-14 22:50:41 +08:00
|
|
|
core->solid_cache_invalid = FALSE;
|
2002-02-16 01:44:05 +08:00
|
|
|
|
|
|
|
core->scale_brush = NULL;
|
|
|
|
core->last_scale_brush = NULL;
|
|
|
|
core->last_scale_width = 0;
|
|
|
|
core->last_scale_height = 0;
|
|
|
|
|
|
|
|
core->scale_pixmap = NULL;
|
|
|
|
core->last_scale_pixmap = NULL;
|
|
|
|
core->last_scale_pixmap_width = 0;
|
|
|
|
core->last_scale_pixmap_height = 0;
|
2002-02-13 22:50:37 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
g_assert (PAINT_CORE_SUBSAMPLE == KERNEL_SUBSAMPLE);
|
2002-02-13 22:50:37 +08:00
|
|
|
|
|
|
|
for (i = 0; i < KERNEL_SUBSAMPLE + 1; i++)
|
|
|
|
for (j = 0; j < KERNEL_SUBSAMPLE + 1; j++)
|
2002-02-15 03:31:16 +08:00
|
|
|
core->kernel_brushes[i][j] = NULL;
|
2002-02-13 22:50:37 +08:00
|
|
|
|
2002-02-16 01:44:05 +08:00
|
|
|
core->last_brush_mask = NULL;
|
|
|
|
core->cache_invalid = FALSE;
|
2002-02-13 22:50:37 +08:00
|
|
|
|
2002-02-16 01:44:05 +08:00
|
|
|
core->grr_brush = NULL;
|
2003-07-25 00:35:25 +08:00
|
|
|
core->brush_bound_segs = NULL;
|
|
|
|
core->n_brush_bound_segs = 0;
|
2002-02-13 22:50:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_finalize (GObject *object)
|
2002-02-13 22:50:37 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
GimpPaintCore *core;
|
2002-02-13 22:50:37 +08:00
|
|
|
gint i, j;
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
core = GIMP_PAINT_CORE (object);
|
2002-02-13 22:50:37 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_cleanup (core);
|
2002-02-13 22:50:37 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
if (core->pressure_brush)
|
2002-02-13 22:50:37 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
temp_buf_free (core->pressure_brush);
|
|
|
|
core->pressure_brush = NULL;
|
2002-02-13 22:50:37 +08:00
|
|
|
}
|
|
|
|
|
2003-07-14 22:50:41 +08:00
|
|
|
for (i = 0; i < PAINT_CORE_SOLID_SUBSAMPLE; i++)
|
|
|
|
for (j = 0; j < PAINT_CORE_SOLID_SUBSAMPLE; j++)
|
|
|
|
if (core->solid_brushes[i][j])
|
|
|
|
{
|
|
|
|
temp_buf_free (core->solid_brushes[i][j]);
|
|
|
|
core->solid_brushes[i][j] = NULL;
|
|
|
|
}
|
2002-02-13 22:50:37 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
if (core->scale_brush)
|
2002-02-13 22:50:37 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
temp_buf_free (core->scale_brush);
|
|
|
|
core->scale_brush = NULL;
|
2002-02-13 22:50:37 +08:00
|
|
|
}
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
if (core->scale_pixmap)
|
2002-02-13 22:50:37 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
temp_buf_free (core->scale_pixmap);
|
|
|
|
core->scale_pixmap = NULL;
|
2002-02-13 22:50:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < KERNEL_SUBSAMPLE + 1; i++)
|
|
|
|
for (j = 0; j < KERNEL_SUBSAMPLE + 1; j++)
|
2002-02-15 03:31:16 +08:00
|
|
|
if (core->kernel_brushes[i][j])
|
2002-02-13 22:50:37 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
temp_buf_free (core->kernel_brushes[i][j]);
|
|
|
|
core->kernel_brushes[i][j] = NULL;
|
2002-02-13 22:50:37 +08:00
|
|
|
}
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
if (core->grr_brush)
|
2002-02-13 22:50:37 +08:00
|
|
|
{
|
2003-01-06 06:07:10 +08:00
|
|
|
g_signal_handlers_disconnect_by_func (core->grr_brush,
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_invalidate_cache,
|
|
|
|
core);
|
2003-01-06 06:07:10 +08:00
|
|
|
g_object_unref (core->grr_brush);
|
2002-02-15 03:31:16 +08:00
|
|
|
core->grr_brush = NULL;
|
2002-02-13 22:50:37 +08:00
|
|
|
}
|
|
|
|
|
2003-07-25 00:35:25 +08:00
|
|
|
if (core->brush_bound_segs)
|
|
|
|
{
|
|
|
|
g_free (core->brush_bound_segs);
|
|
|
|
core->brush_bound_segs = NULL;
|
|
|
|
core->n_brush_bound_segs = 0;
|
|
|
|
}
|
|
|
|
|
2002-02-13 22:50:37 +08:00
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
2001-02-28 03:18:01 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
void
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_paint (GimpPaintCore *core,
|
|
|
|
GimpDrawable *drawable,
|
2002-02-22 00:02:30 +08:00
|
|
|
GimpPaintOptions *paint_options,
|
2002-02-15 03:31:16 +08:00
|
|
|
GimpPaintCoreState paint_state)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
2003-03-04 02:43:11 +08:00
|
|
|
g_return_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options));
|
2002-02-15 03:31:16 +08:00
|
|
|
|
2002-02-21 19:01:12 +08:00
|
|
|
if (paint_state == MOTION_PAINT)
|
2002-02-16 01:44:05 +08:00
|
|
|
{
|
2002-02-21 19:01:12 +08:00
|
|
|
/* If we current point == last point, check if the brush
|
|
|
|
* wants to be painted in that case. (Direction dependent
|
|
|
|
* pixmap brush pipes don't, as they don't know which
|
|
|
|
* pixmap to select.)
|
|
|
|
*/
|
|
|
|
if (core->last_coords.x == core->cur_coords.x &&
|
|
|
|
core->last_coords.y == core->cur_coords.y &&
|
|
|
|
! gimp_brush_want_null_motion (core->brush,
|
|
|
|
&core->last_coords,
|
|
|
|
&core->cur_coords))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (core->flags & CORE_HANDLES_CHANGING_BRUSH)
|
|
|
|
{
|
|
|
|
core->brush = gimp_brush_select_brush (core->brush,
|
|
|
|
&core->last_coords,
|
|
|
|
&core->cur_coords);
|
|
|
|
}
|
2002-06-13 03:18:34 +08:00
|
|
|
|
|
|
|
/* Save coordinates for gimp_paint_core_interpolate() */
|
|
|
|
core->last_paint.x = core->cur_coords.x;
|
|
|
|
core->last_paint.y = core->cur_coords.y;
|
2002-02-16 01:44:05 +08:00
|
|
|
}
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
GIMP_PAINT_CORE_GET_CLASS (core)->paint (core,
|
|
|
|
drawable,
|
|
|
|
paint_options,
|
|
|
|
paint_state);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2000-03-05 08:06:11 +08:00
|
|
|
gboolean
|
2002-06-17 18:34:28 +08:00
|
|
|
gimp_paint_core_start (GimpPaintCore *core,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
GimpPaintOptions *paint_options,
|
|
|
|
GimpCoords *coords)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2003-05-08 21:12:46 +08:00
|
|
|
GimpItem *item;
|
2002-06-17 18:34:28 +08:00
|
|
|
GimpImage *gimage;
|
2001-07-07 20:17:23 +08:00
|
|
|
|
2002-02-15 03: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);
|
2003-03-04 02:43:11 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), FALSE);
|
2002-02-15 03:31:16 +08:00
|
|
|
g_return_val_if_fail (coords != NULL, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2003-05-08 21:12:46 +08:00
|
|
|
item = GIMP_ITEM (drawable);
|
|
|
|
gimage = gimp_item_get_image (item);
|
2002-02-26 01:58:50 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE);
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
core->cur_coords = *coords;
|
1998-06-06 11:49:01 +08:00
|
|
|
|
2002-02-13 22:50:37 +08:00
|
|
|
/* Each buffer is the same size as
|
|
|
|
* the maximum bounds of the active brush...
|
|
|
|
*/
|
|
|
|
|
2003-07-25 00:35:25 +08:00
|
|
|
if (core->grr_brush != gimp_context_get_brush (GIMP_CONTEXT (paint_options)))
|
1999-10-27 02:27:27 +08:00
|
|
|
{
|
2003-07-25 00:35:25 +08:00
|
|
|
if (core->grr_brush)
|
|
|
|
{
|
|
|
|
g_signal_handlers_disconnect_by_func (core->grr_brush,
|
|
|
|
gimp_paint_core_invalidate_cache,
|
|
|
|
core);
|
|
|
|
g_object_unref (core->grr_brush);
|
|
|
|
core->grr_brush = NULL;
|
|
|
|
}
|
2002-02-13 22:50:37 +08:00
|
|
|
|
2003-07-25 00:35:25 +08:00
|
|
|
if (core->brush_bound_segs)
|
|
|
|
{
|
|
|
|
g_free (core->brush_bound_segs);
|
|
|
|
core->brush_bound_segs = NULL;
|
|
|
|
core->n_brush_bound_segs = 0;
|
|
|
|
}
|
|
|
|
}
|
2002-02-13 22:50:37 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
if (! core->grr_brush)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2003-07-25 00:35:25 +08:00
|
|
|
core->grr_brush = gimp_context_get_brush (GIMP_CONTEXT (paint_options));
|
|
|
|
|
|
|
|
if (! core->grr_brush)
|
|
|
|
{
|
|
|
|
g_message (_("No brushes available for use with this tool."));
|
|
|
|
return FALSE;
|
|
|
|
}
|
2000-06-06 06:08:45 +08:00
|
|
|
|
2003-07-25 00:35:25 +08:00
|
|
|
g_object_ref (core->grr_brush);
|
|
|
|
g_signal_connect (core->grr_brush, "invalidate_preview",
|
|
|
|
G_CALLBACK (gimp_paint_core_invalidate_cache),
|
|
|
|
core);
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
core->spacing = (gdouble) gimp_brush_get_spacing (core->grr_brush) / 100.0;
|
1999-07-26 15:24:47 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
core->brush = core->grr_brush;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2002-02-07 19:33:01 +08:00
|
|
|
/* Allocate the undo structure */
|
2002-02-15 03:31:16 +08:00
|
|
|
if (core->undo_tiles)
|
2003-05-27 01:02:06 +08:00
|
|
|
tile_manager_unref (core->undo_tiles);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2003-05-08 21:12:46 +08:00
|
|
|
core->undo_tiles = tile_manager_new (gimp_item_width (item),
|
|
|
|
gimp_item_height (item),
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_drawable_bytes (drawable));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Allocate the canvas blocks structure */
|
2002-02-15 03:31:16 +08:00
|
|
|
if (core->canvas_tiles)
|
2003-05-27 01:02:06 +08:00
|
|
|
tile_manager_unref (core->canvas_tiles);
|
2002-02-07 19:33:01 +08:00
|
|
|
|
2003-05-08 21:12:46 +08:00
|
|
|
core->canvas_tiles = tile_manager_new (gimp_item_width (item),
|
|
|
|
gimp_item_height (item),
|
2002-02-15 03:31:16 +08:00
|
|
|
1);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Get the initial undo extents */
|
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
core->x1 = core->x2 = core->cur_coords.x;
|
|
|
|
core->y1 = core->y2 = core->cur_coords.y;
|
|
|
|
|
|
|
|
core->last_paint.x = -1e6;
|
|
|
|
core->last_paint.y = -1e6;
|
2003-07-10 20:13:21 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2002-02-16 01:44:05 +08:00
|
|
|
void
|
|
|
|
gimp_paint_core_finish (GimpPaintCore *core,
|
|
|
|
GimpDrawable *drawable)
|
|
|
|
{
|
2003-02-14 22:14:29 +08:00
|
|
|
GimpPaintInfo *paint_info;
|
|
|
|
GimpImage *gimage;
|
2002-02-16 01:44:05 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
|
|
|
|
2002-02-26 01:58:50 +08:00
|
|
|
gimage = gimp_item_get_image (GIMP_ITEM (drawable));
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
2002-02-16 01:44:05 +08:00
|
|
|
|
|
|
|
/* Determine if any part of the image has been altered--
|
|
|
|
* if nothing has, then just return...
|
|
|
|
*/
|
2003-02-14 22:14:29 +08:00
|
|
|
if ((core->x2 == core->x1) || (core->y2 == core->y1))
|
2002-02-16 01:44:05 +08:00
|
|
|
return;
|
|
|
|
|
2003-02-14 22:14:29 +08:00
|
|
|
paint_info = (GimpPaintInfo *)
|
|
|
|
gimp_container_get_child_by_name (gimage->gimp->paint_info_list,
|
|
|
|
g_type_name (G_TYPE_FROM_INSTANCE (core)));
|
|
|
|
|
2003-02-13 19:23:50 +08:00
|
|
|
gimp_image_undo_group_start (gimage, GIMP_UNDO_GROUP_PAINT,
|
2003-02-14 22:14:29 +08:00
|
|
|
paint_info ? paint_info->blurb : _("Paint"));
|
2002-02-16 01:44:05 +08:00
|
|
|
|
2003-02-14 22:14:29 +08:00
|
|
|
gimp_paint_core_push_undo (gimage, NULL, core);
|
2002-02-16 01:44:05 +08:00
|
|
|
|
2003-02-14 22:14:29 +08:00
|
|
|
gimp_drawable_push_undo (drawable, NULL,
|
2002-06-07 03:44:05 +08:00
|
|
|
core->x1, core->y1,
|
|
|
|
core->x2, core->y2,
|
|
|
|
core->undo_tiles,
|
|
|
|
TRUE);
|
2003-05-27 01:02:06 +08:00
|
|
|
|
|
|
|
tile_manager_unref (core->undo_tiles);
|
2002-02-16 01:44:05 +08:00
|
|
|
core->undo_tiles = NULL;
|
|
|
|
|
2003-02-13 19:23:50 +08:00
|
|
|
gimp_image_undo_group_end (gimage);
|
2002-02-16 01:44:05 +08:00
|
|
|
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
/* invalidate the previews -- have to do it here, because
|
2002-02-16 01:44:05 +08:00
|
|
|
* it is not done during the actual painting.
|
|
|
|
*/
|
|
|
|
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (drawable));
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage));
|
2002-02-16 01:44:05 +08:00
|
|
|
}
|
|
|
|
|
2003-09-17 20:05:11 +08:00
|
|
|
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);
|
|
|
|
|
|
|
|
if (tile_is_valid (src_tile) == TRUE)
|
|
|
|
{
|
|
|
|
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,
|
|
|
|
GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
GimpImage *gimage;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
|
|
|
|
|
|
|
gimage = gimp_item_get_image (GIMP_ITEM (drawable));
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (gimage));
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
gimp_paint_core_copy_valid_tiles (core->undo_tiles,
|
|
|
|
gimp_drawable_data (drawable),
|
|
|
|
core->x1, core->y1,
|
|
|
|
core->x2 - core->x1,
|
|
|
|
core->y2 - core->y1);
|
|
|
|
|
|
|
|
tile_manager_unref (core->undo_tiles);
|
|
|
|
core->undo_tiles = NULL;
|
|
|
|
|
|
|
|
gimp_drawable_update (drawable,
|
|
|
|
core->x1, core->y1,
|
|
|
|
core->x2 - core->x1, core->y2 - core->y1);
|
|
|
|
}
|
|
|
|
|
2002-02-16 01:44:05 +08:00
|
|
|
void
|
|
|
|
gimp_paint_core_cleanup (GimpPaintCore *core)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
|
|
|
|
|
|
|
|
if (core->undo_tiles)
|
|
|
|
{
|
2003-05-27 01:02:06 +08:00
|
|
|
tile_manager_unref (core->undo_tiles);
|
2002-02-16 01:44:05 +08:00
|
|
|
core->undo_tiles = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (core->canvas_tiles)
|
|
|
|
{
|
2003-05-27 01:02:06 +08:00
|
|
|
tile_manager_unref (core->canvas_tiles);
|
2002-02-16 01:44:05 +08:00
|
|
|
core->canvas_tiles = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (core->orig_buf)
|
|
|
|
{
|
|
|
|
temp_buf_free (core->orig_buf);
|
|
|
|
core->orig_buf = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (core->canvas_buf)
|
|
|
|
{
|
|
|
|
temp_buf_free (core->canvas_buf);
|
|
|
|
core->canvas_buf = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-23 21:22:38 +08:00
|
|
|
/**
|
|
|
|
* gimp_paint_core_constrain_helper:
|
|
|
|
* @dx: the (fixed) delta-x
|
|
|
|
* @dy: a suggested delta-y
|
2003-07-10 20:13:21 +08:00
|
|
|
*
|
2003-05-23 21:22:38 +08:00
|
|
|
* Returns an adjusted dy' near dy such that the slope (dx,dy') is a
|
|
|
|
* multiple of 15 degrees.
|
|
|
|
**/
|
|
|
|
static gdouble
|
|
|
|
gimp_paint_core_constrain_helper (gdouble dx,
|
|
|
|
gdouble dy)
|
|
|
|
{
|
|
|
|
static gdouble slope[4] = { 0, 0.26795, 0.57735, 1 };
|
|
|
|
static gdouble divider[3] = { 0.13165, 0.41421, 0.76732 };
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
if (dy < 0)
|
|
|
|
return - gimp_paint_core_constrain_helper (dx,-dy);
|
|
|
|
dx = fabs (dx);
|
|
|
|
for (i = 0; i < 3; i ++)
|
|
|
|
if (dy < dx * divider[i])
|
|
|
|
break;
|
|
|
|
dy = dx * slope[i];
|
|
|
|
return dy;
|
|
|
|
}
|
|
|
|
|
2002-02-16 01:44:05 +08:00
|
|
|
/**
|
|
|
|
* gimp_paint_core_constrain:
|
|
|
|
* @core: the #GimpPaintCore.
|
2003-05-23 21:22:38 +08:00
|
|
|
*
|
|
|
|
* Restricts the (core->last_coords, core->cur_coords) vector to 15
|
|
|
|
* degree steps, possibly changing core->cur_coords.
|
2002-02-16 01:44:05 +08:00
|
|
|
**/
|
|
|
|
void
|
|
|
|
gimp_paint_core_constrain (GimpPaintCore *core)
|
|
|
|
{
|
2003-05-23 21:22:38 +08:00
|
|
|
gdouble dx, dy;
|
2002-02-16 01:44:05 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
|
|
|
|
|
|
|
|
dx = core->cur_coords.x - core->last_coords.x;
|
|
|
|
dy = core->cur_coords.y - core->last_coords.y;
|
|
|
|
|
2003-05-23 21:22:38 +08:00
|
|
|
/* This algorithm changes only one of dx and dy, and does not try
|
|
|
|
* to constrain the resulting dx and dy to integers. This gives
|
|
|
|
* at least two benefits:
|
|
|
|
* 1. gimp_paint_core_constrain is idempotent, even if followed by
|
|
|
|
* a rounding operation.
|
|
|
|
* 2. For any two lines with the same starting-point and ideal
|
|
|
|
* 15-degree direction, the points plotted by
|
|
|
|
* gimp_paint_core_interpolate for the shorter line will always
|
|
|
|
* be a superset of those plotted for the longer line.
|
|
|
|
*/
|
|
|
|
if (fabs(dx) > fabs(dy))
|
|
|
|
core->cur_coords.y = core->last_coords.y +
|
|
|
|
gimp_paint_core_constrain_helper (dx,dy);
|
|
|
|
else
|
|
|
|
core->cur_coords.x = core->last_coords.x +
|
|
|
|
gimp_paint_core_constrain_helper (dy,dx);
|
2002-02-16 01:44:05 +08:00
|
|
|
}
|
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
/**
|
|
|
|
* gimp_avoid_exact_integer
|
|
|
|
* @x: points to a gdouble
|
|
|
|
*
|
|
|
|
* Adjusts *x such that it is not too close to an integer. This is used
|
|
|
|
* for decision algorithms that would be vulnerable to rounding glitches
|
|
|
|
* if exact integers were input.
|
|
|
|
*
|
|
|
|
* Side effects: Changes the value of *x
|
|
|
|
**/
|
|
|
|
static void
|
|
|
|
gimp_avoid_exact_integer (gdouble *x)
|
|
|
|
{
|
|
|
|
gdouble integral = floor (*x);
|
|
|
|
gdouble fractional = *x - integral;
|
|
|
|
|
|
|
|
if (fractional < EPSILON)
|
|
|
|
*x = integral + EPSILON;
|
|
|
|
else if (fractional > (1-EPSILON))
|
|
|
|
*x = integral + (1-EPSILON);
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
2002-02-22 00:02:30 +08:00
|
|
|
gimp_paint_core_interpolate (GimpPaintCore *core,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
GimpPaintOptions *paint_options)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
GimpCoords delta;
|
2002-06-13 03:18:34 +08:00
|
|
|
gint n, num_points;
|
|
|
|
gdouble t0, dt, tn;
|
|
|
|
gdouble st_factor, st_offset;
|
2002-02-15 03:31:16 +08:00
|
|
|
gdouble initial;
|
|
|
|
gdouble dist;
|
|
|
|
gdouble total;
|
|
|
|
gdouble pixel_dist;
|
|
|
|
gdouble pixel_initial;
|
|
|
|
gdouble xd, yd;
|
|
|
|
gdouble mag;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_PAINT_CORE (core));
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
2003-03-04 02:43:11 +08:00
|
|
|
g_return_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options));
|
2002-02-15 03:31:16 +08:00
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
gimp_avoid_exact_integer (&core->last_coords.x);
|
|
|
|
gimp_avoid_exact_integer (&core->last_coords.y);
|
|
|
|
gimp_avoid_exact_integer (&core->cur_coords.x);
|
|
|
|
gimp_avoid_exact_integer (&core->cur_coords.y);
|
2003-07-10 20:13:21 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
delta.x = core->cur_coords.x - core->last_coords.x;
|
|
|
|
delta.y = core->cur_coords.y - core->last_coords.y;
|
|
|
|
delta.pressure = core->cur_coords.pressure - core->last_coords.pressure;
|
|
|
|
delta.xtilt = core->cur_coords.xtilt - core->last_coords.xtilt;
|
|
|
|
delta.ytilt = core->cur_coords.ytilt - core->last_coords.ytilt;
|
|
|
|
delta.wheel = core->cur_coords.wheel - core->last_coords.wheel;
|
2001-03-31 00:39:14 +08:00
|
|
|
|
2002-02-16 01:44:05 +08:00
|
|
|
/* return if there has been no motion */
|
|
|
|
if (! delta.x &&
|
|
|
|
! delta.y &&
|
2001-11-14 00:21:34 +08:00
|
|
|
! delta.pressure &&
|
2002-02-16 01:44:05 +08:00
|
|
|
! delta.xtilt &&
|
|
|
|
! delta.ytilt &&
|
2001-11-14 00:21:34 +08:00
|
|
|
! delta.wheel)
|
1997-11-25 06:05:25 +08:00
|
|
|
return;
|
1999-07-23 07:11:46 +08:00
|
|
|
|
2000-12-31 12:07:42 +08:00
|
|
|
/* calculate the distance traveled in the coordinate space of the brush */
|
2002-02-15 03:31:16 +08:00
|
|
|
mag = gimp_vector2_length (&(core->brush->x_axis));
|
2001-11-14 00:21:34 +08:00
|
|
|
xd = gimp_vector2_inner_product ((GimpVector2 *) &delta,
|
2002-02-15 03:31:16 +08:00
|
|
|
&(core->brush->x_axis)) / (mag * mag);
|
1998-07-24 16:56:18 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
mag = gimp_vector2_length (&(core->brush->y_axis));
|
2001-11-14 00:21:34 +08:00
|
|
|
yd = gimp_vector2_inner_product ((GimpVector2 *) &delta,
|
2002-02-15 03:31:16 +08:00
|
|
|
&(core->brush->y_axis)) / (mag * mag);
|
1998-07-24 16:56:18 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
dist = 0.5 * sqrt (xd * xd + yd * yd);
|
|
|
|
total = dist + core->distance;
|
|
|
|
initial = core->distance;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2001-11-14 00:21:34 +08:00
|
|
|
pixel_dist = gimp_vector2_length ((GimpVector2 *) &delta);
|
2002-02-15 03:31:16 +08:00
|
|
|
pixel_initial = core->pixel_dist;
|
1999-09-26 03:49:58 +08:00
|
|
|
|
|
|
|
/* FIXME: need to adapt the spacing to the size */
|
2001-02-27 13:21:12 +08:00
|
|
|
/* lastscale = MIN (gimp_paint_tool->lastpressure, 1/256); */
|
|
|
|
/* curscale = MIN (gimp_paint_tool->curpressure, 1/256); */
|
|
|
|
/* spacing = gimp_paint_tool->spacing * sqrt (0.5 * (lastscale + curscale)); */
|
1999-09-09 09:47:54 +08:00
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
/* Compute spacing parameters such that a brush position will be
|
|
|
|
* made each time the line crosses the *center* of a pixel row or
|
|
|
|
* column, according to whether the line is mostly horizontal or
|
|
|
|
* mostly vertical. The term "stripe" will mean "column" if the
|
|
|
|
* line is horizontalish; "row" if the line is verticalish.
|
|
|
|
*
|
|
|
|
* We start by deriving coefficients for a new parameter 's':
|
|
|
|
* s = t * st_factor + st_offset
|
|
|
|
* such that the "nice" brush positions are the ones with *integer*
|
|
|
|
* s values. (Actually the value of s will be 1/2 less than the nice
|
|
|
|
* brush position's x or y coordinate - note that st_factor may
|
|
|
|
* be negative!)
|
|
|
|
*/
|
2003-07-10 20:13:21 +08:00
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
if (delta.x*delta.x > delta.y*delta.y)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2002-06-13 03:18:34 +08:00
|
|
|
st_factor = delta.x;
|
|
|
|
st_offset = core->last_coords.x - 0.5;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
st_factor = delta.y;
|
|
|
|
st_offset = core->last_coords.y - 0.5;
|
|
|
|
}
|
2003-07-10 20:13:21 +08:00
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
if (fabs (st_factor) > dist / core->spacing)
|
|
|
|
{
|
|
|
|
/* The stripe principle leads to brush positions that are spaced
|
|
|
|
* *closer* than the official brush spacing. Use the official
|
|
|
|
* spacing instead. This is the common case when the brush spacing
|
|
|
|
* is large.
|
|
|
|
* The net effect is then to put a lower bound on the spacing, but
|
|
|
|
* one that varies with the slope of the line. This is suppose to
|
|
|
|
* make thin lines (say, with a 1x1 brush) prettier while leaving
|
|
|
|
* lines with larger brush spacing as they used to look in 1.2.x.
|
|
|
|
*/
|
2003-08-21 18:44:11 +08:00
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
dt = core->spacing / dist;
|
|
|
|
n = (gint) (initial / core->spacing + 1.0 + EPSILON);
|
|
|
|
t0 = (n * core->spacing - initial) / dist;
|
|
|
|
num_points = 1 + (gint) floor ((1 + EPSILON - t0) / dt);
|
2003-08-21 18:44:11 +08:00
|
|
|
|
|
|
|
/* if we arnt going to paint anything this time and the brush
|
|
|
|
* has only moved on one axis return without updating the brush
|
|
|
|
* position, distance etc. so that we can more accurately space
|
|
|
|
* brush strokes when curves are supplied to us in single pixel
|
|
|
|
* chunks.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (num_points == 0 && (delta.x == 0 || delta.y == 0))
|
|
|
|
return;
|
2002-06-13 03:18:34 +08:00
|
|
|
}
|
|
|
|
else if (fabs (st_factor) < EPSILON)
|
|
|
|
{
|
|
|
|
/* Hm, we've hardly moved at all. Don't draw anything, but reset the
|
|
|
|
* old coordinates and hope we've gone longer the next time.
|
|
|
|
*/
|
|
|
|
core->cur_coords.x = core->last_coords.x;
|
|
|
|
core->cur_coords.y = core->last_coords.y;
|
|
|
|
/* ... but go along with the current pressure, tilt and wheel */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gint direction = st_factor > 0 ? 1 : -1;
|
|
|
|
gint x, y;
|
|
|
|
gint s0, sn;
|
|
|
|
|
|
|
|
/* Choose the first and last stripe to paint.
|
|
|
|
* FIRST PRIORITY is to avoid gaps painting with a 1x1 aliasing
|
|
|
|
* brush when a horizontalish line segment follows a verticalish
|
|
|
|
* one or vice versa - no matter what the angle between the two
|
|
|
|
* lines is. This will also limit the local thinning that a 1x1
|
|
|
|
* subsampled brush may suffer in the same situation.
|
|
|
|
* SECOND PRIORITY is to avoid making free-hand drawings
|
|
|
|
* unpleasantly fat by plotting redundant points.
|
|
|
|
* These are achieved by the following rules, but it is a little
|
|
|
|
* tricky to see just why. Do not change this algorithm unless you
|
|
|
|
* are sure you know what you're doing!
|
|
|
|
*/
|
2003-07-10 20:13:21 +08:00
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
/* Basic case: round the beginning and ending point to nearest
|
|
|
|
* stripe center.
|
|
|
|
*/
|
|
|
|
s0 = (gint) floor (st_offset + 0.5);
|
|
|
|
sn = (gint) floor (st_offset + st_factor + 0.5);
|
|
|
|
|
|
|
|
t0 = (s0 - st_offset) / st_factor;
|
|
|
|
tn = (sn - st_offset) / st_factor;
|
2003-07-10 20:13:21 +08:00
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
x = (gint) floor (core->last_coords.x + t0 * delta.x);
|
|
|
|
y = (gint) floor (core->last_coords.y + t0 * delta.y);
|
|
|
|
if (t0 < 0.0 && !( x == (gint) floor (core->last_coords.x) &&
|
|
|
|
y == (gint) floor (core->last_coords.y) ))
|
|
|
|
{
|
|
|
|
/* Exception A: If the first stripe's brush position is
|
|
|
|
* EXTRApolated into a different pixel square than the
|
|
|
|
* ideal starting point, dont't plot it.
|
|
|
|
*/
|
|
|
|
s0 += direction;
|
|
|
|
}
|
|
|
|
else if (x == (gint) floor (core->last_paint.x) &&
|
|
|
|
y == (gint) floor (core->last_paint.y))
|
|
|
|
{
|
|
|
|
/* Exception B: If first stripe's brush position is within the
|
|
|
|
* same pixel square as the last plot of the previous line,
|
|
|
|
* don't plot it either.
|
|
|
|
*/
|
|
|
|
s0 += direction;
|
|
|
|
}
|
2000-12-31 12:07:42 +08:00
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
x = (gint) floor (core->last_coords.x + tn * delta.x);
|
|
|
|
y = (gint) floor (core->last_coords.y + tn * delta.y);
|
|
|
|
if (tn > 1.0 && !( x == (gint) floor( core->cur_coords.x ) &&
|
|
|
|
y == (gint) floor( core->cur_coords.y ) ))
|
|
|
|
{
|
|
|
|
/* Exception C: If the last stripe's brush position is
|
|
|
|
* EXTRApolated into a different pixel square than the
|
|
|
|
* ideal ending point, don't plot it.
|
|
|
|
*/
|
|
|
|
sn -= direction;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
t0 = (s0 - st_offset) / st_factor;
|
|
|
|
tn = (sn - st_offset) / st_factor;
|
|
|
|
dt = direction * 1.0 / st_factor;
|
|
|
|
num_points = 1 + direction * (sn - s0);
|
2002-02-15 03:31:16 +08:00
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
if (num_points >= 1)
|
|
|
|
{
|
|
|
|
/* Hack the reported total distance such that it looks to the
|
|
|
|
* next line as if the the last pixel plotted were at an integer
|
|
|
|
* multiple of the brush spacing. This helps prevent artifacts
|
|
|
|
* for connected lines when the brush spacing is such that some
|
|
|
|
* slopes will use the stripe regime and other slopes will use
|
|
|
|
* the nominal brush spacing.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (tn < 1)
|
|
|
|
total = initial + tn * dist;
|
|
|
|
|
|
|
|
total = core->spacing * (gint) (total / core->spacing + 0.5);
|
|
|
|
total += (1.0 - tn) * dist;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (n = 0; n < num_points; n++)
|
|
|
|
{
|
|
|
|
GimpBrush *current_brush;
|
|
|
|
gdouble t = t0 + n*dt;
|
2002-02-15 03:31:16 +08:00
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
core->cur_coords.x = core->last_coords.x + t * delta.x;
|
|
|
|
core->cur_coords.y = core->last_coords.y + t * delta.y;
|
|
|
|
core->cur_coords.pressure = core->last_coords.pressure + t * delta.pressure;
|
|
|
|
core->cur_coords.xtilt = core->last_coords.xtilt + t * delta.xtilt;
|
|
|
|
core->cur_coords.ytilt = core->last_coords.ytilt + t * delta.ytilt;
|
|
|
|
core->cur_coords.wheel = core->last_coords.wheel + t * delta.wheel;
|
2002-02-16 01:44:05 +08:00
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
core->distance = initial + t * dist;
|
|
|
|
core->pixel_dist = pixel_initial + t * pixel_dist;
|
Jens Lautenbacher <jtl@gimp.org>
2000-12-18 Sven Neumann <sven@gimp.org>
Jens Lautenbacher <jtl@gimp.org>
* app/Makefile.am
* app/gimpbrushlistP.h
* app/gimpbrushpipeP.h
* app/gimpobjectP.h: removed these three files
* app/parasitelistP.h
* app/channels_dialog.c
* app/docindex.c
* app/gimpdrawable.c
* app/gimpdrawableP.h
* app/gimpimage.c
* app/gimpimageP.h
* app/gimplist.[ch]
* app/gimpobject.c
* app/gimpobject.h
* app/gimpsetP.h: changed according to header removal
* app/airbrush.c
* app/brush_select.[ch]
* app/brushes_cmds.c
* app/gimpbrush.[ch]
* app/gimpbrushgenerated.[ch]
* app/gimpbrushlist.[ch]
* app/gimpbrushpipe.[ch]
* app/gimpcontextpreview.c
* app/paint_core.c
* app/paintbrush.c
* app/pencil.c
* tools/pdbgen/pdb/brushes.pdb: Big Brushes Cleanup.
The GimpBrush* object hierarchy and the file formats were broken by
"design". This made it overly difficult to read and write pixmap
brushes and brush pipes, leading to the situation that The GIMP was
not able to read it's very own file formats. Since the GimpBrush
format did support arbitrary color depths, the introduction of a
file format for pixmap brushes was unnecessary.
The GimpBrushPixmap object is dead. GimpBrush has an additional
pixmap temp_buf and handles pixmap brushes transparently. The file
format of pixmap brushes is not any longer a grayscale brush plus
a pattern, but a simple brush with RGBA data. The old brushes can
still be loaded, but the .gpb format is deprecated.
GimpBrushPipe derives from GimpBrush. The fileformat is still a text
header, followed by a number of brushes, but those brushes are stored
in the new GimpBrush format (no pattern anymore). The pipe does not
care about the depth of the contained GimpBrushes, so we get
grayscale BrushPipes for free. Since the brush loader still loads the
old format, old .gih files can also still be loaded.
Since the brushes in the GimpBrushPipe do not any longer contain a
pointer to the pipe object, we do only temporarily switch brushes
in the paint_core routines. This is not very elegant, but the best
we can do without a major redesign.
* app/patterns.[ch]: changed the loader to work with a filedescriptor
instead of a filehandle to make it work with the new brush loading
code.
* plug-ins/common/.cvsignore
* plug-ins/common/Makefile.am
* plug-ins/common/plugin-defs.pl
* plug-ins/common/gih.c: new plug-in that saves GIH files in the
new format (loader will follow soon)
* plug-ins/common/gpb.c: removed since Pixmap Brushes are no longer
supported as a special file format.
* plug-ins/common/gbr.c: load and save brushes in the new brush format
which allows RGBA brushes too.
* plug-ins/common/pat.c: load and save grayscale patterns too
2000-12-18 23:14:08 +08:00
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
/* save the current brush */
|
|
|
|
current_brush = core->brush;
|
Jens Lautenbacher <jtl@gimp.org>
2000-12-18 Sven Neumann <sven@gimp.org>
Jens Lautenbacher <jtl@gimp.org>
* app/Makefile.am
* app/gimpbrushlistP.h
* app/gimpbrushpipeP.h
* app/gimpobjectP.h: removed these three files
* app/parasitelistP.h
* app/channels_dialog.c
* app/docindex.c
* app/gimpdrawable.c
* app/gimpdrawableP.h
* app/gimpimage.c
* app/gimpimageP.h
* app/gimplist.[ch]
* app/gimpobject.c
* app/gimpobject.h
* app/gimpsetP.h: changed according to header removal
* app/airbrush.c
* app/brush_select.[ch]
* app/brushes_cmds.c
* app/gimpbrush.[ch]
* app/gimpbrushgenerated.[ch]
* app/gimpbrushlist.[ch]
* app/gimpbrushpipe.[ch]
* app/gimpcontextpreview.c
* app/paint_core.c
* app/paintbrush.c
* app/pencil.c
* tools/pdbgen/pdb/brushes.pdb: Big Brushes Cleanup.
The GimpBrush* object hierarchy and the file formats were broken by
"design". This made it overly difficult to read and write pixmap
brushes and brush pipes, leading to the situation that The GIMP was
not able to read it's very own file formats. Since the GimpBrush
format did support arbitrary color depths, the introduction of a
file format for pixmap brushes was unnecessary.
The GimpBrushPixmap object is dead. GimpBrush has an additional
pixmap temp_buf and handles pixmap brushes transparently. The file
format of pixmap brushes is not any longer a grayscale brush plus
a pattern, but a simple brush with RGBA data. The old brushes can
still be loaded, but the .gpb format is deprecated.
GimpBrushPipe derives from GimpBrush. The fileformat is still a text
header, followed by a number of brushes, but those brushes are stored
in the new GimpBrush format (no pattern anymore). The pipe does not
care about the depth of the contained GimpBrushes, so we get
grayscale BrushPipes for free. Since the brush loader still loads the
old format, old .gih files can also still be loaded.
Since the brushes in the GimpBrushPipe do not any longer contain a
pointer to the pipe object, we do only temporarily switch brushes
in the paint_core routines. This is not very elegant, but the best
we can do without a major redesign.
* app/patterns.[ch]: changed the loader to work with a filedescriptor
instead of a filehandle to make it work with the new brush loading
code.
* plug-ins/common/.cvsignore
* plug-ins/common/Makefile.am
* plug-ins/common/plugin-defs.pl
* plug-ins/common/gih.c: new plug-in that saves GIH files in the
new format (loader will follow soon)
* plug-ins/common/gpb.c: removed since Pixmap Brushes are no longer
supported as a special file format.
* plug-ins/common/gbr.c: load and save brushes in the new brush format
which allows RGBA brushes too.
* plug-ins/common/pat.c: load and save grayscale patterns too
2000-12-18 23:14:08 +08:00
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
gimp_paint_core_paint (core, drawable, paint_options, MOTION_PAINT);
|
Jens Lautenbacher <jtl@gimp.org>
2000-12-18 Sven Neumann <sven@gimp.org>
Jens Lautenbacher <jtl@gimp.org>
* app/Makefile.am
* app/gimpbrushlistP.h
* app/gimpbrushpipeP.h
* app/gimpobjectP.h: removed these three files
* app/parasitelistP.h
* app/channels_dialog.c
* app/docindex.c
* app/gimpdrawable.c
* app/gimpdrawableP.h
* app/gimpimage.c
* app/gimpimageP.h
* app/gimplist.[ch]
* app/gimpobject.c
* app/gimpobject.h
* app/gimpsetP.h: changed according to header removal
* app/airbrush.c
* app/brush_select.[ch]
* app/brushes_cmds.c
* app/gimpbrush.[ch]
* app/gimpbrushgenerated.[ch]
* app/gimpbrushlist.[ch]
* app/gimpbrushpipe.[ch]
* app/gimpcontextpreview.c
* app/paint_core.c
* app/paintbrush.c
* app/pencil.c
* tools/pdbgen/pdb/brushes.pdb: Big Brushes Cleanup.
The GimpBrush* object hierarchy and the file formats were broken by
"design". This made it overly difficult to read and write pixmap
brushes and brush pipes, leading to the situation that The GIMP was
not able to read it's very own file formats. Since the GimpBrush
format did support arbitrary color depths, the introduction of a
file format for pixmap brushes was unnecessary.
The GimpBrushPixmap object is dead. GimpBrush has an additional
pixmap temp_buf and handles pixmap brushes transparently. The file
format of pixmap brushes is not any longer a grayscale brush plus
a pattern, but a simple brush with RGBA data. The old brushes can
still be loaded, but the .gpb format is deprecated.
GimpBrushPipe derives from GimpBrush. The fileformat is still a text
header, followed by a number of brushes, but those brushes are stored
in the new GimpBrush format (no pattern anymore). The pipe does not
care about the depth of the contained GimpBrushes, so we get
grayscale BrushPipes for free. Since the brush loader still loads the
old format, old .gih files can also still be loaded.
Since the brushes in the GimpBrushPipe do not any longer contain a
pointer to the pipe object, we do only temporarily switch brushes
in the paint_core routines. This is not very elegant, but the best
we can do without a major redesign.
* app/patterns.[ch]: changed the loader to work with a filedescriptor
instead of a filehandle to make it work with the new brush loading
code.
* plug-ins/common/.cvsignore
* plug-ins/common/Makefile.am
* plug-ins/common/plugin-defs.pl
* plug-ins/common/gih.c: new plug-in that saves GIH files in the
new format (loader will follow soon)
* plug-ins/common/gpb.c: removed since Pixmap Brushes are no longer
supported as a special file format.
* plug-ins/common/gbr.c: load and save brushes in the new brush format
which allows RGBA brushes too.
* plug-ins/common/pat.c: load and save grayscale patterns too
2000-12-18 23:14:08 +08:00
|
|
|
|
2002-06-13 03:18:34 +08:00
|
|
|
/* restore the current brush pointer */
|
|
|
|
core->brush = current_brush;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
2000-12-31 12:07:42 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
core->cur_coords.x = core->last_coords.x + delta.x;
|
|
|
|
core->cur_coords.y = core->last_coords.y + delta.y;
|
|
|
|
core->cur_coords.pressure = core->last_coords.pressure + delta.pressure;
|
|
|
|
core->cur_coords.xtilt = core->last_coords.xtilt + delta.xtilt;
|
|
|
|
core->cur_coords.ytilt = core->last_coords.ytilt + delta.ytilt;
|
|
|
|
core->cur_coords.wheel = core->last_coords.wheel + delta.wheel;
|
|
|
|
|
|
|
|
core->distance = total;
|
|
|
|
core->pixel_dist = pixel_initial + pixel_dist;
|
2003-08-21 18:44:11 +08:00
|
|
|
|
|
|
|
core->last_coords = core->cur_coords;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1998-06-06 11:49:01 +08:00
|
|
|
|
2002-02-16 01:44:05 +08:00
|
|
|
/* protected functions */
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
TempBuf *
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_get_paint_area (GimpPaintCore *core,
|
2001-02-28 03:18:01 +08:00
|
|
|
GimpDrawable *drawable,
|
|
|
|
gdouble scale)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-03-05 08:06:11 +08:00
|
|
|
gint x, y;
|
|
|
|
gint x1, y1, x2, y2;
|
|
|
|
gint bytes;
|
|
|
|
gint dwidth, dheight;
|
|
|
|
gint bwidth, bheight;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
bytes = (gimp_drawable_has_alpha (drawable) ?
|
|
|
|
gimp_drawable_bytes (drawable) : gimp_drawable_bytes (drawable) + 1);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2002-02-21 19:01:12 +08:00
|
|
|
gimp_paint_core_calc_brush_size (core,
|
|
|
|
core->brush->mask,
|
2002-02-15 03:31:16 +08:00
|
|
|
scale,
|
|
|
|
&bwidth, &bheight);
|
1999-09-09 09:47:54 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
/* adjust the x and y coordinates to the upper left corner of the brush */
|
2002-02-15 03:31:16 +08:00
|
|
|
x = (gint) floor (core->cur_coords.x) - (bwidth >> 1);
|
|
|
|
y = (gint) floor (core->cur_coords.y) - (bheight >> 1);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2003-05-08 21:12:46 +08:00
|
|
|
dwidth = gimp_item_width (GIMP_ITEM (drawable));
|
|
|
|
dheight = gimp_item_height (GIMP_ITEM (drawable));
|
1998-07-25 02:52:03 +08:00
|
|
|
|
2000-01-26 07:06:12 +08:00
|
|
|
x1 = CLAMP (x - 1, 0, dwidth);
|
|
|
|
y1 = CLAMP (y - 1, 0, dheight);
|
|
|
|
x2 = CLAMP (x + bwidth + 1, 0, dwidth);
|
|
|
|
y2 = CLAMP (y + bheight + 1, 0, dheight);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* configure the canvas buffer */
|
|
|
|
if ((x2 - x1) && (y2 - y1))
|
2002-02-15 03:31:16 +08:00
|
|
|
core->canvas_buf = temp_buf_resize (core->canvas_buf, bytes,
|
|
|
|
x1, y1,
|
|
|
|
(x2 - x1), (y2 - y1));
|
1997-11-25 06:05:25 +08:00
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
return core->canvas_buf;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TempBuf *
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_get_orig_image (GimpPaintCore *core,
|
2001-02-28 03:18:01 +08:00
|
|
|
GimpDrawable *drawable,
|
|
|
|
gint x1,
|
|
|
|
gint y1,
|
|
|
|
gint x2,
|
|
|
|
gint y2)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-06-06 06:08:45 +08:00
|
|
|
PixelRegion srcPR;
|
|
|
|
PixelRegion destPR;
|
|
|
|
Tile *undo_tile;
|
|
|
|
gint h;
|
|
|
|
gint refd;
|
|
|
|
gint pixelwidth;
|
|
|
|
gint dwidth;
|
|
|
|
gint dheight;
|
|
|
|
guchar *s;
|
|
|
|
guchar *d;
|
|
|
|
gpointer pr;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
core->orig_buf = temp_buf_resize (core->orig_buf,
|
|
|
|
gimp_drawable_bytes (drawable),
|
|
|
|
x1, y1,
|
|
|
|
(x2 - x1), (y2 - y1));
|
1998-07-25 02:52:03 +08:00
|
|
|
|
2003-05-08 21:12:46 +08:00
|
|
|
dwidth = gimp_item_width (GIMP_ITEM (drawable));
|
|
|
|
dheight = gimp_item_height (GIMP_ITEM (drawable));
|
1998-07-25 02:52:03 +08:00
|
|
|
|
2000-01-26 07:06:12 +08:00
|
|
|
x1 = CLAMP (x1, 0, dwidth);
|
|
|
|
y1 = CLAMP (y1, 0, dheight);
|
|
|
|
x2 = CLAMP (x2, 0, dwidth);
|
|
|
|
y2 = CLAMP (y2, 0, dheight);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* configure the pixel regions */
|
2002-02-13 22:50:37 +08:00
|
|
|
pixel_region_init (&srcPR, gimp_drawable_data (drawable),
|
|
|
|
x1, y1,
|
|
|
|
(x2 - x1), (y2 - y1),
|
|
|
|
FALSE);
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
destPR.bytes = core->orig_buf->bytes;
|
2002-02-13 22:50:37 +08:00
|
|
|
destPR.x = 0;
|
|
|
|
destPR.y = 0;
|
|
|
|
destPR.w = (x2 - x1);
|
|
|
|
destPR.h = (y2 - y1);
|
2002-02-15 03:31:16 +08:00
|
|
|
destPR.rowstride = core->orig_buf->bytes * core->orig_buf->width;
|
|
|
|
destPR.data = (temp_buf_data (core->orig_buf) +
|
|
|
|
(y1 - core->orig_buf->y) * destPR.rowstride +
|
|
|
|
(x1 - core->orig_buf->x) * destPR.bytes);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-07-25 02:52:03 +08:00
|
|
|
for (pr = pixel_regions_register (2, &srcPR, &destPR);
|
|
|
|
pr != NULL;
|
|
|
|
pr = pixel_regions_process (pr))
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
/* If the undo tile corresponding to this location is valid, use it */
|
2002-02-15 03:31:16 +08:00
|
|
|
undo_tile = tile_manager_get_tile (core->undo_tiles,
|
2002-02-13 22:50:37 +08:00
|
|
|
srcPR.x, srcPR.y,
|
1998-08-16 03:17:36 +08:00
|
|
|
FALSE, FALSE);
|
1998-08-12 01:35:34 +08:00
|
|
|
if (tile_is_valid (undo_tile) == TRUE)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-07-10 12:33:21 +08:00
|
|
|
refd = 1;
|
2002-02-15 03:31:16 +08:00
|
|
|
undo_tile = tile_manager_get_tile (core->undo_tiles,
|
2002-02-13 22:50:37 +08:00
|
|
|
srcPR.x, srcPR.y,
|
1998-08-16 03:17:36 +08:00
|
|
|
TRUE, FALSE);
|
1998-10-25 13:55:36 +08:00
|
|
|
s = (unsigned char*)tile_data_pointer (undo_tile, 0, 0) +
|
1998-08-12 01:35:34 +08:00
|
|
|
srcPR.rowstride * (srcPR.y % TILE_HEIGHT) +
|
|
|
|
srcPR.bytes * (srcPR.x % TILE_WIDTH); /* dubious... */
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1998-07-11 22:00:55 +08:00
|
|
|
refd = 0;
|
1997-11-25 06:05:25 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
1998-07-10 12:33:21 +08:00
|
|
|
if (refd)
|
|
|
|
tile_release (undo_tile, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
return core->orig_buf;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2002-03-19 23:05:38 +08:00
|
|
|
gimp_paint_core_paste_canvas (GimpPaintCore *core,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
gdouble brush_opacity,
|
|
|
|
gdouble image_opacity,
|
|
|
|
GimpLayerModeEffects paint_mode,
|
|
|
|
GimpBrushApplicationMode brush_hardness,
|
|
|
|
gdouble brush_scale,
|
|
|
|
GimpPaintApplicationMode mode)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2002-11-13 00:33:35 +08:00
|
|
|
MaskBuf *brush_mask = gimp_paint_core_get_brush_mask (core,
|
|
|
|
brush_hardness,
|
|
|
|
brush_scale);
|
|
|
|
|
|
|
|
if (brush_mask)
|
|
|
|
gimp_paint_core_paste (core, brush_mask, drawable,
|
|
|
|
brush_opacity,
|
|
|
|
image_opacity, paint_mode,
|
|
|
|
mode);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
/* Similar to gimp_paint_core_paste_canvas, but replaces the alpha channel
|
|
|
|
* rather than using it to composite (i.e. transparent over opaque
|
|
|
|
* becomes transparent rather than opauqe.
|
|
|
|
*/
|
1997-12-08 09:13:10 +08:00
|
|
|
void
|
2002-03-19 23:05:38 +08:00
|
|
|
gimp_paint_core_replace_canvas (GimpPaintCore *core,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
gdouble brush_opacity,
|
|
|
|
gdouble image_opacity,
|
|
|
|
GimpBrushApplicationMode brush_hardness,
|
|
|
|
gdouble brush_scale,
|
|
|
|
GimpPaintApplicationMode mode)
|
1997-12-08 09:13:10 +08:00
|
|
|
{
|
2002-11-13 00:33:35 +08:00
|
|
|
MaskBuf *brush_mask = gimp_paint_core_get_brush_mask (core,
|
|
|
|
brush_hardness,
|
|
|
|
brush_scale);
|
|
|
|
|
|
|
|
if (brush_mask)
|
|
|
|
gimp_paint_core_replace (core, brush_mask, drawable,
|
|
|
|
brush_opacity,
|
|
|
|
image_opacity, mode);
|
1997-12-08 09:13:10 +08:00
|
|
|
}
|
|
|
|
|
1998-07-09 13:31:06 +08:00
|
|
|
|
1999-10-27 02:27:27 +08:00
|
|
|
static void
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_invalidate_cache (GimpBrush *brush,
|
|
|
|
GimpPaintCore *core)
|
2001-02-27 13:21:12 +08:00
|
|
|
{
|
1999-10-27 02:27:27 +08:00
|
|
|
/* Make sure we don't cache data for a brush that has changed */
|
2002-02-13 22:50:37 +08:00
|
|
|
|
2003-07-14 22:50:41 +08:00
|
|
|
core->cache_invalid = TRUE;
|
|
|
|
core->solid_cache_invalid = TRUE;
|
2003-07-25 00:35:25 +08:00
|
|
|
|
|
|
|
if (core->brush_bound_segs)
|
|
|
|
{
|
|
|
|
g_free (core->brush_bound_segs);
|
|
|
|
core->brush_bound_segs = NULL;
|
|
|
|
core->n_brush_bound_segs = 0;
|
|
|
|
}
|
1998-07-09 13:31:06 +08:00
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
/************************************************************
|
|
|
|
* LOCAL FUNCTION DEFINITIONS *
|
|
|
|
************************************************************/
|
|
|
|
|
1999-09-09 09:47:54 +08:00
|
|
|
static void
|
2002-02-21 19:01:12 +08:00
|
|
|
gimp_paint_core_calc_brush_size (GimpPaintCore *core,
|
|
|
|
MaskBuf *mask,
|
|
|
|
gdouble scale,
|
|
|
|
gint *width,
|
|
|
|
gint *height)
|
1999-09-09 09:47:54 +08:00
|
|
|
{
|
2000-12-12 03:30:22 +08:00
|
|
|
scale = CLAMP (scale, 0.0, 1.0);
|
|
|
|
|
2002-02-21 19:01:12 +08:00
|
|
|
if (! core->use_pressure)
|
1999-09-09 09:47:54 +08:00
|
|
|
{
|
|
|
|
*width = mask->width;
|
|
|
|
*height = mask->height;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-03-05 08:06:11 +08:00
|
|
|
gdouble ratio;
|
1999-09-09 09:47:54 +08:00
|
|
|
|
2000-06-06 06:08:45 +08:00
|
|
|
if (scale < 1 / 256)
|
|
|
|
ratio = 1 / 16;
|
1999-09-09 09:47:54 +08:00
|
|
|
else
|
|
|
|
ratio = sqrt (scale);
|
2000-12-31 12:07:42 +08:00
|
|
|
|
|
|
|
*width = MAX ((gint) (mask->width * ratio + 0.5), 1);
|
|
|
|
*height = MAX ((gint) (mask->height * ratio + 0.5), 1);
|
1999-09-09 09:47:54 +08:00
|
|
|
}
|
2001-02-27 13:21:12 +08:00
|
|
|
}
|
1999-09-09 09:47:54 +08:00
|
|
|
|
2003-09-01 08:50:35 +08:00
|
|
|
static inline void
|
|
|
|
rotate_pointers (gulong **p,
|
2003-08-14 16:46:05 +08:00
|
|
|
guint32 n)
|
|
|
|
{
|
|
|
|
guint32 i;
|
2003-09-01 08:50:35 +08:00
|
|
|
gulong *tmp;
|
2003-08-14 16:46:05 +08:00
|
|
|
|
|
|
|
tmp = p[0];
|
|
|
|
for (i = 0; i < n-1; i++)
|
|
|
|
{
|
|
|
|
p[i] = p[i+1];
|
|
|
|
}
|
|
|
|
p[i] = tmp;
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
static MaskBuf *
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_subsample_mask (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
MaskBuf *mask,
|
|
|
|
gdouble x,
|
|
|
|
gdouble y)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-06-06 06:08:45 +08:00
|
|
|
MaskBuf *dest;
|
|
|
|
gdouble left;
|
|
|
|
guchar *m;
|
|
|
|
guchar *d;
|
2000-03-05 08:06:11 +08:00
|
|
|
const gint *k;
|
2000-06-06 06:08:45 +08:00
|
|
|
gint index1;
|
|
|
|
gint index2;
|
2003-07-14 22:50:41 +08:00
|
|
|
gint dest_offset_x = 0;
|
|
|
|
gint dest_offset_y = 0;
|
2000-03-05 08:06:11 +08:00
|
|
|
const gint *kernel;
|
2000-06-06 06:08:45 +08:00
|
|
|
gint i, j;
|
|
|
|
gint r, s;
|
2003-08-14 20:57:08 +08:00
|
|
|
gulong *accum[KERNEL_HEIGHT];
|
2003-08-14 16:46:05 +08:00
|
|
|
gint offs;
|
|
|
|
gint kernel_sum;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2003-07-14 22:50:41 +08:00
|
|
|
while (x < 0) x += mask->width;
|
2000-12-31 12:07:42 +08:00
|
|
|
left = x - floor (x);
|
2002-02-13 22:50:37 +08:00
|
|
|
index1 = (gint) (left * (gdouble) (KERNEL_SUBSAMPLE + 1));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2003-07-14 22:50:41 +08:00
|
|
|
while (y < 0) y += mask->height;
|
2000-12-31 12:07:42 +08:00
|
|
|
left = y - floor (y);
|
2002-02-13 22:50:37 +08:00
|
|
|
index2 = (gint) (left * (gdouble) (KERNEL_SUBSAMPLE + 1));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2003-07-14 22:50:41 +08:00
|
|
|
|
|
|
|
if ((mask->width % 2) == 0)
|
|
|
|
{
|
|
|
|
index1 += KERNEL_SUBSAMPLE >> 1;
|
|
|
|
|
|
|
|
if (index1 > KERNEL_SUBSAMPLE)
|
|
|
|
{
|
|
|
|
index1 -= KERNEL_SUBSAMPLE + 1;
|
|
|
|
dest_offset_x = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((mask->height % 2) == 0)
|
|
|
|
{
|
|
|
|
index2 += KERNEL_SUBSAMPLE >> 1;
|
|
|
|
|
|
|
|
if (index2 > KERNEL_SUBSAMPLE)
|
|
|
|
{
|
|
|
|
index2 -= KERNEL_SUBSAMPLE + 1;
|
|
|
|
dest_offset_y = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
kernel = subsample[index2][index1];
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
if (mask == core->last_brush_mask && ! core->cache_invalid)
|
2000-06-06 06:08:45 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
if (core->kernel_brushes[index2][index1])
|
2003-10-12 21:28:05 +08:00
|
|
|
return core->kernel_brushes[index2][index1];
|
2000-06-06 06:08:45 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-07-14 22:50:41 +08:00
|
|
|
for (i = 0; i < KERNEL_SUBSAMPLE + 1; i++)
|
|
|
|
for (j = 0; j < KERNEL_SUBSAMPLE + 1; j++)
|
|
|
|
if (core->kernel_brushes[i][j])
|
|
|
|
{
|
|
|
|
mask_buf_free (core->kernel_brushes[i][j]);
|
|
|
|
core->kernel_brushes[i][j] = NULL;
|
|
|
|
}
|
2000-06-06 06:08:45 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
core->last_brush_mask = mask;
|
|
|
|
core->cache_invalid = FALSE;
|
2000-06-06 06:08:45 +08:00
|
|
|
}
|
2000-12-31 12:07:42 +08:00
|
|
|
|
2002-02-13 22:50:37 +08:00
|
|
|
dest = mask_buf_new (mask->width + 2,
|
|
|
|
mask->height + 2);
|
|
|
|
|
2003-08-14 20:57:08 +08:00
|
|
|
/* Allocate and initialize the accum buffer */
|
2003-08-14 16:46:05 +08:00
|
|
|
for (i = 0; i < KERNEL_HEIGHT ; i++)
|
2003-08-14 20:57:08 +08:00
|
|
|
accum[i] = g_new0 (gulong, dest->width);
|
2003-08-14 16:46:05 +08:00
|
|
|
|
2003-08-14 20:57:08 +08:00
|
|
|
/* Investigate modifiying kernelgen to make the sum the same
|
|
|
|
* for all kernels. That way kernal_sum becomes a constant
|
|
|
|
*/
|
2003-08-14 16:46:05 +08:00
|
|
|
kernel_sum = 0;
|
|
|
|
for (i = 0; i < KERNEL_HEIGHT * KERNEL_WIDTH; i++)
|
|
|
|
{
|
|
|
|
kernel_sum += kernel[i];
|
|
|
|
}
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
core->kernel_brushes[index2][index1] = dest;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
m = mask_buf_data (mask);
|
|
|
|
for (i = 0; i < mask->height; i++)
|
|
|
|
{
|
|
|
|
for (j = 0; j < mask->width; j++)
|
|
|
|
{
|
|
|
|
k = kernel;
|
|
|
|
for (r = 0; r < KERNEL_HEIGHT; r++)
|
|
|
|
{
|
2003-08-14 16:46:05 +08:00
|
|
|
offs = j + dest_offset_x;
|
1997-11-25 06:05:25 +08:00
|
|
|
s = KERNEL_WIDTH;
|
|
|
|
while (s--)
|
|
|
|
{
|
2003-08-14 16:46:05 +08:00
|
|
|
accum[r][offs++] += *m * *k++;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
m++;
|
|
|
|
}
|
2003-08-14 16:46:05 +08:00
|
|
|
|
|
|
|
/* store the accum buffer into the destination mask */
|
|
|
|
d = mask_buf_data (dest) + (i + dest_offset_y) * dest->width;
|
|
|
|
for (j = 0; j < dest->width; j++)
|
|
|
|
*d++ = (accum[0][j] + 127) / kernel_sum;
|
|
|
|
|
2003-08-14 20:57:08 +08:00
|
|
|
rotate_pointers (accum, KERNEL_HEIGHT);
|
|
|
|
|
|
|
|
memset (accum[KERNEL_HEIGHT - 1], 0, sizeof (gulong) * dest->width);
|
2003-08-14 16:46:05 +08:00
|
|
|
}
|
|
|
|
|
2003-08-14 20:57:08 +08:00
|
|
|
/* store the rest of the accum buffer into the dest mask */
|
|
|
|
while (i + dest_offset_y < dest->height)
|
|
|
|
{
|
2003-08-14 16:46:05 +08:00
|
|
|
d = mask_buf_data (dest) + (i + dest_offset_y) * dest->width;
|
|
|
|
for (j = 0; j < dest->width; j++)
|
2003-08-14 20:57:08 +08:00
|
|
|
*d++ = (accum[0][j] + (kernel_sum / 2)) / kernel_sum;
|
|
|
|
|
|
|
|
rotate_pointers (accum, KERNEL_HEIGHT);
|
2003-08-14 16:46:05 +08:00
|
|
|
i++;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2003-08-14 16:46:05 +08:00
|
|
|
for (i = 0; i < KERNEL_HEIGHT ; i++)
|
2003-08-14 20:57:08 +08:00
|
|
|
g_free (accum[i]);
|
2003-08-14 16:46:05 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
1998-06-15 06:42:36 +08:00
|
|
|
/* #define FANCY_PRESSURE */
|
|
|
|
|
1998-06-06 11:49:01 +08:00
|
|
|
static MaskBuf *
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_pressurize_mask (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
MaskBuf *brush_mask,
|
|
|
|
gdouble x,
|
|
|
|
gdouble y,
|
|
|
|
gdouble pressure)
|
1998-06-06 11:49:01 +08:00
|
|
|
{
|
2000-06-06 06:08:45 +08:00
|
|
|
static guchar mapi[256];
|
2002-02-15 03:31:16 +08:00
|
|
|
guchar *source;
|
|
|
|
guchar *dest;
|
|
|
|
MaskBuf *subsample_mask;
|
|
|
|
gint i;
|
1998-06-15 06:42:36 +08:00
|
|
|
#ifdef FANCY_PRESSURE
|
2002-02-15 03:31:16 +08:00
|
|
|
static gdouble map[256];
|
|
|
|
gdouble ds, s, c;
|
1998-06-15 06:42:36 +08:00
|
|
|
#endif
|
1998-06-06 11:49:01 +08:00
|
|
|
|
|
|
|
/* Get the raw subsampled mask */
|
2002-02-15 03:31:16 +08:00
|
|
|
subsample_mask = gimp_paint_core_subsample_mask (core,
|
2002-02-13 22:50:37 +08:00
|
|
|
brush_mask,
|
|
|
|
x, y);
|
1998-06-06 11:49:01 +08:00
|
|
|
|
|
|
|
/* Special case pressure = 0.5 */
|
2000-06-06 06:08:45 +08:00
|
|
|
if ((int)(pressure * 100 + 0.5) == 50)
|
1998-06-06 11:49:01 +08:00
|
|
|
return subsample_mask;
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
if (core->pressure_brush)
|
|
|
|
mask_buf_free (core->pressure_brush);
|
2000-06-06 06:08:45 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
core->pressure_brush = mask_buf_new (brush_mask->width + 2,
|
|
|
|
brush_mask->height + 2);
|
1998-06-06 11:49:01 +08:00
|
|
|
|
1998-06-15 06:42:36 +08:00
|
|
|
#ifdef FANCY_PRESSURE
|
1998-06-06 11:49:01 +08:00
|
|
|
/* Create the pressure profile
|
|
|
|
|
|
|
|
It is: I'(I) = tanh(20*(pressure-0.5)*I) : pressure > 0.5
|
|
|
|
I'(I) = 1 - tanh(20*(0.5-pressure)*(1-I)) : pressure < 0.5
|
|
|
|
|
|
|
|
It looks like:
|
|
|
|
|
|
|
|
low pressure medium pressure high pressure
|
|
|
|
|
|
|
|
| / --
|
|
|
|
| / /
|
|
|
|
/ / |
|
|
|
|
-- / |
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
ds = (pressure - 0.5)*(20./256.);
|
|
|
|
s = 0;
|
|
|
|
c = 1.0;
|
|
|
|
|
|
|
|
if (ds > 0)
|
|
|
|
{
|
|
|
|
for (i=0;i<256;i++)
|
|
|
|
{
|
|
|
|
map[i] = s/c;
|
|
|
|
s += c*ds;
|
|
|
|
c += s*ds;
|
|
|
|
}
|
|
|
|
for (i=0;i<256;i++)
|
|
|
|
mapi[i] = (int)(255*map[i]/map[255]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ds = -ds;
|
|
|
|
for (i=255;i>=0;i--)
|
|
|
|
{
|
|
|
|
map[i] = s/c;
|
|
|
|
s += c*ds;
|
|
|
|
c += s*ds;
|
|
|
|
}
|
|
|
|
for (i=0;i<256;i++)
|
|
|
|
mapi[i] = (int)(255*(1-map[i]/map[0]));
|
|
|
|
}
|
1998-06-15 06:42:36 +08:00
|
|
|
#else /* ! FANCY_PRESSURE */
|
|
|
|
|
2000-12-31 12:07:42 +08:00
|
|
|
for (i = 0; i < 256; i++)
|
1998-06-15 06:42:36 +08:00
|
|
|
{
|
2000-12-31 12:07:42 +08:00
|
|
|
gint tmp = (pressure / 0.5) * i;
|
|
|
|
|
1998-06-15 06:42:36 +08:00
|
|
|
if (tmp > 255)
|
|
|
|
mapi[i] = 255;
|
|
|
|
else
|
|
|
|
mapi[i] = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* FANCY_PRESSURE */
|
1998-06-06 11:49:01 +08:00
|
|
|
|
|
|
|
/* Now convert the brush */
|
|
|
|
|
|
|
|
source = mask_buf_data (subsample_mask);
|
2002-02-15 03:31:16 +08:00
|
|
|
dest = mask_buf_data (core->pressure_brush);
|
1998-06-06 11:49:01 +08:00
|
|
|
|
|
|
|
i = subsample_mask->width * subsample_mask->height;
|
|
|
|
while (i--)
|
|
|
|
{
|
|
|
|
*dest++ = mapi[(*source++)];
|
|
|
|
}
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
return core->pressure_brush;
|
1998-06-06 11:49:01 +08:00
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
static MaskBuf *
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_solidify_mask (GimpPaintCore *core,
|
2003-07-14 22:50:41 +08:00
|
|
|
MaskBuf *brush_mask,
|
|
|
|
gdouble x,
|
|
|
|
gdouble y)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2003-07-14 22:50:41 +08:00
|
|
|
MaskBuf *dest;
|
|
|
|
guchar *m;
|
|
|
|
guchar *d;
|
|
|
|
gint dest_offset_x = 0;
|
|
|
|
gint dest_offset_y = 0;
|
|
|
|
gint i, j;
|
|
|
|
|
|
|
|
if ((brush_mask->width % 2) == 0)
|
2002-02-15 03:31:16 +08:00
|
|
|
{
|
2003-07-14 22:50:41 +08:00
|
|
|
while (x < 0) x += brush_mask->width;
|
|
|
|
|
|
|
|
if ((x - floor (x)) >= 0.5)
|
|
|
|
dest_offset_x++;
|
2002-02-15 03:31:16 +08:00
|
|
|
}
|
2000-06-06 06:08:45 +08:00
|
|
|
|
2003-07-14 22:50:41 +08:00
|
|
|
if ((brush_mask->height % 2) == 0)
|
|
|
|
{
|
|
|
|
while (y < 0) y += brush_mask->height;
|
|
|
|
|
|
|
|
if ((y - floor (y)) >= 0.5)
|
|
|
|
dest_offset_y++;
|
|
|
|
}
|
1999-09-09 09:47:54 +08:00
|
|
|
|
2003-07-14 22:50:41 +08:00
|
|
|
if (brush_mask == core->last_solid_brush && ! core->solid_cache_invalid)
|
|
|
|
{
|
|
|
|
if (core->solid_brushes[dest_offset_y][dest_offset_x])
|
|
|
|
return core->solid_brushes[dest_offset_y][dest_offset_x];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < PAINT_CORE_SOLID_SUBSAMPLE; i++)
|
|
|
|
for (j = 0; j < PAINT_CORE_SOLID_SUBSAMPLE; j++)
|
|
|
|
if (core->solid_brushes[i][j])
|
|
|
|
{
|
|
|
|
mask_buf_free (core->solid_brushes[i][j]);
|
|
|
|
core->solid_brushes[i][j] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
core->last_solid_brush = brush_mask;
|
|
|
|
core->solid_cache_invalid = FALSE;
|
|
|
|
}
|
1999-07-02 00:52:50 +08:00
|
|
|
|
2003-07-14 22:50:41 +08:00
|
|
|
dest = mask_buf_new (brush_mask->width + 2,
|
|
|
|
brush_mask->height + 2);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2003-07-14 22:50:41 +08:00
|
|
|
core->solid_brushes[dest_offset_y][dest_offset_x] = dest;
|
|
|
|
|
|
|
|
m = mask_buf_data (brush_mask);
|
|
|
|
d = (mask_buf_data (dest) +
|
|
|
|
(dest_offset_y + 1) * dest->width +
|
|
|
|
(dest_offset_x + 1));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
for (i = 0; i < brush_mask->height; i++)
|
|
|
|
{
|
|
|
|
for (j = 0; j < brush_mask->width; j++)
|
|
|
|
{
|
2003-07-14 22:50:41 +08:00
|
|
|
*d++ = (*m++) ? OPAQUE_OPACITY : TRANSPARENT_OPACITY;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
2003-07-14 22:50:41 +08:00
|
|
|
|
|
|
|
d += 2;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
2003-07-14 22:50:41 +08:00
|
|
|
return dest;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1999-09-09 09:47:54 +08:00
|
|
|
static MaskBuf *
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_scale_mask (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
MaskBuf *brush_mask,
|
|
|
|
gdouble scale)
|
1999-09-09 09:47:54 +08:00
|
|
|
{
|
2000-06-06 06:08:45 +08:00
|
|
|
gint dest_width;
|
|
|
|
gint dest_height;
|
1999-09-09 09:47:54 +08:00
|
|
|
|
2000-12-12 03:30:22 +08:00
|
|
|
scale = CLAMP (scale, 0.0, 1.0);
|
|
|
|
|
2001-02-27 13:21:12 +08:00
|
|
|
if (scale == 0.0)
|
1999-09-09 09:47:54 +08:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (scale == 1.0)
|
|
|
|
return brush_mask;
|
2000-03-05 08:06:11 +08:00
|
|
|
|
2002-02-21 19:01:12 +08:00
|
|
|
gimp_paint_core_calc_brush_size (core,
|
|
|
|
brush_mask,
|
|
|
|
scale,
|
2002-02-15 03:31:16 +08:00
|
|
|
&dest_width, &dest_height);
|
1999-09-09 09:47:54 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
if (brush_mask == core->last_scale_brush &&
|
|
|
|
core->scale_brush &&
|
|
|
|
! core->cache_invalid &&
|
|
|
|
dest_width == core->last_scale_width &&
|
|
|
|
dest_height == core->last_scale_height)
|
2002-02-13 22:50:37 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
return core->scale_brush;
|
2002-02-13 22:50:37 +08:00
|
|
|
}
|
1999-09-09 09:47:54 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
core->last_scale_brush = brush_mask;
|
|
|
|
core->last_scale_width = dest_width;
|
|
|
|
core->last_scale_height = dest_height;
|
1999-09-09 09:47:54 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
if (core->scale_brush)
|
|
|
|
mask_buf_free (core->scale_brush);
|
2000-03-05 08:06:11 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
core->scale_brush = brush_scale_mask (brush_mask,
|
|
|
|
dest_width, dest_height);
|
2003-11-26 00:41:20 +08:00
|
|
|
|
|
|
|
core->cache_invalid = TRUE;
|
|
|
|
core->solid_cache_invalid = TRUE;
|
1999-09-09 09:47:54 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
return core->scale_brush;
|
1999-09-09 09:47:54 +08:00
|
|
|
}
|
|
|
|
|
1999-09-10 03:11:38 +08:00
|
|
|
static MaskBuf *
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_scale_pixmap (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
MaskBuf *brush_mask,
|
|
|
|
gdouble scale)
|
1999-09-10 03:11:38 +08:00
|
|
|
{
|
2000-06-06 06:08:45 +08:00
|
|
|
gint dest_width;
|
|
|
|
gint dest_height;
|
1999-09-10 03:11:38 +08:00
|
|
|
|
2000-12-12 03:30:22 +08:00
|
|
|
scale = CLAMP (scale, 0.0, 1.0);
|
|
|
|
|
2000-12-31 12:07:42 +08:00
|
|
|
if (scale == 0.0)
|
1999-09-10 03:11:38 +08:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (scale == 1.0)
|
|
|
|
return brush_mask;
|
2000-03-05 08:06:11 +08:00
|
|
|
|
2002-02-21 19:01:12 +08:00
|
|
|
gimp_paint_core_calc_brush_size (core,
|
|
|
|
brush_mask,
|
|
|
|
scale,
|
2002-02-15 03:31:16 +08:00
|
|
|
&dest_width, &dest_height);
|
1999-09-10 03:11:38 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
if (brush_mask == core->last_scale_pixmap &&
|
|
|
|
core->scale_pixmap &&
|
|
|
|
! core->cache_invalid &&
|
|
|
|
dest_width == core->last_scale_pixmap_width &&
|
|
|
|
dest_height == core->last_scale_pixmap_height)
|
2002-02-13 22:50:37 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
return core->scale_pixmap;
|
2002-02-13 22:50:37 +08:00
|
|
|
}
|
1999-09-10 03:11:38 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
core->last_scale_pixmap = brush_mask;
|
|
|
|
core->last_scale_pixmap_width = dest_width;
|
|
|
|
core->last_scale_pixmap_height = dest_height;
|
1999-09-10 03:11:38 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
if (core->scale_pixmap)
|
|
|
|
mask_buf_free (core->scale_pixmap);
|
2000-03-05 08:06:11 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
core->scale_pixmap = brush_scale_pixmap (brush_mask,
|
|
|
|
dest_width, dest_height);
|
|
|
|
core->cache_invalid = TRUE;
|
1999-09-10 03:11:38 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
return core->scale_pixmap;
|
1999-09-10 03:11:38 +08:00
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
static MaskBuf *
|
2002-03-19 23:05:38 +08:00
|
|
|
gimp_paint_core_get_brush_mask (GimpPaintCore *core,
|
|
|
|
GimpBrushApplicationMode brush_hardness,
|
|
|
|
gdouble scale)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
MaskBuf *mask;
|
2001-12-02 05:02:34 +08:00
|
|
|
|
2002-06-08 08:01:17 +08:00
|
|
|
if (core->use_pressure)
|
|
|
|
mask = gimp_paint_core_scale_mask (core, core->brush->mask, scale);
|
1999-09-09 09:47:54 +08:00
|
|
|
else
|
2002-06-08 08:01:17 +08:00
|
|
|
mask = core->brush->mask;
|
2000-03-05 08:06:11 +08:00
|
|
|
|
2002-11-13 00:33:35 +08:00
|
|
|
if (!mask)
|
|
|
|
return NULL;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
switch (brush_hardness)
|
|
|
|
{
|
2002-03-19 23:05:38 +08:00
|
|
|
case GIMP_BRUSH_SOFT:
|
2002-02-15 03:31:16 +08:00
|
|
|
mask = gimp_paint_core_subsample_mask (core, mask,
|
|
|
|
core->cur_coords.x,
|
|
|
|
core->cur_coords.y);
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
2002-06-08 08:01:17 +08:00
|
|
|
|
2002-03-19 23:05:38 +08:00
|
|
|
case GIMP_BRUSH_HARD:
|
2003-07-14 22:50:41 +08:00
|
|
|
mask = gimp_paint_core_solidify_mask (core, mask,
|
|
|
|
core->cur_coords.x,
|
|
|
|
core->cur_coords.y);
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
2002-06-08 08:01:17 +08:00
|
|
|
|
2002-03-19 23:05:38 +08:00
|
|
|
case GIMP_BRUSH_PRESSURE:
|
2002-06-08 08:01:17 +08:00
|
|
|
if (core->use_pressure)
|
|
|
|
mask = gimp_paint_core_pressurize_mask (core, mask,
|
|
|
|
core->cur_coords.x,
|
|
|
|
core->cur_coords.y,
|
|
|
|
core->cur_coords.pressure);
|
|
|
|
else
|
|
|
|
mask = gimp_paint_core_subsample_mask (core, mask,
|
|
|
|
core->cur_coords.x,
|
|
|
|
core->cur_coords.y);
|
1998-06-06 11:49:01 +08:00
|
|
|
break;
|
2002-06-08 08:01:17 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
1999-09-09 09:47:54 +08:00
|
|
|
return mask;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2002-03-19 23:05:38 +08:00
|
|
|
gimp_paint_core_paste (GimpPaintCore *core,
|
|
|
|
MaskBuf *brush_mask,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
gdouble brush_opacity,
|
|
|
|
gdouble image_opacity,
|
|
|
|
GimpLayerModeEffects paint_mode,
|
|
|
|
GimpPaintApplicationMode mode)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-06-06 06:08:45 +08:00
|
|
|
GimpImage *gimage;
|
|
|
|
PixelRegion srcPR;
|
1997-11-25 06:05:25 +08:00
|
|
|
TileManager *alt = NULL;
|
2000-06-06 06:08:45 +08:00
|
|
|
gint offx;
|
|
|
|
gint offy;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2002-02-26 01:58:50 +08:00
|
|
|
gimage = gimp_item_get_image (GIMP_ITEM (drawable));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* set undo blocks */
|
2002-02-15 03:31:16 +08:00
|
|
|
set_undo_tiles (core,
|
2002-02-13 22:50:37 +08:00
|
|
|
drawable,
|
2003-07-16 19:25:37 +08:00
|
|
|
core->canvas_buf->x,
|
|
|
|
core->canvas_buf->y,
|
|
|
|
core->canvas_buf->width,
|
|
|
|
core->canvas_buf->height);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* If the mode is CONSTANT:
|
|
|
|
* combine the canvas buf, the brush mask to the canvas tiles
|
|
|
|
*/
|
2002-03-19 23:05:38 +08:00
|
|
|
if (mode == GIMP_PAINT_CONSTANT)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
/* initialize any invalid canvas tiles */
|
2002-02-15 03:31:16 +08:00
|
|
|
set_canvas_tiles (core,
|
|
|
|
core->canvas_buf->x,
|
|
|
|
core->canvas_buf->y,
|
|
|
|
core->canvas_buf->width,
|
|
|
|
core->canvas_buf->height);
|
|
|
|
|
|
|
|
brush_to_canvas_tiles (core, brush_mask, brush_opacity);
|
|
|
|
canvas_tiles_to_canvas_buf (core);
|
|
|
|
alt = core->undo_tiles;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
/* Otherwise:
|
|
|
|
* combine the canvas buf and the brush mask to the canvas buf
|
|
|
|
*/
|
2000-12-31 12:07:42 +08:00
|
|
|
else
|
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
brush_to_canvas_buf (core, brush_mask, brush_opacity);
|
2000-12-31 12:07:42 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* intialize canvas buf source pixel regions */
|
2002-02-15 03:31:16 +08:00
|
|
|
srcPR.bytes = core->canvas_buf->bytes;
|
2002-02-13 22:50:37 +08:00
|
|
|
srcPR.x = 0;
|
|
|
|
srcPR.y = 0;
|
2002-02-15 03:31:16 +08:00
|
|
|
srcPR.w = core->canvas_buf->width;
|
|
|
|
srcPR.h = core->canvas_buf->height;
|
|
|
|
srcPR.rowstride = core->canvas_buf->width * core->canvas_buf->bytes;
|
|
|
|
srcPR.data = temp_buf_data (core->canvas_buf);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* apply the paint area to the gimage */
|
2003-10-06 22:40:12 +08:00
|
|
|
gimp_drawable_apply_region (drawable, &srcPR,
|
|
|
|
FALSE, NULL,
|
|
|
|
image_opacity, paint_mode,
|
|
|
|
alt, /* specify an alternative src1 */
|
|
|
|
core->canvas_buf->x,
|
|
|
|
core->canvas_buf->y);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Update the undo extents */
|
2002-02-15 03:31:16 +08:00
|
|
|
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);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
/* Update the gimage -- It is important to call gimp_image_update()
|
|
|
|
* instead of gimp_drawable_update() because we don't want the
|
|
|
|
* drawable and image previews to be constantly invalidated
|
1997-12-08 09:13:10 +08:00
|
|
|
*/
|
2003-05-08 22:06:03 +08:00
|
|
|
gimp_item_offsets (GIMP_ITEM (drawable), &offx, &offy);
|
2001-11-01 05:20:09 +08:00
|
|
|
gimp_image_update (gimage,
|
2002-02-15 03:31:16 +08:00
|
|
|
core->canvas_buf->x + offx,
|
|
|
|
core->canvas_buf->y + offy,
|
|
|
|
core->canvas_buf->width,
|
|
|
|
core->canvas_buf->height);
|
1997-12-08 09:13:10 +08:00
|
|
|
}
|
|
|
|
|
2002-02-15 03: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-08 09:13:10 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
* When not drawing on alpha-enabled images, it just paints using
|
|
|
|
* NORMAL mode.
|
|
|
|
*/
|
1997-12-08 09:13:10 +08:00
|
|
|
static void
|
2002-03-19 23:05:38 +08:00
|
|
|
gimp_paint_core_replace (GimpPaintCore *core,
|
|
|
|
MaskBuf *brush_mask,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
gdouble brush_opacity,
|
|
|
|
gdouble image_opacity,
|
|
|
|
GimpPaintApplicationMode mode)
|
1997-12-08 09:13:10 +08:00
|
|
|
{
|
2000-06-06 06:08:45 +08:00
|
|
|
GimpImage *gimage;
|
|
|
|
PixelRegion srcPR;
|
|
|
|
PixelRegion maskPR;
|
1999-07-02 00:52:50 +08:00
|
|
|
TileManager *alt = NULL;
|
2000-06-06 06:08:45 +08:00
|
|
|
gint offx;
|
|
|
|
gint offy;
|
1997-12-08 09:13:10 +08:00
|
|
|
|
2001-01-15 05:11:52 +08:00
|
|
|
if (! gimp_drawable_has_alpha (drawable))
|
1997-12-08 09:13:10 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
gimp_paint_core_paste (core, brush_mask, drawable,
|
2002-03-04 01:38:12 +08:00
|
|
|
brush_opacity,
|
|
|
|
image_opacity, GIMP_NORMAL_MODE,
|
2001-02-28 03:18:01 +08:00
|
|
|
mode);
|
1997-12-08 09:13:10 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-02-26 01:58:50 +08:00
|
|
|
gimage = gimp_item_get_image (GIMP_ITEM (drawable));
|
1997-12-08 09:13:10 +08:00
|
|
|
|
|
|
|
/* set undo blocks */
|
2002-02-15 03:31:16 +08:00
|
|
|
set_undo_tiles (core,
|
2002-02-13 22:50:37 +08:00
|
|
|
drawable,
|
2002-02-15 03:31:16 +08:00
|
|
|
core->canvas_buf->x,
|
|
|
|
core->canvas_buf->y,
|
|
|
|
core->canvas_buf->width,
|
|
|
|
core->canvas_buf->height);
|
1997-12-08 09:13:10 +08:00
|
|
|
|
2002-03-19 23:05:38 +08:00
|
|
|
if (mode == GIMP_PAINT_CONSTANT)
|
2000-03-05 08:06:11 +08:00
|
|
|
{
|
|
|
|
/* initialize any invalid canvas tiles */
|
2002-02-15 03:31:16 +08:00
|
|
|
set_canvas_tiles (core,
|
|
|
|
core->canvas_buf->x,
|
|
|
|
core->canvas_buf->y,
|
|
|
|
core->canvas_buf->width,
|
|
|
|
core->canvas_buf->height);
|
2000-03-05 08:06:11 +08:00
|
|
|
|
|
|
|
/* combine the brush mask and the canvas tiles */
|
2002-02-15 03:31:16 +08:00
|
|
|
brush_to_canvas_tiles (core, brush_mask, brush_opacity);
|
2000-03-05 08:06:11 +08:00
|
|
|
|
2001-02-27 13:21:12 +08:00
|
|
|
/* set the alt source as the unaltered undo_tiles */
|
2002-02-15 03:31:16 +08:00
|
|
|
alt = core->undo_tiles;
|
2000-03-05 08:06:11 +08:00
|
|
|
|
|
|
|
/* initialize the maskPR from the canvas tiles */
|
2002-02-15 03:31:16 +08:00
|
|
|
pixel_region_init (&maskPR, core->canvas_tiles,
|
|
|
|
core->canvas_buf->x,
|
|
|
|
core->canvas_buf->y,
|
|
|
|
core->canvas_buf->width,
|
|
|
|
core->canvas_buf->height,
|
2002-02-13 22:50:37 +08:00
|
|
|
FALSE);
|
2000-03-05 08:06:11 +08:00
|
|
|
}
|
2000-12-31 12:07:42 +08:00
|
|
|
else
|
2000-03-05 08:06:11 +08:00
|
|
|
{
|
|
|
|
/* The mask is just the brush mask */
|
2000-06-06 06:08:45 +08:00
|
|
|
maskPR.bytes = 1;
|
2001-02-27 13:21:12 +08:00
|
|
|
maskPR.x = 0;
|
2000-06-06 06:08:45 +08:00
|
|
|
maskPR.y = 0;
|
2002-02-15 03:31:16 +08:00
|
|
|
maskPR.w = core->canvas_buf->width;
|
|
|
|
maskPR.h = core->canvas_buf->height;
|
2000-03-05 08:06:11 +08:00
|
|
|
maskPR.rowstride = maskPR.bytes * brush_mask->width;
|
2000-06-06 06:08:45 +08:00
|
|
|
maskPR.data = mask_buf_data (brush_mask);
|
2000-03-05 08:06:11 +08:00
|
|
|
}
|
2000-12-31 12:07:42 +08:00
|
|
|
|
1997-12-08 09:13:10 +08:00
|
|
|
/* intialize canvas buf source pixel regions */
|
2002-02-15 03:31:16 +08:00
|
|
|
srcPR.bytes = core->canvas_buf->bytes;
|
2001-02-27 13:21:12 +08:00
|
|
|
srcPR.x = 0;
|
2000-06-06 06:08:45 +08:00
|
|
|
srcPR.y = 0;
|
2002-02-15 03:31:16 +08:00
|
|
|
srcPR.w = core->canvas_buf->width;
|
|
|
|
srcPR.h = core->canvas_buf->height;
|
|
|
|
srcPR.rowstride = core->canvas_buf->width * core->canvas_buf->bytes;
|
|
|
|
srcPR.data = temp_buf_data (core->canvas_buf);
|
1997-12-08 09:13:10 +08:00
|
|
|
|
|
|
|
/* apply the paint area to the gimage */
|
2003-10-06 22:40:12 +08:00
|
|
|
gimp_drawable_replace_region (drawable, &srcPR,
|
|
|
|
FALSE, NULL,
|
|
|
|
image_opacity,
|
|
|
|
&maskPR,
|
|
|
|
core->canvas_buf->x,
|
|
|
|
core->canvas_buf->y);
|
1997-12-08 09:13:10 +08:00
|
|
|
|
|
|
|
/* Update the undo extents */
|
2002-02-15 03:31:16 +08:00
|
|
|
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) ;
|
1997-12-08 09:13:10 +08:00
|
|
|
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
/* Update the gimage -- It is important to call gimp_image_update()
|
|
|
|
* instead of gimp_drawable_update() because we don't want the
|
|
|
|
* drawable and image previews to be constantly invalidated
|
1997-11-25 06:05:25 +08:00
|
|
|
*/
|
2003-05-08 22:06:03 +08:00
|
|
|
gimp_item_offsets (GIMP_ITEM (drawable), &offx, &offy);
|
2001-11-01 05:20:09 +08:00
|
|
|
gimp_image_update (gimage,
|
2002-02-15 03:31:16 +08:00
|
|
|
core->canvas_buf->x + offx,
|
|
|
|
core->canvas_buf->y + offy,
|
|
|
|
core->canvas_buf->width,
|
|
|
|
core->canvas_buf->height);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1999-07-02 00:52:50 +08:00
|
|
|
static void
|
2002-02-15 03:31:16 +08:00
|
|
|
canvas_tiles_to_canvas_buf (GimpPaintCore *core)
|
1999-07-02 00:52:50 +08:00
|
|
|
{
|
2000-06-06 06:08:45 +08:00
|
|
|
PixelRegion srcPR;
|
|
|
|
PixelRegion maskPR;
|
1999-07-02 00:52:50 +08:00
|
|
|
|
|
|
|
/* combine the canvas tiles and the canvas buf */
|
2002-02-15 03:31:16 +08:00
|
|
|
srcPR.bytes = core->canvas_buf->bytes;
|
2001-02-27 13:21:12 +08:00
|
|
|
srcPR.x = 0;
|
2000-06-06 06:08:45 +08:00
|
|
|
srcPR.y = 0;
|
2002-02-15 03:31:16 +08:00
|
|
|
srcPR.w = core->canvas_buf->width;
|
|
|
|
srcPR.h = core->canvas_buf->height;
|
|
|
|
srcPR.rowstride = core->canvas_buf->width * core->canvas_buf->bytes;
|
|
|
|
srcPR.data = temp_buf_data (core->canvas_buf);
|
|
|
|
|
|
|
|
pixel_region_init (&maskPR, core->canvas_tiles,
|
|
|
|
core->canvas_buf->x,
|
|
|
|
core->canvas_buf->y,
|
|
|
|
core->canvas_buf->width,
|
|
|
|
core->canvas_buf->height,
|
2002-02-13 22:50:37 +08:00
|
|
|
FALSE);
|
1999-07-02 00:52:50 +08:00
|
|
|
|
|
|
|
/* apply the canvas tiles to the canvas buf */
|
|
|
|
apply_mask_to_region (&srcPR, &maskPR, OPAQUE_OPACITY);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2002-02-15 03:31:16 +08:00
|
|
|
brush_to_canvas_tiles (GimpPaintCore *core,
|
2001-02-28 03:18:01 +08:00
|
|
|
MaskBuf *brush_mask,
|
2002-03-04 01:38:12 +08:00
|
|
|
gdouble brush_opacity)
|
1999-07-02 00:52:50 +08:00
|
|
|
{
|
2000-06-06 06:08:45 +08:00
|
|
|
PixelRegion srcPR;
|
|
|
|
PixelRegion maskPR;
|
2001-02-28 03:18:01 +08:00
|
|
|
gint x;
|
|
|
|
gint y;
|
|
|
|
gint xoff;
|
|
|
|
gint yoff;
|
1999-07-02 00:52:50 +08:00
|
|
|
|
|
|
|
/* combine the brush mask and the canvas tiles */
|
2002-02-15 03:31:16 +08:00
|
|
|
pixel_region_init (&srcPR, core->canvas_tiles,
|
|
|
|
core->canvas_buf->x,
|
|
|
|
core->canvas_buf->y,
|
|
|
|
core->canvas_buf->width,
|
|
|
|
core->canvas_buf->height,
|
2002-02-13 22:50:37 +08:00
|
|
|
TRUE);
|
1999-07-02 00:52:50 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
x = (gint) floor (core->cur_coords.x) - (brush_mask->width >> 1);
|
|
|
|
y = (gint) floor (core->cur_coords.y) - (brush_mask->height >> 1);
|
2003-07-14 22:50:41 +08:00
|
|
|
|
1999-07-02 00:52:50 +08:00
|
|
|
xoff = (x < 0) ? -x : 0;
|
|
|
|
yoff = (y < 0) ? -y : 0;
|
|
|
|
|
2000-06-06 06:08:45 +08:00
|
|
|
maskPR.bytes = 1;
|
2001-02-27 13:21:12 +08:00
|
|
|
maskPR.x = 0;
|
2000-06-06 06:08:45 +08:00
|
|
|
maskPR.y = 0;
|
|
|
|
maskPR.w = srcPR.w;
|
|
|
|
maskPR.h = srcPR.h;
|
1999-07-02 00:52:50 +08:00
|
|
|
maskPR.rowstride = maskPR.bytes * brush_mask->width;
|
2002-02-13 22:50:37 +08:00
|
|
|
maskPR.data = mask_buf_data (brush_mask) + (yoff * maskPR.rowstride +
|
|
|
|
xoff * maskPR.bytes);
|
1999-07-02 00:52:50 +08:00
|
|
|
|
|
|
|
/* combine the mask to the canvas tiles */
|
2002-03-04 01:38:12 +08:00
|
|
|
combine_mask_and_region (&srcPR, &maskPR, brush_opacity * 255.999);
|
1999-07-02 00:52:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2002-02-15 03:31:16 +08:00
|
|
|
brush_to_canvas_buf (GimpPaintCore *core,
|
2001-02-28 03:18:01 +08:00
|
|
|
MaskBuf *brush_mask,
|
2002-03-04 01:38:12 +08:00
|
|
|
gdouble brush_opacity)
|
1999-07-02 00:52:50 +08:00
|
|
|
{
|
2000-06-06 06:08:45 +08:00
|
|
|
PixelRegion srcPR;
|
|
|
|
PixelRegion maskPR;
|
2001-02-28 03:18:01 +08:00
|
|
|
gint x;
|
|
|
|
gint y;
|
|
|
|
gint xoff;
|
|
|
|
gint yoff;
|
2000-06-06 06:08:45 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
x = (gint) floor (core->cur_coords.x) - (brush_mask->width >> 1);
|
|
|
|
y = (gint) floor (core->cur_coords.y) - (brush_mask->height >> 1);
|
2003-07-14 22:50:41 +08:00
|
|
|
|
1999-07-02 00:52:50 +08:00
|
|
|
xoff = (x < 0) ? -x : 0;
|
|
|
|
yoff = (y < 0) ? -y : 0;
|
|
|
|
|
|
|
|
/* combine the canvas buf and the brush mask to the canvas buf */
|
2002-02-15 03:31:16 +08:00
|
|
|
srcPR.bytes = core->canvas_buf->bytes;
|
2001-02-27 13:21:12 +08:00
|
|
|
srcPR.x = 0;
|
2000-06-06 06:08:45 +08:00
|
|
|
srcPR.y = 0;
|
2002-02-15 03:31:16 +08:00
|
|
|
srcPR.w = core->canvas_buf->width;
|
|
|
|
srcPR.h = core->canvas_buf->height;
|
|
|
|
srcPR.rowstride = core->canvas_buf->width * core->canvas_buf->bytes;
|
|
|
|
srcPR.data = temp_buf_data (core->canvas_buf);
|
1999-07-02 00:52:50 +08:00
|
|
|
|
2000-06-06 06:08:45 +08:00
|
|
|
maskPR.bytes = 1;
|
2001-02-27 13:21:12 +08:00
|
|
|
maskPR.x = 0;
|
2000-06-06 06:08:45 +08:00
|
|
|
maskPR.y = 0;
|
|
|
|
maskPR.w = srcPR.w;
|
|
|
|
maskPR.h = srcPR.h;
|
1999-07-02 00:52:50 +08:00
|
|
|
maskPR.rowstride = maskPR.bytes * brush_mask->width;
|
2000-06-06 06:08:45 +08:00
|
|
|
maskPR.data = mask_buf_data (brush_mask) + yoff * maskPR.rowstride + xoff * maskPR.bytes;
|
1999-07-02 00:52:50 +08:00
|
|
|
|
|
|
|
/* apply the mask */
|
2002-03-04 01:38:12 +08:00
|
|
|
apply_mask_to_region (&srcPR, &maskPR, brush_opacity * 255.999);
|
1999-07-02 00:52:50 +08:00
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
static void
|
2002-02-15 03:31:16 +08:00
|
|
|
set_undo_tiles (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
GimpDrawable *drawable,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gint h)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-06-06 06:08:45 +08:00
|
|
|
gint i;
|
|
|
|
gint j;
|
1997-11-25 06:05:25 +08:00
|
|
|
Tile *src_tile;
|
|
|
|
Tile *dest_tile;
|
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
if (! core->undo_tiles)
|
1998-08-16 03:17:36 +08:00
|
|
|
{
|
1999-11-23 06:38:02 +08:00
|
|
|
g_warning ("set_undo_tiles: undo_tiles is null");
|
1998-08-16 03:17:36 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
for (i = y; i < (y + h); i += (TILE_HEIGHT - (i % TILE_HEIGHT)))
|
|
|
|
{
|
|
|
|
for (j = x; j < (x + w); j += (TILE_WIDTH - (j % TILE_WIDTH)))
|
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
dest_tile = tile_manager_get_tile (core->undo_tiles, j, i,
|
2002-02-13 22:50:37 +08:00
|
|
|
FALSE, FALSE);
|
|
|
|
|
1998-08-12 01:35:34 +08:00
|
|
|
if (tile_is_valid (dest_tile) == FALSE)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2001-01-15 05:11:52 +08:00
|
|
|
src_tile = tile_manager_get_tile (gimp_drawable_data (drawable),
|
|
|
|
j, i, TRUE, FALSE);
|
2002-02-15 03:31:16 +08:00
|
|
|
tile_manager_map_tile (core->undo_tiles, j, i, src_tile);
|
1998-07-10 10:43:12 +08:00
|
|
|
tile_release (src_tile, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2002-02-15 03:31:16 +08:00
|
|
|
set_canvas_tiles (GimpPaintCore *core,
|
2002-02-13 22:50:37 +08:00
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint w,
|
|
|
|
gint h)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-06-06 06:08:45 +08:00
|
|
|
gint i;
|
|
|
|
gint j;
|
1997-11-25 06:05:25 +08:00
|
|
|
Tile *tile;
|
|
|
|
|
|
|
|
for (i = y; i < (y + h); i += (TILE_HEIGHT - (i % TILE_HEIGHT)))
|
|
|
|
{
|
|
|
|
for (j = x; j < (x + w); j += (TILE_WIDTH - (j % TILE_WIDTH)))
|
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
tile = tile_manager_get_tile (core->canvas_tiles, j, i,
|
2002-02-13 22:50:37 +08:00
|
|
|
FALSE, FALSE);
|
|
|
|
|
1998-08-12 01:35:34 +08:00
|
|
|
if (tile_is_valid (tile) == FALSE)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
tile = tile_manager_get_tile (core->canvas_tiles, j, i,
|
2002-02-13 22:50:37 +08:00
|
|
|
TRUE, TRUE);
|
2000-06-06 06:08:45 +08:00
|
|
|
memset (tile_data_pointer (tile, 0, 0), 0, tile_size (tile));
|
1998-07-10 10:43:12 +08:00
|
|
|
tile_release (tile, TRUE);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-09-10 03:11:38 +08:00
|
|
|
/**************************************************/
|
|
|
|
/* Brush pipe utility functions */
|
|
|
|
/**************************************************/
|
|
|
|
|
|
|
|
void
|
2002-03-19 23:05:38 +08:00
|
|
|
gimp_paint_core_color_area_with_pixmap (GimpPaintCore *core,
|
|
|
|
GimpImage *dest,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
TempBuf *area,
|
|
|
|
gdouble scale,
|
|
|
|
GimpBrushApplicationMode mode)
|
1999-09-10 03:11:38 +08:00
|
|
|
{
|
2002-02-15 03:31:16 +08:00
|
|
|
PixelRegion destPR;
|
|
|
|
void *pr;
|
|
|
|
guchar *d;
|
|
|
|
gint ulx;
|
|
|
|
gint uly;
|
|
|
|
gint offsetx;
|
|
|
|
gint offsety;
|
|
|
|
gint y;
|
|
|
|
TempBuf *pixmap_mask;
|
|
|
|
TempBuf *brush_mask;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_BRUSH (core->brush));
|
|
|
|
g_return_if_fail (core->brush->pixmap != NULL);
|
2001-02-27 13:21:12 +08:00
|
|
|
|
1999-09-10 03:11:38 +08:00
|
|
|
/* scale the brushes */
|
2002-02-15 03:31:16 +08:00
|
|
|
pixmap_mask = gimp_paint_core_scale_pixmap (core,
|
|
|
|
core->brush->pixmap,
|
2002-02-13 22:50:37 +08:00
|
|
|
scale);
|
2000-06-06 06:08:45 +08:00
|
|
|
|
2002-11-13 00:33:35 +08:00
|
|
|
if (!pixmap_mask)
|
|
|
|
return;
|
|
|
|
|
2003-07-14 22:50:41 +08:00
|
|
|
if (mode != GIMP_BRUSH_HARD)
|
2002-02-15 03:31:16 +08:00
|
|
|
brush_mask = gimp_paint_core_scale_mask (core,
|
|
|
|
core->brush->mask,
|
2002-02-13 22:50:37 +08:00
|
|
|
scale);
|
1999-09-10 03:11:38 +08:00
|
|
|
else
|
|
|
|
brush_mask = NULL;
|
|
|
|
|
2000-06-06 06:08:45 +08:00
|
|
|
destPR.bytes = area->bytes;
|
2001-02-27 13:21:12 +08:00
|
|
|
destPR.x = 0;
|
2000-06-06 06:08:45 +08:00
|
|
|
destPR.y = 0;
|
|
|
|
destPR.w = area->width;
|
|
|
|
destPR.h = area->height;
|
1999-09-10 03:11:38 +08:00
|
|
|
destPR.rowstride = destPR.bytes * area->width;
|
2000-06-06 06:08:45 +08:00
|
|
|
destPR.data = temp_buf_data (area);
|
2003-07-14 22:50:41 +08:00
|
|
|
|
1999-09-10 03:11:38 +08:00
|
|
|
pr = pixel_regions_register (1, &destPR);
|
|
|
|
|
|
|
|
/* Calculate upper left corner of brush as in
|
2002-02-15 03:31:16 +08:00
|
|
|
* gimp_paint_core_get_paint_area. Ugly to have to do this here, too.
|
1999-09-10 03:11:38 +08:00
|
|
|
*/
|
2002-02-15 03:31:16 +08:00
|
|
|
ulx = (gint) floor (core->cur_coords.x) - (pixmap_mask->width >> 1);
|
|
|
|
uly = (gint) floor (core->cur_coords.y) - (pixmap_mask->height >> 1);
|
1999-09-10 03:11:38 +08:00
|
|
|
|
|
|
|
offsetx = area->x - ulx;
|
|
|
|
offsety = area->y - uly;
|
|
|
|
|
|
|
|
for (; pr != NULL; pr = pixel_regions_process (pr))
|
|
|
|
{
|
|
|
|
d = destPR.data;
|
|
|
|
for (y = 0; y < destPR.h; y++)
|
|
|
|
{
|
|
|
|
paint_line_pixmap_mask (dest, drawable, pixmap_mask, brush_mask,
|
|
|
|
d, offsetx, y + offsety,
|
|
|
|
destPR.bytes, destPR.w, mode);
|
|
|
|
d += destPR.rowstride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2002-03-19 23:05:38 +08:00
|
|
|
paint_line_pixmap_mask (GimpImage *dest,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
TempBuf *pixmap_mask,
|
|
|
|
TempBuf *brush_mask,
|
|
|
|
guchar *d,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint bytes,
|
|
|
|
gint width,
|
|
|
|
GimpBrushApplicationMode mode)
|
1999-09-10 03:11:38 +08:00
|
|
|
{
|
2000-06-06 06:08:45 +08:00
|
|
|
guchar *b;
|
|
|
|
guchar *p;
|
|
|
|
guchar *mask;
|
|
|
|
gdouble alpha;
|
|
|
|
gdouble factor = 0.00392156986; /* 1.0 / 255.0 */
|
|
|
|
gint x_index;
|
2000-06-28 05:26:59 +08:00
|
|
|
gint i,byte_loop;
|
1999-09-10 03:11:38 +08:00
|
|
|
|
|
|
|
/* Make sure x, y are positive */
|
|
|
|
while (x < 0)
|
|
|
|
x += pixmap_mask->width;
|
|
|
|
while (y < 0)
|
|
|
|
y += pixmap_mask->height;
|
|
|
|
|
|
|
|
/* Point to the approriate scanline */
|
|
|
|
b = temp_buf_data (pixmap_mask) +
|
|
|
|
(y % pixmap_mask->height) * pixmap_mask->width * pixmap_mask->bytes;
|
2003-07-14 22:50:41 +08:00
|
|
|
|
2002-03-19 23:05:38 +08:00
|
|
|
if (mode == GIMP_BRUSH_SOFT && brush_mask)
|
1999-09-10 03:11:38 +08:00
|
|
|
{
|
2003-07-14 22:50:41 +08:00
|
|
|
/* ditto, except for the brush mask,
|
2002-03-19 23:05:38 +08:00
|
|
|
so we can pre-multiply the alpha value */
|
1999-09-10 03:11:38 +08:00
|
|
|
mask = temp_buf_data (brush_mask) +
|
|
|
|
(y % brush_mask->height) * brush_mask->width;
|
|
|
|
for (i = 0; i < width; i++)
|
|
|
|
{
|
|
|
|
/* attempt to avoid doing this calc twice in the loop */
|
|
|
|
x_index = ((i + x) % pixmap_mask->width);
|
|
|
|
p = b + x_index * pixmap_mask->bytes;
|
|
|
|
d[bytes-1] = mask[x_index];
|
2003-07-14 22:50:41 +08:00
|
|
|
|
2002-02-15 03:31:16 +08:00
|
|
|
/* multiply alpha into the pixmap data
|
|
|
|
* maybe we could do this at tool creation or brush switch time?
|
|
|
|
* and compute it for the whole brush at once and cache it?
|
|
|
|
*/
|
1999-09-10 03:11:38 +08:00
|
|
|
alpha = d[bytes-1] * factor;
|
2002-02-15 03:31:16 +08:00
|
|
|
if (alpha)
|
2003-07-14 22:50:41 +08:00
|
|
|
for (byte_loop = 0; byte_loop < bytes - 1; byte_loop++)
|
2000-06-28 05:26:59 +08:00
|
|
|
d[byte_loop] *= alpha;
|
|
|
|
|
1999-09-10 03:11:38 +08:00
|
|
|
/* printf("i: %i d->r: %i d->g: %i d->b: %i d->a: %i\n",i,(int)d[0], (int)d[1], (int)d[2], (int)d[3]); */
|
2003-09-06 01:44:39 +08:00
|
|
|
gimp_image_transform_color (dest, drawable, d, GIMP_RGB, p);
|
1999-09-10 03:11:38 +08:00
|
|
|
d += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (i = 0; i < width; i++)
|
|
|
|
{
|
|
|
|
/* attempt to avoid doing this calc twice in the loop */
|
|
|
|
x_index = ((i + x) % pixmap_mask->width);
|
|
|
|
p = b + x_index * pixmap_mask->bytes;
|
|
|
|
d[bytes-1] = 255;
|
2003-07-14 22:50:41 +08:00
|
|
|
|
1999-09-10 03:11:38 +08:00
|
|
|
/* multiply alpha into the pixmap data */
|
|
|
|
/* maybe we could do this at tool creation or brush switch time? */
|
|
|
|
/* and compute it for the whole brush at once and cache it? */
|
2003-09-06 01:44:39 +08:00
|
|
|
gimp_image_transform_color (dest, drawable, d, GIMP_RGB, p);
|
1999-09-10 03:11:38 +08:00
|
|
|
d += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|