From a7aeec26550e24fa8b9d8f678afa65c48a5524d5 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Sun, 8 Aug 2021 14:53:05 +0200 Subject: GPencil: New Select Random operator Select strokes or points randomly (similar to meshes). Reviewed By: pepeland Differential Revision: https://developer.blender.org/D12157 --- source/blender/editors/gpencil/gpencil_intern.h | 1 + source/blender/editors/gpencil/gpencil_ops.c | 1 + source/blender/editors/gpencil/gpencil_select.c | 233 ++++++++++++++++++++++++ 3 files changed, 235 insertions(+) (limited to 'source/blender/editors/gpencil') diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index d1a1e417d9e..b6730cb123b 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -375,6 +375,7 @@ void GPENCIL_OT_select_less(struct wmOperatorType *ot); void GPENCIL_OT_select_first(struct wmOperatorType *ot); void GPENCIL_OT_select_last(struct wmOperatorType *ot); void GPENCIL_OT_select_alternate(struct wmOperatorType *ot); +void GPENCIL_OT_select_random(struct wmOperatorType *ot); void GPENCIL_OT_select_vertex_color(struct wmOperatorType *ot); void GPENCIL_OT_duplicate(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 35640cf3b66..8c78a402e81 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -555,6 +555,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_select_first); WM_operatortype_append(GPENCIL_OT_select_last); WM_operatortype_append(GPENCIL_OT_select_alternate); + WM_operatortype_append(GPENCIL_OT_select_random); WM_operatortype_append(GPENCIL_OT_select_vertex_color); WM_operatortype_append(GPENCIL_OT_duplicate); diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index 69734fa1ba8..4865cd3ecc4 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -33,6 +33,7 @@ #include "BLI_ghash.h" #include "BLI_lasso_2d.h" #include "BLI_math_vector.h" +#include "BLI_rand.h" #include "BLI_utildefines.h" #include "DNA_gpencil_types.h" @@ -193,6 +194,28 @@ static void deselect_all_selected(bContext *C) CTX_DATA_END; } +static void select_all_stroke_points(bGPdata *gpd, bGPDstroke *gps, bool select) +{ + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + if (select) { + pt->flag |= GP_SPOINT_SELECT; + } + else { + pt->flag &= ~GP_SPOINT_SELECT; + } + } + + if (select) { + gps->flag |= GP_STROKE_SELECT; + BKE_gpencil_stroke_select_index_set(gpd, gps); + } + else { + gps->flag &= ~GP_STROKE_SELECT; + BKE_gpencil_stroke_select_index_reset(gps); + } +} + static void select_all_curve_points(bGPdata *gpd, bGPDstroke *gps, bGPDcurve *gpc, bool deselect) { for (int i = 0; i < gpc->tot_curve_points; i++) { @@ -512,6 +535,216 @@ void GPENCIL_OT_select_alternate(wmOperatorType *ot) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Select Random Operator + * \{ */ + +static int gpencil_select_random_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_active_object(C); + ToolSettings *ts = CTX_data_tool_settings(C); + bGPdata *gpd = ED_gpencil_data_get_active(C); + if ((gpd == NULL) || (GPENCIL_NONE_EDIT_MODE(gpd))) { + return OPERATOR_CANCELLED; + } + + const bool unselect_ends = RNA_boolean_get(op->ptr, "unselect_ends"); + const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); + const float randfac = RNA_float_get(op->ptr, "ratio"); + const int seed = WM_operator_properties_select_random_seed_increment_get(op); + const int start = (unselect_ends) ? 1 : 0; + const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd); + + int selectmode; + if (ob && ob->mode == OB_MODE_SCULPT_GPENCIL) { + selectmode = gpencil_select_mode_from_sculpt(ts->gpencil_selectmode_sculpt); + } + else if (ob && ob->mode == OB_MODE_VERTEX_GPENCIL) { + selectmode = gpencil_select_mode_from_vertex(ts->gpencil_selectmode_vertex); + } + else { + selectmode = ts->gpencil_selectmode_edit; + } + + bool changed = false; + int seed_iter = seed; + int stroke_idx = 0; + + if (is_curve_edit) { + GP_EDITABLE_CURVES_BEGIN(gps_iter, C, gpl, gps, gpc) + { + /* Only apply to unselected strokes (if select). */ + if (select) { + if ((gps->flag & GP_STROKE_SELECT) || (gps->totpoints == 0)) { + continue; + } + } + else { + if (((gps->flag & GP_STROKE_SELECT) == 0) || (gps->totpoints == 0)) { + continue; + } + } + + /* Different seed by stroke. */ + seed_iter += gps->totpoints + stroke_idx; + stroke_idx++; + + if (selectmode == GP_SELECTMODE_STROKE) { + RNG *rng = BLI_rng_new(seed_iter); + const unsigned int j = BLI_rng_get_uint(rng) % gps->totpoints; + bool select_stroke = ((gps->totpoints * randfac) <= j) ? true : false; + select_stroke ^= select; + /* Curve function has select paremter inverted. */ + select_all_curve_points(gpd, gps, gps->editcurve, !select_stroke); + changed = true; + } + else { + int elem_map_len = 0; + bGPDcurve_point **elem_map = MEM_mallocN(sizeof(*elem_map) * gpc->tot_curve_points, + __func__); + bGPDcurve_point *ptc; + for (int i = start; i < gpc->tot_curve_points; i++) { + bGPDcurve_point *gpc_pt = &gpc->curve_points[i]; + elem_map[elem_map_len++] = gpc_pt; + } + + BLI_array_randomize(elem_map, sizeof(*elem_map), elem_map_len, seed_iter); + const int count_select = elem_map_len * randfac; + for (int i = 0; i < count_select; i++) { + ptc = elem_map[i]; + if (select) { + ptc->flag |= GP_SPOINT_SELECT; + BEZT_SEL_ALL(&ptc->bezt); + } + else { + ptc->flag &= ~GP_SPOINT_SELECT; + BEZT_DESEL_ALL(&ptc->bezt); + } + } + MEM_freeN(elem_map); + + /* unselect start and end points */ + if (unselect_ends) { + bGPDcurve_point *gpc_pt = &gpc->curve_points[0]; + gpc_pt->flag &= ~GP_SPOINT_SELECT; + BEZT_DESEL_ALL(&gpc_pt->bezt); + + gpc_pt = &gpc->curve_points[gpc->tot_curve_points - 1]; + gpc_pt->flag &= ~GP_SPOINT_SELECT; + BEZT_DESEL_ALL(&gpc_pt->bezt); + } + + BKE_gpencil_curve_sync_selection(gpd, gps); + } + + changed = true; + } + GP_EDITABLE_CURVES_END(gps_iter); + } + else { + CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) { + /* Only apply to unselected strokes (if select). */ + if (select) { + if ((gps->flag & GP_STROKE_SELECT) || (gps->totpoints == 0)) { + continue; + } + } + else { + if (((gps->flag & GP_STROKE_SELECT) == 0) || (gps->totpoints == 0)) { + continue; + } + } + + /* Different seed by stroke. */ + seed_iter += gps->totpoints + stroke_idx; + stroke_idx++; + + if (selectmode == GP_SELECTMODE_STROKE) { + RNG *rng = BLI_rng_new(seed_iter); + const unsigned int j = BLI_rng_get_uint(rng) % gps->totpoints; + bool select_stroke = ((gps->totpoints * randfac) <= j) ? true : false; + select_stroke ^= select; + select_all_stroke_points(gpd, gps, select_stroke); + changed = true; + } + else { + int elem_map_len = 0; + bGPDspoint **elem_map = MEM_mallocN(sizeof(*elem_map) * gps->totpoints, __func__); + bGPDspoint *pt; + for (int i = start; i < gps->totpoints; i++) { + pt = &gps->points[i]; + elem_map[elem_map_len++] = pt; + } + + BLI_array_randomize(elem_map, sizeof(*elem_map), elem_map_len, seed_iter); + const int count_select = elem_map_len * randfac; + for (int i = 0; i < count_select; i++) { + pt = elem_map[i]; + if (select) { + pt->flag |= GP_SPOINT_SELECT; + } + else { + pt->flag &= ~GP_SPOINT_SELECT; + } + } + MEM_freeN(elem_map); + + /* unselect start and end points */ + if (unselect_ends) { + pt = &gps->points[0]; + pt->flag &= ~GP_SPOINT_SELECT; + + pt = &gps->points[gps->totpoints - 1]; + pt->flag &= ~GP_SPOINT_SELECT; + } + + BKE_gpencil_stroke_sync_selection(gpd, gps); + } + + changed = true; + } + CTX_DATA_END; + } + + if (changed) { + /* updates */ + DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); + + /* copy on write tag is needed, or else no refresh happens */ + DEG_id_tag_update(&gpd->id, ID_RECALC_COPY_ON_WRITE); + + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL); + } + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_select_random(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Random"; + ot->idname = "GPENCIL_OT_select_random"; + ot->description = "Select random points for non selected strokes"; + + /* callbacks */ + ot->exec = gpencil_select_random_exec; + ot->poll = gpencil_select_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + WM_operator_properties_select_random(ot); + RNA_def_boolean(ot->srna, + "unselect_ends", + false, + "Unselect Ends", + "Do not select the first and last point of the stroke"); +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Select Grouped Operator * \{ */ -- cgit v1.2.3