mirror of https://github.com/GNOME/gimp.git
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:
parent
5eb341d2a5
commit
a4e81c3a6c
35
ChangeLog
35
ChangeLog
|
@ -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>
|
||||
|
||||
* app/tools/gimpeditselectiontool.c (gimp_edit_selection_tool_motion):
|
||||
|
|
|
@ -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<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;
|
||||
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<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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue