From a4e81c3a6c95ab30c63f5832b9ec6440276c6fcf Mon Sep 17 00:00:00 2001 From: Michael Schumacher Date: Sun, 11 Mar 2007 16:28:08 +0000 Subject: [PATCH] Made brushes scalable (both up and down) by using existing scaling 2007-03-11 Michael Schumacher 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 --- ChangeLog | 35 ++++ app/base/brush-scale.c | 339 +++---------------------------- app/base/brush-scale.h | 10 +- app/base/temp-buf.c | 5 +- app/base/temp-buf.h | 3 +- app/core/gimpbrush.c | 42 +++- app/core/gimpbrush.h | 10 + app/core/gimpbrushgenerated.c | 201 +++++++++++++----- app/paint/gimpbrushcore.c | 59 ++---- app/paint/gimppaintoptions.c | 2 +- app/tools/gimppaintoptions-gui.c | 14 +- 11 files changed, 289 insertions(+), 431 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0e51d4d98d..95e01c7e42 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,38 @@ +2007-03-11 Michael Schumacher + + 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 * app/tools/gimpeditselectiontool.c (gimp_edit_selection_tool_motion): diff --git a/app/base/brush-scale.c b/app/base/brush-scale.c index 4e57331bed..4145244240 100644 --- a/app/base/brush-scale.c +++ b/app/base/brush-scale.c @@ -24,327 +24,40 @@ #include "brush-scale.h" #include "temp-buf.h" +#include "pixel-region.h" + +#include "paint-funcs/scale-funcs.h" MaskBuf * -brush_scale_mask (MaskBuf *brush_mask, - gint dest_width, - gint dest_height) +brush_scale_buf (MaskBuf *brush_mask, + gint dest_width, + gint dest_height, + gint bpp) { - MaskBuf *scale_brush; - gint src_width; - gint src_height; - 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; + PixelRegion source_region; + PixelRegion dest_region; + MaskBuf *dest_brush_mask; - g_return_val_if_fail (brush_mask != NULL && - dest_width != 0 && dest_height != 0, NULL); + /* Use existing scaling routines for brush scaling. */ - src_width = brush_mask->width; - src_height = brush_mask->height; + pixel_region_init_temp_buf (&source_region, brush_mask, + brush_mask->x, + brush_mask->y, + brush_mask->width, + brush_mask->height); - scale_brush = mask_buf_new (dest_width, dest_height); - g_return_val_if_fail (scale_brush != NULL, NULL); + dest_brush_mask = mask_buf_new (dest_width, dest_height, bpp); + g_return_val_if_fail (dest_brush_mask != NULL, NULL); - /* get the data */ - dest = mask_buf_data (scale_brush); - src = mask_buf_data (brush_mask); + pixel_region_init_temp_buf (&dest_region, dest_brush_mask, + brush_mask->x, + brush_mask->y, + dest_width, + dest_height); - fx = fx0 = (256.0 * src_width) / dest_width; - fy = fy0 = (256.0 * src_height) / dest_height; - area = (fx0 * fy0) >> 8; + scale_region (&source_region, &dest_region, GIMP_INTERPOLATION_LINEAR, + NULL, NULL); - x = x0 = 0; - y = y0 = 0; - dx = dx0 = 0; - dy = dy0 = 0; - - for (i=0; i> 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; + return dest_brush_mask; } - - -#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> 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 diff --git a/app/base/brush-scale.h b/app/base/brush-scale.h index 9412e708a1..ace861a6aa 100644 --- a/app/base/brush-scale.h +++ b/app/base/brush-scale.h @@ -20,12 +20,10 @@ #define __BRUSH_SCALE_H__ -MaskBuf * brush_scale_mask (MaskBuf *brush_mask, - gint dest_width, - gint dest_height); -MaskBuf * brush_scale_pixmap (MaskBuf *pixmap, - gint dest_width, - gint dest_height); +MaskBuf * brush_scale_buf (MaskBuf *brush_mask, + gint dest_width, + gint dest_height, + gint bpp); #endif /* __BRUSH_SCALE_H__ */ diff --git a/app/base/temp-buf.c b/app/base/temp-buf.c index c01a6fc865..59b1c2f264 100644 --- a/app/base/temp-buf.c +++ b/app/base/temp-buf.c @@ -487,11 +487,12 @@ temp_buf_to_gray (TempBuf *src_buf, MaskBuf * mask_buf_new (gint width, - gint height) + gint height, + gint bpp) { 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 diff --git a/app/base/temp-buf.h b/app/base/temp-buf.h index 072168bb3f..e22c55a75e 100644 --- a/app/base/temp-buf.h +++ b/app/base/temp-buf.h @@ -72,7 +72,8 @@ gsize temp_buf_get_memsize (TempBuf *buf); /* The mask buffer functions */ MaskBuf * mask_buf_new (gint width, - gint height); + gint height, + gint bpp); void mask_buf_free (MaskBuf *mask_buf); guchar * mask_buf_data (MaskBuf *mask_buf); guchar * mask_buf_data_clear (MaskBuf *mask_buf); diff --git a/app/core/gimpbrush.c b/app/core/gimpbrush.c index 951606401e..0be8ffcd76 100644 --- a/app/core/gimpbrush.c +++ b/app/core/gimpbrush.c @@ -83,6 +83,10 @@ static TempBuf * gimp_brush_real_scale_mask (GimpBrush *brush, static TempBuf * gimp_brush_real_scale_pixmap (GimpBrush *brush, 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) @@ -125,6 +129,7 @@ gimp_brush_class_init (GimpBrushClass *klass) klass->want_null_motion = gimp_brush_real_want_null_motion; klass->scale_mask = gimp_brush_real_scale_mask; klass->scale_pixmap = gimp_brush_real_scale_pixmap; + klass->get_scaled_size = gimp_brush_real_get_scaled_size; klass->spacing_changed = NULL; 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_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) { /* TODO: the scale function should scale the pixmap and the * mask in one run */ - pixmap_buf = brush_scale_pixmap (pixmap_buf, - brush_width, brush_height); + pixmap_buf = brush_scale_buf (pixmap_buf, + brush_width, brush_height, pixmap_buf->bytes); } scale = TRUE; @@ -370,11 +375,10 @@ gimp_brush_real_scale_mask (GimpBrush *brush, gint width; gint height; - width = (gint) (brush->mask->width * scale + 0.5); - height = (gint) (brush->mask->height * scale + 0.5); + gimp_brush_get_scaled_size (brush, scale, &width, &height); 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; } @@ -386,15 +390,23 @@ gimp_brush_real_scale_pixmap (GimpBrush *brush, gint width; gint height; - width = (gint) (brush->pixmap->width * scale + 0.5); - height = (gint) (brush->pixmap->height * scale + 0.5); + gimp_brush_get_scaled_size (brush, scale, &width, &height); 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; } +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 */ @@ -476,6 +488,18 @@ gimp_brush_scale_pixmap (GimpBrush *brush, 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 * gimp_brush_get_mask (const GimpBrush *brush) { diff --git a/app/core/gimpbrush.h b/app/core/gimpbrush.h index 9a8095e8b6..641d2f0a10 100644 --- a/app/core/gimpbrush.h +++ b/app/core/gimpbrush.h @@ -61,6 +61,10 @@ struct _GimpBrushClass gdouble scale); TempBuf * (* scale_pixmap) (GimpBrush *brush, gdouble scale); + void (* get_scaled_size) (GimpBrush *brush, + gdouble scale, + gint *width, + gint *height); /* signals */ void (* spacing_changed) (GimpBrush *brush); @@ -84,6 +88,12 @@ TempBuf * gimp_brush_scale_mask (GimpBrush *brush, TempBuf * gimp_brush_scale_pixmap (GimpBrush *brush, 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_pixmap (const GimpBrush *brush); diff --git a/app/core/gimpbrushgenerated.c b/app/core/gimpbrushgenerated.c index bc07e30024..86e801105b 100644 --- a/app/core/gimpbrushgenerated.c +++ b/app/core/gimpbrushgenerated.c @@ -64,6 +64,25 @@ static gchar * gimp_brush_generated_get_extension (GimpData *data); static GimpData * gimp_brush_generated_duplicate (GimpData *data); static TempBuf * gimp_brush_generated_scale_mask (GimpBrush *gbrush, 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) @@ -78,15 +97,16 @@ gimp_brush_generated_class_init (GimpBrushGeneratedClass *klass) GimpDataClass *data_class = GIMP_DATA_CLASS (klass); GimpBrushClass *brush_class = GIMP_BRUSH_CLASS (klass); - object_class->set_property = gimp_brush_generated_set_property; - object_class->get_property = gimp_brush_generated_get_property; + object_class->set_property = gimp_brush_generated_set_property; + object_class->get_property = gimp_brush_generated_get_property; - data_class->save = gimp_brush_generated_save; - data_class->dirty = gimp_brush_generated_dirty; - data_class->get_extension = gimp_brush_generated_get_extension; - data_class->duplicate = gimp_brush_generated_duplicate; + data_class->save = gimp_brush_generated_save; + data_class->dirty = gimp_brush_generated_dirty; + data_class->get_extension = gimp_brush_generated_get_extension; + 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_param_spec_enum ("shape", NULL, NULL, @@ -254,62 +274,31 @@ gimp_brush_generated_calc (GimpBrushGenerated *brush, gdouble exponent; guchar a; gint length; - gint width = 0; - gint height = 0; + gint half_width = 0; + gint half_height = 0; guchar *lookup; gdouble sum; gdouble c, s, cs, ss; - gdouble short_radius; gdouble buffer[OVERSAMPLING]; GimpVector2 x_axis; GimpVector2 y_axis; TempBuf *mask; - s = sin (gimp_deg_to_rad (angle)); - c = cos (gimp_deg_to_rad (angle)); + gimp_brush_generated_get_half_width_and_height (brush, + 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; - 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; + centerp = temp_buf_data (mask) + half_height * mask->width + half_width; /* set up lookup table */ length = OVERSAMPLING * ceil (1 + sqrt (2 * @@ -358,9 +347,9 @@ gimp_brush_generated_calc (GimpBrushGenerated *brush, ss = sin (- 2 * G_PI / spikes); /* 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; @@ -454,6 +443,108 @@ gimp_brush_generated_scale_mask (GimpBrush *gbrush, 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 * gimp_brush_generated_new (const gchar *name, GimpBrushGeneratedShape shape, diff --git a/app/paint/gimpbrushcore.c b/app/paint/gimpbrushcore.c index 456052e5c2..de504362ac 100644 --- a/app/paint/gimpbrushcore.c +++ b/app/paint/gimpbrushcore.c @@ -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, GimpBrush *brush); -static gdouble gimp_brush_core_calc_brush_size (GimpBrushCore *core, - MaskBuf *mask, - gdouble scale, - gint *width, - gint *height); +static gdouble gimp_brush_core_calc_brush_length_scale + (GimpBrushCore *core, + gdouble scale); + static inline void rotate_pointers (gulong **p, guint32 n); static MaskBuf * gimp_brush_core_subsample_mask (GimpBrushCore *core, @@ -447,8 +446,7 @@ gimp_brush_core_interpolate (GimpPaintCore *paint_core, ! delta_wheel) return; - scale = gimp_brush_core_calc_brush_size (core, NULL, core->scale, - NULL, NULL); + scale = gimp_brush_core_calc_brush_length_scale (core, core->scale); /* calculate the distance traveled in the coordinate space of the brush */ temp_vec = core->brush->x_axis; @@ -681,6 +679,7 @@ gimp_brush_core_get_paint_area (GimpPaintCore *paint_core, GimpPaintOptions *paint_options) { GimpBrushCore *core = GIMP_BRUSH_CORE (paint_core); + gdouble length_scale; gint x, y; gint x1, y1, x2, y2; gint drawable_width, drawable_height; @@ -703,8 +702,8 @@ gimp_brush_core_get_paint_area (GimpPaintCore *paint_core, core->scale *= paint_options->brush_scale; } - gimp_brush_core_calc_brush_size (core, core->brush->mask, core->scale, - &brush_width, &brush_height); + length_scale = gimp_brush_core_calc_brush_length_scale (core, core->scale); + 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 */ 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; gdouble scale = 1.0; - gint brush_width; - gint brush_height; g_return_if_fail (GIMP_IS_BRUSH_CORE (core)); 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) scale *= paint_options->brush_scale; - scale = gimp_brush_core_calc_brush_size (core, core->main_brush->mask, scale, - &brush_width, &brush_height); + scale = gimp_brush_core_calc_brush_length_scale (core, scale); if (scale > 0.0) mask = gimp_brush_scale_mask (core->main_brush, scale); @@ -932,25 +928,14 @@ gimp_brush_core_invalidate_cache (GimpBrush *brush, ************************************************************/ static gdouble -gimp_brush_core_calc_brush_size (GimpBrushCore *core, - MaskBuf *mask, - gdouble scale, - gint *width, - gint *height) +gimp_brush_core_calc_brush_length_scale (GimpBrushCore *core, + gdouble scale) { gdouble ratio = 1.0; - scale = CLAMP (scale, 0.0, 1.0); - if (scale == 1.0) { ratio = scale; - - if (mask) - { - *width = mask->width; - *height = mask->height; - } } else { @@ -958,12 +943,6 @@ gimp_brush_core_calc_brush_size (GimpBrushCore *core, ratio = 1 / 16; else 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; @@ -1063,7 +1042,8 @@ gimp_brush_core_subsample_mask (GimpBrushCore *core, } dest = mask_buf_new (mask->width + 2, - mask->height + 2); + mask->height + 2, + mask->bytes); /* Allocate and initialize the accum buffer */ for (i = 0; i < KERNEL_HEIGHT ; i++) @@ -1142,7 +1122,8 @@ gimp_brush_core_pressurize_mask (GimpBrushCore *core, mask_buf_free (core->pressure_brush); core->pressure_brush = mask_buf_new (brush_mask->width + 2, - brush_mask->height + 2); + brush_mask->height + 2, + 1); #ifdef FANCY_PRESSURE /* Create the pressure profile @@ -1278,7 +1259,8 @@ gimp_brush_core_solidify_mask (GimpBrushCore *core, } 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; @@ -1314,8 +1296,8 @@ gimp_brush_core_scale_mask (GimpBrushCore *core, if (scale == 1.0) return brush->mask; - scale = gimp_brush_core_calc_brush_size (core, brush->mask, scale, - &dest_width, &dest_height); + scale = gimp_brush_core_calc_brush_length_scale (core, scale); + gimp_brush_get_scaled_size (brush, scale, &dest_width, &dest_height); if (! core->cache_invalid && brush->mask == core->last_scale_brush && @@ -1357,8 +1339,7 @@ gimp_brush_core_scale_pixmap (GimpBrushCore *core, if (scale == 1.0) return brush->pixmap; - scale = gimp_brush_core_calc_brush_size (core, brush->pixmap, scale, - &dest_width, &dest_height); + scale = gimp_brush_core_calc_brush_length_scale (core, scale); if (! core->cache_invalid && brush->pixmap == core->last_scale_pixmap && diff --git a/app/paint/gimppaintoptions.c b/app/paint/gimppaintoptions.c index 73642c1de3..253f438a99 100644 --- a/app/paint/gimppaintoptions.c +++ b/app/paint/gimppaintoptions.c @@ -131,7 +131,7 @@ gimp_paint_options_class_init (GimpPaintOptionsClass *klass) GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_BRUSH_SCALE, "brush-scale", NULL, - 0.0, 1.0, DEFAULT_BRUSH_SCALE, + 0.0, 100.0, DEFAULT_BRUSH_SCALE, GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_APPLICATION_MODE, "application-mode", NULL, diff --git a/app/tools/gimppaintoptions-gui.c b/app/tools/gimppaintoptions-gui.c index 4135d70d84..b23a669ae6 100644 --- a/app/tools/gimppaintoptions-gui.c +++ b/app/tools/gimppaintoptions-gui.c @@ -78,6 +78,7 @@ gimp_paint_options_gui (GimpToolOptions *tool_options) GtkWidget *menu; GtkWidget *label; GtkWidget *button; + GtkWidget *adj; GtkWidget *incremental_toggle = NULL; gint table_row = 0; GType tool_type; @@ -124,11 +125,14 @@ gimp_paint_options_gui (GimpToolOptions *tool_options) if (tool_type != GIMP_TYPE_SMUDGE_TOOL) { - gimp_prop_scale_entry_new (config, "brush-scale", - GTK_TABLE (table), 0, table_row++, - _("Scale:"), - 0.01, 0.1, 2, - FALSE, 0.0, 0.0); + adj = gimp_prop_scale_entry_new (config, "brush-scale", + GTK_TABLE (table), 0, table_row++, + _("Scale:"), + 0.01, 0.1, 2, + FALSE, 0.0, 0.0); + + gimp_scale_entry_set_logarithmic (adj, TRUE); + } }