Made brushes scalable (both up and down) by using existing scaling

2007-03-11  Michael Schumacher  <schumaml@cvs.gnome.org>

	Made brushes scalable (both up and down) by using existing
	scaling routines, and also refactored some brush-code. Patch by
	Martin Nordholts. Fixes bug #65030.

	* app/paint/gimpbrushcore.c:
	(gimp_brush_core_calc_brush_length_scale) Refactored 'get brush
	size' code to where it belongs, in GimpBrush-classes, and renamed
	gimp_brush_core_calc_brush_size to
	gimp_brush_core_calc_brush_length_scale.

	* app/paint/gimppaintoptions.c (gimp_paint_options_class_init):
	Changed Scale scale to [0.0, 100.0].

	* app/base/temp-buf.[ch] (mask_buf_new): Change signature to also
	take a bpp parameter.

	* app/base/brush-scale.[ch]: Changed brush_scale_(mask|pixmap) to
	the new brush_scale_buf, which uses existing scaling routines
	(scale_region) instead of dedicated down-scaling only routines.

	* app/tools/gimppaintoptions-gui.c (gimp_paint_options_gui): Made
	the brush Scale-slider logarithmic.

	* app/core/gimpbrushgenerated.c: Implemented the new
	get_scaled_size method inherited from GimpBrush, and modified
	gimp_brush_generated_calc to use this helper function.

	* app/core/gimpbrush.[ch]: Added public virtual method
	get_scaled_size to GimpBrush, overridden by GimpBrushGenerated,
	which calculates the buffer sizes for a given brush scaled with a
	given scale. Also changed calls to brush_scale_(mask|pixmap) to
	the new brush_scale_buf.

svn path=/trunk/; revision=22099
This commit is contained in:
Michael Schumacher
2007-03-11 16:28:08 +00:00
committed by Michael Schumacher
parent 5eb341d2a5
commit a4e81c3a6c
11 changed files with 289 additions and 431 deletions

View File

@ -1,3 +1,38 @@
2007-03-11 Michael Schumacher <schumaml@cvs.gnome.org>
Made brushes scalable (both up and down) by using existing
scaling routines, and also refactored some brush-code. Patch by
Martin Nordholts. Fixes bug #65030.
* app/paint/gimpbrushcore.c:
(gimp_brush_core_calc_brush_length_scale) Refactored 'get brush
size' code to where it belongs, in GimpBrush-classes, and renamed
gimp_brush_core_calc_brush_size to
gimp_brush_core_calc_brush_length_scale.
* app/paint/gimppaintoptions.c (gimp_paint_options_class_init):
Changed Scale scale to [0.0, 100.0].
* app/base/temp-buf.[ch] (mask_buf_new): Change signature to also
take a bpp parameter.
* app/base/brush-scale.[ch]: Changed brush_scale_(mask|pixmap) to
the new brush_scale_buf, which uses existing scaling routines
(scale_region) instead of dedicated down-scaling only routines.
* app/tools/gimppaintoptions-gui.c (gimp_paint_options_gui): Made
the brush Scale-slider logarithmic.
* app/core/gimpbrushgenerated.c: Implemented the new
get_scaled_size method inherited from GimpBrush, and modified
gimp_brush_generated_calc to use this helper function.
* app/core/gimpbrush.[ch]: Added public virtual method
get_scaled_size to GimpBrush, overridden by GimpBrushGenerated,
which calculates the buffer sizes for a given brush scaled with a
given scale. Also changed calls to brush_scale_(mask|pixmap) to
the new brush_scale_buf.
2007-03-10 Sven Neumann <sven@gimp.org> 2007-03-10 Sven Neumann <sven@gimp.org>
* app/tools/gimpeditselectiontool.c (gimp_edit_selection_tool_motion): * app/tools/gimpeditselectiontool.c (gimp_edit_selection_tool_motion):

View File

@ -24,327 +24,40 @@
#include "brush-scale.h" #include "brush-scale.h"
#include "temp-buf.h" #include "temp-buf.h"
#include "pixel-region.h"
#include "paint-funcs/scale-funcs.h"
MaskBuf * MaskBuf *
brush_scale_mask (MaskBuf *brush_mask, brush_scale_buf (MaskBuf *brush_mask,
gint dest_width, gint dest_width,
gint dest_height) gint dest_height,
gint bpp)
{ {
MaskBuf *scale_brush; PixelRegion source_region;
gint src_width; PixelRegion dest_region;
gint src_height; MaskBuf *dest_brush_mask;
gint value;
gint area;
gint i, j;
gint x, x0, y, y0;
gint dx, dx0, dy, dy0;
gint fx, fx0, fy, fy0;
guchar *src, *dest;
g_return_val_if_fail (brush_mask != NULL && /* Use existing scaling routines for brush scaling. */
dest_width != 0 && dest_height != 0, NULL);
src_width = brush_mask->width; pixel_region_init_temp_buf (&source_region, brush_mask,
src_height = brush_mask->height; brush_mask->x,
brush_mask->y,
brush_mask->width,
brush_mask->height);
scale_brush = mask_buf_new (dest_width, dest_height); dest_brush_mask = mask_buf_new (dest_width, dest_height, bpp);
g_return_val_if_fail (scale_brush != NULL, NULL); g_return_val_if_fail (dest_brush_mask != NULL, NULL);
/* get the data */ pixel_region_init_temp_buf (&dest_region, dest_brush_mask,
dest = mask_buf_data (scale_brush); brush_mask->x,
src = mask_buf_data (brush_mask); brush_mask->y,
dest_width,
dest_height);
fx = fx0 = (256.0 * src_width) / dest_width; scale_region (&source_region, &dest_region, GIMP_INTERPOLATION_LINEAR,
fy = fy0 = (256.0 * src_height) / dest_height; NULL, NULL);
area = (fx0 * fy0) >> 8;
x = x0 = 0; return dest_brush_mask;
y = y0 = 0;
dx = dx0 = 0;
dy = dy0 = 0;
for (i=0; i<dest_height; i++)
{
for (j=0; j<dest_width; j++)
{
value = 0;
fy = fy0;
y = y0;
dy = dy0;
if (dy)
{
fx = fx0;
x = x0;
dx = dx0;
if (dx)
{
value += (dx * dy * src[x + src_width * y]) >> 8;
x++;
fx -= dx;
dx = 0;
}
while (fx >= 256)
{
value += dy * src[x + src_width * y];
x++;
fx -= 256;
}
if (fx)
{
value += fx * dy * src[x + src_width * y] >> 8;
dx = 256 - fx;
}
y++;
fy -= dy;
dy = 0;
}
while (fy >= 256)
{
fx = fx0;
x = x0;
dx = dx0;
if (dx)
{
value += dx * src[x + src_width * y];
x++;
fx -= dx;
dx = 0;
}
while (fx >= 256)
{
value += 256 * src[x + src_width * y];
x++;
fx -= 256;
}
if (fx)
{
value += fx * src[x + src_width * y];
dx = 256 - fx;
}
y++;
fy -= 256;
}
if (fy)
{
fx = fx0;
x = x0;
dx = dx0;
if (dx)
{
value += (dx * fy * src[x + src_width * y]) >> 8;
x++;
fx -= dx;
dx = 0;
}
while (fx >= 256)
{
value += fy * src[x + src_width * y];
x++;
fx -= 256;
}
if (fx)
{
value += (fx * fy * src[x + src_width * y]) >> 8;
dx = 256 - fx;
}
dy = 256 - fy;
}
*dest++ = MIN ((value / area), 255);
x0 = x;
dx0 = dx;
}
x0 = 0;
dx0 = 0;
y0 = y;
dy0 = dy;
}
return scale_brush;
} }
#define ADD_RGB(dest, factor, src) \
dest[0] += factor * src[0]; \
dest[1] += factor * src[1]; \
dest[2] += factor * src[2];
MaskBuf *
brush_scale_pixmap (MaskBuf *pixmap,
gint dest_width,
gint dest_height)
{
MaskBuf *scale_brush;
gint src_width;
gint src_height;
gint value[3];
gint factor;
gint area;
gint i, j;
gint x, x0, y, y0;
gint dx, dx0, dy, dy0;
gint fx, fx0, fy, fy0;
guchar *src, *src_ptr, *dest;
g_return_val_if_fail (pixmap != NULL && pixmap->bytes == 3 &&
dest_width != 0 && dest_height != 0, NULL);
src_width = pixmap->width;
src_height = pixmap->height;
scale_brush = temp_buf_new (dest_width, dest_height, 3, 0, 0, NULL);
g_return_val_if_fail (scale_brush != NULL, NULL);
/* get the data */
dest = mask_buf_data (scale_brush);
src = mask_buf_data (pixmap);
fx = fx0 = (256.0 * src_width) / dest_width;
fy = fy0 = (256.0 * src_height) / dest_height;
area = (fx0 * fy0) >> 8;
x = x0 = 0;
y = y0 = 0;
dx = dx0 = 0;
dy = dy0 = 0;
for (i=0; i<dest_height; i++)
{
for (j=0; j<dest_width; j++)
{
value[0] = 0;
value[1] = 0;
value[2] = 0;
fy = fy0;
y = y0;
dy = dy0;
if (dy)
{
fx = fx0;
x = x0;
dx = dx0;
if (dx)
{
factor = (dx * dy) >> 8;
src_ptr = src + 3 * (x + y * src_width);
ADD_RGB (value, factor, src_ptr);
x++;
fx -= dx;
dx = 0;
}
while (fx >= 256)
{
factor = dy;
src_ptr = src + 3 * (x + y * src_width);
ADD_RGB (value, factor, src_ptr);
x++;
fx -= 256;
}
if (fx)
{
factor = (fx * dy) >> 8;
src_ptr = src + 3 * (x + y * src_width);
ADD_RGB (value, factor, src_ptr);
dx = 256 - fx;
}
y++;
fy -= dy;
dy = 0;
}
while (fy >= 256)
{
fx = fx0;
x = x0;
dx = dx0;
if (dx)
{
factor = dx;
src_ptr = src + 3 * (x + y * src_width);
ADD_RGB (value, factor, src_ptr);
x++;
fx -= dx;
dx = 0;
}
while (fx >= 256)
{
factor = 256;
src_ptr = src + 3 * (x + y * src_width);
ADD_RGB (value, factor, src_ptr);
x++;
fx -= 256;
}
if (fx)
{
factor = fx;
src_ptr = src + 3 * (x + y * src_width);
ADD_RGB (value, factor, src_ptr);
dx = 256 - fx;
}
y++;
fy -= 256;
}
if (fy)
{
fx = fx0;
x = x0;
dx = dx0;
if (dx)
{
factor = (dx * fy) >> 8;
src_ptr = src + 3 * (x + y * src_width);
ADD_RGB (value, factor, src_ptr);
x++;
fx -= dx;
dx = 0;
}
while (fx >= 256)
{
factor = fy;
src_ptr = src + 3 * (x + y * src_width);
ADD_RGB (value, factor, src_ptr);
x++;
fx -= 256;
}
if (fx)
{
factor = (fx * fy) >> 8;
src_ptr = src + 3 * (x + y * src_width);
ADD_RGB (value, factor, src_ptr);
dx = 256 - fx;
}
dy = 256 - fy;
}
*dest++ = MIN ((value[0] / area), 255);
*dest++ = MIN ((value[1] / area), 255);
*dest++ = MIN ((value[2] / area), 255);
x0 = x;
dx0 = dx;
}
x0 = 0;
dx0 = 0;
y0 = y;
dy0 = dy;
}
return scale_brush;
}
#undef ADD_RGB

View File

@ -20,12 +20,10 @@
#define __BRUSH_SCALE_H__ #define __BRUSH_SCALE_H__
MaskBuf * brush_scale_mask (MaskBuf *brush_mask, MaskBuf * brush_scale_buf (MaskBuf *brush_mask,
gint dest_width, gint dest_width,
gint dest_height); gint dest_height,
MaskBuf * brush_scale_pixmap (MaskBuf *pixmap, gint bpp);
gint dest_width,
gint dest_height);
#endif /* __BRUSH_SCALE_H__ */ #endif /* __BRUSH_SCALE_H__ */

View File

@ -487,11 +487,12 @@ temp_buf_to_gray (TempBuf *src_buf,
MaskBuf * MaskBuf *
mask_buf_new (gint width, mask_buf_new (gint width,
gint height) gint height,
gint bpp)
{ {
static guchar empty = 0; static guchar empty = 0;
return temp_buf_new (width, height, 1, 0, 0, &empty); return temp_buf_new (width, height, bpp, 0, 0, &empty);
} }
void void

View File

@ -72,7 +72,8 @@ gsize temp_buf_get_memsize (TempBuf *buf);
/* The mask buffer functions */ /* The mask buffer functions */
MaskBuf * mask_buf_new (gint width, MaskBuf * mask_buf_new (gint width,
gint height); gint height,
gint bpp);
void mask_buf_free (MaskBuf *mask_buf); void mask_buf_free (MaskBuf *mask_buf);
guchar * mask_buf_data (MaskBuf *mask_buf); guchar * mask_buf_data (MaskBuf *mask_buf);
guchar * mask_buf_data_clear (MaskBuf *mask_buf); guchar * mask_buf_data_clear (MaskBuf *mask_buf);

View File

@ -83,6 +83,10 @@ static TempBuf * gimp_brush_real_scale_mask (GimpBrush *brush,
static TempBuf * gimp_brush_real_scale_pixmap (GimpBrush *brush, static TempBuf * gimp_brush_real_scale_pixmap (GimpBrush *brush,
gdouble scale); gdouble scale);
static void gimp_brush_real_get_scaled_size (GimpBrush *brush,
gdouble scale,
gint *scaled_width,
gint *scaled_height);
G_DEFINE_TYPE (GimpBrush, gimp_brush, GIMP_TYPE_DATA) G_DEFINE_TYPE (GimpBrush, gimp_brush, GIMP_TYPE_DATA)
@ -125,6 +129,7 @@ gimp_brush_class_init (GimpBrushClass *klass)
klass->want_null_motion = gimp_brush_real_want_null_motion; klass->want_null_motion = gimp_brush_real_want_null_motion;
klass->scale_mask = gimp_brush_real_scale_mask; klass->scale_mask = gimp_brush_real_scale_mask;
klass->scale_pixmap = gimp_brush_real_scale_pixmap; klass->scale_pixmap = gimp_brush_real_scale_pixmap;
klass->get_scaled_size = gimp_brush_real_get_scaled_size;
klass->spacing_changed = NULL; klass->spacing_changed = NULL;
g_object_class_install_property (object_class, PROP_SPACING, g_object_class_install_property (object_class, PROP_SPACING,
@ -270,15 +275,15 @@ gimp_brush_get_new_preview (GimpViewable *viewable,
if (brush_width <= 0) brush_width = 1; if (brush_width <= 0) brush_width = 1;
if (brush_height <= 0) brush_height = 1; if (brush_height <= 0) brush_height = 1;
mask_buf = brush_scale_mask (mask_buf, brush_width, brush_height); mask_buf = brush_scale_buf (mask_buf, brush_width, brush_height, mask_buf->bytes);
if (pixmap_buf) if (pixmap_buf)
{ {
/* TODO: the scale function should scale the pixmap and the /* TODO: the scale function should scale the pixmap and the
* mask in one run * mask in one run
*/ */
pixmap_buf = brush_scale_pixmap (pixmap_buf, pixmap_buf = brush_scale_buf (pixmap_buf,
brush_width, brush_height); brush_width, brush_height, pixmap_buf->bytes);
} }
scale = TRUE; scale = TRUE;
@ -370,11 +375,10 @@ gimp_brush_real_scale_mask (GimpBrush *brush,
gint width; gint width;
gint height; gint height;
width = (gint) (brush->mask->width * scale + 0.5); gimp_brush_get_scaled_size (brush, scale, &width, &height);
height = (gint) (brush->mask->height * scale + 0.5);
if (width > 0 && height > 0) if (width > 0 && height > 0)
return brush_scale_mask (brush->mask, width, height); return brush_scale_buf (brush->mask, width, height, brush->mask->bytes);
return NULL; return NULL;
} }
@ -386,15 +390,23 @@ gimp_brush_real_scale_pixmap (GimpBrush *brush,
gint width; gint width;
gint height; gint height;
width = (gint) (brush->pixmap->width * scale + 0.5); gimp_brush_get_scaled_size (brush, scale, &width, &height);
height = (gint) (brush->pixmap->height * scale + 0.5);
if (width > 0 && height > 0) if (width > 0 && height > 0)
return brush_scale_pixmap (brush->pixmap, width, height); return brush_scale_buf (brush->pixmap, width, height, brush->pixmap->bytes);
return NULL; return NULL;
} }
static void
gimp_brush_real_get_scaled_size (GimpBrush *brush,
gdouble scale,
gint *width,
gint *height)
{
*width = (gint) (brush->mask->width * scale + 0.5);
*height = (gint) (brush->mask->height * scale + 0.5);
}
/* public functions */ /* public functions */
@ -476,6 +488,18 @@ gimp_brush_scale_pixmap (GimpBrush *brush,
return GIMP_BRUSH_GET_CLASS (brush)->scale_pixmap (brush, scale); return GIMP_BRUSH_GET_CLASS (brush)->scale_pixmap (brush, scale);
} }
void
gimp_brush_get_scaled_size (GimpBrush *brush,
gdouble scale,
gint *width,
gint *height)
{
g_return_if_fail (GIMP_IS_BRUSH (brush));
g_return_if_fail (scale > 0.0);
return GIMP_BRUSH_GET_CLASS (brush)->get_scaled_size (brush, scale, width, height);
}
TempBuf * TempBuf *
gimp_brush_get_mask (const GimpBrush *brush) gimp_brush_get_mask (const GimpBrush *brush)
{ {

View File

@ -61,6 +61,10 @@ struct _GimpBrushClass
gdouble scale); gdouble scale);
TempBuf * (* scale_pixmap) (GimpBrush *brush, TempBuf * (* scale_pixmap) (GimpBrush *brush,
gdouble scale); gdouble scale);
void (* get_scaled_size) (GimpBrush *brush,
gdouble scale,
gint *width,
gint *height);
/* signals */ /* signals */
void (* spacing_changed) (GimpBrush *brush); void (* spacing_changed) (GimpBrush *brush);
@ -84,6 +88,12 @@ TempBuf * gimp_brush_scale_mask (GimpBrush *brush,
TempBuf * gimp_brush_scale_pixmap (GimpBrush *brush, TempBuf * gimp_brush_scale_pixmap (GimpBrush *brush,
gdouble scale); gdouble scale);
/* Gets width and height of the scaled mask of the brush, with given scale. */
void gimp_brush_get_scaled_size (GimpBrush *brush,
gdouble scale,
gint *width,
gint *height);
TempBuf * gimp_brush_get_mask (const GimpBrush *brush); TempBuf * gimp_brush_get_mask (const GimpBrush *brush);
TempBuf * gimp_brush_get_pixmap (const GimpBrush *brush); TempBuf * gimp_brush_get_pixmap (const GimpBrush *brush);

View File

@ -64,6 +64,25 @@ static gchar * gimp_brush_generated_get_extension (GimpData *data);
static GimpData * gimp_brush_generated_duplicate (GimpData *data); static GimpData * gimp_brush_generated_duplicate (GimpData *data);
static TempBuf * gimp_brush_generated_scale_mask (GimpBrush *gbrush, static TempBuf * gimp_brush_generated_scale_mask (GimpBrush *gbrush,
gdouble scale); gdouble scale);
static void gimp_brush_generated_get_half_width_and_height
(GimpBrushGenerated *gbrush,
GimpBrushGeneratedShape shape,
gfloat radius,
gint spikes,
gfloat hardness,
gfloat aspect_ratio,
gdouble angle_in_degrees,
gint *half_width,
gint *half_height,
gdouble *_s,
gdouble *_c,
GimpVector2 *_x_axis,
GimpVector2 *_y_axis);
static void gimp_brush_generated_real_get_scaled_size
(GimpBrush *gbrush,
gdouble scale,
gint *width,
gint *height);
G_DEFINE_TYPE (GimpBrushGenerated, gimp_brush_generated, GIMP_TYPE_BRUSH) G_DEFINE_TYPE (GimpBrushGenerated, gimp_brush_generated, GIMP_TYPE_BRUSH)
@ -87,6 +106,7 @@ gimp_brush_generated_class_init (GimpBrushGeneratedClass *klass)
data_class->duplicate = gimp_brush_generated_duplicate; data_class->duplicate = gimp_brush_generated_duplicate;
brush_class->scale_mask = gimp_brush_generated_scale_mask; brush_class->scale_mask = gimp_brush_generated_scale_mask;
brush_class->get_scaled_size = gimp_brush_generated_real_get_scaled_size;
g_object_class_install_property (object_class, PROP_SHAPE, g_object_class_install_property (object_class, PROP_SHAPE,
g_param_spec_enum ("shape", NULL, NULL, g_param_spec_enum ("shape", NULL, NULL,
@ -254,62 +274,31 @@ gimp_brush_generated_calc (GimpBrushGenerated *brush,
gdouble exponent; gdouble exponent;
guchar a; guchar a;
gint length; gint length;
gint width = 0; gint half_width = 0;
gint height = 0; gint half_height = 0;
guchar *lookup; guchar *lookup;
gdouble sum; gdouble sum;
gdouble c, s, cs, ss; gdouble c, s, cs, ss;
gdouble short_radius;
gdouble buffer[OVERSAMPLING]; gdouble buffer[OVERSAMPLING];
GimpVector2 x_axis; GimpVector2 x_axis;
GimpVector2 y_axis; GimpVector2 y_axis;
TempBuf *mask; TempBuf *mask;
s = sin (gimp_deg_to_rad (angle)); gimp_brush_generated_get_half_width_and_height (brush,
c = cos (gimp_deg_to_rad (angle)); shape,
radius,
spikes,
hardness,
aspect_ratio,
angle,
&half_width, &half_height,
&s, &c, &x_axis, &y_axis);
short_radius = radius / aspect_ratio; mask = temp_buf_new (half_width * 2 + 1,
half_height * 2 + 1,
1, half_width, half_height, NULL);
x_axis.x = c * radius; centerp = temp_buf_data (mask) + half_height * mask->width + half_width;
x_axis.y = -1.0 * s * radius;
y_axis.x = s * short_radius;
y_axis.y = c * short_radius;
switch (shape)
{
case GIMP_BRUSH_GENERATED_CIRCLE:
width = ceil (sqrt (x_axis.x * x_axis.x + y_axis.x * y_axis.x));
height = ceil (sqrt (x_axis.y * x_axis.y + y_axis.y * y_axis.y));
break;
case GIMP_BRUSH_GENERATED_SQUARE:
width = ceil (fabs (x_axis.x) + fabs (y_axis.x));
height = ceil (fabs (x_axis.y) + fabs (y_axis.y));
break;
case GIMP_BRUSH_GENERATED_DIAMOND:
width = ceil (MAX (fabs (x_axis.x), fabs (y_axis.x)));
height = ceil (MAX (fabs (x_axis.y), fabs (y_axis.y)));
break;
default:
g_return_val_if_reached (NULL);
}
if (spikes > 2)
{
/* could be optimized by respecting the angle */
width = height = ceil (sqrt (radius * radius +
short_radius * short_radius));
y_axis.x = s * radius;
y_axis.y = c * radius;
}
mask = temp_buf_new (width * 2 + 1,
height * 2 + 1,
1, width, height, NULL);
centerp = temp_buf_data (mask) + height * mask->width + width;
/* set up lookup table */ /* set up lookup table */
length = OVERSAMPLING * ceil (1 + sqrt (2 * length = OVERSAMPLING * ceil (1 + sqrt (2 *
@ -358,9 +347,9 @@ gimp_brush_generated_calc (GimpBrushGenerated *brush,
ss = sin (- 2 * G_PI / spikes); ss = sin (- 2 * G_PI / spikes);
/* for an even number of spikes compute one half and mirror it */ /* for an even number of spikes compute one half and mirror it */
for (y = (spikes % 2 ? -height : 0); y <= height; y++) for (y = (spikes % 2 ? -half_height : 0); y <= half_height; y++)
{ {
for (x = -width; x <= width; x++) for (x = -half_width; x <= half_width; x++)
{ {
gdouble tx, ty, angle; gdouble tx, ty, angle;
@ -454,6 +443,108 @@ gimp_brush_generated_scale_mask (GimpBrush *gbrush,
NULL, NULL); NULL, NULL);
} }
/* This function is shared between gimp_brush_get_scaled_size and
gimp_brush_generated_calc, therefore we provide a bunch of optional pointers
for returnvalues. */
static void
gimp_brush_generated_get_half_width_and_height
(GimpBrushGenerated *gbrush,
GimpBrushGeneratedShape shape,
gfloat radius,
gint spikes,
gfloat hardness,
gfloat aspect_ratio,
gdouble angle_in_degrees,
gint *half_width,
gint *half_height,
gdouble *_s,
gdouble *_c,
GimpVector2 *_x_axis,
GimpVector2 *_y_axis)
{
gdouble c, s;
gdouble short_radius;
GimpVector2 x_axis;
GimpVector2 y_axis;
s = sin (gimp_deg_to_rad (angle_in_degrees));
c = cos (gimp_deg_to_rad (angle_in_degrees));
short_radius = radius / aspect_ratio;
x_axis.x = c * radius;
x_axis.y = -1.0 * s * radius;
y_axis.x = s * short_radius;
y_axis.y = c * short_radius;
switch (shape)
{
case GIMP_BRUSH_GENERATED_CIRCLE:
*half_width = ceil (sqrt (x_axis.x * x_axis.x + y_axis.x * y_axis.x));
*half_height = ceil (sqrt (x_axis.y * x_axis.y + y_axis.y * y_axis.y));
break;
case GIMP_BRUSH_GENERATED_SQUARE:
*half_width = ceil (fabs (x_axis.x) + fabs (y_axis.x));
*half_height = ceil (fabs (x_axis.y) + fabs (y_axis.y));
break;
case GIMP_BRUSH_GENERATED_DIAMOND:
*half_width = ceil (MAX (fabs (x_axis.x), fabs (y_axis.x)));
*half_height = ceil (MAX (fabs (x_axis.y), fabs (y_axis.y)));
break;
}
if (spikes > 2)
{
/* could be optimized by respecting the angle */
*half_width = *half_height = ceil (sqrt (radius * radius +
short_radius * short_radius));
y_axis.x = s * radius;
y_axis.y = c * radius;
}
/* These will typically be set then this function is called by
gimp_brush_generated_calc, which needs the values in its algorithms. */
if (_s != NULL)
*_s = s;
if (_c != NULL)
*_c = c;
if (_x_axis != NULL)
*_x_axis = x_axis;
if (_y_axis != NULL)
*_y_axis = y_axis;
}
static void
gimp_brush_generated_real_get_scaled_size (GimpBrush *brush,
gdouble scale,
gint *width,
gint *height)
{
GimpBrushGenerated *gbrush;
gint half_width;
gint half_height;
gbrush = GIMP_BRUSH_GENERATED (brush);
gimp_brush_generated_get_half_width_and_height (gbrush,
gbrush->shape,
gbrush->radius * scale,
gbrush->spikes,
gbrush->hardness,
gbrush->aspect_ratio,
gbrush->angle,
&half_width, &half_height,
NULL, NULL, NULL, NULL);
*width = half_width * 2 + 1;
*height = half_height * 2 + 1;
}
GimpData * GimpData *
gimp_brush_generated_new (const gchar *name, gimp_brush_generated_new (const gchar *name,
GimpBrushGeneratedShape shape, GimpBrushGeneratedShape shape,

View File

@ -83,11 +83,10 @@ static TempBuf *gimp_brush_core_get_paint_area (GimpPaintCore *paint_core,
static void gimp_brush_core_real_set_brush (GimpBrushCore *core, static void gimp_brush_core_real_set_brush (GimpBrushCore *core,
GimpBrush *brush); GimpBrush *brush);
static gdouble gimp_brush_core_calc_brush_size (GimpBrushCore *core, static gdouble gimp_brush_core_calc_brush_length_scale
MaskBuf *mask, (GimpBrushCore *core,
gdouble scale, gdouble scale);
gint *width,
gint *height);
static inline void rotate_pointers (gulong **p, static inline void rotate_pointers (gulong **p,
guint32 n); guint32 n);
static MaskBuf * gimp_brush_core_subsample_mask (GimpBrushCore *core, static MaskBuf * gimp_brush_core_subsample_mask (GimpBrushCore *core,
@ -447,8 +446,7 @@ gimp_brush_core_interpolate (GimpPaintCore *paint_core,
! delta_wheel) ! delta_wheel)
return; return;
scale = gimp_brush_core_calc_brush_size (core, NULL, core->scale, scale = gimp_brush_core_calc_brush_length_scale (core, core->scale);
NULL, NULL);
/* calculate the distance traveled in the coordinate space of the brush */ /* calculate the distance traveled in the coordinate space of the brush */
temp_vec = core->brush->x_axis; temp_vec = core->brush->x_axis;
@ -681,6 +679,7 @@ gimp_brush_core_get_paint_area (GimpPaintCore *paint_core,
GimpPaintOptions *paint_options) GimpPaintOptions *paint_options)
{ {
GimpBrushCore *core = GIMP_BRUSH_CORE (paint_core); GimpBrushCore *core = GIMP_BRUSH_CORE (paint_core);
gdouble length_scale;
gint x, y; gint x, y;
gint x1, y1, x2, y2; gint x1, y1, x2, y2;
gint drawable_width, drawable_height; gint drawable_width, drawable_height;
@ -703,8 +702,8 @@ gimp_brush_core_get_paint_area (GimpPaintCore *paint_core,
core->scale *= paint_options->brush_scale; core->scale *= paint_options->brush_scale;
} }
gimp_brush_core_calc_brush_size (core, core->brush->mask, core->scale, length_scale = gimp_brush_core_calc_brush_length_scale (core, core->scale);
&brush_width, &brush_height); gimp_brush_get_scaled_size (core->brush, length_scale, &brush_width, &brush_height);
/* adjust the x and y coordinates to the upper left corner of the brush */ /* adjust the x and y coordinates to the upper left corner of the brush */
x = (gint) floor (paint_core->cur_coords.x) - (brush_width >> 1); x = (gint) floor (paint_core->cur_coords.x) - (brush_width >> 1);
@ -784,8 +783,6 @@ gimp_brush_core_create_bound_segs (GimpBrushCore *core,
{ {
TempBuf *mask = NULL; TempBuf *mask = NULL;
gdouble scale = 1.0; gdouble scale = 1.0;
gint brush_width;
gint brush_height;
g_return_if_fail (GIMP_IS_BRUSH_CORE (core)); g_return_if_fail (GIMP_IS_BRUSH_CORE (core));
g_return_if_fail (core->main_brush != NULL); g_return_if_fail (core->main_brush != NULL);
@ -794,8 +791,7 @@ gimp_brush_core_create_bound_segs (GimpBrushCore *core,
if (GIMP_BRUSH_CORE_GET_CLASS (core)->use_scale) if (GIMP_BRUSH_CORE_GET_CLASS (core)->use_scale)
scale *= paint_options->brush_scale; scale *= paint_options->brush_scale;
scale = gimp_brush_core_calc_brush_size (core, core->main_brush->mask, scale, scale = gimp_brush_core_calc_brush_length_scale (core, scale);
&brush_width, &brush_height);
if (scale > 0.0) if (scale > 0.0)
mask = gimp_brush_scale_mask (core->main_brush, scale); mask = gimp_brush_scale_mask (core->main_brush, scale);
@ -932,25 +928,14 @@ gimp_brush_core_invalidate_cache (GimpBrush *brush,
************************************************************/ ************************************************************/
static gdouble static gdouble
gimp_brush_core_calc_brush_size (GimpBrushCore *core, gimp_brush_core_calc_brush_length_scale (GimpBrushCore *core,
MaskBuf *mask, gdouble scale)
gdouble scale,
gint *width,
gint *height)
{ {
gdouble ratio = 1.0; gdouble ratio = 1.0;
scale = CLAMP (scale, 0.0, 1.0);
if (scale == 1.0) if (scale == 1.0)
{ {
ratio = scale; ratio = scale;
if (mask)
{
*width = mask->width;
*height = mask->height;
}
} }
else else
{ {
@ -958,12 +943,6 @@ gimp_brush_core_calc_brush_size (GimpBrushCore *core,
ratio = 1 / 16; ratio = 1 / 16;
else else
ratio = sqrt (scale); ratio = sqrt (scale);
if (mask)
{
*width = MAX ((gint) (mask->width * ratio + 0.5), 1);
*height = MAX ((gint) (mask->height * ratio + 0.5), 1);
}
} }
return ratio; return ratio;
@ -1063,7 +1042,8 @@ gimp_brush_core_subsample_mask (GimpBrushCore *core,
} }
dest = mask_buf_new (mask->width + 2, dest = mask_buf_new (mask->width + 2,
mask->height + 2); mask->height + 2,
mask->bytes);
/* Allocate and initialize the accum buffer */ /* Allocate and initialize the accum buffer */
for (i = 0; i < KERNEL_HEIGHT ; i++) for (i = 0; i < KERNEL_HEIGHT ; i++)
@ -1142,7 +1122,8 @@ gimp_brush_core_pressurize_mask (GimpBrushCore *core,
mask_buf_free (core->pressure_brush); mask_buf_free (core->pressure_brush);
core->pressure_brush = mask_buf_new (brush_mask->width + 2, core->pressure_brush = mask_buf_new (brush_mask->width + 2,
brush_mask->height + 2); brush_mask->height + 2,
1);
#ifdef FANCY_PRESSURE #ifdef FANCY_PRESSURE
/* Create the pressure profile /* Create the pressure profile
@ -1278,7 +1259,8 @@ gimp_brush_core_solidify_mask (GimpBrushCore *core,
} }
dest = mask_buf_new (brush_mask->width + 2, dest = mask_buf_new (brush_mask->width + 2,
brush_mask->height + 2); brush_mask->height + 2,
brush_mask->bytes);
core->solid_brushes[dest_offset_y][dest_offset_x] = dest; core->solid_brushes[dest_offset_y][dest_offset_x] = dest;
@ -1314,8 +1296,8 @@ gimp_brush_core_scale_mask (GimpBrushCore *core,
if (scale == 1.0) if (scale == 1.0)
return brush->mask; return brush->mask;
scale = gimp_brush_core_calc_brush_size (core, brush->mask, scale, scale = gimp_brush_core_calc_brush_length_scale (core, scale);
&dest_width, &dest_height); gimp_brush_get_scaled_size (brush, scale, &dest_width, &dest_height);
if (! core->cache_invalid && if (! core->cache_invalid &&
brush->mask == core->last_scale_brush && brush->mask == core->last_scale_brush &&
@ -1357,8 +1339,7 @@ gimp_brush_core_scale_pixmap (GimpBrushCore *core,
if (scale == 1.0) if (scale == 1.0)
return brush->pixmap; return brush->pixmap;
scale = gimp_brush_core_calc_brush_size (core, brush->pixmap, scale, scale = gimp_brush_core_calc_brush_length_scale (core, scale);
&dest_width, &dest_height);
if (! core->cache_invalid && if (! core->cache_invalid &&
brush->pixmap == core->last_scale_pixmap && brush->pixmap == core->last_scale_pixmap &&

View File

@ -131,7 +131,7 @@ gimp_paint_options_class_init (GimpPaintOptionsClass *klass)
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_BRUSH_SCALE, GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_BRUSH_SCALE,
"brush-scale", NULL, "brush-scale", NULL,
0.0, 1.0, DEFAULT_BRUSH_SCALE, 0.0, 100.0, DEFAULT_BRUSH_SCALE,
GIMP_PARAM_STATIC_STRINGS); GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_APPLICATION_MODE, GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_APPLICATION_MODE,
"application-mode", NULL, "application-mode", NULL,

View File

@ -78,6 +78,7 @@ gimp_paint_options_gui (GimpToolOptions *tool_options)
GtkWidget *menu; GtkWidget *menu;
GtkWidget *label; GtkWidget *label;
GtkWidget *button; GtkWidget *button;
GtkWidget *adj;
GtkWidget *incremental_toggle = NULL; GtkWidget *incremental_toggle = NULL;
gint table_row = 0; gint table_row = 0;
GType tool_type; GType tool_type;
@ -124,11 +125,14 @@ gimp_paint_options_gui (GimpToolOptions *tool_options)
if (tool_type != GIMP_TYPE_SMUDGE_TOOL) if (tool_type != GIMP_TYPE_SMUDGE_TOOL)
{ {
gimp_prop_scale_entry_new (config, "brush-scale", adj = gimp_prop_scale_entry_new (config, "brush-scale",
GTK_TABLE (table), 0, table_row++, GTK_TABLE (table), 0, table_row++,
_("Scale:"), _("Scale:"),
0.01, 0.1, 2, 0.01, 0.1, 2,
FALSE, 0.0, 0.0); FALSE, 0.0, 0.0);
gimp_scale_entry_set_logarithmic (adj, TRUE);
} }
} }