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