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:
Michael Natterer 2010-10-09 22:00:19 +02:00
parent f8d6821790
commit 3de4d7263a
12 changed files with 137 additions and 132 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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,

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}