Commit 831b75e3 authored by Sven Neumann's avatar Sven Neumann

Correct scaling of brush pipes and pixmap brushes.


--Sven
parent d21d00be
Thu Sep 9 21:02:46 MEST 1999 Sven Neumann <sven@gimp.org>
* app/airbrush.c
* app/gimpbrushpipe.[ch]
* app/paint_core.[ch]
* app/paintbrush.c
* app/pencil.c: scaling of brush pipes should now work correctly.
Needs a little bit of optimization though...
Thu Sep 9 19:16:25 MEST 1999 Simon Budig <Simon.Budig@unix-ag.org>
(checked in by Sven Neumann <sven@gimp.org>)
......
......@@ -15,6 +15,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include "appenv.h"
#include "gimpbrushlist.h"
......@@ -309,7 +310,8 @@ airbrush_motion (PaintCore *paint_core,
if (GIMP_IS_BRUSH_PIXMAP (paint_core->brush))
{
mode = INCREMENTAL;
color_area_with_pixmap (paint_core, gimage, drawable, area, SOFT);
paint_core_color_area_with_pixmap (paint_core, gimage, drawable, area,
scale, SOFT);
}
else
{
......
......@@ -481,127 +481,4 @@ gimp_brush_pixmap_pixmap (GimpBrushPixmap *brush)
return brush->pixmap_mask;
}
void
color_area_with_pixmap (PaintCore *paint_core,
GImage *dest,
GimpDrawable *drawable,
TempBuf *area,
int mode)
{
PixelRegion destPR;
void *pr;
guchar *d;
int ulx, uly, offsetx, offsety, y;
GimpBrushPixmap *pixmap;
g_return_if_fail (GIMP_IS_BRUSH_PIXMAP (paint_core->brush));
pixmap = GIMP_BRUSH_PIXMAP (paint_core->brush);
destPR.bytes = area->bytes;
destPR.x = 0; destPR.y = 0;
destPR.w = area->width;
destPR.h = area->height;
destPR.rowstride = destPR.bytes * area->width;
destPR.data = temp_buf_data (area);
pr = pixel_regions_register (1, &destPR);
/* Calculate upper left corner of brush as in
* paint_core_get_paint_area. Ugly to have to do this here, too.
*/
ulx = (int) paint_core->curx - (paint_core->brush->mask->width >> 1);
uly = (int) paint_core->cury - (paint_core->brush->mask->height >> 1);
offsetx = area->x - ulx;
offsety = area->y - uly;
for (; pr != NULL; pr = pixel_regions_process (pr))
{
d = destPR.data;
for (y = 0; y < destPR.h; y++)
{
paint_line_pixmap_mask (dest, drawable, pixmap,
d, offsetx, y + offsety,
destPR.bytes, destPR.w, mode);
d += destPR.rowstride;
}
}
}
static void
paint_line_pixmap_mask (GImage *dest,
GimpDrawable *drawable,
GimpBrushPixmap *brush,
guchar *d,
int x,
int y,
int bytes,
int width,
int mode)
{
guchar *b, *p;
int x_index;
gdouble alpha;
gdouble factor = 0.00392156986; /* 1.0/255.0 */
gint i;
gint j;
guchar *mask;
/* Make sure x, y are positive */
while (x < 0)
x += brush->pixmap_mask->width;
while (y < 0)
y += brush->pixmap_mask->height;
/* Point to the approriate scanline */
b = temp_buf_data (brush->pixmap_mask) +
(y % brush->pixmap_mask->height) * brush->pixmap_mask->width * brush->pixmap_mask->bytes;
/* ditto, except for the brush mask, so we can pre-multiply the alpha value */
mask = temp_buf_data((brush->gbrush).mask) +
(y % brush->pixmap_mask->height) * brush->pixmap_mask->width;
if(mode == SOFT)
{
for (i = 0; i < width; i++)
{
/* attempt to avoid doing this calc twice in the loop */
x_index = ((i + x) % brush->pixmap_mask->width);
p = b + x_index * brush->pixmap_mask->bytes;
d[bytes-1] = mask[x_index];
/* multiply alpha into the pixmap data */
/* maybe we could do this at tool creation or brush switch time? */
/* and compute it for the whole brush at once and cache it? */
if(alpha = d[bytes-1] * factor)
{
d[0] *= alpha;
d[1] *= alpha;
d[2] *= alpha;
}
/* printf("i: %i d->r: %i d->g: %i d->b: %i d->a: %i\n",i,(int)d[0], (int)d[1], (int)d[2], (int)d[3]); */
gimage_transform_color (dest, drawable, p, d, RGB);
d += bytes;
}
}
else
{
for (i = 0; i < width; i++)
{
/* attempt to avoid doing this calc twice in the loop */
x_index = ((i + x) % brush->pixmap_mask->width);
p = b + x_index * brush->pixmap_mask->bytes;
d[bytes-1] = 255;
/* multiply alpha into the pixmap data */
/* maybe we could do this at tool creation or brush switch time? */
/* and compute it for the whole brush at once and cache it? */
gimage_transform_color (dest, drawable, p, d, RGB);
d += bytes;
}
}
}
......@@ -481,127 +481,4 @@ gimp_brush_pixmap_pixmap (GimpBrushPixmap *brush)
return brush->pixmap_mask;
}
void
color_area_with_pixmap (PaintCore *paint_core,
GImage *dest,
GimpDrawable *drawable,
TempBuf *area,
int mode)
{
PixelRegion destPR;
void *pr;
guchar *d;
int ulx, uly, offsetx, offsety, y;
GimpBrushPixmap *pixmap;
g_return_if_fail (GIMP_IS_BRUSH_PIXMAP (paint_core->brush));
pixmap = GIMP_BRUSH_PIXMAP (paint_core->brush);
destPR.bytes = area->bytes;
destPR.x = 0; destPR.y = 0;
destPR.w = area->width;
destPR.h = area->height;
destPR.rowstride = destPR.bytes * area->width;
destPR.data = temp_buf_data (area);
pr = pixel_regions_register (1, &destPR);
/* Calculate upper left corner of brush as in
* paint_core_get_paint_area. Ugly to have to do this here, too.
*/
ulx = (int) paint_core->curx - (paint_core->brush->mask->width >> 1);
uly = (int) paint_core->cury - (paint_core->brush->mask->height >> 1);
offsetx = area->x - ulx;
offsety = area->y - uly;
for (; pr != NULL; pr = pixel_regions_process (pr))
{
d = destPR.data;
for (y = 0; y < destPR.h; y++)
{
paint_line_pixmap_mask (dest, drawable, pixmap,
d, offsetx, y + offsety,
destPR.bytes, destPR.w, mode);
d += destPR.rowstride;
}
}
}
static void
paint_line_pixmap_mask (GImage *dest,
GimpDrawable *drawable,
GimpBrushPixmap *brush,
guchar *d,
int x,
int y,
int bytes,
int width,
int mode)
{
guchar *b, *p;
int x_index;
gdouble alpha;
gdouble factor = 0.00392156986; /* 1.0/255.0 */
gint i;
gint j;
guchar *mask;
/* Make sure x, y are positive */
while (x < 0)
x += brush->pixmap_mask->width;
while (y < 0)
y += brush->pixmap_mask->height;
/* Point to the approriate scanline */
b = temp_buf_data (brush->pixmap_mask) +
(y % brush->pixmap_mask->height) * brush->pixmap_mask->width * brush->pixmap_mask->bytes;
/* ditto, except for the brush mask, so we can pre-multiply the alpha value */
mask = temp_buf_data((brush->gbrush).mask) +
(y % brush->pixmap_mask->height) * brush->pixmap_mask->width;
if(mode == SOFT)
{
for (i = 0; i < width; i++)
{
/* attempt to avoid doing this calc twice in the loop */
x_index = ((i + x) % brush->pixmap_mask->width);
p = b + x_index * brush->pixmap_mask->bytes;
d[bytes-1] = mask[x_index];
/* multiply alpha into the pixmap data */
/* maybe we could do this at tool creation or brush switch time? */
/* and compute it for the whole brush at once and cache it? */
if(alpha = d[bytes-1] * factor)
{
d[0] *= alpha;
d[1] *= alpha;
d[2] *= alpha;
}
/* printf("i: %i d->r: %i d->g: %i d->b: %i d->a: %i\n",i,(int)d[0], (int)d[1], (int)d[2], (int)d[3]); */
gimage_transform_color (dest, drawable, p, d, RGB);
d += bytes;
}
}
else
{
for (i = 0; i < width; i++)
{
/* attempt to avoid doing this calc twice in the loop */
x_index = ((i + x) % brush->pixmap_mask->width);
p = b + x_index * brush->pixmap_mask->bytes;
d[bytes-1] = 255;
/* multiply alpha into the pixmap data */
/* maybe we could do this at tool creation or brush switch time? */
/* and compute it for the whole brush at once and cache it? */
gimage_transform_color (dest, drawable, p, d, RGB);
d += bytes;
}
}
}
......@@ -44,10 +44,4 @@ GimpBrushPipe *gimp_brush_pixmap_load (char *filename);
TempBuf *gimp_brush_pixmap_pixmap (GimpBrushPixmap *);
void color_area_with_pixmap (PaintCore *paint_core,
GImage *dest,
GimpDrawable *drawable,
TempBuf *area,
int mode);
#endif /* __GIMPBRUSHPIPE_H__ */
......@@ -481,127 +481,4 @@ gimp_brush_pixmap_pixmap (GimpBrushPixmap *brush)
return brush->pixmap_mask;
}
void
color_area_with_pixmap (PaintCore *paint_core,
GImage *dest,
GimpDrawable *drawable,
TempBuf *area,
int mode)
{
PixelRegion destPR;
void *pr;
guchar *d;
int ulx, uly, offsetx, offsety, y;
GimpBrushPixmap *pixmap;
g_return_if_fail (GIMP_IS_BRUSH_PIXMAP (paint_core->brush));
pixmap = GIMP_BRUSH_PIXMAP (paint_core->brush);
destPR.bytes = area->bytes;
destPR.x = 0; destPR.y = 0;
destPR.w = area->width;
destPR.h = area->height;
destPR.rowstride = destPR.bytes * area->width;
destPR.data = temp_buf_data (area);
pr = pixel_regions_register (1, &destPR);
/* Calculate upper left corner of brush as in
* paint_core_get_paint_area. Ugly to have to do this here, too.
*/
ulx = (int) paint_core->curx - (paint_core->brush->mask->width >> 1);
uly = (int) paint_core->cury - (paint_core->brush->mask->height >> 1);
offsetx = area->x - ulx;
offsety = area->y - uly;
for (; pr != NULL; pr = pixel_regions_process (pr))
{
d = destPR.data;
for (y = 0; y < destPR.h; y++)
{
paint_line_pixmap_mask (dest, drawable, pixmap,
d, offsetx, y + offsety,
destPR.bytes, destPR.w, mode);
d += destPR.rowstride;
}
}
}
static void
paint_line_pixmap_mask (GImage *dest,
GimpDrawable *drawable,
GimpBrushPixmap *brush,
guchar *d,
int x,
int y,
int bytes,
int width,
int mode)
{
guchar *b, *p;
int x_index;
gdouble alpha;
gdouble factor = 0.00392156986; /* 1.0/255.0 */
gint i;
gint j;
guchar *mask;
/* Make sure x, y are positive */
while (x < 0)
x += brush->pixmap_mask->width;
while (y < 0)
y += brush->pixmap_mask->height;
/* Point to the approriate scanline */
b = temp_buf_data (brush->pixmap_mask) +
(y % brush->pixmap_mask->height) * brush->pixmap_mask->width * brush->pixmap_mask->bytes;
/* ditto, except for the brush mask, so we can pre-multiply the alpha value */
mask = temp_buf_data((brush->gbrush).mask) +
(y % brush->pixmap_mask->height) * brush->pixmap_mask->width;
if(mode == SOFT)
{
for (i = 0; i < width; i++)
{
/* attempt to avoid doing this calc twice in the loop */
x_index = ((i + x) % brush->pixmap_mask->width);
p = b + x_index * brush->pixmap_mask->bytes;
d[bytes-1] = mask[x_index];
/* multiply alpha into the pixmap data */
/* maybe we could do this at tool creation or brush switch time? */
/* and compute it for the whole brush at once and cache it? */
if(alpha = d[bytes-1] * factor)
{
d[0] *= alpha;
d[1] *= alpha;
d[2] *= alpha;
}
/* printf("i: %i d->r: %i d->g: %i d->b: %i d->a: %i\n",i,(int)d[0], (int)d[1], (int)d[2], (int)d[3]); */
gimage_transform_color (dest, drawable, p, d, RGB);
d += bytes;
}
}
else
{
for (i = 0; i < width; i++)
{
/* attempt to avoid doing this calc twice in the loop */
x_index = ((i + x) % brush->pixmap_mask->width);
p = b + x_index * brush->pixmap_mask->bytes;
d[bytes-1] = 255;
/* multiply alpha into the pixmap data */
/* maybe we could do this at tool creation or brush switch time? */
/* and compute it for the whole brush at once and cache it? */
gimage_transform_color (dest, drawable, p, d, RGB);
d += bytes;
}
}
}
......@@ -44,10 +44,4 @@ GimpBrushPipe *gimp_brush_pixmap_load (char *filename);
TempBuf *gimp_brush_pixmap_pixmap (GimpBrushPixmap *);
void color_area_with_pixmap (PaintCore *paint_core,
GImage *dest,
GimpDrawable *drawable,
TempBuf *area,
int mode);
#endif /* __GIMPBRUSHPIPE_H__ */
......@@ -15,6 +15,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include "appenv.h"
#include "gimpbrushlist.h"
......@@ -309,7 +310,8 @@ airbrush_motion (PaintCore *paint_core,
if (GIMP_IS_BRUSH_PIXMAP (paint_core->brush))
{
mode = INCREMENTAL;
color_area_with_pixmap (paint_core, gimage, drawable, area, SOFT);
paint_core_color_area_with_pixmap (paint_core, gimage, drawable, area,
scale, SOFT);
}
else
{
......
......@@ -156,7 +156,8 @@ pencil_motion (PaintCore *paint_core,
if (GIMP_IS_BRUSH_PIXMAP (paint_core->brush))
{
/* if its a pixmap, do pixmap stuff */
color_area_with_pixmap (paint_core, gimage, drawable, area, HARD);
paint_core_color_area_with_pixmap (paint_core, gimage, drawable, area,
scale, HARD);
paint_appl_mode = INCREMENTAL;
}
else
......
......@@ -29,6 +29,7 @@
#include "gdisplay.h"
#include "gimage_mask.h"
#include "gimpbrushlist.h"
#include "gimpbrushpipe.h"
#include "gimprc.h"
#include "gradient.h" /* for grad_get_color_at() */
#include "paint_funcs.h"
......@@ -61,6 +62,7 @@ static MaskBuf * paint_core_subsample_mask (MaskBuf *, double, double);
static MaskBuf * paint_core_pressurize_mask (MaskBuf *, double, double, double);
static MaskBuf * paint_core_solidify_mask (MaskBuf *);
static MaskBuf * paint_core_scale_mask (MaskBuf *, gdouble);
static MaskBuf * paint_core_scale_pixmap (MaskBuf *, gdouble);
static MaskBuf * paint_core_get_brush_mask (PaintCore *, BrushApplicationMode, gdouble);
static void paint_core_paste (PaintCore *, MaskBuf *,
GimpDrawable *, int, int,
......@@ -96,12 +98,17 @@ static TempBuf * canvas_buf = NULL;
static MaskBuf * pressure_brush;
static MaskBuf * solid_brush;
static MaskBuf * scale_brush = NULL;
static MaskBuf * scale_pixmap = NULL;
static MaskBuf * kernel_brushes[5][5];
/* paint buffers utility functions */
static void free_paint_buffers (void);
/* brush pipe utility functions */
static void paint_line_pixmap_mask (GImage *, GimpDrawable *,
TempBuf *, TempBuf *, guchar *,
int, int, int, int, int);
/***********************************************************************/
......@@ -1373,7 +1380,7 @@ paint_core_scale_mask (MaskBuf *brush_mask,
paint_core_calculate_brush_size (brush_mask, scale,
&dest_width, &dest_height);
if (brush_mask == last_brush &&
if (brush_mask == last_brush && !cache_invalid &&
dest_width == last_width && dest_height == last_height)
return scale_brush;
......@@ -1390,6 +1397,41 @@ paint_core_scale_mask (MaskBuf *brush_mask,
return scale_brush;
}
static MaskBuf *
paint_core_scale_pixmap (MaskBuf *brush_mask,
gdouble scale)
{
static MaskBuf *last_brush = NULL;
static gint last_width = 0.0;
static gint last_height = 0.0;
gint dest_width, dest_height;
if (scale == 0.0)
return NULL;
if (scale == 1.0)
return brush_mask;
paint_core_calculate_brush_size (brush_mask, scale,
&dest_width, &dest_height);
if (brush_mask == last_brush && !cache_invalid &&
dest_width == last_width && dest_height == last_height)
return scale_pixmap;
if (scale_pixmap)
mask_buf_free (scale_pixmap);
last_brush = brush_mask;
last_width = dest_width;
last_height = dest_height;
scale_pixmap = brush_scale_pixmap (brush_mask, dest_width, dest_height);
cache_invalid = TRUE;
return scale_pixmap;
}
static MaskBuf *
paint_core_get_brush_mask (PaintCore *paint_core,
BrushApplicationMode brush_hardness,
......@@ -1818,3 +1860,140 @@ free_paint_buffers ()
temp_buf_free (canvas_buf);
canvas_buf = NULL;
}
/**************************************************/
/* Brush pipe utility functions */
/**************************************************/
void
paint_core_color_area_with_pixmap (PaintCore *paint_core,
GImage *dest,
GimpDrawable *drawable,
TempBuf *area,
gdouble scale,
int mode)
{
PixelRegion destPR;
void *pr;
guchar *d;
int ulx, uly, offsetx, offsety, y;
TempBuf *pixmap_mask;
TempBuf *brush_mask;
g_return_if_fail (GIMP_IS_BRUSH_PIXMAP (paint_core->brush));
/* scale the brushes */
pixmap_mask =
paint_core_scale_pixmap (gimp_brush_pixmap_pixmap (GIMP_BRUSH_PIXMAP (paint_core->brush)), scale);
if (mode == SOFT)
brush_mask = paint_core_scale_mask (paint_core->brush->mask, scale);
else
brush_mask = NULL;
destPR.bytes = area->bytes;
destPR.x = 0; destPR.y = 0;
destPR.w = area->width;
destPR.h = area->height;
destPR.rowstride = destPR.bytes * area->width;
destPR.data = temp_buf_data (area);
pr = pixel_regions_register (1, &destPR);
/* Calculate upper left corner of brush as in
* paint_core_get_paint_area. Ugly to have to do this here, too.
*/
ulx = (int) paint_core->curx - (pixmap_mask->width >> 1);
uly = (int) paint_core->cury - (pixmap_mask->height >> 1);
offsetx = area->x - ulx;
offsety = area->y - uly;
for (; pr != NULL; pr = pixel_regions_process (pr))
{
d = destPR.data;
for (y = 0; y < destPR.h; y++)
{
paint_line_pixmap_mask (dest, drawable, pixmap_mask, brush_mask,
d, offsetx, y + offsety,
destPR.bytes, destPR.w, mode);
d += destPR.rowstride;
}
}
}
static void
paint_line_pixmap_mask (GImage *dest,
GimpDrawable *drawable,
TempBuf *pixmap_mask,
TempBuf *brush_mask,
guchar *d,
int x,
int y,
int bytes,
int width,
int mode)
{
guchar *b, *p;
int x_index;
gdouble alpha;
gdouble factor = 0.00392156986; /* 1.0/255.0 */
gint i;
guchar *mask;
/* Make sure x, y are positive */
while (x < 0)
x += pixmap_mask->width;
while (y < 0)
y += pixmap_mask->height;
/* Point to the approriate scanline */
b = temp_buf_data (pixmap_mask) +
(y % pixmap_mask->height) * pixmap_mask->width * pixmap_mask->bytes;
if (mode == SOFT && brush_mask)
{
/* ditto, except for the brush mask, so we can pre-multiply the alpha value */
mask = temp_buf_data (brush_mask) +
(y % brush_mask->height) * brush_mask->width;
for (i = 0; i < width; i++)
{
/* attempt to avoid doing this calc twice in the loop */
x_index = ((i + x) % pixmap_mask->width);
p = b + x_index * pixmap_mask->bytes;
d[bytes-1] = mask[x_index];
/* multiply alpha into the pixmap data */
/* maybe we could do this at tool creation or brush switch time? */
/* and compute it for the whole brush at once and cache it? */
alpha = d[bytes-1] * factor;
if (alpha)
{
d[0] *= alpha;
d[1] *= alpha;
d[2] *= alpha;
}
/* printf("i: %i d->r: %i d->g: %i d->b: %i d->a: %i\n",i,(int)d[0], (int)d[1], (int)d[2], (int)d[3]); */
gimage_transform_color (dest, drawable, p, d, RGB);
d += bytes;
}
}
else
{
for (i = 0; i < width; i++)
{
/* attempt to avoid doing this calc twice in the loop */
x_index = ((i + x) % pixmap_mask->width);
p = b + x_index * pixmap_mask->bytes;
d[bytes-1] = 255;
/* multiply alpha into the pixmap data */
/* maybe we could do this at tool creation or brush switch time? */
/* and compute it for the whole brush at once and cache it? */
gimage_transform_color (dest, drawable, p, d, RGB);
d += bytes;
}
}
}
......@@ -143,5 +143,8 @@ void paint_core_replace_canvas (PaintCore *,
BrushApplicationMode,
gdouble,
PaintApplicationMode);
void paint_core_color_area_with_pixmap (PaintCore *,
GImage *, GimpDrawable *,
TempBuf *, gdouble, int);
#endif /* __PAINT_CORE_H__ */
......@@ -445,7 +445,8 @@ paintbrush_motion (PaintCore *paint_core,
pixmap image into the are instead of the color */
if (GIMP_IS_BRUSH_PIXMAP (paint_core->brush) && !gradient_length)
{
color_area_with_pixmap (paint_core, gimage, drawable, area, SOFT);
paint_core_color_area_with_pixmap (paint_core, gimage, drawable, area,
scale, SOFT);
paint_appl_mode = INCREMENTAL;
}
else
......
......@@ -156,7 +156,8 @@ pencil_motion (PaintCore *paint_core,
if (GIMP_IS_BRUSH_PIXMAP (paint_core->brush))
{
/* if its a pixmap, do pixmap stuff */
color_area_with_pixmap (paint_core, gimage, drawable, area, HARD);
paint_core_color_area_with_pixmap (paint_core, gimage, drawable, area,
scale, HARD);
paint_appl_mode = INCREMENTAL;
}
else
......
......@@ -15,6 +15,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/