Image painting 2D:

Deprecate wrap (BRUSH_TORUS) option, we now have paint flags for tiling
and we can reuse those. Also allows seperate tiling in X/Y
direction for 2D painting now.

Only one tiling is allowed for now.

Options can be found in new "Tiling" panel under the tools tab.

For version patching, we just turn off brush wrapping,
to allow reuse of the flag in the future.
New option is paint mode wide instead of per brush so
a brush having the old wrap option will not enable it
for the whole mode in the version patch.
This commit is contained in:
Antonis Ryakiotakis 2015-07-27 12:55:40 +02:00
parent e355d557f8
commit ba146899c8
7 changed files with 90 additions and 53 deletions

View File

@ -920,6 +920,24 @@ class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel):
row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
class VIEW3D_PT_tools_imagepaint_symmetry(BrushButtonsPanel, Panel):
bl_category = "Tools"
bl_context = "imagepaint"
bl_label = "Tiling"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
toolsettings = context.tool_settings
ipaint = toolsettings.image_paint
col = layout.column(align=True)
row = col.row(align=True)
row.prop(ipaint, "tile_x", text="X", toggle=True)
row.prop(ipaint, "tile_y", text="Y", toggle=True)
class IMAGE_PT_tools_brush_appearance(BrushButtonsPanel, Panel):
bl_label = "Appearance"
bl_options = {'DEFAULT_CLOSED'}
@ -963,10 +981,6 @@ class IMAGE_PT_tools_paint_options(BrushButtonsPanel, Panel):
ups = toolsettings.unified_paint_settings
col = layout.column(align=True)
col.prop(brush, "use_wrap")
col.separator()
col.label(text="Unified Settings:")
row = col.row()
row.prop(ups, "use_unified_size", text="Size")

View File

@ -42,7 +42,7 @@ extern "C" {
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 275
#define BLENDER_SUBVERSION 2
#define BLENDER_SUBVERSION 3
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 5

View File

@ -297,7 +297,6 @@ void BKE_brush_debug_print_state(Brush *br)
/* br->flag */
BR_TEST_FLAG(BRUSH_AIRBRUSH);
BR_TEST_FLAG(BRUSH_TORUS);
BR_TEST_FLAG(BRUSH_ALPHA_PRESSURE);
BR_TEST_FLAG(BRUSH_SIZE_PRESSURE);
BR_TEST_FLAG(BRUSH_JITTER_PRESSURE);

View File

@ -842,4 +842,13 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
if (!MAIN_VERSION_ATLEAST(main, 275, 3)) {
Brush *br;
#define BRUSH_TORUS (1 << 1)
for (br = main->brush.first; br; br = br->id.next) {
br->flag &= ~BRUSH_TORUS;
}
#undef BRUSH_TORUS
}
}

View File

@ -139,6 +139,7 @@ typedef struct ImagePaintState {
int faceindex;
float uv[2];
int do_facesel;
int symmetry;
bool need_redraw;
@ -770,15 +771,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *pai
}
/* keep these functions in sync */
static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, const bool is_torus, float r_rgb[4])
static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, float r_rgb[4])
{
if (is_torus) {
x %= ibuf->x;
if (x < 0) x += ibuf->x;
y %= ibuf->y;
if (y < 0) y += ibuf->y;
}
if (ibuf->rect_float) {
const float *rrgbf = ibuf->rect_float + (ibuf->x * y + x) * 4;
copy_v4_v4(r_rgb, rrgbf);
@ -814,18 +808,30 @@ static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus
}
}
static float paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus, float w)
static void paint_2d_ibuf_tile_convert(ImBuf *ibuf, int *x, int *y, short tile)
{
if (tile & PAINT_TILE_X) {
*x %= ibuf->x;
if (*x < 0) *x += ibuf->x;
}
if (tile & PAINT_TILE_Y) {
*y %= ibuf->y;
if (*y < 0) *y += ibuf->y;
}
}
static float paint_2d_ibuf_add_if(ImBuf *ibuf, int x, int y, float *outrgb, short tile, float w)
{
float inrgb[4];
// XXX: signed unsigned mismatch
if ((x >= (unsigned int)(ibuf->x)) || (y >= (unsigned int)(ibuf->y))) {
if (torus) paint_2d_ibuf_rgb_get(ibuf, x, y, 1, inrgb);
else return 0;
}
else {
paint_2d_ibuf_rgb_get(ibuf, x, y, 0, inrgb);
if (tile) paint_2d_ibuf_tile_convert(ibuf, &x, &y, tile);
/* need to also do clipping here always since tiled coordinates
* are not always within bounds */
if (x < ibuf->x && x >= 0 && y < ibuf->y && y >= 0) {
paint_2d_ibuf_rgb_get(ibuf, x, y, inrgb);
}
else return 0;
mul_v4_fl(inrgb, w);
add_v4_v4(outrgb, inrgb);
@ -833,7 +839,7 @@ static float paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, f
return w;
}
static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short is_torus)
static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short tile)
{
bool sharpen = (s->painter->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
float threshold = s->brush->sharp_threshold;
@ -851,7 +857,7 @@ static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb,
in_off[1] = pos[1];
out_off[0] = out_off[1] = 0;
if (!is_torus) {
if (!tile) {
IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
&out_off[1], &dim[0], &dim[1]);
@ -869,13 +875,23 @@ static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb,
yi = in_off[1] + y;
count = 0.0;
paint_2d_ibuf_rgb_get(ibuf, xi, yi, is_torus, rgba);
if (tile) {
paint_2d_ibuf_tile_convert(ibuf, &xi, &yi, tile);
if (xi < ibuf->x && xi >= 0 && yi < ibuf->y && yi >= 0)
paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
else
zero_v4(rgba);
}
else {
/* coordinates have been clipped properly here, it should be safe to do this */
paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
}
zero_v4(outrgb);
for (yk = 0; yk < kernel->side; yk++) {
for (xk = 0; xk < kernel->side; xk++) {
count += paint_2d_ibuf_add_if(ibuf, xi + xk - kernel->pixel_len,
yi + yk - kernel->pixel_len, outrgb, is_torus,
yi + yk - kernel->pixel_len, outrgb, tile,
kernel->wdata[xk + yk * kernel->side]);
}
}
@ -923,7 +939,7 @@ static void paint_2d_set_region(ImagePaintRegion *region, int destx, int desty,
region->height = height;
}
static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf)
static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf, ImBuf *sbuf, short tile)
{
int destx = region->destx;
int desty = region->desty;
@ -934,15 +950,18 @@ static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf,
int origw, origh, w, h, tot = 0;
/* convert destination and source coordinates to be within image */
destx = destx % dbuf->x;
if (destx < 0) destx += dbuf->x;
desty = desty % dbuf->y;
if (desty < 0) desty += dbuf->y;
srcx = srcx % sbuf->x;
if (srcx < 0) srcx += sbuf->x;
srcy = srcy % sbuf->y;
if (srcy < 0) srcy += sbuf->y;
if (tile & PAINT_TILE_X) {
destx = destx % dbuf->x;
if (destx < 0) destx += dbuf->x;
srcx = srcx % sbuf->x;
if (srcx < 0) srcx += sbuf->x;
}
if (tile & PAINT_TILE_Y) {
desty = desty % dbuf->y;
if (desty < 0) desty += dbuf->y;
srcy = srcy % sbuf->y;
if (srcy < 0) srcy += sbuf->y;
}
/* clip width of blending area to destination imbuf, to avoid writing the
* same pixel twice */
origw = w = (width > dbuf->x) ? dbuf->x : width;
@ -953,23 +972,23 @@ static int paint_2d_torus_split_region(ImagePaintRegion region[4], ImBuf *dbuf,
paint_2d_set_region(&region[tot++], destx, desty, srcx, srcy, w, h);
/* do 3 other rects if needed */
if (w < origw)
if ((tile & PAINT_TILE_X) && w < origw)
paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, desty, (srcx + w) % sbuf->x, srcy, origw - w, h);
if (h < origh)
if ((tile & PAINT_TILE_Y) && h < origh)
paint_2d_set_region(&region[tot++], destx, (desty + h) % dbuf->y, srcx, (srcy + h) % sbuf->y, w, origh - h);
if ((w < origw) && (h < origh))
if ((tile & PAINT_TILE_X) && (tile & PAINT_TILE_Y) && (w < origw) && (h < origh))
paint_2d_set_region(&region[tot++], (destx + w) % dbuf->x, (desty + h) % dbuf->y, (srcx + w) % sbuf->x, (srcy + h) % sbuf->y, origw - w, origh - h);
return tot;
}
static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos)
static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos, short tile)
{
ImagePaintRegion region[4];
int a, tot;
paint_2d_set_region(region, 0, 0, pos[0], pos[1], ibufb->x, ibufb->y);
tot = paint_2d_torus_split_region(region, ibufb, ibuf);
tot = paint_2d_torus_split_region(region, ibufb, ibuf, tile);
for (a = 0; a < tot; a++)
IMB_rectblend(ibufb, ibufb, ibuf, NULL, NULL, NULL, 0, region[a].destx, region[a].desty,
@ -1005,7 +1024,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign
ImagePaintState *s = ((ImagePaintState *)state);
ImBuf *clonebuf = NULL, *frombuf;
ImagePaintRegion region[4];
short torus = s->brush->flag & BRUSH_TORUS;
short tile = s->symmetry & (PAINT_TILE_X | PAINT_TILE_Y);
short blend = s->blend;
const float *offset = s->brush->clone.offset;
float liftpos[2];
@ -1017,14 +1036,14 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign
/* lift from canvas */
if (s->tool == PAINT_TOOL_SOFTEN) {
paint_2d_lift_soften(s, s->canvas, ibufb, bpos, torus);
paint_2d_lift_soften(s, s->canvas, ibufb, bpos, tile);
}
else if (s->tool == PAINT_TOOL_SMEAR) {
if (lastpos[0] == pos[0] && lastpos[1] == pos[1])
return 0;
paint_2d_convert_brushco(ibufb, lastpos, blastpos);
paint_2d_lift_smear(s->canvas, ibufb, blastpos);
paint_2d_lift_smear(s->canvas, ibufb, blastpos, tile);
}
else if (s->tool == PAINT_TOOL_CLONE && s->clonecanvas) {
liftpos[0] = pos[0] - offset[0] * s->canvas->x;
@ -1036,9 +1055,9 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsign
frombuf = (clonebuf) ? clonebuf : ibufb;
if (torus) {
if (tile) {
paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
tot = paint_2d_torus_split_region(region, s->canvas, frombuf);
tot = paint_2d_torus_split_region(region, s->canvas, frombuf, tile);
}
else {
paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
@ -1234,6 +1253,7 @@ void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode)
s->blend = brush->blend;
s->image = s->sima->image;
s->symmetry = settings->imapaint.paint.symmetry_flags;
if (!paint_2d_canvas_set(s, s->image)) {
if (s->warnmultifile)

View File

@ -181,7 +181,7 @@ typedef enum BrushGradientSourceFill {
/* Brush.flag */
typedef enum BrushFlags {
BRUSH_AIRBRUSH = (1 << 0),
BRUSH_TORUS = (1 << 1),
// BRUSH_TORUS = (1 << 1), deprecated, use paint->symmetry_flags & PAINT_TILE_*
BRUSH_ALPHA_PRESSURE = (1 << 2),
BRUSH_SIZE_PRESSURE = (1 << 3),
BRUSH_JITTER_PRESSURE = (1 << 4),

View File

@ -1102,12 +1102,7 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Original Normal",
"When locked keep using normal of surface where stroke was initiated");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "use_wrap", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_TORUS);
RNA_def_property_ui_text(prop, "Wrap", "Enable torus wrapping while painting");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop = RNA_def_property(srna, "use_pressure_strength", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ALPHA_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);