static GimpCanvasItem * gimp_brush_tool_get_outline (GimpPaintTool *paint_tool, GimpDisplay *display, gdouble x, gdouble y) { GimpBrushTool *brush_tool = GIMP_BRUSH_TOOL (paint_tool); GimpCanvasItem *item; item = gimp_brush_tool_create_outline (brush_tool, display, x, y); if (! item) { GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_tool->core); if (brush_core->main_brush && brush_core->dynamics) { /* if an outline was expected, but got scaled away by * transform/dynamics, draw a circle in the "normal" size. */ GimpPaintOptions *options; options = GIMP_PAINT_TOOL_GET_OPTIONS (brush_tool); gimp_paint_tool_set_draw_circle (paint_tool, TRUE, options->brush_size); } } return item; }
static void gimp_brush_tool_brush_changed (GimpContext *context, GimpBrush *brush, GimpBrushTool *brush_tool) { GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (brush_tool); GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_tool->core); gimp_brush_core_set_brush (brush_core, brush); }
static void gimp_eraser_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options) { GimpEraserOptions *options = GIMP_ERASER_OPTIONS (paint_options); GimpContext *context = GIMP_CONTEXT (paint_options); GimpImage *image; gdouble opacity; TempBuf *area; guchar col[MAX_CHANNELS]; gdouble hardness; image = gimp_item_get_image (GIMP_ITEM (drawable)); opacity = gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist); if (opacity == 0.0) return; area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options); if (! area) return; gimp_image_get_background (image, context, gimp_drawable_type (drawable), col); /* set the alpha channel */ col[area->bytes - 1] = OPAQUE_OPACITY; /* color the pixels */ color_pixels (temp_buf_data (area), col, area->width * area->height, area->bytes); opacity *= gimp_paint_options_get_dynamic_opacity (paint_options, &paint_core->cur_coords); hardness = gimp_paint_options_get_dynamic_hardness (paint_options, &paint_core->cur_coords); gimp_brush_core_paste_canvas (GIMP_BRUSH_CORE (paint_core), drawable, MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), (options->anti_erase ? GIMP_ANTI_ERASE_MODE : GIMP_ERASE_MODE), gimp_paint_options_get_brush_mode (paint_options), hardness, paint_options->application_mode); }
static void gimp_smudge_brush_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; }
static void gimp_brush_tool_options_notify (GimpTool *tool, GimpToolOptions *options, const GParamSpec *pspec) { GIMP_TOOL_CLASS (parent_class)->options_notify (tool, options, pspec); if (! strcmp (pspec->name, "brush-size") || ! strcmp (pspec->name, "brush-angle") || ! strcmp (pspec->name, "brush-aspect-ratio")) { GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool); GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_tool->core); g_signal_emit_by_name (brush_core, "set-brush", brush_core->main_brush); } }
static void gimp_brush_tool_oper_update (GimpTool *tool, const GimpCoords *coords, GdkModifierType state, gboolean proximity, GimpDisplay *display) { GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (tool); GimpDrawable *drawable; gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool)); GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state, proximity, display); drawable = gimp_image_get_active_drawable (gimp_display_get_image (display)); if (! gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool)) && drawable && proximity) { GimpContext *context = GIMP_CONTEXT (paint_options); GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool); GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_tool->core); gimp_brush_core_set_brush (brush_core, gimp_context_get_brush (context)); gimp_brush_core_set_dynamics (brush_core, gimp_context_get_dynamics (context)); if (GIMP_BRUSH_CORE_GET_CLASS (brush_core)->handles_transforming_brush) { gimp_brush_core_eval_transform_dynamics (brush_core, drawable, paint_options, coords); } } gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool)); }
static void gimp_brush_tool_cursor_update (GimpTool *tool, const GimpCoords *coords, GdkModifierType state, GimpDisplay *display) { GimpBrushTool *brush_tool = GIMP_BRUSH_TOOL (tool); GimpBrushCore *brush_core = GIMP_BRUSH_CORE (GIMP_PAINT_TOOL (brush_tool)->core); if (! gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool))) { if (! brush_core->main_brush || ! brush_core->dynamics) { gimp_tool_set_cursor (tool, display, gimp_tool_control_get_cursor (tool->control), gimp_tool_control_get_tool_cursor (tool->control), GIMP_CURSOR_MODIFIER_BAD); return; } } GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display); }
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 void gimp_convolve_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options) { GimpConvolve *convolve = GIMP_CONVOLVE (paint_core); GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_core); GimpConvolveOptions *options = GIMP_CONVOLVE_OPTIONS (paint_options); GimpContext *context = GIMP_CONTEXT (paint_options); GimpImage *image; TempBuf *area; PixelRegion srcPR; PixelRegion destPR; PixelRegion tempPR; guchar *buffer; gdouble opacity; gdouble rate; gint bytes; 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; area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options); if (! area) return; rate = options->rate; rate *= gimp_paint_options_get_dynamic_rate (paint_options, &paint_core->cur_coords); gimp_convolve_calculate_matrix (convolve, options->type, brush_core->brush->mask->width / 2, brush_core->brush->mask->height / 2, rate); /* configure the source pixel region */ pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable), area->x, area->y, area->width, area->height, FALSE); if (gimp_drawable_has_alpha (drawable)) { bytes = srcPR.bytes; buffer = g_malloc (area->height * bytes * area->width); pixel_region_init_data (&tempPR, buffer, bytes, bytes * area->width, 0, 0, area->width, area->height); copy_region (&srcPR, &tempPR); } else { /* note: this particular approach needlessly convolves the totally- opaque alpha channel. A faster approach would be to keep tempPR the same number of bytes as srcPR, and extend the paint_core_replace_canvas API to handle non-alpha images. */ bytes = srcPR.bytes + 1; buffer = g_malloc (area->height * bytes * area->width); pixel_region_init_data (&tempPR, buffer, bytes, bytes * area->width, 0, 0, area->width, area->height); add_alpha_region (&srcPR, &tempPR); } /* Convolve the region */ pixel_region_init_data (&tempPR, buffer, bytes, bytes * area->width, 0, 0, area->width, area->height); pixel_region_init_temp_buf (&destPR, area, 0, 0, area->width, area->height); convolve_region (&tempPR, &destPR, convolve->matrix, 3, convolve->matrix_divisor, GIMP_NORMAL_CONVOL, TRUE); g_free (buffer); gimp_brush_core_replace_canvas (brush_core, drawable, MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_paint_options_get_brush_mode (paint_options), 1.0, GIMP_PAINT_INCREMENTAL); }
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); }
void _gimp_paintbrush_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, gdouble opacity) { GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_core); GimpContext *context = GIMP_CONTEXT (paint_options); GimpDynamics *dynamics = brush_core->dynamics; GimpImage *image; GimpRGB gradient_color; GeglBuffer *paint_buffer; gint paint_buffer_x; gint paint_buffer_y; GimpPaintApplicationMode paint_appl_mode; gdouble fade_point; gdouble grad_point; gdouble force; gdouble dyn_force; GimpDynamicsOutput *dyn_output = NULL; image = gimp_item_get_image (GIMP_ITEM (drawable)); 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_appl_mode = paint_options->application_mode; grad_point = gimp_dynamics_get_linear_value (dynamics, GIMP_DYNAMICS_OUTPUT_COLOR, coords, paint_options, fade_point); if (gimp_paint_options_get_gradient_color (paint_options, image, grad_point, paint_core->pixel_dist, &gradient_color)) { /* optionally take the color from the current gradient */ GeglColor *color; opacity *= gradient_color.a; gimp_rgb_set_alpha (&gradient_color, GIMP_OPACITY_OPAQUE); color = gimp_gegl_color_new (&gradient_color); gegl_buffer_set_color (paint_buffer, NULL, color); g_object_unref (color); paint_appl_mode = GIMP_PAINT_INCREMENTAL; } else if (brush_core->brush && gimp_brush_get_pixmap (brush_core->brush)) { /* otherwise check if the brush has a pixmap and use that to * color the area */ gimp_brush_core_color_area_with_pixmap (brush_core, drawable, coords, paint_buffer, paint_buffer_x, paint_buffer_y, gimp_paint_options_get_brush_mode (paint_options)); paint_appl_mode = GIMP_PAINT_INCREMENTAL; } else { /* otherwise fill the area with the foreground color */ GimpRGB foreground; GeglColor *color; gimp_context_get_foreground (context, &foreground); color = gimp_gegl_color_new (&foreground); gegl_buffer_set_color (paint_buffer, NULL, color); g_object_unref (color); } 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; /* finally, let the brush core paste the colored area on the canvas */ gimp_brush_core_paste_canvas (brush_core, drawable, coords, MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), gimp_paint_options_get_brush_mode (paint_options), force, paint_appl_mode); }
static void gimp_clone_motion (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, gdouble opacity, GimpPickable *src_pickable, PixelRegion *srcPR, gint src_offset_x, gint src_offset_y, TempBuf *paint_area, gint paint_area_offset_x, gint paint_area_offset_y, gint paint_area_width, gint paint_area_height) { GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core); GimpCloneOptions *options = GIMP_CLONE_OPTIONS (paint_options); GimpSourceOptions *source_options = GIMP_SOURCE_OPTIONS (paint_options); GimpContext *context = GIMP_CONTEXT (paint_options); GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable)); GimpImage *src_image = NULL; GimpDynamicsOutput *force_output; GimpImageType src_type = 0; GimpImageType dest_type; gpointer pr = NULL; gint y; PixelRegion destPR; GimpPattern *pattern = NULL; gdouble fade_point; gdouble force; switch (options->clone_type) { case GIMP_IMAGE_CLONE: src_image = gimp_pickable_get_image (src_pickable); src_type = gimp_pickable_get_image_type (src_pickable); if (gimp_pickable_get_bytes (src_pickable) < srcPR->bytes) src_type = GIMP_IMAGE_TYPE_WITH_ALPHA (src_type); pixel_region_init_temp_buf (&destPR, paint_area, paint_area_offset_x, paint_area_offset_y, paint_area_width, paint_area_height); pr = pixel_regions_register (2, srcPR, &destPR); break; case GIMP_PATTERN_CLONE: pattern = gimp_context_get_pattern (context); pixel_region_init_temp_buf (&destPR, paint_area, 0, 0, paint_area->width, paint_area->height); pr = pixel_regions_register (1, &destPR); break; } dest_type = gimp_drawable_type (drawable); for (; pr != NULL; pr = pixel_regions_process (pr)) { guchar *s = srcPR->data; guchar *d = destPR.data; for (y = 0; y < destPR.h; y++) { switch (options->clone_type) { case GIMP_IMAGE_CLONE: gimp_clone_line_image (image, dest_type, src_image, src_type, s, d, srcPR->bytes, destPR.bytes, destPR.w); s += srcPR->rowstride; break; case GIMP_PATTERN_CLONE: gimp_clone_line_pattern (image, dest_type, pattern, d, paint_area->x + src_offset_x, paint_area->y + y + src_offset_y, destPR.bytes, destPR.w); break; } d += destPR.rowstride; } } force_output = gimp_dynamics_get_output (GIMP_BRUSH_CORE (paint_core)->dynamics, GIMP_DYNAMICS_OUTPUT_FORCE); fade_point = gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist); force = gimp_dynamics_output_get_linear_value (force_output, coords, paint_options, fade_point); gimp_brush_core_paste_canvas (GIMP_BRUSH_CORE (paint_core), drawable, coords, MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), gimp_paint_options_get_brush_mode (paint_options), force, /* In fixed mode, paint incremental so the * individual brushes are properly applied * on top of each other. * Otherwise the stuff we paint is seamless * and we don't need intermediate masking. */ source_options->align_mode == GIMP_SOURCE_ALIGN_FIXED ? GIMP_PAINT_INCREMENTAL : GIMP_PAINT_CONSTANT); }
GimpCanvasItem * gimp_brush_tool_create_outline (GimpBrushTool *brush_tool, GimpDisplay *display, gdouble x, gdouble y) { GimpBrushCore *brush_core; GimpPaintOptions *options; GimpDisplayShell *shell; const GimpBezierDesc *boundary = NULL; gint width = 0; gint height = 0; g_return_val_if_fail (GIMP_IS_BRUSH_TOOL (brush_tool), NULL); g_return_val_if_fail (GIMP_IS_DISPLAY (display), NULL); if (! GIMP_PAINT_TOOL (brush_tool)->draw_brush) return NULL; brush_core = GIMP_BRUSH_CORE (GIMP_PAINT_TOOL (brush_tool)->core); options = GIMP_PAINT_TOOL_GET_OPTIONS (brush_tool); shell = gimp_display_get_shell (display); if (! brush_core->main_brush || ! brush_core->dynamics) return NULL; if (brush_core->scale > 0.0) boundary = gimp_brush_transform_boundary (brush_core->main_brush, brush_core->scale, brush_core->aspect_ratio, brush_core->angle, brush_core->hardness, &width, &height); /* don't draw the boundary if it becomes too small */ if (boundary && SCALEX (shell, width) > 4 && SCALEY (shell, height) > 4) { x -= width / 2.0; y -= height / 2.0; if (gimp_paint_options_get_brush_mode (options) == GIMP_BRUSH_HARD) { #define EPSILON 0.000001 /* Add EPSILON before rounding since e.g. * (5.0 - 0.5) may end up at (4.499999999....) * due to floating point fnords */ x = RINT (x + EPSILON); y = RINT (y + EPSILON); #undef EPSILON } return gimp_canvas_path_new (shell, boundary, x, y, FALSE, GIMP_PATH_STYLE_OUTLINE); } return NULL; }
void _gimp_paintbrush_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); GimpPressureOptions *pressure_options = paint_options->pressure_options; GimpImage *image; GimpRGB gradient_color; TempBuf *area; guchar col[MAX_CHANNELS]; GimpPaintApplicationMode paint_appl_mode; image = gimp_item_get_image (GIMP_ITEM (drawable)); opacity *= gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist); if (opacity == 0.0) return; paint_appl_mode = paint_options->application_mode; area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options); if (! area) return; /* optionally take the color from the current gradient */ if (gimp_paint_options_get_gradient_color (paint_options, image, paint_core->cur_coords.pressure, paint_core->pixel_dist, &gradient_color)) { opacity *= gradient_color.a; gimp_rgb_get_uchar (&gradient_color, &col[RED_PIX], &col[GREEN_PIX], &col[BLUE_PIX]); col[ALPHA_PIX] = OPAQUE_OPACITY; color_pixels (temp_buf_data (area), col, area->width * area->height, area->bytes); paint_appl_mode = GIMP_PAINT_INCREMENTAL; } /* otherwise check if the brush has a pixmap and use that to color the area */ else if (brush_core->brush && brush_core->brush->pixmap) { gimp_brush_core_color_area_with_pixmap (brush_core, drawable, area, gimp_paint_options_get_brush_mode (paint_options)); paint_appl_mode = GIMP_PAINT_INCREMENTAL; } /* otherwise fill the area with the foreground color */ else { gimp_image_get_foreground (image, context, gimp_drawable_type (drawable), col); col[area->bytes - 1] = OPAQUE_OPACITY; color_pixels (temp_buf_data (area), col, area->width * area->height, area->bytes); } if (paint_core->use_pressure && pressure_options->opacity) opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure; /* finally, let the brush core paste the colored area on the canvas */ gimp_brush_core_paste_canvas (brush_core, drawable, MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), gimp_paint_options_get_brush_mode (paint_options), paint_appl_mode); }
void gimp_source_core_motion (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords) { GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core); GimpSourceOptions *options = GIMP_SOURCE_OPTIONS (paint_options); GimpDynamics *dynamics = GIMP_BRUSH_CORE (paint_core)->dynamics; GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable)); GimpPickable *src_pickable = NULL; GeglBuffer *src_buffer = NULL; GeglRectangle src_rect; gint src_offset_x; gint src_offset_y; GeglBuffer *paint_buffer; gint paint_buffer_x; gint paint_buffer_y; gint paint_area_offset_x; gint paint_area_offset_y; gint paint_area_width; gint paint_area_height; gdouble fade_point; gdouble opacity; 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; src_offset_x = source_core->offset_x; src_offset_y = source_core->offset_y; if (gimp_source_core_use_source (source_core, options)) { src_pickable = GIMP_PICKABLE (source_core->src_drawable); if (options->sample_merged) { GimpImage *src_image = gimp_pickable_get_image (src_pickable); gint off_x, off_y; src_pickable = GIMP_PICKABLE (src_image); gimp_item_get_offset (GIMP_ITEM (source_core->src_drawable), &off_x, &off_y); src_offset_x += off_x; src_offset_y += off_y; } gimp_pickable_flush (src_pickable); } 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_area_offset_x = 0; paint_area_offset_y = 0; paint_area_width = gegl_buffer_get_width (paint_buffer); paint_area_height = gegl_buffer_get_height (paint_buffer); if (gimp_source_core_use_source (source_core, options)) { src_buffer = GIMP_SOURCE_CORE_GET_CLASS (source_core)->get_source (source_core, drawable, paint_options, src_pickable, src_offset_x, src_offset_y, paint_buffer, paint_buffer_x, paint_buffer_y, &paint_area_offset_x, &paint_area_offset_y, &paint_area_width, &paint_area_height, &src_rect); if (! src_buffer) return; } /* Set the paint buffer to transparent */ gegl_buffer_clear (paint_buffer, NULL); GIMP_SOURCE_CORE_GET_CLASS (source_core)->motion (source_core, drawable, paint_options, coords, opacity, src_pickable, src_buffer, &src_rect, src_offset_x, src_offset_y, paint_buffer, paint_buffer_x, paint_buffer_y, paint_area_offset_x, paint_area_offset_y, paint_area_width, paint_area_height); if (src_buffer) g_object_unref (src_buffer); }
static void gimp_dodge_burn_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords) { GimpDodgeBurnOptions *options = GIMP_DODGE_BURN_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; gdouble fade_point; gdouble opacity; gdouble force; 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; /* DodgeBurn the region */ gimp_gegl_dodgeburn (gimp_paint_core_get_orig_image (paint_core), GEGL_RECTANGLE (paint_buffer_x, paint_buffer_y, gegl_buffer_get_width (paint_buffer), gegl_buffer_get_height (paint_buffer)), paint_buffer, GEGL_RECTANGLE (0, 0, 0, 0), options->exposure / 100.0, options->type, options->mode); if (gimp_dynamics_is_output_enabled (dynamics, GIMP_DYNAMICS_OUTPUT_FORCE)) force = gimp_dynamics_get_linear_value (dynamics, GIMP_DYNAMICS_OUTPUT_FORCE, coords, paint_options, fade_point); else force = paint_options->brush_force; /* Replace the newly dodgedburned area (paint_area) to the image */ 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_CONSTANT); }
static void gimp_eraser_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords) { GimpEraserOptions *options = GIMP_ERASER_OPTIONS (paint_options); GimpContext *context = GIMP_CONTEXT (paint_options); GimpDynamics *dynamics = GIMP_BRUSH_CORE (paint_core)->dynamics; GimpDynamicsOutput *opacity_output; GimpDynamicsOutput *force_output; GimpImage *image; gdouble fade_point; gdouble opacity; TempBuf *area; guchar col[MAX_CHANNELS]; gdouble force; image = gimp_item_get_image (GIMP_ITEM (drawable)); opacity_output = gimp_dynamics_get_output (dynamics, GIMP_DYNAMICS_OUTPUT_OPACITY); fade_point = gimp_paint_options_get_fade (paint_options, gimp_item_get_image (GIMP_ITEM (drawable)), paint_core->pixel_dist); opacity = gimp_dynamics_output_get_linear_value (opacity_output, coords, paint_options, fade_point); if (opacity == 0.0) return; area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options, coords); if (! area) return; gimp_image_get_background (image, context, gimp_drawable_type (drawable), col); /* set the alpha channel */ col[area->bytes - 1] = OPAQUE_OPACITY; /* color the pixels */ color_pixels (temp_buf_get_data (area), col, area->width * area->height, area->bytes); force_output = gimp_dynamics_get_output (dynamics, GIMP_DYNAMICS_OUTPUT_FORCE); force = gimp_dynamics_output_get_linear_value (force_output, coords, paint_options, fade_point); gimp_brush_core_paste_canvas (GIMP_BRUSH_CORE (paint_core), drawable, coords, MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), (options->anti_erase ? GIMP_ANTI_ERASE_MODE : GIMP_ERASE_MODE), gimp_paint_options_get_brush_mode (paint_options), force, paint_options->application_mode); }
static void gimp_convolve_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords) { GimpConvolve *convolve = GIMP_CONVOLVE (paint_core); GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_core); GimpConvolveOptions *options = GIMP_CONVOLVE_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; GimpTempBuf *temp_buf; GeglBuffer *convolve_buffer; gdouble fade_point; gdouble opacity; gdouble rate; 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; rate = (options->rate * gimp_dynamics_get_linear_value (dynamics, GIMP_DYNAMICS_OUTPUT_RATE, coords, paint_options, fade_point)); gimp_convolve_calculate_matrix (convolve, options->type, gimp_brush_get_width (brush_core->brush) / 2, gimp_brush_get_height (brush_core->brush) / 2, rate); /* need a linear buffer for gimp_gegl_convolve() */ temp_buf = gimp_temp_buf_new (gegl_buffer_get_width (paint_buffer), gegl_buffer_get_height (paint_buffer), gegl_buffer_get_format (paint_buffer)); convolve_buffer = gimp_temp_buf_create_buffer (temp_buf); gimp_temp_buf_unref (temp_buf); 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)), convolve_buffer, GEGL_RECTANGLE (0, 0, 0, 0)); gimp_gegl_convolve (convolve_buffer, GEGL_RECTANGLE (0, 0, gegl_buffer_get_width (convolve_buffer), gegl_buffer_get_height (convolve_buffer)), paint_buffer, GEGL_RECTANGLE (0, 0, gegl_buffer_get_width (paint_buffer), gegl_buffer_get_height (paint_buffer)), convolve->matrix, 3, convolve->matrix_divisor, GIMP_NORMAL_CONVOL, TRUE); g_object_unref (convolve_buffer); gimp_brush_core_replace_canvas (brush_core, drawable, coords, MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_paint_options_get_brush_mode (paint_options), 1.0, GIMP_PAINT_INCREMENTAL); }
void gimp_source_core_motion (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, GimpSymmetry *sym) { GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core); GimpSourceOptions *options = GIMP_SOURCE_OPTIONS (paint_options); GimpDynamics *dynamics = GIMP_BRUSH_CORE (paint_core)->dynamics; GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable)); GimpPickable *src_pickable = NULL; GeglBuffer *src_buffer = NULL; GeglRectangle src_rect; gint base_src_offset_x; gint base_src_offset_y; gint src_offset_x; gint src_offset_y; GeglBuffer *paint_buffer; gint paint_buffer_x; gint paint_buffer_y; gint paint_area_offset_x; gint paint_area_offset_y; gint paint_area_width; gint paint_area_height; gdouble fade_point; gdouble opacity; GeglNode *op; GimpCoords *origin; GimpCoords *coords; gint n_strokes; gint i; fade_point = gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist); origin = gimp_symmetry_get_origin (sym); /* Some settings are based on the original stroke. */ opacity = gimp_dynamics_get_linear_value (dynamics, GIMP_DYNAMICS_OUTPUT_OPACITY, origin, paint_options, fade_point); if (opacity == 0.0) return; base_src_offset_x = source_core->offset_x; base_src_offset_y = source_core->offset_y; if (gimp_source_core_use_source (source_core, options)) { src_pickable = GIMP_PICKABLE (source_core->src_drawable); if (options->sample_merged) { GimpImage *src_image = gimp_pickable_get_image (src_pickable); gint off_x, off_y; src_pickable = GIMP_PICKABLE (src_image); gimp_item_get_offset (GIMP_ITEM (source_core->src_drawable), &off_x, &off_y); base_src_offset_x += off_x; base_src_offset_y += off_y; } gimp_pickable_flush (src_pickable); } gimp_brush_core_eval_transform_dynamics (GIMP_BRUSH_CORE (paint_core), drawable, paint_options, origin); n_strokes = gimp_symmetry_get_size (sym); for (i = 0; i < n_strokes; i++) { coords = gimp_symmetry_get_coords (sym, i); paint_buffer = gimp_paint_core_get_paint_buffer (paint_core, drawable, paint_options, coords, &paint_buffer_x, &paint_buffer_y, NULL, NULL); if (! paint_buffer) continue; paint_area_offset_x = 0; paint_area_offset_y = 0; paint_area_width = gegl_buffer_get_width (paint_buffer); paint_area_height = gegl_buffer_get_height (paint_buffer); src_offset_x = base_src_offset_x; src_offset_y = base_src_offset_y; if (gimp_source_core_use_source (source_core, options)) { /* When using a source, use the same for every stroke. */ src_offset_x = src_offset_x - coords->x + origin->x; src_offset_y = src_offset_y - coords->y + origin->y; src_buffer = GIMP_SOURCE_CORE_GET_CLASS (source_core)->get_source (source_core, drawable, paint_options, src_pickable, src_offset_x, src_offset_y, paint_buffer, paint_buffer_x, paint_buffer_y, &paint_area_offset_x, &paint_area_offset_y, &paint_area_width, &paint_area_height, &src_rect); if (! src_buffer) continue; } /* Set the paint buffer to transparent */ gegl_buffer_clear (paint_buffer, NULL); op = gimp_symmetry_get_operation (sym, i, gegl_buffer_get_width (paint_buffer), gegl_buffer_get_height (paint_buffer)); GIMP_SOURCE_CORE_GET_CLASS (source_core)->motion (source_core, drawable, paint_options, coords, op, opacity, src_pickable, src_buffer, &src_rect, src_offset_x, src_offset_y, paint_buffer, paint_buffer_x, paint_buffer_y, paint_area_offset_x, paint_area_offset_y, paint_area_width, paint_area_height); if (src_buffer) g_object_unref (src_buffer); } }
static void gimp_clone_motion (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, gdouble opacity, GimpPickable *src_pickable, GeglBuffer *src_buffer, GeglRectangle *src_rect, gint src_offset_x, gint src_offset_y, GeglBuffer *paint_buffer, gint paint_buffer_x, gint paint_buffer_y, gint paint_area_offset_x, gint paint_area_offset_y, gint paint_area_width, gint paint_area_height) { GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core); GimpCloneOptions *options = GIMP_CLONE_OPTIONS (paint_options); GimpSourceOptions *source_options = GIMP_SOURCE_OPTIONS (paint_options); GimpContext *context = GIMP_CONTEXT (paint_options); GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable)); gdouble fade_point; gdouble force; if (gimp_source_core_use_source (source_core, source_options)) { gegl_buffer_copy (src_buffer, GEGL_RECTANGLE (src_rect->x, src_rect->y, paint_area_width, paint_area_height), paint_buffer, GEGL_RECTANGLE (paint_area_offset_x, paint_area_offset_y, 0, 0)); } else if (options->clone_type == GIMP_PATTERN_CLONE) { GimpPattern *pattern = gimp_context_get_pattern (context); GeglBuffer *src_buffer = gimp_pattern_create_buffer (pattern); gegl_buffer_set_pattern (paint_buffer, GEGL_RECTANGLE (paint_area_offset_x, paint_area_offset_y, paint_area_width, paint_area_height), src_buffer, - paint_buffer_x - src_offset_x, - paint_buffer_y - src_offset_y); g_object_unref (src_buffer); } else { g_return_if_reached (); } fade_point = gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist); force = gimp_dynamics_get_linear_value (GIMP_BRUSH_CORE (paint_core)->dynamics, GIMP_DYNAMICS_OUTPUT_FORCE, coords, paint_options, fade_point); gimp_brush_core_paste_canvas (GIMP_BRUSH_CORE (paint_core), drawable, coords, MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), gimp_paint_options_get_brush_mode (paint_options), force, /* In fixed mode, paint incremental so the * individual brushes are properly applied * on top of each other. * Otherwise the stuff we paint is seamless * and we don't need intermediate masking. */ source_options->align_mode == GIMP_SOURCE_ALIGN_FIXED ? GIMP_PAINT_INCREMENTAL : GIMP_PAINT_CONSTANT); }