mirror of https://github.com/GNOME/gimp.git
app: Bug 631619 - Drawing artifacts spread by paintbrush outline on canvas
Add a transform matrix to GimpCanvasBoundary and get rid of the whole BoundSeg transform code in boundary.c and gimpbrushcore.c, it was impossible to get this right on that level. Also fix te extents of GimpCanvasBoundary os it leaves no artifacts.
This commit is contained in:
parent
f8d6821790
commit
3de4d7263a
|
@ -361,34 +361,6 @@ boundary_simplify (BoundSeg *sorted_segs,
|
|||
return (BoundSeg *) g_array_free (new_bounds, FALSE);
|
||||
}
|
||||
|
||||
/*Transform boundary based on a matrix*/
|
||||
|
||||
BoundSeg *
|
||||
boundary_transform (const BoundSeg *segs,
|
||||
gint *num_segs,
|
||||
GimpMatrix3 *matrix)
|
||||
{
|
||||
Boundary *boundary = boundary_new (NULL);
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < *num_segs; i++)
|
||||
{
|
||||
gdouble x1, y1, x2, y2;
|
||||
|
||||
gimp_matrix3_transform_point (matrix, segs[i].x1, segs[i].y1, &x1, &y1);
|
||||
gimp_matrix3_transform_point (matrix, segs[i].x2, segs[i].y2, &x2, &y2);
|
||||
|
||||
boundary_add_seg (boundary,
|
||||
RINT (x1), RINT (y1),
|
||||
RINT (x2), RINT (y2),
|
||||
segs[i].open);
|
||||
}
|
||||
|
||||
*num_segs = boundary->num_segs;
|
||||
|
||||
return boundary_free (boundary, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
boundary_offset (BoundSeg *segs,
|
||||
gint num_segs,
|
||||
|
|
|
@ -56,10 +56,6 @@ BoundSeg * boundary_simplify (BoundSeg *sorted_segs,
|
|||
gint num_groups,
|
||||
gint *num_segs);
|
||||
|
||||
BoundSeg * boundary_transform (const BoundSeg *segs,
|
||||
gint *num_segs,
|
||||
GimpMatrix3 *matrix);
|
||||
|
||||
/* offsets in-place */
|
||||
void boundary_offset (BoundSeg *segs,
|
||||
gint num_segs,
|
||||
|
|
|
@ -43,6 +43,7 @@ enum
|
|||
{
|
||||
PROP_0,
|
||||
PROP_SEGS,
|
||||
PROP_TRANSFORM,
|
||||
PROP_OFFSET_X,
|
||||
PROP_OFFSET_Y
|
||||
};
|
||||
|
@ -54,6 +55,7 @@ struct _GimpCanvasBoundaryPrivate
|
|||
{
|
||||
BoundSeg *segs;
|
||||
gint n_segs;
|
||||
GimpMatrix3 *transform;
|
||||
gdouble offset_x;
|
||||
gdouble offset_y;
|
||||
};
|
||||
|
@ -105,6 +107,10 @@ gimp_canvas_boundary_class_init (GimpCanvasBoundaryClass *klass)
|
|||
gimp_param_spec_array ("segs", NULL, NULL,
|
||||
GIMP_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_TRANSFORM,
|
||||
g_param_spec_pointer ("transform", NULL, NULL,
|
||||
GIMP_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_OFFSET_X,
|
||||
g_param_spec_double ("offset-x", NULL, NULL,
|
||||
-GIMP_MAX_IMAGE_SIZE,
|
||||
|
@ -139,6 +145,12 @@ gimp_canvas_boundary_finalize (GObject *object)
|
|||
private->n_segs = 0;
|
||||
}
|
||||
|
||||
if (private->transform)
|
||||
{
|
||||
g_free (private->transform);
|
||||
private->transform = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
@ -154,6 +166,17 @@ gimp_canvas_boundary_set_property (GObject *object,
|
|||
{
|
||||
case PROP_SEGS:
|
||||
break;
|
||||
case PROP_TRANSFORM:
|
||||
{
|
||||
GimpMatrix3 *transform = g_value_get_pointer (value);
|
||||
if (private->transform)
|
||||
g_free (private->transform);
|
||||
if (transform)
|
||||
private->transform = g_memdup (transform, sizeof (GimpMatrix3));
|
||||
else
|
||||
private->transform = NULL;
|
||||
}
|
||||
break;
|
||||
case PROP_OFFSET_X:
|
||||
private->offset_x = g_value_get_double (value);
|
||||
break;
|
||||
|
@ -179,6 +202,9 @@ gimp_canvas_boundary_get_property (GObject *object,
|
|||
{
|
||||
case PROP_SEGS:
|
||||
break;
|
||||
case PROP_TRANSFORM:
|
||||
g_value_set_pointer (value, private->transform);
|
||||
break;
|
||||
case PROP_OFFSET_X:
|
||||
g_value_set_double (value, private->offset_x);
|
||||
break;
|
||||
|
@ -200,9 +226,36 @@ gimp_canvas_boundary_transform (GimpCanvasItem *item,
|
|||
GimpCanvasBoundaryPrivate *private = GET_PRIVATE (item);
|
||||
gint i;
|
||||
|
||||
if (private->transform)
|
||||
{
|
||||
for (i = 0; i < private->n_segs; i++)
|
||||
{
|
||||
gdouble tx, ty;
|
||||
|
||||
gimp_matrix3_transform_point (private->transform,
|
||||
private->segs[i].x1, private->segs[i].y1,
|
||||
&tx, &ty);
|
||||
gimp_display_shell_transform_xy (shell,
|
||||
tx + private->offset_x,
|
||||
ty + private->offset_y,
|
||||
&segs[i].x1, &segs[i].y1);
|
||||
|
||||
gimp_matrix3_transform_point (private->transform,
|
||||
private->segs[i].x2, private->segs[i].y2,
|
||||
&tx, &ty);
|
||||
gimp_display_shell_transform_xy (shell,
|
||||
tx + private->offset_x,
|
||||
ty + private->offset_y,
|
||||
&segs[i].x2, &segs[i].y2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gimp_display_shell_transform_segments (shell,
|
||||
private->segs, segs, private->n_segs,
|
||||
private->offset_x, private->offset_y);
|
||||
private->segs, segs,
|
||||
private->n_segs,
|
||||
private->offset_x,
|
||||
private->offset_y);
|
||||
|
||||
for (i = 0; i < private->n_segs; i++)
|
||||
{
|
||||
|
@ -227,6 +280,7 @@ gimp_canvas_boundary_transform (GimpCanvasItem *item,
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_canvas_boundary_draw (GimpCanvasItem *item,
|
||||
|
@ -261,17 +315,17 @@ gimp_canvas_boundary_get_extents (GimpCanvasItem *item,
|
|||
|
||||
gimp_canvas_boundary_transform (item, shell, segs);
|
||||
|
||||
x1 = MIN (segs[0].x1, segs[0].x2) - 1;
|
||||
y1 = MIN (segs[0].y1, segs[0].y2) - 1;
|
||||
x2 = MAX (segs[0].x1, segs[0].x2) + 2;
|
||||
y2 = MAX (segs[0].y1, segs[0].y2) + 2;
|
||||
x1 = MIN (segs[0].x1, segs[0].x2);
|
||||
y1 = MIN (segs[0].y1, segs[0].y2);
|
||||
x2 = MAX (segs[0].x1, segs[0].x2);
|
||||
y2 = MAX (segs[0].y1, segs[0].y2);
|
||||
|
||||
for (i = 1; i < private->n_segs; i++)
|
||||
{
|
||||
gint x3 = MIN (segs[i].x1, segs[i].x2) - 1;
|
||||
gint y3 = MIN (segs[i].y1, segs[i].y2) - 1;
|
||||
gint x4 = MAX (segs[i].x1, segs[i].x2) + 2;
|
||||
gint y4 = MAX (segs[i].y1, segs[i].y2) + 2;
|
||||
gint x3 = MIN (segs[i].x1, segs[i].x2);
|
||||
gint y3 = MIN (segs[i].y1, segs[i].y2);
|
||||
gint x4 = MAX (segs[i].x1, segs[i].x2);
|
||||
gint y4 = MAX (segs[i].y1, segs[i].y2);
|
||||
|
||||
x1 = MIN (x1, x3);
|
||||
y1 = MIN (y1, y3);
|
||||
|
@ -281,10 +335,10 @@ gimp_canvas_boundary_get_extents (GimpCanvasItem *item,
|
|||
|
||||
g_free (segs);
|
||||
|
||||
rectangle.x = x1;
|
||||
rectangle.y = y1;
|
||||
rectangle.width = x2 - x1;
|
||||
rectangle.height = y2 - y1;
|
||||
rectangle.x = x1 - 2;
|
||||
rectangle.y = y1 - 2;
|
||||
rectangle.width = x2 - x1 + 4;
|
||||
rectangle.height = y2 - y1 + 4;
|
||||
|
||||
return gdk_region_rectangle (&rectangle);
|
||||
}
|
||||
|
@ -293,6 +347,7 @@ GimpCanvasItem *
|
|||
gimp_canvas_boundary_new (GimpDisplayShell *shell,
|
||||
const BoundSeg *segs,
|
||||
gint n_segs,
|
||||
GimpMatrix3 *transform,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y)
|
||||
{
|
||||
|
@ -303,6 +358,7 @@ gimp_canvas_boundary_new (GimpDisplayShell *shell,
|
|||
|
||||
item = g_object_new (GIMP_TYPE_CANVAS_BOUNDARY,
|
||||
"shell", shell,
|
||||
"transform", transform,
|
||||
"offset-x", offset_x,
|
||||
"offset-y", offset_y,
|
||||
NULL);
|
||||
|
|
|
@ -52,6 +52,7 @@ GType gimp_canvas_boundary_get_type (void) G_GNUC_CONST;
|
|||
GimpCanvasItem * gimp_canvas_boundary_new (GimpDisplayShell *shell,
|
||||
const BoundSeg *segs,
|
||||
gint n_segs,
|
||||
GimpMatrix3 *transform,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y);
|
||||
|
||||
|
|
|
@ -219,7 +219,6 @@ gimp_brush_core_init (GimpBrushCore *core)
|
|||
core->rand = g_rand_new ();
|
||||
|
||||
core->brush_bound_segs = NULL;
|
||||
core->transformed_brush_bound_segs = NULL;
|
||||
core->n_brush_bound_segs = 0;
|
||||
core->brush_bound_width = 0;
|
||||
core->brush_bound_height = 0;
|
||||
|
@ -322,12 +321,6 @@ gimp_brush_core_finalize (GObject *object)
|
|||
core->brush_bound_height = 0;
|
||||
}
|
||||
|
||||
if (core->transformed_brush_bound_segs)
|
||||
{
|
||||
g_free (core->transformed_brush_bound_segs);
|
||||
core->transformed_brush_bound_segs = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
@ -943,7 +936,7 @@ gimp_brush_core_set_dynamics (GimpBrushCore *core,
|
|||
}
|
||||
|
||||
void
|
||||
gimp_brush_core_create_bound_segs (GimpBrushCore *core,
|
||||
gimp_brush_core_create_boundary (GimpBrushCore *core,
|
||||
GimpPaintOptions *paint_options)
|
||||
{
|
||||
TempBuf *mask = NULL;
|
||||
|
@ -1016,23 +1009,24 @@ gimp_brush_core_create_bound_segs (GimpBrushCore *core,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
gimp_brush_core_transform_bound_segs (GimpBrushCore *core,
|
||||
GimpPaintOptions *paint_options)
|
||||
gboolean
|
||||
gimp_brush_core_get_transform (GimpBrushCore *core,
|
||||
GimpMatrix3 *matrix)
|
||||
{
|
||||
gdouble scale;
|
||||
gdouble angle;
|
||||
gdouble aspect_ratio;
|
||||
gdouble height;
|
||||
gdouble width;
|
||||
GimpMatrix3 matrix;
|
||||
gdouble scale_x;
|
||||
gdouble scale_y;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_BRUSH_CORE (core), FALSE);
|
||||
g_return_val_if_fail (matrix != 0, FALSE);
|
||||
g_return_val_if_fail (core->main_brush != NULL, FALSE);
|
||||
g_return_val_if_fail (core->brush_bound_segs != NULL, FALSE);
|
||||
|
||||
g_return_if_fail (GIMP_IS_BRUSH_CORE (core));
|
||||
g_return_if_fail (core->main_brush != NULL);
|
||||
g_return_if_fail (core->brush_bound_segs != NULL);
|
||||
gimp_matrix3_identity (matrix);
|
||||
|
||||
scale = core->scale;
|
||||
angle = core->angle;
|
||||
|
@ -1068,28 +1062,21 @@ gimp_brush_core_transform_bound_segs (GimpBrushCore *core,
|
|||
scale_y = scale / aspect_ratio;
|
||||
}
|
||||
|
||||
if (core->transformed_brush_bound_segs)
|
||||
{
|
||||
g_free (core->transformed_brush_bound_segs);
|
||||
core->transformed_brush_bound_segs = NULL;
|
||||
}
|
||||
|
||||
if ((scale > 0.0) && (aspect_ratio > 0.0))
|
||||
{
|
||||
scale = gimp_brush_core_clamp_brush_scale (core, scale);
|
||||
|
||||
gimp_brush_transform_matrix (height, width,
|
||||
scale, aspect_ratio, angle, &matrix);
|
||||
|
||||
core->transformed_brush_bound_segs =
|
||||
boundary_transform (core->brush_bound_segs,
|
||||
&core->n_brush_bound_segs,
|
||||
&matrix);
|
||||
scale, aspect_ratio, angle, matrix);
|
||||
|
||||
/* FIXME. Do noy use scale_x/scale_y */
|
||||
core->transformed_brush_bound_width = core->brush_bound_width * scale_x;
|
||||
core->transformed_brush_bound_height = core->brush_bound_height * scale_y;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -85,7 +85,6 @@ struct _GimpBrushCore
|
|||
|
||||
/* don't use these... */
|
||||
BoundSeg *brush_bound_segs;
|
||||
BoundSeg *transformed_brush_bound_segs;
|
||||
gint n_brush_bound_segs;
|
||||
gint brush_bound_width;
|
||||
gint brush_bound_height;
|
||||
|
@ -120,10 +119,10 @@ void gimp_brush_core_set_brush (GimpBrushCore *core,
|
|||
void gimp_brush_core_set_dynamics (GimpBrushCore *core,
|
||||
GimpDynamics *dynamics);
|
||||
|
||||
void gimp_brush_core_create_bound_segs (GimpBrushCore *core,
|
||||
void gimp_brush_core_create_boundary(GimpBrushCore *core,
|
||||
GimpPaintOptions *options);
|
||||
void gimp_brush_core_transform_bound_segs (GimpBrushCore *core,
|
||||
GimpPaintOptions *paint_options);
|
||||
gboolean gimp_brush_core_get_transform (GimpBrushCore *core,
|
||||
GimpMatrix3 *matrix);
|
||||
|
||||
void gimp_brush_core_paste_canvas (GimpBrushCore *core,
|
||||
GimpDrawable *drawable,
|
||||
|
|
|
@ -296,6 +296,7 @@ gimp_brush_tool_draw_brush (GimpBrushTool *brush_tool,
|
|||
GimpDrawTool *draw_tool;
|
||||
GimpBrushCore *brush_core;
|
||||
GimpPaintOptions *options;
|
||||
GimpMatrix3 matrix;
|
||||
|
||||
g_return_if_fail (GIMP_IS_BRUSH_TOOL (brush_tool));
|
||||
|
||||
|
@ -307,27 +308,14 @@ gimp_brush_tool_draw_brush (GimpBrushTool *brush_tool,
|
|||
options = GIMP_PAINT_TOOL_GET_OPTIONS (brush_tool);
|
||||
|
||||
if (! brush_core->brush_bound_segs && brush_core->main_brush)
|
||||
gimp_brush_core_create_bound_segs (brush_core, options);
|
||||
gimp_brush_core_create_boundary (brush_core, options);
|
||||
|
||||
#define TRANSFORM_BOUNDARY 1
|
||||
|
||||
#if TRANSFORM_BOUNDARY
|
||||
if (brush_core->brush_bound_segs)
|
||||
gimp_brush_core_transform_bound_segs (brush_core, options);
|
||||
|
||||
if (brush_core->transformed_brush_bound_segs)
|
||||
#else
|
||||
if (brush_core->brush_bound_segs)
|
||||
#endif
|
||||
if (brush_core->brush_bound_segs &&
|
||||
gimp_brush_core_get_transform (brush_core, &matrix))
|
||||
{
|
||||
GimpDisplayShell *shell = gimp_display_get_shell (draw_tool->display);
|
||||
#if TRANSFORM_BOUNDARY
|
||||
gdouble width = brush_core->transformed_brush_bound_width;
|
||||
gdouble height = brush_core->transformed_brush_bound_height;
|
||||
#else
|
||||
gdouble width = brush_core->brush_bound_width;
|
||||
gdouble height = brush_core->brush_bound_height;
|
||||
#endif
|
||||
|
||||
/* don't draw the boundary if it becomes too small */
|
||||
if (SCALEX (shell, width) > 4 && SCALEY (shell, height) > 4)
|
||||
|
@ -348,13 +336,9 @@ gimp_brush_tool_draw_brush (GimpBrushTool *brush_tool,
|
|||
}
|
||||
|
||||
gimp_draw_tool_add_boundary (draw_tool,
|
||||
#if TRANSFORM_BOUNDARY
|
||||
brush_core->transformed_brush_bound_segs,
|
||||
brush_core->n_brush_bound_segs,
|
||||
#else
|
||||
brush_core->brush_bound_segs,
|
||||
brush_core->n_brush_bound_segs,
|
||||
#endif
|
||||
&matrix,
|
||||
x, y);
|
||||
}
|
||||
else if (draw_fallback)
|
||||
|
|
|
@ -754,6 +754,7 @@ gimp_draw_tool_add_pen (GimpDrawTool *draw_tool,
|
|||
* @draw_tool: a #GimpDrawTool
|
||||
* @bound_segs: the sorted brush outline
|
||||
* @n_bound_segs: the number of segments in @bound_segs
|
||||
* @matrix: transform matrix for the boundary
|
||||
* @offset_x: x offset
|
||||
* @offset_y: y offset
|
||||
*
|
||||
|
@ -766,6 +767,7 @@ GimpCanvasItem *
|
|||
gimp_draw_tool_add_boundary (GimpDrawTool *draw_tool,
|
||||
const BoundSeg *bound_segs,
|
||||
gint n_bound_segs,
|
||||
GimpMatrix3 *transform,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y)
|
||||
{
|
||||
|
@ -777,6 +779,7 @@ gimp_draw_tool_add_boundary (GimpDrawTool *draw_tool,
|
|||
|
||||
item = gimp_canvas_boundary_new (gimp_display_get_shell (draw_tool->display),
|
||||
bound_segs, n_bound_segs,
|
||||
transform,
|
||||
offset_x, offset_y);
|
||||
|
||||
gimp_draw_tool_add_item (draw_tool, item);
|
||||
|
|
|
@ -163,6 +163,7 @@ GimpCanvasItem * gimp_draw_tool_add_pen (GimpDrawTool *draw_too
|
|||
GimpCanvasItem * gimp_draw_tool_add_boundary (GimpDrawTool *draw_tool,
|
||||
const BoundSeg *bound_segs,
|
||||
gint n_bound_segs,
|
||||
GimpMatrix3 *transform,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y);
|
||||
|
||||
|
|
|
@ -812,6 +812,7 @@ gimp_edit_selection_tool_draw (GimpDrawTool *draw_tool)
|
|||
gimp_draw_tool_add_boundary (draw_tool,
|
||||
edit_select->segs_in,
|
||||
edit_select->num_segs_in,
|
||||
NULL,
|
||||
edit_select->cumlx + off_x,
|
||||
edit_select->cumly + off_y);
|
||||
}
|
||||
|
@ -821,6 +822,7 @@ gimp_edit_selection_tool_draw (GimpDrawTool *draw_tool)
|
|||
gimp_draw_tool_add_boundary (draw_tool,
|
||||
edit_select->segs_out,
|
||||
edit_select->num_segs_out,
|
||||
NULL,
|
||||
edit_select->cumlx + off_x,
|
||||
edit_select->cumly + off_y);
|
||||
}
|
||||
|
@ -962,6 +964,7 @@ gimp_edit_selection_tool_draw (GimpDrawTool *draw_tool)
|
|||
gimp_draw_tool_add_boundary (draw_tool,
|
||||
edit_select->segs_in,
|
||||
edit_select->num_segs_in,
|
||||
NULL,
|
||||
edit_select->cumlx,
|
||||
edit_select->cumly);
|
||||
break;
|
||||
|
|
|
@ -331,6 +331,7 @@ gimp_region_select_tool_draw (GimpDrawTool *draw_tool)
|
|||
gimp_draw_tool_add_boundary (draw_tool,
|
||||
region_sel->segs,
|
||||
region_sel->n_segs,
|
||||
NULL,
|
||||
off_x, off_y);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -966,6 +966,7 @@ gimp_transform_tool_draw (GimpDrawTool *draw_tool)
|
|||
|
||||
gimp_draw_tool_add_boundary (draw_tool,
|
||||
segs_in, num_segs_in,
|
||||
NULL,
|
||||
0, 0);
|
||||
g_free (segs_in);
|
||||
}
|
||||
|
@ -991,6 +992,7 @@ gimp_transform_tool_draw (GimpDrawTool *draw_tool)
|
|||
|
||||
gimp_draw_tool_add_boundary (draw_tool,
|
||||
segs_out, num_segs_out,
|
||||
NULL,
|
||||
0, 0);
|
||||
g_free (segs_out);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue