Gimp/app/paint/gimppaintoptions.c
Alexia Death 9774988f30 Real dynamic hardness support for both generated and pixmap brushes.
For generated brushes, dynamic input is applied on top of the set hardness as a factor.
For pixmaps, it influences the amount of blur applied to the stamp. Be warned, process is slow
for large pixmaps. The odd feature previously advertised as hardness is left in but disabled.
If I figure out what it should be exposed as, it might be made available again.
2010-01-01 15:54:31 +02:00

656 lines
22 KiB
C

/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995-1999 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include "libgimpbase/gimpbase.h"
#include "libgimpmath/gimpmath.h"
#include "libgimpconfig/gimpconfig.h"
#include "paint-types.h"
#include "core/gimp.h"
#include "core/gimpimage.h"
#include "core/gimpdynamics.h"
#include "core/gimpdynamicsoutput.h"
#include "core/gimpgradient.h"
#include "core/gimppaintinfo.h"
#include "gimppaintoptions.h"
#include "gimp-intl.h"
#define DEFAULT_BRUSH_SCALE 1.0
#define DEFAULT_BRUSH_ASPECT_RATIO 1.0
#define DEFAULT_BRUSH_ANGLE 0.0
#define DEFAULT_APPLICATION_MODE GIMP_PAINT_CONSTANT
#define DEFAULT_HARD FALSE
#define DEFAULT_USE_FADE FALSE
#define DEFAULT_FADE_LENGTH 100.0
#define DEFAULT_FADE_REVERSE FALSE
#define DEFAULT_FADE_REPEAT GIMP_REPEAT_NONE
#define DEFAULT_FADE_UNIT GIMP_UNIT_PIXEL
#define DEFAULT_USE_JITTER FALSE
#define DEFAULT_JITTER_AMOUNT 0.2
#define DEFAULT_USE_GRADIENT FALSE
#define DEFAULT_GRADIENT_REVERSE FALSE
#define DEFAULT_GRADIENT_REPEAT GIMP_REPEAT_TRIANGULAR
#define DEFAULT_GRADIENT_LENGTH 100.0
#define DEFAULT_GRADIENT_UNIT GIMP_UNIT_PIXEL
#define DYNAMIC_MAX_VALUE 1.0
#define DYNAMIC_MIN_VALUE 0.0
enum
{
PROP_0,
PROP_PAINT_INFO,
PROP_BRUSH_SCALE,
PROP_BRUSH_ASPECT_RATIO,
PROP_BRUSH_ANGLE,
PROP_APPLICATION_MODE,
PROP_HARD,
PROP_USE_FADE,
PROP_FADE_LENGTH,
PROP_FADE_REVERSE,
PROP_FADE_REPEAT,
PROP_FADE_UNIT,
PROP_USE_JITTER,
PROP_JITTER_AMOUNT,
PROP_USE_GRADIENT,
PROP_GRADIENT_REVERSE,
PROP_BRUSH_VIEW_TYPE,
PROP_BRUSH_VIEW_SIZE,
PROP_PATTERN_VIEW_TYPE,
PROP_PATTERN_VIEW_SIZE,
PROP_GRADIENT_VIEW_TYPE,
PROP_GRADIENT_VIEW_SIZE
};
static void gimp_paint_options_finalize (GObject *object);
static void gimp_paint_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_paint_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_paint_options_notify (GObject *object,
GParamSpec *pspec);
G_DEFINE_TYPE (GimpPaintOptions, gimp_paint_options, GIMP_TYPE_TOOL_OPTIONS)
#define parent_class gimp_paint_options_parent_class
static void
gimp_paint_options_class_init (GimpPaintOptionsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gimp_paint_options_finalize;
object_class->set_property = gimp_paint_options_set_property;
object_class->get_property = gimp_paint_options_get_property;
object_class->notify = gimp_paint_options_notify;
g_object_class_install_property (object_class, PROP_PAINT_INFO,
g_param_spec_object ("paint-info",
NULL, NULL,
GIMP_TYPE_PAINT_INFO,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_BRUSH_SCALE,
"brush-scale", _("Brush Scale"),
0.01, 10.0, DEFAULT_BRUSH_SCALE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_BRUSH_ASPECT_RATIO,
"brush-aspect-ratio", _("Brush Aspect Ratio"),
0.01, 10.0, DEFAULT_BRUSH_ASPECT_RATIO,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_BRUSH_ANGLE,
"brush-angle", _("Brush Angle"),
-180.0, 180.0, DEFAULT_BRUSH_ANGLE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_APPLICATION_MODE,
"application-mode", NULL,
GIMP_TYPE_PAINT_APPLICATION_MODE,
DEFAULT_APPLICATION_MODE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_HARD,
"hard", NULL,
DEFAULT_HARD,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_USE_FADE,
"use-fade", NULL,
DEFAULT_USE_FADE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_FADE_LENGTH,
"fade-length", NULL,
0.0, 32767.0, DEFAULT_FADE_LENGTH,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_UNIT (object_class, PROP_FADE_UNIT,
"fade-unit", NULL,
TRUE, TRUE, DEFAULT_FADE_UNIT,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_FADE_REVERSE,
"fade-reverse", NULL,
DEFAULT_FADE_REVERSE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_FADE_REPEAT,
"fade-repeat", NULL,
GIMP_TYPE_REPEAT_MODE,
DEFAULT_FADE_REPEAT,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_USE_JITTER,
"use-jitter", NULL,
DEFAULT_USE_JITTER,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_JITTER_AMOUNT,
"jitter-amount", NULL,
0.0, 50.0, DEFAULT_JITTER_AMOUNT,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_USE_GRADIENT,
"use-gradient", NULL,
DEFAULT_USE_GRADIENT,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_GRADIENT_REVERSE,
"gradient-reverse", NULL,
DEFAULT_GRADIENT_REVERSE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_BRUSH_VIEW_TYPE,
"brush-view-type", NULL,
GIMP_TYPE_VIEW_TYPE,
GIMP_VIEW_TYPE_GRID,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_BRUSH_VIEW_SIZE,
"brush-view-size", NULL,
GIMP_VIEW_SIZE_TINY,
GIMP_VIEWABLE_MAX_BUTTON_SIZE,
GIMP_VIEW_SIZE_SMALL,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_PATTERN_VIEW_TYPE,
"pattern-view-type", NULL,
GIMP_TYPE_VIEW_TYPE,
GIMP_VIEW_TYPE_GRID,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_PATTERN_VIEW_SIZE,
"pattern-view-size", NULL,
GIMP_VIEW_SIZE_TINY,
GIMP_VIEWABLE_MAX_BUTTON_SIZE,
GIMP_VIEW_SIZE_SMALL,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_GRADIENT_VIEW_TYPE,
"gradient-view-type", NULL,
GIMP_TYPE_VIEW_TYPE,
GIMP_VIEW_TYPE_LIST,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_GRADIENT_VIEW_SIZE,
"gradient-view-size", NULL,
GIMP_VIEW_SIZE_TINY,
GIMP_VIEWABLE_MAX_BUTTON_SIZE,
GIMP_VIEW_SIZE_LARGE,
GIMP_PARAM_STATIC_STRINGS);
}
static void
gimp_paint_options_init (GimpPaintOptions *options)
{
options->application_mode_save = DEFAULT_APPLICATION_MODE;
options->fade_options = g_slice_new0 (GimpFadeOptions);
options->jitter_options = g_slice_new0 (GimpJitterOptions);
options->gradient_options = g_slice_new0 (GimpGradientOptions);
}
static void
gimp_paint_options_finalize (GObject *object)
{
GimpPaintOptions *options = GIMP_PAINT_OPTIONS (object);
if (options->paint_info)
g_object_unref (options->paint_info);
g_slice_free (GimpFadeOptions, options->fade_options);
g_slice_free (GimpJitterOptions, options->jitter_options);
g_slice_free (GimpGradientOptions, options->gradient_options);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gimp_paint_options_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpPaintOptions *options = GIMP_PAINT_OPTIONS (object);
GimpFadeOptions *fade_options = options->fade_options;
GimpJitterOptions *jitter_options = options->jitter_options;
GimpGradientOptions *gradient_options = options->gradient_options;
switch (property_id)
{
case PROP_PAINT_INFO:
options->paint_info = g_value_dup_object (value);
break;
case PROP_BRUSH_SCALE:
options->brush_scale = g_value_get_double (value);
break;
case PROP_BRUSH_ASPECT_RATIO:
options->brush_aspect_ratio = g_value_get_double (value);
break;
case PROP_BRUSH_ANGLE:
options->brush_angle = - 1.0 * g_value_get_double (value) / 360.0; /* let's make the angle mathematically correct */
break;
case PROP_APPLICATION_MODE:
options->application_mode = g_value_get_enum (value);
break;
case PROP_HARD:
options->hard = g_value_get_boolean (value);
break;
case PROP_USE_FADE:
fade_options->use_fade = g_value_get_boolean (value);
break;
case PROP_FADE_LENGTH:
fade_options->fade_length = g_value_get_double (value);
break;
case PROP_FADE_REVERSE:
fade_options->fade_reverse = g_value_get_boolean (value);
break;
case PROP_FADE_REPEAT:
fade_options->fade_repeat = g_value_get_enum (value);
break;
case PROP_FADE_UNIT:
fade_options->fade_unit = g_value_get_int (value);
break;
case PROP_USE_JITTER:
jitter_options->use_jitter = g_value_get_boolean (value);
break;
case PROP_JITTER_AMOUNT:
jitter_options->jitter_amount = g_value_get_double (value);
break;
case PROP_USE_GRADIENT:
gradient_options->use_gradient = g_value_get_boolean (value);
break;
case PROP_GRADIENT_REVERSE:
gradient_options->gradient_reverse = g_value_get_boolean (value);
break;
case PROP_BRUSH_VIEW_TYPE:
options->brush_view_type = g_value_get_enum (value);
break;
case PROP_BRUSH_VIEW_SIZE:
options->brush_view_size = g_value_get_int (value);
break;
case PROP_PATTERN_VIEW_TYPE:
options->pattern_view_type = g_value_get_enum (value);
break;
case PROP_PATTERN_VIEW_SIZE:
options->pattern_view_size = g_value_get_int (value);
break;
case PROP_GRADIENT_VIEW_TYPE:
options->gradient_view_type = g_value_get_enum (value);
break;
case PROP_GRADIENT_VIEW_SIZE:
options->gradient_view_size = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_paint_options_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpPaintOptions *options = GIMP_PAINT_OPTIONS (object);
GimpFadeOptions *fade_options = options->fade_options;
GimpJitterOptions *jitter_options = options->jitter_options;
GimpGradientOptions *gradient_options = options->gradient_options;
switch (property_id)
{
case PROP_PAINT_INFO:
g_value_set_object (value, options->paint_info);
break;
case PROP_BRUSH_SCALE:
g_value_set_double (value, options->brush_scale);
break;
case PROP_BRUSH_ASPECT_RATIO:
g_value_set_double (value, options->brush_aspect_ratio);
break;
case PROP_BRUSH_ANGLE:
g_value_set_double (value, - 1.0 * options->brush_angle * 360.0); /* mathematically correct -> intuitively correct */
break;
case PROP_APPLICATION_MODE:
g_value_set_enum (value, options->application_mode);
break;
case PROP_HARD:
g_value_set_boolean (value, options->hard);
break;
case PROP_USE_FADE:
g_value_set_boolean (value, fade_options->use_fade);
break;
case PROP_FADE_LENGTH:
g_value_set_double (value, fade_options->fade_length);
break;
case PROP_FADE_REVERSE:
g_value_set_boolean (value, fade_options->fade_reverse);
break;
case PROP_FADE_REPEAT:
g_value_set_enum (value, fade_options->fade_repeat);
break;
case PROP_FADE_UNIT:
g_value_set_int (value, fade_options->fade_unit);
break;
case PROP_USE_JITTER:
g_value_set_boolean (value, jitter_options->use_jitter);
break;
case PROP_JITTER_AMOUNT:
g_value_set_double (value, jitter_options->jitter_amount);
break;
case PROP_USE_GRADIENT:
g_value_set_boolean (value, gradient_options->use_gradient);
break;
case PROP_GRADIENT_REVERSE:
g_value_set_boolean (value, gradient_options->gradient_reverse);
break;
case PROP_BRUSH_VIEW_TYPE:
g_value_set_enum (value, options->brush_view_type);
break;
case PROP_BRUSH_VIEW_SIZE:
g_value_set_int (value, options->brush_view_size);
break;
case PROP_PATTERN_VIEW_TYPE:
g_value_set_enum (value, options->pattern_view_type);
break;
case PROP_PATTERN_VIEW_SIZE:
g_value_set_int (value, options->pattern_view_size);
break;
case PROP_GRADIENT_VIEW_TYPE:
g_value_set_enum (value, options->gradient_view_type);
break;
case PROP_GRADIENT_VIEW_SIZE:
g_value_set_int (value, options->gradient_view_size);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_paint_options_notify (GObject *object,
GParamSpec *pspec)
{
GimpPaintOptions *options = GIMP_PAINT_OPTIONS (object);
if (pspec->param_id == PROP_USE_GRADIENT)
{
if (options->gradient_options->use_gradient)
{
options->application_mode_save = options->application_mode;
options->application_mode = GIMP_PAINT_INCREMENTAL;
}
else
{
options->application_mode = options->application_mode_save;
}
g_object_notify (object, "application-mode");
}
if (G_OBJECT_CLASS (parent_class)->notify)
G_OBJECT_CLASS (parent_class)->notify (object, pspec);
}
GimpPaintOptions *
gimp_paint_options_new (GimpPaintInfo *paint_info)
{
GimpPaintOptions *options;
g_return_val_if_fail (GIMP_IS_PAINT_INFO (paint_info), NULL);
options = g_object_new (paint_info->paint_options_type,
"gimp", paint_info->gimp,
"name", gimp_object_get_name (paint_info),
"paint-info", paint_info,
NULL);
return options;
}
gdouble
gimp_paint_options_get_fade (GimpPaintOptions *paint_options,
GimpImage *image,
gdouble pixel_dist)
{
GimpFadeOptions *fade_options;
gdouble z = -1.0;
g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options),
DYNAMIC_MAX_VALUE);
g_return_val_if_fail (GIMP_IS_IMAGE (image), DYNAMIC_MAX_VALUE);
fade_options = paint_options->fade_options;
if (fade_options->use_fade)
{
gdouble fade_out = 0.0;
gdouble unit_factor;
gdouble pos;
switch (fade_options->fade_unit)
{
case GIMP_UNIT_PIXEL:
fade_out = fade_options->fade_length;
break;
case GIMP_UNIT_PERCENT:
fade_out = (MAX (gimp_image_get_width (image),
gimp_image_get_height (image)) *
fade_options->fade_length / 100);
break;
default:
{
gdouble xres;
gdouble yres;
gimp_image_get_resolution (image, &xres, &yres);
unit_factor = gimp_unit_get_factor (fade_options->fade_unit);
fade_out = (fade_options->fade_length *
MAX (xres, yres) / unit_factor);
}
break;
}
/* factor in the fade out value */
if (fade_out > 0.0)
{
pos = pixel_dist / fade_out;
}
else
pos = DYNAMIC_MAX_VALUE;
/* for no repeat, set pos close to 1.0 after the first chunk */
if (fade_options->fade_repeat == GIMP_REPEAT_NONE && pos >= DYNAMIC_MAX_VALUE)
pos = DYNAMIC_MAX_VALUE - 0.0000001;
if (((gint) pos & 1) &&
fade_options->fade_repeat != GIMP_REPEAT_SAWTOOTH)
pos = DYNAMIC_MAX_VALUE - (pos - (gint) pos);
else
pos = pos - (gint) pos;
/* Model the amount of paint left as a gaussian curve */
z = exp (- pos * pos * 5.541);
if (fade_options->fade_reverse)
z = 1.0 - z;
return z; /* ln (1/255) */
}
return DYNAMIC_MIN_VALUE;
}
gdouble
gimp_paint_options_get_jitter (GimpPaintOptions *paint_options,
GimpImage *image)
{
GimpJitterOptions *jitter_options;
g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), 0.0);
jitter_options = paint_options->jitter_options;
if (jitter_options->use_jitter)
{
return jitter_options->jitter_amount;
}
return 0.0;
}
gboolean
gimp_paint_options_get_gradient_color (GimpPaintOptions *paint_options,
GimpImage *image,
gdouble grad_point,
gdouble pixel_dist,
GimpRGB *color)
{
GimpGradientOptions *gradient_options;
GimpGradient *gradient;
GimpDynamics *dynamics;
g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), FALSE);
g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
g_return_val_if_fail (color != NULL, FALSE);
gradient_options = paint_options->gradient_options;
gradient = gimp_context_get_gradient (GIMP_CONTEXT (paint_options));
dynamics = gimp_context_get_dynamics (GIMP_CONTEXT (paint_options));
if (gimp_dynamics_output_is_enabled(dynamics->color_output) && gradient_options->use_gradient)
{
gimp_gradient_get_color_at (gradient, GIMP_CONTEXT (paint_options),
NULL, grad_point,
gradient_options->gradient_reverse,
color);
return TRUE;
}
return FALSE;
}
GimpBrushApplicationMode
gimp_paint_options_get_brush_mode (GimpPaintOptions *paint_options)
{
GimpDynamics *dynamics;
g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), GIMP_BRUSH_SOFT);
if (paint_options->hard)
return GIMP_BRUSH_HARD;
dynamics = gimp_context_get_dynamics (GIMP_CONTEXT (paint_options));
/* Im leaving the pressurize code in here, but Im not sure how,
* or if at all it should be used. Not as hardness anyway.
*
* if (gimp_dynamics_output_is_enabled(dynamics->hardness_output))
* return GIMP_BRUSH_PRESSURE; */
return GIMP_BRUSH_SOFT;
}