diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_mask.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_mask.c | 111 |
1 files changed, 100 insertions, 11 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 6e0402fc6e0..05ffb80d8a1 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -25,6 +25,7 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" +#include "DNA_vec_types.h" #include "BLI_bitmap_draw_2d.h" #include "BLI_lasso_2d.h" @@ -99,6 +100,9 @@ typedef struct MaskTaskData { PaintMaskFloodMode mode; float value; float (*clip_planes_final)[4]; + + bool front_faces_only; + float view_normal[3]; } MaskTaskData; static void mask_flood_fill_task_cb(void *__restrict userdata, @@ -264,9 +268,15 @@ static void mask_box_select_task_cb(void *__restrict userdata, bool any_masked = false; bool redraw = false; + float vertex_normal[3]; + BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) { - if (is_effected(clip_planes_final, vi.co)) { + SCULPT_vertex_normal_get(data->ob->sculpt, vi.index, vertex_normal); + float dot = dot_v3v3(data->view_normal, vertex_normal); + const bool is_effected_front_face = !(data->front_faces_only && dot < 0.0f); + + if (is_effected_front_face && is_effected(clip_planes_final, vi.co)) { float prevmask = *vi.mask; if (!any_masked) { any_masked = true; @@ -290,27 +300,33 @@ static void mask_box_select_task_cb(void *__restrict userdata, } } -bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *rect, bool select) +static int paint_mask_gesture_box_exec(bContext *C, wmOperator *op) { + ViewContext vc; Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Sculpt *sd = vc->scene->toolsettings->sculpt; + ED_view3d_viewcontext_init(C, &vc, depsgraph); + + Sculpt *sd = vc.scene->toolsettings->sculpt; BoundBox bb; float clip_planes[4][4]; float clip_planes_final[4][4]; - ARegion *region = vc->region; - Object *ob = vc->obact; - PaintMaskFloodMode mode; + ARegion *region = vc.region; + Object *ob = vc.obact; bool multires; PBVH *pbvh; PBVHNode **nodes; int totnode; int symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; - mode = PAINT_MASK_FLOOD_VALUE; - float value = select ? 1.0f : 0.0f; + const PaintMaskFloodMode mode = RNA_enum_get(op->ptr, "mode"); + const float value = RNA_float_get(op->ptr, "value"); + const bool front_faces_only = RNA_boolean_get(op->ptr, "use_front_faces_only"); + + rcti rect; + WM_operator_properties_border_to_rcti(op, &rect); /* Transform the clip planes in object space. */ - ED_view3d_clipping_calc(&bb, clip_planes, vc->region, vc->obact, rect); + ED_view3d_clipping_calc(&bb, clip_planes, vc.region, vc.obact, &rect); BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true, false); pbvh = ob->sculpt->pbvh; @@ -318,6 +334,16 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti * SCULPT_undo_push_begin("Mask box fill"); + /* Calculate the view normal in object space. */ + float mat[3][3]; + float view_dir[3] = {0.0f, 0.0f, 1.0f}; + float true_view_normal[3]; + copy_m3_m4(mat, vc.rv3d->viewinv); + mul_m3_v3(mat, view_dir); + copy_m3_m4(mat, ob->imat); + mul_m3_v3(mat, view_dir); + normalize_v3_v3(true_view_normal, view_dir); + for (int symmpass = 0; symmpass <= symm; symmpass++) { if (symmpass == 0 || (symm & symmpass && (symm != 5 || symmpass != 3) && (symm != 6 || (symmpass != 3 && symmpass != 5)))) { @@ -340,8 +366,11 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti * .mode = mode, .value = value, .clip_planes_final = clip_planes_final, + .front_faces_only = front_faces_only, }; + flip_v3_v3(data.view_normal, true_view_normal, symmpass); + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings); @@ -383,7 +412,7 @@ typedef struct LassoMaskData { * Lasso select. This could be defined as part of #VIEW3D_OT_select_lasso, * still the shortcuts conflict, so we will use a separate operator. */ -static bool is_effected_lasso(LassoMaskData *data, float co[3]) +static bool is_effected_lasso(LassoMaskData *data, const float co[3]) { float scr_co_f[2]; int scr_co_s[2]; @@ -433,9 +462,15 @@ static void mask_gesture_lasso_task_cb(void *__restrict userdata, PBVHVertexIter vi; bool any_masked = false; + float vertex_normal[3]; + BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) { - if (is_effected_lasso(lasso_data, vi.co)) { + SCULPT_vertex_normal_get(data->ob->sculpt, vi.index, vertex_normal); + float dot = dot_v3v3(lasso_data->task_data.view_normal, vertex_normal); + const bool is_effected_front_face = !(data->front_faces_only && dot < 0.0f); + + if (is_effected_front_face && is_effected_lasso(lasso_data, vi.co)) { if (!any_masked) { any_masked = true; @@ -473,6 +508,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) bool multires; PaintMaskFloodMode mode = RNA_enum_get(op->ptr, "mode"); float value = RNA_float_get(op->ptr, "value"); + const bool front_faces_only = RNA_boolean_get(op->ptr, "use_front_faces_only"); /* Calculations of individual vertices are done in 2D screen space to diminish the amount of * calculations done. Bounding box PBVH collision is not computed against enclosing rectangle @@ -505,6 +541,16 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) SCULPT_undo_push_begin("Mask lasso fill"); + /* Calculate the view normal in object space. */ + float mat[3][3]; + float view_dir[3] = {0.0f, 0.0f, 1.0f}; + float true_view_normal[3]; + copy_m3_m4(mat, vc.rv3d->viewinv); + mul_m3_v3(mat, view_dir); + copy_m3_m4(mat, ob->imat); + mul_m3_v3(mat, view_dir); + normalize_v3_v3(true_view_normal, view_dir); + for (int symmpass = 0; symmpass <= symm; symmpass++) { if ((symmpass == 0) || (symm & symmpass && (symm != 5 || symmpass != 3) && (symm != 6 || (symmpass != 3 && symmpass != 5)))) { @@ -514,6 +560,8 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) flip_plane(clip_planes_final[j], clip_planes[j], symmpass); } + flip_v3_v3(data.task_data.view_normal, true_view_normal, symmpass); + data.symmpass = symmpass; /* Gather nodes inside lasso's enclosing rectangle @@ -530,6 +578,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) data.task_data.multires = multires; data.task_data.mode = mode; data.task_data.value = value; + data.task_data.front_faces_only = front_faces_only; TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); @@ -588,4 +637,44 @@ void PAINT_OT_mask_lasso_gesture(wmOperatorType *ot) "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked", 0.0f, 1.0f); + RNA_def_boolean(ot->srna, + "use_front_faces_only", + false, + "Front Faces Only", + "Affect only faces facing towards the view"); +} + +void PAINT_OT_mask_box_gesture(wmOperatorType *ot) +{ + ot->name = "Mask Box Gesture"; + ot->idname = "PAINT_OT_mask_box_gesture"; + ot->description = "Add mask within the box as you move the brush"; + + ot->invoke = WM_gesture_box_invoke; + ot->modal = WM_gesture_box_modal; + ot->exec = paint_mask_gesture_box_exec; + + ot->poll = SCULPT_mode_poll; + + ot->flag = OPTYPE_REGISTER; + + /* Properties. */ + WM_operator_properties_border(ot); + + RNA_def_enum(ot->srna, "mode", mode_items, PAINT_MASK_FLOOD_VALUE, "Mode", NULL); + RNA_def_float( + ot->srna, + "value", + 1.0f, + 0.0f, + 1.0f, + "Value", + "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked", + 0.0f, + 1.0f); + RNA_def_boolean(ot->srna, + "use_front_faces_only", + false, + "Front Faces Only", + "Affect only faces facing towards the view"); } |