Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <campbell@blender.org>2022-03-16 08:57:22 +0300
committerCampbell Barton <campbell@blender.org>2022-03-16 12:09:55 +0300
commit2d4218739518dc3f706dea352a93b46c19a15ab1 (patch)
tree7a9fc282fb8132c7e493b09d67f30be1eb0ae325
parent9df27e7f00509583e6c3b1187c14634171f64dfa (diff)
View 3D: refactor edit-mode meta-element selection
Meta-element selection now follows conventions for other picking functions (e.g. EDBM_select_pick). - Split meta-element find-nearest into a separate function. - Cycle the meta-element starting from the active & selected instead of comparing & setting a static variable. - Order elements using depth (from front-to-back) when cycling multiple elements.
-rw-r--r--source/blender/editors/include/ED_mball.h6
-rw-r--r--source/blender/editors/metaball/mball_edit.c250
2 files changed, 138 insertions, 118 deletions
diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h
index 74071765716..7f2c4dff311 100644
--- a/source/blender/editors/include/ED_mball.h
+++ b/source/blender/editors/include/ED_mball.h
@@ -12,6 +12,7 @@ extern "C" {
#endif
struct Base;
+struct MetaElem;
struct Object;
struct SelectPick_Params;
struct UndoType;
@@ -32,6 +33,11 @@ struct MetaElem *ED_mball_add_primitive(struct bContext *C,
float dia,
int type);
+struct Base *ED_mball_base_and_elem_from_select_buffer(struct Base **bases,
+ uint bases_len,
+ const uint select_id,
+ struct MetaElem **r_ml);
+
/**
* Select meta-element with mouse click (user can select radius circle or stiffness circle).
*
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index a19e2761394..55cae268e75 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -736,15 +736,42 @@ void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
/** \name Select Pick Utility
* \{ */
-bool ED_mball_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params)
+Base *ED_mball_base_and_elem_from_select_buffer(Base **bases,
+ uint bases_len,
+ const uint select_id,
+ MetaElem **r_ml)
+{
+ const uint hit_object = select_id & 0xFFFF;
+ Base *base = NULL;
+ MetaElem *ml = NULL;
+ /* TODO(campbell): optimize, eg: sort & binary search. */
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ if (bases[base_index]->object->runtime.select_id == hit_object) {
+ base = bases[base_index];
+ break;
+ }
+ }
+ if (base != NULL) {
+ const uint hit_elem = (select_id & ~MBALLSEL_ANY) >> 16;
+ MetaBall *mb = base->object->data;
+ ml = BLI_findlink(mb->editelems, hit_elem);
+ }
+ *r_ml = ml;
+ return base;
+}
+
+static bool ed_mball_findnearest_metaelem(bContext *C,
+ const int mval[2],
+ bool use_cycle,
+ Base **r_base,
+ MetaElem **r_ml,
+ uint *r_selmask)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- static MetaElem *startelem = NULL;
ViewContext vc;
int a, hits;
GPUSelectResult buffer[MAXPICKELEMS];
rcti rect;
- bool changed = false;
bool found = false;
ED_view3d_viewcontext_init(C, &vc, depsgraph);
@@ -755,144 +782,131 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], const struct SelectPic
buffer,
ARRAY_SIZE(buffer),
&rect,
- VIEW3D_SELECT_PICK_NEAREST,
+ use_cycle ? VIEW3D_SELECT_PICK_ALL : VIEW3D_SELECT_PICK_NEAREST,
VIEW3D_SELECT_FILTER_NOP);
- FOREACH_BASE_IN_EDIT_MODE_BEGIN (vc.view_layer, vc.v3d, base) {
- ED_view3d_viewcontext_init_object(&vc, base->object);
- MetaBall *mb = (MetaBall *)base->object->data;
- MetaElem *ml, *ml_act = NULL;
+ if (hits == 0) {
+ return false;
+ }
- /* does startelem exist? */
- ml = mb->editelems->first;
- while (ml) {
- if (ml == startelem) {
- break;
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
+
+ int hit_cycle_offset = 0;
+ if (use_cycle) {
+ /* When cycling, use the hit directly after the current active meta-element (when set). */
+ const int base_index = vc.obact->runtime.select_id;
+ MetaBall *mb = (MetaBall *)vc.obact->data;
+ MetaElem *ml = mb->lastelem;
+ if (ml && (ml->flag & SELECT)) {
+ const int ml_index = BLI_findindex(mb->editelems, ml);
+ BLI_assert(ml_index != -1);
+
+ /* Count backwards in case the active meta-element has multiple entries,
+ * ensure this steps onto the next meta-element. */
+ a = hits;
+ while (a--) {
+ const int select_id = buffer[a].id;
+ if (select_id == -1) {
+ continue;
+ }
+
+ if (((select_id & 0xFFFF) == base_index) &&
+ ((select_id & ~MBALLSEL_ANY) >> 16 == ml_index)) {
+ hit_cycle_offset = a + 1;
+ break;
+ }
}
- ml = ml->next;
}
+ }
- if (ml == NULL) {
- startelem = mb->editelems->first;
+ for (a = 0; a < hits; a++) {
+ const int index = (hit_cycle_offset == 0) ? a : ((a + hit_cycle_offset) % hits);
+ const uint select_id = buffer[index].id;
+ if (select_id == -1) {
+ continue;
}
- if (hits > 0) {
- int metaelem_id = 0;
- ml = startelem;
- while (ml) {
- for (a = 0; a < hits; a++) {
- const int hitresult = buffer[a].id;
- if (hitresult == -1) {
- continue;
- }
-
- const uint hit_object = hitresult & 0xFFFF;
- if (vc.obedit->runtime.select_id != hit_object) {
- continue;
- }
-
- if (metaelem_id != (hitresult & 0xFFFF0000 & ~MBALLSEL_ANY)) {
- continue;
- }
+ MetaElem *ml;
+ Base *base = ED_mball_base_and_elem_from_select_buffer(bases, bases_len, select_id, &ml);
+ if (ml == NULL) {
+ continue;
+ }
+ *r_base = base;
+ *r_ml = ml;
+ *r_selmask = select_id & MBALLSEL_ANY;
+ found = true;
+ break;
+ }
- if (hitresult & MBALLSEL_RADIUS) {
- ml->flag |= MB_SCALE_RAD;
- ml_act = ml;
- break;
- }
+ MEM_freeN(bases);
- if (hitresult & MBALLSEL_STIFF) {
- ml->flag &= ~MB_SCALE_RAD;
- ml_act = ml;
- break;
- }
- }
+ return found;
+}
- if (ml_act) {
- break;
- }
- ml = ml->next;
- if (ml == NULL) {
- ml = mb->editelems->first;
- }
- if (ml == startelem) {
- break;
- }
+bool ED_mball_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params)
+{
+ Base *base = NULL;
+ MetaElem *ml = NULL;
+ uint selmask = 0;
- metaelem_id += 0x10000;
- }
+ bool changed = false;
- /* When some metaelem was found, then it is necessary to select or deselect it. */
- if (ml_act) {
- found = true;
+ bool found = ed_mball_findnearest_metaelem(C, mval, true, &base, &ml, &selmask);
- if (params->sel_op == SEL_OP_SET) {
- uint objects_len;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
- vc.view_layer, vc.v3d, &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob_iter = objects[ob_index];
+ if ((params->sel_op == SEL_OP_SET) && (found || params->deselect_all)) {
+ /* Deselect everything. */
+ changed |= ED_mball_deselect_all_multi(C);
+ }
- if (ob_iter == base->object) {
- continue;
- }
+ if (found) {
+ if (selmask & MBALLSEL_RADIUS) {
+ ml->flag |= MB_SCALE_RAD;
+ }
+ else if (selmask & MBALLSEL_STIFF) {
+ ml->flag &= ~MB_SCALE_RAD;
+ }
- BKE_mball_deselect_all((MetaBall *)ob_iter->data);
- DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data);
- }
- MEM_freeN(objects);
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ ml->flag |= SELECT;
+ break;
+ }
+ case SEL_OP_SUB: {
+ ml->flag &= ~SELECT;
+ break;
+ }
+ case SEL_OP_XOR: {
+ if (ml->flag & SELECT) {
+ ml->flag &= ~SELECT;
}
-
- switch (params->sel_op) {
- case SEL_OP_ADD: {
- ml_act->flag |= SELECT;
- break;
- }
- case SEL_OP_SUB: {
- ml_act->flag &= ~SELECT;
- break;
- }
- case SEL_OP_XOR: {
- if (ml_act->flag & SELECT) {
- ml_act->flag &= ~SELECT;
- }
- else {
- ml_act->flag |= SELECT;
- }
- break;
- }
- case SEL_OP_SET: {
- /* Deselect all existing metaelems */
- BKE_mball_deselect_all(mb);
-
- /* Select only metaelem clicked on */
- ml_act->flag |= SELECT;
- break;
- }
- case SEL_OP_AND: {
- BLI_assert_unreachable(); /* Doesn't make sense for picking. */
- break;
- }
+ else {
+ ml->flag |= SELECT;
}
+ break;
+ }
+ case SEL_OP_SET: {
+ /* Deselect has already been performed. */
+ ml->flag |= SELECT;
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
+ }
+ }
- mb->lastelem = ml_act;
-
- DEG_id_tag_update(&mb->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ MetaBall *mb = (MetaBall *)base->object->data;
+ mb->lastelem = ml;
- if (vc.view_layer->basact != base) {
- ED_object_base_activate(C, base);
- }
+ DEG_id_tag_update(&mb->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb);
- changed = true;
- }
+ if (view_layer->basact != base) {
+ ED_object_base_activate(C, base);
}
- }
- FOREACH_BASE_IN_EDIT_MODE_END;
- if (params->deselect_all && !found) {
- ED_mball_deselect_all_multi(C);
changed = true;
}