So I had this helper function that wraps values into a range and I was wondering, if it works for repeated patterns, too. And indeed, it does:
It’s extremely similar to the symmetry implementation. But first no matter where the user draws, the position gets wrapped into a range from 0.0 to patternsize. Then comes a for loop and draws the dab nine times at once with an offset of patternsize (surprise: this impacts performance)…
mypaint-tiled-surface.c, line 606:
// Pattern pass
if(self->surface_do_pattern){
const int p_Xsize = self->surface_pattern_X_size;
const int p_Ysize = self->surface_pattern_Y_size;
// no matter where the user draws, the dabs will land in a range of 0.0 to size
x = circular_wrap(x,p_Xsize); // circular_wrap() in helpers.c from pigmentblending-test branch
y = circular_wrap(y,p_Ysize);
for (int i = 0; i <= p_Xsize*2; i= i + p_Xsize) {
for (int j = 0; j <= p_Ysize*2; j= j + p_Ysize) {
if(draw_dab_internal(self, x + i, y + j, radius, color_r, color_g, color_b,
opaque, hardness, color_a, aspect_ratio, angle,
lock_alpha, colorize)) {
surface_modified = TRUE;
}
}
}
} else
// Normal pass
if (draw_dab_internal(self, x, y, radius, color_r, color_g, color_b,
opaque, hardness, color_a, aspect_ratio, angle,
lock_alpha, colorize)) {
surface_modified = TRUE;
}
// Symmetry pass
if(self->surface_do_symmetry) {
const float symm_x = self->surface_center_x + (self->surface_center_x - x);
if (draw_dab_internal(self, symm_x, y, radius, color_r, color_g, color_b,
opaque, hardness, color_a, aspect_ratio, -angle,
lock_alpha, colorize)) {
surface_modified = TRUE;
}
}
Plus a few more lines to set it all up, just like symmetry. See git:
This already works “okay” for development with hardcoded values and manual export using the frame with the same values as patternsize. But what it really needs is a GUI. I did have the simple, minimalistic idea to connect it to the frame. However I’m completely lost in that whole GUI code, tried to figure out how symmetry or the frame work, how the values get pulled and pushed from gui to brushengine. I’m still confused…
This may not be the most intuitive solution, but at least it doesn’t need extra menus/windows/overlays. Three new elements in the frame options: Headline “Seamless Pattern”, Active Checkbox, Button to Set patternsize from Frame. When the Button is hit, two things should happen: First the pattern x & y sizes get set to the frame size, second the frame moves in the middle of the pattern, which should be x = x-size (of frame&pattern), y = y-size (of frame&pattern)… Top left corner of the top left pattern “tile” sits at 0,0.
Things that suck: Performance could be better, maybe if the 9x drawing of the same dab is moved further into draw_dab_internal or something. Drawing next to the covered area picks up transparency when smudging. And it would be a lot more awesome if the pattern covers a bigger area - Maybe instead of actually drawing multiple dabs, it might be possible to just render the same area multiple times…