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
|
|
|
*/
|
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"
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
#include <stdlib.h>
|
1999-06-03 23:02:48 +08:00
|
|
|
#include <stdio.h> /* temporary for debugging */
|
1997-11-25 06:05:25 +08:00
|
|
|
#include <string.h>
|
app/appenv.h New file. Includes <math.h>. Move G_PI, RINT(), ROUND() etc
1999-09-01 Tor Lillqvist <tml@iki.fi>
* app/appenv.h
* libgimp/gimpmath.h: New file. Includes <math.h>. Move G_PI,
RINT(), ROUND() etc from app/appenv.h here, so plug-ins can
use them, too. Remove some commented-out old stuff in appenv.h.
* libgimp/gimp.h: Include gimpmath.h.
* libgimp/gimp.c (gimp_main): Win32: Don't install signal
handlers, we can't do anything useful in the handler ourselves
anyway (it would be nice to print out a backtrace, but that seems
pretty hard to do, even if not impossible). Let Windows inform the
user about the crash. If the plug-in was compiled with MSVC, and
the user also has it, she is offered a chance to start the
debugger automatically anyway.
* app/*several*.c: Include gimpmath.h for G_PI etc. Don't include
<math.h>, as gimpmath.h includes it.
* plug-ins/*/*many*.c: Include config.h. Don't include <math.h>.
Remove all the duplicated definitions of G_PI and rint(). Use
RINT() instead of rint().
* app/app_procs.[ch]: app_exit() takes a gboolean.
* app/batch.c
* app/commands.c
* app/interface.c: Call app_exit() with FALSE or TRUE.
* app/main.c (on_error): Call gimp_fatal_error. (main): Don't
install any signal handler on Win32 here, either.
* app/errors.c (gimp_fatal_error, gimp_terminate): Win32: Format
the message and call MessageBox with it. g_on_error_query doesn't
do anything useful on Win32, and printf'ing a message to stdout or
stderr doesn't do anything, either, in a windowing application.
1999-09-02 04:30:56 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
#include "appenv.h"
|
1999-09-09 09:47:54 +08:00
|
|
|
#include "brush_scale.h"
|
|
|
|
#include "devices.h"
|
1997-11-25 06:05:25 +08:00
|
|
|
#include "drawable.h"
|
|
|
|
#include "errors.h"
|
|
|
|
#include "gdisplay.h"
|
|
|
|
#include "gimage_mask.h"
|
1999-09-10 03:11:38 +08:00
|
|
|
#include "gimpbrushpipe.h"
|
1998-07-19 01:39:23 +08:00
|
|
|
#include "gimprc.h"
|
1999-03-19 08:42:27 +08:00
|
|
|
#include "gradient.h" /* for grad_get_color_at() */
|
1997-11-25 06:05:25 +08:00
|
|
|
#include "paint_funcs.h"
|
|
|
|
#include "paint_core.h"
|
|
|
|
#include "selection.h"
|
|
|
|
#include "tools.h"
|
|
|
|
#include "undo.h"
|
1999-05-13 19:12:32 +08:00
|
|
|
#include "cursorutil.h"
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-12-16 08:37:09 +08:00
|
|
|
#include "libgimp/gimpintl.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
|
|
|
#include "libgimp/gimpmath.h"
|
1998-12-16 08:37:09 +08:00
|
|
|
|
1998-08-12 01:35:34 +08:00
|
|
|
#include "tile.h" /* ick. */
|
1998-07-08 14:41:58 +08:00
|
|
|
|
1999-05-15 08:02:47 +08:00
|
|
|
/* target size */
|
1999-06-22 06:12:07 +08:00
|
|
|
#define TARGET_HEIGHT 15
|
|
|
|
#define TARGET_WIDTH 15
|
1999-05-15 08:02:47 +08:00
|
|
|
|
1999-09-02 02:46:25 +08:00
|
|
|
#define EPSILON 0.00001
|
|
|
|
|
|
|
|
#define STATUSBAR_SIZE 128
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* global variables--for use in the various paint tools */
|
|
|
|
PaintCore non_gui_paint_core;
|
|
|
|
|
|
|
|
/* local function prototypes */
|
1999-09-09 09:47:54 +08:00
|
|
|
static void paint_core_calculate_brush_size (MaskBuf *, double, int *, int *);
|
1997-11-25 06:05:25 +08:00
|
|
|
static MaskBuf * paint_core_subsample_mask (MaskBuf *, double, double);
|
1999-06-22 06:12:07 +08:00
|
|
|
static MaskBuf * paint_core_pressurize_mask (MaskBuf *, double, double, double);
|
1997-11-25 06:05:25 +08:00
|
|
|
static MaskBuf * paint_core_solidify_mask (MaskBuf *);
|
1999-09-09 09:47:54 +08:00
|
|
|
static MaskBuf * paint_core_scale_mask (MaskBuf *, gdouble);
|
1999-09-10 03:11:38 +08:00
|
|
|
static MaskBuf * paint_core_scale_pixmap (MaskBuf *, gdouble);
|
1999-09-09 09:47:54 +08:00
|
|
|
static MaskBuf * paint_core_get_brush_mask (PaintCore *, BrushApplicationMode, gdouble);
|
1999-06-22 06:12:07 +08:00
|
|
|
static void paint_core_paste (PaintCore *, MaskBuf *,
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
GimpDrawable *, int, int,
|
|
|
|
LayerModeEffects,
|
|
|
|
PaintApplicationMode);
|
1999-06-22 06:12:07 +08:00
|
|
|
static void paint_core_replace (PaintCore *, MaskBuf *,
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
GimpDrawable *, int, int,
|
|
|
|
PaintApplicationMode);
|
1999-07-02 00:52:50 +08:00
|
|
|
static void brush_to_canvas_tiles (PaintCore *, MaskBuf *, int);
|
|
|
|
static void canvas_tiles_to_canvas_buf (PaintCore *);
|
|
|
|
static void brush_to_canvas_buf (PaintCore *, MaskBuf *, int);
|
1998-01-22 15:02:57 +08:00
|
|
|
static void set_undo_tiles (GimpDrawable *, int, int, int, int);
|
1997-11-25 06:05:25 +08:00
|
|
|
static void set_canvas_tiles (int, int, int, int);
|
1999-10-27 02:27:27 +08:00
|
|
|
static void paint_core_invalidate_cache (GimpBrush *brush, gpointer *blah);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
/* undo blocks variables */
|
|
|
|
static TileManager * undo_tiles = NULL;
|
|
|
|
static TileManager * canvas_tiles = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
/* paint buffers variables */
|
|
|
|
static TempBuf * orig_buf = NULL;
|
|
|
|
static TempBuf * canvas_buf = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
/* brush buffers */
|
1998-06-06 11:49:01 +08:00
|
|
|
static MaskBuf * pressure_brush;
|
1997-11-25 06:05:25 +08:00
|
|
|
static MaskBuf * solid_brush;
|
1999-09-09 09:47:54 +08:00
|
|
|
static MaskBuf * scale_brush = NULL;
|
1999-09-10 03:11:38 +08:00
|
|
|
static MaskBuf * scale_pixmap = NULL;
|
1998-03-24 10:18:58 +08:00
|
|
|
static MaskBuf * kernel_brushes[5][5];
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
|
|
|
|
/* paint buffers utility functions */
|
|
|
|
static void free_paint_buffers (void);
|
|
|
|
|
1999-09-10 03:11:38 +08:00
|
|
|
/* brush pipe utility functions */
|
|
|
|
static void paint_line_pixmap_mask (GImage *, GimpDrawable *,
|
|
|
|
TempBuf *, TempBuf *, guchar *,
|
|
|
|
int, int, int, int, int);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/***********************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
#define KERNEL_WIDTH 3
|
|
|
|
#define KERNEL_HEIGHT 3
|
|
|
|
|
|
|
|
/* Brush pixel subsampling kernels */
|
1998-12-26 02:22:01 +08:00
|
|
|
static const int subsample[5][5][9] = {
|
1998-03-24 10:18:58 +08:00
|
|
|
{
|
|
|
|
{ 64, 64, 0, 64, 64, 0, 0, 0, 0, },
|
|
|
|
{ 32, 96, 0, 32, 96, 0, 0, 0, 0, },
|
|
|
|
{ 0, 128, 0, 0, 128, 0, 0, 0, 0, },
|
|
|
|
{ 0, 96, 32, 0, 96, 32, 0, 0, 0, },
|
|
|
|
{ 0, 64, 64, 0, 64, 64, 0, 0, 0, },
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{ 32, 32, 0, 96, 96, 0, 0, 0, 0, },
|
|
|
|
{ 16, 48, 0, 48, 144, 0, 0, 0, 0, },
|
|
|
|
{ 0, 64, 0, 0, 192, 0, 0, 0, 0, },
|
|
|
|
{ 0, 48, 16, 0, 144, 48, 0, 0, 0, },
|
|
|
|
{ 0, 32, 32, 0, 96, 96, 0, 0, 0, },
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{ 0, 0, 0, 128, 128, 0, 0, 0, 0, },
|
|
|
|
{ 0, 0, 0, 64, 192, 0, 0, 0, 0, },
|
|
|
|
{ 0, 0, 0, 0, 256, 0, 0, 0, 0, },
|
|
|
|
{ 0, 0, 0, 0, 192, 64, 0, 0, 0, },
|
|
|
|
{ 0, 0, 0, 0, 128, 128, 0, 0, 0, },
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{ 0, 0, 0, 96, 96, 0, 32, 32, 0, },
|
|
|
|
{ 0, 0, 0, 48, 144, 0, 16, 48, 0, },
|
|
|
|
{ 0, 0, 0, 0, 192, 0, 0, 64, 0, },
|
|
|
|
{ 0, 0, 0, 0, 144, 48, 0, 48, 16, },
|
|
|
|
{ 0, 0, 0, 0, 96, 96, 0, 32, 32, },
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{ 0, 0, 0, 64, 64, 0, 64, 64, 0, },
|
|
|
|
{ 0, 0, 0, 32, 96, 0, 32, 96, 0, },
|
|
|
|
{ 0, 0, 0, 0, 128, 0, 0, 128, 0, },
|
|
|
|
{ 0, 0, 0, 0, 96, 32, 0, 96, 32, },
|
|
|
|
{ 0, 0, 0, 0, 64, 64, 0, 64, 64, },
|
|
|
|
},
|
1997-11-25 06:05:25 +08:00
|
|
|
};
|
|
|
|
|
1999-05-13 19:12:32 +08:00
|
|
|
static void
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_core_sample_color (GimpDrawable *drawable,
|
1999-10-27 02:27:27 +08:00
|
|
|
int x,
|
|
|
|
int y,
|
|
|
|
int state)
|
1999-05-13 19:12:32 +08:00
|
|
|
{
|
1999-10-27 02:27:27 +08:00
|
|
|
guchar *color;
|
|
|
|
|
|
|
|
if ((color = gimp_drawable_get_color_at (drawable, x, y)))
|
1999-05-13 19:12:32 +08:00
|
|
|
{
|
|
|
|
if ((state & GDK_CONTROL_MASK))
|
1999-10-27 02:27:27 +08:00
|
|
|
gimp_context_set_foreground (gimp_context_get_user (),
|
|
|
|
color[RED_PIX],
|
|
|
|
color[GREEN_PIX],
|
|
|
|
color[BLUE_PIX]);
|
1999-05-13 19:12:32 +08:00
|
|
|
else
|
1999-10-27 02:27:27 +08:00
|
|
|
gimp_context_set_background (gimp_context_get_user (),
|
|
|
|
color[RED_PIX],
|
|
|
|
color[GREEN_PIX],
|
|
|
|
color[BLUE_PIX]);
|
1999-06-03 23:02:48 +08:00
|
|
|
|
1999-10-27 02:27:27 +08:00
|
|
|
g_free (color);
|
1999-05-13 19:12:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_core_button_press (Tool *tool,
|
|
|
|
GdkEventButton *bevent,
|
|
|
|
gpointer gdisp_ptr)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
PaintCore * paint_core;
|
|
|
|
GDisplay * gdisp;
|
1999-06-03 23:02:48 +08:00
|
|
|
gboolean draw_line;
|
1997-11-25 06:05:25 +08:00
|
|
|
double x, y;
|
1998-01-22 15:02:57 +08:00
|
|
|
GimpDrawable *drawable;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
gdisp = (GDisplay *) gdisp_ptr;
|
|
|
|
paint_core = (PaintCore *) tool->private;
|
|
|
|
|
|
|
|
gdisplay_untransform_coords_f (gdisp, (double) bevent->x, (double) bevent->y, &x, &y, TRUE);
|
1998-01-22 15:02:57 +08:00
|
|
|
drawable = gimage_active_drawable (gdisp->gimage);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
if (! paint_core_init (paint_core, drawable, x, y))
|
1997-11-25 06:05:25 +08:00
|
|
|
return;
|
|
|
|
|
1999-06-03 23:02:48 +08:00
|
|
|
draw_line = FALSE;
|
|
|
|
|
1998-06-06 11:49:01 +08:00
|
|
|
paint_core->curpressure = bevent->pressure;
|
|
|
|
paint_core->curxtilt = bevent->xtilt;
|
|
|
|
paint_core->curytilt = bevent->ytilt;
|
1999-09-04 22:42:43 +08:00
|
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
|
|
|
paint_core->curwheel = bevent->wheel;
|
|
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
1997-11-25 06:05:25 +08:00
|
|
|
paint_core->state = bevent->state;
|
1999-09-02 02:46:25 +08:00
|
|
|
|
|
|
|
if (gdisp_ptr != tool->gdisp_ptr)
|
|
|
|
{
|
|
|
|
/* initialize the statusbar display */
|
|
|
|
paint_core->context_id =
|
|
|
|
gtk_statusbar_get_context_id (GTK_STATUSBAR (gdisp->statusbar), "paint");
|
|
|
|
}
|
|
|
|
/* if this is a new image, reinit the core vals */
|
1999-06-03 23:02:48 +08:00
|
|
|
if ((gdisp_ptr != tool->gdisp_ptr) || ! (bevent->state & GDK_SHIFT_MASK))
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
/* initialize some values */
|
1999-05-15 08:02:47 +08:00
|
|
|
paint_core->startx = paint_core->lastx = paint_core->curx = x;
|
|
|
|
paint_core->starty = paint_core->lasty = paint_core->cury = y;
|
1998-06-06 11:49:01 +08:00
|
|
|
paint_core->startpressure = paint_core->lastpressure = paint_core->curpressure;
|
|
|
|
paint_core->startytilt = paint_core->lastytilt = paint_core->curytilt;
|
|
|
|
paint_core->startxtilt = paint_core->lastxtilt = paint_core->curxtilt;
|
1999-09-04 22:42:43 +08:00
|
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
|
|
|
paint_core->startwheel = paint_core->lastwheel = paint_core->curwheel;
|
|
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
1999-08-14 20:34:08 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
/* If shift is down and this is not the first paint
|
|
|
|
* stroke, then draw a line from the last coords to the pointer
|
|
|
|
*/
|
1999-06-18 04:34:50 +08:00
|
|
|
else if (bevent->state & GDK_SHIFT_MASK)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-06-03 23:02:48 +08:00
|
|
|
draw_line = TRUE;
|
1997-11-25 06:05:25 +08:00
|
|
|
paint_core->startx = paint_core->lastx;
|
|
|
|
paint_core->starty = paint_core->lasty;
|
1998-06-06 11:49:01 +08:00
|
|
|
paint_core->startpressure = paint_core->lastpressure;
|
|
|
|
paint_core->startxtilt = paint_core->lastxtilt;
|
|
|
|
paint_core->startytilt = paint_core->lastytilt;
|
1999-09-04 22:42:43 +08:00
|
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
|
|
|
paint_core->startwheel = paint_core->lastwheel;
|
|
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
1999-06-18 04:34:50 +08:00
|
|
|
|
1999-11-25 09:59:14 +08:00
|
|
|
/* Restrict to multiples of 15 degrees if ctrl is pressed */
|
|
|
|
if (bevent->state & GDK_CONTROL_MASK)
|
1999-06-18 04:34:50 +08:00
|
|
|
{
|
1999-11-25 09:59:14 +08:00
|
|
|
int tangens2[6] = { 34, 106, 196, 334, 618, 1944 };
|
|
|
|
int cosinus[7] = { 256, 247, 222, 181, 128, 66, 0 };
|
|
|
|
int dx, dy, i, radius, frac;
|
|
|
|
|
|
|
|
dx = paint_core->curx - paint_core->lastx;
|
|
|
|
dy = paint_core->cury - paint_core->lasty;
|
|
|
|
|
|
|
|
if (dy)
|
1999-06-18 04:34:50 +08:00
|
|
|
{
|
1999-11-25 09:59:14 +08:00
|
|
|
radius = sqrt (SQR (dx) + SQR (dy));
|
|
|
|
frac = abs ((dx << 8) / dy);
|
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
{
|
|
|
|
if (frac < tangens2[i])
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
dx = dx > 0 ? (cosinus[6-i] * radius) >> 8 : - ((cosinus[6-i] * radius) >> 8);
|
|
|
|
dy = dy > 0 ? (cosinus[i] * radius) >> 8 : - ((cosinus[i] * radius) >> 8);
|
1999-06-18 04:34:50 +08:00
|
|
|
}
|
1999-11-25 09:59:14 +08:00
|
|
|
paint_core->curx = paint_core->lastx + dx;
|
|
|
|
paint_core->cury = paint_core->lasty + dy;
|
1999-06-18 04:34:50 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
tool->state = ACTIVE;
|
|
|
|
tool->gdisp_ptr = gdisp_ptr;
|
|
|
|
tool->paused_count = 0;
|
|
|
|
|
|
|
|
/* pause the current selection and grab the pointer */
|
1998-06-29 08:24:44 +08:00
|
|
|
gdisplays_selection_visibility (gdisp->gimage, SelectionPause);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-05 17:10:35 +08:00
|
|
|
/* add motion memory if perfectmouse is set */
|
|
|
|
if (perfectmouse != 0)
|
1997-11-25 06:05:25 +08:00
|
|
|
gdk_pointer_grab (gdisp->canvas->window, FALSE,
|
|
|
|
GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
|
|
|
|
NULL, NULL, bevent->time);
|
|
|
|
else
|
|
|
|
gdk_pointer_grab (gdisp->canvas->window, FALSE,
|
1998-07-19 01:39:23 +08:00
|
|
|
GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK |
|
|
|
|
GDK_BUTTON_RELEASE_MASK,
|
1997-11-25 06:05:25 +08:00
|
|
|
NULL, NULL, bevent->time);
|
|
|
|
|
|
|
|
/* Let the specific painting function initialize itself */
|
1998-01-22 15:02:57 +08:00
|
|
|
(* paint_core->paint_func) (paint_core, drawable, INIT_PAINT);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-13 19:12:32 +08:00
|
|
|
if (paint_core->pick_colors
|
1999-06-08 06:38:20 +08:00
|
|
|
&& !(bevent->state & GDK_SHIFT_MASK)
|
1999-05-13 19:12:32 +08:00
|
|
|
&& (bevent->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)))
|
1999-08-14 20:34:08 +08:00
|
|
|
{
|
|
|
|
paint_core_sample_color (drawable, x, y, bevent->state);
|
|
|
|
paint_core->pick_state = TRUE;
|
|
|
|
return;
|
|
|
|
}
|
1999-05-13 19:12:32 +08:00
|
|
|
else
|
|
|
|
paint_core->pick_state = FALSE;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
/* Paint to the image */
|
|
|
|
if (draw_line)
|
|
|
|
{
|
1999-08-01 22:26:59 +08:00
|
|
|
draw_core_pause (paint_core->core, tool);
|
1998-01-22 15:02:57 +08:00
|
|
|
paint_core_interpolate (paint_core, drawable);
|
1997-11-25 06:05:25 +08:00
|
|
|
paint_core->lastx = paint_core->curx;
|
|
|
|
paint_core->lasty = paint_core->cury;
|
1998-06-06 11:49:01 +08:00
|
|
|
paint_core->lastpressure = paint_core->curpressure;
|
|
|
|
paint_core->lastxtilt = paint_core->curxtilt;
|
|
|
|
paint_core->lastytilt = paint_core->curytilt;
|
1999-09-04 22:42:43 +08:00
|
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
|
|
|
paint_core->lastwheel = paint_core->curwheel;
|
|
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
else
|
Overhaul of pixmap brushes and pipes: No separate pixmap pipe
brush tool any longer. The paintbrush, airbrush and pencil
tools, which already knew how to handle the single-pixmap
brushes now also handle the pipes as well.
* app/pixmapbrush.{h,c}
* app/gimpbrushpixmap.{h,c}: Removed these files.
* app/Makefile.am
* app/makefile.{cygwin,msc}: Remove from here, too.
* app/gimpbrushpipe.{h,c}: Total overhaul.
* app/paint_core.h
* app/apptypes.h: Some more types moved to apptypes.h
* app/context_manager.c
* app/tool_options.c
* app/tools.c
* app/toolsF.h: Remove PIXMAPBRUSH tool.
* app/gimpbrush.h: New method: select_brush. Used to change the
brush in paint_core, for pipe brushes.
* app/gimpbrush.c: Add gimp_brush_select_brush, which is dummy for
the normal brushes (returns the same brush).
* app/paint_core.c: Call the brush's select_brush method to get a
potential new brush before calling the paint_func.
* app/gimpbrushlist.c: Various changes related to the pixmap and
pipe overhaul.
* app/airbrush.c
* app/pencil.c: Reorder code a bit in the tool motion function to
avoid executing unnecessary code in the case of a pixmap brush.
Other changes in the same commit:
* app/install.c: Make quote_spaces extern.
* app/appenv.h: Declare it.
* libgimp/gimpui.def: Add missing entry points.
* libgimp/makefile.{cygwin,msc}: Add missing objects to gimpui.
1999-08-26 08:54:30 +08:00
|
|
|
{
|
1999-08-31 05:24:13 +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 (paint_core->lastx != paint_core->curx
|
|
|
|
|| paint_core->lasty != paint_core->cury
|
|
|
|
|| (* GIMP_BRUSH_CLASS (GTK_OBJECT (paint_core->brush)
|
|
|
|
->klass)->want_null_motion) (paint_core))
|
|
|
|
{
|
|
|
|
if (paint_core->flags & TOOL_CAN_HANDLE_CHANGING_BRUSH)
|
|
|
|
paint_core->brush =
|
|
|
|
(* GIMP_BRUSH_CLASS (GTK_OBJECT (paint_core->brush)
|
|
|
|
->klass)->select_brush) (paint_core);
|
|
|
|
(* paint_core->paint_func) (paint_core, drawable, MOTION_PAINT);
|
|
|
|
}
|
Overhaul of pixmap brushes and pipes: No separate pixmap pipe
brush tool any longer. The paintbrush, airbrush and pencil
tools, which already knew how to handle the single-pixmap
brushes now also handle the pipes as well.
* app/pixmapbrush.{h,c}
* app/gimpbrushpixmap.{h,c}: Removed these files.
* app/Makefile.am
* app/makefile.{cygwin,msc}: Remove from here, too.
* app/gimpbrushpipe.{h,c}: Total overhaul.
* app/paint_core.h
* app/apptypes.h: Some more types moved to apptypes.h
* app/context_manager.c
* app/tool_options.c
* app/tools.c
* app/toolsF.h: Remove PIXMAPBRUSH tool.
* app/gimpbrush.h: New method: select_brush. Used to change the
brush in paint_core, for pipe brushes.
* app/gimpbrush.c: Add gimp_brush_select_brush, which is dummy for
the normal brushes (returns the same brush).
* app/paint_core.c: Call the brush's select_brush method to get a
potential new brush before calling the paint_func.
* app/gimpbrushlist.c: Various changes related to the pixmap and
pipe overhaul.
* app/airbrush.c
* app/pencil.c: Reorder code a bit in the tool motion function to
avoid executing unnecessary code in the case of a pixmap brush.
Other changes in the same commit:
* app/install.c: Make quote_spaces extern.
* app/appenv.h: Declare it.
* libgimp/gimpui.def: Add missing entry points.
* libgimp/makefile.{cygwin,msc}: Add missing objects to gimpui.
1999-08-26 08:54:30 +08:00
|
|
|
}
|
1999-12-26 05:32:52 +08:00
|
|
|
if (paint_core->flags & TOOL_TRACES_ON_WINDOW)
|
|
|
|
(* paint_core->paint_func) (paint_core, drawable, PRETRACE_PAINT);
|
1998-10-05 04:16:17 +08:00
|
|
|
gdisplay_flush_now (gdisp);
|
1999-12-26 05:32:52 +08:00
|
|
|
if (paint_core->flags & TOOL_TRACES_ON_WINDOW)
|
|
|
|
(* paint_core->paint_func) (paint_core, drawable, POSTTRACE_PAINT);
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_core_button_release (Tool *tool,
|
|
|
|
GdkEventButton *bevent,
|
|
|
|
gpointer gdisp_ptr)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
GDisplay * gdisp;
|
|
|
|
GImage * gimage;
|
|
|
|
PaintCore * paint_core;
|
|
|
|
|
|
|
|
gdisp = (GDisplay *) gdisp_ptr;
|
|
|
|
gimage = gdisp->gimage;
|
|
|
|
paint_core = (PaintCore *) tool->private;
|
|
|
|
|
|
|
|
/* resume the current selection and ungrab the pointer */
|
1998-06-29 08:24:44 +08:00
|
|
|
gdisplays_selection_visibility (gdisp->gimage, SelectionResume);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
gdk_pointer_ungrab (bevent->time);
|
|
|
|
gdk_flush ();
|
|
|
|
|
|
|
|
/* Let the specific painting function finish up */
|
|
|
|
(* paint_core->paint_func) (paint_core, gimage_active_drawable (gdisp->gimage), FINISH_PAINT);
|
|
|
|
|
|
|
|
/* Set tool state to inactive -- no longer painting */
|
1999-05-15 08:02:47 +08:00
|
|
|
draw_core_stop (paint_core->core, tool);
|
1997-11-25 06:05:25 +08:00
|
|
|
tool->state = INACTIVE;
|
|
|
|
|
1999-05-13 19:12:32 +08:00
|
|
|
paint_core->pick_state = FALSE;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
paint_core_finish (paint_core, gimage_active_drawable (gdisp->gimage), tool->ID);
|
|
|
|
gdisplays_flush ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_core_motion (Tool *tool,
|
|
|
|
GdkEventMotion *mevent,
|
|
|
|
gpointer gdisp_ptr)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
GDisplay * gdisp;
|
|
|
|
PaintCore * paint_core;
|
|
|
|
|
|
|
|
gdisp = (GDisplay *) gdisp_ptr;
|
|
|
|
paint_core = (PaintCore *) tool->private;
|
|
|
|
|
|
|
|
gdisplay_untransform_coords_f (gdisp, (double) mevent->x, (double) mevent->y,
|
|
|
|
&paint_core->curx, &paint_core->cury, TRUE);
|
1999-05-13 19:12:32 +08:00
|
|
|
|
|
|
|
if (paint_core->pick_state)
|
|
|
|
{
|
1999-05-15 08:02:47 +08:00
|
|
|
paint_core_sample_color (gimage_active_drawable (gdisp->gimage),
|
|
|
|
paint_core->curx, paint_core->cury, mevent->state);
|
1999-05-13 19:12:32 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1998-06-06 11:49:01 +08:00
|
|
|
paint_core->curpressure = mevent->pressure;
|
|
|
|
paint_core->curxtilt = mevent->xtilt;
|
|
|
|
paint_core->curytilt = mevent->ytilt;
|
1999-09-04 22:42:43 +08:00
|
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
|
|
|
paint_core->curwheel = mevent->wheel;
|
|
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
1997-11-25 06:05:25 +08:00
|
|
|
paint_core->state = mevent->state;
|
|
|
|
|
|
|
|
paint_core_interpolate (paint_core, gimage_active_drawable (gdisp->gimage));
|
|
|
|
|
1999-12-26 05:32:52 +08:00
|
|
|
if (paint_core->flags & TOOL_TRACES_ON_WINDOW)
|
Add gimpcolorspace object.
2000-01-04 Tor Lillqvist <tml@iki.fi>
* libgimp/makefile.{cygwin.msc}: Add gimpcolorspace object.
* libgimp/gimp.def: Add functions from it.
Fixes from Hans Breuer:
* app/datafiles.c: redefine the executable flag for Win32
to _S_IREAD, to get _all_ files from the plug-in dirs as
executables (including scripts)
* app/main.c: Win32-specific changes to allow building Gimp as a
console application, with all its benefits (like inheriting the
console), but hide it if the user doesn't want it. Also, if stdout
goes to a console, give the user a chance to read the help or
version messages. (tml: I am not convinced that it is better to
build gimp as a console application, but let's try it this way for
a while.)
* app/makefile.{cygwin,msc}: Build as console application, and
link with shell32 library.
* app/paint_core.c (paint_core_motion): Pass the value of a call
to the function gimage_active_drawable() to the paint_func,
instead of just passing the address of gimage_active_drawable...
(tml: This code is only called when the TOOL_TRACES_ON_WINDOW flag
is on, and only the clone tool sets that, and the clone tool's
paint_func doesn't use the drawable argument, so this hasn't
caused any trouble.)
* app/plug_in.c: On Win32, to support scripts, use new function
xspawn() instead of _spawnv. Add some more code to properly kill
plug-ins.
* libgimp/color_display.h: Add G_MODULE_EXPORT declarations.
2000-01-05 01:46:41 +08:00
|
|
|
(* paint_core->paint_func) (paint_core, gimage_active_drawable (gdisp->gimage), PRETRACE_PAINT);
|
1998-10-05 04:16:17 +08:00
|
|
|
gdisplay_flush_now (gdisp);
|
1999-12-26 05:32:52 +08:00
|
|
|
if (paint_core->flags & TOOL_TRACES_ON_WINDOW)
|
Add gimpcolorspace object.
2000-01-04 Tor Lillqvist <tml@iki.fi>
* libgimp/makefile.{cygwin.msc}: Add gimpcolorspace object.
* libgimp/gimp.def: Add functions from it.
Fixes from Hans Breuer:
* app/datafiles.c: redefine the executable flag for Win32
to _S_IREAD, to get _all_ files from the plug-in dirs as
executables (including scripts)
* app/main.c: Win32-specific changes to allow building Gimp as a
console application, with all its benefits (like inheriting the
console), but hide it if the user doesn't want it. Also, if stdout
goes to a console, give the user a chance to read the help or
version messages. (tml: I am not convinced that it is better to
build gimp as a console application, but let's try it this way for
a while.)
* app/makefile.{cygwin,msc}: Build as console application, and
link with shell32 library.
* app/paint_core.c (paint_core_motion): Pass the value of a call
to the function gimage_active_drawable() to the paint_func,
instead of just passing the address of gimage_active_drawable...
(tml: This code is only called when the TOOL_TRACES_ON_WINDOW flag
is on, and only the clone tool sets that, and the clone tool's
paint_func doesn't use the drawable argument, so this hasn't
caused any trouble.)
* app/plug_in.c: On Win32, to support scripts, use new function
xspawn() instead of _spawnv. Add some more code to properly kill
plug-ins.
* libgimp/color_display.h: Add G_MODULE_EXPORT declarations.
2000-01-05 01:46:41 +08:00
|
|
|
(* paint_core->paint_func) (paint_core, gimage_active_drawable (gdisp->gimage), POSTTRACE_PAINT);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
paint_core->lastx = paint_core->curx;
|
|
|
|
paint_core->lasty = paint_core->cury;
|
1998-06-06 11:49:01 +08:00
|
|
|
paint_core->lastpressure = paint_core->curpressure;
|
|
|
|
paint_core->lastxtilt = paint_core->curxtilt;
|
|
|
|
paint_core->lastytilt = paint_core->curytilt;
|
1999-09-04 22:42:43 +08:00
|
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
|
|
|
paint_core->lastwheel = paint_core->curwheel;
|
|
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_core_cursor_update (Tool *tool,
|
|
|
|
GdkEventMotion *mevent,
|
|
|
|
gpointer gdisp_ptr)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
GDisplay *gdisp;
|
|
|
|
Layer *layer;
|
1999-05-13 19:12:32 +08:00
|
|
|
PaintCore * paint_core;
|
1997-11-25 06:05:25 +08:00
|
|
|
GdkCursorType ctype = GDK_TOP_LEFT_ARROW;
|
1999-05-15 08:36:42 +08:00
|
|
|
int x, y;
|
1999-09-02 02:46:25 +08:00
|
|
|
gchar status_str[STATUSBAR_SIZE];
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
gdisp = (GDisplay *) gdisp_ptr;
|
1999-05-13 19:12:32 +08:00
|
|
|
paint_core = (PaintCore *) tool->private;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-15 08:02:47 +08:00
|
|
|
/* undraw the current tool */
|
|
|
|
draw_core_pause (paint_core->core, tool);
|
1999-09-02 02:46:25 +08:00
|
|
|
if (paint_core->context_id)
|
|
|
|
gtk_statusbar_pop (GTK_STATUSBAR (gdisp->statusbar), paint_core->context_id);
|
1999-05-15 08:02:47 +08:00
|
|
|
|
1999-06-05 10:11:16 +08:00
|
|
|
if ((layer = gimage_get_active_layer (gdisp->gimage)))
|
1998-01-22 15:02:57 +08:00
|
|
|
{
|
1999-05-15 08:02:47 +08:00
|
|
|
/* If shift is down and this is not the first paint stroke, draw a line */
|
1999-06-18 04:34:50 +08:00
|
|
|
if (gdisp_ptr == tool->gdisp_ptr && (mevent->state & GDK_SHIFT_MASK))
|
1999-09-02 02:46:25 +08:00
|
|
|
{
|
|
|
|
gdouble dx, dy, d;
|
1999-08-21 21:16:20 +08:00
|
|
|
|
1999-09-02 02:46:25 +08:00
|
|
|
ctype = GDK_PENCIL;
|
1999-06-08 06:38:20 +08:00
|
|
|
/* Get the current coordinates */
|
|
|
|
gdisplay_untransform_coords_f (gdisp,
|
|
|
|
(double) mevent->x,
|
|
|
|
(double) mevent->y,
|
|
|
|
&paint_core->curx,
|
|
|
|
&paint_core->cury, TRUE);
|
1999-05-15 08:36:42 +08:00
|
|
|
|
1999-09-02 02:46:25 +08:00
|
|
|
dx = paint_core->curx - paint_core->lastx;
|
|
|
|
dy = paint_core->cury - paint_core->lasty;
|
|
|
|
|
1999-11-25 09:59:14 +08:00
|
|
|
/* Restrict to multiples of 15 degrees if ctrl is pressed */
|
|
|
|
if (mevent->state & GDK_CONTROL_MASK)
|
1999-06-18 04:34:50 +08:00
|
|
|
{
|
1999-11-25 09:59:14 +08:00
|
|
|
int idx = dx;
|
|
|
|
int idy = dy;
|
|
|
|
int tangens2[6] = { 34, 106, 196, 334, 618, 1944 };
|
|
|
|
int cosinus[7] = { 256, 247, 222, 181, 128, 66, 0 };
|
|
|
|
int i, radius, frac;
|
|
|
|
|
|
|
|
if (idy)
|
1999-06-18 04:34:50 +08:00
|
|
|
{
|
1999-11-25 09:59:14 +08:00
|
|
|
radius = sqrt (SQR (idx) + SQR (idy));
|
|
|
|
frac = abs ((idx << 8) / idy);
|
|
|
|
for (i = 0; i < 6; i++)
|
|
|
|
{
|
|
|
|
if (frac < tangens2[i])
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
dx = idx > 0 ? (cosinus[6-i] * radius) >> 8 : - ((cosinus[6-i] * radius) >> 8);
|
|
|
|
dy = idy > 0 ? (cosinus[i] * radius) >> 8 : - ((cosinus[i] * radius) >> 8);
|
1999-06-18 04:34:50 +08:00
|
|
|
}
|
1999-11-25 09:59:14 +08:00
|
|
|
|
|
|
|
paint_core->curx = paint_core->lastx + dx;
|
|
|
|
paint_core->cury = paint_core->lasty + dy;
|
1999-06-18 04:34:50 +08:00
|
|
|
}
|
|
|
|
|
1999-09-02 02:46:25 +08:00
|
|
|
/* show distance in statusbar */
|
|
|
|
if (gdisp->dot_for_dot)
|
|
|
|
{
|
|
|
|
d = sqrt (SQR (dx) + SQR (dy));
|
|
|
|
g_snprintf (status_str, STATUSBAR_SIZE, "%.1f %s", d, _("pixels"));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gchar *format_str = g_strdup_printf ("%%.%df %s",
|
|
|
|
gimp_unit_get_digits (gdisp->gimage->unit),
|
|
|
|
gimp_unit_get_symbol (gdisp->gimage->unit));
|
|
|
|
d = gimp_unit_get_factor (gdisp->gimage->unit) *
|
|
|
|
sqrt (SQR (dx / gdisp->gimage->xresolution) + SQR (dy / gdisp->gimage->yresolution));
|
|
|
|
|
|
|
|
g_snprintf (status_str, STATUSBAR_SIZE, format_str, d);
|
|
|
|
g_free (format_str);
|
|
|
|
}
|
|
|
|
gtk_statusbar_push (GTK_STATUSBAR (gdisp->statusbar), paint_core->context_id,
|
|
|
|
status_str);
|
|
|
|
|
1999-05-15 08:02:47 +08:00
|
|
|
if (paint_core->core->gc == NULL)
|
|
|
|
draw_core_start (paint_core->core, gdisp->canvas->window, tool);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* is this a bad hack ? */
|
|
|
|
paint_core->core->paused_count = 0;
|
|
|
|
draw_core_resume (paint_core->core, tool);
|
|
|
|
}
|
1999-06-03 23:02:48 +08:00
|
|
|
}
|
1999-06-08 06:38:20 +08:00
|
|
|
/* If Ctrl or Mod1 is pressed, pick colors */
|
|
|
|
else if (paint_core->pick_colors
|
|
|
|
&& !(mevent->state & GDK_SHIFT_MASK)
|
|
|
|
&& (mevent->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)))
|
|
|
|
{
|
|
|
|
ctype = GIMP_COLOR_PICKER_CURSOR;
|
|
|
|
}
|
1999-06-03 23:02:48 +08:00
|
|
|
/* Normal operation -- no modifier pressed or first stroke */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int off_x, off_y;
|
|
|
|
|
1999-06-08 06:38:20 +08:00
|
|
|
drawable_offsets (GIMP_DRAWABLE(layer), &off_x, &off_y);
|
|
|
|
gdisplay_untransform_coords (gdisp, (double) mevent->x, (double) mevent->y,
|
|
|
|
&x, &y, TRUE, FALSE);
|
|
|
|
|
1999-06-03 23:02:48 +08:00
|
|
|
if (x >= off_x && y >= off_y &&
|
|
|
|
x < (off_x + drawable_width (GIMP_DRAWABLE(layer))) &&
|
|
|
|
y < (off_y + drawable_height (GIMP_DRAWABLE(layer))))
|
|
|
|
{
|
|
|
|
/* One more test--is there a selected region?
|
|
|
|
* if so, is cursor inside?
|
|
|
|
*/
|
|
|
|
if (gimage_mask_is_empty (gdisp->gimage))
|
|
|
|
ctype = GDK_PENCIL;
|
|
|
|
else if (gimage_mask_value (gdisp->gimage, x, y))
|
|
|
|
ctype = GDK_PENCIL;
|
|
|
|
}
|
1999-05-15 08:02:47 +08:00
|
|
|
}
|
1999-06-08 06:38:20 +08:00
|
|
|
gdisplay_install_tool_cursor (gdisp, ctype);
|
1998-01-22 15:02:57 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-06-22 06:12:07 +08:00
|
|
|
paint_core_control (Tool *tool,
|
|
|
|
ToolAction action,
|
|
|
|
gpointer gdisp_ptr)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
PaintCore * paint_core;
|
|
|
|
GDisplay *gdisp;
|
1998-01-22 15:02:57 +08:00
|
|
|
GimpDrawable *drawable;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
gdisp = (GDisplay *) gdisp_ptr;
|
|
|
|
paint_core = (PaintCore *) tool->private;
|
1998-01-22 15:02:57 +08:00
|
|
|
drawable = gimage_active_drawable (gdisp->gimage);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
switch (action)
|
|
|
|
{
|
1999-06-22 06:12:07 +08:00
|
|
|
case PAUSE:
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
1999-06-22 06:12:07 +08:00
|
|
|
|
|
|
|
case RESUME:
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
1999-06-22 06:12:07 +08:00
|
|
|
|
|
|
|
case HALT:
|
1998-01-22 15:02:57 +08:00
|
|
|
(* paint_core->paint_func) (paint_core, drawable, FINISH_PAINT);
|
1999-05-15 08:02:47 +08:00
|
|
|
draw_core_stop (paint_core->core, tool);
|
1997-11-25 06:05:25 +08:00
|
|
|
paint_core_cleanup ();
|
|
|
|
break;
|
1999-06-22 06:12:07 +08:00
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_core_draw (Tool *tool)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-05-15 08:02:47 +08:00
|
|
|
GDisplay *gdisp;
|
|
|
|
PaintCore * paint_core;
|
1999-05-15 08:36:42 +08:00
|
|
|
int tx1, ty1, tx2, ty2;
|
1999-05-15 08:02:47 +08:00
|
|
|
|
|
|
|
paint_core = (PaintCore *) tool->private;
|
|
|
|
|
1999-06-08 06:38:20 +08:00
|
|
|
/* if shift was never used, paint_core->core->gc is NULL
|
|
|
|
and we don't care about a redraw */
|
1999-05-15 08:02:47 +08:00
|
|
|
if (paint_core->core->gc != NULL)
|
|
|
|
{
|
|
|
|
gdisp = (GDisplay *) tool->gdisp_ptr;
|
|
|
|
|
1999-05-15 08:36:42 +08:00
|
|
|
gdisplay_transform_coords (gdisp, paint_core->lastx, paint_core->lasty,
|
|
|
|
&tx1, &ty1, 1);
|
|
|
|
gdisplay_transform_coords (gdisp, paint_core->curx, paint_core->cury,
|
|
|
|
&tx2, &ty2, 1);
|
|
|
|
|
1999-05-15 08:02:47 +08:00
|
|
|
/* Draw start target */
|
|
|
|
gdk_draw_line (gdisp->canvas->window, paint_core->core->gc,
|
1999-05-15 08:36:42 +08:00
|
|
|
tx1 - (TARGET_WIDTH >> 1), ty1,
|
|
|
|
tx1 + (TARGET_WIDTH >> 1), ty1);
|
1999-05-15 08:02:47 +08:00
|
|
|
gdk_draw_line (gdisp->canvas->window, paint_core->core->gc,
|
1999-05-15 08:36:42 +08:00
|
|
|
tx1, ty1 - (TARGET_HEIGHT >> 1),
|
|
|
|
tx1, ty1 + (TARGET_HEIGHT >> 1));
|
1999-05-15 08:02:47 +08:00
|
|
|
|
|
|
|
/* Draw end target */
|
|
|
|
gdk_draw_line (gdisp->canvas->window, paint_core->core->gc,
|
1999-05-15 08:36:42 +08:00
|
|
|
tx2 - (TARGET_WIDTH >> 1), ty2,
|
|
|
|
tx2 + (TARGET_WIDTH >> 1), ty2);
|
1999-05-15 08:02:47 +08:00
|
|
|
gdk_draw_line (gdisp->canvas->window, paint_core->core->gc,
|
1999-05-15 08:36:42 +08:00
|
|
|
tx2, ty2 - (TARGET_HEIGHT >> 1),
|
|
|
|
tx2, ty2 + (TARGET_HEIGHT >> 1));
|
1999-05-15 08:02:47 +08:00
|
|
|
|
|
|
|
/* Draw the line between the start and end coords */
|
|
|
|
gdk_draw_line (gdisp->canvas->window, paint_core->core->gc,
|
1999-05-15 08:36:42 +08:00
|
|
|
tx1, ty1, tx2, ty2);
|
1999-05-15 08:02:47 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
return;
|
1999-05-15 08:02:47 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
Tool *
|
1999-07-03 01:40:10 +08:00
|
|
|
paint_core_new (ToolType type)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
Tool * tool;
|
|
|
|
PaintCore * private;
|
|
|
|
|
1999-07-03 01:40:10 +08:00
|
|
|
tool = tools_new_tool (type);
|
|
|
|
private = g_new (PaintCore, 1);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-05-15 08:02:47 +08:00
|
|
|
private->core = draw_core_new (paint_core_draw);
|
1999-05-15 20:13:43 +08:00
|
|
|
|
1999-05-13 19:12:32 +08:00
|
|
|
private->pick_colors = FALSE;
|
1999-08-27 05:33:58 +08:00
|
|
|
private->flags = 0;
|
1999-09-02 02:46:25 +08:00
|
|
|
private->context_id = 0;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
tool->private = (void *) private;
|
1999-06-26 19:16:47 +08:00
|
|
|
|
1999-07-03 01:40:10 +08:00
|
|
|
tool->button_press_func = paint_core_button_press;
|
1997-11-25 06:05:25 +08:00
|
|
|
tool->button_release_func = paint_core_button_release;
|
1999-07-03 01:40:10 +08:00
|
|
|
tool->motion_func = paint_core_motion;
|
|
|
|
tool->cursor_update_func = paint_core_cursor_update;
|
|
|
|
tool->control_func = paint_core_control;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
return tool;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_core_free (Tool *tool)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
PaintCore * paint_core;
|
|
|
|
|
|
|
|
paint_core = (PaintCore *) tool->private;
|
|
|
|
|
|
|
|
/* Make sure the selection core is not visible */
|
|
|
|
if (tool->state == ACTIVE && paint_core->core)
|
|
|
|
draw_core_stop (paint_core->core, tool);
|
|
|
|
|
|
|
|
/* Free the selection core */
|
|
|
|
if (paint_core->core)
|
|
|
|
draw_core_free (paint_core->core);
|
|
|
|
|
|
|
|
/* Cleanup memory */
|
|
|
|
paint_core_cleanup ();
|
|
|
|
|
|
|
|
/* Free the paint core */
|
|
|
|
g_free (paint_core);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_core_init (PaintCore *paint_core,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
double x,
|
|
|
|
double y)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-11-14 18:50:19 +08:00
|
|
|
static GimpBrush *brush = NULL;
|
1998-07-10 16:59:55 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
paint_core->curx = x;
|
|
|
|
paint_core->cury = y;
|
|
|
|
|
1998-06-06 11:49:01 +08:00
|
|
|
/* Set up some defaults for non-gui use */
|
1999-09-02 04:16:18 +08:00
|
|
|
if (paint_core == &non_gui_paint_core)
|
|
|
|
{
|
|
|
|
paint_core->startpressure = paint_core->lastpressure = paint_core->curpressure = 0.5;
|
|
|
|
paint_core->startxtilt = paint_core->lastxtilt = paint_core->curxtilt = 0;
|
|
|
|
paint_core->startytilt = paint_core->lastytilt = paint_core->curytilt = 0;
|
1999-09-05 01:56:22 +08:00
|
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
1999-09-04 22:42:43 +08:00
|
|
|
paint_core->startwheel = paint_core->lastwheel = paint_core->curwheel = 0.5;
|
1999-09-05 02:37:42 +08:00
|
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
1999-09-02 04:16:18 +08:00
|
|
|
}
|
1998-06-06 11:49:01 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
/* Each buffer is the same size as the maximum bounds of the active brush... */
|
1999-10-27 02:27:27 +08:00
|
|
|
if (brush && brush != gimp_context_get_brush (NULL))
|
|
|
|
{
|
|
|
|
gtk_signal_disconnect_by_func (GTK_OBJECT (brush),
|
|
|
|
GTK_SIGNAL_FUNC (paint_core_invalidate_cache),
|
|
|
|
NULL);
|
|
|
|
gtk_object_unref (GTK_OBJECT (brush));
|
|
|
|
}
|
|
|
|
if (!(brush = gimp_context_get_brush (NULL)))
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-12-16 08:37:09 +08:00
|
|
|
g_message (_("No brushes available for use with this tool."));
|
1997-11-25 06:05:25 +08:00
|
|
|
return FALSE;
|
|
|
|
}
|
1999-10-27 02:27:27 +08:00
|
|
|
gtk_object_ref (GTK_OBJECT (brush));
|
|
|
|
gtk_signal_connect (GTK_OBJECT (brush), "dirty",
|
|
|
|
GTK_SIGNAL_FUNC (paint_core_invalidate_cache),
|
|
|
|
NULL);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-04-22 22:34:00 +08:00
|
|
|
paint_core->spacing = (double) gimp_brush_get_spacing (brush) / 100.0;
|
1999-07-26 15:24:47 +08:00
|
|
|
|
1998-07-24 16:56:18 +08:00
|
|
|
paint_core->brush = brush;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* free the block structures */
|
|
|
|
if (undo_tiles)
|
|
|
|
tile_manager_destroy (undo_tiles);
|
|
|
|
if (canvas_tiles)
|
|
|
|
tile_manager_destroy (canvas_tiles);
|
|
|
|
|
|
|
|
/* Allocate the undo structure */
|
1998-01-22 15:02:57 +08:00
|
|
|
undo_tiles = tile_manager_new (drawable_width (drawable),
|
|
|
|
drawable_height (drawable),
|
|
|
|
drawable_bytes (drawable));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Allocate the canvas blocks structure */
|
1998-01-22 15:02:57 +08:00
|
|
|
canvas_tiles = tile_manager_new (drawable_width (drawable),
|
|
|
|
drawable_height (drawable), 1);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Get the initial undo extents */
|
|
|
|
paint_core->x1 = paint_core->x2 = paint_core->curx;
|
|
|
|
paint_core->y1 = paint_core->y2 = paint_core->cury;
|
|
|
|
paint_core->distance = 0.0;
|
1999-09-26 03:49:58 +08:00
|
|
|
paint_core->pixel_dist = 0.0;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
1999-03-19 08:42:27 +08:00
|
|
|
void
|
1999-05-15 08:02:47 +08:00
|
|
|
paint_core_get_color_from_gradient (PaintCore *paint_core,
|
1999-09-26 03:49:58 +08:00
|
|
|
double gradient_length,
|
|
|
|
double *r,
|
|
|
|
double *g,
|
|
|
|
double *b,
|
|
|
|
double *a,
|
|
|
|
int mode)
|
1999-03-19 08:42:27 +08:00
|
|
|
{
|
|
|
|
double y;
|
1999-09-09 09:47:54 +08:00
|
|
|
double distance; /* distance in current brush stroke */
|
1999-03-19 08:42:27 +08:00
|
|
|
|
1999-09-26 03:49:58 +08:00
|
|
|
distance = paint_core->pixel_dist;
|
1999-03-19 08:42:27 +08:00
|
|
|
y = ((double) distance / gradient_length);
|
|
|
|
|
1999-12-23 05:15:58 +08:00
|
|
|
/* for the once modes, set y close to 1.0 after the first chunk */
|
|
|
|
if ( (mode == ONCE_FORWARD || mode == ONCE_BACKWARDS) && y >= 1.0 )
|
|
|
|
y = 0.9999999;
|
1999-03-19 08:42:27 +08:00
|
|
|
|
1999-12-23 05:15:58 +08:00
|
|
|
if ( (((int)y & 1) && mode != LOOP_SAWTOOTH) || mode == ONCE_BACKWARDS )
|
1999-09-26 03:49:58 +08:00
|
|
|
y = 1.0 - (y - (int)y);
|
1999-03-19 08:42:27 +08:00
|
|
|
else
|
1999-09-26 03:49:58 +08:00
|
|
|
y = y - (int)y;
|
1999-03-19 08:42:27 +08:00
|
|
|
|
1999-10-27 02:27:27 +08:00
|
|
|
gradient_get_color_at (gimp_context_get_gradient (NULL), y, r, g, b, a);
|
1999-03-19 08:42:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
void
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_core_interpolate (PaintCore *paint_core,
|
|
|
|
GimpDrawable *drawable)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-07-23 07:11:46 +08:00
|
|
|
double n;
|
1998-07-24 16:56:18 +08:00
|
|
|
vector2d delta;
|
1999-09-04 22:42:43 +08:00
|
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
|
|
|
double dpressure, dxtilt, dytilt, dwheel;
|
|
|
|
#else /* !GTK_HAVE_SIX_VALUATORS */
|
1998-07-24 16:56:18 +08:00
|
|
|
double dpressure, dxtilt, dytilt;
|
1999-09-04 22:42:43 +08:00
|
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
1999-09-26 03:49:58 +08:00
|
|
|
/* double spacing; */
|
|
|
|
/* double lastscale, curscale; */
|
1997-11-25 06:05:25 +08:00
|
|
|
double left;
|
|
|
|
double t;
|
|
|
|
double initial;
|
|
|
|
double dist;
|
|
|
|
double total;
|
1999-09-26 03:49:58 +08:00
|
|
|
double pixel_dist;
|
|
|
|
double pixel_initial;
|
1998-07-24 16:56:18 +08:00
|
|
|
double xd, yd;
|
|
|
|
double mag;
|
|
|
|
delta.x = paint_core->curx - paint_core->lastx;
|
|
|
|
delta.y = paint_core->cury - paint_core->lasty;
|
1998-06-06 11:49:01 +08:00
|
|
|
dpressure = paint_core->curpressure - paint_core->lastpressure;
|
|
|
|
dxtilt = paint_core->curxtilt - paint_core->lastxtilt;
|
|
|
|
dytilt = paint_core->curytilt - paint_core->lastytilt;
|
1999-09-04 22:42:43 +08:00
|
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
|
|
|
dwheel = paint_core->curwheel - paint_core->lastwheel;
|
|
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-07-26 15:24:47 +08:00
|
|
|
/* return if there has been no motion */
|
1999-09-04 22:42:43 +08:00
|
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
|
|
|
if (!delta.x && !delta.y && !dpressure && !dxtilt && !dytilt && !dwheel)
|
|
|
|
#else /* !GTK_HAVE_SIX_VALUATORS */
|
1998-07-24 16:56:18 +08:00
|
|
|
if (!delta.x && !delta.y && !dpressure && !dxtilt && !dytilt)
|
1999-09-04 22:42:43 +08:00
|
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
1997-11-25 06:05:25 +08:00
|
|
|
return;
|
1999-07-23 07:11:46 +08:00
|
|
|
|
1999-07-26 15:24:47 +08:00
|
|
|
/* calculate the distance traveled in the coordinate space of the brush */
|
1998-07-24 16:56:18 +08:00
|
|
|
mag = vector2d_magnitude (&(paint_core->brush->x_axis));
|
|
|
|
xd = vector2d_dot_product(&delta, &(paint_core->brush->x_axis)) / (mag*mag);
|
|
|
|
|
|
|
|
mag = vector2d_magnitude (&(paint_core->brush->y_axis));
|
1999-07-26 15:24:47 +08:00
|
|
|
yd = vector2d_dot_product(&delta, &(paint_core->brush->y_axis)) / (mag*mag);
|
1998-07-24 16:56:18 +08:00
|
|
|
|
1999-09-26 03:49:58 +08:00
|
|
|
dist = 0.5 * sqrt (xd*xd + yd*yd);
|
1997-11-25 06:05:25 +08:00
|
|
|
total = dist + paint_core->distance;
|
|
|
|
initial = paint_core->distance;
|
|
|
|
|
1999-09-26 03:49:58 +08:00
|
|
|
pixel_dist = vector2d_magnitude (&delta);
|
|
|
|
pixel_initial = paint_core->pixel_dist;
|
|
|
|
|
|
|
|
/* FIXME: need to adapt the spacing to the size */
|
|
|
|
/* lastscale = MIN (paint_core->lastpressure, 1/256); */
|
|
|
|
/* curscale = MIN (paint_core->curpressure, 1/256); */
|
|
|
|
/* spacing = paint_core->spacing * sqrt (0.5 * (lastscale + curscale)); */
|
1999-09-09 09:47:54 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
while (paint_core->distance < total)
|
|
|
|
{
|
|
|
|
n = (int) (paint_core->distance / paint_core->spacing + 1.0 + EPSILON);
|
|
|
|
left = n * paint_core->spacing - paint_core->distance;
|
1999-09-26 03:49:58 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
paint_core->distance += left;
|
|
|
|
|
1999-07-23 07:11:46 +08:00
|
|
|
if (paint_core->distance <= (total+EPSILON))
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
t = (paint_core->distance - initial) / dist;
|
|
|
|
|
1998-07-24 16:56:18 +08:00
|
|
|
paint_core->curx = paint_core->lastx + delta.x * t;
|
|
|
|
paint_core->cury = paint_core->lasty + delta.y * t;
|
1999-09-26 03:49:58 +08:00
|
|
|
paint_core->pixel_dist = pixel_initial + pixel_dist * t;
|
1998-06-06 11:49:01 +08:00
|
|
|
paint_core->curpressure = paint_core->lastpressure + dpressure * t;
|
|
|
|
paint_core->curxtilt = paint_core->lastxtilt + dxtilt * t;
|
|
|
|
paint_core->curytilt = paint_core->lastytilt + dytilt * t;
|
1999-09-04 22:42:43 +08:00
|
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
|
|
|
paint_core->curwheel = paint_core->lastwheel + dwheel * t;
|
|
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
1999-08-27 05:33:58 +08:00
|
|
|
if (paint_core->flags & TOOL_CAN_HANDLE_CHANGING_BRUSH)
|
|
|
|
paint_core->brush =
|
|
|
|
(* GIMP_BRUSH_CLASS (GTK_OBJECT (paint_core->brush)
|
|
|
|
->klass)->select_brush) (paint_core);
|
1998-01-22 15:02:57 +08:00
|
|
|
(* paint_core->paint_func) (paint_core, drawable, MOTION_PAINT);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
paint_core->distance = total;
|
1999-09-26 03:49:58 +08:00
|
|
|
paint_core->pixel_dist = pixel_initial + pixel_dist;
|
1998-07-24 16:56:18 +08:00
|
|
|
paint_core->curx = paint_core->lastx + delta.x;
|
|
|
|
paint_core->cury = paint_core->lasty + delta.y;
|
1998-06-06 11:49:01 +08:00
|
|
|
paint_core->curpressure = paint_core->lastpressure + dpressure;
|
|
|
|
paint_core->curxtilt = paint_core->lastxtilt + dxtilt;
|
|
|
|
paint_core->curytilt = paint_core->lastytilt + dytilt;
|
1999-09-04 22:42:43 +08:00
|
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
|
|
|
paint_core->curwheel = paint_core->lastwheel + dwheel;
|
|
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_core_finish (PaintCore *paint_core,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
int tool_id)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
GImage *gimage;
|
|
|
|
PaintUndo *pu;
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
if (! (gimage = drawable_gimage (drawable)))
|
1997-11-25 06:05:25 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* Determine if any part of the image has been altered--
|
|
|
|
* if nothing has, then just return...
|
|
|
|
*/
|
1998-06-06 11:49:01 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
if ((paint_core->x2 == paint_core->x1) || (paint_core->y2 == paint_core->y1))
|
|
|
|
return;
|
|
|
|
|
|
|
|
undo_push_group_start (gimage, PAINT_CORE_UNDO);
|
|
|
|
|
|
|
|
pu = (PaintUndo *) g_malloc (sizeof (PaintUndo));
|
|
|
|
pu->tool_ID = tool_id;
|
|
|
|
pu->lastx = paint_core->startx;
|
|
|
|
pu->lasty = paint_core->starty;
|
1998-06-06 11:49:01 +08:00
|
|
|
pu->lastpressure = paint_core->startpressure;
|
|
|
|
pu->lastxtilt = paint_core->startxtilt;
|
|
|
|
pu->lastytilt = paint_core->startytilt;
|
1999-09-04 22:42:43 +08:00
|
|
|
#ifdef GTK_HAVE_SIX_VALUATORS
|
|
|
|
pu->lastwheel = paint_core->startwheel;
|
|
|
|
#endif /* GTK_HAVE_SIX_VALUATORS */
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* Push a paint undo */
|
|
|
|
undo_push_paint (gimage, pu);
|
|
|
|
|
|
|
|
/* push an undo */
|
1998-01-22 15:02:57 +08:00
|
|
|
drawable_apply_image (drawable, paint_core->x1, paint_core->y1,
|
1997-11-25 06:05:25 +08:00
|
|
|
paint_core->x2, paint_core->y2, undo_tiles, TRUE);
|
|
|
|
undo_tiles = NULL;
|
|
|
|
|
|
|
|
/* push the group end */
|
|
|
|
undo_push_group_end (gimage);
|
|
|
|
|
|
|
|
/* invalidate the drawable--have to do it here, because
|
|
|
|
* it is not done during the actual painting.
|
|
|
|
*/
|
1998-01-22 15:02:57 +08:00
|
|
|
drawable_invalidate_preview (drawable);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
paint_core_cleanup ()
|
|
|
|
{
|
|
|
|
/* CLEANUP */
|
|
|
|
/* If the undo tiles exist, nuke them */
|
|
|
|
if (undo_tiles)
|
|
|
|
{
|
|
|
|
tile_manager_destroy (undo_tiles);
|
|
|
|
undo_tiles = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the canvas blocks exist, nuke them */
|
|
|
|
if (canvas_tiles)
|
|
|
|
{
|
|
|
|
tile_manager_destroy (canvas_tiles);
|
|
|
|
canvas_tiles = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free the temporary buffers if they exist */
|
|
|
|
free_paint_buffers ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************/
|
|
|
|
/* Painting functions */
|
|
|
|
/************************/
|
|
|
|
|
|
|
|
TempBuf *
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_core_get_paint_area (PaintCore *paint_core,
|
1999-09-09 09:47:54 +08:00
|
|
|
GimpDrawable *drawable,
|
|
|
|
gdouble scale)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
int x, y;
|
|
|
|
int x1, y1, x2, y2;
|
|
|
|
int bytes;
|
1998-07-25 02:52:03 +08:00
|
|
|
int dwidth, dheight;
|
1999-09-09 09:47:54 +08:00
|
|
|
int bwidth, bheight;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
bytes = drawable_has_alpha (drawable) ?
|
|
|
|
drawable_bytes (drawable) : drawable_bytes (drawable) + 1;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-09-09 09:47:54 +08:00
|
|
|
paint_core_calculate_brush_size (paint_core->brush->mask, scale,
|
|
|
|
&bwidth, &bheight);
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
/* adjust the x and y coordinates to the upper left corner of the brush */
|
1999-09-09 09:47:54 +08:00
|
|
|
x = (int) paint_core->curx - (bwidth >> 1);
|
|
|
|
y = (int) paint_core->cury - (bheight >> 1);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-07-25 02:52:03 +08:00
|
|
|
dwidth = drawable_width (drawable);
|
|
|
|
dheight = drawable_height (drawable);
|
|
|
|
|
|
|
|
x1 = BOUNDS (x - 1, 0, dwidth);
|
|
|
|
y1 = BOUNDS (y - 1, 0, dheight);
|
1999-09-09 09:47:54 +08:00
|
|
|
x2 = BOUNDS (x + bwidth + 1, 0, dwidth);
|
|
|
|
y2 = BOUNDS (y + bheight + 1, 0, dheight);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* configure the canvas buffer */
|
|
|
|
if ((x2 - x1) && (y2 - y1))
|
|
|
|
canvas_buf = temp_buf_resize (canvas_buf, bytes, x1, y1,
|
|
|
|
(x2 - x1), (y2 - y1));
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return canvas_buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
TempBuf *
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_core_get_orig_image (PaintCore *paint_core,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
int x1, int y1, int x2, int y2)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
PixelRegion srcPR, destPR;
|
|
|
|
Tile *undo_tile;
|
|
|
|
int h;
|
1998-07-10 12:33:21 +08:00
|
|
|
int refd;
|
1997-11-25 06:05:25 +08:00
|
|
|
int pixelwidth;
|
1998-07-25 02:52:03 +08:00
|
|
|
int dwidth, dheight;
|
1997-11-25 06:05:25 +08:00
|
|
|
unsigned char * s, * d;
|
|
|
|
void * pr;
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
orig_buf = temp_buf_resize (orig_buf, drawable_bytes (drawable),
|
1997-11-25 06:05:25 +08:00
|
|
|
x1, y1, (x2 - x1), (y2 - y1));
|
1998-07-25 02:52:03 +08:00
|
|
|
|
|
|
|
dwidth = drawable_width (drawable);
|
|
|
|
dheight = drawable_height (drawable);
|
|
|
|
|
|
|
|
x1 = BOUNDS (x1, 0, dwidth);
|
|
|
|
y1 = BOUNDS (y1, 0, dheight);
|
|
|
|
x2 = BOUNDS (x2, 0, dwidth);
|
|
|
|
y2 = BOUNDS (y2, 0, dheight);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* configure the pixel regions */
|
1998-07-25 02:52:03 +08:00
|
|
|
pixel_region_init (&srcPR, drawable_data (drawable), x1, y1,
|
|
|
|
(x2 - x1), (y2 - y1), FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
destPR.bytes = orig_buf->bytes;
|
|
|
|
destPR.x = 0; destPR.y = 0;
|
|
|
|
destPR.w = (x2 - x1); destPR.h = (y2 - y1);
|
|
|
|
destPR.rowstride = orig_buf->bytes * orig_buf->width;
|
|
|
|
destPR.data = temp_buf_data (orig_buf) +
|
|
|
|
(y1 - orig_buf->y) * destPR.rowstride + (x1 - orig_buf->x) * destPR.bytes;
|
|
|
|
|
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 */
|
1998-07-25 02:52:03 +08:00
|
|
|
undo_tile = tile_manager_get_tile (undo_tiles, 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;
|
1998-07-25 02:52:03 +08:00
|
|
|
undo_tile = tile_manager_get_tile (undo_tiles, 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
|
|
|
}
|
|
|
|
|
|
|
|
return orig_buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
paint_core_paste_canvas (PaintCore *paint_core,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
int brush_opacity,
|
|
|
|
int image_opacity,
|
|
|
|
LayerModeEffects paint_mode,
|
1999-09-09 09:47:54 +08:00
|
|
|
BrushApplicationMode brush_hardness,
|
|
|
|
gdouble brush_scale,
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
PaintApplicationMode mode)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
MaskBuf *brush_mask;
|
|
|
|
|
|
|
|
/* get the brush mask */
|
1999-09-09 09:47:54 +08:00
|
|
|
brush_mask = paint_core_get_brush_mask (paint_core, brush_hardness, brush_scale);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* paste the canvas buf */
|
1998-01-22 15:02:57 +08:00
|
|
|
paint_core_paste (paint_core, brush_mask, drawable,
|
1997-11-25 06:05:25 +08:00
|
|
|
brush_opacity, image_opacity, paint_mode, mode);
|
|
|
|
}
|
|
|
|
|
1997-12-08 09:13:10 +08:00
|
|
|
/* Similar to 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. */
|
|
|
|
void
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
paint_core_replace_canvas (PaintCore *paint_core,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
int brush_opacity,
|
|
|
|
int image_opacity,
|
1999-09-09 09:47:54 +08:00
|
|
|
BrushApplicationMode brush_hardness,
|
|
|
|
gdouble brush_scale,
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
PaintApplicationMode mode)
|
1997-12-08 09:13:10 +08:00
|
|
|
{
|
|
|
|
MaskBuf *brush_mask;
|
|
|
|
|
|
|
|
/* get the brush mask */
|
1999-09-09 09:47:54 +08:00
|
|
|
brush_mask = paint_core_get_brush_mask (paint_core, brush_hardness, brush_scale);
|
1997-12-08 09:13:10 +08:00
|
|
|
|
|
|
|
/* paste the canvas buf */
|
1998-01-22 15:02:57 +08:00
|
|
|
paint_core_replace (paint_core, brush_mask, drawable,
|
1997-12-08 09:13:10 +08:00
|
|
|
brush_opacity, image_opacity, mode);
|
|
|
|
}
|
|
|
|
|
1999-10-27 02:27:27 +08:00
|
|
|
static MaskBuf *last_brush_mask = NULL;
|
|
|
|
static gboolean cache_invalid = FALSE;
|
1998-07-09 13:31:06 +08:00
|
|
|
|
1999-10-27 02:27:27 +08:00
|
|
|
static void
|
|
|
|
paint_core_invalidate_cache (GimpBrush *brush,
|
|
|
|
gpointer *blah)
|
1998-07-09 13:31:06 +08:00
|
|
|
{
|
1999-10-27 02:27:27 +08:00
|
|
|
/* Make sure we don't cache data for a brush that has changed */
|
1998-07-10 16:59:55 +08:00
|
|
|
if (last_brush_mask == brush->mask)
|
1999-10-27 02:27:27 +08:00
|
|
|
cache_invalid = TRUE;
|
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
|
|
|
|
paint_core_calculate_brush_size (MaskBuf *mask,
|
|
|
|
double scale,
|
|
|
|
int *width,
|
|
|
|
int *height)
|
|
|
|
{
|
|
|
|
if (current_device == GDK_CORE_POINTER)
|
|
|
|
{
|
|
|
|
*width = mask->width;
|
|
|
|
*height = mask->height;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
double ratio;
|
|
|
|
|
|
|
|
if (scale < 1/256)
|
|
|
|
ratio = 1/16;
|
|
|
|
else
|
|
|
|
ratio = sqrt (scale);
|
|
|
|
|
|
|
|
*width = MAX ((int)(mask->width * ratio + 0.5), 1);
|
|
|
|
*height = MAX ((int)(mask->height * ratio + 0.5), 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
static MaskBuf *
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_core_subsample_mask (MaskBuf *mask,
|
|
|
|
double x,
|
|
|
|
double y)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
MaskBuf * dest;
|
|
|
|
double left;
|
|
|
|
unsigned char * m, * d;
|
1998-12-26 02:22:01 +08:00
|
|
|
const int * k;
|
1997-11-25 06:05:25 +08:00
|
|
|
int index1, index2;
|
1998-12-26 02:22:01 +08:00
|
|
|
const int * kernel;
|
1997-11-25 06:05:25 +08:00
|
|
|
int new_val;
|
|
|
|
int i, j;
|
|
|
|
int r, s;
|
|
|
|
|
|
|
|
x += (x < 0) ? mask->width : 0;
|
1998-03-24 10:18:58 +08:00
|
|
|
left = x - floor(x) + 0.125;
|
1997-11-25 06:05:25 +08:00
|
|
|
index1 = (int) (left * 4);
|
|
|
|
|
|
|
|
y += (y < 0) ? mask->height : 0;
|
1998-03-24 10:18:58 +08:00
|
|
|
left = y - floor(y) + 0.125;
|
1997-11-25 06:05:25 +08:00
|
|
|
index2 = (int) (left * 4);
|
|
|
|
|
|
|
|
kernel = subsample[index2][index1];
|
|
|
|
|
1998-07-10 16:59:55 +08:00
|
|
|
if ((mask == last_brush_mask) && kernel_brushes[index2][index1] &&
|
|
|
|
!cache_invalid)
|
1997-11-25 06:05:25 +08:00
|
|
|
return kernel_brushes[index2][index1];
|
1998-07-10 16:59:55 +08:00
|
|
|
else if (mask != last_brush_mask || cache_invalid)
|
1998-03-24 10:18:58 +08:00
|
|
|
for (i = 0; i < 5; i++)
|
|
|
|
for (j = 0; j < 5; j++)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
if (kernel_brushes[i][j])
|
|
|
|
mask_buf_free (kernel_brushes[i][j]);
|
|
|
|
kernel_brushes[i][j] = NULL;
|
|
|
|
}
|
|
|
|
|
1998-07-10 16:59:55 +08:00
|
|
|
last_brush_mask = mask;
|
1999-10-27 02:27:27 +08:00
|
|
|
cache_invalid = FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
kernel_brushes[index2][index1] = mask_buf_new (mask->width + 2, mask->height + 2);
|
|
|
|
dest = kernel_brushes[index2][index1];
|
|
|
|
|
|
|
|
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++)
|
|
|
|
{
|
|
|
|
d = mask_buf_data (dest) + (i+r) * dest->width + j;
|
|
|
|
s = KERNEL_WIDTH;
|
|
|
|
while (s--)
|
|
|
|
{
|
1999-07-27 16:47:31 +08:00
|
|
|
new_val = *d + ((*m * *k++ + 128) >> 8);
|
1998-07-25 02:52:03 +08:00
|
|
|
*d++ = MINIMUM (new_val, 255);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
m++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
1998-06-15 06:42:36 +08:00
|
|
|
/* #define FANCY_PRESSURE */
|
|
|
|
|
1998-06-06 11:49:01 +08:00
|
|
|
static MaskBuf *
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_core_pressurize_mask (MaskBuf *brush_mask,
|
|
|
|
double x,
|
|
|
|
double y,
|
|
|
|
double pressure)
|
1998-06-06 11:49:01 +08:00
|
|
|
{
|
|
|
|
static MaskBuf *last_brush = NULL;
|
|
|
|
static unsigned char mapi[256];
|
|
|
|
unsigned char *source;
|
|
|
|
unsigned char *dest;
|
|
|
|
MaskBuf *subsample_mask;
|
|
|
|
int i;
|
1998-06-15 06:42:36 +08:00
|
|
|
#ifdef FANCY_PRESSURE
|
|
|
|
static double map[256];
|
1998-06-06 11:49:01 +08:00
|
|
|
double 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 */
|
1999-09-09 09:47:54 +08:00
|
|
|
subsample_mask = paint_core_subsample_mask (brush_mask, x, y);
|
1998-06-06 11:49:01 +08:00
|
|
|
|
|
|
|
/* Special case pressure = 0.5 */
|
|
|
|
if ((int)(pressure*100+0.5) == 50)
|
|
|
|
return subsample_mask;
|
|
|
|
|
|
|
|
/* Make sure we have the right sized buffer */
|
|
|
|
if (brush_mask != last_brush)
|
|
|
|
{
|
|
|
|
if (pressure_brush)
|
|
|
|
mask_buf_free (pressure_brush);
|
|
|
|
pressure_brush = mask_buf_new (brush_mask->width + 2,
|
|
|
|
brush_mask->height +2);
|
|
|
|
}
|
|
|
|
|
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 */
|
|
|
|
|
|
|
|
for (i=0;i<256;i++)
|
|
|
|
{
|
|
|
|
int tmp = (pressure/0.5)*i;
|
|
|
|
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);
|
|
|
|
dest = mask_buf_data (pressure_brush);
|
|
|
|
|
|
|
|
i = subsample_mask->width * subsample_mask->height;
|
|
|
|
while (i--)
|
|
|
|
{
|
|
|
|
*dest++ = mapi[(*source++)];
|
|
|
|
}
|
|
|
|
|
|
|
|
return pressure_brush;
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
static MaskBuf *
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_core_solidify_mask (MaskBuf *brush_mask)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
static MaskBuf *last_brush = NULL;
|
|
|
|
int i, j;
|
|
|
|
unsigned char * data, * src;
|
|
|
|
|
1999-09-09 09:47:54 +08:00
|
|
|
if (brush_mask == last_brush && !cache_invalid)
|
1997-11-25 06:05:25 +08:00
|
|
|
return solid_brush;
|
|
|
|
last_brush = brush_mask;
|
1999-09-09 09:47:54 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
if (solid_brush)
|
|
|
|
mask_buf_free (solid_brush);
|
1999-07-02 00:52:50 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
solid_brush = mask_buf_new (brush_mask->width + 2, brush_mask->height + 2);
|
|
|
|
|
|
|
|
/* get the data and advance one line into it */
|
|
|
|
data = mask_buf_data (solid_brush) + solid_brush->width;
|
|
|
|
src = mask_buf_data (brush_mask);
|
|
|
|
|
|
|
|
for (i = 0; i < brush_mask->height; i++)
|
|
|
|
{
|
|
|
|
data++;
|
|
|
|
for (j = 0; j < brush_mask->width; j++)
|
|
|
|
{
|
1998-01-25 09:24:46 +08:00
|
|
|
*data++ = (*src++) ? OPAQUE_OPACITY : TRANSPARENT_OPACITY;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
data++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return solid_brush;
|
|
|
|
}
|
|
|
|
|
1999-09-09 09:47:54 +08:00
|
|
|
static MaskBuf *
|
|
|
|
paint_core_scale_mask (MaskBuf *brush_mask,
|
|
|
|
gdouble scale)
|
|
|
|
{
|
|
|
|
static MaskBuf *last_brush = NULL;
|
|
|
|
static gint last_width = 0.0;
|
|
|
|
static gint last_height = 0.0;
|
|
|
|
gint dest_width, dest_height;
|
|
|
|
|
|
|
|
if (scale == 0.0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (scale == 1.0)
|
|
|
|
return brush_mask;
|
|
|
|
|
|
|
|
paint_core_calculate_brush_size (brush_mask, scale,
|
|
|
|
&dest_width, &dest_height);
|
|
|
|
|
1999-09-10 03:11:38 +08:00
|
|
|
if (brush_mask == last_brush && !cache_invalid &&
|
1999-09-09 09:47:54 +08:00
|
|
|
dest_width == last_width && dest_height == last_height)
|
|
|
|
return scale_brush;
|
|
|
|
|
|
|
|
if (scale_brush)
|
|
|
|
mask_buf_free (scale_brush);
|
|
|
|
|
|
|
|
last_brush = brush_mask;
|
|
|
|
last_width = dest_width;
|
|
|
|
last_height = dest_height;
|
|
|
|
|
|
|
|
scale_brush = brush_scale_mask (brush_mask, dest_width, dest_height);
|
|
|
|
cache_invalid = TRUE;
|
|
|
|
|
|
|
|
return scale_brush;
|
|
|
|
}
|
|
|
|
|
1999-09-10 03:11:38 +08:00
|
|
|
static MaskBuf *
|
|
|
|
paint_core_scale_pixmap (MaskBuf *brush_mask,
|
|
|
|
gdouble scale)
|
|
|
|
{
|
|
|
|
static MaskBuf *last_brush = NULL;
|
|
|
|
static gint last_width = 0.0;
|
|
|
|
static gint last_height = 0.0;
|
|
|
|
gint dest_width, dest_height;
|
|
|
|
|
|
|
|
if (scale == 0.0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (scale == 1.0)
|
|
|
|
return brush_mask;
|
|
|
|
|
|
|
|
paint_core_calculate_brush_size (brush_mask, scale,
|
|
|
|
&dest_width, &dest_height);
|
|
|
|
|
|
|
|
if (brush_mask == last_brush && !cache_invalid &&
|
|
|
|
dest_width == last_width && dest_height == last_height)
|
|
|
|
return scale_pixmap;
|
|
|
|
|
|
|
|
if (scale_pixmap)
|
|
|
|
mask_buf_free (scale_pixmap);
|
|
|
|
|
|
|
|
last_brush = brush_mask;
|
|
|
|
last_width = dest_width;
|
|
|
|
last_height = dest_height;
|
|
|
|
|
|
|
|
scale_pixmap = brush_scale_pixmap (brush_mask, dest_width, dest_height);
|
|
|
|
cache_invalid = TRUE;
|
|
|
|
|
|
|
|
return scale_pixmap;
|
|
|
|
}
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
static MaskBuf *
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
paint_core_get_brush_mask (PaintCore *paint_core,
|
1999-09-09 09:47:54 +08:00
|
|
|
BrushApplicationMode brush_hardness,
|
|
|
|
gdouble scale)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1999-09-09 09:47:54 +08:00
|
|
|
MaskBuf * mask;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-09-09 09:47:54 +08:00
|
|
|
if (current_device == GDK_CORE_POINTER)
|
|
|
|
mask = paint_core->brush->mask;
|
|
|
|
else
|
|
|
|
mask = paint_core_scale_mask (paint_core->brush->mask, scale);
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
switch (brush_hardness)
|
|
|
|
{
|
|
|
|
case SOFT:
|
1999-09-09 09:47:54 +08:00
|
|
|
mask = paint_core_subsample_mask (mask, paint_core->curx, paint_core->cury);
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
case HARD:
|
1999-09-09 09:47:54 +08:00
|
|
|
mask = paint_core_solidify_mask (mask);
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
1998-06-06 11:49:01 +08:00
|
|
|
case PRESSURE:
|
1999-09-09 09:47:54 +08:00
|
|
|
mask = paint_core_pressurize_mask (mask, paint_core->curx, paint_core->cury,
|
|
|
|
paint_core->curpressure);
|
1998-06-06 11:49:01 +08:00
|
|
|
break;
|
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
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
paint_core_paste (PaintCore *paint_core,
|
|
|
|
MaskBuf *brush_mask,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
int brush_opacity,
|
|
|
|
int image_opacity,
|
|
|
|
LayerModeEffects paint_mode,
|
|
|
|
PaintApplicationMode mode)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
GImage *gimage;
|
|
|
|
PixelRegion srcPR;
|
|
|
|
TileManager *alt = NULL;
|
|
|
|
int offx, offy;
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
if (! (gimage = drawable_gimage (drawable)))
|
1997-11-25 06:05:25 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* set undo blocks */
|
1998-01-22 15:02:57 +08:00
|
|
|
set_undo_tiles (drawable,
|
1997-11-25 06:05:25 +08:00
|
|
|
canvas_buf->x, canvas_buf->y,
|
|
|
|
canvas_buf->width, canvas_buf->height);
|
|
|
|
|
|
|
|
/* If the mode is CONSTANT:
|
|
|
|
* combine the canvas buf, the brush mask to the canvas tiles
|
|
|
|
*/
|
|
|
|
if (mode == CONSTANT)
|
|
|
|
{
|
|
|
|
/* initialize any invalid canvas tiles */
|
|
|
|
set_canvas_tiles (canvas_buf->x, canvas_buf->y,
|
|
|
|
canvas_buf->width, canvas_buf->height);
|
|
|
|
|
1999-07-02 00:52:50 +08:00
|
|
|
brush_to_canvas_tiles (paint_core, brush_mask, brush_opacity);
|
|
|
|
canvas_tiles_to_canvas_buf (paint_core);
|
1997-11-25 06:05:25 +08:00
|
|
|
alt = undo_tiles;
|
|
|
|
}
|
|
|
|
/* Otherwise:
|
|
|
|
* combine the canvas buf and the brush mask to the canvas buf
|
|
|
|
*/
|
|
|
|
else /* mode != CONSTANT */
|
1999-07-02 00:52:50 +08:00
|
|
|
brush_to_canvas_buf (paint_core, brush_mask, brush_opacity);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* intialize canvas buf source pixel regions */
|
|
|
|
srcPR.bytes = canvas_buf->bytes;
|
|
|
|
srcPR.x = 0; srcPR.y = 0;
|
|
|
|
srcPR.w = canvas_buf->width;
|
|
|
|
srcPR.h = canvas_buf->height;
|
|
|
|
srcPR.rowstride = canvas_buf->width * canvas_buf->bytes;
|
|
|
|
srcPR.data = temp_buf_data (canvas_buf);
|
|
|
|
|
|
|
|
/* apply the paint area to the gimage */
|
1998-01-22 15:02:57 +08:00
|
|
|
gimage_apply_image (gimage, drawable, &srcPR,
|
1997-11-25 06:05:25 +08:00
|
|
|
FALSE, image_opacity, paint_mode,
|
|
|
|
alt, /* specify an alternative src1 */
|
|
|
|
canvas_buf->x, canvas_buf->y);
|
|
|
|
|
|
|
|
/* Update the undo extents */
|
|
|
|
paint_core->x1 = MINIMUM (paint_core->x1, canvas_buf->x);
|
|
|
|
paint_core->y1 = MINIMUM (paint_core->y1, canvas_buf->y);
|
|
|
|
paint_core->x2 = MAXIMUM (paint_core->x2, (canvas_buf->x + canvas_buf->width));
|
|
|
|
paint_core->y2 = MAXIMUM (paint_core->y2, (canvas_buf->y + canvas_buf->height));
|
|
|
|
|
|
|
|
/* Update the gimage--it is important to call gdisplays_update_area
|
1997-12-08 09:13:10 +08:00
|
|
|
* instead of drawable_update because we don't want the drawable
|
|
|
|
* preview to be constantly invalidated
|
|
|
|
*/
|
1998-01-22 15:02:57 +08:00
|
|
|
drawable_offsets (drawable, &offx, &offy);
|
1998-06-29 08:24:44 +08:00
|
|
|
gdisplays_update_area (gimage, canvas_buf->x + offx, canvas_buf->y + offy,
|
1997-12-08 09:13:10 +08:00
|
|
|
canvas_buf->width, canvas_buf->height);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This works similarly to 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).
|
|
|
|
|
|
|
|
When not drawing on alpha-enabled images, it just paints using NORMAL
|
|
|
|
mode.
|
|
|
|
*/
|
|
|
|
static void
|
Actually use the enum types GimpImageType, GimpImageBaseType,
* app/*.[ch]: Actually use the enum types GimpImageType,
GimpImageBaseType, LayerModeEffects, PaintApplicationMode,
BrushApplicationMode, GimpFillType and ConvertPaletteType, instead
of just int or gint. Hopefully I catched most of the places
where these should be used.
Add an enum ConvolutionType, suffix the too general constants
NORMAL, ABSOLUTE and NEGATIVE with _CONVOL. Use NORMAL_MODE
instead of NORMAL in some places (this was what was intended). Fix
some minor gccisms.
* app/apptypes.h: New file. This file contains the above
enumeration types, and some opaque struct typedefs. It was
necessary to collect these in one header that doesn't include
other headers, because when we started using the above mentioned
types in the headers, all hell broke loose because of the
spaghetti-like cross-inclusion mess between headers.
(An example: Header A includes header B, which includes header C
which includes A. B uses a type defined in A. This is not defined,
because A hasn't defined it yet at the point where it includes B,
and A included from B of course is skipped as we already are
reading A.)
1999-08-19 07:41:39 +08:00
|
|
|
paint_core_replace (PaintCore *paint_core,
|
|
|
|
MaskBuf *brush_mask,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
int brush_opacity,
|
|
|
|
int image_opacity,
|
|
|
|
PaintApplicationMode mode)
|
1997-12-08 09:13:10 +08:00
|
|
|
{
|
|
|
|
GImage *gimage;
|
|
|
|
PixelRegion srcPR, maskPR;
|
1999-07-02 00:52:50 +08:00
|
|
|
TileManager *alt = NULL;
|
1997-12-08 09:13:10 +08:00
|
|
|
int offx, offy;
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
if (!drawable_has_alpha (drawable))
|
1997-12-08 09:13:10 +08:00
|
|
|
{
|
1998-01-22 15:02:57 +08:00
|
|
|
paint_core_paste (paint_core, brush_mask, drawable,
|
1997-12-08 09:13:10 +08:00
|
|
|
brush_opacity, image_opacity, NORMAL_MODE,
|
|
|
|
mode);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1998-01-22 15:02:57 +08:00
|
|
|
if (! (gimage = drawable_gimage (drawable)))
|
1997-12-08 09:13:10 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* set undo blocks */
|
1998-01-22 15:02:57 +08:00
|
|
|
set_undo_tiles (drawable,
|
1997-12-08 09:13:10 +08:00
|
|
|
canvas_buf->x, canvas_buf->y,
|
|
|
|
canvas_buf->width, canvas_buf->height);
|
|
|
|
|
1999-07-02 00:52:50 +08:00
|
|
|
if (mode == CONSTANT)
|
|
|
|
{
|
|
|
|
/* initialize any invalid canvas tiles */
|
|
|
|
set_canvas_tiles (canvas_buf->x, canvas_buf->y,
|
|
|
|
canvas_buf->width, canvas_buf->height);
|
|
|
|
|
|
|
|
/* combine the brush mask and the canvas tiles */
|
|
|
|
brush_to_canvas_tiles (paint_core, brush_mask, brush_opacity);
|
|
|
|
|
|
|
|
/* set the alt source as the unaltered undo_tiles */
|
|
|
|
alt = undo_tiles;
|
|
|
|
|
|
|
|
/* initialize the maskPR from the canvas tiles */
|
|
|
|
pixel_region_init (&maskPR, canvas_tiles,
|
|
|
|
canvas_buf->x, canvas_buf->y,
|
|
|
|
canvas_buf->width, canvas_buf->height, FALSE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* The mask is just the brush mask */
|
|
|
|
maskPR.bytes = 1;
|
|
|
|
maskPR.x = 0; maskPR.y = 0;
|
|
|
|
maskPR.w = canvas_buf->width;
|
|
|
|
maskPR.h = canvas_buf->height;
|
|
|
|
maskPR.rowstride = maskPR.bytes * brush_mask->width;
|
|
|
|
maskPR.data = mask_buf_data (brush_mask);
|
|
|
|
}
|
1997-12-08 09:13:10 +08:00
|
|
|
|
|
|
|
/* intialize canvas buf source pixel regions */
|
|
|
|
srcPR.bytes = canvas_buf->bytes;
|
|
|
|
srcPR.x = 0; srcPR.y = 0;
|
|
|
|
srcPR.w = canvas_buf->width;
|
|
|
|
srcPR.h = canvas_buf->height;
|
|
|
|
srcPR.rowstride = canvas_buf->width * canvas_buf->bytes;
|
|
|
|
srcPR.data = temp_buf_data (canvas_buf);
|
|
|
|
|
|
|
|
/* apply the paint area to the gimage */
|
1998-01-22 15:02:57 +08:00
|
|
|
gimage_replace_image (gimage, drawable, &srcPR,
|
1997-12-08 09:13:10 +08:00
|
|
|
FALSE, image_opacity,
|
1999-07-02 00:52:50 +08:00
|
|
|
&maskPR,
|
1997-12-08 09:13:10 +08:00
|
|
|
canvas_buf->x, canvas_buf->y);
|
|
|
|
|
|
|
|
/* Update the undo extents */
|
|
|
|
paint_core->x1 = MINIMUM (paint_core->x1, canvas_buf->x);
|
|
|
|
paint_core->y1 = MINIMUM (paint_core->y1, canvas_buf->y);
|
|
|
|
paint_core->x2 = MAXIMUM (paint_core->x2, (canvas_buf->x + canvas_buf->width));
|
|
|
|
paint_core->y2 = MAXIMUM (paint_core->y2, (canvas_buf->y + canvas_buf->height));
|
|
|
|
|
|
|
|
/* Update the gimage--it is important to call gdisplays_update_area
|
1997-11-25 06:05:25 +08:00
|
|
|
* instead of drawable_update because we don't want the drawable
|
|
|
|
* preview to be constantly invalidated
|
|
|
|
*/
|
1998-01-22 15:02:57 +08:00
|
|
|
drawable_offsets (drawable, &offx, &offy);
|
1998-06-29 08:24:44 +08:00
|
|
|
gdisplays_update_area (gimage, canvas_buf->x + offx, canvas_buf->y + offy,
|
1997-11-25 06:05:25 +08:00
|
|
|
canvas_buf->width, canvas_buf->height);
|
|
|
|
}
|
|
|
|
|
1999-07-02 00:52:50 +08:00
|
|
|
static void
|
|
|
|
canvas_tiles_to_canvas_buf(PaintCore *paint_core)
|
|
|
|
{
|
|
|
|
PixelRegion srcPR, maskPR;
|
|
|
|
|
|
|
|
/* combine the canvas tiles and the canvas buf */
|
|
|
|
srcPR.bytes = canvas_buf->bytes;
|
|
|
|
srcPR.x = 0; srcPR.y = 0;
|
|
|
|
srcPR.w = canvas_buf->width;
|
|
|
|
srcPR.h = canvas_buf->height;
|
|
|
|
srcPR.rowstride = canvas_buf->width * canvas_buf->bytes;
|
|
|
|
srcPR.data = temp_buf_data (canvas_buf);
|
|
|
|
|
|
|
|
pixel_region_init (&maskPR, canvas_tiles,
|
|
|
|
canvas_buf->x, canvas_buf->y,
|
|
|
|
canvas_buf->width, canvas_buf->height, FALSE);
|
|
|
|
|
|
|
|
/* apply the canvas tiles to the canvas buf */
|
|
|
|
apply_mask_to_region (&srcPR, &maskPR, OPAQUE_OPACITY);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-09-09 09:47:54 +08:00
|
|
|
brush_to_canvas_tiles (PaintCore *paint_core,
|
|
|
|
MaskBuf *brush_mask,
|
|
|
|
int brush_opacity)
|
1999-07-02 00:52:50 +08:00
|
|
|
{
|
|
|
|
PixelRegion srcPR, maskPR;
|
|
|
|
int x, y;
|
|
|
|
int xoff, yoff;
|
|
|
|
|
|
|
|
/* combine the brush mask and the canvas tiles */
|
|
|
|
pixel_region_init (&srcPR, canvas_tiles,
|
|
|
|
canvas_buf->x, canvas_buf->y,
|
|
|
|
canvas_buf->width, canvas_buf->height, TRUE);
|
|
|
|
|
|
|
|
x = (int) paint_core->curx - (brush_mask->width >> 1);
|
|
|
|
y = (int) paint_core->cury - (brush_mask->height >> 1);
|
|
|
|
xoff = (x < 0) ? -x : 0;
|
|
|
|
yoff = (y < 0) ? -y : 0;
|
|
|
|
|
|
|
|
maskPR.bytes = 1;
|
|
|
|
maskPR.x = 0; maskPR.y = 0;
|
|
|
|
maskPR.w = srcPR.w;
|
|
|
|
maskPR.h = srcPR.h;
|
|
|
|
maskPR.rowstride = maskPR.bytes * brush_mask->width;
|
|
|
|
maskPR.data = mask_buf_data (brush_mask) + yoff * maskPR.rowstride + xoff * maskPR.bytes;
|
|
|
|
|
|
|
|
/* combine the mask to the canvas tiles */
|
|
|
|
combine_mask_and_region (&srcPR, &maskPR, brush_opacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-09-09 09:47:54 +08:00
|
|
|
brush_to_canvas_buf (PaintCore *paint_core,
|
|
|
|
MaskBuf *brush_mask,
|
|
|
|
int brush_opacity)
|
1999-07-02 00:52:50 +08:00
|
|
|
{
|
|
|
|
PixelRegion srcPR, maskPR;
|
|
|
|
int x, y;
|
|
|
|
int xoff, yoff;
|
|
|
|
|
|
|
|
x = (int) paint_core->curx - (brush_mask->width >> 1);
|
|
|
|
y = (int) paint_core->cury - (brush_mask->height >> 1);
|
|
|
|
xoff = (x < 0) ? -x : 0;
|
|
|
|
yoff = (y < 0) ? -y : 0;
|
|
|
|
|
|
|
|
/* combine the canvas buf and the brush mask to the canvas buf */
|
|
|
|
srcPR.bytes = canvas_buf->bytes;
|
|
|
|
srcPR.x = 0; srcPR.y = 0;
|
|
|
|
srcPR.w = canvas_buf->width;
|
|
|
|
srcPR.h = canvas_buf->height;
|
|
|
|
srcPR.rowstride = canvas_buf->width * canvas_buf->bytes;
|
|
|
|
srcPR.data = temp_buf_data (canvas_buf);
|
|
|
|
|
|
|
|
maskPR.bytes = 1;
|
|
|
|
maskPR.x = 0; maskPR.y = 0;
|
|
|
|
maskPR.w = srcPR.w;
|
|
|
|
maskPR.h = srcPR.h;
|
|
|
|
maskPR.rowstride = maskPR.bytes * brush_mask->width;
|
|
|
|
maskPR.data = mask_buf_data (brush_mask) + yoff * maskPR.rowstride + xoff * maskPR.bytes;
|
|
|
|
|
|
|
|
/* apply the mask */
|
|
|
|
apply_mask_to_region (&srcPR, &maskPR, brush_opacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
1997-11-25 06:05:25 +08:00
|
|
|
static void
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_to_canvas_tiles (PaintCore *paint_core,
|
|
|
|
MaskBuf *brush_mask,
|
|
|
|
int brush_opacity)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
PixelRegion srcPR, maskPR;
|
|
|
|
int x, y;
|
|
|
|
int xoff, yoff;
|
|
|
|
|
|
|
|
/* combine the brush mask and the canvas tiles */
|
|
|
|
pixel_region_init (&srcPR, canvas_tiles,
|
|
|
|
canvas_buf->x, canvas_buf->y,
|
|
|
|
canvas_buf->width, canvas_buf->height, TRUE);
|
|
|
|
|
|
|
|
x = (int) paint_core->curx - (brush_mask->width >> 1);
|
|
|
|
y = (int) paint_core->cury - (brush_mask->height >> 1);
|
|
|
|
xoff = (x < 0) ? -x : 0;
|
|
|
|
yoff = (y < 0) ? -y : 0;
|
|
|
|
|
|
|
|
maskPR.bytes = 1;
|
|
|
|
maskPR.x = 0; maskPR.y = 0;
|
|
|
|
maskPR.w = srcPR.w;
|
|
|
|
maskPR.h = srcPR.h;
|
|
|
|
maskPR.rowstride = maskPR.bytes * brush_mask->width;
|
|
|
|
maskPR.data = mask_buf_data (brush_mask) + yoff * maskPR.rowstride + xoff * maskPR.bytes;
|
|
|
|
|
|
|
|
/* combine the mask and canvas tiles */
|
|
|
|
combine_mask_and_region (&srcPR, &maskPR, brush_opacity);
|
|
|
|
|
|
|
|
/* combine the canvas tiles and the canvas buf */
|
|
|
|
srcPR.bytes = canvas_buf->bytes;
|
|
|
|
srcPR.x = 0; srcPR.y = 0;
|
|
|
|
srcPR.w = canvas_buf->width;
|
|
|
|
srcPR.h = canvas_buf->height;
|
|
|
|
srcPR.rowstride = canvas_buf->width * canvas_buf->bytes;
|
|
|
|
srcPR.data = temp_buf_data (canvas_buf);
|
|
|
|
|
|
|
|
pixel_region_init (&maskPR, canvas_tiles,
|
|
|
|
canvas_buf->x, canvas_buf->y,
|
|
|
|
canvas_buf->width, canvas_buf->height, FALSE);
|
|
|
|
|
|
|
|
/* apply the canvas tiles to the canvas buf */
|
1998-01-25 09:24:46 +08:00
|
|
|
apply_mask_to_region (&srcPR, &maskPR, OPAQUE_OPACITY);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-06-03 23:02:48 +08:00
|
|
|
paint_to_canvas_buf (PaintCore *paint_core,
|
|
|
|
MaskBuf *brush_mask,
|
|
|
|
int brush_opacity)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
PixelRegion srcPR, maskPR;
|
1998-03-27 16:13:45 +08:00
|
|
|
int x, y;
|
|
|
|
int xoff, yoff;
|
|
|
|
|
|
|
|
x = (int) paint_core->curx - (brush_mask->width >> 1);
|
|
|
|
y = (int) paint_core->cury - (brush_mask->height >> 1);
|
|
|
|
xoff = (x < 0) ? -x : 0;
|
|
|
|
yoff = (y < 0) ? -y : 0;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* combine the canvas buf and the brush mask to the canvas buf */
|
|
|
|
srcPR.bytes = canvas_buf->bytes;
|
|
|
|
srcPR.x = 0; srcPR.y = 0;
|
|
|
|
srcPR.w = canvas_buf->width;
|
|
|
|
srcPR.h = canvas_buf->height;
|
|
|
|
srcPR.rowstride = canvas_buf->width * canvas_buf->bytes;
|
|
|
|
srcPR.data = temp_buf_data (canvas_buf);
|
|
|
|
|
|
|
|
maskPR.bytes = 1;
|
|
|
|
maskPR.x = 0; maskPR.y = 0;
|
|
|
|
maskPR.w = srcPR.w;
|
|
|
|
maskPR.h = srcPR.h;
|
|
|
|
maskPR.rowstride = maskPR.bytes * brush_mask->width;
|
1998-03-27 16:13:45 +08:00
|
|
|
maskPR.data = mask_buf_data (brush_mask) + yoff * maskPR.rowstride + xoff * maskPR.bytes;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* apply the mask */
|
|
|
|
apply_mask_to_region (&srcPR, &maskPR, brush_opacity);
|
|
|
|
}
|
1999-07-02 00:52:50 +08:00
|
|
|
#endif
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
static void
|
1999-06-03 23:02:48 +08:00
|
|
|
set_undo_tiles (GimpDrawable *drawable,
|
|
|
|
int x, int y, int w, int h)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
Tile *src_tile;
|
|
|
|
Tile *dest_tile;
|
|
|
|
|
1998-08-16 03:17:36 +08:00
|
|
|
if (undo_tiles == NULL)
|
|
|
|
{
|
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)))
|
|
|
|
{
|
1998-08-16 03:17:36 +08:00
|
|
|
dest_tile = tile_manager_get_tile (undo_tiles, j, i, 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
|
|
|
{
|
1998-08-16 03:17:36 +08:00
|
|
|
src_tile = tile_manager_get_tile (drawable_data (drawable), j, i, TRUE, FALSE);
|
|
|
|
tile_manager_map_tile (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
|
1999-06-03 23:02:48 +08:00
|
|
|
set_canvas_tiles (int x, int y, int w, int h)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
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)))
|
|
|
|
{
|
1998-08-16 03:17:36 +08:00
|
|
|
tile = tile_manager_get_tile (canvas_tiles, j, i, FALSE, FALSE);
|
1998-08-12 01:35:34 +08:00
|
|
|
if (tile_is_valid (tile) == FALSE)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
1998-08-16 03:17:36 +08:00
|
|
|
tile = tile_manager_get_tile (canvas_tiles, j, i, TRUE, TRUE);
|
1998-08-12 01:35:34 +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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************/
|
|
|
|
/* Paint buffers utility functions */
|
|
|
|
/*****************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_paint_buffers ()
|
|
|
|
{
|
|
|
|
if (orig_buf)
|
|
|
|
temp_buf_free (orig_buf);
|
|
|
|
orig_buf = NULL;
|
|
|
|
|
|
|
|
if (canvas_buf)
|
|
|
|
temp_buf_free (canvas_buf);
|
|
|
|
canvas_buf = NULL;
|
|
|
|
}
|
1999-09-10 03:11:38 +08:00
|
|
|
|
|
|
|
|
|
|
|
/**************************************************/
|
|
|
|
/* Brush pipe utility functions */
|
|
|
|
/**************************************************/
|
|
|
|
|
|
|
|
void
|
|
|
|
paint_core_color_area_with_pixmap (PaintCore *paint_core,
|
|
|
|
GImage *dest,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
TempBuf *area,
|
|
|
|
gdouble scale,
|
|
|
|
int mode)
|
|
|
|
{
|
|
|
|
|
|
|
|
PixelRegion destPR;
|
|
|
|
void *pr;
|
|
|
|
guchar *d;
|
|
|
|
int ulx, uly, offsetx, offsety, y;
|
|
|
|
TempBuf *pixmap_mask;
|
|
|
|
TempBuf *brush_mask;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_BRUSH_PIXMAP (paint_core->brush));
|
|
|
|
|
|
|
|
/* scale the brushes */
|
|
|
|
pixmap_mask =
|
|
|
|
paint_core_scale_pixmap (gimp_brush_pixmap_pixmap (GIMP_BRUSH_PIXMAP (paint_core->brush)), scale);
|
|
|
|
if (mode == SOFT)
|
|
|
|
brush_mask = paint_core_scale_mask (paint_core->brush->mask, scale);
|
|
|
|
else
|
|
|
|
brush_mask = NULL;
|
|
|
|
|
|
|
|
destPR.bytes = area->bytes;
|
|
|
|
destPR.x = 0; destPR.y = 0;
|
|
|
|
destPR.w = area->width;
|
|
|
|
destPR.h = area->height;
|
|
|
|
destPR.rowstride = destPR.bytes * area->width;
|
|
|
|
destPR.data = temp_buf_data (area);
|
|
|
|
|
|
|
|
pr = pixel_regions_register (1, &destPR);
|
|
|
|
|
|
|
|
/* Calculate upper left corner of brush as in
|
|
|
|
* paint_core_get_paint_area. Ugly to have to do this here, too.
|
|
|
|
*/
|
|
|
|
|
|
|
|
ulx = (int) paint_core->curx - (pixmap_mask->width >> 1);
|
|
|
|
uly = (int) paint_core->cury - (pixmap_mask->height >> 1);
|
|
|
|
|
|
|
|
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
|
|
|
|
paint_line_pixmap_mask (GImage *dest,
|
|
|
|
GimpDrawable *drawable,
|
|
|
|
TempBuf *pixmap_mask,
|
|
|
|
TempBuf *brush_mask,
|
|
|
|
guchar *d,
|
|
|
|
int x,
|
|
|
|
int y,
|
|
|
|
int bytes,
|
|
|
|
int width,
|
|
|
|
int mode)
|
|
|
|
{
|
|
|
|
guchar *b, *p;
|
|
|
|
int x_index;
|
|
|
|
gdouble alpha;
|
|
|
|
gdouble factor = 0.00392156986; /* 1.0/255.0 */
|
|
|
|
gint i;
|
|
|
|
guchar *mask;
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
if (mode == SOFT && brush_mask)
|
|
|
|
{
|
|
|
|
/* ditto, except for the brush mask, so we can pre-multiply the alpha value */
|
|
|
|
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];
|
|
|
|
|
|
|
|
/* 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? */
|
|
|
|
alpha = d[bytes-1] * factor;
|
|
|
|
if (alpha)
|
|
|
|
{
|
|
|
|
d[0] *= alpha;
|
|
|
|
d[1] *= alpha;
|
|
|
|
d[2] *= alpha;
|
|
|
|
}
|
|
|
|
/* 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]); */
|
|
|
|
gimage_transform_color (dest, drawable, p, d, RGB);
|
|
|
|
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;
|
|
|
|
|
|
|
|
/* 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? */
|
|
|
|
gimage_transform_color (dest, drawable, p, d, RGB);
|
|
|
|
d += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|