Cleanup: style, use braces for editors
[blender.git] / source / blender / editors / util / ed_transverts.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 edutil
22  */
23
24 #include "MEM_guardedalloc.h"
25
26 #include "DNA_armature_types.h"
27 #include "DNA_curve_types.h"
28 #include "DNA_lattice_types.h"
29 #include "DNA_meta_types.h"
30 #include "DNA_scene_types.h"
31 #include "DNA_object_types.h"
32
33 #include "BLI_blenlib.h"
34 #include "BLI_utildefines.h"
35 #include "BLI_math.h"
36
37 #include "BKE_curve.h"
38 #include "BKE_lattice.h"
39 #include "BKE_editmesh.h"
40 #include "BKE_DerivedMesh.h"
41 #include "BKE_context.h"
42 #include "BKE_mesh_iterators.h"
43
44 #include "DEG_depsgraph.h"
45
46 #include "ED_armature.h"
47
48 #include "ED_transverts.h" /* own include */
49
50 /* copied from editobject.c, now uses (almost) proper depgraph */
51 void ED_transverts_update_obedit(TransVertStore *tvs, Object *obedit)
52 {
53   const int mode = tvs->mode;
54   BLI_assert(ED_transverts_check_obedit(obedit) == true);
55
56   DEG_id_tag_update(obedit->data, 0);
57
58   if (obedit->type == OB_MESH) {
59     BMEditMesh *em = BKE_editmesh_from_object(obedit);
60     BM_mesh_normals_update(em->bm);
61   }
62   else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
63     Curve *cu = obedit->data;
64     ListBase *nurbs = BKE_curve_editNurbs_get(cu);
65     Nurb *nu = nurbs->first;
66
67     while (nu) {
68       /* keep handles' vectors unchanged */
69       if (nu->bezt && (mode & TM_SKIP_HANDLES)) {
70         int a = nu->pntsu;
71         TransVert *tv = tvs->transverts;
72         BezTriple *bezt = nu->bezt;
73
74         while (a--) {
75           if (bezt->hide == 0) {
76             bool skip_handle = false;
77             if (bezt->f2 & SELECT) {
78               skip_handle = (mode & TM_SKIP_HANDLES) != 0;
79             }
80
81             if ((bezt->f1 & SELECT) && !skip_handle) {
82               BLI_assert(tv->loc == bezt->vec[0]);
83               tv++;
84             }
85
86             if (bezt->f2 & SELECT) {
87               float v[3];
88
89               if (((bezt->f1 & SELECT) && !skip_handle) == 0) {
90                 sub_v3_v3v3(v, tv->loc, tv->oldloc);
91                 add_v3_v3(bezt->vec[0], v);
92               }
93
94               if (((bezt->f3 & SELECT) && !skip_handle) == 0) {
95                 sub_v3_v3v3(v, tv->loc, tv->oldloc);
96                 add_v3_v3(bezt->vec[2], v);
97               }
98
99               BLI_assert(tv->loc == bezt->vec[1]);
100               tv++;
101             }
102
103             if ((bezt->f3 & SELECT) && !skip_handle) {
104               BLI_assert(tv->loc == bezt->vec[2]);
105               tv++;
106             }
107           }
108
109           bezt++;
110         }
111       }
112
113       BKE_nurb_test_2d(nu);
114       BKE_nurb_handles_test(nu, true); /* test for bezier too */
115       nu = nu->next;
116     }
117   }
118   else if (obedit->type == OB_ARMATURE) {
119     bArmature *arm = obedit->data;
120     EditBone *ebo;
121     TransVert *tv = tvs->transverts;
122     int a = 0;
123
124     /* Ensure all bone tails are correctly adjusted */
125     for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
126       /* adjust tip if both ends selected */
127       if ((ebo->flag & BONE_ROOTSEL) && (ebo->flag & BONE_TIPSEL)) {
128         if (tv) {
129           float diffvec[3];
130
131           sub_v3_v3v3(diffvec, tv->loc, tv->oldloc);
132           add_v3_v3(ebo->tail, diffvec);
133
134           a++;
135           if (a < tvs->transverts_tot) {
136             tv++;
137           }
138         }
139       }
140     }
141
142     /* Ensure all bones are correctly adjusted */
143     for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
144       if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
145         /* If this bone has a parent tip that has been moved */
146         if (ebo->parent->flag & BONE_TIPSEL) {
147           copy_v3_v3(ebo->head, ebo->parent->tail);
148         }
149         /* If this bone has a parent tip that has NOT been moved */
150         else {
151           copy_v3_v3(ebo->parent->tail, ebo->head);
152         }
153       }
154     }
155     if (arm->flag & ARM_MIRROR_EDIT) {
156       ED_armature_edit_transform_mirror_update(obedit);
157     }
158   }
159   else if (obedit->type == OB_LATTICE) {
160     Lattice *lt = obedit->data;
161
162     if (lt->editlatt->latt->flag & LT_OUTSIDE) {
163       outside_lattice(lt->editlatt->latt);
164     }
165   }
166 }
167
168 static void set_mapped_co(void *vuserdata,
169                           int index,
170                           const float co[3],
171                           const float UNUSED(no[3]),
172                           const short UNUSED(no_s[3]))
173 {
174   void **userdata = vuserdata;
175   BMEditMesh *em = userdata[0];
176   TransVert *tv = userdata[1];
177   BMVert *eve = BM_vert_at_index(em->bm, index);
178
179   if (BM_elem_index_get(eve) != TM_INDEX_SKIP) {
180     tv = &tv[BM_elem_index_get(eve)];
181
182     /* be clever, get the closest vertex to the original,
183      * behaves most logically when the mirror modifier is used for eg [#33051]*/
184     if ((tv->flag & TX_VERT_USE_MAPLOC) == 0) {
185       /* first time */
186       copy_v3_v3(tv->maploc, co);
187       tv->flag |= TX_VERT_USE_MAPLOC;
188     }
189     else {
190       /* find best location to use */
191       if (len_squared_v3v3(eve->co, co) < len_squared_v3v3(eve->co, tv->maploc)) {
192         copy_v3_v3(tv->maploc, co);
193       }
194     }
195   }
196 }
197
198 bool ED_transverts_check_obedit(Object *obedit)
199 {
200   return (ELEM(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL));
201 }
202
203 void ED_transverts_create_from_obedit(TransVertStore *tvs, Object *obedit, const int mode)
204 {
205   Nurb *nu;
206   BezTriple *bezt;
207   BPoint *bp;
208   TransVert *tv = NULL;
209   MetaElem *ml;
210   BMVert *eve;
211   EditBone *ebo;
212   int a;
213
214   tvs->transverts_tot = 0;
215
216   if (obedit->type == OB_MESH) {
217     BMEditMesh *em = BKE_editmesh_from_object(obedit);
218     BMesh *bm = em->bm;
219     BMIter iter;
220     void *userdata[2] = {em, NULL};
221     /*int proptrans = 0; */ /*UNUSED*/
222
223     /* abuses vertex index all over, set, just set dirty here,
224      * perhaps this could use its own array instead? - campbell */
225
226     /* transform now requires awareness for select mode, so we tag the f1 flags in verts */
227     tvs->transverts_tot = 0;
228     if (em->selectmode & SCE_SELECT_VERTEX) {
229       BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
230         if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
231           BM_elem_index_set(eve, TM_INDEX_ON); /* set_dirty! */
232           tvs->transverts_tot++;
233         }
234         else {
235           BM_elem_index_set(eve, TM_INDEX_OFF); /* set_dirty! */
236         }
237       }
238     }
239     else if (em->selectmode & SCE_SELECT_EDGE) {
240       BMEdge *eed;
241
242       BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
243         BM_elem_index_set(eve, TM_INDEX_OFF); /* set_dirty! */
244       }
245
246       BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
247         if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
248           BM_elem_index_set(eed->v1, TM_INDEX_ON); /* set_dirty! */
249           BM_elem_index_set(eed->v2, TM_INDEX_ON); /* set_dirty! */
250         }
251       }
252
253       BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
254         if (BM_elem_index_get(eve) == TM_INDEX_ON) {
255           tvs->transverts_tot++;
256         }
257       }
258     }
259     else {
260       BMFace *efa;
261
262       BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
263         BM_elem_index_set(eve, TM_INDEX_OFF); /* set_dirty! */
264       }
265
266       BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
267         if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
268           BMIter liter;
269           BMLoop *l;
270
271           BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
272             BM_elem_index_set(l->v, TM_INDEX_ON); /* set_dirty! */
273           }
274         }
275       }
276
277       BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
278         if (BM_elem_index_get(eve) == TM_INDEX_ON) {
279           tvs->transverts_tot++;
280         }
281       }
282     }
283     /* for any of the 3 loops above which all dirty the indices */
284     bm->elem_index_dirty |= BM_VERT;
285
286     /* and now make transverts */
287     if (tvs->transverts_tot) {
288       tv = tvs->transverts = MEM_callocN(tvs->transverts_tot * sizeof(TransVert), __func__);
289
290       a = 0;
291       BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
292         if (BM_elem_index_get(eve)) {
293           BM_elem_index_set(eve, a); /* set_dirty! */
294           copy_v3_v3(tv->oldloc, eve->co);
295           tv->loc = eve->co;
296           tv->flag = (BM_elem_index_get(eve) == TM_INDEX_ON) ? SELECT : 0;
297
298           if (mode & TM_CALC_NORMALS) {
299             tv->flag |= TX_VERT_USE_NORMAL;
300             copy_v3_v3(tv->normal, eve->no);
301           }
302
303           tv++;
304           a++;
305         }
306         else {
307           BM_elem_index_set(eve, TM_INDEX_SKIP); /* set_dirty! */
308         }
309       }
310       /* set dirty already, above */
311
312       userdata[1] = tvs->transverts;
313     }
314
315     if (tvs->transverts && em->mesh_eval_cage) {
316       BM_mesh_elem_table_ensure(bm, BM_VERT);
317       BKE_mesh_foreach_mapped_vert(em->mesh_eval_cage, set_mapped_co, userdata, MESH_FOREACH_NOP);
318     }
319   }
320   else if (obedit->type == OB_ARMATURE) {
321     bArmature *arm = obedit->data;
322     int totmalloc = BLI_listbase_count(arm->edbo);
323
324     totmalloc *= 2; /* probably overkill but bones can have 2 trans verts each */
325
326     tv = tvs->transverts = MEM_callocN(totmalloc * sizeof(TransVert), __func__);
327
328     for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
329       if (ebo->layer & arm->layer) {
330         const bool tipsel = (ebo->flag & BONE_TIPSEL) != 0;
331         const bool rootsel = (ebo->flag & BONE_ROOTSEL) != 0;
332         const bool rootok = (!(ebo->parent && (ebo->flag & BONE_CONNECTED) &&
333                                (ebo->parent->flag & BONE_TIPSEL)));
334
335         if ((tipsel && rootsel) || (rootsel)) {
336           /* Don't add the tip (unless mode & TM_ALL_JOINTS, for getting all joints),
337            * otherwise we get zero-length bones as tips will snap to the same
338            * location as heads.
339            */
340           if (rootok) {
341             copy_v3_v3(tv->oldloc, ebo->head);
342             tv->loc = ebo->head;
343             tv->flag = SELECT;
344             tv++;
345             tvs->transverts_tot++;
346           }
347
348           if ((mode & TM_ALL_JOINTS) && (tipsel)) {
349             copy_v3_v3(tv->oldloc, ebo->tail);
350             tv->loc = ebo->tail;
351             tv->flag = SELECT;
352             tv++;
353             tvs->transverts_tot++;
354           }
355         }
356         else if (tipsel) {
357           copy_v3_v3(tv->oldloc, ebo->tail);
358           tv->loc = ebo->tail;
359           tv->flag = SELECT;
360           tv++;
361           tvs->transverts_tot++;
362         }
363       }
364     }
365   }
366   else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
367     Curve *cu = obedit->data;
368     int totmalloc = 0;
369     ListBase *nurbs = BKE_curve_editNurbs_get(cu);
370
371     for (nu = nurbs->first; nu; nu = nu->next) {
372       if (nu->type == CU_BEZIER) {
373         totmalloc += 3 * nu->pntsu;
374       }
375       else {
376         totmalloc += nu->pntsu * nu->pntsv;
377       }
378     }
379     tv = tvs->transverts = MEM_callocN(totmalloc * sizeof(TransVert), __func__);
380
381     nu = nurbs->first;
382     while (nu) {
383       if (nu->type == CU_BEZIER) {
384         a = nu->pntsu;
385         bezt = nu->bezt;
386         while (a--) {
387           if (bezt->hide == 0) {
388             bool skip_handle = false;
389             if (bezt->f2 & SELECT) {
390               skip_handle = (mode & TM_SKIP_HANDLES) != 0;
391             }
392
393             if ((bezt->f1 & SELECT) && !skip_handle) {
394               copy_v3_v3(tv->oldloc, bezt->vec[0]);
395               tv->loc = bezt->vec[0];
396               tv->flag = bezt->f1 & SELECT;
397
398               if (mode & TM_CALC_NORMALS) {
399                 tv->flag |= TX_VERT_USE_NORMAL;
400                 BKE_nurb_bezt_calc_plane(nu, bezt, tv->normal);
401               }
402
403               tv++;
404               tvs->transverts_tot++;
405             }
406             if (bezt->f2 & SELECT) {
407               copy_v3_v3(tv->oldloc, bezt->vec[1]);
408               tv->loc = bezt->vec[1];
409               tv->flag = bezt->f2 & SELECT;
410
411               if (mode & TM_CALC_NORMALS) {
412                 tv->flag |= TX_VERT_USE_NORMAL;
413                 BKE_nurb_bezt_calc_plane(nu, bezt, tv->normal);
414               }
415
416               tv++;
417               tvs->transverts_tot++;
418             }
419             if ((bezt->f3 & SELECT) && !skip_handle) {
420               copy_v3_v3(tv->oldloc, bezt->vec[2]);
421               tv->loc = bezt->vec[2];
422               tv->flag = bezt->f3 & SELECT;
423
424               if (mode & TM_CALC_NORMALS) {
425                 tv->flag |= TX_VERT_USE_NORMAL;
426                 BKE_nurb_bezt_calc_plane(nu, bezt, tv->normal);
427               }
428
429               tv++;
430               tvs->transverts_tot++;
431             }
432           }
433           bezt++;
434         }
435       }
436       else {
437         a = nu->pntsu * nu->pntsv;
438         bp = nu->bp;
439         while (a--) {
440           if (bp->hide == 0) {
441             if (bp->f1 & SELECT) {
442               copy_v3_v3(tv->oldloc, bp->vec);
443               tv->loc = bp->vec;
444               tv->flag = bp->f1 & SELECT;
445               tv++;
446               tvs->transverts_tot++;
447             }
448           }
449           bp++;
450         }
451       }
452       nu = nu->next;
453     }
454   }
455   else if (obedit->type == OB_MBALL) {
456     MetaBall *mb = obedit->data;
457     int totmalloc = BLI_listbase_count(mb->editelems);
458
459     tv = tvs->transverts = MEM_callocN(totmalloc * sizeof(TransVert), __func__);
460
461     ml = mb->editelems->first;
462     while (ml) {
463       if (ml->flag & SELECT) {
464         tv->loc = &ml->x;
465         copy_v3_v3(tv->oldloc, tv->loc);
466         tv->flag = SELECT;
467         tv++;
468         tvs->transverts_tot++;
469       }
470       ml = ml->next;
471     }
472   }
473   else if (obedit->type == OB_LATTICE) {
474     Lattice *lt = obedit->data;
475
476     bp = lt->editlatt->latt->def;
477
478     a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
479
480     tv = tvs->transverts = MEM_callocN(a * sizeof(TransVert), __func__);
481
482     while (a--) {
483       if (bp->f1 & SELECT) {
484         if (bp->hide == 0) {
485           copy_v3_v3(tv->oldloc, bp->vec);
486           tv->loc = bp->vec;
487           tv->flag = bp->f1 & SELECT;
488           tv++;
489           tvs->transverts_tot++;
490         }
491       }
492       bp++;
493     }
494   }
495
496   if (!tvs->transverts_tot && tvs->transverts) {
497     /* prevent memory leak. happens for curves/latticies due to */
498     /* difficult condition of adding points to trans data */
499     MEM_freeN(tvs->transverts);
500     tvs->transverts = NULL;
501   }
502
503   tvs->mode = mode;
504 }
505
506 void ED_transverts_free(TransVertStore *tvs)
507 {
508   MEM_SAFE_FREE(tvs->transverts);
509   tvs->transverts_tot = 0;
510 }
511
512 bool ED_transverts_poll(bContext *C)
513 {
514   Object *obedit = CTX_data_edit_object(C);
515   if (obedit) {
516     if (ED_transverts_check_obedit(obedit)) {
517       return true;
518     }
519   }
520   return false;
521 }