[Bf-blender-cvs] [2d421873951] master: View 3D: refactor edit-mode meta-element selection

Campbell Barton noreply at git.blender.org
Wed Mar 16 10:12:12 CET 2022


Commit: 2d4218739518dc3f706dea352a93b46c19a15ab1
Author: Campbell Barton
Date:   Wed Mar 16 16:57:22 2022 +1100
Branches: master
https://developer.blender.org/rB2d4218739518dc3f706dea352a93b46c19a15ab1

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.

===================================================================

M	source/blender/editors/include/ED_mball.h
M	source/blender/editors/metaball/mball_edit.c

===================================================================

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;
   }



More information about the Bf-blender-cvs mailing list