forked from bartvdbraak/blender
Fix T35170: Undoing edit op on a basis shapekey could generate extra offset on its 'children'.
Based on investigation by sergey (Sergey Sharybin) and revzin (Grigory Revzin). Based on patch D460 by revzin (Grigory Revzin). Differential Revision: https://developer.blender.org/D460
This commit is contained in:
parent
b7f5ab0cd3
commit
dab0bd9de6
@ -2210,7 +2210,7 @@ bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
|
|||||||
/**
|
/**
|
||||||
* Check if given keyblock (as index) is used as basis by others in given key.
|
* Check if given keyblock (as index) is used as basis by others in given key.
|
||||||
*/
|
*/
|
||||||
bool BKE_keyblock_is_basis(struct Key *key, const int index)
|
bool BKE_keyblock_is_basis(Key *key, const int index)
|
||||||
{
|
{
|
||||||
KeyBlock *kb;
|
KeyBlock *kb;
|
||||||
int i;
|
int i;
|
||||||
|
@ -532,30 +532,56 @@ static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
|
|||||||
return um;
|
return um;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void undoMesh_to_editbtMesh(void *umv, void *em_v, void *UNUSED(obdata))
|
static void undoMesh_to_editbtMesh(void *umv, void *em_v, void *obdata)
|
||||||
{
|
{
|
||||||
BMEditMesh *em = em_v, *em_tmp;
|
BMEditMesh *em = em_v, *em_tmp;
|
||||||
Object *ob = em->ob;
|
Object *ob = em->ob;
|
||||||
UndoMesh *um = umv;
|
UndoMesh *um = umv;
|
||||||
BMesh *bm;
|
BMesh *bm;
|
||||||
|
Key *key = ((Mesh *) obdata)->key;
|
||||||
|
|
||||||
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me);
|
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me);
|
||||||
|
|
||||||
ob->shapenr = em->bm->shapenr = um->shapenr;
|
em->bm->shapenr = um->shapenr;
|
||||||
|
|
||||||
EDBM_mesh_free(em);
|
EDBM_mesh_free(em);
|
||||||
|
|
||||||
bm = BM_mesh_create(&allocsize);
|
bm = BM_mesh_create(&allocsize);
|
||||||
|
|
||||||
BM_mesh_bm_from_me(bm, &um->me, true, false, ob->shapenr);
|
BM_mesh_bm_from_me(bm, &um->me, true, false, um->shapenr);
|
||||||
|
|
||||||
em_tmp = BKE_editmesh_create(bm, true);
|
em_tmp = BKE_editmesh_create(bm, true);
|
||||||
*em = *em_tmp;
|
*em = *em_tmp;
|
||||||
|
|
||||||
em->selectmode = um->selectmode;
|
em->selectmode = um->selectmode;
|
||||||
bm->selectmode = um->selectmode;
|
bm->selectmode = um->selectmode;
|
||||||
em->ob = ob;
|
em->ob = ob;
|
||||||
|
|
||||||
|
/* T35170: Restore the active key on the RealMesh. Otherwise 'fake' offset propagation happens
|
||||||
|
* if the active is a basis for any other. */
|
||||||
|
if (key && (key->type == KEY_RELATIVE)) {
|
||||||
|
/* Since we can't add, remove or reorder keyblocks in editmode, it's safe to assume
|
||||||
|
* shapenr from restored bmesh and keyblock indices are in sync. */
|
||||||
|
const int kb_act_idx = ob->shapenr - 1;
|
||||||
|
|
||||||
|
/* If it is, let's patch the current mesh key block to its restored value.
|
||||||
|
* Else, the offsets won't be computed and it won't matter. */
|
||||||
|
if (BKE_keyblock_is_basis(key, kb_act_idx)) {
|
||||||
|
KeyBlock *kb_act = BLI_findlink(&key->block, kb_act_idx);
|
||||||
|
|
||||||
|
if (kb_act->totelem != um->me.totvert) {
|
||||||
|
/* The current mesh has some extra/missing verts compared to the undo, adjust. */
|
||||||
|
MEM_SAFE_FREE(kb_act->data);
|
||||||
|
kb_act->data = MEM_mallocN((size_t)(key->elemsize * bm->totvert), __func__);
|
||||||
|
kb_act->totelem = um->me.totvert;
|
||||||
|
}
|
||||||
|
|
||||||
|
BKE_keyblock_update_from_mesh(&um->me, kb_act);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ob->shapenr = um->shapenr;
|
||||||
|
|
||||||
MEM_freeN(em_tmp);
|
MEM_freeN(em_tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user