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