[Bf-blender-cvs] [04accc6fd95] temp-angavrilov: Shape Key editing: propagate updates through basis chains.

Alexander Gavrilov noreply at git.blender.org
Sun Feb 5 16:22:07 CET 2023


Commit: 04accc6fd95d8a40d6522676670283765246eb65
Author: Alexander Gavrilov
Date:   Sun Feb 5 17:20:41 2023 +0200
Branches: temp-angavrilov
https://developer.blender.org/rB04accc6fd95d8a40d6522676670283765246eb65

Shape Key editing: propagate updates through basis chains.

It is possible to organize shape keys into a tree through the
reference key setting. Mesh editing and sculpting a reference
key is supposed to update all its children, but this was only
done for one level of dependencies.

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

M	source/blender/blenkernel/BKE_key.h
M	source/blender/blenkernel/intern/key.cc
M	source/blender/bmesh/intern/bmesh_mesh_convert.cc
M	source/blender/editors/curve/editcurve.c
M	source/blender/editors/sculpt_paint/sculpt.cc

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

diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index 10c95253f38..5d6f5e3c201 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -185,6 +185,12 @@ bool BKE_keyblock_move(struct Object *ob, int org_index, int new_index);
  */
 bool BKE_keyblock_is_basis(const struct Key *key, int index);
 
+/**
+ * Returns an array containing true for every key that has this one as basis.
+ * If none are found, returns null.
+ */
+bool *BKE_keyblock_get_dependent_keys(const struct Key *key, int index);
+
 /* -------------------------------------------------------------------- */
 /** \name Key-Block Data Access
  * \{ */
diff --git a/source/blender/blenkernel/intern/key.cc b/source/blender/blenkernel/intern/key.cc
index b8ff350917e..b8d8442b93d 100644
--- a/source/blender/blenkernel/intern/key.cc
+++ b/source/blender/blenkernel/intern/key.cc
@@ -2592,3 +2592,50 @@ bool BKE_keyblock_is_basis(const Key *key, const int index)
 
   return false;
 }
+
+bool *BKE_keyblock_get_dependent_keys(const struct Key *key, int index)
+{
+  /* Simple checks. */
+  if (key->type != KEY_RELATIVE) {
+    return nullptr;
+  }
+
+  const int count = BLI_listbase_count(&key->block);
+
+  if (index < 0 || index >= count) {
+    return nullptr;
+  }
+
+  /* Seed the table with the specified key. */
+  bool *marked = static_cast<bool *>(MEM_callocN(sizeof(bool) * count, __func__));
+
+  marked[index] = true;
+
+  /* Iterative breadth-first search through the key list. */
+  int updated, total = 0;
+
+  do {
+    const KeyBlock *kb;
+    int i;
+
+    updated = 0;
+
+    for (i = 0, kb = static_cast<const KeyBlock *>(key->block.first); kb; i++, kb = kb->next) {
+      if (!marked[i] && kb->relative >= 0 && kb->relative < count && marked[kb->relative]) {
+        marked[i] = true;
+        updated++;
+        total++;
+      }
+    }
+  } while (updated > 0);
+
+  if (total == 0) {
+    MEM_freeN(marked);
+    return nullptr;
+  }
+  else {
+    /* After the search is complete, exclude the original key. */
+    marked[index] = false;
+    return marked;
+  }
+}
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
index d58337400a2..55b6b37e7b1 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
@@ -721,6 +721,7 @@ static void bm_to_mesh_shape(BMesh *bm,
   BMIter iter;
   BMVert *eve;
   float(*ofs)[3] = nullptr;
+  bool *dependent = nullptr;
 
   /* Editing the basis key updates others. */
   if ((key->type == KEY_RELATIVE) &&
@@ -729,7 +730,7 @@ static void bm_to_mesh_shape(BMesh *bm,
       /* Original key-indices are only used to check the vertex existed when entering edit-mode. */
       (cd_shape_keyindex_offset != -1) &&
       /* Offsets are only needed if the current shape is a basis for others. */
-      BKE_keyblock_is_basis(key, bm->shapenr - 1)) {
+      (dependent = BKE_keyblock_get_dependent_keys(key, bm->shapenr - 1)) != nullptr) {
 
     BLI_assert(actkey != nullptr); /* Assured by `actkey_has_layer` check. */
     const int actkey_uuid = bm_to_mesh_shape_layer_index_from_kb(bm, actkey);
@@ -755,6 +756,8 @@ static void bm_to_mesh_shape(BMesh *bm,
          * ones, creating a mess when doing e.g. subdivide + translate. */
         MEM_freeN(ofs);
         ofs = nullptr;
+        MEM_freeN(dependent);
+        dependent = nullptr;
         break;
       }
     }
@@ -781,7 +784,9 @@ static void bm_to_mesh_shape(BMesh *bm,
     }
   }
 
-  LISTBASE_FOREACH (KeyBlock *, currkey, &key->block) {
+  int currkey_i;
+
+  LISTBASE_FOREACH_INDEX (KeyBlock *, currkey, &key->block, currkey_i) {
     int keyi;
     float(*currkey_data)[3];
 
@@ -792,8 +797,7 @@ static void bm_to_mesh_shape(BMesh *bm,
 
     /* Common case, the layer data is available, use it where possible. */
     if (cd_shape_offset != -1) {
-      const bool apply_offset = (ofs != nullptr) && (currkey != actkey) &&
-                                (bm->shapenr - 1 == currkey->relative);
+      const bool apply_offset = (ofs != nullptr) && (currkey != actkey) && dependent[currkey_i];
 
       if (currkey->data && (currkey->totelem == bm->totvert)) {
         /* Use memory in-place. */
@@ -882,6 +886,7 @@ static void bm_to_mesh_shape(BMesh *bm,
 
   if (ofs) {
     MEM_freeN(ofs);
+    MEM_freeN(dependent);
   }
 }
 
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index f7107650f8c..e8a53ca4dc6 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -630,7 +630,7 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
     return;
   }
 
-  int a, i;
+  int a, i, currkey_i;
   EditNurb *editnurb = cu->editnurb;
   KeyBlock *actkey = BLI_findlink(&cu->key->block, editnurb->shapenr - 1);
   BezTriple *bezt, *oldbezt;
@@ -639,11 +639,14 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
   int totvert = BKE_keyblock_curve_element_count(&editnurb->nurbs);
 
   float(*ofs)[3] = NULL;
+  bool *dependent = NULL;
   float *oldkey, *newkey, *ofp;
 
   /* editing the base key should update others */
   if (cu->key->type == KEY_RELATIVE) {
-    if (BKE_keyblock_is_basis(cu->key, editnurb->shapenr - 1)) { /* active key is a base */
+    dependent = BKE_keyblock_get_dependent_keys(cu->key, editnurb->shapenr - 1);
+
+    if (dependent) { /* active key is a base */
       int totvec = 0;
 
       /* Calculate needed memory to store offset */
@@ -701,9 +704,8 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
     }
   }
 
-  LISTBASE_FOREACH (KeyBlock *, currkey, &cu->key->block) {
-    const bool apply_offset = (ofs && (currkey != actkey) &&
-                               (editnurb->shapenr - 1 == currkey->relative));
+  LISTBASE_FOREACH_INDEX (KeyBlock *, currkey, &cu->key->block, currkey_i) {
+    const bool apply_offset = (ofs && (currkey != actkey) && dependent[currkey_i]);
 
     float *fp = newkey = MEM_callocN(cu->key->elemsize * totvert, "currkey->data");
     ofp = oldkey = currkey->data;
@@ -867,6 +869,7 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
 
   if (ofs) {
     MEM_freeN(ofs);
+    MEM_freeN(dependent);
   }
 }
 
diff --git a/source/blender/editors/sculpt_paint/sculpt.cc b/source/blender/editors/sculpt_paint/sculpt.cc
index 2cdfc5377df..61831ce18c3 100644
--- a/source/blender/editors/sculpt_paint/sculpt.cc
+++ b/source/blender/editors/sculpt_paint/sculpt.cc
@@ -3327,7 +3327,7 @@ void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
   const int kb_act_idx = ob->shapenr - 1;
 
   /* For relative keys editing of base should update other keys. */
-  if (BKE_keyblock_is_basis(me->key, kb_act_idx)) {
+  if (bool *dependent = BKE_keyblock_get_dependent_keys(me->key, kb_act_idx)) {
     ofs = BKE_keyblock_convert_to_vertcos(ob, kb);
 
     /* Calculate key coord offsets (from previous location). */
@@ -3336,13 +3336,14 @@ void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
     }
 
     /* Apply offsets on other keys. */
-    LISTBASE_FOREACH (KeyBlock *, currkey, &me->key->block) {
-      if ((currkey != kb) && (currkey->relative == kb_act_idx)) {
+    LISTBASE_FOREACH_INDEX (KeyBlock *, currkey, &me->key->block, a) {
+      if ((currkey != kb) && dependent[a]) {
         BKE_keyblock_update_from_offset(ob, currkey, ofs);
       }
     }
 
     MEM_freeN(ofs);
+    MEM_freeN(dependent);
   }
 
   /* Modifying of basis key should update mesh. */



More information about the Bf-blender-cvs mailing list