diff options
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_mask.c')
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_mask.c | 795 |
1 files changed, 410 insertions, 385 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index b88ae861229..ca48030daed 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -60,478 +60,503 @@ #include <stdlib.h> static const EnumPropertyItem mode_items[] = { - {PAINT_MASK_FLOOD_VALUE, "VALUE", 0, "Value", "Set mask to the level specified by the 'value' property"}, - {PAINT_MASK_FLOOD_VALUE_INVERSE, "VALUE_INVERSE", 0, "Value Inverted", "Set mask to the level specified by the inverted 'value' property"}, - {PAINT_MASK_INVERT, "INVERT", 0, "Invert", "Invert the mask"}, - {0}}; - - -static void mask_flood_fill_set_elem( - float *elem, - PaintMaskFloodMode mode, - float value) + {PAINT_MASK_FLOOD_VALUE, + "VALUE", + 0, + "Value", + "Set mask to the level specified by the 'value' property"}, + {PAINT_MASK_FLOOD_VALUE_INVERSE, + "VALUE_INVERSE", + 0, + "Value Inverted", + "Set mask to the level specified by the inverted 'value' property"}, + {PAINT_MASK_INVERT, "INVERT", 0, "Invert", "Invert the mask"}, + {0}}; + +static void mask_flood_fill_set_elem(float *elem, PaintMaskFloodMode mode, float value) { - switch (mode) { - case PAINT_MASK_FLOOD_VALUE: - (*elem) = value; - break; - case PAINT_MASK_FLOOD_VALUE_INVERSE: - (*elem) = 1.0f - value; - break; - case PAINT_MASK_INVERT: - (*elem) = 1.0f - (*elem); - break; - } + switch (mode) { + case PAINT_MASK_FLOOD_VALUE: + (*elem) = value; + break; + case PAINT_MASK_FLOOD_VALUE_INVERSE: + (*elem) = 1.0f - value; + break; + case PAINT_MASK_INVERT: + (*elem) = 1.0f - (*elem); + break; + } } typedef struct MaskTaskData { - Object *ob; - PBVH *pbvh; - PBVHNode **nodes; - bool multires; - - PaintMaskFloodMode mode; - float value; - float (*clip_planes_final)[4]; + Object *ob; + PBVH *pbvh; + PBVHNode **nodes; + bool multires; + + PaintMaskFloodMode mode; + float value; + float (*clip_planes_final)[4]; } MaskTaskData; -static void mask_flood_fill_task_cb( - void *__restrict userdata, - const int i, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void mask_flood_fill_task_cb(void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - MaskTaskData *data = userdata; + MaskTaskData *data = userdata; - PBVHNode *node = data->nodes[i]; + PBVHNode *node = data->nodes[i]; - const PaintMaskFloodMode mode = data->mode; - const float value = data->value; + const PaintMaskFloodMode mode = data->mode; + const float value = data->value; - PBVHVertexIter vi; + PBVHVertexIter vi; - sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK); + sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK); - BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) { - mask_flood_fill_set_elem(vi.mask, mode, value); - } BKE_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) + { + mask_flood_fill_set_elem(vi.mask, mode, value); + } + BKE_pbvh_vertex_iter_end; - BKE_pbvh_node_mark_redraw(node); - if (data->multires) - BKE_pbvh_node_mark_normals_update(node); + BKE_pbvh_node_mark_redraw(node); + if (data->multires) + BKE_pbvh_node_mark_normals_update(node); } static int mask_flood_fill_exec(bContext *C, wmOperator *op) { - ARegion *ar = CTX_wm_region(C); - struct Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - PaintMaskFloodMode mode; - float value; - PBVH *pbvh; - PBVHNode **nodes; - int totnode; - bool multires; - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + ARegion *ar = CTX_wm_region(C); + struct Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + PaintMaskFloodMode mode; + float value; + PBVH *pbvh; + PBVHNode **nodes; + int totnode; + bool multires; + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - mode = RNA_enum_get(op->ptr, "mode"); - value = RNA_float_get(op->ptr, "value"); + mode = RNA_enum_get(op->ptr, "mode"); + value = RNA_float_get(op->ptr, "value"); - BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, true); - pbvh = ob->sculpt->pbvh; - multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS); + BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, true); + pbvh = ob->sculpt->pbvh; + multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS); - BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); + BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); - sculpt_undo_push_begin("Mask flood fill"); + sculpt_undo_push_begin("Mask flood fill"); - MaskTaskData data = { - .ob = ob, .pbvh = pbvh, .nodes = nodes, .multires = multires, - .mode = mode, .value = value, - }; + MaskTaskData data = { + .ob = ob, + .pbvh = pbvh, + .nodes = nodes, + .multires = multires, + .mode = mode, + .value = value, + }; - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range( + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range( - 0, totnode, &data, mask_flood_fill_task_cb, - &settings); + 0, totnode, &data, mask_flood_fill_task_cb, &settings); - if (multires) - multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); + if (multires) + multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); - sculpt_undo_push_end(); + sculpt_undo_push_end(); - if (nodes) - MEM_freeN(nodes); + if (nodes) + MEM_freeN(nodes); - ED_region_tag_redraw(ar); + ED_region_tag_redraw(ar); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void PAINT_OT_mask_flood_fill(struct wmOperatorType *ot) { - /* identifiers */ - ot->name = "Mask Flood Fill"; - ot->idname = "PAINT_OT_mask_flood_fill"; - ot->description = "Fill the whole mask with a given value, or invert its values"; - - /* api callbacks */ - ot->exec = mask_flood_fill_exec; - ot->poll = sculpt_mode_poll; - - ot->flag = OPTYPE_REGISTER; - - /* rna */ - RNA_def_enum(ot->srna, "mode", mode_items, PAINT_MASK_FLOOD_VALUE, "Mode", NULL); - RNA_def_float(ot->srna, "value", 0, 0, 1, "Value", - "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked", 0, 1); + /* identifiers */ + ot->name = "Mask Flood Fill"; + ot->idname = "PAINT_OT_mask_flood_fill"; + ot->description = "Fill the whole mask with a given value, or invert its values"; + + /* api callbacks */ + ot->exec = mask_flood_fill_exec; + ot->poll = sculpt_mode_poll; + + ot->flag = OPTYPE_REGISTER; + + /* rna */ + RNA_def_enum(ot->srna, "mode", mode_items, PAINT_MASK_FLOOD_VALUE, "Mode", NULL); + RNA_def_float( + ot->srna, + "value", + 0, + 0, + 1, + "Value", + "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked", + 0, + 1); } /* Box select, operator is VIEW3D_OT_select_box, defined in view3d_select.c */ static bool is_effected(float planes[4][4], const float co[3]) { - return isect_point_planes_v3(planes, 4, co); + return isect_point_planes_v3(planes, 4, co); } static void flip_plane(float out[4], const float in[4], const char symm) { - if (symm & PAINT_SYMM_X) - out[0] = -in[0]; - else - out[0] = in[0]; - if (symm & PAINT_SYMM_Y) - out[1] = -in[1]; - else - out[1] = in[1]; - if (symm & PAINT_SYMM_Z) - out[2] = -in[2]; - else - out[2] = in[2]; - - out[3] = in[3]; + if (symm & PAINT_SYMM_X) + out[0] = -in[0]; + else + out[0] = in[0]; + if (symm & PAINT_SYMM_Y) + out[1] = -in[1]; + else + out[1] = in[1]; + if (symm & PAINT_SYMM_Z) + out[2] = -in[2]; + else + out[2] = in[2]; + + out[3] = in[3]; } -static void mask_box_select_task_cb( - void *__restrict userdata, - const int i, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void mask_box_select_task_cb(void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - MaskTaskData *data = userdata; + MaskTaskData *data = userdata; - PBVHNode *node = data->nodes[i]; + PBVHNode *node = data->nodes[i]; - const PaintMaskFloodMode mode = data->mode; - const float value = data->value; - float (*clip_planes_final)[4] = data->clip_planes_final; + const PaintMaskFloodMode mode = data->mode; + const float value = data->value; + float(*clip_planes_final)[4] = data->clip_planes_final; - PBVHVertexIter vi; - bool any_masked = false; + PBVHVertexIter vi; + bool any_masked = false; - BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) { - if (is_effected(clip_planes_final, vi.co)) { - if (!any_masked) { - any_masked = true; + BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) + { + if (is_effected(clip_planes_final, vi.co)) { + if (!any_masked) { + any_masked = true; - sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK); + sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK); - BKE_pbvh_node_mark_redraw(node); - if (data->multires) - BKE_pbvh_node_mark_normals_update(node); - } - mask_flood_fill_set_elem(vi.mask, mode, value); - } - } BKE_pbvh_vertex_iter_end; + BKE_pbvh_node_mark_redraw(node); + if (data->multires) + BKE_pbvh_node_mark_normals_update(node); + } + mask_flood_fill_set_elem(vi.mask, mode, value); + } + } + BKE_pbvh_vertex_iter_end; } bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *rect, bool select) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Sculpt *sd = vc->scene->toolsettings->sculpt; - BoundBox bb; - float clip_planes[4][4]; - float clip_planes_final[4][4]; - ARegion *ar = vc->ar; - struct Scene *scene = vc->scene; - Object *ob = vc->obact; - PaintMaskFloodMode mode; - float value; - bool multires; - PBVH *pbvh; - PBVHNode **nodes; - int totnode, symmpass; - int symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; - - mode = PAINT_MASK_FLOOD_VALUE; - value = select ? 1.0 : 0.0; - - /* transform the clip planes in object space */ - ED_view3d_clipping_calc(&bb, clip_planes, vc->ar, vc->obact, rect); - negate_m4(clip_planes); - - BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, true); - pbvh = ob->sculpt->pbvh; - multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS); - - sculpt_undo_push_begin("Mask box fill"); - - for (symmpass = 0; symmpass <= symm; ++symmpass) { - if (symmpass == 0 || - (symm & symmpass && - (symm != 5 || symmpass != 3) && - (symm != 6 || (symmpass != 3 && symmpass != 5)))) - { - int j = 0; - - /* flip the planes symmetrically as needed */ - for (; j < 4; j++) { - flip_plane(clip_planes_final[j], clip_planes[j], symmpass); - } - - BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode); - - MaskTaskData data = { - .ob = ob, .pbvh = pbvh, .nodes = nodes, .multires = multires, - .mode = mode, .value = value, .clip_planes_final = clip_planes_final, - }; - - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT); - BLI_task_parallel_range( - 0, totnode, &data, mask_box_select_task_cb, - &settings); - - if (nodes) - MEM_freeN(nodes); - } - } - - if (multires) - multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); - - sculpt_undo_push_end(); - - ED_region_tag_redraw(ar); - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - return true; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Sculpt *sd = vc->scene->toolsettings->sculpt; + BoundBox bb; + float clip_planes[4][4]; + float clip_planes_final[4][4]; + ARegion *ar = vc->ar; + struct Scene *scene = vc->scene; + Object *ob = vc->obact; + PaintMaskFloodMode mode; + float value; + bool multires; + PBVH *pbvh; + PBVHNode **nodes; + int totnode, symmpass; + int symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; + + mode = PAINT_MASK_FLOOD_VALUE; + value = select ? 1.0 : 0.0; + + /* transform the clip planes in object space */ + ED_view3d_clipping_calc(&bb, clip_planes, vc->ar, vc->obact, rect); + negate_m4(clip_planes); + + BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, true); + pbvh = ob->sculpt->pbvh; + multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS); + + sculpt_undo_push_begin("Mask box fill"); + + for (symmpass = 0; symmpass <= symm; ++symmpass) { + if (symmpass == 0 || (symm & symmpass && (symm != 5 || symmpass != 3) && + (symm != 6 || (symmpass != 3 && symmpass != 5)))) { + int j = 0; + + /* flip the planes symmetrically as needed */ + for (; j < 4; j++) { + flip_plane(clip_planes_final[j], clip_planes[j], symmpass); + } + + BKE_pbvh_search_gather( + pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode); + + MaskTaskData data = { + .ob = ob, + .pbvh = pbvh, + .nodes = nodes, + .multires = multires, + .mode = mode, + .value = value, + .clip_planes_final = clip_planes_final, + }; + + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && + totnode > SCULPT_THREADED_LIMIT); + BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings); + + if (nodes) + MEM_freeN(nodes); + } + } + + if (multires) + multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); + + sculpt_undo_push_end(); + + ED_region_tag_redraw(ar); + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return true; } typedef struct LassoMaskData { - struct ViewContext *vc; - float projviewobjmat[4][4]; - BLI_bitmap *px; - int width; - rcti rect; /* bounding box for scanfilling */ - int symmpass; - - MaskTaskData task_data; + struct ViewContext *vc; + float projviewobjmat[4][4]; + BLI_bitmap *px; + int width; + rcti rect; /* bounding box for scanfilling */ + int symmpass; + + MaskTaskData task_data; } 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]) { - float scr_co_f[2]; - int scr_co_s[2]; - float co_final[3]; - - flip_v3_v3(co_final, co, data->symmpass); - /* first project point to 2d space */ - ED_view3d_project_float_v2_m4(data->vc->ar, co_final, scr_co_f, data->projviewobjmat); - - scr_co_s[0] = scr_co_f[0]; - scr_co_s[1] = scr_co_f[1]; - - /* clip against screen, because lasso is limited to screen only */ - if ((scr_co_s[0] < data->rect.xmin) || - (scr_co_s[1] < data->rect.ymin) || - (scr_co_s[0] >= data->rect.xmax) || - (scr_co_s[1] >= data->rect.ymax)) - { - return false; - } - - scr_co_s[0] -= data->rect.xmin; - scr_co_s[1] -= data->rect.ymin; - - return BLI_BITMAP_TEST_BOOL(data->px, scr_co_s[1] * data->width + scr_co_s[0]); + float scr_co_f[2]; + int scr_co_s[2]; + float co_final[3]; + + flip_v3_v3(co_final, co, data->symmpass); + /* first project point to 2d space */ + ED_view3d_project_float_v2_m4(data->vc->ar, co_final, scr_co_f, data->projviewobjmat); + + scr_co_s[0] = scr_co_f[0]; + scr_co_s[1] = scr_co_f[1]; + + /* clip against screen, because lasso is limited to screen only */ + if ((scr_co_s[0] < data->rect.xmin) || (scr_co_s[1] < data->rect.ymin) || + (scr_co_s[0] >= data->rect.xmax) || (scr_co_s[1] >= data->rect.ymax)) { + return false; + } + + scr_co_s[0] -= data->rect.xmin; + scr_co_s[1] -= data->rect.ymin; + + return BLI_BITMAP_TEST_BOOL(data->px, scr_co_s[1] * data->width + scr_co_s[0]); } static void mask_lasso_px_cb(int x, int x_end, int y, void *user_data) { - LassoMaskData *data = user_data; - int index = (y * data->width) + x; - int index_end = (y * data->width) + x_end; - do { - BLI_BITMAP_ENABLE(data->px, index); - } while (++index != index_end); + LassoMaskData *data = user_data; + int index = (y * data->width) + x; + int index_end = (y * data->width) + x_end; + do { + BLI_BITMAP_ENABLE(data->px, index); + } while (++index != index_end); } -static void mask_gesture_lasso_task_cb( - void *__restrict userdata, - const int i, - const ParallelRangeTLS *__restrict UNUSED(tls)) +static void mask_gesture_lasso_task_cb(void *__restrict userdata, + const int i, + const ParallelRangeTLS *__restrict UNUSED(tls)) { - LassoMaskData *lasso_data = userdata; - MaskTaskData *data = &lasso_data->task_data; + LassoMaskData *lasso_data = userdata; + MaskTaskData *data = &lasso_data->task_data; - PBVHNode *node = data->nodes[i]; + PBVHNode *node = data->nodes[i]; - const PaintMaskFloodMode mode = data->mode; - const float value = data->value; + const PaintMaskFloodMode mode = data->mode; + const float value = data->value; - PBVHVertexIter vi; - bool any_masked = false; + PBVHVertexIter vi; + bool any_masked = false; - BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) { - if (is_effected_lasso(lasso_data, vi.co)) { - if (!any_masked) { - any_masked = true; + BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) + { + if (is_effected_lasso(lasso_data, vi.co)) { + if (!any_masked) { + any_masked = true; - sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK); + sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK); - BKE_pbvh_node_mark_redraw(node); - if (data->multires) - BKE_pbvh_node_mark_normals_update(node); - } + BKE_pbvh_node_mark_redraw(node); + if (data->multires) + BKE_pbvh_node_mark_normals_update(node); + } - mask_flood_fill_set_elem(vi.mask, mode, value); - } - } BKE_pbvh_vertex_iter_end; + mask_flood_fill_set_elem(vi.mask, mode, value); + } + } + BKE_pbvh_vertex_iter_end; } static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) { - int mcords_tot; - const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); - - if (mcords) { - Depsgraph *depsgraph = CTX_data_depsgraph(C); - float clip_planes[4][4], clip_planes_final[4][4]; - BoundBox bb; - Object *ob; - ViewContext vc; - LassoMaskData data; - struct Scene *scene = CTX_data_scene(C); - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - int symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; - PBVH *pbvh; - PBVHNode **nodes; - int totnode, symmpass; - bool multires; - PaintMaskFloodMode mode = RNA_enum_get(op->ptr, "mode"); - float value = RNA_float_get(op->ptr, "value"); - - /* 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 - * of lasso */ - ED_view3d_viewcontext_init(C, &vc); - - /* lasso data calculations */ - data.vc = &vc; - ob = vc.obact; - ED_view3d_ob_project_mat_get(vc.rv3d, ob, data.projviewobjmat); - - BLI_lasso_boundbox(&data.rect, mcords, mcords_tot); - data.width = data.rect.xmax - data.rect.xmin; - data.px = BLI_BITMAP_NEW(data.width * (data.rect.ymax - data.rect.ymin), __func__); - - BLI_bitmap_draw_2d_poly_v2i_n( - data.rect.xmin, data.rect.ymin, data.rect.xmax, data.rect.ymax, - mcords, mcords_tot, - mask_lasso_px_cb, &data); - - ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, &data.rect); - negate_m4(clip_planes); - - BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, true); - pbvh = ob->sculpt->pbvh; - multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS); - - sculpt_undo_push_begin("Mask lasso fill"); - - for (symmpass = 0; symmpass <= symm; ++symmpass) { - if ((symmpass == 0) || - (symm & symmpass && - (symm != 5 || symmpass != 3) && - (symm != 6 || (symmpass != 3 && symmpass != 5)))) - { - int j = 0; - - /* flip the planes symmetrically as needed */ - for (; j < 4; j++) { - flip_plane(clip_planes_final[j], clip_planes[j], symmpass); - } - - data.symmpass = symmpass; - - /* gather nodes inside lasso's enclosing rectangle - * (should greatly help with bigger meshes) */ - BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode); - - data.task_data.ob = ob; - data.task_data.pbvh = pbvh; - data.task_data.nodes = nodes; - data.task_data.multires = multires; - data.task_data.mode = mode; - data.task_data.value = value; - - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && (totnode > SCULPT_THREADED_LIMIT)); - BLI_task_parallel_range( - 0, totnode, &data, mask_gesture_lasso_task_cb, - &settings); - - if (nodes) - MEM_freeN(nodes); - } - } - - if (multires) - multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); - - sculpt_undo_push_end(); - - ED_region_tag_redraw(vc.ar); - MEM_freeN((void *)mcords); - MEM_freeN(data.px); - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - return OPERATOR_FINISHED; - } - return OPERATOR_PASS_THROUGH; + int mcords_tot; + const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + + if (mcords) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); + float clip_planes[4][4], clip_planes_final[4][4]; + BoundBox bb; + Object *ob; + ViewContext vc; + LassoMaskData data; + struct Scene *scene = CTX_data_scene(C); + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + int symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL; + PBVH *pbvh; + PBVHNode **nodes; + int totnode, symmpass; + bool multires; + PaintMaskFloodMode mode = RNA_enum_get(op->ptr, "mode"); + float value = RNA_float_get(op->ptr, "value"); + + /* 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 + * of lasso */ + ED_view3d_viewcontext_init(C, &vc); + + /* lasso data calculations */ + data.vc = &vc; + ob = vc.obact; + ED_view3d_ob_project_mat_get(vc.rv3d, ob, data.projviewobjmat); + + BLI_lasso_boundbox(&data.rect, mcords, mcords_tot); + data.width = data.rect.xmax - data.rect.xmin; + data.px = BLI_BITMAP_NEW(data.width * (data.rect.ymax - data.rect.ymin), __func__); + + BLI_bitmap_draw_2d_poly_v2i_n(data.rect.xmin, + data.rect.ymin, + data.rect.xmax, + data.rect.ymax, + mcords, + mcords_tot, + mask_lasso_px_cb, + &data); + + ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, &data.rect); + negate_m4(clip_planes); + + BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, false, true); + pbvh = ob->sculpt->pbvh; + multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS); + + sculpt_undo_push_begin("Mask lasso fill"); + + for (symmpass = 0; symmpass <= symm; ++symmpass) { + if ((symmpass == 0) || (symm & symmpass && (symm != 5 || symmpass != 3) && + (symm != 6 || (symmpass != 3 && symmpass != 5)))) { + int j = 0; + + /* flip the planes symmetrically as needed */ + for (; j < 4; j++) { + flip_plane(clip_planes_final[j], clip_planes[j], symmpass); + } + + data.symmpass = symmpass; + + /* gather nodes inside lasso's enclosing rectangle + * (should greatly help with bigger meshes) */ + BKE_pbvh_search_gather( + pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode); + + data.task_data.ob = ob; + data.task_data.pbvh = pbvh; + data.task_data.nodes = nodes; + data.task_data.multires = multires; + data.task_data.mode = mode; + data.task_data.value = value; + + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && + (totnode > SCULPT_THREADED_LIMIT)); + BLI_task_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings); + + if (nodes) + MEM_freeN(nodes); + } + } + + if (multires) + multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); + + sculpt_undo_push_end(); + + ED_region_tag_redraw(vc.ar); + MEM_freeN((void *)mcords); + MEM_freeN(data.px); + + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; + } + return OPERATOR_PASS_THROUGH; } void PAINT_OT_mask_lasso_gesture(wmOperatorType *ot) { - ot->name = "Mask Lasso Gesture"; - ot->idname = "PAINT_OT_mask_lasso_gesture"; - ot->description = "Add mask within the lasso as you move the brush"; - - ot->invoke = WM_gesture_lasso_invoke; - ot->modal = WM_gesture_lasso_modal; - ot->exec = paint_mask_gesture_lasso_exec; - - ot->poll = sculpt_mode_poll; - - ot->flag = OPTYPE_REGISTER; - - /* properties */ - WM_operator_properties_gesture_lasso(ot); - - RNA_def_enum(ot->srna, "mode", mode_items, PAINT_MASK_FLOOD_VALUE, "Mode", NULL); - RNA_def_float(ot->srna, "value", 1.0, 0, 1.0, "Value", - "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked", 0, 1); + ot->name = "Mask Lasso Gesture"; + ot->idname = "PAINT_OT_mask_lasso_gesture"; + ot->description = "Add mask within the lasso as you move the brush"; + + ot->invoke = WM_gesture_lasso_invoke; + ot->modal = WM_gesture_lasso_modal; + ot->exec = paint_mask_gesture_lasso_exec; + + ot->poll = sculpt_mode_poll; + + ot->flag = OPTYPE_REGISTER; + + /* properties */ + WM_operator_properties_gesture_lasso(ot); + + RNA_def_enum(ot->srna, "mode", mode_items, PAINT_MASK_FLOOD_VALUE, "Mode", NULL); + RNA_def_float( + ot->srna, + "value", + 1.0, + 0, + 1.0, + "Value", + "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked", + 0, + 1); } |