Index: gimpclone.c =================================================================== RCS file: /cvs/gnome/gimp/app/paint/gimpclone.c,v retrieving revision 1.126 diff -u -r1.126 gimpclone.c --- gimpclone.c 7 Dec 2005 21:17:12 -0000 1.126 +++ gimpclone.c 15 Dec 2005 19:31:32 -0000 @@ -62,14 +62,7 @@ gint src_bytes, gint dest_bytes, gint width); -static void gimp_clone_line_pattern (GimpImage *dest, - GimpDrawable *drawable, - GimpPattern *pattern, - guchar *d, - gint x, - gint y, - gint bytes, - gint width); + static void gimp_clone_set_src_drawable (GimpClone *clone, GimpDrawable *drawable); @@ -424,7 +417,7 @@ } } -static void +void gimp_clone_line_pattern (GimpImage *dest, GimpDrawable *drawable, GimpPattern *pattern, @@ -448,9 +441,12 @@ while (y < 0) y += pattern->mask->height; + //printf("x2: %i y2: %i\n", x, y); /* Get a pointer to the appropriate scanline of the pattern buffer */ pat = temp_buf_data (pattern->mask) + (y % pattern->mask->height) * pattern->mask->width * pat_bytes; + + //printf("y pat->m->height: %i\n", y % pattern->mask->height); color_type = (pat_bytes == 3 || pat_bytes == 4) ? GIMP_RGB : GIMP_GRAY; Index: gimpclone.h =================================================================== RCS file: /cvs/gnome/gimp/app/paint/gimpclone.h,v retrieving revision 1.27 diff -u -r1.27 gimpclone.h --- gimpclone.h 29 Aug 2005 20:48:26 -0000 1.27 +++ gimpclone.h 15 Dec 2005 19:31:32 -0000 @@ -63,5 +63,13 @@ GType gimp_clone_get_type (void) G_GNUC_CONST; +void gimp_clone_line_pattern (GimpImage *dest, + GimpDrawable *drawable, + GimpPattern *pattern, + guchar *d, + gint x, + gint y, + gint bytes, + gint width); #endif /* __GIMP_CLONE_H__ */ Index: gimppaintbrush.c =================================================================== RCS file: /cvs/gnome/gimp/app/paint/gimppaintbrush.c,v retrieving revision 1.55 diff -u -r1.55 gimppaintbrush.c --- gimppaintbrush.c 7 Dec 2005 21:11:53 -0000 1.55 +++ gimppaintbrush.c 15 Dec 2005 19:31:32 -0000 @@ -35,21 +35,45 @@ #include "core/gimpdrawable.h" #include "core/gimpgradient.h" #include "core/gimpimage.h" +#include "core/gimppattern.h" +#include "core/gimppickable.h" #include "gimppaintbrush.h" #include "gimppaintoptions.h" +#include "gimpsmudge.h" +#include "gimpclone.h" #include "gimp-intl.h" +static gboolean gimp_paintbrush_start (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *options); + +static void gimp_paintbrush_class_init (GimpPaintbrushClass *klass); +static void gimp_paintbrush_init (GimpPaintbrush *paintbrush); static void gimp_paintbrush_paint (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, GimpPaintState paint_state, guint32 time); +void _gimp_paintbrush_smudge_motion (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options, + gdouble opacity); + + +static void gimp_paintbrush_nonclipped_painthit_coords (GimpPaintCore *paint_core, + gint *x, + gint *y, + gint *w, + gint *h); + +/* static GimpPaintCoreClass *parent_class = NULL; */ G_DEFINE_TYPE (GimpPaintbrush, gimp_paintbrush, GIMP_TYPE_BRUSH_CORE); +#define parent_class gimp_paintbrush_parent_class void @@ -85,18 +109,219 @@ GimpPaintState paint_state, guint32 time) { + + gboolean use_smudge; + GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_core); + + use_smudge = gimp_paint_options_get_smudge(paint_options); + + switch (paint_state) { - case GIMP_PAINT_STATE_MOTION: + + case GIMP_PAINT_STATE_INIT: + printf("gh0 init\n"); _gimp_paintbrush_motion (paint_core, drawable, paint_options, GIMP_OPACITY_OPAQUE); + + if (use_smudge) + { + + printf("gh0.1 init-smudge\n"); + //brush_core->orig_spacing = brush_core->spacing; + //brush_core->spacing = 1.0/100.0; + printf("spacing %f\n", brush_core->spacing); + brush_core->initialized = gimp_paintbrush_start (paint_core, drawable, + paint_options); + } + + case GIMP_PAINT_STATE_MOTION: + + if (use_smudge) + { + _gimp_paintbrush_smudge_motion (paint_core, drawable, paint_options, + GIMP_OPACITY_OPAQUE); + } + else + { + _gimp_paintbrush_motion (paint_core, drawable, paint_options, + GIMP_OPACITY_OPAQUE); + } + + break; + + case GIMP_PAINT_STATE_FINISH: + printf("gh2 finish\n"); + if (brush_core->accum_data) + { + g_free(brush_core->accum_data); + brush_core->accum_data = NULL; + } + brush_core->initialized = FALSE; break; + default: break; } } +static gboolean +gimp_paintbrush_start (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options) +{ + GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_core); + GimpImage *gimage; + TempBuf *area; + PixelRegion srcPR; + gint x,y,w,h; + gint bytes; + + gimage = gimp_item_get_image (GIMP_ITEM (drawable)); + + if (gimp_drawable_is_indexed (drawable)) + return FALSE; + + area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options); + if (! area) + return FALSE; + + /* adjust the x and y coordinates to the upper left corner of the brush */ + gimp_paintbrush_nonclipped_painthit_coords (paint_core, &x, &y, &w, &h); + + /* Allocate the accumulation buffer */ + bytes = gimp_drawable_bytes (drawable); + brush_core->accum_data = g_malloc (w * h * bytes); + /* If clipped, prefill the smudge buffer + with the color at the brush position. */ + if (x != area->x || y != area->y || w != area->width || h != area->height) + { + guchar *fill; + + fill = gimp_pickable_get_color_at (GIMP_PICKABLE (drawable), + CLAMP ((gint) paint_core->cur_coords.x, + 0, gimp_item_width (GIMP_ITEM (drawable)) - 1), + CLAMP ((gint) paint_core->cur_coords.y, + 0, gimp_item_height (GIMP_ITEM (drawable)) - 1)); + g_return_val_if_fail (fill != NULL, FALSE); + + pixel_region_init_data (&srcPR, brush_core->accum_data, + bytes, bytes * w, + 0, 0, w, h ); + + color_region (&srcPR, fill); + g_free (fill); + } + + + pixel_region_init (&srcPR, gimp_drawable_data (drawable), + area->x, area->y, area->width, area->height, FALSE); + + pixel_region_init_data (&brush_core->accumPR, brush_core->accum_data, + bytes, bytes * w, + area->x - x, + area->y - y, + area->width, + area->height); + + + /* copy the region under the original painthit. */ + copy_region (&srcPR, &brush_core->accumPR); + + pixel_region_init_data (&brush_core->accumPR, + brush_core->accum_data, + bytes, bytes * w, + area->x - x, + area->y -y, + area->width, + area->height); + + return TRUE; + + } + +void +_gimp_paintbrush_smudge_motion (GimpPaintCore *paint_core, + GimpDrawable *drawable, + GimpPaintOptions *paint_options, + gdouble opacity) +{ + GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_core); + GimpContext *context = GIMP_CONTEXT (paint_options); + GimpImage *gimage; + TempBuf *area; + PixelRegion srcPR, destPR, tempPR; + gdouble rate; + gint x,y,w,h; + + gimage = gimp_item_get_image (GIMP_ITEM (drawable)); + + opacity *= gimp_paint_options_get_fade (paint_options, gimage, + paint_core->pixel_dist); + + rate = gimp_paint_options_get_smudge(paint_options) / 100.0; + + if (opacity == 0.0) + return; + + + gimp_paintbrush_nonclipped_painthit_coords (paint_core, &x, &y, &w, &h); + + /* Get the paint area (Smudge won't scale!) */ + area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options); + if (! area) + return; + + /* srcPR will be the pixels under the current painthit from the drawable */ + pixel_region_init (&srcPR, gimp_drawable_data (drawable), + area->x, area->y, area->width, area->height, FALSE); + + pixel_region_init_data ( &tempPR, brush_core->accum_data, + brush_core->accumPR.bytes, + brush_core->accumPR.rowstride, + area->x - x, + area->y - y, + area->width, + area->height); + + + /* The dest will be the paint area we got above (= canvas_buf) */ + + pixel_region_init_temp_buf (&destPR, area, + 0, 0, area->width, area->height); + + + blend_region (&srcPR, &tempPR, &tempPR, ROUND (rate * 255.0)); + + /* re-init the tempPR */ + pixel_region_init_data (&tempPR, brush_core->accum_data, + brush_core->accumPR.bytes, + brush_core->accumPR.rowstride, + area->x - x, + area->y - y, + area->width, + area->height); + + + if (! gimp_drawable_has_alpha (drawable)) + add_alpha_region (&tempPR, &destPR); + else + copy_region (&tempPR, &destPR); + + + opacity = 100.0; + gimp_brush_core_replace_canvas (GIMP_BRUSH_CORE (paint_core), drawable, + MIN (opacity, GIMP_OPACITY_OPAQUE), + gimp_context_get_opacity (context), + gimp_paint_options_get_brush_mode (paint_options), + GIMP_PAINT_INCREMENTAL); + +} + + + + void _gimp_paintbrush_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, @@ -106,14 +331,32 @@ GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_core); GimpContext *context = GIMP_CONTEXT (paint_options); GimpPressureOptions *pressure_options = paint_options->pressure_options; + GimpColorJitterOptions *color_jitter_options; GimpImage *gimage; + PixelRegion brushPR; + PixelRegion patternPR; + guchar *p; + GimpPattern *pattern = NULL; GimpRGB gradient_color; + GimpRGB foreground_color; + GimpHSV random_color; + gdouble hue; + gdouble sat; + gdouble val; + gpointer pr = NULL; + TempBuf *area; + TempBuf *pattern_buf; + guchar col[MAX_CHANNELS]; GimpPaintApplicationMode paint_appl_mode; + gint y; + gboolean active[MAX_CHANNELS] = { TRUE, TRUE, TRUE, TRUE }; + gint brush_h; + gint brush_w; - gimage = gimp_item_get_image (GIMP_ITEM (drawable)); + gimage = gimp_item_get_image (GIMP_ITEM (drawable)); opacity *= gimp_paint_options_get_fade (paint_options, gimage, paint_core->pixel_dist); if (opacity == 0.0) @@ -122,9 +365,121 @@ paint_appl_mode = paint_options->application_mode; area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options); + + brush_h = brush_core->main_brush->mask->height; + brush_w = brush_core->main_brush->mask->width; + if (! area) return; + /* So, wtf is this? the idea, create a new pixel_region the size of the brush, and fill it with + the data from a pattern, but with it "fixed", just like in clone. then we composite the brush image + mulitplied into the pattern/texture image, into a new brush image. Then we use that new brush image + as the new brush, now with "texture" + + Thats the theory anyway, but this is a prototype. Before were done, we need to add a new Texture + type, texture dialog, textuere data factory, etc. And plug it into the gui, and add it to th + "context" stuff, etc" + + */ + + pattern = gimp_context_get_pattern (context); + if (pattern) + { + /* create a tempbuf, and resize it to the same size as the brush data, then make + a pixel_region of it. Now, I'm assuming that combine_region needs the regions to + be the same size, so I make patternPR and brushPR the same size. + + But, it seems like maybe I should make both of them the size of the area (aka, the to + be painted area) since the combine region keeps wanting to walk off the end of the + pattern region. But doing that doesnt seem to help any. + + */ + pattern_buf = NULL; + pattern_buf = temp_buf_copy (gimp_pattern_get_mask (pattern), pattern_buf); + pattern_buf = temp_buf_resize (pattern_buf, + pattern_buf->bytes, + 0,0, + brush_w, + brush_h); + /* create a pixel_region from the tmp_buf */ + pixel_region_init_temp_buf (&patternPR, + pattern_buf, + 0, 0, + area->width, + area->height); + + pr = pixel_regions_register(1, &patternPR); + + /* copy the pattern info into a pixel region we can composite with + the brush */ + + /* patternPR is coming up with garbage... not sure why */ + + for (; pr != NULL; pr = pixel_regions_process (pr)) + { + p = patternPR.data; + + /* copy line by line from pattern to patternPR*/ + for (y = 0; y < patternPR.h; y++) + { + /* This seems to work for cloning from patterns, so I'm not sure whats up. It looks + like its doing the right thing, and is creating the proper size regions and all that, and + I don't actually get any segfaults here, but later on in combine_region. But it wouldn't + surprise me if something was wrong here */ + gimp_clone_line_pattern (gimage, + drawable, + pattern, + p, + area->x, /* note, note offset here, I think that makes this always "registered" which I think we want..? */ + area->y + y, + patternPR.bytes, + patternPR.w); + p += patternPR.rowstride; + } + + } + + + /* brushPR looks to do the right thing */ + pixel_region_init_temp_buf (&brushPR, + brush_core->brush->mask, + 0, 0, + brush_w, + brush_h); + + + printf("gh3, about to combine_regions\n"); + + printf("pattern x: %i y: %i w: %i h: %i bytes: %i\n", patternPR.x, patternPR.y, patternPR.w, patternPR.h, patternPR.bytes); + /* This is the part that always seems to want to segfauly. Basically, deep inside of combine_regions, the code is walking off + the end of the patternPR region. It seems like it wants to go one row past the last row, for reasons unknown. All the pixel + region sizes seem correct, as best I can tell. + */ + combine_regions (&patternPR, + &brushPR, + &brushPR, + NULL, + NULL, + 128, + GIMP_NORMAL_MODE, + active, + COMBINE_INTEN_INTEN); + + printf("brush x: %i y: %i w: %i h: %i bytes: %i\n", brushPR.x, brushPR.y, brushPR.w, brushPR.h, brushPR.bytes); + + } + + /* it seems like maybe theres a better place to be finally setting what color + we are going to paint with, but alas... */ + + /* use the pixmap if we have that, other wise use the forground or the gradient, + and if we have a randomizer, use it */ + + /* we probably want some methods to shift the color in hue/sat/val land as a first + pass, though RGB components is easy as well */ + + if (gimp_paint_options_get_gradient_color (paint_options, gimage, paint_core->cur_coords.pressure, paint_core->pixel_dist, @@ -154,15 +509,51 @@ paint_appl_mode = GIMP_PAINT_INCREMENTAL; } - else + else { + /* normal painting with the foreground color */ gimp_image_get_foreground (gimage, drawable, context, col); col[area->bytes - 1] = OPAQUE_OPACITY; + gimp_rgb_set_uchar(&foreground_color, col[0],col[1],col[2]); + gimp_rgb_to_hsv(&foreground_color, &random_color); + /* why do we use an accessor for this? it's just paint_options->color_jitter_options... -akl */ + color_jitter_options = gimp_paint_options_get_color_jitter(paint_options, gimage); + if (color_jitter_options->use_color_jitter) + { + /* I'm not sure what the best way to apply the "jitter amount". This an attempt to make the jitter amount + relative to percentage of the normal values, but thats kind of weird, and doesnt work at all for say, black. + + Maybe just +/- rand(amount) is better? dunno, need to play around some and wee what we feels better */ + + /* this is code the does the sorta percentage based approach above + random_color.h = random_color.h + g_random_double_range (-(color_options->color_jitter_hue_amounthue * random_color.h), (color_options->hue * random_color.h)); + random_color.s = random_color.s + g_random_double_range (-(color_options->sat * random_color.s), (color_options->sat * random_color.s)); + random_color.v = random_color.v + g_random_double_range (-(color_options->val * random_color.v), (colval * random_color.v)); + + */ + + hue = color_jitter_options->color_jitter_hue_amount; + sat = color_jitter_options->color_jitter_sat_amount; + val = color_jitter_options->color_jitter_val_amount; + random_color.h = random_color.h + g_random_double_range (-hue, hue); + random_color.s = random_color.s + g_random_double_range (-sat, sat); + random_color.v = random_color.v + g_random_double_range (-val, val); + + /* printf("randomized: h: %f s: %f v: %f\n", random_color.h, random_color.s, random_color.v); */ + gimp_hsv_to_rgb(&random_color, &foreground_color); + gimp_rgb_get_uchar(&foreground_color, &col[0], &col[1], &col[2]); + } + /* this stuff looks like crap without incremenatal mode */ + paint_appl_mode = GIMP_PAINT_INCREMENTAL; color_pixels (temp_buf_data (area), col, area->width * area->height, area->bytes); } + /* we should refactor this a bit, since we want to seperate the stuff that picks the + color and the stuff that colors the "area" (aka, the brush data to be composited). + So we can make the "randomize color" stuff once, and not for each options */ + if (pressure_options->opacity) opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure; @@ -172,4 +563,21 @@ gimp_context_get_paint_mode (context), gimp_paint_options_get_brush_mode (paint_options), paint_appl_mode); +} + + +static void +gimp_paintbrush_nonclipped_painthit_coords (GimpPaintCore *paint_core, + gint *x, + gint *y, + gint *w, + gint *h) +{ + GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_core); + + /* Note: these are the brush mask size plus a border of 1 pixel */ + *x = (gint) paint_core->cur_coords.x - brush_core->brush->mask->width / 2 - 1; + *y = (gint) paint_core->cur_coords.y - brush_core->brush->mask->height / 2 - 1; + *w = brush_core->brush->mask->width + 2; + *h = brush_core->brush->mask->height + 2; }