Bug 768872 - Tiling Symmetry doesn't wrap vertical coordinates over...
... edges for MyPaint brush. Adding the concept of "stateful" symmetry when a tool needs to make sure of corresponding stroke numbers and orders while painting (i.e. stroke N at time T+1 is the continuation of stroke N at time T). This is the case for the MyPaint brushes and the ink tool.
This commit is contained in:
@ -324,45 +324,106 @@ gimp_tiling_update_strokes (GimpSymmetry *sym,
|
||||
width = gimp_item_get_width (GIMP_ITEM (drawable));
|
||||
height = gimp_item_get_height (GIMP_ITEM (drawable));
|
||||
|
||||
if (origin->x > 0 && tiling->max_x == 0 && tiling->interval_x >= 1.0)
|
||||
startx = fmod (origin->x, tiling->interval_x) - tiling->interval_x;
|
||||
|
||||
if (origin->y > 0 && tiling->max_y == 0 && tiling->interval_y >= 1.0)
|
||||
if (sym->stateful)
|
||||
{
|
||||
starty = fmod (origin->y, tiling->interval_y) - tiling->interval_y;
|
||||
/* While I can compute exactly the right number of strokes to
|
||||
* paint on-canvas for stateless tools, stateful tools need to
|
||||
* always have the same number and order of strokes. For this
|
||||
* reason, I compute strokes to fill 2 times the width and height.
|
||||
* This makes the symmetry less efficient with stateful tools, but
|
||||
* also weird behavior may happen if you decide to paint out of
|
||||
* canvas and expect tiling to work in-canvas since it won't
|
||||
* actually be infinite (as no new strokes can be added while
|
||||
* painting since we are stateful).
|
||||
*/
|
||||
gint i, j;
|
||||
|
||||
if (tiling->shift > 0.0)
|
||||
startx -= tiling->shift * floor (origin->y / tiling->interval_y + 1);
|
||||
}
|
||||
|
||||
for (y_count = 0, y = starty; y < height + tiling->interval_y;
|
||||
y_count++, y += tiling->interval_y)
|
||||
{
|
||||
if (tiling->max_y && y_count >= tiling->max_y)
|
||||
break;
|
||||
|
||||
for (x_count = 0, x = startx; x < width + tiling->interval_x;
|
||||
x_count++, x += tiling->interval_x)
|
||||
if (tiling->interval_x < 1.0)
|
||||
{
|
||||
if (tiling->max_x && x_count >= tiling->max_x)
|
||||
break;
|
||||
|
||||
coords = g_memdup (origin, sizeof (GimpCoords));
|
||||
coords->x = x;
|
||||
coords->y = y;
|
||||
strokes = g_list_prepend (strokes, coords);
|
||||
|
||||
if (tiling->interval_x < 1.0)
|
||||
break;
|
||||
x_count = 1;
|
||||
}
|
||||
else if (tiling->max_x == 0)
|
||||
{
|
||||
x_count = (gint) ceil (width / tiling->interval_x);
|
||||
startx -= tiling->interval_x * (gdouble) x_count;
|
||||
x_count = 2 * x_count + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
x_count = tiling->max_x;
|
||||
}
|
||||
|
||||
if (tiling->max_x || startx + tiling->shift <= 0.0)
|
||||
startx = startx + tiling->shift;
|
||||
else
|
||||
startx = startx - tiling->interval_x + tiling->shift;
|
||||
|
||||
if (tiling->interval_y < 1.0)
|
||||
break;
|
||||
{
|
||||
y_count = 1;
|
||||
}
|
||||
else if (tiling->max_y == 0)
|
||||
{
|
||||
y_count = (gint) ceil (height / tiling->interval_y);
|
||||
starty -= tiling->interval_y * (gdouble) y_count;
|
||||
y_count = 2 * y_count + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
y_count = tiling->max_y;
|
||||
}
|
||||
|
||||
for (i = 0, x = startx; i < x_count; i++)
|
||||
{
|
||||
for (j = 0, y = starty; j < y_count; j++)
|
||||
{
|
||||
coords = g_memdup (origin, sizeof (GimpCoords));
|
||||
coords->x = x;
|
||||
coords->y = y;
|
||||
strokes = g_list_prepend (strokes, coords);
|
||||
|
||||
y += tiling->interval_y;
|
||||
}
|
||||
x += tiling->interval_x;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (origin->x > 0 && tiling->max_x == 0 && tiling->interval_x >= 1.0)
|
||||
startx = fmod (origin->x, tiling->interval_x) - tiling->interval_x;
|
||||
|
||||
if (origin->y > 0 && tiling->max_y == 0 && tiling->interval_y >= 1.0)
|
||||
{
|
||||
starty = fmod (origin->y, tiling->interval_y) - tiling->interval_y;
|
||||
|
||||
if (tiling->shift > 0.0)
|
||||
startx -= tiling->shift * floor (origin->y / tiling->interval_y + 1);
|
||||
}
|
||||
|
||||
for (y_count = 0, y = starty; y < height + tiling->interval_y;
|
||||
y_count++, y += tiling->interval_y)
|
||||
{
|
||||
if (tiling->max_y && y_count >= tiling->max_y)
|
||||
break;
|
||||
|
||||
for (x_count = 0, x = startx; x < width + tiling->interval_x;
|
||||
x_count++, x += tiling->interval_x)
|
||||
{
|
||||
if (tiling->max_x && x_count >= tiling->max_x)
|
||||
break;
|
||||
|
||||
coords = g_memdup (origin, sizeof (GimpCoords));
|
||||
coords->x = x;
|
||||
coords->y = y;
|
||||
strokes = g_list_prepend (strokes, coords);
|
||||
|
||||
if (tiling->interval_x < 1.0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (tiling->max_x || startx + tiling->shift <= 0.0)
|
||||
startx = startx + tiling->shift;
|
||||
else
|
||||
startx = startx - tiling->interval_x + tiling->shift;
|
||||
|
||||
if (tiling->interval_y < 1.0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sym->strokes = strokes;
|
||||
|
||||
@ -272,6 +272,33 @@ gimp_symmetry_real_update_version (GimpSymmetry *symmetry)
|
||||
|
||||
/***** Public Functions *****/
|
||||
|
||||
/**
|
||||
* gimp_symmetry_set_stateful:
|
||||
* @sym: the #GimpSymmetry
|
||||
* @stateful: whether the symmetry should be stateful or stateless.
|
||||
*
|
||||
* By default, symmetry is made stateless, which means in particular
|
||||
* that the size of points can change from one stroke to the next, and
|
||||
* in particular you cannot map the coordinates from a stroke to the
|
||||
* next. I.e. stroke N at time T+1 is not necessarily the continuation
|
||||
* of stroke N at time T.
|
||||
* To obtain corresponding strokes, stateful tools, such as MyPaint
|
||||
* brushes or the ink tool, need to run this function. They should reset
|
||||
* to stateless behavior once finished painting.
|
||||
*
|
||||
* One of the first consequence of being stateful is that the number of
|
||||
* strokes cannot be changed, so more strokes than possible on canvas
|
||||
* may be computed, and oppositely it will be possible to end up in
|
||||
* cases with missing strokes (e.g. a tiling, theoretically infinite,
|
||||
* won't be for the ink tool if one draws too far out of canvas).
|
||||
**/
|
||||
void
|
||||
gimp_symmetry_set_stateful (GimpSymmetry *symmetry,
|
||||
gboolean stateful)
|
||||
{
|
||||
symmetry->stateful = stateful;
|
||||
}
|
||||
|
||||
/**
|
||||
* gimp_symmetry_set_origin:
|
||||
* @sym: the #GimpSymmetry
|
||||
|
||||
@ -50,6 +50,7 @@ struct _GimpSymmetry
|
||||
gint version;
|
||||
|
||||
GList *strokes;
|
||||
gboolean stateful;
|
||||
};
|
||||
|
||||
struct _GimpSymmetryClass
|
||||
@ -74,6 +75,8 @@ struct _GimpSymmetryClass
|
||||
|
||||
GType gimp_symmetry_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void gimp_symmetry_set_stateful (GimpSymmetry *symmetry,
|
||||
gboolean stateful);
|
||||
void gimp_symmetry_set_origin (GimpSymmetry *symmetry,
|
||||
GimpDrawable *drawable,
|
||||
GimpCoords *origin);
|
||||
|
||||
@ -168,6 +168,7 @@ gimp_ink_paint (GimpPaintCore *paint_core,
|
||||
GimpContext *context = GIMP_CONTEXT (paint_options);
|
||||
GimpRGB foreground;
|
||||
|
||||
gimp_symmetry_set_stateful (sym, TRUE);
|
||||
gimp_context_get_foreground (context, &foreground);
|
||||
gimp_palettes_add_color_history (context->gimp,
|
||||
&foreground);
|
||||
@ -217,6 +218,7 @@ gimp_ink_paint (GimpPaintCore *paint_core,
|
||||
break;
|
||||
|
||||
case GIMP_PAINT_STATE_FINISH:
|
||||
gimp_symmetry_set_stateful (sym, FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,6 +212,7 @@ gimp_mybrush_core_paint (GimpPaintCore *paint_core,
|
||||
case GIMP_PAINT_STATE_INIT:
|
||||
gimp_context_get_foreground (context, &fg);
|
||||
gimp_palettes_add_color_history (context->gimp, &fg);
|
||||
gimp_symmetry_set_stateful (sym, TRUE);
|
||||
|
||||
mybrush->private->surface =
|
||||
gimp_mypaint_surface_new (gimp_drawable_get_buffer (drawable),
|
||||
@ -233,6 +234,7 @@ gimp_mybrush_core_paint (GimpPaintCore *paint_core,
|
||||
break;
|
||||
|
||||
case GIMP_PAINT_STATE_FINISH:
|
||||
gimp_symmetry_set_stateful (sym, FALSE);
|
||||
mypaint_surface_unref ((MyPaintSurface *) mybrush->private->surface);
|
||||
mybrush->private->surface = NULL;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user