static TempBuf * gimp_ink_get_paint_area (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords) { GimpInk *ink = GIMP_INK (paint_core); gint x, y; gint width, height; gint dwidth, dheight; gint x1, y1, x2, y2; gint bytes; bytes = gimp_drawable_bytes_with_alpha (drawable); gimp_blob_bounds (ink->cur_blob, &x, &y, &width, &height); dwidth = gimp_item_get_width (GIMP_ITEM (drawable)); dheight = gimp_item_get_height (GIMP_ITEM (drawable)); x1 = CLAMP (x / SUBSAMPLE - 1, 0, dwidth); y1 = CLAMP (y / SUBSAMPLE - 1, 0, dheight); x2 = CLAMP ((x + width) / SUBSAMPLE + 2, 0, dwidth); y2 = CLAMP ((y + height) / SUBSAMPLE + 2, 0, dheight); /* configure the canvas buffer */ if ((x2 - x1) && (y2 - y1)) paint_core->canvas_buf = temp_buf_resize (paint_core->canvas_buf, bytes, x1, y1, (x2 - x1), (y2 - y1)); else return NULL; return paint_core->canvas_buf; }
static void gimp_ink_undo_constructed (GObject *object) { GimpInkUndo *ink_undo = GIMP_INK_UNDO (object); GimpInk *ink; G_OBJECT_CLASS (parent_class)->constructed (object); g_assert (GIMP_IS_INK (GIMP_PAINT_CORE_UNDO (ink_undo)->paint_core)); ink = GIMP_INK (GIMP_PAINT_CORE_UNDO (ink_undo)->paint_core); if (ink->start_blobs) { gint i; GimpBlob *blob; for (i = 0; i < g_list_length (ink->start_blobs); i++) { blob = g_list_nth_data (ink->start_blobs, i); ink_undo->last_blobs = g_list_prepend (ink_undo->last_blobs, gimp_blob_duplicate (blob)); } ink_undo->last_blobs = g_list_reverse (ink_undo->last_blobs); } }
static void gimp_ink_paint (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, GimpPaintState paint_state, guint32 time) { GimpInk *ink = GIMP_INK (paint_core); GimpCoords last_coords; gimp_paint_core_get_last_coords (paint_core, &last_coords); switch (paint_state) { case GIMP_PAINT_STATE_INIT: if (coords->x == last_coords.x && coords->y == last_coords.y) { /* start with new blobs if we're not interpolating */ if (ink->start_blob) { g_free (ink->start_blob); ink->start_blob = NULL; } if (ink->last_blob) { g_free (ink->last_blob); ink->last_blob = NULL; } } else if (ink->last_blob) { /* save the start blob of the line for undo otherwise */ if (ink->start_blob) g_free (ink->start_blob); ink->start_blob = gimp_blob_duplicate (ink->last_blob); } break; case GIMP_PAINT_STATE_MOTION: gimp_ink_motion (paint_core, drawable, paint_options, coords, time); break; case GIMP_PAINT_STATE_FINISH: break; } }
static GeglBuffer * gimp_ink_get_paint_buffer (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, gint *paint_buffer_x, gint *paint_buffer_y) { GimpInk *ink = GIMP_INK (paint_core); gint x, y; gint width, height; gint dwidth, dheight; gint x1, y1, x2, y2; gimp_blob_bounds (ink->cur_blob, &x, &y, &width, &height); dwidth = gimp_item_get_width (GIMP_ITEM (drawable)); dheight = gimp_item_get_height (GIMP_ITEM (drawable)); x1 = CLAMP (x / SUBSAMPLE - 1, 0, dwidth); y1 = CLAMP (y / SUBSAMPLE - 1, 0, dheight); x2 = CLAMP ((x + width) / SUBSAMPLE + 2, 0, dwidth); y2 = CLAMP ((y + height) / SUBSAMPLE + 2, 0, dheight); /* configure the canvas buffer */ if ((x2 - x1) && (y2 - y1)) { GimpTempBuf *temp_buf; const Babl *format; if (gimp_drawable_get_linear (drawable)) format = babl_format ("RGBA float"); else format = babl_format ("R'G'B'A float"); temp_buf = gimp_temp_buf_new ((x2 - x1), (y2 - y1), format); *paint_buffer_x = x1; *paint_buffer_y = y1; if (paint_core->paint_buffer) g_object_unref (paint_core->paint_buffer); paint_core->paint_buffer = gimp_temp_buf_create_buffer (temp_buf); gimp_temp_buf_unref (temp_buf); return paint_core->paint_buffer; } return NULL; }
static void gimp_ink_undo_constructed (GObject *object) { GimpInkUndo *ink_undo = GIMP_INK_UNDO (object); GimpInk *ink; G_OBJECT_CLASS (parent_class)->constructed (object); g_assert (GIMP_IS_INK (GIMP_PAINT_CORE_UNDO (ink_undo)->paint_core)); ink = GIMP_INK (GIMP_PAINT_CORE_UNDO (ink_undo)->paint_core); if (ink->start_blob) ink_undo->last_blob = gimp_blob_duplicate (ink->start_blob); }
static void gimp_ink_finalize (GObject *object) { GimpInk *ink = GIMP_INK (object); if (ink->start_blob) { g_free (ink->start_blob); ink->start_blob = NULL; } if (ink->last_blob) { g_free (ink->last_blob); ink->last_blob = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); }
static void gimp_ink_undo_pop (GimpUndo *undo, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { GimpInkUndo *ink_undo = GIMP_INK_UNDO (undo); GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum); if (GIMP_PAINT_CORE_UNDO (ink_undo)->paint_core) { GimpInk *ink = GIMP_INK (GIMP_PAINT_CORE_UNDO (ink_undo)->paint_core); GList *tmp_blobs; tmp_blobs = ink->last_blobs; ink->last_blobs = ink_undo->last_blobs; ink_undo->last_blobs = tmp_blobs; } }
static void gimp_ink_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, guint32 time) { GimpInk *ink = GIMP_INK (paint_core); GimpInkOptions *options = GIMP_INK_OPTIONS (paint_options); GimpContext *context = GIMP_CONTEXT (paint_options); GimpBlob *blob_union = NULL; GimpBlob *blob_to_render; GeglBuffer *paint_buffer; gint paint_buffer_x; gint paint_buffer_y; GimpRGB foreground; GeglColor *color; if (! ink->last_blob) { ink->last_blob = ink_pen_ellipse (options, coords->x, coords->y, coords->pressure, coords->xtilt, coords->ytilt, 100); if (ink->start_blob) g_free (ink->start_blob); ink->start_blob = gimp_blob_duplicate (ink->last_blob); blob_to_render = ink->last_blob; } else { GimpBlob *blob = ink_pen_ellipse (options, coords->x, coords->y, coords->pressure, coords->xtilt, coords->ytilt, coords->velocity * 100); blob_union = gimp_blob_convex_union (ink->last_blob, blob); g_free (ink->last_blob); ink->last_blob = blob; blob_to_render = blob_union; } /* Get the buffer */ ink->cur_blob = blob_to_render; paint_buffer = gimp_paint_core_get_paint_buffer (paint_core, drawable, paint_options, coords, &paint_buffer_x, &paint_buffer_y); ink->cur_blob = NULL; if (! paint_buffer) return; gimp_context_get_foreground (context, &foreground); color = gimp_gegl_color_new (&foreground); gegl_buffer_set_color (paint_buffer, NULL, color); g_object_unref (color); /* draw the blob directly to the canvas_buffer */ render_blob (paint_core->canvas_buffer, GEGL_RECTANGLE (paint_core->paint_buffer_x, paint_core->paint_buffer_y, gegl_buffer_get_width (paint_core->paint_buffer), gegl_buffer_get_height (paint_core->paint_buffer)), blob_to_render); /* draw the paint_area using the just rendered canvas_buffer as mask */ gimp_paint_core_paste (paint_core, paint_core->canvas_buffer, GEGL_RECTANGLE (paint_core->paint_buffer_x, paint_core->paint_buffer_y, gegl_buffer_get_width (paint_core->paint_buffer), gegl_buffer_get_height (paint_core->paint_buffer)), drawable, GIMP_OPACITY_OPAQUE, gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), GIMP_PAINT_CONSTANT); if (blob_union) g_free (blob_union); }
static void gimp_ink_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, guint32 time) { GimpInk *ink = GIMP_INK (paint_core); GimpInkOptions *options = GIMP_INK_OPTIONS (paint_options); GimpContext *context = GIMP_CONTEXT (paint_options); GimpImage *image; GimpBlob *blob_union = NULL; GimpBlob *blob_to_render; TempBuf *area; guchar col[MAX_CHANNELS]; PixelRegion blob_maskPR; image = gimp_item_get_image (GIMP_ITEM (drawable)); if (! ink->last_blob) { ink->last_blob = ink_pen_ellipse (options, coords->x, coords->y, coords->pressure, coords->xtilt, coords->ytilt, 100); if (ink->start_blob) g_free (ink->start_blob); ink->start_blob = gimp_blob_duplicate (ink->last_blob); blob_to_render = ink->last_blob; } else { GimpBlob *blob = ink_pen_ellipse (options, coords->x, coords->y, coords->pressure, coords->xtilt, coords->ytilt, coords->velocity * 100); blob_union = gimp_blob_convex_union (ink->last_blob, blob); g_free (ink->last_blob); ink->last_blob = blob; blob_to_render = blob_union; } /* Get the buffer */ ink->cur_blob = blob_to_render; area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options, coords); ink->cur_blob = NULL; if (! area) return; gimp_image_get_foreground (image, context, gimp_drawable_type (drawable), col); /* set the alpha channel */ col[paint_core->canvas_buf->bytes - 1] = OPAQUE_OPACITY; /* color the pixels */ color_pixels (temp_buf_get_data (paint_core->canvas_buf), col, area->width * area->height, area->bytes); gimp_paint_core_validate_canvas_tiles (paint_core, paint_core->canvas_buf->x, paint_core->canvas_buf->y, paint_core->canvas_buf->width, paint_core->canvas_buf->height); /* draw the blob directly to the canvas_tiles */ pixel_region_init (&blob_maskPR, paint_core->canvas_tiles, paint_core->canvas_buf->x, paint_core->canvas_buf->y, paint_core->canvas_buf->width, paint_core->canvas_buf->height, TRUE); render_blob (blob_to_render, &blob_maskPR); /* draw the canvas_buf using the just rendered canvas_tiles as mask */ pixel_region_init (&blob_maskPR, paint_core->canvas_tiles, paint_core->canvas_buf->x, paint_core->canvas_buf->y, paint_core->canvas_buf->width, paint_core->canvas_buf->height, FALSE); gimp_paint_core_paste (paint_core, &blob_maskPR, drawable, GIMP_OPACITY_OPAQUE, gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), GIMP_PAINT_CONSTANT); if (blob_union) g_free (blob_union); }