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. */ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs