Edit Mesh: pass in Mesh instead of BMEditMesh to EDBM_update_generic
[blender.git] / source / blender / editors / object / object_data_transform.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edobj
22  *
23  * Use to transform object origins only.
24  *
25  * This is a small API to store & apply transformations to object data,
26  * where a transformation matrix can be continually applied ontop of the original values
27  * so we don't loose precision over time.
28  */
29
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "DNA_anim_types.h"
34 #include "DNA_armature_types.h"
35 #include "DNA_mesh_types.h"
36 #include "DNA_meta_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_collection_types.h"
40 #include "DNA_lattice_types.h"
41
42 #include "BLI_math.h"
43 #include "BLI_listbase.h"
44 #include "BLI_utildefines.h"
45
46 #include "BKE_curve.h"
47 #include "BKE_editmesh.h"
48 #include "BKE_mball.h"
49 #include "BKE_mesh.h"
50 #include "BKE_armature.h"
51 #include "BKE_lattice.h"
52 #include "BKE_scene.h"
53
54 #include "bmesh.h"
55
56 #include "DEG_depsgraph.h"
57 #include "DEG_depsgraph_query.h"
58
59 #include "WM_types.h"
60
61 #include "ED_object.h"
62 #include "ED_mesh.h"
63 #include "ED_armature.h"
64
65 #include "MEM_guardedalloc.h"
66
67 /* -------------------------------------------------------------------- */
68 /** \name Internal Transform Get/Apply
69  *
70  * Some object data types don't have utility functions to access their transformation data.
71  * Define these locally.
72  *
73  * \{ */
74
75 /* Armature */
76
77 struct ElemData_Armature {
78   float tail[3];
79   float head[3];
80   float roll;
81   float arm_tail[3];
82   float arm_head[3];
83   float arm_roll;
84   float rad_tail;
85   float rad_head;
86   float dist;
87   float xwidth;
88   float zwidth;
89 };
90
91 static struct ElemData_Armature *armature_coords_and_quats_get_recurse(
92     const ListBase *bone_base, struct ElemData_Armature *elem_array)
93 {
94   struct ElemData_Armature *elem = elem_array;
95   for (const Bone *bone = bone_base->first; bone; bone = bone->next) {
96
97 #define COPY_PTR(member) memcpy(elem->member, bone->member, sizeof(bone->member))
98 #define COPY_VAL(member) memcpy(&elem->member, &bone->member, sizeof(bone->member))
99     COPY_PTR(head);
100     COPY_PTR(tail);
101     COPY_VAL(roll);
102     COPY_PTR(arm_head);
103     COPY_PTR(arm_tail);
104     COPY_VAL(arm_roll);
105     COPY_VAL(rad_tail);
106     COPY_VAL(rad_head);
107     COPY_VAL(dist);
108     COPY_VAL(xwidth);
109     COPY_VAL(zwidth);
110 #undef COPY_PTR
111 #undef COPY_VAL
112
113     elem = armature_coords_and_quats_get_recurse(&bone->childbase, elem + 1);
114   }
115   return elem;
116 }
117
118 static void armature_coords_and_quats_get(const bArmature *arm,
119                                           struct ElemData_Armature *elem_array)
120 {
121   armature_coords_and_quats_get_recurse(&arm->bonebase, elem_array);
122 }
123
124 static const struct ElemData_Armature *armature_coords_and_quats_apply_with_mat4_recurse(
125     ListBase *bone_base, const struct ElemData_Armature *elem_array, const float mat[4][4])
126 {
127   const struct ElemData_Armature *elem = elem_array;
128   for (Bone *bone = bone_base->first; bone; bone = bone->next) {
129
130 #define COPY_PTR(member) memcpy(bone->member, elem->member, sizeof(bone->member))
131 #define COPY_VAL(member) memcpy(&bone->member, &elem->member, sizeof(bone->member))
132     COPY_PTR(head);
133     COPY_PTR(tail);
134     COPY_VAL(roll);
135     COPY_PTR(arm_head);
136     COPY_PTR(arm_tail);
137     COPY_VAL(arm_roll);
138     COPY_VAL(rad_tail);
139     COPY_VAL(rad_head);
140     COPY_VAL(dist);
141     COPY_VAL(xwidth);
142     COPY_VAL(zwidth);
143 #undef COPY_PTR
144 #undef COPY_VAL
145
146     elem = armature_coords_and_quats_apply_with_mat4_recurse(&bone->childbase, elem + 1, mat);
147   }
148   return elem;
149 }
150
151 static void armature_coords_and_quats_apply_with_mat4(bArmature *arm,
152                                                       const struct ElemData_Armature *elem_array,
153                                                       const float mat[4][4])
154 {
155   armature_coords_and_quats_apply_with_mat4_recurse(&arm->bonebase, elem_array, mat);
156   BKE_armature_transform(arm, mat, true);
157 }
158
159 static void armature_coords_and_quats_apply(bArmature *arm,
160                                             const struct ElemData_Armature *elem_array)
161 {
162   /* Avoid code duplication by using a unit matrix. */
163   float mat[4][4];
164   unit_m4(mat);
165   armature_coords_and_quats_apply_with_mat4(arm, elem_array, mat);
166 }
167
168 /* Edit Armature */
169 static void edit_armature_coords_and_quats_get(const bArmature *arm,
170                                                struct ElemData_Armature *elem_array)
171 {
172   struct ElemData_Armature *elem = elem_array;
173   for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next, elem++) {
174
175 #define COPY_PTR(member) memcpy(elem->member, ebone->member, sizeof(ebone->member))
176 #define COPY_VAL(member) memcpy(&elem->member, &ebone->member, sizeof(ebone->member))
177     /* Unused for edit bones: arm_head, arm_tail, arm_roll */
178     COPY_PTR(head);
179     COPY_PTR(tail);
180     COPY_VAL(roll);
181     COPY_VAL(rad_tail);
182     COPY_VAL(rad_head);
183     COPY_VAL(dist);
184     COPY_VAL(xwidth);
185     COPY_VAL(zwidth);
186 #undef COPY_PTR
187 #undef COPY_VAL
188   }
189 }
190
191 static void edit_armature_coords_and_quats_apply_with_mat4(
192     bArmature *arm, const struct ElemData_Armature *elem_array, const float mat[4][4])
193 {
194   const struct ElemData_Armature *elem = elem_array;
195   for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next, elem++) {
196
197 #define COPY_PTR(member) memcpy(ebone->member, elem->member, sizeof(ebone->member))
198 #define COPY_VAL(member) memcpy(&ebone->member, &elem->member, sizeof(ebone->member))
199     /* Unused for edit bones: arm_head, arm_tail, arm_roll */
200     COPY_PTR(head);
201     COPY_PTR(tail);
202     COPY_VAL(roll);
203     COPY_VAL(rad_tail);
204     COPY_VAL(rad_head);
205     COPY_VAL(dist);
206     COPY_VAL(xwidth);
207     COPY_VAL(zwidth);
208 #undef COPY_PTR
209 #undef COPY_VAL
210   }
211   ED_armature_edit_transform(arm, mat, true);
212 }
213
214 static void edit_armature_coords_and_quats_apply(bArmature *arm,
215                                                  const struct ElemData_Armature *elem_array)
216 {
217   /* Avoid code duplication by using a unit matrix. */
218   float mat[4][4];
219   unit_m4(mat);
220   edit_armature_coords_and_quats_apply_with_mat4(arm, elem_array, mat);
221 }
222
223 /* MetaBall */
224
225 struct ElemData_MetaBall {
226   float co[3];
227   float quat[4];
228   float exp[3];
229   float rad;
230 };
231
232 static void metaball_coords_and_quats_get(const MetaBall *mb, struct ElemData_MetaBall *elem_array)
233 {
234   struct ElemData_MetaBall *elem = elem_array;
235   for (const MetaElem *ml = mb->elems.first; ml; ml = ml->next, elem++) {
236     copy_v3_v3(elem->co, &ml->x);
237     copy_qt_qt(elem->quat, ml->quat);
238     copy_v3_v3(elem->exp, &ml->expx);
239     elem->rad = ml->rad;
240   }
241 }
242
243 static void metaball_coords_and_quats_apply_with_mat4(MetaBall *mb,
244                                                       const struct ElemData_MetaBall *elem_array,
245                                                       const float mat[4][4])
246 {
247   const struct ElemData_MetaBall *elem = elem_array;
248   for (MetaElem *ml = mb->elems.first; ml; ml = ml->next, elem++) {
249     copy_v3_v3(&ml->x, elem->co);
250     copy_qt_qt(ml->quat, elem->quat);
251     copy_v3_v3(&ml->expx, elem->exp);
252     ml->rad = elem->rad;
253   }
254   BKE_mball_transform(mb, mat, true);
255 }
256
257 static void metaball_coords_and_quats_apply(MetaBall *mb,
258                                             const struct ElemData_MetaBall *elem_array)
259 {
260   /* Avoid code duplication by using a unit matrix. */
261   float mat[4][4];
262   unit_m4(mat);
263   metaball_coords_and_quats_apply_with_mat4(mb, elem_array, mat);
264 }
265
266 /** \} */
267
268 /* -------------------------------------------------------------------- */
269 /** \name Public Object Data Storage API
270  *
271  * Used for interactively transforming object data.
272  *
273  * Store object data transformation in an opaque struct.
274  * \{ */
275
276 struct XFormObjectData {
277   ID *id;
278   bool is_edit_mode;
279 };
280
281 struct XFormObjectData_Mesh {
282   struct XFormObjectData base;
283   float elem_array[0][3];
284 };
285
286 struct XFormObjectData_Lattice {
287   struct XFormObjectData base;
288   float elem_array[0][3];
289 };
290
291 struct XFormObjectData_Curve {
292   struct XFormObjectData base;
293   float elem_array[0][3];
294 };
295
296 struct XFormObjectData_Armature {
297   struct XFormObjectData base;
298   struct ElemData_Armature elem_array[0];
299 };
300
301 struct XFormObjectData_MetaBall {
302   struct XFormObjectData base;
303   struct ElemData_MetaBall elem_array[0];
304 };
305
306 struct XFormObjectData *ED_object_data_xform_create_ex(ID *id, bool is_edit_mode)
307 {
308   struct XFormObjectData *xod_base = NULL;
309   switch (GS(id->name)) {
310     case ID_ME: {
311       Mesh *me = (Mesh *)id;
312       if (is_edit_mode) {
313         BMesh *bm = me->edit_mesh->bm;
314         const int elem_array_len = bm->totvert;
315         struct XFormObjectData_Mesh *xod = MEM_mallocN(
316             sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__);
317         BM_mesh_vert_coords_get(bm, xod->elem_array);
318         xod_base = &xod->base;
319       }
320       else {
321         const int elem_array_len = me->totvert;
322         struct XFormObjectData_Mesh *xod = MEM_mallocN(
323             sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__);
324         BKE_mesh_vert_coords_get(me, xod->elem_array);
325         xod_base = &xod->base;
326       }
327       break;
328     }
329     case ID_LT: {
330       Lattice *lt_orig = (Lattice *)id;
331       Lattice *lt = is_edit_mode ? lt_orig->editlatt->latt : lt_orig;
332       const int elem_array_len = lt->pntsu * lt->pntsv * lt->pntsw;
333       struct XFormObjectData_Lattice *xod = MEM_mallocN(
334           sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__);
335       BKE_lattice_vert_coords_get(lt, xod->elem_array);
336       xod_base = &xod->base;
337       break;
338     }
339     case ID_CU: {
340       Curve *cu = (Curve *)id;
341       const short ob_type = BKE_curve_type_get(cu);
342       if (ob_type == OB_FONT) {
343         /* We could support translation. */
344         break;
345       }
346
347       ListBase *nurbs;
348       if (is_edit_mode) {
349         EditNurb *editnurb = cu->editnurb;
350         nurbs = &editnurb->nurbs;
351       }
352       else {
353         nurbs = &cu->nurb;
354       }
355
356       const int elem_array_len = BKE_nurbList_verts_count(nurbs);
357       struct XFormObjectData_Curve *xod = MEM_mallocN(
358           sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__);
359       BKE_curve_nurbs_vert_coords_get(nurbs, xod->elem_array, elem_array_len);
360       xod_base = &xod->base;
361       break;
362     }
363     case ID_AR: {
364       bArmature *arm = (bArmature *)id;
365       if (is_edit_mode) {
366         const int elem_array_len = BLI_listbase_count(arm->edbo);
367         struct XFormObjectData_Armature *xod = MEM_mallocN(
368             sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__);
369         edit_armature_coords_and_quats_get(arm, xod->elem_array);
370         xod_base = &xod->base;
371       }
372       else {
373         const int elem_array_len = BKE_armature_bonelist_count(&arm->bonebase);
374         struct XFormObjectData_Armature *xod = MEM_mallocN(
375             sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__);
376         armature_coords_and_quats_get(arm, xod->elem_array);
377         xod_base = &xod->base;
378       }
379       break;
380     }
381     case ID_MB: {
382       /* Edit mode and object mode are shared. */
383       MetaBall *mb = (MetaBall *)id;
384       const int elem_array_len = BLI_listbase_count(&mb->elems);
385       struct XFormObjectData_MetaBall *xod = MEM_mallocN(
386           sizeof(*xod) + (sizeof(*xod->elem_array) * elem_array_len), __func__);
387       metaball_coords_and_quats_get(mb, xod->elem_array);
388       xod_base = &xod->base;
389       break;
390     }
391     default: {
392       break;
393     }
394   }
395   if (xod_base) {
396     xod_base->id = id;
397     xod_base->is_edit_mode = is_edit_mode;
398   }
399   return xod_base;
400 }
401
402 struct XFormObjectData *ED_object_data_xform_create(ID *id)
403 {
404   return ED_object_data_xform_create_ex(id, false);
405 }
406
407 struct XFormObjectData *ED_object_data_xform_create_from_edit_mode(ID *id)
408 {
409   return ED_object_data_xform_create_ex(id, true);
410 }
411
412 void ED_object_data_xform_destroy(struct XFormObjectData *xod)
413 {
414   MEM_freeN(xod);
415 }
416
417 void ED_object_data_xform_by_mat4(struct XFormObjectData *xod_base, const float mat[4][4])
418 {
419   switch (GS(xod_base->id->name)) {
420     case ID_ME: {
421       Mesh *me = (Mesh *)xod_base->id;
422       struct XFormObjectData_Mesh *xod = (struct XFormObjectData_Mesh *)xod_base;
423       if (xod_base->is_edit_mode) {
424         BMesh *bm = me->edit_mesh->bm;
425         BM_mesh_vert_coords_apply_with_mat4(bm, xod->elem_array, mat);
426       }
427       else {
428         BKE_mesh_vert_coords_apply_with_mat4(me, xod->elem_array, mat);
429       }
430       break;
431     }
432     case ID_LT: {
433       Lattice *lt_orig = (Lattice *)xod_base->id;
434       Lattice *lt = xod_base->is_edit_mode ? lt_orig->editlatt->latt : lt_orig;
435       struct XFormObjectData_Lattice *xod = (struct XFormObjectData_Lattice *)xod_base;
436       BKE_lattice_vert_coords_apply_with_mat4(lt, xod->elem_array, mat);
437       break;
438     }
439     case ID_CU: {
440       BLI_assert(xod_base->is_edit_mode == false); /* Not used currently. */
441       Curve *cu = (Curve *)xod_base->id;
442       struct XFormObjectData_Curve *xod = (struct XFormObjectData_Curve *)xod_base;
443       if (xod_base->is_edit_mode) {
444         EditNurb *editnurb = cu->editnurb;
445         BKE_curve_nurbs_vert_coords_apply_with_mat4(&editnurb->nurbs, xod->elem_array, mat, true);
446       }
447       else {
448         BKE_curve_nurbs_vert_coords_apply_with_mat4(&cu->nurb, xod->elem_array, mat, true);
449       }
450       break;
451     }
452     case ID_AR: {
453       BLI_assert(xod_base->is_edit_mode == false); /* Not used currently. */
454       bArmature *arm = (bArmature *)xod_base->id;
455       struct XFormObjectData_Armature *xod = (struct XFormObjectData_Armature *)xod_base;
456       if (xod_base->is_edit_mode) {
457         edit_armature_coords_and_quats_apply_with_mat4(arm, xod->elem_array, mat);
458       }
459       else {
460         armature_coords_and_quats_apply_with_mat4(arm, xod->elem_array, mat);
461       }
462       break;
463     }
464     case ID_MB: {
465       /* Metaballs are a special case, edit-mode and object mode data is shared. */
466       MetaBall *mb = (MetaBall *)xod_base->id;
467       struct XFormObjectData_MetaBall *xod = (struct XFormObjectData_MetaBall *)xod_base;
468       metaball_coords_and_quats_apply_with_mat4(mb, xod->elem_array, mat);
469       break;
470     }
471     default: {
472       break;
473     }
474   }
475 }
476
477 void ED_object_data_xform_restore(struct XFormObjectData *xod_base)
478 {
479   switch (GS(xod_base->id->name)) {
480     case ID_ME: {
481       Mesh *me = (Mesh *)xod_base->id;
482       struct XFormObjectData_Mesh *xod = (struct XFormObjectData_Mesh *)xod_base;
483       if (xod_base->is_edit_mode) {
484         BMesh *bm = me->edit_mesh->bm;
485         BM_mesh_vert_coords_apply(bm, xod->elem_array);
486       }
487       else {
488         BKE_mesh_vert_coords_apply(me, xod->elem_array);
489       }
490       break;
491     }
492     case ID_LT: {
493       Lattice *lt_orig = (Lattice *)xod_base->id;
494       Lattice *lt = xod_base->is_edit_mode ? lt_orig->editlatt->latt : lt_orig;
495       struct XFormObjectData_Lattice *xod = (struct XFormObjectData_Lattice *)xod_base;
496       BKE_lattice_vert_coords_apply(lt, xod->elem_array);
497       break;
498     }
499     case ID_CU: {
500       Curve *cu = (Curve *)xod_base->id;
501       struct XFormObjectData_Curve *xod = (struct XFormObjectData_Curve *)xod_base;
502       if (xod_base->is_edit_mode) {
503         EditNurb *editnurb = cu->editnurb;
504         BKE_curve_nurbs_vert_coords_apply(&editnurb->nurbs, xod->elem_array, true);
505       }
506       else {
507         BKE_curve_nurbs_vert_coords_apply(&cu->nurb, xod->elem_array, true);
508       }
509       break;
510     }
511     case ID_AR: {
512       bArmature *arm = (bArmature *)xod_base->id;
513       struct XFormObjectData_Armature *xod = (struct XFormObjectData_Armature *)xod_base;
514       if (xod_base->is_edit_mode) {
515         edit_armature_coords_and_quats_apply(arm, xod->elem_array);
516       }
517       else {
518         armature_coords_and_quats_apply(arm, xod->elem_array);
519       }
520       break;
521     }
522     case ID_MB: {
523       /* Metaballs are a special case, edit-mode and object mode data is shared. */
524       MetaBall *mb = (MetaBall *)xod_base->id;
525       struct XFormObjectData_MetaBall *xod = (struct XFormObjectData_MetaBall *)xod_base;
526       metaball_coords_and_quats_apply(mb, xod->elem_array);
527       break;
528     }
529     default: {
530       break;
531     }
532   }
533 }
534
535 void ED_object_data_xform_tag_update(struct XFormObjectData *xod_base)
536 {
537   switch (GS(xod_base->id->name)) {
538     case ID_ME: {
539       Mesh *me = (Mesh *)xod_base->id;
540       if (xod_base->is_edit_mode) {
541         EDBM_update_generic(me, true, false);
542         EDBM_mesh_normals_update(me->edit_mesh);
543       }
544       DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY);
545       break;
546     }
547     case ID_LT: {
548       /* Generic update. */
549       Lattice *lt = (Lattice *)xod_base->id;
550       DEG_id_tag_update(&lt->id, ID_RECALC_GEOMETRY);
551       break;
552     }
553     case ID_CU: {
554       /* Generic update. */
555       Curve *cu = (Curve *)xod_base->id;
556       DEG_id_tag_update(&cu->id, ID_RECALC_GEOMETRY);
557       break;
558     }
559     case ID_AR: {
560       /* Generic update. */
561       bArmature *arm = (bArmature *)xod_base->id;
562       /* XXX, zero is needed, no other flags properly update this. */
563       DEG_id_tag_update(&arm->id, 0);
564       break;
565     }
566     case ID_MB: {
567       /* Generic update. */
568       MetaBall *mb = (MetaBall *)xod_base->id;
569       DEG_id_tag_update(&mb->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
570       break;
571     }
572
573     default: {
574       break;
575     }
576   }
577 }
578
579 /** \} */
580
581 /* -------------------------------------------------------------------- */
582 /** \name Object Data Transform Container
583  *
584  * Use to implement 'Affect Only Origins' feature.
585  *
586  * \{ */
587
588 struct XFormObjectData_Container {
589   GHash *obdata_in_obmode_map;
590 };
591
592 struct XFormObjectData_Extra {
593   Object *ob;
594   float obmat_orig[4][4];
595   struct XFormObjectData *xod;
596 };
597
598 void ED_object_data_xform_container_item_ensure(struct XFormObjectData_Container *xds, Object *ob)
599 {
600   if (xds->obdata_in_obmode_map == NULL) {
601     xds->obdata_in_obmode_map = BLI_ghash_ptr_new(__func__);
602   }
603
604   void **xf_p;
605   if (!BLI_ghash_ensure_p(xds->obdata_in_obmode_map, ob->data, &xf_p)) {
606     struct XFormObjectData_Extra *xf = MEM_mallocN(sizeof(*xf), __func__);
607     copy_m4_m4(xf->obmat_orig, ob->obmat);
608     xf->ob = ob;
609     /* Result may be NULL, that's OK. */
610     xf->xod = ED_object_data_xform_create(ob->data);
611     *xf_p = xf;
612   }
613 }
614
615 /**
616  * This may be called multiple times with the same data.
617  * Each time, the original transformations are re-applied, instead of accumulating the changes.
618  */
619 void ED_object_data_xform_container_update_all(struct XFormObjectData_Container *xds,
620                                                struct Main *bmain,
621                                                Depsgraph *depsgraph)
622 {
623   if (xds->obdata_in_obmode_map == NULL) {
624     return;
625   }
626   BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
627
628   GHashIterator gh_iter;
629   GHASH_ITER (gh_iter, xds->obdata_in_obmode_map) {
630     ID *id = BLI_ghashIterator_getKey(&gh_iter);
631     struct XFormObjectData_Extra *xf = BLI_ghashIterator_getValue(&gh_iter);
632     if (xf->xod == NULL) {
633       continue;
634     }
635
636     Object *ob_eval = DEG_get_evaluated_object(depsgraph, xf->ob);
637     float imat[4][4], dmat[4][4];
638     invert_m4_m4(imat, xf->obmat_orig);
639     mul_m4_m4m4(dmat, imat, ob_eval->obmat);
640     invert_m4(dmat);
641
642     ED_object_data_xform_by_mat4(xf->xod, dmat);
643     if (xf->ob->type == OB_ARMATURE) {
644       /* TODO: none of the current flags properly update armatures, needs investigation. */
645       DEG_id_tag_update(id, 0);
646     }
647     else {
648       DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
649     }
650   }
651 }
652
653 /** Callback for #GHash free. */
654 static void trans_obdata_in_obmode_free_elem(void *xf_p)
655 {
656   struct XFormObjectData_Extra *xf = xf_p;
657   if (xf->xod) {
658     ED_object_data_xform_destroy(xf->xod);
659   }
660   MEM_freeN(xf);
661 }
662
663 struct XFormObjectData_Container *ED_object_data_xform_container_create(void)
664 {
665   struct XFormObjectData_Container *xds = MEM_callocN(sizeof(*xds), __func__);
666   xds->obdata_in_obmode_map = BLI_ghash_ptr_new(__func__);
667   return xds;
668 }
669
670 void ED_object_data_xform_container_destroy(struct XFormObjectData_Container *xds)
671 {
672   BLI_ghash_free(xds->obdata_in_obmode_map, NULL, trans_obdata_in_obmode_free_elem);
673   MEM_freeN(xds);
674 }
675
676 /** \} */