Shape Key editing: propagate updates through basis chains #105422
|
@ -182,6 +182,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);
|
||||
|
||||
/**
|
||||
angavrilov marked this conversation as resolved
Outdated
|
||||
* Returns a newly allocated 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
|
||||
* \{ */
|
||||
|
|
|
@ -2598,3 +2598,46 @@ bool BKE_keyblock_is_basis(const Key *key, const int index)
|
|||
|
||||
return false;
|
||||
angavrilov marked this conversation as resolved
Outdated
Hans Goudey
commented
I don't think this I don't think this `Simple checks.` comment is adding anything here. Such early return condition checking is not exactly out of the ordinary, and the fact that they're "simple" is already obvious from looking at the code.
|
||||
}
|
||||
|
||||
bool *BKE_keyblock_get_dependent_keys(const Key *key, const int index)
|
||||
{
|
||||
if (key->type != KEY_RELATIVE) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const int count = BLI_listbase_count(&key->block);
|
||||
|
||||
if (index < 0 || index >= count) {
|
||||
return nullptr;
|
||||
Hans Goudey
commented
This is a C++ file, might as well use This is a C++ file, might as well use `Array` or `BitVector` here
Alexander Gavrilov
commented
It's returned to the function caller, which still includes C code. It's returned to the function caller, which still includes C code.
|
||||
}
|
||||
|
||||
/* 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. This method minimizes
|
||||
* the number of scans through the list and is failsafe vs reference cycles. */
|
||||
bool updated, found = false;
|
||||
int i;
|
||||
|
||||
do {
|
||||
angavrilov marked this conversation as resolved
Outdated
Hans Goudey
commented
Use the Use the `LISTBASE_FOREACH_INDEX` macro
|
||||
updated = false;
|
||||
|
||||
LISTBASE_FOREACH_INDEX (const KeyBlock *, kb, &key->block, i) {
|
||||
if (!marked[i] && kb->relative >= 0 && kb->relative < count && marked[kb->relative]) {
|
||||
marked[i] = true;
|
||||
updated = found = true;
|
||||
}
|
||||
}
|
||||
} while (updated);
|
||||
|
||||
if (!found) {
|
||||
MEM_freeN(marked);
|
||||
return nullptr;
|
||||
angavrilov marked this conversation as resolved
Outdated
Hans Goudey
commented
else after return else after return
|
||||
}
|
||||
|
||||
/* After the search is complete, exclude the original key. */
|
||||
marked[index] = false;
|
||||
return marked;
|
||||
}
|
||||
|
|
|
@ -795,6 +795,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) &&
|
||||
|
@ -803,7 +804,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. */
|
||||
|
@ -830,6 +831,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;
|
||||
}
|
||||
}
|
||||
|
@ -856,7 +859,8 @@ 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];
|
||||
|
||||
|
@ -867,8 +871,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. */
|
||||
|
@ -956,9 +959,8 @@ static void bm_to_mesh_shape(BMesh *bm,
|
|||
}
|
||||
}
|
||||
|
||||
if (ofs) {
|
||||
MEM_freeN(ofs);
|
||||
}
|
||||
MEM_SAFE_FREE(ofs);
|
||||
MEM_SAFE_FREE(dependent);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -631,7 +631,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;
|
||||
|
@ -640,11 +640,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 */
|
||||
|
@ -702,9 +705,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;
|
||||
|
@ -866,9 +868,8 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
|
|||
currkey->data = newkey;
|
||||
}
|
||||
|
||||
if (ofs) {
|
||||
MEM_freeN(ofs);
|
||||
}
|
||||
MEM_SAFE_FREE(ofs);
|
||||
MEM_SAFE_FREE(dependent);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -3406,11 +3406,11 @@ void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
|
|||
{
|
||||
Mesh *me = (Mesh *)ob->data;
|
||||
float(*ofs)[3] = nullptr;
|
||||
int a;
|
||||
int a, currkey_i;
|
||||
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). */
|
||||
|
@ -3419,13 +3419,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, currkey_i) {
|
||||
if ((currkey != kb) && dependent[currkey_i]) {
|
||||
BKE_keyblock_update_from_offset(ob, currkey, ofs);
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(ofs);
|
||||
MEM_freeN(dependent);
|
||||
}
|
||||
|
||||
/* Modifying of basis key should update mesh. */
|
||||
|
|
Loading…
Reference in New Issue
an array
->an allocated array
Would just help to write down that it's supposed to be freed