Mask brush implementation:

* Users can now select/create a mask brush to directly interact with the
stencil. This acts similarly to a paint brush, however only the mask
texture is relevant and the brush uses a Mask value to paint.

* Also, now inverted mask layer is correctly displayed.
This commit is contained in:
2014-04-26 01:24:45 +03:00
parent 7e62314aed
commit d5a64694e6
4 changed files with 98 additions and 29 deletions

View File

@@ -997,11 +997,6 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
col = layout.column()
if capabilities.has_radius:
row = col.row(align=True)
self.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
self.prop_unified_size(row, context, brush, "use_pressure_size")
if brush.image_tool == 'SOFTEN':
col = layout.column(align=True)
col.row().prop(brush, "direction", expand=True)
@@ -1011,6 +1006,14 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
col.separator()
col.prop(brush, "blur_mode")
if brush.image_tool == 'MASK':
col.prop(brush, "weight", text="Mask Value", slider=True)
if capabilities.has_radius:
row = col.row(align=True)
self.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
self.prop_unified_size(row, context, brush, "use_pressure_size")
row = col.row(align=True)
if capabilities.has_space_attenuation:

View File

@@ -257,6 +257,7 @@ typedef struct ProjPaintState {
bool do_layer_clone;
bool do_layer_stencil;
bool do_layer_stencil_inv;
bool do_stencil_brush;
bool do_occlude; /* Use raytraced occlusion? - ortherwise will paint right through to the back*/
bool do_backfacecull; /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */
@@ -358,6 +359,19 @@ static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int
return &ma->texpaintslot[ma->paint_active_slot];
}
static Image *project_paint_face_paint_image(const ProjPaintState *ps, int face_index)
{
if (ps->do_stencil_brush) {
return ps->stencil_ima;
}
else {
MFace *mf = ps->dm_mface + face_index;
Material *ma = ps->dm->mat[mf->mat_nr];
return ma->texpaintslot[ma->paint_active_slot].ima;
}
}
static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int face_index)
{
MFace *mf = ps->dm_mface + face_index;
@@ -540,7 +554,7 @@ static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2],
interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[2], tf->uv[3], w);
}
ima = project_paint_face_paint_slot(ps, face_index)->ima;
ima = project_paint_face_paint_image(ps, face_index);
ibuf = BKE_image_get_first_ibuf(ima); /* we must have got the imbuf before getting here */
if (!ibuf) return 0;
@@ -902,8 +916,8 @@ static bool check_seam(const ProjPaintState *ps,
/* Only need to check if 'i2_fidx' is valid because we know i1_fidx is the same vert on both faces */
if (i2_fidx != -1) {
Image *tpage = project_paint_face_paint_slot(ps, face_index)->ima;
Image *orig_tpage = project_paint_face_paint_slot(ps, orig_face)->ima;
Image *tpage = project_paint_face_paint_image(ps, face_index);
Image *orig_tpage = project_paint_face_paint_image(ps, orig_face);
BLI_assert(i1_fidx != -1);
@@ -2738,7 +2752,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
face_index = GET_INT_FROM_POINTER(node->link);
/* Image context switching */
tpage = project_paint_face_paint_slot(ps, face_index)->ima;
tpage = project_paint_face_paint_image(ps, face_index);
if (tpage_last != tpage) {
tpage_last = tpage;
@@ -2906,7 +2920,7 @@ static void project_paint_begin(ProjPaintState *ps)
ProjPaintImage *projIma;
Image *tpage_last = NULL, *tpage;
TexPaintSlot *slot_last = NULL, *slot;
TexPaintSlot *slot_last = NULL, *slot = NULL;
TexPaintSlot *slot_last_clone = NULL, *slot_clone;
/* Face vars */
@@ -2999,16 +3013,19 @@ static void project_paint_begin(ProjPaintState *ps)
ps->dm_mtface_clone = MEM_mallocN(ps->dm_totface * sizeof (MTFace *), "proj_paint_mtfaces");
}
if (ps->do_layer_stencil) {
if (ps->do_layer_stencil || ps->do_stencil_brush) {
//int layer_num = CustomData_get_stencil_layer(&ps->dm->faceData, CD_MTFACE);
int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY);
if (layer_num != -1)
ps->dm_mtface_stencil = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
if (ps->dm_mtface_stencil == NULL) {
ps->do_layer_stencil = false;
ps->dm_mtface_stencil = NULL;
/* get active instead */
ps->dm_mtface_stencil = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
}
if (ps->do_stencil_brush)
tf_base = ps->dm_mtface_stencil;
}
/* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
@@ -3283,21 +3300,23 @@ static void project_paint_begin(ProjPaintState *ps)
is_face_sel = true;
}
slot = project_paint_face_paint_slot(ps, face_index);
/* all faces should have a valid slot, reassert here */
if (slot == NULL)
continue;
if (!ps->do_stencil_brush) {
slot = project_paint_face_paint_slot(ps, face_index);
/* all faces should have a valid slot, reassert here */
if (slot == NULL)
continue;
if (slot != slot_last) {
if (!slot->uvname[0] || !(tf_base = CustomData_get_layer_named(&ps->dm->faceData, CD_MTFACE, slot->uvname)))
tf_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
slot_last = slot;
if (slot != slot_last) {
if (!slot->uvname[0] || !(tf_base = CustomData_get_layer_named(&ps->dm->faceData, CD_MTFACE, slot->uvname)))
tf_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
slot_last = slot;
}
/* don't allow using the same inage for painting and stencilling */
if (slot->ima == ps->stencil_ima)
continue;
}
/* don't allow using the same inage for painting and stencilling */
if (slot->ima == ps->stencil_ima)
continue;
*tf = tf_base + face_index;
if (ps->do_layer_clone) {
@@ -3320,7 +3339,7 @@ static void project_paint_begin(ProjPaintState *ps)
/* tfbase here should be non-null! */
BLI_assert (tf_base != NULL);
if (is_face_sel && ((slot && (tpage = slot->ima)) || (tpage = project_paint_face_paint_slot(ps, face_index)->ima))) {
if (is_face_sel && ((slot && (tpage = slot->ima)) || (tpage = project_paint_face_paint_image(ps, face_index)))) {
float *v1coSS, *v2coSS, *v3coSS, *v4coSS = NULL;
v1coSS = ps->screenCoords[mf->v1];
@@ -3898,6 +3917,35 @@ static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, con
}
}
static void do_projectpaint_mask(ProjPaintState *ps, ProjPixel *projPixel, float mask)
{
unsigned char rgba_ub[4];
rgba_ub[0] = rgba_ub[1] = rgba_ub[2] = ps->brush->weight * 255.0;
rgba_ub[3] = f_to_char(mask);
if (ps->do_masking) {
IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend);
}
else {
IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend);
}
}
static void do_projectpaint_mask_f(ProjPaintState *ps, ProjPixel *projPixel, float mask)
{
float rgba[4];
rgba[0] = rgba[1] = rgba[2] = ps->brush->weight;
rgba[3] = mask;
if (ps->do_masking) {
IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend);
}
else {
IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend);
}
}
/* run this for single and multithreaded painting */
static void *do_projectpaint_thread(void *ph_v)
{
@@ -4203,6 +4251,10 @@ static void *do_projectpaint_thread(void *ph_v)
if (is_floatbuf) do_projectpaint_soften_f(ps, projPixel, mask, softenArena, &softenPixels_f);
else do_projectpaint_soften(ps, projPixel, mask, softenArena, &softenPixels);
break;
case PAINT_TOOL_MASK:
if (is_floatbuf) do_projectpaint_mask_f(ps, projPixel, mask);
else do_projectpaint_mask(ps, projPixel, mask);
break;
default:
if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, texrgb, mask);
else do_projectpaint_draw(ps, projPixel, texrgb, mask);
@@ -4432,7 +4484,9 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
if (ps->tool == PAINT_TOOL_CLONE)
ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) ? 1 : 0;
ps->do_layer_stencil = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? 1 : 0;
ps->do_stencil_brush = ps->brush->imagepaint_tool == PAINT_TOOL_MASK;
/* deactivate stenciling for the stencil brush :) */
ps->do_layer_stencil = ((settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) && !(ps->do_stencil_brush)) ? 1 : 0;
ps->do_layer_stencil_inv = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) ? 1 : 0;

View File

@@ -217,12 +217,13 @@ static Material *give_current_material_or_def(Object *ob, int matnr)
static struct TextureDrawState {
Object *ob;
Image *stencil;
bool stencil_invert;
bool use_game_mat;
int is_lit, is_tex;
int color_profile;
bool use_backface_culling;
unsigned char obcol[4];
} Gtexdraw = {NULL, NULL, false, 0, 0, 0, false, {0, 0, 0, 0}};
} Gtexdraw = {NULL, NULL, false, false, 0, 0, 0, false, {0, 0, 0, 0}};
static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *ma, struct TextureDrawState gtexdraw)
{
@@ -258,6 +259,9 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
if (!Gtexdraw.stencil_invert) {
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
}
}
glActiveTexture(GL_TEXTURE0);
}
@@ -394,6 +398,7 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
Gtexdraw.ob = ob;
Gtexdraw.stencil = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? imapaint->stencil : NULL;
Gtexdraw.stencil_invert = ((imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0);
Gtexdraw.is_tex = is_tex;
Gtexdraw.color_profile = BKE_scene_check_color_management_enabled(scene);
@@ -415,6 +420,7 @@ static void draw_textured_end(void)
if(Gtexdraw.ob->mode & OB_MODE_TEXTURE_PAINT) {
glActiveTexture(GL_TEXTURE1);
GPU_set_tpage(NULL, 0, 0);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);

View File

@@ -285,6 +285,12 @@ static void rna_Paint_brush_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
BKE_paint_invalidate_overlay_all();
WM_main_add_notifier(NC_BRUSH | NA_EDITED, br);
}
static void rna_ImaPaint_stencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
/* not the best solution maybe, but will refresh the 3D viewport */
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
}
#else
static void rna_def_palettecolor(BlenderRNA *brna)
@@ -591,7 +597,7 @@ static void rna_def_image_paint(BlenderRNA *brna)
prop = RNA_def_property(srna, "invert_stencil", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMAGEPAINT_PROJECT_LAYER_STENCIL_INV);
RNA_def_property_ui_text(prop, "Invert", "Invert the stencil layer");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_stencil_update");
prop = RNA_def_property(srna, "stencil_image", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "stencil");