diff options
author | Campbell Barton <ideasman42@gmail.com> | 2016-05-25 12:12:43 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2016-05-25 12:12:43 +0300 |
commit | 15911eebdab1e61bc872ecb63956f2fe2727dd85 (patch) | |
tree | ea64dc045261d2fc1f6de0b5703fd66bb1355525 /source/blender/editors/mesh/editmesh_undo.c | |
parent | 18b418e8e01b7d91da0240f0c5fc4370d4c4f6d9 (diff) |
Move editmesh undo into its own file
Diffstat (limited to 'source/blender/editors/mesh/editmesh_undo.c')
-rw-r--r-- | source/blender/editors/mesh/editmesh_undo.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c new file mode 100644 index 00000000000..287ee97e9a0 --- /dev/null +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -0,0 +1,173 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/editmesh_undo.c + * \ingroup edmesh + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_key_types.h" + +#include "BLI_listbase.h" + +#include "BKE_DerivedMesh.h" +#include "BKE_context.h" +#include "BKE_key.h" +#include "BKE_mesh.h" +#include "BKE_editmesh.h" + +#include "ED_mesh.h" +#include "ED_util.h" + + +/* for callbacks */ + +static void *getEditMesh(bContext *C) +{ + Object *obedit = CTX_data_edit_object(C); + if (obedit && obedit->type == OB_MESH) { + Mesh *me = obedit->data; + return me->edit_btmesh; + } + return NULL; +} + +typedef struct UndoMesh { + Mesh me; + int selectmode; + + /** \note + * this isn't a prefect solution, if you edit keys and change shapes this works well (fixing [#32442]), + * but editing shape keys, going into object mode, removing or changing their order, + * then go back into editmode and undo will give issues - where the old index will be out of sync + * with the new object index. + * + * There are a few ways this could be made to work but for now its a known limitation with mixing + * object and editmode operations - Campbell */ + int shapenr; +} UndoMesh; + +/* undo simply makes copies of a bmesh */ +static void *editbtMesh_to_undoMesh(void *emv, void *obdata) +{ + BMEditMesh *em = emv; + Mesh *obme = obdata; + + UndoMesh *um = MEM_callocN(sizeof(UndoMesh), "undo Mesh"); + + /* make sure shape keys work */ + um->me.key = obme->key ? BKE_key_copy_nolib(obme->key) : NULL; + + /* BM_mesh_validate(em->bm); */ /* for troubleshooting */ + + BM_mesh_bm_to_me( + em->bm, &um->me, (&(struct BMeshToMeshParams){ + .cd_mask_extra = CD_MASK_SHAPE_KEYINDEX, + })); + + um->selectmode = em->selectmode; + um->shapenr = em->bm->shapenr; + + return um; +} + +static void undoMesh_to_editbtMesh(void *umv, void *em_v, void *obdata) +{ + BMEditMesh *em = em_v, *em_tmp; + Object *ob = em->ob; + UndoMesh *um = umv; + BMesh *bm; + Key *key = ((Mesh *) obdata)->key; + + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(&um->me); + + em->bm->shapenr = um->shapenr; + + EDBM_mesh_free(em); + + bm = BM_mesh_create(&allocsize); + + BM_mesh_bm_from_me( + bm, &um->me, (&(struct BMeshFromMeshParams){ + .calc_face_normal = true, .active_shapekey = um->shapenr, + })); + + em_tmp = BKE_editmesh_create(bm, true); + *em = *em_tmp; + + em->selectmode = um->selectmode; + bm->selectmode = um->selectmode; + 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); +} + +static void free_undo(void *me_v) +{ + Mesh *me = me_v; + if (me->key) { + BKE_key_free(me->key); + MEM_freeN(me->key); + } + + BKE_mesh_free(me, false); + MEM_freeN(me); +} + +/* and this is all the undo system needs to know */ +void undo_push_mesh(bContext *C, const char *name) +{ + /* em->ob gets out of date and crashes on mesh undo, + * this is an easy way to ensure its OK + * though we could investigate the matter further. */ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + em->ob = obedit; + + undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL); +} |