[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