Applied modified patch from Alexia Death which adds velocity support to

2008-05-10  Michael Natterer  <mitch@gimp.org>

	Applied modified patch from Alexia Death which adds velocity
	support to paint tools in the spirit of the pressure support we
	already have. Fixes bug #529431.

	* app/display/gimpdisplayshell-coords.c
	(gimp_display_shell_eval_event): tweak velocity calculation to
	work in screen coordinates.

	* app/paint/gimppaintoptions.[ch]: add velocity options in the
	same way as there are pressure options. Add utility functions
	which return dynamic opatity and dynamic rate according to the the
	option's settings and some GimpCoords' pressure and velocity.

	* app/tools/gimppaintoptions-gui.c: add GUI for the velocity
	options.

	* app/paint/gimpbrushcore.h: remove PRESSURE_SCALE define, it's
	now in gimppaintoptions.h.

	* app/paint/gimpbrushcore.c (gimp_brush_core_interpolate):
	inerpolate velocity too.

	(gimp_brush_core_calc_brush_scale): take velocity into account.

	(gimp_brush_core_get_brush_mask): always pressurize the mask in
	the GIMP_BRUSH_PRESSURE because there always is velocity (unlike
	pressure which is only there on tablets).

	* app/paint/gimpairbrush.c
	* app/paint/gimpclone.c
	* app/paint/gimpconvolve.c
	* app/paint/gimpdodgeburn.c
	* app/paint/gimperaser.c
	* app/paint/gimpheal.c
	* app/paint/gimppaintbrush.c
	* app/paint/gimpsmudge.c: get opacity and rate from the new paint
	options utility functions which take both pressure and velocity
	into account.

	* app/paint/gimppaintbrush.c: take velocity into account when
	calculating the gradient color offset.

	* app/paint/gimpairbrush.c: do some additional fiddling with
	velocity in the asynchronous airbrush timeout.

	* app/paint/gimpairbrushoptions.c: override the velocity-size
	property and have it default to FALSE.


svn path=/trunk/; revision=25604
This commit is contained in:
Michael Natterer 2008-05-10 10:03:21 +00:00 committed by Michael Natterer
parent d6db9d5262
commit 82c2616f0f
16 changed files with 563 additions and 95 deletions

View File

@ -1,3 +1,53 @@
2008-05-10 Michael Natterer <mitch@gimp.org>
Applied modified patch from Alexia Death which adds velocity
support to paint tools in the spirit of the pressure support we
already have. Fixes bug #529431.
* app/display/gimpdisplayshell-coords.c
(gimp_display_shell_eval_event): tweak velocity calculation to
work in screen coordinates.
* app/paint/gimppaintoptions.[ch]: add velocity options in the
same way as there are pressure options. Add utility functions
which return dynamic opatity and dynamic rate according to the the
option's settings and some GimpCoords' pressure and velocity.
* app/tools/gimppaintoptions-gui.c: add GUI for the velocity
options.
* app/paint/gimpbrushcore.h: remove PRESSURE_SCALE define, it's
now in gimppaintoptions.h.
* app/paint/gimpbrushcore.c (gimp_brush_core_interpolate):
inerpolate velocity too.
(gimp_brush_core_calc_brush_scale): take velocity into account.
(gimp_brush_core_get_brush_mask): always pressurize the mask in
the GIMP_BRUSH_PRESSURE because there always is velocity (unlike
pressure which is only there on tablets).
* app/paint/gimpairbrush.c
* app/paint/gimpclone.c
* app/paint/gimpconvolve.c
* app/paint/gimpdodgeburn.c
* app/paint/gimperaser.c
* app/paint/gimpheal.c
* app/paint/gimppaintbrush.c
* app/paint/gimpsmudge.c: get opacity and rate from the new paint
options utility functions which take both pressure and velocity
into account.
* app/paint/gimppaintbrush.c: take velocity into account when
calculating the gradient color offset.
* app/paint/gimpairbrush.c: do some additional fiddling with
velocity in the asynchronous airbrush timeout.
* app/paint/gimpairbrushoptions.c: override the velocity-size
property and have it default to FALSE.
2008-05-10 Martin Nordholts <martinn@svn.gnome.org>
* app/tools/gimpcroptool.c: Add a GimpRectangleTool::cancel()
@ -69,8 +119,7 @@
(gimp_display_shell_canvas_tool_events): call it here instead and
add comments about how BUTTON_PRESS and FOCUS_IN interact.
Also return TRUE from BUTTON_PRESS, BUTTON_RELEASE and
MOTION_NOTIFY.
Return TRUE from BUTTON_PRESS, BUTTON_RELEASE and MOTION_NOTIFY.
2008-05-08 Sven Neumann <sven@gimp.org>

View File

@ -27,6 +27,8 @@
#include "gimpdisplayshell.h"
#include "gimpdisplayshell-coords.h"
/* Velocity unit is screen pixels per millisecond we pass to tools as 1. */
#define VELOCITY_UNIT 3.0
/* public functions */
@ -259,12 +261,22 @@ gimp_display_shell_eval_event (GimpDisplayShell *shell,
}
else
{
coords->velocity =
(coords->distance / (gdouble) coords->delta_time) / 10;
/* We need to calculate the velocity in screen coordinates
* for human interaction
*/
gdouble screen_distance = (coords->distance *
MIN (shell->scale_x, shell->scale_y));
/* Calculate raw valocity */
coords->velocity = ((screen_distance / (gdouble) coords->delta_time) /
VELOCITY_UNIT);
/* Adding velocity dependent smooth, feels better in tools this way. */
coords->velocity = (shell->last_coords.velocity *
(1 - MIN (SMOOTH_FACTOR, coords->velocity)) +
coords->velocity *
MIN (SMOOTH_FACTOR, coords->velocity));
/* A little smooth on this too, feels better in tools this way. */
coords->velocity = (shell->last_coords.velocity * (1 - SMOOTH_FACTOR)
+ coords->velocity * SMOOTH_FACTOR);
/* Speed needs upper limit */
coords->velocity = MIN (coords->velocity, 1.0);
}

View File

@ -136,14 +136,17 @@ gimp_airbrush_paint (GimpPaintCore *paint_core,
if (options->rate != 0.0)
{
gdouble timeout;
gdouble dynamic_rate;
gint timeout;
airbrush->drawable = drawable;
airbrush->paint_options = paint_options;
timeout = (paint_options->pressure_options->rate ?
(10000 / (options->rate * PRESSURE_SCALE * paint_core->cur_coords.pressure)) :
(10000 / options->rate));
dynamic_rate = gimp_paint_options_get_dynamic_rate (paint_options,
&paint_core->cur_coords,
paint_core->use_pressure);
timeout = 10000 / (options->rate * dynamic_rate);
airbrush->timeout_id = g_timeout_add (timeout,
gimp_airbrush_timeout,
@ -173,17 +176,26 @@ gimp_airbrush_motion (GimpPaintCore *paint_core,
GimpAirbrushOptions *options = GIMP_AIRBRUSH_OPTIONS (paint_options);
gdouble opacity;
gboolean saved_pressure;
gboolean saved_velocity;
opacity = options->pressure / 100.0;
saved_pressure = paint_options->pressure_options->hardness;
saved_velocity = paint_options->velocity_options->hardness;
if (saved_pressure)
opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure;
opacity *= GIMP_PAINT_PRESSURE_SCALE * paint_core->cur_coords.pressure;
if (saved_velocity)
opacity *= MAX (0.0, 1 - GIMP_PAINT_VELOCITY_SCALE * paint_core->cur_coords.velocity);
paint_options->pressure_options->hardness = FALSE;
paint_options->velocity_options->hardness = FALSE;
_gimp_paintbrush_motion (paint_core, drawable, paint_options, opacity);
paint_options->pressure_options->hardness = saved_pressure;
paint_options->velocity_options->hardness = saved_velocity;
}
static gboolean

View File

@ -35,7 +35,8 @@ enum
{
PROP_0,
PROP_RATE,
PROP_PRESSURE
PROP_PRESSURE,
PROP_VELOCITY_SIZE
};
@ -69,6 +70,12 @@ gimp_airbrush_options_class_init (GimpAirbrushOptionsClass *klass)
"pressure", NULL,
0.0, 100.0, AIRBRUSH_DEFAULT_PRESSURE,
GIMP_PARAM_STATIC_STRINGS);
/* override velocity size because its unavaliable to the airbrush */
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_VELOCITY_SIZE,
"velocity-size", NULL,
FALSE,
GIMP_PARAM_STATIC_STRINGS);
}
static void
@ -92,6 +99,10 @@ gimp_airbrush_options_set_property (GObject *object,
case PROP_PRESSURE:
options->pressure = g_value_get_double (value);
break;
case PROP_VELOCITY_SIZE:
GIMP_PAINT_OPTIONS (options)->velocity_options->size = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@ -114,6 +125,10 @@ gimp_airbrush_options_get_property (GObject *object,
case PROP_PRESSURE:
g_value_set_double (value, options->pressure);
break;
case PROP_VELOCITY_SIZE:
g_value_set_boolean (value, GIMP_PAINT_OPTIONS (options)->velocity_options->size);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;

View File

@ -87,7 +87,9 @@ static void gimp_brush_core_real_set_brush (GimpBrushCore *core,
static gdouble gimp_brush_core_calc_brush_scale (GimpBrushCore *core,
GimpPaintOptions *paint_options,
gdouble pressure);
gdouble pressure,
gdouble velocity);
static inline void rotate_pointers (gulong **p,
guint32 n);
static TempBuf * gimp_brush_core_subsample_mask (GimpBrushCore *core,
@ -356,7 +358,8 @@ gimp_brush_core_start (GimpPaintCore *paint_core,
}
core->scale = gimp_brush_core_calc_brush_scale (core, paint_options,
coords->pressure);
coords->pressure,
coords->velocity);
core->spacing = (gdouble) gimp_brush_get_spacing (core->main_brush) / 100.0;
@ -406,6 +409,7 @@ gimp_brush_core_interpolate (GimpPaintCore *paint_core,
gdouble delta_pressure;
gdouble delta_xtilt, delta_ytilt;
gdouble delta_wheel;
gdouble delta_velocity;
GimpVector2 temp_vec;
gint n, num_points;
gdouble t0, dt, tn;
@ -431,6 +435,7 @@ gimp_brush_core_interpolate (GimpPaintCore *paint_core,
delta_xtilt = paint_core->cur_coords.xtilt - paint_core->last_coords.xtilt;
delta_ytilt = paint_core->cur_coords.ytilt - paint_core->last_coords.ytilt;
delta_wheel = paint_core->cur_coords.wheel - paint_core->last_coords.wheel;
delta_velocity = paint_core->cur_coords.velocity - paint_core->last_coords.velocity;
/* return if there has been no motion */
if (! delta_vec.x &&
@ -438,7 +443,8 @@ gimp_brush_core_interpolate (GimpPaintCore *paint_core,
! delta_pressure &&
! delta_xtilt &&
! delta_ytilt &&
! delta_wheel)
! delta_wheel &&
! delta_velocity)
return;
/* calculate the distance traveled in the coordinate space of the brush */
@ -631,6 +637,8 @@ gimp_brush_core_interpolate (GimpPaintCore *paint_core,
p * delta_ytilt);
paint_core->cur_coords.wheel = (paint_core->last_coords.wheel +
p * delta_wheel);
paint_core->cur_coords.velocity = (paint_core->last_coords.velocity +
p * delta_velocity);
if (core->jitter > 0.0)
{
@ -663,6 +671,7 @@ gimp_brush_core_interpolate (GimpPaintCore *paint_core,
paint_core->cur_coords.xtilt = paint_core->last_coords.xtilt + delta_xtilt;
paint_core->cur_coords.ytilt = paint_core->last_coords.ytilt + delta_ytilt;
paint_core->cur_coords.wheel = paint_core->last_coords.wheel + delta_wheel;
paint_core->cur_coords.velocity = paint_core->last_coords.velocity + delta_velocity;
paint_core->distance = total;
paint_core->pixel_dist = pixel_initial + pixel_dist;
@ -682,8 +691,11 @@ gimp_brush_core_get_paint_area (GimpPaintCore *paint_core,
gint brush_width, brush_height;
if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_scaling_brush)
core->scale = gimp_brush_core_calc_brush_scale (core, paint_options,
paint_core->cur_coords.pressure);
{
core->scale = gimp_brush_core_calc_brush_scale (core, paint_options,
paint_core->cur_coords.pressure,
paint_core->cur_coords.velocity);
}
/* else use scale from start(), we don't support on-the-fly scaling */
gimp_brush_scale_size (core->brush, core->scale,
@ -917,20 +929,41 @@ gimp_brush_core_invalidate_cache (GimpBrush *brush,
static gdouble
gimp_brush_core_calc_brush_scale (GimpBrushCore *core,
GimpPaintOptions *paint_options,
gdouble pressure)
gdouble pressure,
gdouble velocity)
{
gdouble scale = 1.0;
if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_scaling_brush &&
GIMP_PAINT_CORE (core)->use_pressure)
if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_scaling_brush)
{
if (paint_options->pressure_options->inverse_size)
scale = 1.0 - 0.9 * pressure;
else if (paint_options->pressure_options->size)
scale = pressure;
if (! (GIMP_PAINT_CORE (core)->use_pressure &&
(paint_options->pressure_options->inverse_size ||
paint_options->pressure_options->size)))
{
pressure = -1;
}
else if (paint_options->pressure_options->inverse_size)
{
pressure = 1.0 - 0.9 * pressure;
}
if (scale < 1 / 256.0)
scale = 1 / 16.0;
if (paint_options->velocity_options->size)
{
velocity = 1.0 - sqrt (velocity);
}
else if (paint_options->velocity_options->inverse_size)
{
velocity = sqrt (velocity);
}
else
{
velocity = -1;
}
scale = gimp_paint_options_get_dynamics_mix (pressure, velocity);
if (scale < 1 / 64.0)
scale = 1 / 8.0;
else
scale = sqrt (scale);
}
@ -1361,6 +1394,8 @@ gimp_brush_core_get_brush_mask (GimpBrushCore *core,
{
GimpPaintCore *paint_core = GIMP_PAINT_CORE (core);
TempBuf *mask;
gdouble pressure;
gdouble velocity;
mask = gimp_brush_core_scale_mask (core, core->brush);
@ -1382,15 +1417,17 @@ gimp_brush_core_get_brush_mask (GimpBrushCore *core,
break;
case GIMP_BRUSH_PRESSURE:
if (paint_core->use_pressure)
mask = gimp_brush_core_pressurize_mask (core, mask,
paint_core->cur_coords.x,
paint_core->cur_coords.y,
paint_core->cur_coords.pressure);
if (! paint_core->use_pressure)
pressure = -1.0;
else
mask = gimp_brush_core_subsample_mask (core, mask,
paint_core->cur_coords.x,
paint_core->cur_coords.y);
pressure = GIMP_PAINT_PRESSURE_SCALE * paint_core->cur_coords.pressure;
velocity = GIMP_PAINT_VELOCITY_SCALE * paint_core->cur_coords.velocity;
mask = gimp_brush_core_pressurize_mask (core, mask,
paint_core->cur_coords.x,
paint_core->cur_coords.y,
gimp_paint_options_get_dynamics_mix (pressure, velocity));
break;
default:

View File

@ -27,8 +27,6 @@
#define BRUSH_CORE_SOLID_SUBSAMPLE 2
#define BRUSH_CORE_JITTER_LUTSIZE 360
#define PRESSURE_SCALE 1.5
#define GIMP_TYPE_BRUSH_CORE (gimp_brush_core_get_type ())
#define GIMP_BRUSH_CORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_BRUSH_CORE, GimpBrushCore))
@ -129,4 +127,5 @@ void gimp_brush_core_color_area_with_pixmap
TempBuf * gimp_brush_core_get_brush_mask (GimpBrushCore *core,
GimpBrushApplicationMode brush_hardness);
#endif /* __GIMP_BRUSH_CORE_H__ */

View File

@ -235,8 +235,9 @@ gimp_clone_motion (GimpSourceCore *source_core,
}
}
if (paint_options->pressure_options->opacity)
opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure;
opacity *= gimp_paint_options_get_dynamic_opacity (paint_options,
&paint_core->cur_coords,
paint_core->use_pressure);
gimp_brush_core_paste_canvas (GIMP_BRUSH_CORE (paint_core), drawable,
MIN (opacity, GIMP_OPACITY_OPAQUE),

View File

@ -118,11 +118,10 @@ gimp_convolve_motion (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GimpPaintOptions *paint_options)
{
GimpConvolve *convolve = GIMP_CONVOLVE (paint_core);
GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_core);
GimpConvolveOptions *options = GIMP_CONVOLVE_OPTIONS (paint_options);
GimpContext *context = GIMP_CONTEXT (paint_options);
GimpPressureOptions *pressure_options = paint_options->pressure_options;
GimpConvolve *convolve = GIMP_CONVOLVE (paint_core);
GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_core);
GimpConvolveOptions *options = GIMP_CONVOLVE_OPTIONS (paint_options);
GimpContext *context = GIMP_CONTEXT (paint_options);
GimpImage *image;
TempBuf *area;
PixelRegion srcPR;
@ -154,8 +153,9 @@ gimp_convolve_motion (GimpPaintCore *paint_core,
rate = options->rate;
if (pressure_options->rate)
rate *= PRESSURE_SCALE * paint_core->cur_coords.pressure;
rate *= gimp_paint_options_get_dynamic_rate (paint_options,
&paint_core->cur_coords,
paint_core->use_pressure);
gimp_convolve_calculate_matrix (convolve, options->type, rate);

View File

@ -162,15 +162,14 @@ gimp_dodge_burn_motion (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GimpPaintOptions *paint_options)
{
GimpDodgeBurn *dodgeburn = GIMP_DODGE_BURN (paint_core);
GimpContext *context = GIMP_CONTEXT (paint_options);
GimpPressureOptions *pressure_options = paint_options->pressure_options;
GimpImage *image;
TempBuf *area;
TempBuf *orig;
PixelRegion srcPR, destPR, tempPR;
guchar *temp_data;
gdouble opacity;
GimpDodgeBurn *dodgeburn = GIMP_DODGE_BURN (paint_core);
GimpContext *context = GIMP_CONTEXT (paint_options);
GimpImage *image;
TempBuf *area;
TempBuf *orig;
PixelRegion srcPR, destPR, tempPR;
guchar *temp_data;
gdouble opacity;
image = gimp_item_get_image (GIMP_ITEM (drawable));
@ -236,8 +235,9 @@ gimp_dodge_burn_motion (GimpPaintCore *paint_core,
g_free (temp_data);
if (pressure_options->opacity)
opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure;
opacity *= gimp_paint_options_get_dynamic_opacity (paint_options,
&paint_core->cur_coords,
paint_core->use_pressure);
/* Replace the newly dodgedburned area (canvas_buf) to the image */
gimp_brush_core_replace_canvas (GIMP_BRUSH_CORE (paint_core), drawable,

View File

@ -102,13 +102,12 @@ gimp_eraser_motion (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GimpPaintOptions *paint_options)
{
GimpEraserOptions *options = GIMP_ERASER_OPTIONS (paint_options);
GimpContext *context = GIMP_CONTEXT (paint_options);
GimpPressureOptions *pressure_options = paint_options->pressure_options;
GimpImage *image;
gdouble opacity;
TempBuf *area;
guchar col[MAX_CHANNELS];
GimpEraserOptions *options = GIMP_ERASER_OPTIONS (paint_options);
GimpContext *context = GIMP_CONTEXT (paint_options);
GimpImage *image;
gdouble opacity;
TempBuf *area;
guchar col[MAX_CHANNELS];
image = gimp_item_get_image (GIMP_ITEM (drawable));
@ -131,8 +130,9 @@ gimp_eraser_motion (GimpPaintCore *paint_core,
color_pixels (temp_buf_data (area), col,
area->width * area->height, area->bytes);
if (pressure_options->opacity)
opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure;
opacity *= gimp_paint_options_get_dynamic_opacity (paint_options,
&paint_core->cur_coords,
paint_core->use_pressure);
gimp_brush_core_paste_canvas (GIMP_BRUSH_CORE (paint_core), drawable,
MIN (opacity, GIMP_OPACITY_OPAQUE),

View File

@ -540,9 +540,9 @@ gimp_heal_motion (GimpSourceCore *source_core,
temp_buf_free (temp);
/* check the brush pressure */
if (paint_options->pressure_options->opacity)
opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure;
opacity *= gimp_paint_options_get_dynamic_opacity (paint_options,
&paint_core->cur_coords,
paint_core->use_pressure);
/* replace the canvas with our healed data */
gimp_brush_core_replace_canvas (GIMP_BRUSH_CORE (paint_core),

View File

@ -108,11 +108,13 @@ _gimp_paintbrush_motion (GimpPaintCore *paint_core,
GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_core);
GimpContext *context = GIMP_CONTEXT (paint_options);
GimpPressureOptions *pressure_options = paint_options->pressure_options;
GimpVelocityOptions *velocity_options = paint_options->velocity_options;
GimpImage *image;
GimpRGB gradient_color;
TempBuf *area;
guchar col[MAX_CHANNELS];
GimpPaintApplicationMode paint_appl_mode;
gdouble colmix = 0.0;
image = gimp_item_get_image (GIMP_ITEM (drawable));
@ -125,11 +127,28 @@ _gimp_paintbrush_motion (GimpPaintCore *paint_core,
if (! area)
return;
if (paint_core->use_pressure &&
pressure_options->color &&
velocity_options->color)
{
colmix = (paint_core->cur_coords.pressure * 0.5 +
paint_core->cur_coords.velocity * 0.5);
}
else if (paint_core->use_pressure &&
pressure_options->color)
{
colmix = paint_core->cur_coords.pressure;
}
else if (velocity_options->color)
{
colmix = paint_core->cur_coords.velocity;
}
paint_appl_mode = paint_options->application_mode;
/* optionally take the color from the current gradient */
if (gimp_paint_options_get_gradient_color (paint_options, image,
paint_core->cur_coords.pressure,
colmix,
paint_core->pixel_dist,
&gradient_color))
{
@ -169,8 +188,9 @@ _gimp_paintbrush_motion (GimpPaintCore *paint_core,
area->bytes);
}
if (paint_core->use_pressure && pressure_options->opacity)
opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure;
opacity *= gimp_paint_options_get_dynamic_opacity (paint_options,
&paint_core->cur_coords,
paint_core->use_pressure);
/* finally, let the brush core paste the colored area on the canvas */
gimp_brush_core_paste_canvas (brush_core, drawable,

View File

@ -46,6 +46,14 @@
#define DEFAULT_PRESSURE_INVERSE_SIZE FALSE
#define DEFAULT_PRESSURE_COLOR FALSE
#define DEFAULT_VELOCITY_EXPANDED FALSE
#define DEFAULT_VELOCITY_OPACITY FALSE
#define DEFAULT_VELOCITY_HARDNESS FALSE
#define DEFAULT_VELOCITY_RATE FALSE
#define DEFAULT_VELOCITY_SIZE TRUE
#define DEFAULT_VELOCITY_INVERSE_SIZE FALSE
#define DEFAULT_VELOCITY_COLOR FALSE
#define DEFAULT_USE_FADE FALSE
#define DEFAULT_FADE_LENGTH 100.0
#define DEFAULT_FADE_UNIT GIMP_UNIT_PIXEL
@ -77,6 +85,14 @@ enum
PROP_PRESSURE_INVERSE_SIZE,
PROP_PRESSURE_COLOR,
PROP_VELOCITY_EXPANDED,
PROP_VELOCITY_OPACITY,
PROP_VELOCITY_HARDNESS,
PROP_VELOCITY_RATE,
PROP_VELOCITY_SIZE,
PROP_VELOCITY_INVERSE_SIZE,
PROP_VELOCITY_COLOR,
PROP_USE_FADE,
PROP_FADE_LENGTH,
PROP_FADE_UNIT,
@ -177,6 +193,35 @@ gimp_paint_options_class_init (GimpPaintOptionsClass *klass)
DEFAULT_PRESSURE_INVERSE_SIZE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_VELOCITY_EXPANDED,
"velocity-expanded", NULL,
DEFAULT_VELOCITY_EXPANDED,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_VELOCITY_OPACITY,
"velocity-opacity", NULL,
DEFAULT_VELOCITY_OPACITY,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_VELOCITY_HARDNESS,
"velocity-hardness", NULL,
DEFAULT_VELOCITY_HARDNESS,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_VELOCITY_RATE,
"velocity-rate", NULL,
DEFAULT_VELOCITY_RATE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_VELOCITY_SIZE,
"velocity-size", NULL,
DEFAULT_VELOCITY_SIZE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_VELOCITY_COLOR,
"velocity-color", NULL,
DEFAULT_VELOCITY_COLOR,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_VELOCITY_INVERSE_SIZE,
"velocity-inverse-size", NULL,
DEFAULT_VELOCITY_INVERSE_SIZE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_USE_FADE,
"use-fade", NULL,
DEFAULT_USE_FADE,
@ -264,6 +309,7 @@ gimp_paint_options_init (GimpPaintOptions *options)
options->application_mode_save = DEFAULT_APPLICATION_MODE;
options->pressure_options = g_slice_new0 (GimpPressureOptions);
options->velocity_options = g_slice_new0 (GimpVelocityOptions);
options->fade_options = g_slice_new0 (GimpFadeOptions);
options->jitter_options = g_slice_new0 (GimpJitterOptions);
options->gradient_options = g_slice_new0 (GimpGradientOptions);
@ -278,6 +324,7 @@ gimp_paint_options_finalize (GObject *object)
g_object_unref (options->paint_info);
g_slice_free (GimpPressureOptions, options->pressure_options);
g_slice_free (GimpVelocityOptions, options->velocity_options);
g_slice_free (GimpFadeOptions, options->fade_options);
g_slice_free (GimpJitterOptions, options->jitter_options);
g_slice_free (GimpGradientOptions, options->gradient_options);
@ -293,6 +340,7 @@ gimp_paint_options_set_property (GObject *object,
{
GimpPaintOptions *options = GIMP_PAINT_OPTIONS (object);
GimpPressureOptions *pressure_options = options->pressure_options;
GimpVelocityOptions *velocity_options = options->velocity_options;
GimpFadeOptions *fade_options = options->fade_options;
GimpJitterOptions *jitter_options = options->jitter_options;
GimpGradientOptions *gradient_options = options->gradient_options;
@ -335,6 +383,28 @@ gimp_paint_options_set_property (GObject *object,
pressure_options->color = g_value_get_boolean (value);
break;
case PROP_VELOCITY_EXPANDED:
velocity_options->expanded = g_value_get_boolean (value);
break;
case PROP_VELOCITY_OPACITY:
velocity_options->opacity = g_value_get_boolean (value);
break;
case PROP_VELOCITY_HARDNESS:
velocity_options->hardness = g_value_get_boolean (value);
break;
case PROP_VELOCITY_RATE:
velocity_options->rate = g_value_get_boolean (value);
break;
case PROP_VELOCITY_SIZE:
velocity_options->size = g_value_get_boolean (value);
break;
case PROP_VELOCITY_INVERSE_SIZE:
velocity_options->inverse_size = g_value_get_boolean (value);
break;
case PROP_VELOCITY_COLOR:
velocity_options->color = g_value_get_boolean (value);
break;
case PROP_USE_FADE:
fade_options->use_fade = g_value_get_boolean (value);
break;
@ -403,6 +473,7 @@ gimp_paint_options_get_property (GObject *object,
{
GimpPaintOptions *options = GIMP_PAINT_OPTIONS (object);
GimpPressureOptions *pressure_options = options->pressure_options;
GimpVelocityOptions *velocity_options = options->velocity_options;
GimpFadeOptions *fade_options = options->fade_options;
GimpJitterOptions *jitter_options = options->jitter_options;
GimpGradientOptions *gradient_options = options->gradient_options;
@ -445,6 +516,28 @@ gimp_paint_options_get_property (GObject *object,
g_value_set_boolean (value, pressure_options->color);
break;
case PROP_VELOCITY_EXPANDED:
g_value_set_boolean (value, velocity_options->expanded);
break;
case PROP_VELOCITY_OPACITY:
g_value_set_boolean (value, velocity_options->opacity);
break;
case PROP_VELOCITY_HARDNESS:
g_value_set_boolean (value, velocity_options->hardness);
break;
case PROP_VELOCITY_RATE:
g_value_set_boolean (value, velocity_options->rate);
break;
case PROP_VELOCITY_SIZE:
g_value_set_boolean (value, velocity_options->size);
break;
case PROP_VELOCITY_INVERSE_SIZE:
g_value_set_boolean (value, velocity_options->inverse_size);
break;
case PROP_VELOCITY_COLOR:
g_value_set_boolean (value, velocity_options->color);
break;
case PROP_USE_FADE:
g_value_set_boolean (value, fade_options->use_fade);
break;
@ -624,11 +717,12 @@ gimp_paint_options_get_jitter (GimpPaintOptions *paint_options,
gboolean
gimp_paint_options_get_gradient_color (GimpPaintOptions *paint_options,
GimpImage *image,
gdouble pressure,
gdouble grad_point,
gdouble pixel_dist,
GimpRGB *color)
{
GimpPressureOptions *pressure_options;
GimpVelocityOptions *velocity_options;
GimpGradientOptions *gradient_options;
GimpGradient *gradient;
@ -637,14 +731,15 @@ gimp_paint_options_get_gradient_color (GimpPaintOptions *paint_options,
g_return_val_if_fail (color != NULL, FALSE);
pressure_options = paint_options->pressure_options;
velocity_options = paint_options->velocity_options;
gradient_options = paint_options->gradient_options;
gradient = gimp_context_get_gradient (GIMP_CONTEXT (paint_options));
if (pressure_options->color)
if (pressure_options->color || velocity_options->color)
{
gimp_gradient_get_color_at (gradient, GIMP_CONTEXT (paint_options),
NULL, pressure,
NULL, grad_point,
gradient_options->gradient_reverse,
color);
@ -714,8 +809,91 @@ gimp_paint_options_get_brush_mode (GimpPaintOptions *paint_options)
if (paint_options->hard)
return GIMP_BRUSH_HARD;
if (paint_options->pressure_options->hardness)
if (paint_options->pressure_options->hardness ||
paint_options->velocity_options->hardness)
return GIMP_BRUSH_PRESSURE;
return GIMP_BRUSH_SOFT;
}
/* Calculates dynamics mix to be used for same parameter
* (velocity/pressure) mix Needed in may places and tools.
*/
gdouble
gimp_paint_options_get_dynamics_mix (gdouble mix1,
gdouble mix2)
{
gdouble mixpv = 1.0;
if ((mix1 >= 0) && (mix2 >= 0))
{
mixpv = (mix1 + mix2) * 0.5;
}
else if (mix1 >= 0)
{
mixpv = mix1;
}
else if (mix2 >= 0)
{
mixpv = mix2;
}
return mixpv;
}
gdouble
gimp_paint_options_get_dynamic_opacity (GimpPaintOptions *paint_options,
const GimpCoords *coords,
gboolean use_pressure)
{
gdouble opacity = 1.0;
g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), 1.0);
g_return_val_if_fail (coords != NULL, 1.0);
if (paint_options->pressure_options->opacity ||
paint_options->velocity_options->opacity)
{
gdouble pressure = -1.0;
gdouble velocity = -1.0;
if (paint_options->pressure_options->opacity && use_pressure)
pressure = GIMP_PAINT_PRESSURE_SCALE * coords->pressure;
if (paint_options->velocity_options->opacity)
velocity = GIMP_PAINT_VELOCITY_SCALE * (1 - coords->velocity);
opacity = gimp_paint_options_get_dynamics_mix (pressure, velocity);
}
return opacity;
}
gdouble
gimp_paint_options_get_dynamic_rate (GimpPaintOptions *paint_options,
const GimpCoords *coords,
gboolean use_pressure)
{
gdouble rate = 1.0;
g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), 1.0);
g_return_val_if_fail (coords != NULL, 1.0);
if (paint_options->pressure_options->rate ||
paint_options->velocity_options->rate)
{
gdouble pressure = -1.0;
gdouble velocity = -1.0;
if (paint_options->pressure_options->rate && use_pressure)
pressure = GIMP_PAINT_PRESSURE_SCALE * coords->pressure;
if (paint_options->velocity_options->rate)
velocity = GIMP_PAINT_VELOCITY_SCALE * (1 - coords->velocity);
rate = gimp_paint_options_get_dynamics_mix (pressure, velocity);
}
return rate;
}

View File

@ -31,6 +31,7 @@
typedef struct _GimpPressureOptions GimpPressureOptions;
typedef struct _GimpVelocityOptions GimpVelocityOptions;
typedef struct _GimpFadeOptions GimpFadeOptions;
typedef struct _GimpJitterOptions GimpJitterOptions;
typedef struct _GimpGradientOptions GimpGradientOptions;
@ -46,6 +47,17 @@ struct _GimpPressureOptions
gboolean color;
};
struct _GimpVelocityOptions
{
gboolean expanded;
gboolean opacity;
gboolean hardness;
gboolean rate;
gboolean size;
gboolean inverse_size;
gboolean color;
};
struct _GimpFadeOptions
{
gboolean use_fade;
@ -76,6 +88,8 @@ struct _GimpGradientOptions
#define GIMP_IS_PAINT_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_PAINT_OPTIONS))
#define GIMP_PAINT_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_PAINT_OPTIONS, GimpPaintOptionsClass))
#define GIMP_PAINT_PRESSURE_SCALE 1.5
#define GIMP_PAINT_VELOCITY_SCALE 1.0
typedef struct _GimpPaintOptionsClass GimpPaintOptionsClass;
@ -93,6 +107,7 @@ struct _GimpPaintOptions
gboolean hard;
GimpPressureOptions *pressure_options;
GimpVelocityOptions *velocity_options;
GimpFadeOptions *fade_options;
GimpJitterOptions *jitter_options;
GimpGradientOptions *gradient_options;
@ -124,12 +139,23 @@ gdouble gimp_paint_options_get_jitter (GimpPaintOptions *paint_options,
gboolean gimp_paint_options_get_gradient_color (GimpPaintOptions *paint_options,
GimpImage *image,
gdouble pressure,
gdouble grad_point,
gdouble pixel_dist,
GimpRGB *color);
GimpBrushApplicationMode
gimp_paint_options_get_brush_mode (GimpPaintOptions *paint_options);
gdouble gimp_paint_options_get_dynamics_mix (gdouble mix1,
gdouble mix2);
gdouble gimp_paint_options_get_dynamic_opacity (GimpPaintOptions *paint_options,
const GimpCoords *coords,
gboolean use_pressure);
gdouble gimp_paint_options_get_dynamic_rate (GimpPaintOptions *paint_options,
const GimpCoords *coords,
gboolean use_pressure);
#endif /* __GIMP_PAINT_OPTIONS_H__ */

View File

@ -228,16 +228,16 @@ gimp_smudge_motion (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GimpPaintOptions *paint_options)
{
GimpSmudge *smudge = GIMP_SMUDGE (paint_core);
GimpSmudgeOptions *options = GIMP_SMUDGE_OPTIONS (paint_options);
GimpContext *context = GIMP_CONTEXT (paint_options);
GimpPressureOptions *pressure_options = paint_options->pressure_options;
GimpImage *image;
TempBuf *area;
PixelRegion srcPR, destPR, tempPR;
gdouble rate;
gdouble opacity;
gint x, y, w, h;
GimpSmudge *smudge = GIMP_SMUDGE (paint_core);
GimpSmudgeOptions *options = GIMP_SMUDGE_OPTIONS (paint_options);
GimpContext *context = GIMP_CONTEXT (paint_options);
GimpImage *image;
TempBuf *area;
PixelRegion srcPR, destPR, tempPR;
gdouble rate;
gdouble opacity;
gdouble dynamic_rate;
gint x, y, w, h;
image = gimp_item_get_image (GIMP_ITEM (drawable));
@ -261,12 +261,11 @@ gimp_smudge_motion (GimpPaintCore *paint_core,
pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable),
area->x, area->y, area->width, area->height, FALSE);
/* Enable pressure sensitive rate */
if (pressure_options->rate)
rate = MIN (options->rate / 100.0 * PRESSURE_SCALE *
paint_core->cur_coords.pressure, 1.0);
else
rate = options->rate / 100.0;
/* Enable dynamic rate */
dynamic_rate = gimp_paint_options_get_dynamic_rate (paint_options,
&paint_core->cur_coords,
paint_core->use_pressure);
rate = (options->rate / 100.0) * dynamic_rate;
/* The tempPR will be the built up buffer (for smudge) */
pixel_region_init_data (&tempPR, smudge->accum_data,
@ -305,8 +304,9 @@ gimp_smudge_motion (GimpPaintCore *paint_core,
else
copy_region (&tempPR, &destPR);
if (pressure_options->opacity)
opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure;
opacity *= gimp_paint_options_get_dynamic_opacity (paint_options,
&paint_core->cur_coords,
paint_core->use_pressure);
gimp_brush_core_replace_canvas (GIMP_BRUSH_CORE (paint_core), drawable,
MIN (opacity, GIMP_OPACITY_OPAQUE),

View File

@ -54,6 +54,9 @@
static GtkWidget * pressure_options_gui (GimpPressureOptions *pressure,
GimpPaintOptions *paint_options,
GType tool_type);
static GtkWidget * velocity_options_gui (GimpVelocityOptions *pressure,
GimpPaintOptions *paint_options,
GType tool_type);
static GtkWidget * fade_options_gui (GimpFadeOptions *fade,
GimpPaintOptions *paint_options,
GType tool_type);
@ -65,6 +68,7 @@ static GtkWidget * jitter_options_gui (GimpJitterOptions *jitter,
GimpPaintOptions *paint_options,
GType tool_type);
/* public functions */
GtkWidget *
@ -152,6 +156,14 @@ gimp_paint_options_gui (GimpToolOptions *tool_options)
gtk_widget_show (frame);
}
frame = velocity_options_gui (options->velocity_options,
options, tool_type);
if (frame)
{
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
}
frame = fade_options_gui (options->fade_options,
options, tool_type);
if (frame)
@ -318,6 +330,113 @@ pressure_options_gui (GimpPressureOptions *pressure,
return frame;
}
static GtkWidget *
velocity_options_gui (GimpVelocityOptions *velocity,
GimpPaintOptions *paint_options,
GType tool_type)
{
GObject *config = G_OBJECT (paint_options);
GtkWidget *frame = NULL;
GtkWidget *wbox = NULL;
GtkWidget *button;
if (g_type_is_a (tool_type, GIMP_TYPE_BRUSH_TOOL))
{
GtkWidget *inner_frame;
frame = gimp_prop_expander_new (G_OBJECT (paint_options),
"velocity-expanded",
_("Velocity sensitivity"));
inner_frame = gimp_frame_new ("<expander>");
gtk_container_add (GTK_CONTAINER (frame), inner_frame);
gtk_widget_show (inner_frame);
wbox = gtk_hwrap_box_new (FALSE);
gtk_wrap_box_set_aspect_ratio (GTK_WRAP_BOX (wbox), 4);
gtk_container_add (GTK_CONTAINER (inner_frame), wbox);
gtk_widget_show (wbox);
}
/* the opacity toggle */
if ((g_type_is_a (tool_type, GIMP_TYPE_PAINTBRUSH_TOOL) &&
(tool_type != GIMP_TYPE_AIRBRUSH_TOOL)) ||
tool_type == GIMP_TYPE_CLONE_TOOL ||
tool_type == GIMP_TYPE_HEAL_TOOL ||
tool_type == GIMP_TYPE_PERSPECTIVE_CLONE_TOOL ||
tool_type == GIMP_TYPE_DODGE_BURN_TOOL ||
tool_type == GIMP_TYPE_ERASER_TOOL)
{
button = gimp_prop_check_button_new (config, "velocity-opacity",
_("Opacity"));
gtk_container_add (GTK_CONTAINER (wbox), button);
gtk_widget_show (button);
}
/* the pressure toggle */
if (tool_type == GIMP_TYPE_AIRBRUSH_TOOL ||
tool_type == GIMP_TYPE_CLONE_TOOL ||
tool_type == GIMP_TYPE_HEAL_TOOL ||
tool_type == GIMP_TYPE_PERSPECTIVE_CLONE_TOOL ||
tool_type == GIMP_TYPE_CONVOLVE_TOOL ||
tool_type == GIMP_TYPE_DODGE_BURN_TOOL ||
tool_type == GIMP_TYPE_PAINTBRUSH_TOOL ||
tool_type == GIMP_TYPE_SMUDGE_TOOL)
{
button = gimp_prop_check_button_new (config, "velocity-hardness",
_("Hardness"));
gtk_container_add (GTK_CONTAINER (wbox), button);
gtk_widget_show (button);
}
/* the rate toggle */
if (tool_type == GIMP_TYPE_AIRBRUSH_TOOL ||
tool_type == GIMP_TYPE_CONVOLVE_TOOL ||
tool_type == GIMP_TYPE_SMUDGE_TOOL)
{
button = gimp_prop_check_button_new (config, "velocity-rate",
_("Rate"));
gtk_container_add (GTK_CONTAINER (wbox), button);
gtk_widget_show (button);
}
/* the size toggle */
if (tool_type == GIMP_TYPE_CLONE_TOOL ||
tool_type == GIMP_TYPE_HEAL_TOOL ||
tool_type == GIMP_TYPE_PERSPECTIVE_CLONE_TOOL ||
tool_type == GIMP_TYPE_CONVOLVE_TOOL ||
tool_type == GIMP_TYPE_DODGE_BURN_TOOL ||
tool_type == GIMP_TYPE_ERASER_TOOL ||
tool_type == GIMP_TYPE_PAINTBRUSH_TOOL ||
tool_type == GIMP_TYPE_PENCIL_TOOL)
{
button = gimp_prop_check_button_new (config, "velocity-size",
_("Size"));
gtk_container_add (GTK_CONTAINER (wbox), button);
gtk_widget_show (button);
}
/* the inverse size toggle */
if (tool_type == GIMP_TYPE_AIRBRUSH_TOOL)
{
button = gimp_prop_check_button_new (config, "velocity-inverse-size",
_("Size"));
gtk_container_add (GTK_CONTAINER (wbox), button);
gtk_widget_show (button);
}
/* the color toggle */
if (g_type_is_a (tool_type, GIMP_TYPE_PAINTBRUSH_TOOL))
{
button = gimp_prop_check_button_new (config, "velocity-color",
_("Color"));
gtk_container_add (GTK_CONTAINER (wbox), button);
gtk_widget_show (button);
}
return frame;
}
static GtkWidget *
fade_options_gui (GimpFadeOptions *fade,
GimpPaintOptions *paint_options,