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