static void gimp_smudge_paint (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, GimpPaintState paint_state, guint32 time) { GimpSmudge *smudge = GIMP_SMUDGE (paint_core); switch (paint_state) { case GIMP_PAINT_STATE_MOTION: /* initialization fails if the user starts outside the drawable */ if (! smudge->initialized) smudge->initialized = gimp_smudge_start (paint_core, drawable, paint_options, coords); if (smudge->initialized) gimp_smudge_motion (paint_core, drawable, paint_options, coords); break; case GIMP_PAINT_STATE_FINISH: if (smudge->accum_buffer) { g_object_unref (smudge->accum_buffer); smudge->accum_buffer = NULL; } smudge->initialized = FALSE; break; default: break; } }
static void gimp_smudge_accumulator_coords (GimpPaintCore *paint_core, const GimpCoords *coords, gint *x, gint *y) { GimpSmudge *smudge = GIMP_SMUDGE (paint_core); *x = (gint) coords->x - gegl_buffer_get_width (smudge->accum_buffer) / 2; *y = (gint) coords->y - gegl_buffer_get_height (smudge->accum_buffer) / 2; }
static void gimp_smudge_finalize (GObject *object) { GimpSmudge *smudge = GIMP_SMUDGE (object); if (smudge->accum_buffer) { g_object_unref (smudge->accum_buffer); smudge->accum_buffer = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); }
static void gimp_smudge_finalize (GObject *object) { GimpSmudge *smudge = GIMP_SMUDGE (object); if (smudge->accum_data) { g_free (smudge->accum_data); smudge->accum_data = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); }
static void gimp_smudge_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords) { GimpSmudge *smudge = GIMP_SMUDGE (paint_core); GimpSmudgeOptions *options = GIMP_SMUDGE_OPTIONS (paint_options); GimpContext *context = GIMP_CONTEXT (paint_options); GimpDynamics *dynamics = GIMP_BRUSH_CORE (paint_core)->dynamics; GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable)); GeglBuffer *paint_buffer; gint paint_buffer_x; gint paint_buffer_y; gint paint_buffer_width; gint paint_buffer_height; gdouble fade_point; gdouble opacity; gdouble rate; gdouble dynamic_rate; gint x, y; gdouble force; gdouble dyn_force; GimpDynamicsOutput *dyn_output = NULL; fade_point = gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist); opacity = gimp_dynamics_get_linear_value (dynamics, GIMP_DYNAMICS_OUTPUT_OPACITY, coords, paint_options, fade_point); if (opacity == 0.0) return; paint_buffer = gimp_paint_core_get_paint_buffer (paint_core, drawable, paint_options, coords, &paint_buffer_x, &paint_buffer_y); if (! paint_buffer) return; paint_buffer_width = gegl_buffer_get_width (paint_buffer); paint_buffer_height = gegl_buffer_get_height (paint_buffer); /* Get the unclipped acumulator coordinates */ gimp_smudge_accumulator_coords (paint_core, coords, &x, &y); /* Enable dynamic rate */ dynamic_rate = gimp_dynamics_get_linear_value (dynamics, GIMP_DYNAMICS_OUTPUT_RATE, coords, paint_options, fade_point); rate = (options->rate / 100.0) * dynamic_rate; /* Smudge uses the buffer Accum. * For each successive painthit Accum is built like this * Accum = rate*Accum + (1-rate)*I. * where I is the pixels under the current painthit. * Then the paint area (paint_area) is built as * (Accum,1) (if no alpha), */ gimp_gegl_smudge_blend (smudge->accum_buffer, GEGL_RECTANGLE (paint_buffer_x - x, paint_buffer_y - y, paint_buffer_width, paint_buffer_height), gimp_drawable_get_buffer (drawable), GEGL_RECTANGLE (paint_buffer_x, paint_buffer_y, paint_buffer_width, paint_buffer_height), smudge->accum_buffer, GEGL_RECTANGLE (paint_buffer_x - x, paint_buffer_y - y, paint_buffer_width, paint_buffer_height), rate); gegl_buffer_copy (smudge->accum_buffer, GEGL_RECTANGLE (paint_buffer_x - x, paint_buffer_y - y, paint_buffer_width, paint_buffer_height), paint_buffer, GEGL_RECTANGLE (0, 0, 0, 0)); dyn_output = gimp_dynamics_get_output (dynamics, GIMP_DYNAMICS_OUTPUT_FORCE); dyn_force = gimp_dynamics_get_linear_value (dynamics, GIMP_DYNAMICS_OUTPUT_FORCE, coords, paint_options, fade_point); if (gimp_dynamics_output_is_enabled (dyn_output)) force = dyn_force; else force = paint_options->brush_force; gimp_brush_core_replace_canvas (GIMP_BRUSH_CORE (paint_core), drawable, coords, MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_paint_options_get_brush_mode (paint_options), force, GIMP_PAINT_INCREMENTAL); }
static gboolean gimp_smudge_start (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords) { GimpSmudge *smudge = GIMP_SMUDGE (paint_core); GeglBuffer *paint_buffer; gint paint_buffer_x; gint paint_buffer_y; gint accum_size; gint x, y; paint_buffer = gimp_paint_core_get_paint_buffer (paint_core, drawable, paint_options, coords, &paint_buffer_x, &paint_buffer_y); if (! paint_buffer) return FALSE; gimp_smudge_accumulator_size (paint_options, coords, &accum_size); /* Allocate the accumulation buffer */ smudge->accum_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, accum_size, accum_size), babl_format ("RGBA float")); /* adjust the x and y coordinates to the upper left corner of the * accumulator */ gimp_smudge_accumulator_coords (paint_core, coords, &x, &y); /* If clipped, prefill the smudge buffer with the color at the * brush position. */ if (x != paint_buffer_x || y != paint_buffer_y || accum_size != gegl_buffer_get_width (paint_buffer) || accum_size != gegl_buffer_get_height (paint_buffer)) { GimpRGB pixel; GeglColor *color; gimp_pickable_get_color_at (GIMP_PICKABLE (drawable), CLAMP ((gint) coords->x, 0, gimp_item_get_width (GIMP_ITEM (drawable)) - 1), CLAMP ((gint) coords->y, 0, gimp_item_get_height (GIMP_ITEM (drawable)) - 1), &pixel); color = gimp_gegl_color_new (&pixel); gegl_buffer_set_color (smudge->accum_buffer, NULL, color); g_object_unref (color); } /* copy the region under the original painthit. */ gegl_buffer_copy (gimp_drawable_get_buffer (drawable), GEGL_RECTANGLE (paint_buffer_x, paint_buffer_y, gegl_buffer_get_width (paint_buffer), gegl_buffer_get_height (paint_buffer)), smudge->accum_buffer, GEGL_RECTANGLE (paint_buffer_x - x, paint_buffer_y - y, 0, 0)); return TRUE; }
static void gimp_smudge_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options) { GimpSmudge *smudge = GIMP_SMUDGE (paint_core); GimpSmudgeOptions *options = GIMP_SMUDGE_OPTIONS (paint_options); GimpContext *context = GIMP_CONTEXT (paint_options); GimpPressureOptions *pressure_options = paint_options->pressure_options; GimpImage *image; TempBuf *area; PixelRegion srcPR, destPR, tempPR; gdouble rate; gdouble opacity; gint x, y, w, h; image = gimp_item_get_image (GIMP_ITEM (drawable)); if (gimp_drawable_is_indexed (drawable)) return; opacity = gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist); if (opacity == 0.0) return; /* Get the unclipped brush coordinates */ gimp_smudge_brush_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_get_tiles (drawable), area->x, area->y, area->width, area->height, FALSE); /* Enable pressure sensitive rate */ if (pressure_options->rate) rate = MIN (options->rate / 100.0 * PRESSURE_SCALE * paint_core->cur_coords.pressure, 1.0); else rate = options->rate / 100.0; /* The tempPR will be the built up buffer (for smudge) */ pixel_region_init_data (&tempPR, smudge->accum_data, smudge->accumPR.bytes, smudge->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); /* Smudge uses the buffer Accum. * For each successive painthit Accum is built like this * Accum = rate*Accum + (1-rate)*I. * where I is the pixels under the current painthit. * Then the paint area (canvas_buf) is built as * (Accum,1) (if no alpha), */ blend_region (&srcPR, &tempPR, &tempPR, ROUND (rate * 255.0)); /* re-init the tempPR */ pixel_region_init_data (&tempPR, smudge->accum_data, smudge->accumPR.bytes, smudge->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); if (pressure_options->opacity) opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure; 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); }
static gboolean gimp_smudge_start (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options) { GimpSmudge *smudge = GIMP_SMUDGE (paint_core); GimpImage *image; TempBuf *area; PixelRegion srcPR; gint bytes; gint x, y, w, h; image = 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_smudge_brush_coords (paint_core, &x, &y, &w, &h); /* Allocate the accumulation buffer */ bytes = gimp_drawable_bytes (drawable); smudge->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[4]; gimp_pickable_get_pixel_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), fill); pixel_region_init_data (&srcPR, smudge->accum_data, bytes, bytes * w, 0, 0, w, h); color_region (&srcPR, fill); } pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable), area->x, area->y, area->width, area->height, FALSE); pixel_region_init_data (&smudge->accumPR, smudge->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, &smudge->accumPR); pixel_region_init_data (&smudge->accumPR, smudge->accum_data, bytes, bytes * w, area->x - x, area->y - y, area->width, area->height); return TRUE; }